1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2002-2003 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate /*
34*0Sstevel@tonic-gate  *	Implements the "putdev" command.
35*0Sstevel@tonic-gate  */
36*0Sstevel@tonic-gate #include	<sys/types.h>
37*0Sstevel@tonic-gate #include	<stdio.h>
38*0Sstevel@tonic-gate #include	<stdlib.h>
39*0Sstevel@tonic-gate #include	<string.h>
40*0Sstevel@tonic-gate #include	<errno.h>
41*0Sstevel@tonic-gate #include	<unistd.h>
42*0Sstevel@tonic-gate #include	<fmtmsg.h>
43*0Sstevel@tonic-gate #include	<devmgmt.h>
44*0Sstevel@tonic-gate #include	<devtab.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate /*
48*0Sstevel@tonic-gate  * General Purpose Constants
49*0Sstevel@tonic-gate  *	TRUE		Boolean TRUE (if not already defined)
50*0Sstevel@tonic-gate  *	FALSE		Boolean FALSE (if not already defined)
51*0Sstevel@tonic-gate  *	NULL		Null address (if not already defined)
52*0Sstevel@tonic-gate  */
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate #ifndef	TRUE
55*0Sstevel@tonic-gate #define	TRUE	(1)
56*0Sstevel@tonic-gate #endif
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate #ifndef	FALSE
59*0Sstevel@tonic-gate #define	FALSE	(0)
60*0Sstevel@tonic-gate #endif
61*0Sstevel@tonic-gate 
62*0Sstevel@tonic-gate /*
63*0Sstevel@tonic-gate  * Exit codes
64*0Sstevel@tonic-gate  *	EX_OK		All went well
65*0Sstevel@tonic-gate  *	EX_ERROR	Usage or internal error
66*0Sstevel@tonic-gate  *	EX_DEVTAB	Had trouble accessing/reading/writing the device table
67*0Sstevel@tonic-gate  *	EX_EXISTS	The specified alias already exists
68*0Sstevel@tonic-gate  *	EX_ATTRIB	One or more attributes requested for removal was not
69*0Sstevel@tonic-gate  *			defined for the device
70*0Sstevel@tonic-gate  *	EX_RELPATH	Pathname supplied for cdevice, bdevice or pathname
71*0Sstevel@tonic-gate  *			attributes was not a full pathname
72*0Sstevel@tonic-gate  */
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate #define	EX_OK		0
75*0Sstevel@tonic-gate #define	EX_ERROR	1
76*0Sstevel@tonic-gate #define	EX_DEVTAB	2
77*0Sstevel@tonic-gate #define	EX_EXISTS	3
78*0Sstevel@tonic-gate #define	EX_ATTRIB	4
79*0Sstevel@tonic-gate #define	EX_RELPATH	4
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 
82*0Sstevel@tonic-gate /*
83*0Sstevel@tonic-gate  * Error messages
84*0Sstevel@tonic-gate  */
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate #define	E_USAGE		"usage: putdev -a alias [attribute=value [...]]\n       putdev -m device attribute=value [attribute=value [...]]\n       putdev -d device [attribute [...]]"
87*0Sstevel@tonic-gate #define	E_ALIASIS	"Alias already exists in table: %s"
88*0Sstevel@tonic-gate #define	E_NODEV		"Device does not exist in table: %s"
89*0Sstevel@tonic-gate #define	E_NOALIAS	"Cannot use \"alias\" as an attribute"
90*0Sstevel@tonic-gate #define	E_NOATTR	"Attribute not found: %s"
91*0Sstevel@tonic-gate #define	E_NODEVTAB	"Cannot open the device table: %s"
92*0Sstevel@tonic-gate #define	E_NOMKDTAB	"Cannot create a new device table: %s"
93*0Sstevel@tonic-gate #define	E_INVALIAS	"Not a valid device alias: %s"
94*0Sstevel@tonic-gate #define E_MULTIPLE	"Multiple definitions of an attribute are not allowed."
95*0Sstevel@tonic-gate #define	E_INTERNAL	"Internal error, errno=%d"
96*0Sstevel@tonic-gate #define	E_RELPATH	"Full pathname required for cdevice,bdevice and pathname attributes."
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * Macros
101*0Sstevel@tonic-gate  *	stdmsg(r,l,s,t)	    Using fmtmsg(), write a standard message to the
102*0Sstevel@tonic-gate  *			    standard error stream.
103*0Sstevel@tonic-gate  *			    Where:
104*0Sstevel@tonic-gate  *				r   The recoverability of the error
105*0Sstevel@tonic-gate  *				l   The label-component
106*0Sstevel@tonic-gate  *				s   The severity-component
107*0Sstevel@tonic-gate  *				t   The text-component
108*0Sstevel@tonic-gate  */
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate #define stdmsg(r,l,s,t) (void) fmtmsg(MM_PRINT|MM_UTIL|r,l,s,t,MM_NULLACT,MM_NULLTAG)
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /*
114*0Sstevel@tonic-gate  * Static data
115*0Sstevel@tonic-gate  *	msg		Space for message's text-component
116*0Sstevel@tonic-gate  */
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate static	char		msg[256];	/* Space for text of message */
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate /*
121*0Sstevel@tonic-gate  * char *mklbl(cmd)
122*0Sstevel@tonic-gate  *	char   *cmd
123*0Sstevel@tonic-gate  *
124*0Sstevel@tonic-gate  *	This function builds a standard label from the command used to invoke
125*0Sstevel@tonic-gate  *	this process and the standard label prefix ("UX:")
126*0Sstevel@tonic-gate  *
127*0Sstevel@tonic-gate  * Arguments:
128*0Sstevel@tonic-gate  *	char *cmd	The command used to invoke this process.
129*0Sstevel@tonic-gate  *
130*0Sstevel@tonic-gate  * Returns:  char *
131*0Sstevel@tonic-gate  *	Pointer to malloc()ed space containing the standard label,
132*0Sstevel@tonic-gate  *	or (char *) NULL if an error occurred.
133*0Sstevel@tonic-gate  */
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate static char *
136*0Sstevel@tonic-gate mklbl(cmd)
137*0Sstevel@tonic-gate 	char   *cmd;
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	/* Automatic data */
140*0Sstevel@tonic-gate 	char   *rtn;		/* Value to return */
141*0Sstevel@tonic-gate 	char   *p;		/* Temporary */
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate 	/* Find the 1st char of the basename of the command */
144*0Sstevel@tonic-gate 	if (p = strrchr(cmd, '/')) p++;
145*0Sstevel@tonic-gate 	else p = cmd;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	/* Allocate and build the string value to return */
148*0Sstevel@tonic-gate 	if (rtn = (char *) malloc(strlen("UX:")+strlen(p)+1)) {
149*0Sstevel@tonic-gate 	    (void) strcpy(rtn, "UX:");
150*0Sstevel@tonic-gate 	    (void) strcat(rtn, p);
151*0Sstevel@tonic-gate 	}
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 
154*0Sstevel@tonic-gate 	/* Now that we've done all of that work, change the environment
155*0Sstevel@tonic-gate 	 * so that only the text-component is written by fmtmsg().
156*0Sstevel@tonic-gate 	 * (This should go away in SVR4.1)
157*0Sstevel@tonic-gate 	 */
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate 	(void) putenv("MSGVERB=text");
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	/* Done */
163*0Sstevel@tonic-gate 	return(rtn);
164*0Sstevel@tonic-gate }
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate /*
167*0Sstevel@tonic-gate  * putdev -a alias [attribute=value [...]]
168*0Sstevel@tonic-gate  * putdev -m alias attribute=value [attribute=value [...]]
169*0Sstevel@tonic-gate  * putdev -d alias [attribute [...]]
170*0Sstevel@tonic-gate  *
171*0Sstevel@tonic-gate  * 	Modify the device-table.  If -a specified, add a record for <alias>
172*0Sstevel@tonic-gate  * 	to the table.  If -m specified, modify the attributes specified for
173*0Sstevel@tonic-gate  *	the <device> specified.  If -d specified, remove the specified
174*0Sstevel@tonic-gate  *	attributes from the specified device or remove the specified device.
175*0Sstevel@tonic-gate  *
176*0Sstevel@tonic-gate  * Options:
177*0Sstevel@tonic-gate  *	-a		Add an alias description to the device table
178*0Sstevel@tonic-gate  *	-m		Modify an existing device description
179*0Sstevel@tonic-gate  *	-d		(if no attributes specified) remove the specified
180*0Sstevel@tonic-gate  *			device from the device table, or (if attributes
181*0Sstevel@tonic-gate  *			specified) remove the specified attributes from
182*0Sstevel@tonic-gate  *			the specified device.
183*0Sstevel@tonic-gate  *
184*0Sstevel@tonic-gate  * Exit values:
185*0Sstevel@tonic-gate  *	0		All went well
186*0Sstevel@tonic-gate  *	1		Usage error (includes specifying "alias" as an
187*0Sstevel@tonic-gate  *			<attribute>)
188*0Sstevel@tonic-gate  *	2		The device table file could not be opened, read
189*0Sstevel@tonic-gate  *			or modified
190*0Sstevel@tonic-gate  *	3		If -a, the alias already exists.  Otherwise, the
191*0Sstevel@tonic-gate  *			specified device does not exist in the table
192*0Sstevel@tonic-gate  *	4		One of the specified attributes did not exist
193*0Sstevel@tonic-gate  *			for the device and therefore wasn't removed
194*0Sstevel@tonic-gate  */
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate main(argc, argv)
197*0Sstevel@tonic-gate 	int	argc;			/* Argument count */
198*0Sstevel@tonic-gate 	char   *argv[];			/* Argument list */
199*0Sstevel@tonic-gate {
200*0Sstevel@tonic-gate 	/* Automatic data */
201*0Sstevel@tonic-gate 	char	      **plist;		/* Ptr to list of undef'nd attrs */
202*0Sstevel@tonic-gate 	char	       *lbl;		/* Ptr to label for messages */
203*0Sstevel@tonic-gate 	char	       *alias;		/* Ptr to <alias> on command-line */
204*0Sstevel@tonic-gate 	char	       *device;		/* Ptr to <device> on command-line */
205*0Sstevel@tonic-gate 	char	       *p;		/* Temp ptr to char */
206*0Sstevel@tonic-gate 	int		noerr;		/* FLAG, TRUE if all's well */
207*0Sstevel@tonic-gate 	int		a_seen;		/* TRUE if -a seen on command-line */
208*0Sstevel@tonic-gate 	int		m_seen;		/* TRUE if -m seen on command-line */
209*0Sstevel@tonic-gate 	int		d_seen;		/* TRUE if -a seen on command-line */
210*0Sstevel@tonic-gate 	int		optchar;	/* Option extracted */
211*0Sstevel@tonic-gate 	int		exitcd;		/* Value to return at exit */
212*0Sstevel@tonic-gate 	int		nattrs;		/* Number of attributes on command */
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 
215*0Sstevel@tonic-gate 	/* Generate the label for messages */
216*0Sstevel@tonic-gate 	lbl = mklbl(argv[0]);
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 	/* Extract arguments - validate usage */
219*0Sstevel@tonic-gate 	noerr = TRUE;
220*0Sstevel@tonic-gate 	a_seen = FALSE;
221*0Sstevel@tonic-gate 	m_seen = FALSE;
222*0Sstevel@tonic-gate 	d_seen = FALSE;
223*0Sstevel@tonic-gate 	opterr = FALSE;
224*0Sstevel@tonic-gate 	while ((optchar = getopt(argc, argv, "a:d:m:")) != EOF) switch (optchar) {
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate 	case 'a':
227*0Sstevel@tonic-gate 	    if (!(a_seen || m_seen || d_seen)) {
228*0Sstevel@tonic-gate 		a_seen = TRUE;
229*0Sstevel@tonic-gate 		alias = optarg;
230*0Sstevel@tonic-gate 	    }
231*0Sstevel@tonic-gate 	    else noerr = FALSE;
232*0Sstevel@tonic-gate 	    break;
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate 	case 'd':
235*0Sstevel@tonic-gate 	    if (!(a_seen || m_seen || d_seen)) {
236*0Sstevel@tonic-gate 		d_seen = TRUE;
237*0Sstevel@tonic-gate 		device = optarg;
238*0Sstevel@tonic-gate 	    }
239*0Sstevel@tonic-gate 	    else noerr = FALSE;
240*0Sstevel@tonic-gate 	    break;
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	case 'm':
243*0Sstevel@tonic-gate 	    if (!(a_seen || m_seen || d_seen)) {
244*0Sstevel@tonic-gate 		m_seen = TRUE;
245*0Sstevel@tonic-gate 		device = optarg;
246*0Sstevel@tonic-gate 	    }
247*0Sstevel@tonic-gate 	    else noerr = FALSE;
248*0Sstevel@tonic-gate 	    break;
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 	case '?':
251*0Sstevel@tonic-gate 	default:
252*0Sstevel@tonic-gate 	    noerr = FALSE;
253*0Sstevel@tonic-gate 	}
254*0Sstevel@tonic-gate 
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate 	/* Write a usage message if we've seen a blatant error */
257*0Sstevel@tonic-gate 	if (!(a_seen || m_seen || d_seen) || !noerr) {
258*0Sstevel@tonic-gate 	    stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
259*0Sstevel@tonic-gate 	    exit(EX_ERROR);
260*0Sstevel@tonic-gate 	}
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	/* Set up */
264*0Sstevel@tonic-gate 	exitcd = EX_OK;
265*0Sstevel@tonic-gate 	nattrs = argc - optind;
266*0Sstevel@tonic-gate 
267*0Sstevel@tonic-gate 
268*0Sstevel@tonic-gate 	/*  putdev -a alias [attr=value [...]] */
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	if (a_seen) {
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	    /* Syntax check */
273*0Sstevel@tonic-gate 	    if (nattrs < 0) {
274*0Sstevel@tonic-gate 		stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
275*0Sstevel@tonic-gate 		exitcd = EX_ERROR;
276*0Sstevel@tonic-gate 	    } else {
277*0Sstevel@tonic-gate 
278*0Sstevel@tonic-gate 		/* Attempt to add the new alias */
279*0Sstevel@tonic-gate 		if (!(_adddevtabrec(alias, &argv[optind]))) {
280*0Sstevel@tonic-gate 
281*0Sstevel@tonic-gate 		    /* Attempt failed.  Write appropriate error message. */
282*0Sstevel@tonic-gate 
283*0Sstevel@tonic-gate 		    switch(errno) {
284*0Sstevel@tonic-gate 
285*0Sstevel@tonic-gate 		    /*
286*0Sstevel@tonic-gate 		     * EINVAL indicates that <alias> is not valid or "alias"
287*0Sstevel@tonic-gate 		     * was mentioned as <attr> in <attr>=<value> pair.  If the
288*0Sstevel@tonic-gate 		     * alias is a valid alias, assume that's the problem.
289*0Sstevel@tonic-gate 		     */
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 		    case EINVAL:
292*0Sstevel@tonic-gate 			if (_validalias(alias))
293*0Sstevel@tonic-gate 			    p = E_NOALIAS;
294*0Sstevel@tonic-gate 			else (void) snprintf(p=msg, sizeof(msg), E_INVALIAS, alias);
295*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, p);
296*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
297*0Sstevel@tonic-gate 			break;
298*0Sstevel@tonic-gate 
299*0Sstevel@tonic-gate 		    /*
300*0Sstevel@tonic-gate 		     * EEXIST indicates that the alias <alias> already exists
301*0Sstevel@tonic-gate 		     * in the device table.
302*0Sstevel@tonic-gate 		     */
303*0Sstevel@tonic-gate 
304*0Sstevel@tonic-gate 		    case EEXIST:
305*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_ALIASIS, alias);
306*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
307*0Sstevel@tonic-gate 			exitcd = EX_EXISTS;
308*0Sstevel@tonic-gate 			break;
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 		    /*
311*0Sstevel@tonic-gate 		     * EACCES and ENOENT indicate problems reading or writing
312*0Sstevel@tonic-gate 		     * the device table.
313*0Sstevel@tonic-gate 		     */
314*0Sstevel@tonic-gate 
315*0Sstevel@tonic-gate 		    case EACCES:
316*0Sstevel@tonic-gate 		    case ENOENT:
317*0Sstevel@tonic-gate 	                p = _devtabpath();
318*0Sstevel@tonic-gate 			if (access(p, R_OK) == 0)
319*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
320*0Sstevel@tonic-gate 			else
321*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
322*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
323*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
324*0Sstevel@tonic-gate 			break;
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 		    /*
327*0Sstevel@tonic-gate 		     * EAGAIN indicates that an attribute was defined on the
328*0Sstevel@tonic-gate 		     * command line more than once.
329*0Sstevel@tonic-gate 		     */
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 		    case EAGAIN:
332*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, E_MULTIPLE);
333*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
334*0Sstevel@tonic-gate 			break;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 		    /*
337*0Sstevel@tonic-gate 		     * ENXIO indicates that a relative pathname was supplied
338*0Sstevel@tonic-gate 		     * for the cdevice, bdevice or pathname attributes.  Full
339*0Sstevel@tonic-gate 		     * pathnames are required for these attributes.
340*0Sstevel@tonic-gate 		     */
341*0Sstevel@tonic-gate 		    case ENXIO:
342*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, E_RELPATH);
343*0Sstevel@tonic-gate 			exitcd = EX_RELPATH;
344*0Sstevel@tonic-gate 			break;
345*0Sstevel@tonic-gate 
346*0Sstevel@tonic-gate 		    /*
347*0Sstevel@tonic-gate 		     * Some other problem (odd?)
348*0Sstevel@tonic-gate 		     */
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 		    default:
351*0Sstevel@tonic-gate 			(void) sprintf(msg, E_INTERNAL, errno);
352*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
353*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
354*0Sstevel@tonic-gate 		    }
355*0Sstevel@tonic-gate 		}
356*0Sstevel@tonic-gate 	    }
357*0Sstevel@tonic-gate 	}   /* End -a case */
358*0Sstevel@tonic-gate 
359*0Sstevel@tonic-gate 
360*0Sstevel@tonic-gate 	/* putdev -m device attr=value [...] */
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	else if (m_seen) {
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	    /* Check usage */
365*0Sstevel@tonic-gate 
366*0Sstevel@tonic-gate 	    if (nattrs <= 0) {
367*0Sstevel@tonic-gate 		stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
368*0Sstevel@tonic-gate 		exitcd = EX_ERROR;
369*0Sstevel@tonic-gate 	    } else {
370*0Sstevel@tonic-gate 
371*0Sstevel@tonic-gate 		/* Attempt to modify a device's record */
372*0Sstevel@tonic-gate 		if (!(_moddevtabrec(device, &argv[optind]))) {
373*0Sstevel@tonic-gate 
374*0Sstevel@tonic-gate 		    /* Modification attempt failed */
375*0Sstevel@tonic-gate 
376*0Sstevel@tonic-gate 		    switch(errno) {
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 		    /*
379*0Sstevel@tonic-gate 		     * EINVAL indicates that "alias" was used as an attribute
380*0Sstevel@tonic-gate 		     * in an <attr>=<value> pair.
381*0Sstevel@tonic-gate 		     */
382*0Sstevel@tonic-gate 
383*0Sstevel@tonic-gate 		    case EINVAL:
384*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, E_NOALIAS);
385*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
386*0Sstevel@tonic-gate 			break;
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 		    /*
389*0Sstevel@tonic-gate 		     * ENODEV indicates that the device that was to
390*0Sstevel@tonic-gate 		     * be modified doesn't exist.
391*0Sstevel@tonic-gate 		     */
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate 		    case ENODEV:
394*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_NODEV, device);
395*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
396*0Sstevel@tonic-gate 			exitcd = EX_EXISTS;
397*0Sstevel@tonic-gate 			break;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 		    /*
400*0Sstevel@tonic-gate 		     * ENOENT indicates that the device-table doesn't exist.
401*0Sstevel@tonic-gate 		     */
402*0Sstevel@tonic-gate 
403*0Sstevel@tonic-gate 		    case ENOENT:
404*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath());
405*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
406*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
407*0Sstevel@tonic-gate 			break;
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 		    /*
410*0Sstevel@tonic-gate 		     * EACCES indicates that there was a problem reading the
411*0Sstevel@tonic-gate 		     * old device table or creating the new table.  If the
412*0Sstevel@tonic-gate 		     * old table is readable, assume that we can't create the
413*0Sstevel@tonic-gate 		     * new table.  Otherwise, assume that the old table isn't
414*0Sstevel@tonic-gate 		     * accessible.
415*0Sstevel@tonic-gate 		     */
416*0Sstevel@tonic-gate 
417*0Sstevel@tonic-gate 		    case EACCES:
418*0Sstevel@tonic-gate 	                p = _devtabpath();
419*0Sstevel@tonic-gate 			if (access(p, R_OK) == 0)
420*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
421*0Sstevel@tonic-gate 			else
422*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
423*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
424*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
425*0Sstevel@tonic-gate 			break;
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 		    /*
428*0Sstevel@tonic-gate 		     * EAGAIN indicates that an attribute was specified more than
429*0Sstevel@tonic-gate 		     * once on the command line.
430*0Sstevel@tonic-gate 		     */
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 		    case EAGAIN:
433*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, E_MULTIPLE);
434*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
435*0Sstevel@tonic-gate 			break;
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 		    /*
438*0Sstevel@tonic-gate 		     * ENXIO indicates that a relative pathname was supplied
439*0Sstevel@tonic-gate 		     * for the cdevice, bdevice or pathname attributes.  Full
440*0Sstevel@tonic-gate 		     * pathnames are required for these attributes.
441*0Sstevel@tonic-gate 		     */
442*0Sstevel@tonic-gate 		    case ENXIO:
443*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, E_RELPATH);
444*0Sstevel@tonic-gate 			exitcd = EX_RELPATH;
445*0Sstevel@tonic-gate 			break;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 		    /*
448*0Sstevel@tonic-gate 		     * Some strange problem...
449*0Sstevel@tonic-gate 		     */
450*0Sstevel@tonic-gate 
451*0Sstevel@tonic-gate 		    default:
452*0Sstevel@tonic-gate 			(void) sprintf(msg, E_INTERNAL, errno);
453*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
454*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
455*0Sstevel@tonic-gate 		    }
456*0Sstevel@tonic-gate 		}
457*0Sstevel@tonic-gate 	    }
458*0Sstevel@tonic-gate 	}   /* End -m case */
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 	else if (d_seen) {
461*0Sstevel@tonic-gate 
462*0Sstevel@tonic-gate 	    /* putdev -d device [attr [...]] */
463*0Sstevel@tonic-gate 
464*0Sstevel@tonic-gate 	    /* Check usage */
465*0Sstevel@tonic-gate 	    if (nattrs < 0) {
466*0Sstevel@tonic-gate 		stdmsg(MM_NRECOV, lbl, MM_ERROR, E_USAGE);
467*0Sstevel@tonic-gate 		exitcd = EX_ERROR;
468*0Sstevel@tonic-gate 	    } else {
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 		/*
471*0Sstevel@tonic-gate 		 * Determine case (removing a device or attributes
472*0Sstevel@tonic-gate 		 * to a device.
473*0Sstevel@tonic-gate 		 */
474*0Sstevel@tonic-gate 
475*0Sstevel@tonic-gate 		if (nattrs == 0) {
476*0Sstevel@tonic-gate 
477*0Sstevel@tonic-gate 		    /* putdev -d device */
478*0Sstevel@tonic-gate 
479*0Sstevel@tonic-gate 		    /* Attempt to remove the specified device */
480*0Sstevel@tonic-gate 		    if (!(_rmdevtabrec(device))) switch(errno) {
481*0Sstevel@tonic-gate 
482*0Sstevel@tonic-gate 			/*
483*0Sstevel@tonic-gate 			 * ENODEV indicates that the named device is not
484*0Sstevel@tonic-gate 			 * defined in the device table.
485*0Sstevel@tonic-gate 			 */
486*0Sstevel@tonic-gate 
487*0Sstevel@tonic-gate 		    case ENODEV:
488*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_NODEV, device);
489*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
490*0Sstevel@tonic-gate 			exitcd = EX_EXISTS;
491*0Sstevel@tonic-gate 			break;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 			/*
494*0Sstevel@tonic-gate 			 * ENOENT indicates that the device table can't
495*0Sstevel@tonic-gate 			 * be found.
496*0Sstevel@tonic-gate 			 */
497*0Sstevel@tonic-gate 
498*0Sstevel@tonic-gate 		    case ENOENT:
499*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath());
500*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
501*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
502*0Sstevel@tonic-gate 			break;
503*0Sstevel@tonic-gate 
504*0Sstevel@tonic-gate 			/*
505*0Sstevel@tonic-gate 			 * EACCES indicates that there was a problem reading the
506*0Sstevel@tonic-gate 			 * old device table or creating the new table.  If the
507*0Sstevel@tonic-gate 			 * old table is readable, assume that we can't create the
508*0Sstevel@tonic-gate 			 * new table.  Otherwise, assume that the old table isn't
509*0Sstevel@tonic-gate 			 * accessible.
510*0Sstevel@tonic-gate 			 */
511*0Sstevel@tonic-gate 
512*0Sstevel@tonic-gate 		    case EACCES:
513*0Sstevel@tonic-gate 			p = _devtabpath();
514*0Sstevel@tonic-gate 			if (access(p, R_OK) == 0)
515*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
516*0Sstevel@tonic-gate 			else
517*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
518*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
519*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
520*0Sstevel@tonic-gate 			break;
521*0Sstevel@tonic-gate 
522*0Sstevel@tonic-gate 			/*
523*0Sstevel@tonic-gate 			 * Some strange problem...
524*0Sstevel@tonic-gate 			 */
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 		    default:
527*0Sstevel@tonic-gate 			(void) sprintf(msg, E_INTERNAL, errno);
528*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
529*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 		    }   /* End switch */
532*0Sstevel@tonic-gate 		}
533*0Sstevel@tonic-gate 		else {
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate 		    /* putdev -d device attr [attr [...]] */
536*0Sstevel@tonic-gate 
537*0Sstevel@tonic-gate 		    /*
538*0Sstevel@tonic-gate 		     * Attempt to remove the specified attributes from the
539*0Sstevel@tonic-gate 		     * specified device.
540*0Sstevel@tonic-gate 		     */
541*0Sstevel@tonic-gate 		    if (!(_rmdevtabattrs(device, &argv[optind], &plist))) switch(errno) {
542*0Sstevel@tonic-gate 
543*0Sstevel@tonic-gate 			/*
544*0Sstevel@tonic-gate 			 * EINVAL indicates that a named attribute was not
545*0Sstevel@tonic-gate 			 * defined for the specified device or "alias" was
546*0Sstevel@tonic-gate 			 * requested.  If "plist" points to a list of attrs,
547*0Sstevel@tonic-gate 			 * the former is the problem.  Otherwise, the latter
548*0Sstevel@tonic-gate 			 * is the problem.
549*0Sstevel@tonic-gate 			 */
550*0Sstevel@tonic-gate 
551*0Sstevel@tonic-gate 		    case EINVAL:
552*0Sstevel@tonic-gate 			if (plist) {
553*0Sstevel@tonic-gate 			    exitcd = EX_ATTRIB;
554*0Sstevel@tonic-gate 			    for (; *plist; plist++) {
555*0Sstevel@tonic-gate 				(void) snprintf(msg, sizeof(msg), E_NOATTR, *plist);
556*0Sstevel@tonic-gate 				stdmsg(MM_RECOVER, lbl, MM_WARNING, msg);
557*0Sstevel@tonic-gate 			    }
558*0Sstevel@tonic-gate 			} else {
559*0Sstevel@tonic-gate 			    stdmsg(MM_NRECOV, lbl, MM_ERROR, E_NOALIAS);
560*0Sstevel@tonic-gate 			    exitcd = EX_ERROR;
561*0Sstevel@tonic-gate 			}
562*0Sstevel@tonic-gate 			break;
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 			/*
565*0Sstevel@tonic-gate 			 * ENODEV indicates that the named device is not
566*0Sstevel@tonic-gate 			 * defined in the device table.
567*0Sstevel@tonic-gate 			 */
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 		    case ENODEV:
570*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_NODEV, device);
571*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
572*0Sstevel@tonic-gate 			exitcd = EX_EXISTS;
573*0Sstevel@tonic-gate 			break;
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 			/*
576*0Sstevel@tonic-gate 			 * ENOENT indicates that the device table can't
577*0Sstevel@tonic-gate 			 * be found.
578*0Sstevel@tonic-gate 			 */
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		    case ENOENT:
581*0Sstevel@tonic-gate 			(void) snprintf(msg, sizeof(msg), E_NODEVTAB, _devtabpath());
582*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
583*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
584*0Sstevel@tonic-gate 			break;
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate 			/*
587*0Sstevel@tonic-gate 			 * EACCES indicates that there was a problem reading the
588*0Sstevel@tonic-gate 			 * old device table or creating the new table.  If the
589*0Sstevel@tonic-gate 			 * old table is readable, assume that we can't create the
590*0Sstevel@tonic-gate 			 * new table.  Otherwise, assume that the old table isn't
591*0Sstevel@tonic-gate 			 * accessible.
592*0Sstevel@tonic-gate 			 */
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 		    case EACCES:
595*0Sstevel@tonic-gate 			p = _devtabpath();
596*0Sstevel@tonic-gate 			if (access(p, R_OK) == 0)
597*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NOMKDTAB, p);
598*0Sstevel@tonic-gate 			else
599*0Sstevel@tonic-gate 			    (void) snprintf(msg, sizeof(msg), E_NODEVTAB, p);
600*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
601*0Sstevel@tonic-gate 			exitcd = EX_DEVTAB;
602*0Sstevel@tonic-gate 			break;
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 			/*
605*0Sstevel@tonic-gate 			 * Some strange problem...
606*0Sstevel@tonic-gate 			 */
607*0Sstevel@tonic-gate 
608*0Sstevel@tonic-gate 		    default:
609*0Sstevel@tonic-gate 			(void) sprintf(msg, E_INTERNAL, errno);
610*0Sstevel@tonic-gate 			stdmsg(MM_NRECOV, lbl, MM_ERROR, msg);
611*0Sstevel@tonic-gate 			exitcd = EX_ERROR;
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 		    }  /* End switch */
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 		}   /* End "putdev -d device attr [...]" case */
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 	    }   /* End passes usage-check case */
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	}   /* End -d case */
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 
622*0Sstevel@tonic-gate 	/* Done.  Return exit code (determined above) */
623*0Sstevel@tonic-gate 	return(exitcd);
624*0Sstevel@tonic-gate }  /* main() */
625