root/usr/src/cmd/devmgmt/cmds/putdgrp.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/*        All Rights Reserved   */

/*
 *      Implements the "putdgrp" command.
 */
#include        <sys/types.h>
#include        <stdio.h>
#include        <stdlib.h>
#include        <string.h>
#include        <errno.h>
#include        <unistd.h>
#include        <fmtmsg.h>
#include        <devmgmt.h>
#include        <devtab.h>


/*
 * General Purpose Constants
 *      TRUE            Boolean TRUE (if not already defined)
 *      FALSE           Boolean FALSE (if not already defined)
 */

#ifndef TRUE
#define TRUE    (1)
#endif

#ifndef FALSE
#define FALSE   (0)
#endif

/*
 * Exit codes
 *      EX_OK           All went well
 *      EX_ERROR        Usage or internal error
 *      EX_DGROUP       Had trouble accessing/reading/writing the
 *                      device-group table
 *      EX_NODGRP       The specified device-group does not exist
 *      EX_NOMEM        One or more device-group members requested for
 *                      removal was not defined for the device
 */

#define EX_OK           0
#define EX_ERROR        1
#define EX_DGROUP       2
#define EX_NODGRP       3
#define EX_NOMEM        4


/*
 * Error messages
 */

#define E_USAGE         "usage: putdgrp [-d] dgroup [device [...]]"
#define E_NODGRP        "Device-group does not exist in table: %s"
#define E_NOTAMEM       "Device-group member not found: %s"
#define E_NODGRPTAB     "Cannot open the device-group table: %s"
#define E_NOMKTAB       "Cannot create a new device-group table: %s"
#define E_INTERNAL      "Internal error, errno=%d"


/*
 * Macros
 *      stdmsg(r,l,s,t)     Using fmtmsg(), write a standard message to the
 *                          standard error stream.
 *                          Where:
 *                              r   The recoverability of the error
 *                              l   The label-component
 *                              s   The severity-component
 *                              t   The text-component
 */

#define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)


/*
 * Static data
 *      msg             Space for message's text-component
 */

static  char            msg[256];       /* Space for text of message */

/*
 * char *mklbl(cmd)
 *      char   *cmd
 *
 *      This function builds a standard label from the command used to invoke
 *      this process and the standard label prefix ("UX:")
 *
 * Arguments:
 *      char *cmd       The command used to invoke this process.
 *
 * Returns:  char *
 *      Pointer to malloc()ed space containing the standard label,
 *      or (char *) NULL if an error occurred.
 */

static char *
mklbl(cmd)
        char   *cmd;
{
        /* Automatic data */
        char   *rtn;            /* Value to return */
        char   *p;              /* Temporary */

        /* Find the 1st char of the basename of the command */
        if (p = strrchr(cmd, '/')) p++;
        else p = cmd;

        /* Allocate and build the string value to return */
        if (rtn = (char *) malloc(strlen("UX:")+strlen(p)+1)) {
            (void) strcpy(rtn, "UX:");
            (void) strcat(rtn, p);
        }

        /* Now that we've done all of this work, set up the environemnt
         * so that only the text-component is written (some requirements
         * say that standard messages are to be non-standard in SVR4.0,
         * this is supposed to change in SVR4.1)
         */

        (void) putenv("MSGVERB=text");

        /* Done */
        return(rtn);
}

/*
 * putdgrp [-d] dgroup [device [...]]
 *
 * Options:
 *      -d
 *
 * Arguments:
 *      dgroup
 *      device
 *
 * Exit values:
 */

