xref: /illumos-gate/usr/src/cmd/modload/plcysubr.c (revision e4a991eb)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * Device policy specific subroutines.  We cannot merge them with
277c478bd9Sstevel@tonic-gate  * drvsubr.c because of static linking requirements.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
30*e4a991ebSAndy Fiddaman /*
31*e4a991ebSAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
32*e4a991ebSAndy Fiddaman  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <stdlib.h>
367c478bd9Sstevel@tonic-gate #include <unistd.h>
377c478bd9Sstevel@tonic-gate #include <string.h>
387c478bd9Sstevel@tonic-gate #include <ctype.h>
397c478bd9Sstevel@tonic-gate #include <priv.h>
407c478bd9Sstevel@tonic-gate #include <string.h>
417c478bd9Sstevel@tonic-gate #include <libgen.h>
427c478bd9Sstevel@tonic-gate #include <libintl.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <alloca.h>
457c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
467c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h>
477c478bd9Sstevel@tonic-gate #include <sys/stat.h>
487c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include "addrem.h"
517c478bd9Sstevel@tonic-gate #include "errmsg.h"
527c478bd9Sstevel@tonic-gate #include "plcysubr.h"
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate size_t devplcysys_sz;
557c478bd9Sstevel@tonic-gate const priv_impl_info_t *privimplinfo;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * New token types should be parsed in parse_plcy_entry.
597c478bd9Sstevel@tonic-gate  */
607c478bd9Sstevel@tonic-gate #define	PSET	0
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate typedef struct token {
637c478bd9Sstevel@tonic-gate 	const char	*token;
647c478bd9Sstevel@tonic-gate 	int		type;
657c478bd9Sstevel@tonic-gate 	ptrdiff_t	off;
667c478bd9Sstevel@tonic-gate } token_t;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static token_t toktab[] = {
697c478bd9Sstevel@tonic-gate 	{ DEVPLCY_TKN_RDP, PSET /* offsetof(devplcysys_t, dps_rdp) */ },
707c478bd9Sstevel@tonic-gate 	{ DEVPLCY_TKN_WRP, PSET /* offsetof(devplcysys_t, dps_wrp) */ },
717c478bd9Sstevel@tonic-gate };
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #define	RDPOL	0
747c478bd9Sstevel@tonic-gate #define	WRPOL	1
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #define	NTOK	(sizeof (toktab)/sizeof (token_t))
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Compute the size of the datastructures needed.
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate void
devplcy_init(void)827c478bd9Sstevel@tonic-gate devplcy_init(void)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate 	if ((privimplinfo = getprivimplinfo()) == NULL) {
857c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_PRIVIMPL));
867c478bd9Sstevel@tonic-gate 		exit(1);
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	devplcysys_sz = DEVPLCYSYS_SZ(privimplinfo);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	toktab[RDPOL].off =
92*e4a991ebSAndy Fiddaman 	    (char *)DEVPLCYSYS_RDP((devplcysys_t *)0, privimplinfo) - (char *)0;
937c478bd9Sstevel@tonic-gate 	toktab[WRPOL].off =
94*e4a991ebSAndy Fiddaman 	    (char *)DEVPLCYSYS_WRP((devplcysys_t *)0, privimplinfo) - (char *)0;
957c478bd9Sstevel@tonic-gate }
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * Read a configuration file line and return a static buffer pointing to it.
997c478bd9Sstevel@tonic-gate  * It returns a static struct fileentry which has several fields:
1007c478bd9Sstevel@tonic-gate  *	- rawbuf, which includes the lines including empty lines and comments
101*e4a991ebSAndy Fiddaman  *	leading up to the file and the entry as found in the file
1027c478bd9Sstevel@tonic-gate  *	- orgentry, pointer in rawbuf to the start of the entry proper.
1037c478bd9Sstevel@tonic-gate  *	- entry, a pre-parsed entry, escaped newlines removed.
1047c478bd9Sstevel@tonic-gate  *	- startline, the line number of the first line in the file
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate fileentry_t *
fgetline(FILE * fp)1077c478bd9Sstevel@tonic-gate fgetline(FILE *fp)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	static size_t sz = BUFSIZ;
1107c478bd9Sstevel@tonic-gate 	static struct fileentry fe;
1117c478bd9Sstevel@tonic-gate 	static int linecnt = 1;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	char *buf = fe.rawbuf;
1147c478bd9Sstevel@tonic-gate 	ptrdiff_t off;
1157c478bd9Sstevel@tonic-gate 	char *p;
1167c478bd9Sstevel@tonic-gate 	int c, lastc, i;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
1197c478bd9Sstevel@tonic-gate 		fe.rawbuf = buf = malloc(sz);
1207c478bd9Sstevel@tonic-gate 		if (buf == NULL)
1217c478bd9Sstevel@tonic-gate 			return (NULL);
1227c478bd9Sstevel@tonic-gate 	}
1237c478bd9Sstevel@tonic-gate 	if (fe.entry != NULL) {
1247c478bd9Sstevel@tonic-gate 		free(fe.entry);
1257c478bd9Sstevel@tonic-gate 		fe.orgentry = fe.entry = NULL;
1267c478bd9Sstevel@tonic-gate 	}
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	i = 0;
1297c478bd9Sstevel@tonic-gate 	off = -1;
1307c478bd9Sstevel@tonic-gate 	c = '\n';
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	while (lastc = c, (c = getc(fp)) != EOF) {
1337c478bd9Sstevel@tonic-gate 		buf[i++] = c;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		if (i == sz) {
1367c478bd9Sstevel@tonic-gate 			sz *= 2;
1377c478bd9Sstevel@tonic-gate 			fe.rawbuf = buf = realloc(buf, sz);
1387c478bd9Sstevel@tonic-gate 			if (buf == NULL)
1397c478bd9Sstevel@tonic-gate 				return (NULL);
1407c478bd9Sstevel@tonic-gate 		}
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 		if (c == '\n') {
1437c478bd9Sstevel@tonic-gate 			linecnt++;
1447c478bd9Sstevel@tonic-gate 			/* Newline, escaped or not yet processing an entry */
1457c478bd9Sstevel@tonic-gate 			if (off == -1 || lastc == '\\')
1467c478bd9Sstevel@tonic-gate 				continue;
1477c478bd9Sstevel@tonic-gate 		} else if (lastc == '\n' && off == -1) {
1487c478bd9Sstevel@tonic-gate 			/* Start of more comments */
1497c478bd9Sstevel@tonic-gate 			if (c == '#')
1507c478bd9Sstevel@tonic-gate 				continue;
1517c478bd9Sstevel@tonic-gate 			/* Found start of entry */
1527c478bd9Sstevel@tonic-gate 			off = i - 1;
1537c478bd9Sstevel@tonic-gate 			fe.startline = linecnt;
1547c478bd9Sstevel@tonic-gate 			continue;
1557c478bd9Sstevel@tonic-gate 		} else
1567c478bd9Sstevel@tonic-gate 			continue;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		buf[i] = '\0';
1597c478bd9Sstevel@tonic-gate 		fe.orgentry = buf + off;
1607c478bd9Sstevel@tonic-gate 		p = fe.entry = strdup(fe.orgentry);
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 		if (p == NULL)
1637c478bd9Sstevel@tonic-gate 			return (NULL);
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 		/* Remove <backslash><newline> */
1667c478bd9Sstevel@tonic-gate 		if ((p = strchr(p, '\\')) != NULL) {
1677c478bd9Sstevel@tonic-gate 			for (off = 0; (p[-off] = p[0]) != '\0'; p++)
1687c478bd9Sstevel@tonic-gate 				if (p[0] == '\\' && p[1] == '\n') {
1697c478bd9Sstevel@tonic-gate 					off += 2;
1707c478bd9Sstevel@tonic-gate 					p++;
1717c478bd9Sstevel@tonic-gate 				}
1727c478bd9Sstevel@tonic-gate 		}
1737c478bd9Sstevel@tonic-gate 		return (&fe);
1747c478bd9Sstevel@tonic-gate 	}
1757c478bd9Sstevel@tonic-gate 	if (lastc != '\n' || off != -1)
1767c478bd9Sstevel@tonic-gate 		return (NULL);
1777c478bd9Sstevel@tonic-gate 	buf[i] = '\0';
1787c478bd9Sstevel@tonic-gate 	linecnt = 1;
1797c478bd9Sstevel@tonic-gate 	return (&fe);
1807c478bd9Sstevel@tonic-gate }
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate  * Parse minor number ranges:
1847c478bd9Sstevel@tonic-gate  *	(minor) or (lowminor-highminor)
1857c478bd9Sstevel@tonic-gate  * Return 0 for success, -1 for failure.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate int
parse_minor_range(const char * range,minor_t * lo,minor_t * hi,char * type)1887c478bd9Sstevel@tonic-gate parse_minor_range(const char *range, minor_t *lo, minor_t *hi, char *type)
1897c478bd9Sstevel@tonic-gate {
1907c478bd9Sstevel@tonic-gate 	unsigned long tmp;
1917c478bd9Sstevel@tonic-gate 	char *p;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (*range++ != '(')
1947c478bd9Sstevel@tonic-gate 		return (-1);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	errno = 0;
1977c478bd9Sstevel@tonic-gate 	tmp = strtoul(range, &p, 0);
1987c478bd9Sstevel@tonic-gate 	if (tmp > L_MAXMIN32 || (tmp == 0 && errno != 0) ||
1997c478bd9Sstevel@tonic-gate 	    (*p != '-' && *p != ')'))
2007c478bd9Sstevel@tonic-gate 		return (-1);
2017c478bd9Sstevel@tonic-gate 	*lo = tmp;
2027c478bd9Sstevel@tonic-gate 	if (*p == '-') {
2037c478bd9Sstevel@tonic-gate 		errno = 0;
2047c478bd9Sstevel@tonic-gate 		tmp = strtoul(p + 1, &p, 0);
2057c478bd9Sstevel@tonic-gate 		if (tmp > L_MAXMIN32 || (tmp == 0 && errno != 0) || *p != ')')
2067c478bd9Sstevel@tonic-gate 			return (-1);
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 	*hi = tmp;
2097c478bd9Sstevel@tonic-gate 	if (*lo > *hi)
2107c478bd9Sstevel@tonic-gate 		return (-1);
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	switch (p[1]) {
2137c478bd9Sstevel@tonic-gate 	case '\0':
2147c478bd9Sstevel@tonic-gate 		*type = '\0';
2157c478bd9Sstevel@tonic-gate 		break;
2167c478bd9Sstevel@tonic-gate 	case 'c':
2177c478bd9Sstevel@tonic-gate 	case 'C':
2187c478bd9Sstevel@tonic-gate 		*type = 'c';
2197c478bd9Sstevel@tonic-gate 		break;
2207c478bd9Sstevel@tonic-gate 	case 'b':
2217c478bd9Sstevel@tonic-gate 	case 'B':
2227c478bd9Sstevel@tonic-gate 		*type = 'b';
2237c478bd9Sstevel@tonic-gate 		break;
2247c478bd9Sstevel@tonic-gate 	default:
2257c478bd9Sstevel@tonic-gate 		return (-1);
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 	return (0);
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate static void
put_minor_range(FILE * fp,fileentry_t * old,const char * devn,const char * tail,minor_t lo,minor_t hi,char type)2317c478bd9Sstevel@tonic-gate put_minor_range(FILE *fp, fileentry_t *old, const char *devn, const char *tail,
2327c478bd9Sstevel@tonic-gate     minor_t lo, minor_t hi, char type)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	/* Preserve preceeding comments */
2357c478bd9Sstevel@tonic-gate 	if (old != NULL && old->rawbuf != old->orgentry)
2367c478bd9Sstevel@tonic-gate 		(void) fwrite(old->rawbuf, 1, old->orgentry - old->rawbuf, fp);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	if (type == '\0') {
2397c478bd9Sstevel@tonic-gate 		put_minor_range(fp, NULL, devn, tail, lo, hi, 'b');
2407c478bd9Sstevel@tonic-gate 		put_minor_range(fp, NULL, devn, tail, lo, hi, 'c');
2417c478bd9Sstevel@tonic-gate 	} else if (lo == hi) {
2427c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s:(%d)%c%s", devn, (int)lo, type, tail);
2437c478bd9Sstevel@tonic-gate 	} else {
2447c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "%s:(%d-%d)%c%s", devn, (int)lo, (int)hi,
2457c478bd9Sstevel@tonic-gate 		    type, tail);
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate }
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate static int
delete_one_entry(const char * filename,const char * entry)2507c478bd9Sstevel@tonic-gate delete_one_entry(const char *filename, const char *entry)
2517c478bd9Sstevel@tonic-gate {
2527c478bd9Sstevel@tonic-gate 	char tfile[MAXPATHLEN];
2537c478bd9Sstevel@tonic-gate 	char ofile[MAXPATHLEN];
2547c478bd9Sstevel@tonic-gate 	char *nfile;
2557c478bd9Sstevel@tonic-gate 	FILE *old, *new;
2567c478bd9Sstevel@tonic-gate 	fileentry_t *fep;
2577c478bd9Sstevel@tonic-gate 	struct stat buf;
2587c478bd9Sstevel@tonic-gate 	int newfd;
2597c478bd9Sstevel@tonic-gate 	char *mpart;
2607c478bd9Sstevel@tonic-gate 	boolean_t delall;
2617c478bd9Sstevel@tonic-gate 	boolean_t delrange;
2627c478bd9Sstevel@tonic-gate 	minor_t rlo, rhi;
2637c478bd9Sstevel@tonic-gate 	char rtype;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	mpart = strchr(entry, ':');
2667c478bd9Sstevel@tonic-gate 	if (mpart == NULL) {
2677c478bd9Sstevel@tonic-gate 		delall = B_TRUE;
2687c478bd9Sstevel@tonic-gate 		delrange = B_FALSE;
2697c478bd9Sstevel@tonic-gate 	} else {
2707c478bd9Sstevel@tonic-gate 		delall = B_FALSE;
2717c478bd9Sstevel@tonic-gate 		mpart++;
2727c478bd9Sstevel@tonic-gate 		if (*mpart == '(') {
2737c478bd9Sstevel@tonic-gate 			if (parse_minor_range(mpart, &rlo, &rhi, &rtype) != 0)
2747c478bd9Sstevel@tonic-gate 				return (-1);
2757c478bd9Sstevel@tonic-gate 			delrange = B_TRUE;
2767c478bd9Sstevel@tonic-gate 		} else {
2777c478bd9Sstevel@tonic-gate 			delrange = B_FALSE;
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 	if (strlen(filename) + sizeof (XEND)  > sizeof (tfile))
2827c478bd9Sstevel@tonic-gate 		return (-1);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	old = fopen(filename, "r");
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	if (old == NULL)
2877c478bd9Sstevel@tonic-gate 		return (-1);
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	(void) snprintf(tfile, sizeof (tfile), "%s%s", filename, XEND);
2907c478bd9Sstevel@tonic-gate 	(void) snprintf(ofile, sizeof (ofile), "%s%s", filename, ".old");
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	nfile = mktemp(tfile);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	new = fopen(nfile, "w");
2957c478bd9Sstevel@tonic-gate 	if (new == NULL) {
2967c478bd9Sstevel@tonic-gate 		(void) fclose(old);
2977c478bd9Sstevel@tonic-gate 		return (ERROR);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	newfd = fileno(new);
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/* Copy permissions, ownership */
3037c478bd9Sstevel@tonic-gate 	if (fstat(fileno(old), &buf) == 0) {
3047c478bd9Sstevel@tonic-gate 		(void) fchown(newfd, buf.st_uid, buf.st_gid);
3057c478bd9Sstevel@tonic-gate 		(void) fchmod(newfd, buf.st_mode);
3067c478bd9Sstevel@tonic-gate 	} else {
3077c478bd9Sstevel@tonic-gate 		(void) fchown(newfd, 0, 3);	/* root:sys */
3087c478bd9Sstevel@tonic-gate 		(void) fchmod(newfd, 0644);
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	while ((fep = fgetline(old))) {
3127c478bd9Sstevel@tonic-gate 		char *tok;
3137c478bd9Sstevel@tonic-gate 		char *min;
3147c478bd9Sstevel@tonic-gate 		char *tail;
3157c478bd9Sstevel@tonic-gate 		char tc;
3167c478bd9Sstevel@tonic-gate 		int len;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 		/* Trailing comments */
3197c478bd9Sstevel@tonic-gate 		if (fep->entry == NULL) {
3207c478bd9Sstevel@tonic-gate 			(void) fputs(fep->rawbuf, new);
3217c478bd9Sstevel@tonic-gate 			break;
3227c478bd9Sstevel@tonic-gate 		}
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 		tok = fep->entry;
3257c478bd9Sstevel@tonic-gate 		while (*tok && isspace(*tok))
3267c478bd9Sstevel@tonic-gate 			tok++;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		if (*tok == '\0') {
3297c478bd9Sstevel@tonic-gate 			(void) fputs(fep->rawbuf, new);
3307c478bd9Sstevel@tonic-gate 			break;
3317c478bd9Sstevel@tonic-gate 		}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 		/* Make sure we can recover the remainder incl. whitespace */
3347c478bd9Sstevel@tonic-gate 		tail = strpbrk(tok, "\t\n ");
3357c478bd9Sstevel@tonic-gate 		if (tail == NULL)
3367c478bd9Sstevel@tonic-gate 			tail = tok + strlen(tok);
3377c478bd9Sstevel@tonic-gate 		tc = *tail;
3387c478bd9Sstevel@tonic-gate 		*tail = '\0';
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 		if (delall || delrange) {
3417c478bd9Sstevel@tonic-gate 			min = strchr(tok, ':');
3427c478bd9Sstevel@tonic-gate 			if (min)
3437c478bd9Sstevel@tonic-gate 				*min++ = '\0';
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 		len = strlen(tok);
3477c478bd9Sstevel@tonic-gate 		if (delrange) {
3487c478bd9Sstevel@tonic-gate 			minor_t lo, hi;
3497c478bd9Sstevel@tonic-gate 			char type;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 			/*
3527c478bd9Sstevel@tonic-gate 			 * Delete or shrink overlapping ranges.
3537c478bd9Sstevel@tonic-gate 			 */
3547c478bd9Sstevel@tonic-gate 			if (strncmp(entry, tok, len) == 0 &&
3557c478bd9Sstevel@tonic-gate 			    entry[len] == ':' &&
3567c478bd9Sstevel@tonic-gate 			    min != NULL &&
3577c478bd9Sstevel@tonic-gate 			    parse_minor_range(min, &lo, &hi, &type) == 0 &&
3587c478bd9Sstevel@tonic-gate 			    (type == rtype || rtype == '\0') &&
3597c478bd9Sstevel@tonic-gate 			    lo <= rhi && hi >= rlo) {
3607c478bd9Sstevel@tonic-gate 				minor_t newlo, newhi;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 				/* Complete overlap, then drop it. */
3637c478bd9Sstevel@tonic-gate 				if (lo >= rlo && hi <= rhi)
3647c478bd9Sstevel@tonic-gate 					continue;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 				/* Partial overlap, shrink range */
3677c478bd9Sstevel@tonic-gate 				if (lo < rlo)
3687c478bd9Sstevel@tonic-gate 					newhi = rlo - 1;
3697c478bd9Sstevel@tonic-gate 				else
3707c478bd9Sstevel@tonic-gate 					newhi = hi;
3717c478bd9Sstevel@tonic-gate 				if (hi > rhi)
3727c478bd9Sstevel@tonic-gate 					newlo = rhi + 1;
3737c478bd9Sstevel@tonic-gate 				else
3747c478bd9Sstevel@tonic-gate 					newlo = lo;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 				/* restore NULed character */
3777c478bd9Sstevel@tonic-gate 				*tail = tc;
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 				/* Split range? */
3807c478bd9Sstevel@tonic-gate 				if (newlo > newhi) {
3817c478bd9Sstevel@tonic-gate 					/*
3827c478bd9Sstevel@tonic-gate 					 * We have two ranges:
3837c478bd9Sstevel@tonic-gate 					 * lo ... newhi (== rlo - 1)
3847c478bd9Sstevel@tonic-gate 					 * newlo (== rhi + 1) .. hi
3857c478bd9Sstevel@tonic-gate 					 */
3867c478bd9Sstevel@tonic-gate 					put_minor_range(new, fep, tok, tail,
3877c478bd9Sstevel@tonic-gate 					    lo, newhi, type);
3887c478bd9Sstevel@tonic-gate 					put_minor_range(new, NULL, tok, tail,
3897c478bd9Sstevel@tonic-gate 					    newlo, hi, type);
3907c478bd9Sstevel@tonic-gate 				} else {
3917c478bd9Sstevel@tonic-gate 					put_minor_range(new, fep, tok, tail,
3927c478bd9Sstevel@tonic-gate 					    newlo, newhi, type);
3937c478bd9Sstevel@tonic-gate 				}
3947c478bd9Sstevel@tonic-gate 				continue;
3957c478bd9Sstevel@tonic-gate 			}
3967c478bd9Sstevel@tonic-gate 		} else if (strcmp(entry, tok) == 0 ||
3977c478bd9Sstevel@tonic-gate 		    (strncmp(entry, tok, len) == 0 &&
3987c478bd9Sstevel@tonic-gate 		    entry[len] == ':' &&
3997c478bd9Sstevel@tonic-gate 		    entry[len+1] == '*' &&
4007c478bd9Sstevel@tonic-gate 		    entry[len+2] == '\0')) {
4017c478bd9Sstevel@tonic-gate 			/*
4027c478bd9Sstevel@tonic-gate 			 * Delete exact match.
4037c478bd9Sstevel@tonic-gate 			 */
4047c478bd9Sstevel@tonic-gate 			continue;
4057c478bd9Sstevel@tonic-gate 		}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		/* Copy unaffected entry. */
4087c478bd9Sstevel@tonic-gate 		(void) fputs(fep->rawbuf, new);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 	(void) fclose(old);
4117c478bd9Sstevel@tonic-gate 	(void) fflush(new);
4127c478bd9Sstevel@tonic-gate 	(void) fsync(newfd);
4137c478bd9Sstevel@tonic-gate 	if (ferror(new) == 0 && fclose(new) == 0 && fep != NULL) {
4147c478bd9Sstevel@tonic-gate 		if (rename(filename, ofile) != 0) {
4157c478bd9Sstevel@tonic-gate 			perror(NULL);
4167c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), ofile);
4177c478bd9Sstevel@tonic-gate 			(void) unlink(ofile);
4187c478bd9Sstevel@tonic-gate 			(void) unlink(nfile);
4197c478bd9Sstevel@tonic-gate 			return (ERROR);
4207c478bd9Sstevel@tonic-gate 		} else if (rename(nfile, filename) != 0) {
4217c478bd9Sstevel@tonic-gate 			perror(NULL);
4227c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_UPDATE), ofile);
4237c478bd9Sstevel@tonic-gate 			(void) rename(ofile, filename);
4247c478bd9Sstevel@tonic-gate 			(void) unlink(nfile);
4257c478bd9Sstevel@tonic-gate 			return (ERROR);
4267c478bd9Sstevel@tonic-gate 		}
4277c478bd9Sstevel@tonic-gate 		(void) unlink(ofile);
4287c478bd9Sstevel@tonic-gate 	} else
4297c478bd9Sstevel@tonic-gate 		(void) unlink(nfile);
4307c478bd9Sstevel@tonic-gate 	return (0);
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate int
delete_plcy_entry(const char * filename,const char * entry)4357c478bd9Sstevel@tonic-gate delete_plcy_entry(const char *filename, const char *entry)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	char *p, *single;
4387c478bd9Sstevel@tonic-gate 	char *copy;
4397c478bd9Sstevel@tonic-gate 	int ret = 0;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	copy = strdup(entry);
4427c478bd9Sstevel@tonic-gate 	if (copy == NULL)
4437c478bd9Sstevel@tonic-gate 		return (ERROR);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	for (single = strtok_r(copy, " \t\n", &p);
4467c478bd9Sstevel@tonic-gate 	    single != NULL;
4477c478bd9Sstevel@tonic-gate 	    single = strtok_r(NULL, " \t\n", &p)) {
4487c478bd9Sstevel@tonic-gate 		if ((ret = delete_one_entry(filename, single)) != 0) {
4497c478bd9Sstevel@tonic-gate 			free(copy);
4507c478bd9Sstevel@tonic-gate 			return (ret);
4517c478bd9Sstevel@tonic-gate 		}
4527c478bd9Sstevel@tonic-gate 	}
4537c478bd9Sstevel@tonic-gate 	free(copy);
4547c478bd9Sstevel@tonic-gate 	return (0);
4557c478bd9Sstevel@tonic-gate }
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*
4587c478bd9Sstevel@tonic-gate  * Analyze the device policy token; new tokens should be added to
4597c478bd9Sstevel@tonic-gate  * toktab; new token types should be coded here.
4607c478bd9Sstevel@tonic-gate  */
4617c478bd9Sstevel@tonic-gate int
parse_plcy_token(char * token,devplcysys_t * dp)4627c478bd9Sstevel@tonic-gate parse_plcy_token(char *token, devplcysys_t *dp)
4637c478bd9Sstevel@tonic-gate {
4647c478bd9Sstevel@tonic-gate 	char *val = strchr(token, '=');
4657c478bd9Sstevel@tonic-gate 	const char *perr;
4667c478bd9Sstevel@tonic-gate 	int i;
4677c478bd9Sstevel@tonic-gate 	priv_set_t *pset;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	if (val == NULL) {
4707c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_EQUALS), token);
4717c478bd9Sstevel@tonic-gate 		return (1);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 	*val++ = '\0';
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	for (i = 0; i < NTOK; i++) {
4767c478bd9Sstevel@tonic-gate 		if (strcmp(token, toktab[i].token) == 0) {
4777c478bd9Sstevel@tonic-gate 			/* standard pointer computation for tokens */
4787c478bd9Sstevel@tonic-gate 			void *item = (char *)dp + toktab[i].off;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 			switch (toktab[i].type) {
4817c478bd9Sstevel@tonic-gate 			case PSET:
4827c478bd9Sstevel@tonic-gate 				pset = priv_str_to_set(val, ",", &perr);
4837c478bd9Sstevel@tonic-gate 				if (pset == NULL) {
484*e4a991ebSAndy Fiddaman 					if (perr == NULL) {
485*e4a991ebSAndy Fiddaman 						(void) fprintf(stderr,
486*e4a991ebSAndy Fiddaman 						    gettext(ERR_NO_MEM));
487*e4a991ebSAndy Fiddaman 					} else {
488*e4a991ebSAndy Fiddaman 						(void) fprintf(stderr,
489*e4a991ebSAndy Fiddaman 						    gettext(ERR_BAD_PRIVS),
490*e4a991ebSAndy Fiddaman 						    perr - val, val, perr);
491*e4a991ebSAndy Fiddaman 					}
4927c478bd9Sstevel@tonic-gate 					return (1);
4937c478bd9Sstevel@tonic-gate 				}
4947c478bd9Sstevel@tonic-gate 				priv_copyset(pset, item);
4957c478bd9Sstevel@tonic-gate 				priv_freeset(pset);
4967c478bd9Sstevel@tonic-gate 				break;
4977c478bd9Sstevel@tonic-gate 			default:
4987c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr,
499*e4a991ebSAndy Fiddaman 				    "Internal Error: bad token type: %d\n",
500*e4a991ebSAndy Fiddaman 				    toktab[i].type);
5017c478bd9Sstevel@tonic-gate 				return (1);
5027c478bd9Sstevel@tonic-gate 			}
5037c478bd9Sstevel@tonic-gate 			/* Standard cleanup & return for good tokens */
5047c478bd9Sstevel@tonic-gate 			val[-1] = '=';
5057c478bd9Sstevel@tonic-gate 			return (0);
5067c478bd9Sstevel@tonic-gate 		}
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, gettext(ERR_BAD_TOKEN), token);
5097c478bd9Sstevel@tonic-gate 	return (1);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate static int
add2str(char ** dstp,const char * str,size_t * sz)5137c478bd9Sstevel@tonic-gate add2str(char **dstp, const char *str, size_t *sz)
5147c478bd9Sstevel@tonic-gate {
5157c478bd9Sstevel@tonic-gate 	char *p = *dstp;
5167c478bd9Sstevel@tonic-gate 	size_t len = strlen(p) + strlen(str) + 1;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if (len > *sz) {
5197c478bd9Sstevel@tonic-gate 		*sz *= 2;
5207c478bd9Sstevel@tonic-gate 		if (*sz < len)
5217c478bd9Sstevel@tonic-gate 			*sz = len;
5227c478bd9Sstevel@tonic-gate 		*dstp = p = realloc(p, *sz);
5237c478bd9Sstevel@tonic-gate 		if (p == NULL) {
5247c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
5257c478bd9Sstevel@tonic-gate 			return (-1);
5267c478bd9Sstevel@tonic-gate 		}
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 	(void) strcat(p, str);
5297c478bd9Sstevel@tonic-gate 	return (0);
5307c478bd9Sstevel@tonic-gate }
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate /*
5337c478bd9Sstevel@tonic-gate  * Verify that the policy entry is valid and return the canonical entry.
5347c478bd9Sstevel@tonic-gate  */
5357c478bd9Sstevel@tonic-gate char *
check_plcy_entry(char * entry,const char * driver,boolean_t todel)5367c478bd9Sstevel@tonic-gate check_plcy_entry(char *entry, const char *driver, boolean_t todel)
5377c478bd9Sstevel@tonic-gate {
5387c478bd9Sstevel@tonic-gate 	char *res;
5397c478bd9Sstevel@tonic-gate 	devplcysys_t *ds;
5407c478bd9Sstevel@tonic-gate 	char *tok;
5417c478bd9Sstevel@tonic-gate 	size_t sz = strlen(entry) * 2 + strlen(driver) + 3;
5427c478bd9Sstevel@tonic-gate 	boolean_t tokseen = B_FALSE;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	devplcy_init();
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	res = malloc(sz);
5477c478bd9Sstevel@tonic-gate 	ds = alloca(devplcysys_sz);
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 	if (res == NULL || ds == NULL) {
5507c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
551*e4a991ebSAndy Fiddaman 		free(res);
5527c478bd9Sstevel@tonic-gate 		return (NULL);
5537c478bd9Sstevel@tonic-gate 	}
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	*res = '\0';
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	while ((tok = strtok(entry, " \t\n")) != NULL) {
5587c478bd9Sstevel@tonic-gate 		entry = NULL;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		/* It's not a token */
5617c478bd9Sstevel@tonic-gate 		if (strchr(tok, '=') == NULL) {
5627c478bd9Sstevel@tonic-gate 			if (strchr(tok, ':') != NULL) {
5637c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(ERR_BAD_MINOR));
5647c478bd9Sstevel@tonic-gate 				free(res);
5657c478bd9Sstevel@tonic-gate 				return (NULL);
5667c478bd9Sstevel@tonic-gate 			}
5677c478bd9Sstevel@tonic-gate 			if (*res != '\0' && add2str(&res, "\n", &sz) != 0)
5687c478bd9Sstevel@tonic-gate 				return (NULL);
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 			if (*tok == '(') {
5717c478bd9Sstevel@tonic-gate 				char type;
5727c478bd9Sstevel@tonic-gate 				if (parse_minor_range(tok, &ds->dps_lomin,
5737c478bd9Sstevel@tonic-gate 				    &ds->dps_himin, &type) != 0 ||
5747c478bd9Sstevel@tonic-gate 				    (!todel && type == '\0')) {
5757c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
5767c478bd9Sstevel@tonic-gate 					    gettext(ERR_BAD_MINOR));
5777c478bd9Sstevel@tonic-gate 					free(res);
5787c478bd9Sstevel@tonic-gate 					return (NULL);
5797c478bd9Sstevel@tonic-gate 				}
5807c478bd9Sstevel@tonic-gate 			} else {
5817c478bd9Sstevel@tonic-gate 				char *tmp = strchr(tok, '*');
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 				if (tmp != NULL &&
5847c478bd9Sstevel@tonic-gate 				    strchr(tmp + 1, '*') != NULL) {
5857c478bd9Sstevel@tonic-gate 					(void) fprintf(stderr,
5867c478bd9Sstevel@tonic-gate 					    gettext(ERR_BAD_MINOR));
5877c478bd9Sstevel@tonic-gate 					free(res);
5887c478bd9Sstevel@tonic-gate 				}
5897c478bd9Sstevel@tonic-gate 			}
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate 			if (add2str(&res, driver, &sz) != 0)
5927c478bd9Sstevel@tonic-gate 				return (NULL);
5937c478bd9Sstevel@tonic-gate 			if (add2str(&res, ":", &sz) != 0)
5947c478bd9Sstevel@tonic-gate 				return (NULL);
5957c478bd9Sstevel@tonic-gate 			if (add2str(&res, tok, &sz) != 0)
5967c478bd9Sstevel@tonic-gate 				return (NULL);
5977c478bd9Sstevel@tonic-gate 			tokseen = B_FALSE;
5987c478bd9Sstevel@tonic-gate 		} else {
5997c478bd9Sstevel@tonic-gate 			if (*res == '\0') {
6007c478bd9Sstevel@tonic-gate 				if (add2str(&res, driver, &sz) != 0)
6017c478bd9Sstevel@tonic-gate 					return (NULL);
6027c478bd9Sstevel@tonic-gate 				if (add2str(&res, ":*", &sz) != 0)
6037c478bd9Sstevel@tonic-gate 					return (NULL);
6047c478bd9Sstevel@tonic-gate 			}
6057c478bd9Sstevel@tonic-gate 			if (parse_plcy_token(tok, ds) != 0) {
6067c478bd9Sstevel@tonic-gate 				free(res);
6077c478bd9Sstevel@tonic-gate 				return (NULL);
6087c478bd9Sstevel@tonic-gate 			}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 			if (add2str(&res, "\t", &sz) != 0)
6117c478bd9Sstevel@tonic-gate 				return (NULL);
6127c478bd9Sstevel@tonic-gate 			if (add2str(&res, tok, &sz) != 0)
6137c478bd9Sstevel@tonic-gate 				return (NULL);
6147c478bd9Sstevel@tonic-gate 			tokseen = B_TRUE;
6157c478bd9Sstevel@tonic-gate 		}
6167c478bd9Sstevel@tonic-gate 	}
617*e4a991ebSAndy Fiddaman 	if ((todel && tokseen) || *res == '\0' || (!todel && !tokseen)) {
6187c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_INVALID_PLCY));
6197c478bd9Sstevel@tonic-gate 		free(res);
6207c478bd9Sstevel@tonic-gate 		return (NULL);
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 	if (!todel)
6237c478bd9Sstevel@tonic-gate 		if (add2str(&res, "\n", &sz) != 0)
6247c478bd9Sstevel@tonic-gate 			return (NULL);
6257c478bd9Sstevel@tonic-gate 	return (res);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate int
update_device_policy(const char * filename,const char * entry,boolean_t repl)6297c478bd9Sstevel@tonic-gate update_device_policy(const char *filename, const char *entry, boolean_t repl)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	FILE *fp;
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	if (repl) {
6347c478bd9Sstevel@tonic-gate 		char *dup, *tok, *s1;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		dup = strdup(entry);
6377c478bd9Sstevel@tonic-gate 		if (dup == NULL) {
6387c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_NO_MEM));
6397c478bd9Sstevel@tonic-gate 			return (ERROR);
6407c478bd9Sstevel@tonic-gate 		}
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 		/*
6437c478bd9Sstevel@tonic-gate 		 * Split the entry in lines; then get the first token
6447c478bd9Sstevel@tonic-gate 		 * of each line.
6457c478bd9Sstevel@tonic-gate 		 */
6467c478bd9Sstevel@tonic-gate 		for (tok = strtok_r(dup, "\n", &s1); tok != NULL;
6477c478bd9Sstevel@tonic-gate 		    tok = strtok_r(NULL, "\n", &s1)) {
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 			tok = strtok(tok, " \n\t");
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 			if (delete_one_entry(filename, tok) != 0) {
6527c478bd9Sstevel@tonic-gate 				free(dup);
6537c478bd9Sstevel@tonic-gate 				return (ERROR);
6547c478bd9Sstevel@tonic-gate 			}
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 		free(dup);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	fp = fopen(filename, "a");
6617c478bd9Sstevel@tonic-gate 	if (fp == NULL)
6627c478bd9Sstevel@tonic-gate 		return (ERROR);
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	(void) fputs(entry, fp);
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate 	if (fflush(fp) != 0 || fsync(fileno(fp)) != 0 || fclose(fp) != 0)
6677c478bd9Sstevel@tonic-gate 		return (ERROR);
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	return (NOERR);
6707c478bd9Sstevel@tonic-gate }
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate /*
6747c478bd9Sstevel@tonic-gate  * We need to allocate the privileges now or the privilege set
6757c478bd9Sstevel@tonic-gate  * parsing code will not allow them.
6767c478bd9Sstevel@tonic-gate  */
6777c478bd9Sstevel@tonic-gate int
check_priv_entry(const char * privlist,boolean_t add)6787c478bd9Sstevel@tonic-gate check_priv_entry(const char *privlist, boolean_t add)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	char *l = strdup(privlist);
6817c478bd9Sstevel@tonic-gate 	char *pr;
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (l == NULL) {
6847c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(ERR_NO_MEM));
6857c478bd9Sstevel@tonic-gate 		return (ERROR);
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	while ((pr = strtok_r(l, ",", &l)) != NULL) {
6897c478bd9Sstevel@tonic-gate 		/* Privilege already exists */
6907c478bd9Sstevel@tonic-gate 		if (priv_getbyname(pr) != -1)
6917c478bd9Sstevel@tonic-gate 			continue;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 		if (add && modctl(MODALLOCPRIV, pr) != 0) {
6947c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(ERR_BAD_PRIV), pr,
695*e4a991ebSAndy Fiddaman 			    strerror(errno));
6967c478bd9Sstevel@tonic-gate 			return (ERROR);
6977c478bd9Sstevel@tonic-gate 		}
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	return (NOERR);
7007c478bd9Sstevel@tonic-gate }
701