xref: /onnv-gate/usr/src/cmd/allocate/add_allocatable.c (revision 4746:0bc0c48f4304)
1*4746Srica /*
2*4746Srica  * CDDL HEADER START
3*4746Srica  *
4*4746Srica  * The contents of this file are subject to the terms of the
5*4746Srica  * Common Development and Distribution License (the "License").
6*4746Srica  * You may not use this file except in compliance with the License.
7*4746Srica  *
8*4746Srica  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4746Srica  * or http://www.opensolaris.org/os/licensing.
10*4746Srica  * See the License for the specific language governing permissions
11*4746Srica  * and limitations under the License.
12*4746Srica  *
13*4746Srica  * When distributing Covered Code, include this CDDL HEADER in each
14*4746Srica  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4746Srica  * If applicable, add the following below this CDDL HEADER, with the
16*4746Srica  * fields enclosed by brackets "[]" replaced with your own identifying
17*4746Srica  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4746Srica  *
19*4746Srica  * CDDL HEADER END
20*4746Srica  */
21*4746Srica 
22*4746Srica /*
23*4746Srica  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*4746Srica  * Use is subject to license terms.
25*4746Srica  */
26*4746Srica 
27*4746Srica #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*4746Srica 
29*4746Srica /*
30*4746Srica  * add_allocatable -
31*4746Srica  *	a command-line interface to add device to device_allocate and
32*4746Srica  *	device_maps.
33*4746Srica  */
34*4746Srica 
35*4746Srica #ifndef	__EXTENSIONS__
36*4746Srica #define	__EXTENSIONS__		/* needed for _strtok_r */
37*4746Srica #endif
38*4746Srica 
39*4746Srica #include <sys/types.h>
40*4746Srica #include <unistd.h>
41*4746Srica #include <stdlib.h>
42*4746Srica #include <strings.h>
43*4746Srica #include <string.h>
44*4746Srica #include <locale.h>
45*4746Srica #include <libintl.h>
46*4746Srica #include <pwd.h>
47*4746Srica #include <nss_dbdefs.h>
48*4746Srica #include <auth_attr.h>
49*4746Srica #include <auth_list.h>
50*4746Srica #include <zone.h>
51*4746Srica #include <tsol/label.h>
52*4746Srica #include <bsm/devices.h>
53*4746Srica #include <bsm/devalloc.h>
54*4746Srica 
55*4746Srica #define	NO_OVERRIDE	-1
56*4746Srica 
57*4746Srica int check_args(da_args *);
58*4746Srica int process_args(int, char **, da_args *, char *);
59*4746Srica int scan_label(char *, char *);
60*4746Srica void usage(da_args *, char *);
61*4746Srica 
62*4746Srica int system_labeled = 0;
63*4746Srica 
64*4746Srica int
main(int argc,char * argv[])65*4746Srica main(int argc, char *argv[])
66*4746Srica {
67*4746Srica 	int		rc;
68*4746Srica 	uid_t		uid;
69*4746Srica 	char		*progname;
70*4746Srica 	char		pwbuf[NSS_LINELEN_PASSWD];
71*4746Srica 	struct passwd	pwd;
72*4746Srica 	da_args		dargs;
73*4746Srica 	devinfo_t	devinfo;
74*4746Srica 
75*4746Srica 	(void) setlocale(LC_ALL, "");
76*4746Srica #if !defined(TEXT_DOMAIN)
77*4746Srica #define	TEXT_DOMAIN	"SYS_TEST"
78*4746Srica #endif
79*4746Srica 	(void) textdomain(TEXT_DOMAIN);
80*4746Srica 	if ((progname = strrchr(argv[0], '/')) == NULL)
81*4746Srica 		progname = argv[0];
82*4746Srica 	else
83*4746Srica 		progname++;
84*4746Srica 
85*4746Srica 	system_labeled = is_system_labeled();
86*4746Srica 	if (system_labeled) {
87*4746Srica 		/*
88*4746Srica 		 * this command can be run only in the global zone.
89*4746Srica 		 */
90*4746Srica 		if (getzoneid() != GLOBAL_ZONEID) {
91*4746Srica 			(void) fprintf(stderr, "%s%s", progname,
92*4746Srica 			    gettext(" : must be run in global zone\n"));
93*4746Srica 			exit(1);
94*4746Srica 		}
95*4746Srica 	} else {
96*4746Srica 		/*
97*4746Srica 		 * this command works in Trusted Extensions only.
98*4746Srica 		 */
99*4746Srica 		(void) fprintf(stderr, "%s%s", progname,
100*4746Srica 		    gettext(" : need to install Trusted Extensions\n"));
101*4746Srica 		exit(1);
102*4746Srica 	}
103*4746Srica 
104*4746Srica 	dargs.optflag = 0;
105*4746Srica 	dargs.rootdir = NULL;
106*4746Srica 	dargs.devnames = NULL;
107*4746Srica 	dargs.devinfo = &devinfo;
108*4746Srica 
109*4746Srica 	if (strcmp(progname, "add_allocatable") == 0) {
110*4746Srica 		dargs.optflag |= DA_ADD;
111*4746Srica 	} else if (strcmp(progname, "remove_allocatable") == 0) {
112*4746Srica 		dargs.optflag |= DA_REMOVE;
113*4746Srica 	} else {
114*4746Srica 		usage(&dargs, progname);
115*4746Srica 		exit(1);
116*4746Srica 	}
117*4746Srica 
118*4746Srica 	uid = getuid();
119*4746Srica 	if ((getpwuid_r(uid, &pwd, pwbuf, sizeof (pwbuf))) == NULL) {
120*4746Srica 		(void) fprintf(stderr, "%s%s", progname,
121*4746Srica 		    gettext(" : getpwuid_r failed: "));
122*4746Srica 		(void) fprintf(stderr, "%s\n", strerror(errno));
123*4746Srica 		exit(2);
124*4746Srica 	}
125*4746Srica 
126*4746Srica 	if (chkauthattr(DEVICE_CONFIG_AUTH, pwd.pw_name) != 1) {
127*4746Srica 		(void) fprintf(stderr, "%s%s%s", progname,
128*4746Srica 		    gettext(" : user lacks authorization:  \n"),
129*4746Srica 		    DEVICE_CONFIG_AUTH);
130*4746Srica 		exit(4);
131*4746Srica 	}
132*4746Srica 
133*4746Srica 	if (process_args(argc, argv, &dargs, progname) != 0) {
134*4746Srica 		usage(&dargs, progname);
135*4746Srica 		exit(1);
136*4746Srica 	}
137*4746Srica 
138*4746Srica 	if (dargs.optflag & DA_ADD) {
139*4746Srica 		if (check_args(&dargs) == NO_OVERRIDE) {
140*4746Srica 			(void) fprintf(stderr, "%s%s%s%s", progname,
141*4746Srica 			    gettext(" : entry exists for "),
142*4746Srica 			    dargs.devinfo->devname, gettext("\n"));
143*4746Srica 			usage(&dargs, progname);
144*4746Srica 			exit(3);
145*4746Srica 		}
146*4746Srica 	}
147*4746Srica 
148*4746Srica 	if (dargs.optflag & DA_DEFATTRS)
149*4746Srica 		rc = da_update_defattrs(&dargs);
150*4746Srica 	else
151*4746Srica 		rc = da_update_device(&dargs);
152*4746Srica 
153*4746Srica 	if ((rc != 0) && (!(dargs.optflag & DA_SILENT))) {
154*4746Srica 		if (rc == -2)
155*4746Srica 			(void) fprintf(stderr, "%s%s", progname,
156*4746Srica 			    gettext(" : device name/type/list missing\n"));
157*4746Srica 		else if (dargs.optflag & DA_ADD)
158*4746Srica 			(void) fprintf(stderr, "%s%s", progname,
159*4746Srica 			    gettext(" : error adding/updating device\n"));
160*4746Srica 		else if (dargs.optflag & DA_REMOVE)
161*4746Srica 			(void) fprintf(stderr, "%s%s", progname,
162*4746Srica 			    gettext(" : error removing device\n"));
163*4746Srica 		rc = 2;	/* exit code for 'Unknown system error' in man page */
164*4746Srica 	}
165*4746Srica 
166*4746Srica 	return (rc);
167*4746Srica }
168*4746Srica 
169*4746Srica int
process_args(int argc,char ** argv,da_args * dargs,char * progname)170*4746Srica process_args(int argc, char **argv, da_args *dargs, char *progname)
171*4746Srica {
172*4746Srica 	int 		c;
173*4746Srica 	int		aflag, cflag, dflag, fflag, lflag, nflag, oflag, tflag;
174*4746Srica 	extern char	*optarg;
175*4746Srica 	devinfo_t	*devinfo;
176*4746Srica 
177*4746Srica 	devinfo = dargs->devinfo;
178*4746Srica 	aflag = cflag = dflag = fflag = lflag = nflag = oflag = tflag = 0;
179*4746Srica 	devinfo->devname = devinfo->devtype = devinfo->devauths =
180*4746Srica 	    devinfo->devexec = devinfo->devopts = devinfo->devlist = NULL;
181*4746Srica 	devinfo->instance = 0;
182*4746Srica 
183*4746Srica 	while ((c = getopt(argc, argv, "a:c:dfl:n:o:st:")) != EOF) {
184*4746Srica 		switch (c) {
185*4746Srica 		case 'a':
186*4746Srica 			devinfo->devauths = optarg;
187*4746Srica 			aflag++;
188*4746Srica 			break;
189*4746Srica 		case 'c':
190*4746Srica 			devinfo->devexec = optarg;
191*4746Srica 			if (strlen(devinfo->devexec) == 0) {
192*4746Srica 				if (!(dargs->optflag & DA_SILENT))
193*4746Srica 					(void) fprintf(stderr, "%s%s", progname,
194*4746Srica 					    gettext(" : device clean program"
195*4746Srica 					    " name not found\n"));
196*4746Srica 				return (1);
197*4746Srica 			}
198*4746Srica 			cflag++;
199*4746Srica 			break;
200*4746Srica 		case 'd':
201*4746Srica 			dargs->optflag |= DA_DEFATTRS;
202*4746Srica 			dflag++;
203*4746Srica 			break;
204*4746Srica 		case 'l':
205*4746Srica 			devinfo->devlist = optarg;
206*4746Srica 			if (strlen(devinfo->devlist) == 0) {
207*4746Srica 				if (!(dargs->optflag & DA_SILENT))
208*4746Srica 					(void) fprintf(stderr, "%s%s", progname,
209*4746Srica 					    gettext(" : device file list"
210*4746Srica 					    " not found\n"));
211*4746Srica 				return (1);
212*4746Srica 			}
213*4746Srica 			lflag++;
214*4746Srica 			break;
215*4746Srica 		case 'f':
216*4746Srica 			dargs->optflag |= DA_FORCE;
217*4746Srica 			fflag++;
218*4746Srica 			break;
219*4746Srica 		case 'n':
220*4746Srica 			devinfo->devname = optarg;
221*4746Srica 			if (strlen(devinfo->devname) == 0) {
222*4746Srica 				if (!(dargs->optflag & DA_SILENT))
223*4746Srica 					(void) fprintf(stderr, "%s%s", progname,
224*4746Srica 					    gettext(" : device name "
225*4746Srica 					    "not found\n"));
226*4746Srica 				return (1);
227*4746Srica 			}
228*4746Srica 			nflag++;
229*4746Srica 			break;
230*4746Srica 		case 'o':
231*4746Srica 			/* check for field delimiters in the option */
232*4746Srica 			if (strpbrk(optarg, ":;=") == NULL) {
233*4746Srica 				if (!(dargs->optflag & DA_SILENT)) {
234*4746Srica 					(void) fprintf(stderr, "%s%s%s",
235*4746Srica 					    progname,
236*4746Srica 					    gettext(" : invalid "
237*4746Srica 					    "key=val string: "),
238*4746Srica 					    optarg);
239*4746Srica 					(void) fprintf(stderr, "%s",
240*4746Srica 					    gettext("\n"));
241*4746Srica 				}
242*4746Srica 				return (1);
243*4746Srica 			}
244*4746Srica 			devinfo->devopts = optarg;
245*4746Srica 			if (dargs->optflag & DA_ADD) {
246*4746Srica 				if (scan_label(devinfo->devopts, progname) != 0)
247*4746Srica 					return (1);
248*4746Srica 			}
249*4746Srica 			oflag++;
250*4746Srica 			break;
251*4746Srica 		case 's':
252*4746Srica 			dargs->optflag |= DA_SILENT;
253*4746Srica 			break;
254*4746Srica 		case 't':
255*4746Srica 			devinfo->devtype = optarg;
256*4746Srica 			if (strlen(devinfo->devtype) == 0) {
257*4746Srica 				if (!(dargs->optflag & DA_SILENT))
258*4746Srica 					(void) fprintf(stderr, "%s%s", progname,
259*4746Srica 					    gettext(" : device type "
260*4746Srica 					    "not found\n"));
261*4746Srica 				return (1);
262*4746Srica 			}
263*4746Srica 			tflag++;
264*4746Srica 			break;
265*4746Srica 		default	:
266*4746Srica 			return (1);
267*4746Srica 		}
268*4746Srica 	}
269*4746Srica 
270*4746Srica 
271*4746Srica 	if (dargs->optflag & DA_ADD) {
272*4746Srica 		if (dflag) {
273*4746Srica 			/* -d requires -t, but does not like -n */
274*4746Srica 			if (nflag || tflag == 0)
275*4746Srica 				return (1);
276*4746Srica 		} else if (nflag == 0 && tflag == 0 && lflag == 0) {
277*4746Srica 			/* require at least -n or -t or -l to be specified */
278*4746Srica 			if (!(dargs->optflag & DA_SILENT))
279*4746Srica 				(void) fprintf(stderr, "%s%s", progname,
280*4746Srica 				    gettext(" : required options missing\n"));
281*4746Srica 			return (1);
282*4746Srica 		}
283*4746Srica 	} else if (dargs->optflag & DA_REMOVE) {
284*4746Srica 		if (dflag) {
285*4746Srica 			/* -d requires -t, but does not like -n */
286*4746Srica 			if (nflag || tflag == 0)
287*4746Srica 				return (1);
288*4746Srica 		} else if (nflag == 0 && tflag == 0) {
289*4746Srica 			/* require at least -n or -t to be specified */
290*4746Srica 			if (!(dargs->optflag & DA_SILENT))
291*4746Srica 				(void) fprintf(stderr, "%s%s", progname,
292*4746Srica 				    gettext(" : required options missing\n"));
293*4746Srica 			return (1);
294*4746Srica 		}
295*4746Srica 		/* there's a bunch not accepted by remove_allocatable */
296*4746Srica 		if (aflag || cflag || lflag || oflag)
297*4746Srica 			return (1);
298*4746Srica 	} else {
299*4746Srica 		return (1);
300*4746Srica 	}
301*4746Srica 
302*4746Srica 	/* check for option specified more than once */
303*4746Srica 	if (aflag > 1 || cflag > 1 || lflag > 1 || fflag > 1 ||
304*4746Srica 	    nflag > 1 || tflag > 1) {
305*4746Srica 		if (!(dargs->optflag & DA_SILENT))
306*4746Srica 			(void) fprintf(stderr, "%s%s", progname,
307*4746Srica 			    gettext(" : multiple-defined options\n"));
308*4746Srica 		return (1);
309*4746Srica 	}
310*4746Srica 
311*4746Srica 	return (0);
312*4746Srica }
313*4746Srica 
314*4746Srica int
verify_label(char * token,char * progname)315*4746Srica verify_label(char *token, char *progname)
316*4746Srica {
317*4746Srica 	int		error = 0;
318*4746Srica 	char		*p, *val, *str;
319*4746Srica 
320*4746Srica 	if ((strstr(token, DAOPT_MINLABEL) == NULL) &&
321*4746Srica 	    (strstr(token, DAOPT_MAXLABEL) == NULL)) {
322*4746Srica 		/* no label specified */
323*4746Srica 		return (0);
324*4746Srica 	}
325*4746Srica 	if ((val = strchr(token, '=')) == NULL)
326*4746Srica 		return (1);
327*4746Srica 	val++;
328*4746Srica 	/*
329*4746Srica 	 * if non-default labels are specified, check if they are correct
330*4746Srica 	 */
331*4746Srica 	if ((strcmp(val, DA_DEFAULT_MIN) != 0) &&
332*4746Srica 	    (strcmp(val, DA_DEFAULT_MAX) != 0)) {
333*4746Srica 		m_label_t	*slabel = NULL;
334*4746Srica 
335*4746Srica 		str = strdup(val);
336*4746Srica 		/* get rid of double quotes if they exist */
337*4746Srica 		while (*str == '"')
338*4746Srica 			str++;
339*4746Srica 		if ((p = strchr(str, '"')) != NULL)
340*4746Srica 			*p = '\0';
341*4746Srica 		if (str_to_label(str, &slabel, MAC_LABEL, L_NO_CORRECTION,
342*4746Srica 		    &error) == -1) {
343*4746Srica 			(void) fprintf(stderr, "%s%s%s", progname,
344*4746Srica 			    gettext(" : bad label input: "),
345*4746Srica 			    val);
346*4746Srica 			(void) fprintf(stderr, "%s", gettext("\n"));
347*4746Srica 			free(str);
348*4746Srica 			m_label_free(slabel);
349*4746Srica 			return (1);
350*4746Srica 		}
351*4746Srica 		free(str);
352*4746Srica 		m_label_free(slabel);
353*4746Srica 	}
354*4746Srica 
355*4746Srica 	return (0);
356*4746Srica }
357*4746Srica 
358*4746Srica int
scan_label(char * devopts,char * progname)359*4746Srica scan_label(char *devopts, char *progname)
360*4746Srica {
361*4746Srica 	char		*tok = NULL;
362*4746Srica 	char		*lasts, *optsarg;
363*4746Srica 
364*4746Srica 	if (devopts == NULL)
365*4746Srica 		return (0);
366*4746Srica 
367*4746Srica 	if ((optsarg = strdup(devopts)) == NULL)
368*4746Srica 		return (1);
369*4746Srica 
370*4746Srica 	if ((tok = strtok_r(optsarg, KV_TOKEN_DELIMIT, &lasts)) == NULL)
371*4746Srica 		return (1);
372*4746Srica 
373*4746Srica 	if (verify_label(tok, progname) != 0) {
374*4746Srica 		free(optsarg);
375*4746Srica 		return (1);
376*4746Srica 	}
377*4746Srica 
378*4746Srica 	while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, &lasts)) != NULL) {
379*4746Srica 		if (verify_label(tok, progname) != 0) {
380*4746Srica 			free(optsarg);
381*4746Srica 			return (1);
382*4746Srica 		}
383*4746Srica 	}
384*4746Srica 
385*4746Srica 	return (0);
386*4746Srica }
387*4746Srica 
388*4746Srica int
check_args(da_args * dargs)389*4746Srica check_args(da_args *dargs)
390*4746Srica {
391*4746Srica 	int		nlen;
392*4746Srica 	char		*kval, *nopts, *ntok, *nstr,
393*4746Srica 	    *defmin, *defmax, *defauths, *defexec;
394*4746Srica 	kva_t		*kva;
395*4746Srica 	devinfo_t	*devinfo;
396*4746Srica 	devalloc_t	*da = NULL;
397*4746Srica 	da_defs_t	*da_defs = NULL;
398*4746Srica 
399*4746Srica 	devinfo = dargs->devinfo;
400*4746Srica 	/*
401*4746Srica 	 * check if we're updating an existing entry without -f
402*4746Srica 	 */
403*4746Srica 	setdaent();
404*4746Srica 	da = getdanam(devinfo->devname);
405*4746Srica 	enddaent();
406*4746Srica 	if (da && !(dargs->optflag & DA_FORCE)) {
407*4746Srica 		freedaent(da);
408*4746Srica 		return (NO_OVERRIDE);
409*4746Srica 	}
410*4746Srica 	if ((devinfo->devopts == NULL) ||
411*4746Srica 	    (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) ||
412*4746Srica 	    (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) ||
413*4746Srica 	    (devinfo->devauths == NULL) ||
414*4746Srica 	    (devinfo->devexec == NULL)) {
415*4746Srica 		/* fill in defaults as required */
416*4746Srica 		defmin = DA_DEFAULT_MIN;
417*4746Srica 		defmax = DA_DEFAULT_MAX;
418*4746Srica 		defauths = DEFAULT_DEV_ALLOC_AUTH;
419*4746Srica 		defexec = DA_DEFAULT_CLEAN;
420*4746Srica 		setdadefent();
421*4746Srica 		if (da_defs = getdadeftype(devinfo->devtype)) {
422*4746Srica 			kva = da_defs->devopts;
423*4746Srica 			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
424*4746Srica 				defmin = strdup(kval);
425*4746Srica 			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
426*4746Srica 				defmax = strdup(kval);
427*4746Srica 			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
428*4746Srica 				defauths = strdup(kval);
429*4746Srica 			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
430*4746Srica 				defexec = strdup(kval);
431*4746Srica 			freedadefent(da_defs);
432*4746Srica 		}
433*4746Srica 		enddadefent();
434*4746Srica 		if (devinfo->devauths == NULL)
435*4746Srica 			devinfo->devauths = defauths;
436*4746Srica 		if (devinfo->devexec == NULL)
437*4746Srica 			devinfo->devexec = defexec;
438*4746Srica 		if (devinfo->devopts == NULL) {
439*4746Srica 			/* add default minlabel and maxlabel */
440*4746Srica 			nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
441*4746Srica 			    strlen(defmin) + strlen(KV_TOKEN_DELIMIT) +
442*4746Srica 			    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) +
443*4746Srica 			    strlen(defmax) + 1;		/* +1 for terminator */
444*4746Srica 			if (nopts = (char *)malloc(nlen)) {
445*4746Srica 				(void) snprintf(nopts, nlen, "%s%s%s%s%s%s%s",
446*4746Srica 				    DAOPT_MINLABEL, KV_ASSIGN, defmin,
447*4746Srica 				    KV_TOKEN_DELIMIT,
448*4746Srica 				    DAOPT_MAXLABEL, KV_ASSIGN, defmax);
449*4746Srica 				devinfo->devopts = nopts;
450*4746Srica 			}
451*4746Srica 		} else {
452*4746Srica 			if (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) {
453*4746Srica 				/* add default minlabel */
454*4746Srica 				ntok = DAOPT_MINLABEL;
455*4746Srica 				nstr = defmin;
456*4746Srica 				nlen = strlen(devinfo->devopts) +
457*4746Srica 				    strlen(KV_TOKEN_DELIMIT) +
458*4746Srica 				    strlen(ntok) + strlen(KV_ASSIGN) +
459*4746Srica 				    strlen(nstr) + 1;
460*4746Srica 				if (nopts = (char *)malloc(nlen)) {
461*4746Srica 					(void) snprintf(nopts, nlen,
462*4746Srica 					    "%s%s%s%s%s",
463*4746Srica 					    devinfo->devopts, KV_TOKEN_DELIMIT,
464*4746Srica 					    ntok, KV_ASSIGN, nstr);
465*4746Srica 					devinfo->devopts = nopts;
466*4746Srica 				}
467*4746Srica 			}
468*4746Srica 			if (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) {
469*4746Srica 				/* add default maxlabel */
470*4746Srica 				ntok = DAOPT_MAXLABEL;
471*4746Srica 				nstr = defmax;
472*4746Srica 				nlen = strlen(devinfo->devopts) +
473*4746Srica 				    strlen(KV_TOKEN_DELIMIT) +
474*4746Srica 				    strlen(ntok) + strlen(KV_ASSIGN) +
475*4746Srica 				    strlen(nstr) + 1;
476*4746Srica 				if (nopts = (char *)malloc(nlen)) {
477*4746Srica 					(void) snprintf(nopts, nlen,
478*4746Srica 					    "%s%s%s%s%s",
479*4746Srica 					    devinfo->devopts, KV_TOKEN_DELIMIT,
480*4746Srica 					    ntok, KV_ASSIGN, nstr);
481*4746Srica 					devinfo->devopts = nopts;
482*4746Srica 				}
483*4746Srica 			}
484*4746Srica 		}
485*4746Srica 	}
486*4746Srica 
487*4746Srica 	return (0);
488*4746Srica }
489*4746Srica 
490*4746Srica void
usage(da_args * dargs,char * progname)491*4746Srica usage(da_args *dargs, char *progname)
492*4746Srica {
493*4746Srica 	if (dargs->optflag & DA_SILENT)
494*4746Srica 		return;
495*4746Srica 	if (dargs->optflag & DA_ADD)
496*4746Srica 		(void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
497*4746Srica 		    gettext(" [-f][-s][-d] -n name -t type -l device-list"
498*4746Srica 		    "\n\t[-a authorization] [-c cleaning program] "
499*4746Srica 		    "[-o key=value]\n"));
500*4746Srica 	else if (dargs->optflag & DA_REMOVE)
501*4746Srica 		(void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
502*4746Srica 		    gettext(" [-f][-s][-d] [-n name|-t type]\n"));
503*4746Srica 	else
504*4746Srica 		(void) fprintf(stderr, gettext("Invalid usage\n"), progname);
505*4746Srica }
506