int
main(int argc, char *argv[])
{
        /* Automatic data */
        char          **plist;          /* Ptr to list of nonmembers */
        char           *lbl;            /* Ptr to label for messages */
        char           *dgroup;         /* Ptr to <dgroup> on command-line */
        char           *p;              /* Temp ptr to char */
        int             noerr;          /* FLAG, TRUE if all's well */
        int             d_seen;         /* TRUE if -a seen on command-line */
        int             optchar;        /* Option extracted */
        int             exitcd;         /* Value to return at exit */
        int             nmems;          /* Number of members on the cmd */


        /* Generate the label for messages */
        lbl = mklbl(argv[0]);

        /* Extract arguments - validate usage */
        noerr = TRUE;
        d_seen = FALSE;
        opterr = FALSE;
        while ((optchar = getopt(argc, argv, "d:")) != EOF) switch (optchar) {

        case 'd':
            if (!d_seen)
            {
                d_seen = TRUE;
                dgroup = optarg;
            }
            else noerr = FALSE;
            break;

        case '?':
        default:
            noerr = FALSE;
        }


        /* Write a usage message if we've seen a blatant error */
        if (!noerr || (!d_seen && ((nmems = argc - optind - 1) < 0)) ||
                      (d_seen && ((nmems = argc - optind) < 0))) {
            stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
            exit(EX_ERROR);
        }


        /* Set up */
        exitcd = EX_OK;


        /* -d on the command line ? */
        if (d_seen) {

            /*
             * Determine case (removing a device group or members
             * of that device group.
             */

            if (nmems == 0) {

                /* putdgrp -d dgroup */

                /* Attempt to remove the specified device */
                if (!(_rmdgrptabrec(dgroup))) switch(errno) {

                    /*
                     * EINVAL indicates that the named device-group was
                     * not found in the device-group table.
                     */

                case EINVAL:
                    (void) snprintf(msg, sizeof(msg), E_NODGRP, dgroup);
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_NODGRP;
                    break;

                    /*
                     * ENOENT indicates that the device-group table can't
                     * be found.
                     */

                case ENOENT:
                    (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, _dgrptabpath());
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_DGROUP;
                    break;

                    /*
                     * EACCES indicates that there was a problem reading the
                     * old device-group table or creating the new table.  If the
                     * old table is readable, assume that we can't create the
                     * new table.  Otherwise, assume that the old table isn't
                     * accessible.
                     */

                case EACCES:
                    p = _dgrptabpath();
                    if (access(p, R_OK) == 0)
                        (void) snprintf(msg, sizeof(msg), E_NOMKTAB, p);
                    else
                        (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, p);
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_DGROUP;
                    break;

                    /*
                     * Some strange problem...
                     */

                default:
                    (void) snprintf(msg, sizeof(msg), E_INTERNAL, errno);
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_ERROR;

                }   /* End switch */
            }
            else {

                /* putdgrp -d dgroup device [device [...]] */

                /*
                 * Attempt to remove the specified devices from the
                 * specified device-group.
                 */
                if (!(_rmdgrpmems(dgroup, &argv[optind], &plist))) switch(errno) {

                    /*
                     * ENODEV indicates that a named device was not part
                     * of the specified device group.
                     */

                case ENODEV:
                    exitcd = EX_NOMEM;
                    for (; *plist; plist++) {
                        (void) snprintf(msg, sizeof(msg), E_NOTAMEM, *plist);
                        stdmsg(MM_RECOVER, lbl, MM_WARNING, msg);
                    }
                    break;

                    /*
                     * EINVAL indicates that the named device-group is not
                     * defined in the device-group table.
                     */

                case EINVAL:
                    (void) snprintf(msg, sizeof(msg), E_NODGRP, dgroup);
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_NODGRP;
                    break;

                    /*
                     * ENOENT indicates that the device table can't
                     * be found.
                     */

                case ENOENT:
                    (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, _dgrptabpath());
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_DGROUP;
                    break;

                    /*
                     * EACCES indicates that there was a problem reading the
                     * old device table or creating the new table.  If the
                     * old table is readable, assume that we can't create the
                     * new table.  Otherwise, assume that the old table isn't
                     * accessible.
                     */

                case EACCES:
                    p = _dgrptabpath();
                    if (access(p, R_OK) == 0)
                        (void) snprintf(msg, sizeof(msg), E_NOMKTAB, p);
                    else
                        (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, p);
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_DGROUP;
                    break;

                    /*
                     * Some strange problem...
                     */

                default:
                    (void) sprintf(msg, E_INTERNAL, errno);
                    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                    exitcd = EX_ERROR;

                }  /* End switch */

            }   /* End "putdgrp -d device attr [...]" case */


        }   /* End -d case */

        else {
            /* Standard case (no -d on the command) */
            if (!(_adddgrptabrec(argv[optind], &argv[optind+1]))) switch(errno) {

                /*
                 * ENOENT indicates that the device-group table does not exist.
                 */

            case ENOENT:
                (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, _dgrptabpath());
                stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                exitcd = EX_DGROUP;
                break;

                /*
                 * EACCES indicates that the device-group table could not be
                 * opened or the new device-group table could not be created.
                 */

            case EACCES:
                p = _dgrptabpath();
                if (access(p, R_OK) == 0)
                        (void) snprintf(msg, sizeof(msg), E_NOMKTAB, p);
                else
                        (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, p);
                stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                exitcd = EX_DGROUP;
                break;

                /*
                 * Some strange error (memory?)
                 */

            default:
                (void) sprintf(msg, E_INTERNAL, errno);
                stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
                exitcd = EX_ERROR;
            }
        }

        /* Done.  Return exit code (determined above) */
        return(exitcd);
}  /* main() */