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