xref: /titanic_50/usr/src/cmd/logadm/conf.c (revision 78eb75caca75144af27b7903ffed3fb549faab2f)
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  */
22*78eb75caSchin 
237c478bd9Sstevel@tonic-gate /*
24*78eb75caSchin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25*78eb75caSchin  * Use is subject to license terms.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
297c478bd9Sstevel@tonic-gate 
30*78eb75caSchin /*
31*78eb75caSchin  * logadm/conf.c -- configuration file module
32*78eb75caSchin  */
33*78eb75caSchin 
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <libintl.h>
367c478bd9Sstevel@tonic-gate #include <fcntl.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/stat.h>
397c478bd9Sstevel@tonic-gate #include <sys/mman.h>
407c478bd9Sstevel@tonic-gate #include <ctype.h>
417c478bd9Sstevel@tonic-gate #include <strings.h>
427c478bd9Sstevel@tonic-gate #include <unistd.h>
437c478bd9Sstevel@tonic-gate #include <stdlib.h>
447c478bd9Sstevel@tonic-gate #include "err.h"
457c478bd9Sstevel@tonic-gate #include "lut.h"
467c478bd9Sstevel@tonic-gate #include "fn.h"
477c478bd9Sstevel@tonic-gate #include "opts.h"
487c478bd9Sstevel@tonic-gate #include "conf.h"
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /* forward declarations of functions private to this module */
517c478bd9Sstevel@tonic-gate static void fillconflist(int lineno, const char *entry, char **args,
527c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags);
537c478bd9Sstevel@tonic-gate static void fillargs(char *arg);
547c478bd9Sstevel@tonic-gate static char *nexttok(char **ptrptr);
557c478bd9Sstevel@tonic-gate static void conf_print(FILE *stream);
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static const char *Confname;	/* name of the confile file */
587c478bd9Sstevel@tonic-gate static char *Confbuf;		/* copy of the config file (a la mmap()) */
597c478bd9Sstevel@tonic-gate static int Conflen;		/* length of mmap'd area */
607c478bd9Sstevel@tonic-gate static int Conffd = -1;		/* file descriptor for config file */
617c478bd9Sstevel@tonic-gate static boolean_t Confchanged;	/* true if we need to write changes back */
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * our structured representation of the configuration file
657c478bd9Sstevel@tonic-gate  * is made up of a list of these
667c478bd9Sstevel@tonic-gate  */
67*78eb75caSchin struct confinfo {
687c478bd9Sstevel@tonic-gate 	struct confinfo *cf_next;
697c478bd9Sstevel@tonic-gate 	int cf_lineno;		/* line number in file */
707c478bd9Sstevel@tonic-gate 	const char *cf_entry;	/* name of entry, if line has an entry */
717c478bd9Sstevel@tonic-gate 	char **cf_args;		/* raw rhs of entry */
727c478bd9Sstevel@tonic-gate 	struct opts *cf_opts;	/* parsed rhs of entry */
737c478bd9Sstevel@tonic-gate 	const char *cf_com;	/* any comment text found */
747c478bd9Sstevel@tonic-gate 	int cf_flags;
757c478bd9Sstevel@tonic-gate };
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate #define	CONFF_DELETED	1	/* entry should be deleted on write back */
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate static struct confinfo *Confinfo;	/* the entries in the config file */
807c478bd9Sstevel@tonic-gate static struct confinfo *Confinfolast;	/* end of list */
817c478bd9Sstevel@tonic-gate static struct lut *Conflut;		/* lookup table keyed by entry name */
827c478bd9Sstevel@tonic-gate static struct fn_list *Confentries;	/* list of valid entry names */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /* allocate & fill in another entry in our list */
857c478bd9Sstevel@tonic-gate static void
867c478bd9Sstevel@tonic-gate fillconflist(int lineno, const char *entry, char **args,
877c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	struct confinfo *cp = MALLOC(sizeof (*cp));
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	cp->cf_next = NULL;
927c478bd9Sstevel@tonic-gate 	cp->cf_lineno = lineno;
937c478bd9Sstevel@tonic-gate 	cp->cf_entry = entry;
947c478bd9Sstevel@tonic-gate 	cp->cf_args = args;
957c478bd9Sstevel@tonic-gate 	cp->cf_opts = opts;
967c478bd9Sstevel@tonic-gate 	cp->cf_com = com;
977c478bd9Sstevel@tonic-gate 	cp->cf_flags = flags;
987c478bd9Sstevel@tonic-gate 	if (entry) {
997c478bd9Sstevel@tonic-gate 		Conflut = lut_add(Conflut, entry, cp);
1007c478bd9Sstevel@tonic-gate 		fn_list_adds(Confentries, entry);
1017c478bd9Sstevel@tonic-gate 	}
1027c478bd9Sstevel@tonic-gate 	if (Confinfo == NULL)
1037c478bd9Sstevel@tonic-gate 		Confinfo = Confinfolast = cp;
1047c478bd9Sstevel@tonic-gate 	else {
1057c478bd9Sstevel@tonic-gate 		Confinfolast->cf_next = cp;
1067c478bd9Sstevel@tonic-gate 		Confinfolast = cp;
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate static char **Args;	/* static buffer for args */
1117c478bd9Sstevel@tonic-gate static int ArgsN;	/* size of our static buffer */
1127c478bd9Sstevel@tonic-gate static int ArgsI;	/* index into Cmdargs as we walk table */
1137c478bd9Sstevel@tonic-gate #define	CONF_ARGS_INC	1024
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate /* callback for lut_walk to build a cmdargs vector */
1167c478bd9Sstevel@tonic-gate static void
1177c478bd9Sstevel@tonic-gate fillargs(char *arg)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	if (ArgsI >= ArgsN) {
1207c478bd9Sstevel@tonic-gate 		/* need bigger table */
1217c478bd9Sstevel@tonic-gate 		Args = REALLOC(Args, sizeof (char *) * (ArgsN + CONF_ARGS_INC));
1227c478bd9Sstevel@tonic-gate 		ArgsN += CONF_ARGS_INC;
1237c478bd9Sstevel@tonic-gate 	}
1247c478bd9Sstevel@tonic-gate 	Args[ArgsI++] = arg;
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate /* isolate and return the next token */
1287c478bd9Sstevel@tonic-gate static char *
1297c478bd9Sstevel@tonic-gate nexttok(char **ptrptr)
1307c478bd9Sstevel@tonic-gate {
1317c478bd9Sstevel@tonic-gate 	char *ptr = *ptrptr;
1327c478bd9Sstevel@tonic-gate 	char *eptr;
1337c478bd9Sstevel@tonic-gate 	char *quote = NULL;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	while (*ptr && isspace(*ptr))
1367c478bd9Sstevel@tonic-gate 		ptr++;
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	if (*ptr == '"' || *ptr == '\'')
1397c478bd9Sstevel@tonic-gate 		quote = ptr++;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	for (eptr = ptr; *eptr; eptr++)
1427c478bd9Sstevel@tonic-gate 		if (quote && *eptr == *quote) {
1437c478bd9Sstevel@tonic-gate 			/* found end quote */
1447c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
1457c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
1467c478bd9Sstevel@tonic-gate 			return (ptr);
1477c478bd9Sstevel@tonic-gate 		} else if (!quote && isspace(*eptr)) {
1487c478bd9Sstevel@tonic-gate 			/* found end of unquoted area */
1497c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
1507c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
1517c478bd9Sstevel@tonic-gate 			return (ptr);
1527c478bd9Sstevel@tonic-gate 		}
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	if (quote)
1557c478bd9Sstevel@tonic-gate 		err(EF_FILE|EF_JMP, "Unbalanced %c quote", *quote);
1567c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	*ptrptr = eptr;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (ptr == eptr)
1617c478bd9Sstevel@tonic-gate 		return (NULL);
1627c478bd9Sstevel@tonic-gate 	else
1637c478bd9Sstevel@tonic-gate 		return (ptr);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * conf_open -- open the configuration file, lock it if we have write perms
1687c478bd9Sstevel@tonic-gate  */
1697c478bd9Sstevel@tonic-gate void
1707c478bd9Sstevel@tonic-gate conf_open(const char *fname, int needwrite)
1717c478bd9Sstevel@tonic-gate {
1727c478bd9Sstevel@tonic-gate 	struct stat stbuf;
1737c478bd9Sstevel@tonic-gate 	int lineno = 0;
1747c478bd9Sstevel@tonic-gate 	char *line;
1757c478bd9Sstevel@tonic-gate 	char *eline;
1767c478bd9Sstevel@tonic-gate 	char *ebuf;
1777c478bd9Sstevel@tonic-gate 	char *comment;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	Confname = fname;
1807c478bd9Sstevel@tonic-gate 	Confentries = fn_list_new(NULL);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* special case this so we don't even try locking the file */
1837c478bd9Sstevel@tonic-gate 	if (strcmp(Confname, "/dev/null") == 0)
1847c478bd9Sstevel@tonic-gate 		return;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if ((Conffd = open(Confname, (needwrite) ? O_RDWR : O_RDONLY)) < 0)
1877c478bd9Sstevel@tonic-gate 		err(EF_SYS, "%s", Confname);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (fstat(Conffd, &stbuf) < 0)
1907c478bd9Sstevel@tonic-gate 		err(EF_SYS, "fstat on %s", Confname);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	if (needwrite && lockf(Conffd, F_LOCK, 0) < 0)
1937c478bd9Sstevel@tonic-gate 		err(EF_SYS, "lockf on %s", Confname);
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	if (stbuf.st_size == 0)
1967c478bd9Sstevel@tonic-gate 		return;	/* empty file, don't bother parsing it */
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if ((Confbuf = (char *)mmap(0, stbuf.st_size,
1997c478bd9Sstevel@tonic-gate 	    PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1)
2007c478bd9Sstevel@tonic-gate 		err(EF_SYS, "mmap on %s", Confname);
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	Conflen = stbuf.st_size;
2037c478bd9Sstevel@tonic-gate 	Confchanged = B_FALSE;
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate 	ebuf = &Confbuf[Conflen];
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (Confbuf[Conflen - 1] != '\n')
2087c478bd9Sstevel@tonic-gate 		err(EF_WARN|EF_FILE, "config file doesn't end with "
2097c478bd9Sstevel@tonic-gate 		    "newline, last line ignored.");
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	line = Confbuf;
2127c478bd9Sstevel@tonic-gate 	while (line < ebuf) {
2137c478bd9Sstevel@tonic-gate 		lineno++;
2147c478bd9Sstevel@tonic-gate 		err_fileline(Confname, lineno);
2157c478bd9Sstevel@tonic-gate 		eline = line;
2167c478bd9Sstevel@tonic-gate 		comment = NULL;
2177c478bd9Sstevel@tonic-gate 		for (; eline < ebuf; eline++) {
2187c478bd9Sstevel@tonic-gate 			/* check for continued lines */
2197c478bd9Sstevel@tonic-gate 			if (comment == NULL && *eline == '\\' &&
2207c478bd9Sstevel@tonic-gate 			    eline + 1 < ebuf && *(eline + 1) == '\n') {
2217c478bd9Sstevel@tonic-gate 				*eline = ' ';
2227c478bd9Sstevel@tonic-gate 				*(eline + 1) = ' ';
2237c478bd9Sstevel@tonic-gate 				lineno++;
2247c478bd9Sstevel@tonic-gate 				err_fileline(Confname, lineno);
2257c478bd9Sstevel@tonic-gate 				continue;
2267c478bd9Sstevel@tonic-gate 			}
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 			/* check for comments */
2297c478bd9Sstevel@tonic-gate 			if (comment == NULL && *eline == '#') {
2307c478bd9Sstevel@tonic-gate 				*eline = '\0';
2317c478bd9Sstevel@tonic-gate 				comment = (eline + 1);
2327c478bd9Sstevel@tonic-gate 				continue;
2337c478bd9Sstevel@tonic-gate 			}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 			/* check for end of line */
2367c478bd9Sstevel@tonic-gate 			if (*eline == '\n')
2377c478bd9Sstevel@tonic-gate 				break;
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 		if (comment >= ebuf)
2407c478bd9Sstevel@tonic-gate 			comment = NULL;
2417c478bd9Sstevel@tonic-gate 		if (eline < ebuf) {
2427c478bd9Sstevel@tonic-gate 			char *entry;
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 			*eline++ = '\0';
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 			/*
2477c478bd9Sstevel@tonic-gate 			 * now we have the entry, if any, at "line"
2487c478bd9Sstevel@tonic-gate 			 * and the comment, if any, at "comment"
2497c478bd9Sstevel@tonic-gate 			 */
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 			/* entry is first token */
2527c478bd9Sstevel@tonic-gate 			if ((entry = nexttok(&line)) != NULL &&
2537c478bd9Sstevel@tonic-gate 			    strcmp(entry, "logadm-version") == 0) {
2547c478bd9Sstevel@tonic-gate 				/*
2557c478bd9Sstevel@tonic-gate 				 * we somehow opened some future format
2567c478bd9Sstevel@tonic-gate 				 * conffile that we likely don't understand.
2577c478bd9Sstevel@tonic-gate 				 * if the given version is "1" then go on,
2587c478bd9Sstevel@tonic-gate 				 * otherwise someone is mixing versions
2597c478bd9Sstevel@tonic-gate 				 * and we can't help them other than to
2607c478bd9Sstevel@tonic-gate 				 * print an error and exit.
2617c478bd9Sstevel@tonic-gate 				 */
2627c478bd9Sstevel@tonic-gate 				if ((entry = nexttok(&line)) != NULL &&
2637c478bd9Sstevel@tonic-gate 				    strcmp(entry, "1") != 0)
2647c478bd9Sstevel@tonic-gate 					err(0, "%s version not "
2657c478bd9Sstevel@tonic-gate 					    "supported by "
2667c478bd9Sstevel@tonic-gate 					    "this version of logadm.",
2677c478bd9Sstevel@tonic-gate 					    Confname);
2687c478bd9Sstevel@tonic-gate 			} else if (entry) {
2697c478bd9Sstevel@tonic-gate 				char *ap;
2707c478bd9Sstevel@tonic-gate 				char **args;
2717c478bd9Sstevel@tonic-gate 				int i;
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate 				ArgsI = 0;
2747c478bd9Sstevel@tonic-gate 				while (ap = nexttok(&line))
2757c478bd9Sstevel@tonic-gate 					fillargs(ap);
2767c478bd9Sstevel@tonic-gate 				if (ArgsI == 0) {
2777c478bd9Sstevel@tonic-gate 					/* short entry allowed */
2787c478bd9Sstevel@tonic-gate 					fillconflist(lineno, entry,
2797c478bd9Sstevel@tonic-gate 					    NULL, NULL, comment, 0);
2807c478bd9Sstevel@tonic-gate 				} else {
2817c478bd9Sstevel@tonic-gate 					Args[ArgsI++] = NULL;
2827c478bd9Sstevel@tonic-gate 					args = MALLOC(sizeof (char *) * ArgsI);
2837c478bd9Sstevel@tonic-gate 					for (i = 0; i < ArgsI; i++)
2847c478bd9Sstevel@tonic-gate 						args[i] = Args[i];
2857c478bd9Sstevel@tonic-gate 					fillconflist(lineno, entry,
2867c478bd9Sstevel@tonic-gate 					    args, NULL, comment, 0);
2877c478bd9Sstevel@tonic-gate 				}
2887c478bd9Sstevel@tonic-gate 			} else
2897c478bd9Sstevel@tonic-gate 				fillconflist(lineno, entry, NULL, NULL,
2907c478bd9Sstevel@tonic-gate 				    comment, 0);
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 		line = eline;
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * possible future enhancement:  go through and mark any entries:
2967c478bd9Sstevel@tonic-gate 	 * 		logfile -P <date>
2977c478bd9Sstevel@tonic-gate 	 * as DELETED if the logfile doesn't exist
2987c478bd9Sstevel@tonic-gate 	 */
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate /*
3027c478bd9Sstevel@tonic-gate  * conf_close -- close the configuration file
3037c478bd9Sstevel@tonic-gate  */
3047c478bd9Sstevel@tonic-gate void
3057c478bd9Sstevel@tonic-gate conf_close(struct opts *opts)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	FILE *fp;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	if (Confchanged && opts_count(opts, "n") == 0 && Conffd != -1) {
3107c478bd9Sstevel@tonic-gate 		if (opts_count(opts, "v"))
3117c478bd9Sstevel@tonic-gate 			(void) out("# writing changes to %s\n", Confname);
3127c478bd9Sstevel@tonic-gate 		if (Debug > 1) {
3137c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "conf_close, %s changed to:\n",
3147c478bd9Sstevel@tonic-gate 			    Confname);
3157c478bd9Sstevel@tonic-gate 			conf_print(stderr);
3167c478bd9Sstevel@tonic-gate 		}
3177c478bd9Sstevel@tonic-gate 		if (lseek(Conffd, (off_t)0, SEEK_SET) < 0)
3187c478bd9Sstevel@tonic-gate 			err(EF_SYS, "lseek on %s", Confname);
3197c478bd9Sstevel@tonic-gate 		if (ftruncate(Conffd, (off_t)0) < 0)
3207c478bd9Sstevel@tonic-gate 			err(EF_SYS, "ftruncate on %s", Confname);
3217c478bd9Sstevel@tonic-gate 		if ((fp = fdopen(Conffd, "w")) == NULL)
3227c478bd9Sstevel@tonic-gate 			err(EF_SYS, "fdopen on %s", Confname);
3237c478bd9Sstevel@tonic-gate 		conf_print(fp);
3247c478bd9Sstevel@tonic-gate 		if (fclose(fp) < 0)
3257c478bd9Sstevel@tonic-gate 			err(EF_SYS, "fclose on %s", Confname);
3267c478bd9Sstevel@tonic-gate 		Conffd = -1;
3277c478bd9Sstevel@tonic-gate 		Confchanged = B_FALSE;
3287c478bd9Sstevel@tonic-gate 	} else if (opts_count(opts, "v")) {
3297c478bd9Sstevel@tonic-gate 		(void) out("# %s unchanged\n", Confname);
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (Conffd != -1) {
3337c478bd9Sstevel@tonic-gate 		(void) close(Conffd);
3347c478bd9Sstevel@tonic-gate 		Conffd = -1;
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 	if (Conflut) {
3377c478bd9Sstevel@tonic-gate 		lut_free(Conflut, free);
3387c478bd9Sstevel@tonic-gate 		Conflut = NULL;
3397c478bd9Sstevel@tonic-gate 	}
3407c478bd9Sstevel@tonic-gate 	if (Confentries) {
3417c478bd9Sstevel@tonic-gate 		fn_list_free(Confentries);
3427c478bd9Sstevel@tonic-gate 		Confentries = NULL;
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate /*
3477c478bd9Sstevel@tonic-gate  * conf_lookup -- lookup an entry in the config file
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate char **
3507c478bd9Sstevel@tonic-gate conf_lookup(const char *lhs)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	if (cp) {
3557c478bd9Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
3567c478bd9Sstevel@tonic-gate 		return (cp->cf_args);
3577c478bd9Sstevel@tonic-gate 	} else
3587c478bd9Sstevel@tonic-gate 		return (NULL);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate /*
3627c478bd9Sstevel@tonic-gate  * conf_opts -- return the parsed opts for an entry
3637c478bd9Sstevel@tonic-gate  */
3647c478bd9Sstevel@tonic-gate struct opts *
3657c478bd9Sstevel@tonic-gate conf_opts(const char *lhs)
3667c478bd9Sstevel@tonic-gate {
3677c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (cp) {
3707c478bd9Sstevel@tonic-gate 		if (cp->cf_opts)
3717c478bd9Sstevel@tonic-gate 			return (cp->cf_opts);	/* already parsed */
3727c478bd9Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
3737c478bd9Sstevel@tonic-gate 		cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF);
3747c478bd9Sstevel@tonic-gate 		return (cp->cf_opts);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 	return (opts_parse(NULL, OPTF_CONF));
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate /*
3807c478bd9Sstevel@tonic-gate  * conf_replace -- replace an entry in the config file
3817c478bd9Sstevel@tonic-gate  */
3827c478bd9Sstevel@tonic-gate void
3837c478bd9Sstevel@tonic-gate conf_replace(const char *lhs, struct opts *newopts)
3847c478bd9Sstevel@tonic-gate {
3857c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
3887c478bd9Sstevel@tonic-gate 		return;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	if (cp) {
3917c478bd9Sstevel@tonic-gate 		cp->cf_opts = newopts;
3927c478bd9Sstevel@tonic-gate 		cp->cf_args = NULL;
3937c478bd9Sstevel@tonic-gate 		if (newopts == NULL)
3947c478bd9Sstevel@tonic-gate 			cp->cf_flags |= CONFF_DELETED;
3957c478bd9Sstevel@tonic-gate 	} else
3967c478bd9Sstevel@tonic-gate 		fillconflist(0, lhs, NULL, newopts, NULL, 0);
3977c478bd9Sstevel@tonic-gate 	Confchanged = B_TRUE;
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate /*
4017c478bd9Sstevel@tonic-gate  * conf_set -- set options for an entry in the config file
4027c478bd9Sstevel@tonic-gate  */
4037c478bd9Sstevel@tonic-gate void
4047c478bd9Sstevel@tonic-gate conf_set(const char *entry, char *o, const char *optarg)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, entry);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
4097c478bd9Sstevel@tonic-gate 		return;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	if (cp) {
4127c478bd9Sstevel@tonic-gate 		if (cp->cf_opts == NULL)
4137c478bd9Sstevel@tonic-gate 			cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF);
4147c478bd9Sstevel@tonic-gate 		cp->cf_flags &= ~CONFF_DELETED;
4157c478bd9Sstevel@tonic-gate 	} else {
4167c478bd9Sstevel@tonic-gate 		fillconflist(0, STRDUP(entry), NULL,
4177c478bd9Sstevel@tonic-gate 		    opts_parse(NULL, OPTF_CONF), NULL, 0);
4187c478bd9Sstevel@tonic-gate 		if ((cp = lut_lookup(Conflut, entry)) == NULL)
4197c478bd9Sstevel@tonic-gate 			err(0, "conf_set internal error");
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 	(void) opts_set(cp->cf_opts, o, optarg);
4227c478bd9Sstevel@tonic-gate 	Confchanged = B_TRUE;
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /*
4267c478bd9Sstevel@tonic-gate  * conf_entries -- list all the entry names
4277c478bd9Sstevel@tonic-gate  */
4287c478bd9Sstevel@tonic-gate struct fn_list *
4297c478bd9Sstevel@tonic-gate conf_entries(void)
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	return (Confentries);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /* print the config file */
4357c478bd9Sstevel@tonic-gate static void
4367c478bd9Sstevel@tonic-gate conf_print(FILE *stream)
4377c478bd9Sstevel@tonic-gate {
4387c478bd9Sstevel@tonic-gate 	struct confinfo *cp;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	for (cp = Confinfo; cp; cp = cp->cf_next) {
4417c478bd9Sstevel@tonic-gate 		if (cp->cf_flags & CONFF_DELETED)
4427c478bd9Sstevel@tonic-gate 			continue;
4437c478bd9Sstevel@tonic-gate 		if (cp->cf_entry) {
4447c478bd9Sstevel@tonic-gate 			char **p;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 			opts_printword(cp->cf_entry, stream);
4477c478bd9Sstevel@tonic-gate 			if (cp->cf_opts) {
4487c478bd9Sstevel@tonic-gate 				/* existence of opts overrides args */
4497c478bd9Sstevel@tonic-gate 				opts_print(cp->cf_opts, stream, "fhnrvVw");
4507c478bd9Sstevel@tonic-gate 			} else if (cp->cf_args) {
4517c478bd9Sstevel@tonic-gate 				for (p = cp->cf_args; *p; p++) {
4527c478bd9Sstevel@tonic-gate 					(void) fprintf(stream, " ");
4537c478bd9Sstevel@tonic-gate 					opts_printword(*p, stream);
4547c478bd9Sstevel@tonic-gate 				}
4557c478bd9Sstevel@tonic-gate 			}
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 		if (cp->cf_com) {
4587c478bd9Sstevel@tonic-gate 			if (cp->cf_entry)
4597c478bd9Sstevel@tonic-gate 				(void) fprintf(stream, " ");
4607c478bd9Sstevel@tonic-gate 			(void) fprintf(stream, "#%s", cp->cf_com);
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 		(void) fprintf(stream, "\n");
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate }
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate #ifdef	TESTMODULE
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate /*
4697c478bd9Sstevel@tonic-gate  * test main for conf module, usage: a.out conffile
4707c478bd9Sstevel@tonic-gate  */
4717c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
4727c478bd9Sstevel@tonic-gate {
4737c478bd9Sstevel@tonic-gate 	err_init(argv[0]);
4747c478bd9Sstevel@tonic-gate 	setbuf(stdout, NULL);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if (argc != 2)
4777c478bd9Sstevel@tonic-gate 		err(EF_RAW, "usage: %s conffile\n", argv[0]);
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	conf_open(argv[1], 1);
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	printf("conffile <%s>:\n", argv[1]);
4827c478bd9Sstevel@tonic-gate 	conf_print(stdout);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	conf_close(opts_parse(NULL, 0));
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	err_done(0);
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate #endif	/* TESTMODULE */
490