xref: /titanic_54/usr/src/cmd/logadm/conf.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 (c) 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  *
26*7c478bd9Sstevel@tonic-gate  * logadm/conf.c -- configuration file module
27*7c478bd9Sstevel@tonic-gate  */
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <stdio.h>
32*7c478bd9Sstevel@tonic-gate #include <libintl.h>
33*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
37*7c478bd9Sstevel@tonic-gate #include <ctype.h>
38*7c478bd9Sstevel@tonic-gate #include <strings.h>
39*7c478bd9Sstevel@tonic-gate #include <unistd.h>
40*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
41*7c478bd9Sstevel@tonic-gate #include "err.h"
42*7c478bd9Sstevel@tonic-gate #include "lut.h"
43*7c478bd9Sstevel@tonic-gate #include "fn.h"
44*7c478bd9Sstevel@tonic-gate #include "opts.h"
45*7c478bd9Sstevel@tonic-gate #include "conf.h"
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate /* forward declarations of functions private to this module */
48*7c478bd9Sstevel@tonic-gate static void fillconflist(int lineno, const char *entry, char **args,
49*7c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags);
50*7c478bd9Sstevel@tonic-gate static void fillargs(char *arg);
51*7c478bd9Sstevel@tonic-gate static char *nexttok(char **ptrptr);
52*7c478bd9Sstevel@tonic-gate static void conf_print(FILE *stream);
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate static const char *Confname;	/* name of the confile file */
55*7c478bd9Sstevel@tonic-gate static char *Confbuf;		/* copy of the config file (a la mmap()) */
56*7c478bd9Sstevel@tonic-gate static int Conflen;		/* length of mmap'd area */
57*7c478bd9Sstevel@tonic-gate static int Conffd = -1;		/* file descriptor for config file */
58*7c478bd9Sstevel@tonic-gate static boolean_t Confchanged;	/* true if we need to write changes back */
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate /*
61*7c478bd9Sstevel@tonic-gate  * our structured representation of the configuration file
62*7c478bd9Sstevel@tonic-gate  * is made up of a list of these
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate static struct confinfo {
65*7c478bd9Sstevel@tonic-gate 	struct confinfo *cf_next;
66*7c478bd9Sstevel@tonic-gate 	int cf_lineno;		/* line number in file */
67*7c478bd9Sstevel@tonic-gate 	const char *cf_entry;	/* name of entry, if line has an entry */
68*7c478bd9Sstevel@tonic-gate 	char **cf_args;		/* raw rhs of entry */
69*7c478bd9Sstevel@tonic-gate 	struct opts *cf_opts;	/* parsed rhs of entry */
70*7c478bd9Sstevel@tonic-gate 	const char *cf_com;	/* any comment text found */
71*7c478bd9Sstevel@tonic-gate 	int cf_flags;
72*7c478bd9Sstevel@tonic-gate };
73*7c478bd9Sstevel@tonic-gate 
74*7c478bd9Sstevel@tonic-gate #define	CONFF_DELETED	1	/* entry should be deleted on write back */
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate static struct confinfo *Confinfo;	/* the entries in the config file */
77*7c478bd9Sstevel@tonic-gate static struct confinfo *Confinfolast;	/* end of list */
78*7c478bd9Sstevel@tonic-gate static struct lut *Conflut;		/* lookup table keyed by entry name */
79*7c478bd9Sstevel@tonic-gate static struct fn_list *Confentries;	/* list of valid entry names */
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate /* allocate & fill in another entry in our list */
82*7c478bd9Sstevel@tonic-gate static void
83*7c478bd9Sstevel@tonic-gate fillconflist(int lineno, const char *entry, char **args,
84*7c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags)
85*7c478bd9Sstevel@tonic-gate {
86*7c478bd9Sstevel@tonic-gate 	struct confinfo *cp = MALLOC(sizeof (*cp));
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 	cp->cf_next = NULL;
89*7c478bd9Sstevel@tonic-gate 	cp->cf_lineno = lineno;
90*7c478bd9Sstevel@tonic-gate 	cp->cf_entry = entry;
91*7c478bd9Sstevel@tonic-gate 	cp->cf_args = args;
92*7c478bd9Sstevel@tonic-gate 	cp->cf_opts = opts;
93*7c478bd9Sstevel@tonic-gate 	cp->cf_com = com;
94*7c478bd9Sstevel@tonic-gate 	cp->cf_flags = flags;
95*7c478bd9Sstevel@tonic-gate 	if (entry) {
96*7c478bd9Sstevel@tonic-gate 		Conflut = lut_add(Conflut, entry, cp);
97*7c478bd9Sstevel@tonic-gate 		fn_list_adds(Confentries, entry);
98*7c478bd9Sstevel@tonic-gate 	}
99*7c478bd9Sstevel@tonic-gate 	if (Confinfo == NULL)
100*7c478bd9Sstevel@tonic-gate 		Confinfo = Confinfolast = cp;
101*7c478bd9Sstevel@tonic-gate 	else {
102*7c478bd9Sstevel@tonic-gate 		Confinfolast->cf_next = cp;
103*7c478bd9Sstevel@tonic-gate 		Confinfolast = cp;
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate static char **Args;	/* static buffer for args */
108*7c478bd9Sstevel@tonic-gate static int ArgsN;	/* size of our static buffer */
109*7c478bd9Sstevel@tonic-gate static int ArgsI;	/* index into Cmdargs as we walk table */
110*7c478bd9Sstevel@tonic-gate #define	CONF_ARGS_INC	1024
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /* callback for lut_walk to build a cmdargs vector */
113*7c478bd9Sstevel@tonic-gate static void
114*7c478bd9Sstevel@tonic-gate fillargs(char *arg)
115*7c478bd9Sstevel@tonic-gate {
116*7c478bd9Sstevel@tonic-gate 	if (ArgsI >= ArgsN) {
117*7c478bd9Sstevel@tonic-gate 		/* need bigger table */
118*7c478bd9Sstevel@tonic-gate 		Args = REALLOC(Args, sizeof (char *) * (ArgsN + CONF_ARGS_INC));
119*7c478bd9Sstevel@tonic-gate 		ArgsN += CONF_ARGS_INC;
120*7c478bd9Sstevel@tonic-gate 	}
121*7c478bd9Sstevel@tonic-gate 	Args[ArgsI++] = arg;
122*7c478bd9Sstevel@tonic-gate }
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate /* isolate and return the next token */
125*7c478bd9Sstevel@tonic-gate static char *
126*7c478bd9Sstevel@tonic-gate nexttok(char **ptrptr)
127*7c478bd9Sstevel@tonic-gate {
128*7c478bd9Sstevel@tonic-gate 	char *ptr = *ptrptr;
129*7c478bd9Sstevel@tonic-gate 	char *eptr;
130*7c478bd9Sstevel@tonic-gate 	char *quote = NULL;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	while (*ptr && isspace(*ptr))
133*7c478bd9Sstevel@tonic-gate 		ptr++;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	if (*ptr == '"' || *ptr == '\'')
136*7c478bd9Sstevel@tonic-gate 		quote = ptr++;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 	for (eptr = ptr; *eptr; eptr++)
139*7c478bd9Sstevel@tonic-gate 		if (quote && *eptr == *quote) {
140*7c478bd9Sstevel@tonic-gate 			/* found end quote */
141*7c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
142*7c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
143*7c478bd9Sstevel@tonic-gate 			return (ptr);
144*7c478bd9Sstevel@tonic-gate 		} else if (!quote && isspace(*eptr)) {
145*7c478bd9Sstevel@tonic-gate 			/* found end of unquoted area */
146*7c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
147*7c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
148*7c478bd9Sstevel@tonic-gate 			return (ptr);
149*7c478bd9Sstevel@tonic-gate 		}
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	if (quote)
152*7c478bd9Sstevel@tonic-gate 		err(EF_FILE|EF_JMP, "Unbalanced %c quote", *quote);
153*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	*ptrptr = eptr;
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate 	if (ptr == eptr)
158*7c478bd9Sstevel@tonic-gate 		return (NULL);
159*7c478bd9Sstevel@tonic-gate 	else
160*7c478bd9Sstevel@tonic-gate 		return (ptr);
161*7c478bd9Sstevel@tonic-gate }
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate /*
164*7c478bd9Sstevel@tonic-gate  * conf_open -- open the configuration file, lock it if we have write perms
165*7c478bd9Sstevel@tonic-gate  */
166*7c478bd9Sstevel@tonic-gate void
167*7c478bd9Sstevel@tonic-gate conf_open(const char *fname, int needwrite)
168*7c478bd9Sstevel@tonic-gate {
169*7c478bd9Sstevel@tonic-gate 	struct stat stbuf;
170*7c478bd9Sstevel@tonic-gate 	int lineno = 0;
171*7c478bd9Sstevel@tonic-gate 	char *line;
172*7c478bd9Sstevel@tonic-gate 	char *eline;
173*7c478bd9Sstevel@tonic-gate 	char *ebuf;
174*7c478bd9Sstevel@tonic-gate 	char *comment;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	Confname = fname;
177*7c478bd9Sstevel@tonic-gate 	Confentries = fn_list_new(NULL);
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate 	/* special case this so we don't even try locking the file */
180*7c478bd9Sstevel@tonic-gate 	if (strcmp(Confname, "/dev/null") == 0)
181*7c478bd9Sstevel@tonic-gate 		return;
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	if ((Conffd = open(Confname, (needwrite) ? O_RDWR : O_RDONLY)) < 0)
184*7c478bd9Sstevel@tonic-gate 		err(EF_SYS, "%s", Confname);
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (fstat(Conffd, &stbuf) < 0)
187*7c478bd9Sstevel@tonic-gate 		err(EF_SYS, "fstat on %s", Confname);
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	if (needwrite && lockf(Conffd, F_LOCK, 0) < 0)
190*7c478bd9Sstevel@tonic-gate 		err(EF_SYS, "lockf on %s", Confname);
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 	if (stbuf.st_size == 0)
193*7c478bd9Sstevel@tonic-gate 		return;	/* empty file, don't bother parsing it */
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if ((Confbuf = (char *)mmap(0, stbuf.st_size,
196*7c478bd9Sstevel@tonic-gate 	    PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1)
197*7c478bd9Sstevel@tonic-gate 		err(EF_SYS, "mmap on %s", Confname);
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	Conflen = stbuf.st_size;
200*7c478bd9Sstevel@tonic-gate 	Confchanged = B_FALSE;
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate 	ebuf = &Confbuf[Conflen];
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	if (Confbuf[Conflen - 1] != '\n')
205*7c478bd9Sstevel@tonic-gate 		err(EF_WARN|EF_FILE, "config file doesn't end with "
206*7c478bd9Sstevel@tonic-gate 		    "newline, last line ignored.");
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	line = Confbuf;
209*7c478bd9Sstevel@tonic-gate 	while (line < ebuf) {
210*7c478bd9Sstevel@tonic-gate 		lineno++;
211*7c478bd9Sstevel@tonic-gate 		err_fileline(Confname, lineno);
212*7c478bd9Sstevel@tonic-gate 		eline = line;
213*7c478bd9Sstevel@tonic-gate 		comment = NULL;
214*7c478bd9Sstevel@tonic-gate 		for (; eline < ebuf; eline++) {
215*7c478bd9Sstevel@tonic-gate 			/* check for continued lines */
216*7c478bd9Sstevel@tonic-gate 			if (comment == NULL && *eline == '\\' &&
217*7c478bd9Sstevel@tonic-gate 			    eline + 1 < ebuf && *(eline + 1) == '\n') {
218*7c478bd9Sstevel@tonic-gate 				*eline = ' ';
219*7c478bd9Sstevel@tonic-gate 				*(eline + 1) = ' ';
220*7c478bd9Sstevel@tonic-gate 				lineno++;
221*7c478bd9Sstevel@tonic-gate 				err_fileline(Confname, lineno);
222*7c478bd9Sstevel@tonic-gate 				continue;
223*7c478bd9Sstevel@tonic-gate 			}
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate 			/* check for comments */
226*7c478bd9Sstevel@tonic-gate 			if (comment == NULL && *eline == '#') {
227*7c478bd9Sstevel@tonic-gate 				*eline = '\0';
228*7c478bd9Sstevel@tonic-gate 				comment = (eline + 1);
229*7c478bd9Sstevel@tonic-gate 				continue;
230*7c478bd9Sstevel@tonic-gate 			}
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 			/* check for end of line */
233*7c478bd9Sstevel@tonic-gate 			if (*eline == '\n')
234*7c478bd9Sstevel@tonic-gate 				break;
235*7c478bd9Sstevel@tonic-gate 		}
236*7c478bd9Sstevel@tonic-gate 		if (comment >= ebuf)
237*7c478bd9Sstevel@tonic-gate 			comment = NULL;
238*7c478bd9Sstevel@tonic-gate 		if (eline < ebuf) {
239*7c478bd9Sstevel@tonic-gate 			char *entry;
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 			*eline++ = '\0';
242*7c478bd9Sstevel@tonic-gate 
243*7c478bd9Sstevel@tonic-gate 			/*
244*7c478bd9Sstevel@tonic-gate 			 * now we have the entry, if any, at "line"
245*7c478bd9Sstevel@tonic-gate 			 * and the comment, if any, at "comment"
246*7c478bd9Sstevel@tonic-gate 			 */
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 			/* entry is first token */
249*7c478bd9Sstevel@tonic-gate 			if ((entry = nexttok(&line)) != NULL &&
250*7c478bd9Sstevel@tonic-gate 			    strcmp(entry, "logadm-version") == 0) {
251*7c478bd9Sstevel@tonic-gate 				/*
252*7c478bd9Sstevel@tonic-gate 				 * we somehow opened some future format
253*7c478bd9Sstevel@tonic-gate 				 * conffile that we likely don't understand.
254*7c478bd9Sstevel@tonic-gate 				 * if the given version is "1" then go on,
255*7c478bd9Sstevel@tonic-gate 				 * otherwise someone is mixing versions
256*7c478bd9Sstevel@tonic-gate 				 * and we can't help them other than to
257*7c478bd9Sstevel@tonic-gate 				 * print an error and exit.
258*7c478bd9Sstevel@tonic-gate 				 */
259*7c478bd9Sstevel@tonic-gate 				if ((entry = nexttok(&line)) != NULL &&
260*7c478bd9Sstevel@tonic-gate 				    strcmp(entry, "1") != 0)
261*7c478bd9Sstevel@tonic-gate 					err(0, "%s version not "
262*7c478bd9Sstevel@tonic-gate 					    "supported by "
263*7c478bd9Sstevel@tonic-gate 					    "this version of logadm.",
264*7c478bd9Sstevel@tonic-gate 					    Confname);
265*7c478bd9Sstevel@tonic-gate 			} else if (entry) {
266*7c478bd9Sstevel@tonic-gate 				char *ap;
267*7c478bd9Sstevel@tonic-gate 				char **args;
268*7c478bd9Sstevel@tonic-gate 				int i;
269*7c478bd9Sstevel@tonic-gate 
270*7c478bd9Sstevel@tonic-gate 				ArgsI = 0;
271*7c478bd9Sstevel@tonic-gate 				while (ap = nexttok(&line))
272*7c478bd9Sstevel@tonic-gate 					fillargs(ap);
273*7c478bd9Sstevel@tonic-gate 				if (ArgsI == 0) {
274*7c478bd9Sstevel@tonic-gate 					/* short entry allowed */
275*7c478bd9Sstevel@tonic-gate 					fillconflist(lineno, entry,
276*7c478bd9Sstevel@tonic-gate 					    NULL, NULL, comment, 0);
277*7c478bd9Sstevel@tonic-gate 				} else {
278*7c478bd9Sstevel@tonic-gate 					Args[ArgsI++] = NULL;
279*7c478bd9Sstevel@tonic-gate 					args = MALLOC(sizeof (char *) * ArgsI);
280*7c478bd9Sstevel@tonic-gate 					for (i = 0; i < ArgsI; i++)
281*7c478bd9Sstevel@tonic-gate 						args[i] = Args[i];
282*7c478bd9Sstevel@tonic-gate 					fillconflist(lineno, entry,
283*7c478bd9Sstevel@tonic-gate 					    args, NULL, comment, 0);
284*7c478bd9Sstevel@tonic-gate 				}
285*7c478bd9Sstevel@tonic-gate 			} else
286*7c478bd9Sstevel@tonic-gate 				fillconflist(lineno, entry, NULL, NULL,
287*7c478bd9Sstevel@tonic-gate 				    comment, 0);
288*7c478bd9Sstevel@tonic-gate 		}
289*7c478bd9Sstevel@tonic-gate 		line = eline;
290*7c478bd9Sstevel@tonic-gate 	}
291*7c478bd9Sstevel@tonic-gate 	/*
292*7c478bd9Sstevel@tonic-gate 	 * possible future enhancement:  go through and mark any entries:
293*7c478bd9Sstevel@tonic-gate 	 * 		logfile -P <date>
294*7c478bd9Sstevel@tonic-gate 	 * as DELETED if the logfile doesn't exist
295*7c478bd9Sstevel@tonic-gate 	 */
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate /*
299*7c478bd9Sstevel@tonic-gate  * conf_close -- close the configuration file
300*7c478bd9Sstevel@tonic-gate  */
301*7c478bd9Sstevel@tonic-gate void
302*7c478bd9Sstevel@tonic-gate conf_close(struct opts *opts)
303*7c478bd9Sstevel@tonic-gate {
304*7c478bd9Sstevel@tonic-gate 	FILE *fp;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	if (Confchanged && opts_count(opts, "n") == 0 && Conffd != -1) {
307*7c478bd9Sstevel@tonic-gate 		if (opts_count(opts, "v"))
308*7c478bd9Sstevel@tonic-gate 			(void) out("# writing changes to %s\n", Confname);
309*7c478bd9Sstevel@tonic-gate 		if (Debug > 1) {
310*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, "conf_close, %s changed to:\n",
311*7c478bd9Sstevel@tonic-gate 			    Confname);
312*7c478bd9Sstevel@tonic-gate 			conf_print(stderr);
313*7c478bd9Sstevel@tonic-gate 		}
314*7c478bd9Sstevel@tonic-gate 		if (lseek(Conffd, (off_t)0, SEEK_SET) < 0)
315*7c478bd9Sstevel@tonic-gate 			err(EF_SYS, "lseek on %s", Confname);
316*7c478bd9Sstevel@tonic-gate 		if (ftruncate(Conffd, (off_t)0) < 0)
317*7c478bd9Sstevel@tonic-gate 			err(EF_SYS, "ftruncate on %s", Confname);
318*7c478bd9Sstevel@tonic-gate 		if ((fp = fdopen(Conffd, "w")) == NULL)
319*7c478bd9Sstevel@tonic-gate 			err(EF_SYS, "fdopen on %s", Confname);
320*7c478bd9Sstevel@tonic-gate 		conf_print(fp);
321*7c478bd9Sstevel@tonic-gate 		if (fclose(fp) < 0)
322*7c478bd9Sstevel@tonic-gate 			err(EF_SYS, "fclose on %s", Confname);
323*7c478bd9Sstevel@tonic-gate 		Conffd = -1;
324*7c478bd9Sstevel@tonic-gate 		Confchanged = B_FALSE;
325*7c478bd9Sstevel@tonic-gate 	} else if (opts_count(opts, "v")) {
326*7c478bd9Sstevel@tonic-gate 		(void) out("# %s unchanged\n", Confname);
327*7c478bd9Sstevel@tonic-gate 	}
328*7c478bd9Sstevel@tonic-gate 
329*7c478bd9Sstevel@tonic-gate 	if (Conffd != -1) {
330*7c478bd9Sstevel@tonic-gate 		(void) close(Conffd);
331*7c478bd9Sstevel@tonic-gate 		Conffd = -1;
332*7c478bd9Sstevel@tonic-gate 	}
333*7c478bd9Sstevel@tonic-gate 	if (Conflut) {
334*7c478bd9Sstevel@tonic-gate 		lut_free(Conflut, free);
335*7c478bd9Sstevel@tonic-gate 		Conflut = NULL;
336*7c478bd9Sstevel@tonic-gate 	}
337*7c478bd9Sstevel@tonic-gate 	if (Confentries) {
338*7c478bd9Sstevel@tonic-gate 		fn_list_free(Confentries);
339*7c478bd9Sstevel@tonic-gate 		Confentries = NULL;
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate }
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate /*
344*7c478bd9Sstevel@tonic-gate  * conf_lookup -- lookup an entry in the config file
345*7c478bd9Sstevel@tonic-gate  */
346*7c478bd9Sstevel@tonic-gate char **
347*7c478bd9Sstevel@tonic-gate conf_lookup(const char *lhs)
348*7c478bd9Sstevel@tonic-gate {
349*7c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 	if (cp) {
352*7c478bd9Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
353*7c478bd9Sstevel@tonic-gate 		return (cp->cf_args);
354*7c478bd9Sstevel@tonic-gate 	} else
355*7c478bd9Sstevel@tonic-gate 		return (NULL);
356*7c478bd9Sstevel@tonic-gate }
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate /*
359*7c478bd9Sstevel@tonic-gate  * conf_opts -- return the parsed opts for an entry
360*7c478bd9Sstevel@tonic-gate  */
361*7c478bd9Sstevel@tonic-gate struct opts *
362*7c478bd9Sstevel@tonic-gate conf_opts(const char *lhs)
363*7c478bd9Sstevel@tonic-gate {
364*7c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	if (cp) {
367*7c478bd9Sstevel@tonic-gate 		if (cp->cf_opts)
368*7c478bd9Sstevel@tonic-gate 			return (cp->cf_opts);	/* already parsed */
369*7c478bd9Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
370*7c478bd9Sstevel@tonic-gate 		cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF);
371*7c478bd9Sstevel@tonic-gate 		return (cp->cf_opts);
372*7c478bd9Sstevel@tonic-gate 	}
373*7c478bd9Sstevel@tonic-gate 	return (opts_parse(NULL, OPTF_CONF));
374*7c478bd9Sstevel@tonic-gate }
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate /*
377*7c478bd9Sstevel@tonic-gate  * conf_replace -- replace an entry in the config file
378*7c478bd9Sstevel@tonic-gate  */
379*7c478bd9Sstevel@tonic-gate void
380*7c478bd9Sstevel@tonic-gate conf_replace(const char *lhs, struct opts *newopts)
381*7c478bd9Sstevel@tonic-gate {
382*7c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
385*7c478bd9Sstevel@tonic-gate 		return;
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 	if (cp) {
388*7c478bd9Sstevel@tonic-gate 		cp->cf_opts = newopts;
389*7c478bd9Sstevel@tonic-gate 		cp->cf_args = NULL;
390*7c478bd9Sstevel@tonic-gate 		if (newopts == NULL)
391*7c478bd9Sstevel@tonic-gate 			cp->cf_flags |= CONFF_DELETED;
392*7c478bd9Sstevel@tonic-gate 	} else
393*7c478bd9Sstevel@tonic-gate 		fillconflist(0, lhs, NULL, newopts, NULL, 0);
394*7c478bd9Sstevel@tonic-gate 	Confchanged = B_TRUE;
395*7c478bd9Sstevel@tonic-gate }
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate /*
398*7c478bd9Sstevel@tonic-gate  * conf_set -- set options for an entry in the config file
399*7c478bd9Sstevel@tonic-gate  */
400*7c478bd9Sstevel@tonic-gate void
401*7c478bd9Sstevel@tonic-gate conf_set(const char *entry, char *o, const char *optarg)
402*7c478bd9Sstevel@tonic-gate {
403*7c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, entry);
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
406*7c478bd9Sstevel@tonic-gate 		return;
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	if (cp) {
409*7c478bd9Sstevel@tonic-gate 		if (cp->cf_opts == NULL)
410*7c478bd9Sstevel@tonic-gate 			cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF);
411*7c478bd9Sstevel@tonic-gate 		cp->cf_flags &= ~CONFF_DELETED;
412*7c478bd9Sstevel@tonic-gate 	} else {
413*7c478bd9Sstevel@tonic-gate 		fillconflist(0, STRDUP(entry), NULL,
414*7c478bd9Sstevel@tonic-gate 		    opts_parse(NULL, OPTF_CONF), NULL, 0);
415*7c478bd9Sstevel@tonic-gate 		if ((cp = lut_lookup(Conflut, entry)) == NULL)
416*7c478bd9Sstevel@tonic-gate 			err(0, "conf_set internal error");
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 	(void) opts_set(cp->cf_opts, o, optarg);
419*7c478bd9Sstevel@tonic-gate 	Confchanged = B_TRUE;
420*7c478bd9Sstevel@tonic-gate }
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate /*
423*7c478bd9Sstevel@tonic-gate  * conf_entries -- list all the entry names
424*7c478bd9Sstevel@tonic-gate  */
425*7c478bd9Sstevel@tonic-gate struct fn_list *
426*7c478bd9Sstevel@tonic-gate conf_entries(void)
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	return (Confentries);
429*7c478bd9Sstevel@tonic-gate }
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate /* print the config file */
432*7c478bd9Sstevel@tonic-gate static void
433*7c478bd9Sstevel@tonic-gate conf_print(FILE *stream)
434*7c478bd9Sstevel@tonic-gate {
435*7c478bd9Sstevel@tonic-gate 	struct confinfo *cp;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	for (cp = Confinfo; cp; cp = cp->cf_next) {
438*7c478bd9Sstevel@tonic-gate 		if (cp->cf_flags & CONFF_DELETED)
439*7c478bd9Sstevel@tonic-gate 			continue;
440*7c478bd9Sstevel@tonic-gate 		if (cp->cf_entry) {
441*7c478bd9Sstevel@tonic-gate 			char **p;
442*7c478bd9Sstevel@tonic-gate 
443*7c478bd9Sstevel@tonic-gate 			opts_printword(cp->cf_entry, stream);
444*7c478bd9Sstevel@tonic-gate 			if (cp->cf_opts) {
445*7c478bd9Sstevel@tonic-gate 				/* existence of opts overrides args */
446*7c478bd9Sstevel@tonic-gate 				opts_print(cp->cf_opts, stream, "fhnrvVw");
447*7c478bd9Sstevel@tonic-gate 			} else if (cp->cf_args) {
448*7c478bd9Sstevel@tonic-gate 				for (p = cp->cf_args; *p; p++) {
449*7c478bd9Sstevel@tonic-gate 					(void) fprintf(stream, " ");
450*7c478bd9Sstevel@tonic-gate 					opts_printword(*p, stream);
451*7c478bd9Sstevel@tonic-gate 				}
452*7c478bd9Sstevel@tonic-gate 			}
453*7c478bd9Sstevel@tonic-gate 		}
454*7c478bd9Sstevel@tonic-gate 		if (cp->cf_com) {
455*7c478bd9Sstevel@tonic-gate 			if (cp->cf_entry)
456*7c478bd9Sstevel@tonic-gate 				(void) fprintf(stream, " ");
457*7c478bd9Sstevel@tonic-gate 			(void) fprintf(stream, "#%s", cp->cf_com);
458*7c478bd9Sstevel@tonic-gate 		}
459*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stream, "\n");
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate }
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate #ifdef	TESTMODULE
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate /*
466*7c478bd9Sstevel@tonic-gate  * test main for conf module, usage: a.out conffile
467*7c478bd9Sstevel@tonic-gate  */
468*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
469*7c478bd9Sstevel@tonic-gate {
470*7c478bd9Sstevel@tonic-gate 	err_init(argv[0]);
471*7c478bd9Sstevel@tonic-gate 	setbuf(stdout, NULL);
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	if (argc != 2)
474*7c478bd9Sstevel@tonic-gate 		err(EF_RAW, "usage: %s conffile\n", argv[0]);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	conf_open(argv[1], 1);
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate 	printf("conffile <%s>:\n", argv[1]);
479*7c478bd9Sstevel@tonic-gate 	conf_print(stdout);
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	conf_close(opts_parse(NULL, 0));
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	err_done(0);
484*7c478bd9Sstevel@tonic-gate }
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate #endif	/* TESTMODULE */
487