xref: /titanic_52/usr/src/cmd/modload/plcysubr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * Device policy specific subroutines.  We cannot merge them with
27*7c478bd9Sstevel@tonic-gate  * drvsubr.c because of static linking requirements.
28*7c478bd9Sstevel@tonic-gate  */
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #include <stdio.h>
33*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
34*7c478bd9Sstevel@tonic-gate #include <unistd.h>
35*7c478bd9Sstevel@tonic-gate #include <string.h>
36*7c478bd9Sstevel@tonic-gate #include <ctype.h>
37*7c478bd9Sstevel@tonic-gate #include <priv.h>
38*7c478bd9Sstevel@tonic-gate #include <string.h>
39*7c478bd9Sstevel@tonic-gate #include <libgen.h>
40*7c478bd9Sstevel@tonic-gate #include <libintl.h>
41*7c478bd9Sstevel@tonic-gate #include <errno.h>
42*7c478bd9Sstevel@tonic-gate #include <alloca.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate #include "addrem.h"
49*7c478bd9Sstevel@tonic-gate #include "errmsg.h"
50*7c478bd9Sstevel@tonic-gate #include "plcysubr.h"
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate size_t devplcysys_sz;
53*7c478bd9Sstevel@tonic-gate const priv_impl_info_t *privimplinfo;
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * New token types should be parsed in parse_plcy_entry.
57*7c478bd9Sstevel@tonic-gate  */
58*7c478bd9Sstevel@tonic-gate #define	PSET	0
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate typedef struct token {
61*7c478bd9Sstevel@tonic-gate 	const char	*token;
62*7c478bd9Sstevel@tonic-gate 	int		type;
63*7c478bd9Sstevel@tonic-gate 	ptrdiff_t	off;
64*7c478bd9Sstevel@tonic-gate } token_t;
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate static token_t toktab[] = {
67*7c478bd9Sstevel@tonic-gate 	{ DEVPLCY_TKN_RDP, PSET /* offsetof(devplcysys_t, dps_rdp) */ },
68*7c478bd9Sstevel@tonic-gate 	{ DEVPLCY_TKN_WRP, PSET /* offsetof(devplcysys_t, dps_wrp) */ },
69*7c478bd9Sstevel@tonic-gate };
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate #define	RDPOL	0
72*7c478bd9Sstevel@tonic-gate #define	WRPOL	1
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #define	NTOK	(sizeof (toktab)/sizeof (token_t))
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * Compute the size of the datastructures needed.
78*7c478bd9Sstevel@tonic-gate  */
79*7c478bd9Sstevel@tonic-gate void
80*7c478bd9Sstevel@tonic-gate devplcy_init(void)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	if ((privimplinfo = getprivimplinfo()) == NULL) {
83*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_PRIVIMPL));
84*7c478bd9Sstevel@tonic-gate 		exit(1);
85*7c478bd9Sstevel@tonic-gate 	}
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 	devplcysys_sz = DEVPLCYSYS_SZ(privimplinfo);
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate 	toktab[RDPOL].off =
90*7c478bd9Sstevel@tonic-gate 		(char *)DEVPLCYSYS_RDP((devplcysys_t *)0, privimplinfo) -
91*7c478bd9Sstevel@tonic-gate 				(char *)0;
92*7c478bd9Sstevel@tonic-gate 	toktab[WRPOL].off =
93*7c478bd9Sstevel@tonic-gate 		(char *)DEVPLCYSYS_WRP((devplcysys_t *)0, privimplinfo) -
94*7c478bd9Sstevel@tonic-gate 				(char *)0;
95*7c478bd9Sstevel@tonic-gate }
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate /*
98*7c478bd9Sstevel@tonic-gate  * Read a configuration file line and return a static buffer pointing to it.
99*7c478bd9Sstevel@tonic-gate  * It returns a static struct fileentry which has several fields:
100*7c478bd9Sstevel@tonic-gate  *	- rawbuf, which includes the lines including empty lines and comments
101*7c478bd9Sstevel@tonic-gate  * 	leading up to the file and the entry as found in the file
102*7c478bd9Sstevel@tonic-gate  *	- orgentry, pointer in rawbuf to the start of the entry proper.
103*7c478bd9Sstevel@tonic-gate  *	- entry, a pre-parsed entry, escaped newlines removed.
104*7c478bd9Sstevel@tonic-gate  *	- startline, the line number of the first line in the file
105*7c478bd9Sstevel@tonic-gate  */
106*7c478bd9Sstevel@tonic-gate fileentry_t *
107*7c478bd9Sstevel@tonic-gate fgetline(FILE *fp)
108*7c478bd9Sstevel@tonic-gate {
109*7c478bd9Sstevel@tonic-gate 	static size_t sz = BUFSIZ;
110*7c478bd9Sstevel@tonic-gate 	static struct fileentry fe;
111*7c478bd9Sstevel@tonic-gate 	static int linecnt = 1;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	char *buf = fe.rawbuf;
114*7c478bd9Sstevel@tonic-gate 	ptrdiff_t off;
115*7c478bd9Sstevel@tonic-gate 	char *p;
116*7c478bd9Sstevel@tonic-gate 	int c, lastc, i;
117*7c478bd9Sstevel@tonic-gate 
118*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
119*7c478bd9Sstevel@tonic-gate 		fe.rawbuf = buf = malloc(sz);
120*7c478bd9Sstevel@tonic-gate 		if (buf == NULL)
121*7c478bd9Sstevel@tonic-gate 			return (NULL);
122*7c478bd9Sstevel@tonic-gate 	}
123*7c478bd9Sstevel@tonic-gate 	if (fe.entry != NULL) {
124*7c478bd9Sstevel@tonic-gate 		free(fe.entry);
125*7c478bd9Sstevel@tonic-gate 		fe.orgentry = fe.entry = NULL;
126*7c478bd9Sstevel@tonic-gate 	}
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	i = 0;
129*7c478bd9Sstevel@tonic-gate 	off = -1;
130*7c478bd9Sstevel@tonic-gate 	c = '\n';
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	while (lastc = c, (c = getc(fp)) != EOF) {
133*7c478bd9Sstevel@tonic-gate 		buf[i++] = c;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 		if (i == sz) {
136*7c478bd9Sstevel@tonic-gate 			sz *= 2;
137*7c478bd9Sstevel@tonic-gate 			fe.rawbuf = buf = realloc(buf, sz);
138*7c478bd9Sstevel@tonic-gate 			if (buf == NULL)
139*7c478bd9Sstevel@tonic-gate 				return (NULL);
140*7c478bd9Sstevel@tonic-gate 		}
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 		if (c == '\n') {
143*7c478bd9Sstevel@tonic-gate 			linecnt++;
144*7c478bd9Sstevel@tonic-gate 			/* Newline, escaped or not yet processing an entry */
145*7c478bd9Sstevel@tonic-gate 			if (off == -1 || lastc == '\\')
146*7c478bd9Sstevel@tonic-gate 				continue;
147*7c478bd9Sstevel@tonic-gate 		} else if (lastc == '\n' && off == -1) {
148*7c478bd9Sstevel@tonic-gate 			/* Start of more comments */
149*7c478bd9Sstevel@tonic-gate 			if (c == '#')
150*7c478bd9Sstevel@tonic-gate 				continue;
151*7c478bd9Sstevel@tonic-gate 			/* Found start of entry */
152*7c478bd9Sstevel@tonic-gate 			off = i - 1;
153*7c478bd9Sstevel@tonic-gate 			fe.startline = linecnt;
154*7c478bd9Sstevel@tonic-gate 			continue;
155*7c478bd9Sstevel@tonic-gate 		} else
156*7c478bd9Sstevel@tonic-gate 			continue;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 		buf[i] = '\0';
159*7c478bd9Sstevel@tonic-gate 		fe.orgentry = buf + off;
160*7c478bd9Sstevel@tonic-gate 		p = fe.entry = strdup(fe.orgentry);
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 		if (p == NULL)
163*7c478bd9Sstevel@tonic-gate 			return (NULL);
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 		/* Remove <backslash><newline> */
166*7c478bd9Sstevel@tonic-gate 		if ((p = strchr(p, '\\')) != NULL) {
167*7c478bd9Sstevel@tonic-gate 			for (off = 0; (p[-off] = p[0]) != '\0'; p++)
168*7c478bd9Sstevel@tonic-gate 				if (p[0] == '\\' && p[1] == '\n') {
169*7c478bd9Sstevel@tonic-gate 					off += 2;
170*7c478bd9Sstevel@tonic-gate 					p++;
171*7c478bd9Sstevel@tonic-gate 				}
172*7c478bd9Sstevel@tonic-gate 		}
173*7c478bd9Sstevel@tonic-gate 		return (&fe);
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate 	if (lastc != '\n' || off != -1)
176*7c478bd9Sstevel@tonic-gate 		return (NULL);
177*7c478bd9Sstevel@tonic-gate 	buf[i] = '\0';
178*7c478bd9Sstevel@tonic-gate 	linecnt = 1;
179*7c478bd9Sstevel@tonic-gate 	return (&fe);
180*7c478bd9Sstevel@tonic-gate }
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate /*
183*7c478bd9Sstevel@tonic-gate  * Parse minor number ranges:
184*7c478bd9Sstevel@tonic-gate  *	(minor) or (lowminor-highminor)
185*7c478bd9Sstevel@tonic-gate  * Return 0 for success, -1 for failure.
186*7c478bd9Sstevel@tonic-gate  */
187*7c478bd9Sstevel@tonic-gate int
188*7c478bd9Sstevel@tonic-gate parse_minor_range(const char *range, minor_t *lo, minor_t *hi, char *type)
189*7c478bd9Sstevel@tonic-gate {
190*7c478bd9Sstevel@tonic-gate 	unsigned long tmp;
191*7c478bd9Sstevel@tonic-gate 	char *p;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	if (*range++ != '(')
194*7c478bd9Sstevel@tonic-gate 		return (-1);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	errno = 0;
197*7c478bd9Sstevel@tonic-gate 	tmp = strtoul(range, &p, 0);
198*7c478bd9Sstevel@tonic-gate 	if (tmp > L_MAXMIN32 || (tmp == 0 && errno != 0) ||
199*7c478bd9Sstevel@tonic-gate 	    (*p != '-' && *p != ')'))
200*7c478bd9Sstevel@tonic-gate 		return (-1);
201*7c478bd9Sstevel@tonic-gate 	*lo = tmp;
202*7c478bd9Sstevel@tonic-gate 	if (*p == '-') {
203*7c478bd9Sstevel@tonic-gate 		errno = 0;
204*7c478bd9Sstevel@tonic-gate 		tmp = strtoul(p + 1, &p, 0);
205*7c478bd9Sstevel@tonic-gate 		if (tmp > L_MAXMIN32 || (tmp == 0 && errno != 0) || *p != ')')
206*7c478bd9Sstevel@tonic-gate 			return (-1);
207*7c478bd9Sstevel@tonic-gate 	}
208*7c478bd9Sstevel@tonic-gate 	*hi = tmp;
209*7c478bd9Sstevel@tonic-gate 	if (*lo > *hi)
210*7c478bd9Sstevel@tonic-gate 		return (-1);
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	switch (p[1]) {
213*7c478bd9Sstevel@tonic-gate 	case '\0':
214*7c478bd9Sstevel@tonic-gate 		*type = '\0';
215*7c478bd9Sstevel@tonic-gate 		break;
216*7c478bd9Sstevel@tonic-gate 	case 'c':
217*7c478bd9Sstevel@tonic-gate 	case 'C':
218*7c478bd9Sstevel@tonic-gate 		*type = 'c';
219*7c478bd9Sstevel@tonic-gate 		break;
220*7c478bd9Sstevel@tonic-gate 	case 'b':
221*7c478bd9Sstevel@tonic-gate 	case 'B':
222*7c478bd9Sstevel@tonic-gate 		*type = 'b';
223*7c478bd9Sstevel@tonic-gate 		break;
224*7c478bd9Sstevel@tonic-gate 	default:
225*7c478bd9Sstevel@tonic-gate 		return (-1);
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate 	return (0);
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate static void
231*7c478bd9Sstevel@tonic-gate put_minor_range(FILE *fp, fileentry_t *old, const char *devn, const char *tail,
232*7c478bd9Sstevel@tonic-gate     minor_t lo, minor_t hi, char type)
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate 	/* Preserve preceeding comments */
235*7c478bd9Sstevel@tonic-gate 	if (old != NULL && old->rawbuf != old->orgentry)
236*7c478bd9Sstevel@tonic-gate 		(void) fwrite(old->rawbuf, 1, old->orgentry - old->rawbuf, fp);
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	if (type == '\0') {
239*7c478bd9Sstevel@tonic-gate 		put_minor_range(fp, NULL, devn, tail, lo, hi, 'b');
240*7c478bd9Sstevel@tonic-gate 		put_minor_range(fp, NULL, devn, tail, lo, hi, 'c');
241*7c478bd9Sstevel@tonic-gate 	} else if (lo == hi) {
242*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s:(%d)%c%s", devn, (int)lo, type, tail);
243*7c478bd9Sstevel@tonic-gate 	} else {
244*7c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s:(%d-%d)%c%s", devn, (int)lo, (int)hi,
245*7c478bd9Sstevel@tonic-gate 		    type, tail);
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate }
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate static int
250*7c478bd9Sstevel@tonic-gate delete_one_entry(const char *filename, const char *entry)
251*7c478bd9Sstevel@tonic-gate {
252*7c478bd9Sstevel@tonic-gate 	char tfile[MAXPATHLEN];
253*7c478bd9Sstevel@tonic-gate 	char ofile[MAXPATHLEN];
254*7c478bd9Sstevel@tonic-gate 	char *nfile;
255*7c478bd9Sstevel@tonic-gate 	FILE *old, *new;
256*7c478bd9Sstevel@tonic-gate 	fileentry_t *fep;
257*7c478bd9Sstevel@tonic-gate 	struct stat buf;
258*7c478bd9Sstevel@tonic-gate 	int newfd;
259*7c478bd9Sstevel@tonic-gate 	char *mpart;
260*7c478bd9Sstevel@tonic-gate 	boolean_t delall;
261*7c478bd9Sstevel@tonic-gate 	boolean_t delrange;
262*7c478bd9Sstevel@tonic-gate 	minor_t rlo, rhi;
263*7c478bd9Sstevel@tonic-gate 	char rtype;
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 	mpart = strchr(entry, ':');
266*7c478bd9Sstevel@tonic-gate 	if (mpart == NULL) {
267*7c478bd9Sstevel@tonic-gate 		delall = B_TRUE;
268*7c478bd9Sstevel@tonic-gate 		delrange = B_FALSE;
269*7c478bd9Sstevel@tonic-gate 	} else {
270*7c478bd9Sstevel@tonic-gate 		delall = B_FALSE;
271*7c478bd9Sstevel@tonic-gate 		mpart++;
272*7c478bd9Sstevel@tonic-gate 		if (*mpart == '(') {
273*7c478bd9Sstevel@tonic-gate 			if (parse_minor_range(mpart, &rlo, &rhi, &rtype) != 0)
274*7c478bd9Sstevel@tonic-gate 				return (-1);
275*7c478bd9Sstevel@tonic-gate 			delrange = B_TRUE;
276*7c478bd9Sstevel@tonic-gate 		} else {
277*7c478bd9Sstevel@tonic-gate 			delrange = B_FALSE;
278*7c478bd9Sstevel@tonic-gate 		}
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if (strlen(filename) + sizeof (XEND)  > sizeof (tfile))
282*7c478bd9Sstevel@tonic-gate 		return (-1);
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate 	old = fopen(filename, "r");
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	if (old == NULL)
287*7c478bd9Sstevel@tonic-gate 		return (-1);
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 	(void) snprintf(tfile, sizeof (tfile), "%s%s", filename, XEND);
290*7c478bd9Sstevel@tonic-gate 	(void) snprintf(ofile, sizeof (ofile), "%s%s", filename, ".old");
291*7c478bd9Sstevel@tonic-gate 
292*7c478bd9Sstevel@tonic-gate 	nfile = mktemp(tfile);
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	new = fopen(nfile, "w");
295*7c478bd9Sstevel@tonic-gate 	if (new == NULL) {
296*7c478bd9Sstevel@tonic-gate 		(void) fclose(old);
297*7c478bd9Sstevel@tonic-gate 		return (ERROR);
298*7c478bd9Sstevel@tonic-gate 	}
299*7c478bd9Sstevel@tonic-gate 
300*7c478bd9Sstevel@tonic-gate 	newfd = fileno(new);
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	/* Copy permissions, ownership */
303*7c478bd9Sstevel@tonic-gate 	if (fstat(fileno(old), &buf) == 0) {
304*7c478bd9Sstevel@tonic-gate 		(void) fchown(newfd, buf.st_uid, buf.st_gid);
305*7c478bd9Sstevel@tonic-gate 		(void) fchmod(newfd, buf.st_mode);
306*7c478bd9Sstevel@tonic-gate 	} else {
307*7c478bd9Sstevel@tonic-gate 		(void) fchown(newfd, 0, 3);	/* root:sys */
308*7c478bd9Sstevel@tonic-gate 		(void) fchmod(newfd, 0644);
309*7c478bd9Sstevel@tonic-gate 	}
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	while ((fep = fgetline(old))) {
312*7c478bd9Sstevel@tonic-gate 		char *tok;
313*7c478bd9Sstevel@tonic-gate 		char *min;
314*7c478bd9Sstevel@tonic-gate 		char *tail;
315*7c478bd9Sstevel@tonic-gate 		char tc;
316*7c478bd9Sstevel@tonic-gate 		int len;
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 		/* Trailing comments */
319*7c478bd9Sstevel@tonic-gate 		if (fep->entry == NULL) {
320*7c478bd9Sstevel@tonic-gate 			(void) fputs(fep->rawbuf, new);
321*7c478bd9Sstevel@tonic-gate 			break;
322*7c478bd9Sstevel@tonic-gate 		}
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 		tok = fep->entry;
325*7c478bd9Sstevel@tonic-gate 		while (*tok && isspace(*tok))
326*7c478bd9Sstevel@tonic-gate 			tok++;
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 		if (*tok == '\0') {
329*7c478bd9Sstevel@tonic-gate 			(void) fputs(fep->rawbuf, new);
330*7c478bd9Sstevel@tonic-gate 			break;
331*7c478bd9Sstevel@tonic-gate 		}
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 		/* Make sure we can recover the remainder incl. whitespace */
334*7c478bd9Sstevel@tonic-gate 		tail = strpbrk(tok, "\t\n ");
335*7c478bd9Sstevel@tonic-gate 		if (tail == NULL)
336*7c478bd9Sstevel@tonic-gate 			tail = tok + strlen(tok);
337*7c478bd9Sstevel@tonic-gate 		tc = *tail;
338*7c478bd9Sstevel@tonic-gate 		*tail = '\0';
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate 		if (delall || delrange) {
341*7c478bd9Sstevel@tonic-gate 			min = strchr(tok, ':');
342*7c478bd9Sstevel@tonic-gate 			if (min)
343*7c478bd9Sstevel@tonic-gate 				*min++ = '\0';
344*7c478bd9Sstevel@tonic-gate 		}
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 		len = strlen(tok);
347*7c478bd9Sstevel@tonic-gate 		if (delrange) {
348*7c478bd9Sstevel@tonic-gate 			minor_t lo, hi;
349*7c478bd9Sstevel@tonic-gate 			char type;
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 			/*
352*7c478bd9Sstevel@tonic-gate 			 * Delete or shrink overlapping ranges.
353*7c478bd9Sstevel@tonic-gate 			 */
354*7c478bd9Sstevel@tonic-gate 			if (strncmp(entry, tok, len) == 0 &&
355*7c478bd9Sstevel@tonic-gate 			    entry[len] == ':' &&
356*7c478bd9Sstevel@tonic-gate 			    min != NULL &&
357*7c478bd9Sstevel@tonic-gate 			    parse_minor_range(min, &lo, &hi, &type) == 0 &&
358*7c478bd9Sstevel@tonic-gate 			    (type == rtype || rtype == '\0') &&
359*7c478bd9Sstevel@tonic-gate 			    lo <= rhi && hi >= rlo) {
360*7c478bd9Sstevel@tonic-gate 				minor_t newlo, newhi;
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 				/* Complete overlap, then drop it. */
363*7c478bd9Sstevel@tonic-gate 				if (lo >= rlo && hi <= rhi)
364*7c478bd9Sstevel@tonic-gate 					continue;
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 				/* Partial overlap, shrink range */
367*7c478bd9Sstevel@tonic-gate 				if (lo < rlo)
368*7c478bd9Sstevel@tonic-gate 					newhi = rlo - 1;
369*7c478bd9Sstevel@tonic-gate 				else
370*7c478bd9Sstevel@tonic-gate 					newhi = hi;
371*7c478bd9Sstevel@tonic-gate 				if (hi > rhi)
372*7c478bd9Sstevel@tonic-gate 					newlo = rhi + 1;
373*7c478bd9Sstevel@tonic-gate 				else
374*7c478bd9Sstevel@tonic-gate 					newlo = lo;
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 				/* restore NULed character */
377*7c478bd9Sstevel@tonic-gate 				*tail = tc;
378*7c478bd9Sstevel@tonic-gate 
379*7c478bd9Sstevel@tonic-gate 				/* Split range? */
380*7c478bd9Sstevel@tonic-gate 				if (newlo > newhi) {
381*7c478bd9Sstevel@tonic-gate 					/*
382*7c478bd9Sstevel@tonic-gate 					 * We have two ranges:
383*7c478bd9Sstevel@tonic-gate 					 * lo ... newhi (== rlo - 1)
384*7c478bd9Sstevel@tonic-gate 					 * newlo (== rhi + 1) .. hi
385*7c478bd9Sstevel@tonic-gate 					 */
386*7c478bd9Sstevel@tonic-gate 					put_minor_range(new, fep, tok, tail,
387*7c478bd9Sstevel@tonic-gate 					    lo, newhi, type);
388*7c478bd9Sstevel@tonic-gate 					put_minor_range(new, NULL, tok, tail,
389*7c478bd9Sstevel@tonic-gate 					    newlo, hi, type);
390*7c478bd9Sstevel@tonic-gate 				} else {
391*7c478bd9Sstevel@tonic-gate 					put_minor_range(new, fep, tok, tail,
392*7c478bd9Sstevel@tonic-gate 					    newlo, newhi, type);
393*7c478bd9Sstevel@tonic-gate 				}
394*7c478bd9Sstevel@tonic-gate 				continue;
395*7c478bd9Sstevel@tonic-gate 			}
396*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(entry, tok) == 0 ||
397*7c478bd9Sstevel@tonic-gate 		    (strncmp(entry, tok, len) == 0 &&
398*7c478bd9Sstevel@tonic-gate 		    entry[len] == ':' &&
399*7c478bd9Sstevel@tonic-gate 		    entry[len+1] == '*' &&
400*7c478bd9Sstevel@tonic-gate 		    entry[len+2] == '\0')) {
401*7c478bd9Sstevel@tonic-gate 			/*
402*7c478bd9Sstevel@tonic-gate 			 * Delete exact match.
403*7c478bd9Sstevel@tonic-gate 			 */
404*7c478bd9Sstevel@tonic-gate 			continue;
405*7c478bd9Sstevel@tonic-gate 		}
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 		/* Copy unaffected entry. */
408*7c478bd9Sstevel@tonic-gate 		(void) fputs(fep->rawbuf, new);
409*7c478bd9Sstevel@tonic-gate 	}
410*7c478bd9Sstevel@tonic-gate 	(void) fclose(old);
411*7c478bd9Sstevel@tonic-gate 	(void) fflush(new);
412*7c478bd9Sstevel@tonic-gate 	(void) fsync(newfd);
413*7c478bd9Sstevel@tonic-gate 	if (ferror(new) == 0 && fclose(new) == 0 && fep != NULL) {
414*7c478bd9Sstevel@tonic-gate 		if (rename(filename, ofile) != 0) {
415*7c478bd9Sstevel@tonic-gate 			perror(NULL);
416*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), ofile);
417*7c478bd9Sstevel@tonic-gate 			(void) unlink(ofile);
418*7c478bd9Sstevel@tonic-gate 			(void) unlink(nfile);
419*7c478bd9Sstevel@tonic-gate 			return (ERROR);
420*7c478bd9Sstevel@tonic-gate 		} else if (rename(nfile, filename) != 0) {
421*7c478bd9Sstevel@tonic-gate 			perror(NULL);
422*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), ofile);
423*7c478bd9Sstevel@tonic-gate 			(void) rename(ofile, filename);
424*7c478bd9Sstevel@tonic-gate 			(void) unlink(nfile);
425*7c478bd9Sstevel@tonic-gate 			return (ERROR);
426*7c478bd9Sstevel@tonic-gate 		}
427*7c478bd9Sstevel@tonic-gate 		(void) unlink(ofile);
428*7c478bd9Sstevel@tonic-gate 	} else
429*7c478bd9Sstevel@tonic-gate 		(void) unlink(nfile);
430*7c478bd9Sstevel@tonic-gate 	return (0);
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate int
435*7c478bd9Sstevel@tonic-gate delete_plcy_entry(const char *filename, const char *entry)
436*7c478bd9Sstevel@tonic-gate {
437*7c478bd9Sstevel@tonic-gate 	char *p, *single;
438*7c478bd9Sstevel@tonic-gate 	char *copy;
439*7c478bd9Sstevel@tonic-gate 	int ret = 0;
440*7c478bd9Sstevel@tonic-gate 
441*7c478bd9Sstevel@tonic-gate 	copy = strdup(entry);
442*7c478bd9Sstevel@tonic-gate 	if (copy == NULL)
443*7c478bd9Sstevel@tonic-gate 		return (ERROR);
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate 	for (single = strtok_r(copy, " \t\n", &p);
446*7c478bd9Sstevel@tonic-gate 	    single != NULL;
447*7c478bd9Sstevel@tonic-gate 	    single = strtok_r(NULL, " \t\n", &p)) {
448*7c478bd9Sstevel@tonic-gate 		if ((ret = delete_one_entry(filename, single)) != 0) {
449*7c478bd9Sstevel@tonic-gate 			free(copy);
450*7c478bd9Sstevel@tonic-gate 			return (ret);
451*7c478bd9Sstevel@tonic-gate 		}
452*7c478bd9Sstevel@tonic-gate 	}
453*7c478bd9Sstevel@tonic-gate 	free(copy);
454*7c478bd9Sstevel@tonic-gate 	return (0);
455*7c478bd9Sstevel@tonic-gate }
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate /*
458*7c478bd9Sstevel@tonic-gate  * Analyze the device policy token; new tokens should be added to
459*7c478bd9Sstevel@tonic-gate  * toktab; new token types should be coded here.
460*7c478bd9Sstevel@tonic-gate  */
461*7c478bd9Sstevel@tonic-gate int
462*7c478bd9Sstevel@tonic-gate parse_plcy_token(char *token, devplcysys_t *dp)
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	char *val = strchr(token, '=');
465*7c478bd9Sstevel@tonic-gate 	const char *perr;
466*7c478bd9Sstevel@tonic-gate 	int i;
467*7c478bd9Sstevel@tonic-gate 	priv_set_t *pset;
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	if (val == NULL) {
470*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_EQUALS), token);
471*7c478bd9Sstevel@tonic-gate 		return (1);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 	*val++ = '\0';
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < NTOK; i++) {
476*7c478bd9Sstevel@tonic-gate 		if (strcmp(token, toktab[i].token) == 0) {
477*7c478bd9Sstevel@tonic-gate 			/* standard pointer computation for tokens */
478*7c478bd9Sstevel@tonic-gate 			void *item = (char *)dp + toktab[i].off;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 			switch (toktab[i].type) {
481*7c478bd9Sstevel@tonic-gate 			case PSET:
482*7c478bd9Sstevel@tonic-gate 				pset = priv_str_to_set(val, ",", &perr);
483*7c478bd9Sstevel@tonic-gate 				if (pset == NULL) {
484*7c478bd9Sstevel@tonic-gate 					if (perr == NULL)
485*7c478bd9Sstevel@tonic-gate 					    (void) fprintf(stderr,
486*7c478bd9Sstevel@tonic-gate 							gettext(ERR_NO_MEM));
487*7c478bd9Sstevel@tonic-gate 					else
488*7c478bd9Sstevel@tonic-gate 					    (void) fprintf(stderr,
489*7c478bd9Sstevel@tonic-gate 						gettext(ERR_BAD_PRIVS),
490*7c478bd9Sstevel@tonic-gate 						perr - val, val, perr);
491*7c478bd9Sstevel@tonic-gate 					return (1);
492*7c478bd9Sstevel@tonic-gate 				}
493*7c478bd9Sstevel@tonic-gate 				priv_copyset(pset, item);
494*7c478bd9Sstevel@tonic-gate 				priv_freeset(pset);
495*7c478bd9Sstevel@tonic-gate 				break;
496*7c478bd9Sstevel@tonic-gate 			default:
497*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
498*7c478bd9Sstevel@tonic-gate 					"Internal Error: bad token type: %d\n",
499*7c478bd9Sstevel@tonic-gate 						toktab[i].type);
500*7c478bd9Sstevel@tonic-gate 				return (1);
501*7c478bd9Sstevel@tonic-gate 			}
502*7c478bd9Sstevel@tonic-gate 			/* Standard cleanup & return for good tokens */
503*7c478bd9Sstevel@tonic-gate 			val[-1] = '=';
504*7c478bd9Sstevel@tonic-gate 			return (0);
505*7c478bd9Sstevel@tonic-gate 		}
506*7c478bd9Sstevel@tonic-gate 	}
507*7c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(ERR_BAD_TOKEN), token);
508*7c478bd9Sstevel@tonic-gate 	return (1);
509*7c478bd9Sstevel@tonic-gate }
510*7c478bd9Sstevel@tonic-gate 
511*7c478bd9Sstevel@tonic-gate static int
512*7c478bd9Sstevel@tonic-gate add2str(char **dstp, const char *str, size_t *sz)
513*7c478bd9Sstevel@tonic-gate {
514*7c478bd9Sstevel@tonic-gate 	char *p = *dstp;
515*7c478bd9Sstevel@tonic-gate 	size_t len = strlen(p) + strlen(str) + 1;
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	if (len > *sz) {
518*7c478bd9Sstevel@tonic-gate 		*sz *= 2;
519*7c478bd9Sstevel@tonic-gate 		if (*sz < len)
520*7c478bd9Sstevel@tonic-gate 			*sz = len;
521*7c478bd9Sstevel@tonic-gate 		*dstp = p = realloc(p, *sz);
522*7c478bd9Sstevel@tonic-gate 		if (p == NULL) {
523*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
524*7c478bd9Sstevel@tonic-gate 			return (-1);
525*7c478bd9Sstevel@tonic-gate 		}
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 	(void) strcat(p, str);
528*7c478bd9Sstevel@tonic-gate 	return (0);
529*7c478bd9Sstevel@tonic-gate }
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate /*
532*7c478bd9Sstevel@tonic-gate  * Verify that the policy entry is valid and return the canonical entry.
533*7c478bd9Sstevel@tonic-gate  */
534*7c478bd9Sstevel@tonic-gate char *
535*7c478bd9Sstevel@tonic-gate check_plcy_entry(char *entry, const char *driver, boolean_t todel)
536*7c478bd9Sstevel@tonic-gate {
537*7c478bd9Sstevel@tonic-gate 	char *res;
538*7c478bd9Sstevel@tonic-gate 	devplcysys_t *ds;
539*7c478bd9Sstevel@tonic-gate 	char *tok;
540*7c478bd9Sstevel@tonic-gate 	size_t sz = strlen(entry) * 2 + strlen(driver) + 3;
541*7c478bd9Sstevel@tonic-gate 	boolean_t tokseen = B_FALSE;
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 	devplcy_init();
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 	res = malloc(sz);
546*7c478bd9Sstevel@tonic-gate 	ds = alloca(devplcysys_sz);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	if (res == NULL || ds == NULL) {
549*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
550*7c478bd9Sstevel@tonic-gate 		return (NULL);
551*7c478bd9Sstevel@tonic-gate 	}
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	*res = '\0';
554*7c478bd9Sstevel@tonic-gate 
555*7c478bd9Sstevel@tonic-gate 	while ((tok = strtok(entry, " \t\n")) != NULL) {
556*7c478bd9Sstevel@tonic-gate 		entry = NULL;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 		/* It's not a token */
559*7c478bd9Sstevel@tonic-gate 		if (strchr(tok, '=') == NULL) {
560*7c478bd9Sstevel@tonic-gate 			if (strchr(tok, ':') != NULL) {
561*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_MINOR));
562*7c478bd9Sstevel@tonic-gate 				free(res);
563*7c478bd9Sstevel@tonic-gate 				return (NULL);
564*7c478bd9Sstevel@tonic-gate 			}
565*7c478bd9Sstevel@tonic-gate 			if (*res != '\0' && add2str(&res, "\n", &sz) != 0)
566*7c478bd9Sstevel@tonic-gate 				return (NULL);
567*7c478bd9Sstevel@tonic-gate 
568*7c478bd9Sstevel@tonic-gate 			if (*tok == '(') {
569*7c478bd9Sstevel@tonic-gate 				char type;
570*7c478bd9Sstevel@tonic-gate 				if (parse_minor_range(tok, &ds->dps_lomin,
571*7c478bd9Sstevel@tonic-gate 				    &ds->dps_himin, &type) != 0 ||
572*7c478bd9Sstevel@tonic-gate 				    (!todel && type == '\0')) {
573*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
574*7c478bd9Sstevel@tonic-gate 					    gettext(ERR_BAD_MINOR));
575*7c478bd9Sstevel@tonic-gate 					free(res);
576*7c478bd9Sstevel@tonic-gate 					return (NULL);
577*7c478bd9Sstevel@tonic-gate 				}
578*7c478bd9Sstevel@tonic-gate 			} else {
579*7c478bd9Sstevel@tonic-gate 				char *tmp = strchr(tok, '*');
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 				if (tmp != NULL &&
582*7c478bd9Sstevel@tonic-gate 				    strchr(tmp + 1, '*') != NULL) {
583*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
584*7c478bd9Sstevel@tonic-gate 					    gettext(ERR_BAD_MINOR));
585*7c478bd9Sstevel@tonic-gate 					free(res);
586*7c478bd9Sstevel@tonic-gate 				}
587*7c478bd9Sstevel@tonic-gate 			}
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 			if (add2str(&res, driver, &sz) != 0)
590*7c478bd9Sstevel@tonic-gate 				return (NULL);
591*7c478bd9Sstevel@tonic-gate 			if (add2str(&res, ":", &sz) != 0)
592*7c478bd9Sstevel@tonic-gate 				return (NULL);
593*7c478bd9Sstevel@tonic-gate 			if (add2str(&res, tok, &sz) != 0)
594*7c478bd9Sstevel@tonic-gate 				return (NULL);
595*7c478bd9Sstevel@tonic-gate 			tokseen = B_FALSE;
596*7c478bd9Sstevel@tonic-gate 		} else {
597*7c478bd9Sstevel@tonic-gate 			if (*res == '\0') {
598*7c478bd9Sstevel@tonic-gate 				if (add2str(&res, driver, &sz) != 0)
599*7c478bd9Sstevel@tonic-gate 					return (NULL);
600*7c478bd9Sstevel@tonic-gate 				if (add2str(&res, ":*", &sz) != 0)
601*7c478bd9Sstevel@tonic-gate 					return (NULL);
602*7c478bd9Sstevel@tonic-gate 			}
603*7c478bd9Sstevel@tonic-gate 			if (parse_plcy_token(tok, ds) != 0) {
604*7c478bd9Sstevel@tonic-gate 				free(res);
605*7c478bd9Sstevel@tonic-gate 				return (NULL);
606*7c478bd9Sstevel@tonic-gate 			}
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 			if (add2str(&res, "\t", &sz) != 0)
609*7c478bd9Sstevel@tonic-gate 				return (NULL);
610*7c478bd9Sstevel@tonic-gate 			if (add2str(&res, tok, &sz) != 0)
611*7c478bd9Sstevel@tonic-gate 				return (NULL);
612*7c478bd9Sstevel@tonic-gate 			tokseen = B_TRUE;
613*7c478bd9Sstevel@tonic-gate 		}
614*7c478bd9Sstevel@tonic-gate 	}
615*7c478bd9Sstevel@tonic-gate 	if (todel && tokseen || *res == '\0' || !todel && !tokseen) {
616*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_INVALID_PLCY));
617*7c478bd9Sstevel@tonic-gate 		free(res);
618*7c478bd9Sstevel@tonic-gate 		return (NULL);
619*7c478bd9Sstevel@tonic-gate 	}
620*7c478bd9Sstevel@tonic-gate 	if (!todel)
621*7c478bd9Sstevel@tonic-gate 		if (add2str(&res, "\n", &sz) != 0)
622*7c478bd9Sstevel@tonic-gate 			return (NULL);
623*7c478bd9Sstevel@tonic-gate 	return (res);
624*7c478bd9Sstevel@tonic-gate }
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate int
627*7c478bd9Sstevel@tonic-gate update_device_policy(const char *filename, const char *entry, boolean_t repl)
628*7c478bd9Sstevel@tonic-gate {
629*7c478bd9Sstevel@tonic-gate 	FILE *fp;
630*7c478bd9Sstevel@tonic-gate 
631*7c478bd9Sstevel@tonic-gate 	if (repl) {
632*7c478bd9Sstevel@tonic-gate 		char *dup, *tok, *s1;
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 		dup = strdup(entry);
635*7c478bd9Sstevel@tonic-gate 		if (dup == NULL) {
636*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
637*7c478bd9Sstevel@tonic-gate 			return (ERROR);
638*7c478bd9Sstevel@tonic-gate 		}
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 		/*
641*7c478bd9Sstevel@tonic-gate 		 * Split the entry in lines; then get the first token
642*7c478bd9Sstevel@tonic-gate 		 * of each line.
643*7c478bd9Sstevel@tonic-gate 		 */
644*7c478bd9Sstevel@tonic-gate 		for (tok = strtok_r(dup, "\n", &s1); tok != NULL;
645*7c478bd9Sstevel@tonic-gate 		    tok = strtok_r(NULL, "\n", &s1)) {
646*7c478bd9Sstevel@tonic-gate 
647*7c478bd9Sstevel@tonic-gate 			tok = strtok(tok, " \n\t");
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 			if (delete_one_entry(filename, tok) != 0) {
650*7c478bd9Sstevel@tonic-gate 				free(dup);
651*7c478bd9Sstevel@tonic-gate 				return (ERROR);
652*7c478bd9Sstevel@tonic-gate 			}
653*7c478bd9Sstevel@tonic-gate 		}
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 		free(dup);
656*7c478bd9Sstevel@tonic-gate 	}
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	fp = fopen(filename, "a");
659*7c478bd9Sstevel@tonic-gate 	if (fp == NULL)
660*7c478bd9Sstevel@tonic-gate 		return (ERROR);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	(void) fputs(entry, fp);
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	if (fflush(fp) != 0 || fsync(fileno(fp)) != 0 || fclose(fp) != 0)
665*7c478bd9Sstevel@tonic-gate 		return (ERROR);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	return (NOERR);
668*7c478bd9Sstevel@tonic-gate }
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate /*
672*7c478bd9Sstevel@tonic-gate  * We need to allocate the privileges now or the privilege set
673*7c478bd9Sstevel@tonic-gate  * parsing code will not allow them.
674*7c478bd9Sstevel@tonic-gate  */
675*7c478bd9Sstevel@tonic-gate int
676*7c478bd9Sstevel@tonic-gate check_priv_entry(const char *privlist, boolean_t add)
677*7c478bd9Sstevel@tonic-gate {
678*7c478bd9Sstevel@tonic-gate 	char *l = strdup(privlist);
679*7c478bd9Sstevel@tonic-gate 	char *pr;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	if (l == NULL) {
682*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
683*7c478bd9Sstevel@tonic-gate 		return (ERROR);
684*7c478bd9Sstevel@tonic-gate 	}
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	while ((pr = strtok_r(l, ",", &l)) != NULL) {
687*7c478bd9Sstevel@tonic-gate 		/* Privilege already exists */
688*7c478bd9Sstevel@tonic-gate 		if (priv_getbyname(pr) != -1)
689*7c478bd9Sstevel@tonic-gate 			continue;
690*7c478bd9Sstevel@tonic-gate 
691*7c478bd9Sstevel@tonic-gate 		if (add && modctl(MODALLOCPRIV, pr) != 0) {
692*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_PRIV), pr,
693*7c478bd9Sstevel@tonic-gate 				strerror(errno));
694*7c478bd9Sstevel@tonic-gate 			return (ERROR);
695*7c478bd9Sstevel@tonic-gate 		}
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 	return (NOERR);
698*7c478bd9Sstevel@tonic-gate }
699