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