1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28/*	  All Rights Reserved  	*/
29
30
31#pragma ident	"%Z%%M%	%I%	%E% SMI"
32
33/*
34 *	Implements the "putdgrp" command.
35 */
36#include	<sys/types.h>
37#include	<stdio.h>
38#include	<stdlib.h>
39#include	<string.h>
40#include	<errno.h>
41#include	<unistd.h>
42#include	<fmtmsg.h>
43#include	<devmgmt.h>
44#include	<devtab.h>
45
46
47/*
48 * General Purpose Constants
49 *	TRUE		Boolean TRUE (if not already defined)
50 *	FALSE		Boolean FALSE (if not already defined)
51 */
52
53#ifndef	TRUE
54#define	TRUE	(1)
55#endif
56
57#ifndef	FALSE
58#define	FALSE	(0)
59#endif
60
61/*
62 * Exit codes
63 *	EX_OK		All went well
64 *	EX_ERROR	Usage or internal error
65 *	EX_DGROUP	Had trouble accessing/reading/writing the
66 *			device-group table
67 *	EX_NODGRP	The specified device-group does not exist
68 *	EX_NOMEM	One or more device-group members requested for
69 *			removal was not defined for the device
70 */
71
72#define	EX_OK		0
73#define	EX_ERROR	1
74#define	EX_DGROUP	2
75#define	EX_NODGRP	3
76#define	EX_NOMEM	4
77
78
79/*
80 * Error messages
81 */
82
83#define	E_USAGE		"usage: putdgrp [-d] dgroup [device [...]]"
84#define	E_NODGRP	"Device-group does not exist in table: %s"
85#define	E_NOTAMEM	"Device-group member not found: %s"
86#define	E_NODGRPTAB	"Cannot open the device-group table: %s"
87#define	E_NOMKTAB	"Cannot create a new device-group table: %s"
88#define	E_INTERNAL	"Internal error, errno=%d"
89
90
91/*
92 * Macros
93 *	stdmsg(r,l,s,t)	    Using fmtmsg(), write a standard message to the
94 *			    standard error stream.
95 *			    Where:
96 *				r   The recoverability of the error
97 *				l   The label-component
98 *				s   The severity-component
99 *				t   The text-component
100 */
101
102#define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)
103
104
105/*
106 * Static data
107 *	msg		Space for message's text-component
108 */
109
110static	char		msg[256];	/* Space for text of message */
111
112/*
113 * char *mklbl(cmd)
114 *	char   *cmd
115 *
116 *	This function builds a standard label from the command used to invoke
117 *	this process and the standard label prefix ("UX:")
118 *
119 * Arguments:
120 *	char *cmd	The command used to invoke this process.
121 *
122 * Returns:  char *
123 *	Pointer to malloc()ed space containing the standard label,
124 *	or (char *) NULL if an error occurred.
125 */
126
127static char *
128mklbl(cmd)
129	char   *cmd;
130{
131	/* Automatic data */
132	char   *rtn;		/* Value to return */
133	char   *p;		/* Temporary */
134
135	/* Find the 1st char of the basename of the command */
136	if (p = strrchr(cmd, '/')) p++;
137	else p = cmd;
138
139	/* Allocate and build the string value to return */
140	if (rtn = (char *) malloc(strlen("UX:")+strlen(p)+1)) {
141	    (void) strcpy(rtn, "UX:");
142	    (void) strcat(rtn, p);
143	}
144
145	/* Now that we've done all of this work, set up the environemnt
146	 * so that only the text-component is written (some requirements
147	 * say that standard messages are to be non-standard in SVR4.0,
148	 * this is supposed to change in SVR4.1)
149	 */
150
151	(void) putenv("MSGVERB=text");
152
153	/* Done */
154	return(rtn);
155}
156
157/*
158 * putdgrp [-d] dgroup [device [...]]
159 *
160 * Options:
161 *	-d
162 *
163 * Arguments:
164 *	dgroup
165 *	device
166 *
167 * Exit values:
168 */
169
170int
171main(int argc, char *argv[])
172{
173	/* Automatic data */
174	char	      **plist;		/* Ptr to list of nonmembers */
175	char	       *lbl;		/* Ptr to label for messages */
176	char	       *dgroup;		/* Ptr to <dgroup> on command-line */
177	char	       *p;		/* Temp ptr to char */
178	int		noerr;		/* FLAG, TRUE if all's well */
179	int		d_seen;		/* TRUE if -a seen on command-line */
180	int		optchar;	/* Option extracted */
181	int		exitcd;		/* Value to return at exit */
182	int		nmems;		/* Number of members on the cmd */
183
184
185	/* Generate the label for messages */
186	lbl = mklbl(argv[0]);
187
188	/* Extract arguments - validate usage */
189	noerr = TRUE;
190	d_seen = FALSE;
191	opterr = FALSE;
192	while ((optchar = getopt(argc, argv, "d:")) != EOF) switch (optchar) {
193
194	case 'd':
195	    if (!d_seen)
196	    {
197		d_seen = TRUE;
198		dgroup = optarg;
199	    }
200	    else noerr = FALSE;
201	    break;
202
203	case '?':
204	default:
205	    noerr = FALSE;
206	}
207
208
209	/* Write a usage message if we've seen a blatant error */
210	if (!noerr || (!d_seen && ((nmems = argc - optind - 1) < 0)) ||
211		      (d_seen && ((nmems = argc - optind) < 0))) {
212	    stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
213	    exit(EX_ERROR);
214	}
215
216
217	/* Set up */
218	exitcd = EX_OK;
219
220
221	/* -d on the command line ? */
222	if (d_seen) {
223
224	    /*
225	     * Determine case (removing a device group or members
226	     * of that device group.
227	     */
228
229	    if (nmems == 0) {
230
231		/* putdgrp -d dgroup */
232
233		/* Attempt to remove the specified device */
234		if (!(_rmdgrptabrec(dgroup))) switch(errno) {
235
236		    /*
237		     * EINVAL indicates that the named device-group was
238		     * not found in the device-group table.
239		     */
240
241		case EINVAL:
242		    (void) snprintf(msg, sizeof(msg), E_NODGRP, dgroup);
243		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
244		    exitcd = EX_NODGRP;
245		    break;
246
247		    /*
248		     * ENOENT indicates that the device-group table can't
249		     * be found.
250		     */
251
252		case ENOENT:
253		    (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, _dgrptabpath());
254		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
255		    exitcd = EX_DGROUP;
256		    break;
257
258		    /*
259		     * EACCES indicates that there was a problem reading the
260		     * old device-group table or creating the new table.  If the
261		     * old table is readable, assume that we can't create the
262		     * new table.  Otherwise, assume that the old table isn't
263		     * accessible.
264		     */
265
266		case EACCES:
267		    p = _dgrptabpath();
268		    if (access(p, R_OK) == 0)
269			(void) snprintf(msg, sizeof(msg), E_NOMKTAB, p);
270		    else
271			(void) snprintf(msg, sizeof(msg), E_NODGRPTAB, p);
272		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
273		    exitcd = EX_DGROUP;
274		    break;
275
276		    /*
277		     * Some strange problem...
278		     */
279
280		default:
281		    (void) snprintf(msg, sizeof(msg), E_INTERNAL, errno);
282		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
283		    exitcd = EX_ERROR;
284
285		}   /* End switch */
286	    }
287	    else {
288
289		/* putdgrp -d dgroup device [device [...]] */
290
291		/*
292		 * Attempt to remove the specified devices from the
293		 * specified device-group.
294		 */
295		if (!(_rmdgrpmems(dgroup, &argv[optind], &plist))) switch(errno) {
296
297		    /*
298		     * ENODEV indicates that a named device was not part
299		     * of the specified device group.
300		     */
301
302		case ENODEV:
303		    exitcd = EX_NOMEM;
304		    for (; *plist; plist++) {
305			(void) snprintf(msg, sizeof(msg), E_NOTAMEM, *plist);
306			stdmsg(MM_RECOVER, lbl, MM_WARNING, msg);
307		    }
308		    break;
309
310		    /*
311		     * EINVAL indicates that the named device-group is not
312		     * defined in the device-group table.
313		     */
314
315		case EINVAL:
316		    (void) snprintf(msg, sizeof(msg), E_NODGRP, dgroup);
317		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
318		    exitcd = EX_NODGRP;
319		    break;
320
321		    /*
322		     * ENOENT indicates that the device table can't
323		     * be found.
324		     */
325
326		case ENOENT:
327		    (void) snprintf(msg, sizeof(msg), E_NODGRPTAB, _dgrptabpath());
328		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
329		    exitcd = EX_DGROUP;
330		    break;
331
332		    /*
333		     * EACCES indicates that there was a problem reading the
334		     * old device table or creating the new table.  If the
335		     * old table is readable, assume that we can't create the
336		     * new table.  Otherwise, assume that the old table isn't
337		     * accessible.
338		     */
339
340		case EACCES:
341		    p = _dgrptabpath();
342		    if (access(p, R_OK) == 0)
343			(void) snprintf(msg, sizeof(msg), E_NOMKTAB, p);
344		    else
345			(void) snprintf(msg, sizeof(msg), E_NODGRPTAB, p);
346		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
347		    exitcd = EX_DGROUP;
348		    break;
349
350		    /*
351		     * Some strange problem...
352		     */
353
354		default:
355		    (void) sprintf(msg, E_INTERNAL, errno);
356		    stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
357		    exitcd = EX_ERROR;
358
359		}  /* End switch */
360
361	    }   /* End "putdgrp -d device attr [...]" case */
362
363
364	}   /* End -d case */
365
366	else {
367	    /* Standard case (no -d on the command) */
368	    if (!(_adddgrptabrec(argv[optind], &argv[optind+1]))) switch(errno) {
369
370		/*
371		 * ENOENT indicates that the device-group table does not exist.
372		 */
373
374	    case ENOENT:
375		(void) snprintf(msg, sizeof(msg), E_NODGRPTAB, _dgrptabpath());
376		stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
377		exitcd = EX_DGROUP;
378		break;
379
380		/*
381		 * EACCES indicates that the device-group table could not be
382		 * opened or the new device-group table could not be created.
383		 */
384
385	    case EACCES:
386		p = _dgrptabpath();
387		if (access(p, R_OK) == 0)
388			(void) snprintf(msg, sizeof(msg), E_NOMKTAB, p);
389		else
390			(void) snprintf(msg, sizeof(msg), E_NODGRPTAB, p);
391		stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
392		exitcd = EX_DGROUP;
393		break;
394
395		/*
396		 * Some strange error (memory?)
397		 */
398
399	    default:
400		(void) sprintf(msg, E_INTERNAL, errno);
401		stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
402		exitcd = EX_ERROR;
403	    }
404	}
405
406	/* Done.  Return exit code (determined above) */
407	return(exitcd);
408}  /* main() */
409