xref: /onnv-gate/usr/src/cmd/logadm/conf.c (revision 12986:04c3fb904c79)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52397Sbasabi  * Common Development and Distribution License (the "License").
62397Sbasabi  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21236Schin 
220Sstevel@tonic-gate /*
23*12986SJohn.Zolnowsky@Sun.COM  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
26236Schin /*
27236Schin  * logadm/conf.c -- configuration file module
28236Schin  */
29236Schin 
300Sstevel@tonic-gate #include <stdio.h>
310Sstevel@tonic-gate #include <libintl.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <sys/types.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/mman.h>
360Sstevel@tonic-gate #include <ctype.h>
370Sstevel@tonic-gate #include <strings.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <stdlib.h>
40*12986SJohn.Zolnowsky@Sun.COM #include <limits.h>
410Sstevel@tonic-gate #include "err.h"
420Sstevel@tonic-gate #include "lut.h"
430Sstevel@tonic-gate #include "fn.h"
440Sstevel@tonic-gate #include "opts.h"
450Sstevel@tonic-gate #include "conf.h"
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* forward declarations of functions private to this module */
48*12986SJohn.Zolnowsky@Sun.COM static void fillconflist(int lineno, const char *entry,
490Sstevel@tonic-gate     struct opts *opts, const char *com, int flags);
500Sstevel@tonic-gate static void fillargs(char *arg);
510Sstevel@tonic-gate static char *nexttok(char **ptrptr);
52*12986SJohn.Zolnowsky@Sun.COM static void conf_print(FILE *cstream, FILE *tstream);
530Sstevel@tonic-gate 
540Sstevel@tonic-gate static const char *Confname;	/* name of the confile file */
55*12986SJohn.Zolnowsky@Sun.COM static int Conffd = -1;		/* file descriptor for config file */
560Sstevel@tonic-gate static char *Confbuf;		/* copy of the config file (a la mmap()) */
57*12986SJohn.Zolnowsky@Sun.COM static int Conflen;		/* length of mmap'd config file area */
58*12986SJohn.Zolnowsky@Sun.COM static const char *Timesname;	/* name of the timestamps file */
59*12986SJohn.Zolnowsky@Sun.COM static int Timesfd = -1;	/* file descriptor for timestamps file */
60*12986SJohn.Zolnowsky@Sun.COM static char *Timesbuf;		/* copy of the timestamps file (a la mmap()) */
61*12986SJohn.Zolnowsky@Sun.COM static int Timeslen;		/* length of mmap'd timestamps area */
62*12986SJohn.Zolnowsky@Sun.COM static int Singlefile;		/* Conf and Times in the same file */
63*12986SJohn.Zolnowsky@Sun.COM static int Changed;		/* what changes need to be written back */
64*12986SJohn.Zolnowsky@Sun.COM static int Canchange;		/* what changes can be written back */
65*12986SJohn.Zolnowsky@Sun.COM static int Changing;		/* what changes have been requested */
66*12986SJohn.Zolnowsky@Sun.COM #define	CHG_NONE	0
67*12986SJohn.Zolnowsky@Sun.COM #define	CHG_TIMES	1
68*12986SJohn.Zolnowsky@Sun.COM #define	CHG_BOTH	3
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * our structured representation of the configuration file
720Sstevel@tonic-gate  * is made up of a list of these
730Sstevel@tonic-gate  */
74236Schin struct confinfo {
750Sstevel@tonic-gate 	struct confinfo *cf_next;
760Sstevel@tonic-gate 	int cf_lineno;		/* line number in file */
770Sstevel@tonic-gate 	const char *cf_entry;	/* name of entry, if line has an entry */
780Sstevel@tonic-gate 	struct opts *cf_opts;	/* parsed rhs of entry */
790Sstevel@tonic-gate 	const char *cf_com;	/* any comment text found */
800Sstevel@tonic-gate 	int cf_flags;
810Sstevel@tonic-gate };
820Sstevel@tonic-gate 
830Sstevel@tonic-gate #define	CONFF_DELETED	1	/* entry should be deleted on write back */
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static struct confinfo *Confinfo;	/* the entries in the config file */
860Sstevel@tonic-gate static struct confinfo *Confinfolast;	/* end of list */
870Sstevel@tonic-gate static struct lut *Conflut;		/* lookup table keyed by entry name */
880Sstevel@tonic-gate static struct fn_list *Confentries;	/* list of valid entry names */
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /* allocate & fill in another entry in our list */
910Sstevel@tonic-gate static void
fillconflist(int lineno,const char * entry,struct opts * opts,const char * com,int flags)92*12986SJohn.Zolnowsky@Sun.COM fillconflist(int lineno, const char *entry,
930Sstevel@tonic-gate     struct opts *opts, const char *com, int flags)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	struct confinfo *cp = MALLOC(sizeof (*cp));
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	cp->cf_next = NULL;
980Sstevel@tonic-gate 	cp->cf_lineno = lineno;
990Sstevel@tonic-gate 	cp->cf_entry = entry;
1000Sstevel@tonic-gate 	cp->cf_opts = opts;
1010Sstevel@tonic-gate 	cp->cf_com = com;
1020Sstevel@tonic-gate 	cp->cf_flags = flags;
1032397Sbasabi 	if (entry != NULL) {
1040Sstevel@tonic-gate 		Conflut = lut_add(Conflut, entry, cp);
1050Sstevel@tonic-gate 		fn_list_adds(Confentries, entry);
1060Sstevel@tonic-gate 	}
1070Sstevel@tonic-gate 	if (Confinfo == NULL)
1080Sstevel@tonic-gate 		Confinfo = Confinfolast = cp;
1090Sstevel@tonic-gate 	else {
1100Sstevel@tonic-gate 		Confinfolast->cf_next = cp;
1110Sstevel@tonic-gate 		Confinfolast = cp;
1120Sstevel@tonic-gate 	}
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static char **Args;	/* static buffer for args */
1160Sstevel@tonic-gate static int ArgsN;	/* size of our static buffer */
1170Sstevel@tonic-gate static int ArgsI;	/* index into Cmdargs as we walk table */
1180Sstevel@tonic-gate #define	CONF_ARGS_INC	1024
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate /* callback for lut_walk to build a cmdargs vector */
1210Sstevel@tonic-gate static void
fillargs(char * arg)1220Sstevel@tonic-gate fillargs(char *arg)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate 	if (ArgsI >= ArgsN) {
1250Sstevel@tonic-gate 		/* need bigger table */
1260Sstevel@tonic-gate 		Args = REALLOC(Args, sizeof (char *) * (ArgsN + CONF_ARGS_INC));
1270Sstevel@tonic-gate 		ArgsN += CONF_ARGS_INC;
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 	Args[ArgsI++] = arg;
1300Sstevel@tonic-gate }
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /* isolate and return the next token */
1330Sstevel@tonic-gate static char *
nexttok(char ** ptrptr)1340Sstevel@tonic-gate nexttok(char **ptrptr)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	char *ptr = *ptrptr;
1370Sstevel@tonic-gate 	char *eptr;
1380Sstevel@tonic-gate 	char *quote = NULL;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	while (*ptr && isspace(*ptr))
1410Sstevel@tonic-gate 		ptr++;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 	if (*ptr == '"' || *ptr == '\'')
1440Sstevel@tonic-gate 		quote = ptr++;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate 	for (eptr = ptr; *eptr; eptr++)
1470Sstevel@tonic-gate 		if (quote && *eptr == *quote) {
1480Sstevel@tonic-gate 			/* found end quote */
1490Sstevel@tonic-gate 			*eptr++ = '\0';
1500Sstevel@tonic-gate 			*ptrptr = eptr;
1510Sstevel@tonic-gate 			return (ptr);
1520Sstevel@tonic-gate 		} else if (!quote && isspace(*eptr)) {
1530Sstevel@tonic-gate 			/* found end of unquoted area */
1540Sstevel@tonic-gate 			*eptr++ = '\0';
1550Sstevel@tonic-gate 			*ptrptr = eptr;
1560Sstevel@tonic-gate 			return (ptr);
1570Sstevel@tonic-gate 		}
1580Sstevel@tonic-gate 
1592397Sbasabi 	if (quote != NULL)
1600Sstevel@tonic-gate 		err(EF_FILE|EF_JMP, "Unbalanced %c quote", *quote);
1610Sstevel@tonic-gate 		/*NOTREACHED*/
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	*ptrptr = eptr;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate 	if (ptr == eptr)
1660Sstevel@tonic-gate 		return (NULL);
1670Sstevel@tonic-gate 	else
1680Sstevel@tonic-gate 		return (ptr);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate /*
172*12986SJohn.Zolnowsky@Sun.COM  * scan the memory image of a file
173*12986SJohn.Zolnowsky@Sun.COM  *	returns: 0: error, 1: ok, 3: -P option found
1740Sstevel@tonic-gate  */
175*12986SJohn.Zolnowsky@Sun.COM static int
conf_scan(const char * fname,char * buf,int buflen,int timescan,struct opts * cliopts)176*12986SJohn.Zolnowsky@Sun.COM conf_scan(const char *fname, char *buf, int buflen, int timescan,
177*12986SJohn.Zolnowsky@Sun.COM     struct opts *cliopts)
1780Sstevel@tonic-gate {
179*12986SJohn.Zolnowsky@Sun.COM 	int ret = 1;
1800Sstevel@tonic-gate 	int lineno = 0;
1810Sstevel@tonic-gate 	char *line;
1820Sstevel@tonic-gate 	char *eline;
1830Sstevel@tonic-gate 	char *ebuf;
184*12986SJohn.Zolnowsky@Sun.COM 	char *entry, *comment;
1850Sstevel@tonic-gate 
186*12986SJohn.Zolnowsky@Sun.COM 	ebuf = &buf[buflen];
1870Sstevel@tonic-gate 
188*12986SJohn.Zolnowsky@Sun.COM 	if (buf[buflen - 1] != '\n')
189*12986SJohn.Zolnowsky@Sun.COM 		err(EF_WARN|EF_FILE, "file %s doesn't end with newline, "
190*12986SJohn.Zolnowsky@Sun.COM 		    "last line ignored.", fname);
1910Sstevel@tonic-gate 
192*12986SJohn.Zolnowsky@Sun.COM 	for (line = buf; line < ebuf; line = eline) {
193*12986SJohn.Zolnowsky@Sun.COM 		char *ap;
194*12986SJohn.Zolnowsky@Sun.COM 		struct opts *opts = NULL;
195*12986SJohn.Zolnowsky@Sun.COM 		struct confinfo *cp;
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 		lineno++;
198*12986SJohn.Zolnowsky@Sun.COM 		err_fileline(fname, lineno);
1990Sstevel@tonic-gate 		eline = line;
2000Sstevel@tonic-gate 		comment = NULL;
2010Sstevel@tonic-gate 		for (; eline < ebuf; eline++) {
2020Sstevel@tonic-gate 			/* check for continued lines */
2030Sstevel@tonic-gate 			if (comment == NULL && *eline == '\\' &&
2040Sstevel@tonic-gate 			    eline + 1 < ebuf && *(eline + 1) == '\n') {
2050Sstevel@tonic-gate 				*eline = ' ';
2060Sstevel@tonic-gate 				*(eline + 1) = ' ';
2070Sstevel@tonic-gate 				lineno++;
208*12986SJohn.Zolnowsky@Sun.COM 				err_fileline(fname, lineno);
2090Sstevel@tonic-gate 				continue;
2100Sstevel@tonic-gate 			}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 			/* check for comments */
2130Sstevel@tonic-gate 			if (comment == NULL && *eline == '#') {
2140Sstevel@tonic-gate 				*eline = '\0';
2150Sstevel@tonic-gate 				comment = (eline + 1);
2160Sstevel@tonic-gate 				continue;
2170Sstevel@tonic-gate 			}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 			/* check for end of line */
2200Sstevel@tonic-gate 			if (*eline == '\n')
2210Sstevel@tonic-gate 				break;
2220Sstevel@tonic-gate 		}
2230Sstevel@tonic-gate 		if (comment >= ebuf)
2240Sstevel@tonic-gate 			comment = NULL;
225*12986SJohn.Zolnowsky@Sun.COM 		if (eline >= ebuf) {
226*12986SJohn.Zolnowsky@Sun.COM 			/* discard trailing unterminated line */
227*12986SJohn.Zolnowsky@Sun.COM 			continue;
228*12986SJohn.Zolnowsky@Sun.COM 		}
229*12986SJohn.Zolnowsky@Sun.COM 		*eline++ = '\0';
2300Sstevel@tonic-gate 
231*12986SJohn.Zolnowsky@Sun.COM 		/*
232*12986SJohn.Zolnowsky@Sun.COM 		 * now we have the entry, if any, at "line"
233*12986SJohn.Zolnowsky@Sun.COM 		 * and the comment, if any, at "comment"
234*12986SJohn.Zolnowsky@Sun.COM 		 */
2350Sstevel@tonic-gate 
236*12986SJohn.Zolnowsky@Sun.COM 		/* entry is first token */
237*12986SJohn.Zolnowsky@Sun.COM 		entry = nexttok(&line);
238*12986SJohn.Zolnowsky@Sun.COM 		if (entry == NULL) {
239*12986SJohn.Zolnowsky@Sun.COM 			/* it's just a comment line */
240*12986SJohn.Zolnowsky@Sun.COM 			if (!timescan)
241*12986SJohn.Zolnowsky@Sun.COM 				fillconflist(lineno, entry, NULL, comment, 0);
242*12986SJohn.Zolnowsky@Sun.COM 			continue;
243*12986SJohn.Zolnowsky@Sun.COM 		}
244*12986SJohn.Zolnowsky@Sun.COM 		if (strcmp(entry, "logadm-version") == 0) {
2450Sstevel@tonic-gate 			/*
246*12986SJohn.Zolnowsky@Sun.COM 			 * we somehow opened some future format
247*12986SJohn.Zolnowsky@Sun.COM 			 * conffile that we likely don't understand.
248*12986SJohn.Zolnowsky@Sun.COM 			 * if the given version is "1" then go on,
249*12986SJohn.Zolnowsky@Sun.COM 			 * otherwise someone is mixing versions
250*12986SJohn.Zolnowsky@Sun.COM 			 * and we can't help them other than to
251*12986SJohn.Zolnowsky@Sun.COM 			 * print an error and exit.
2520Sstevel@tonic-gate 			 */
2530Sstevel@tonic-gate 			if ((entry = nexttok(&line)) != NULL &&
254*12986SJohn.Zolnowsky@Sun.COM 			    strcmp(entry, "1") != 0)
255*12986SJohn.Zolnowsky@Sun.COM 				err(0, "%s version not supported "
256*12986SJohn.Zolnowsky@Sun.COM 				    "by this version of logadm.",
257*12986SJohn.Zolnowsky@Sun.COM 				    fname);
258*12986SJohn.Zolnowsky@Sun.COM 			continue;
259*12986SJohn.Zolnowsky@Sun.COM 		}
260*12986SJohn.Zolnowsky@Sun.COM 
261*12986SJohn.Zolnowsky@Sun.COM 		/* form an argv array */
262*12986SJohn.Zolnowsky@Sun.COM 		ArgsI = 0;
263*12986SJohn.Zolnowsky@Sun.COM 		while (ap = nexttok(&line))
264*12986SJohn.Zolnowsky@Sun.COM 			fillargs(ap);
265*12986SJohn.Zolnowsky@Sun.COM 		Args[ArgsI] = NULL;
266*12986SJohn.Zolnowsky@Sun.COM 
267*12986SJohn.Zolnowsky@Sun.COM 		LOCAL_ERR_BEGIN {
268*12986SJohn.Zolnowsky@Sun.COM 			if (SETJMP) {
269*12986SJohn.Zolnowsky@Sun.COM 				err(EF_FILE, "cannot process invalid entry %s",
270*12986SJohn.Zolnowsky@Sun.COM 				    entry);
271*12986SJohn.Zolnowsky@Sun.COM 				ret = 0;
272*12986SJohn.Zolnowsky@Sun.COM 				LOCAL_ERR_BREAK;
273*12986SJohn.Zolnowsky@Sun.COM 			}
274*12986SJohn.Zolnowsky@Sun.COM 
275*12986SJohn.Zolnowsky@Sun.COM 			if (timescan) {
276*12986SJohn.Zolnowsky@Sun.COM 				/* append to config options */
277*12986SJohn.Zolnowsky@Sun.COM 				cp = lut_lookup(Conflut, entry);
278*12986SJohn.Zolnowsky@Sun.COM 				if (cp == NULL) {
279*12986SJohn.Zolnowsky@Sun.COM 					/* orphaned entry */
280*12986SJohn.Zolnowsky@Sun.COM 					if (opts_count(cliopts, "v"))
281*12986SJohn.Zolnowsky@Sun.COM 						err(EF_FILE, "stale timestamp "
282*12986SJohn.Zolnowsky@Sun.COM 						    "for %s", entry);
283*12986SJohn.Zolnowsky@Sun.COM 					LOCAL_ERR_BREAK;
284*12986SJohn.Zolnowsky@Sun.COM 				}
285*12986SJohn.Zolnowsky@Sun.COM 				opts = cp->cf_opts;
286*12986SJohn.Zolnowsky@Sun.COM 			}
287*12986SJohn.Zolnowsky@Sun.COM 			opts = opts_parse(opts, Args, OPTF_CONF);
288*12986SJohn.Zolnowsky@Sun.COM 			if (!timescan) {
289*12986SJohn.Zolnowsky@Sun.COM 				fillconflist(lineno, entry, opts, comment, 0);
290*12986SJohn.Zolnowsky@Sun.COM 			}
291*12986SJohn.Zolnowsky@Sun.COM 		LOCAL_ERR_END }
292*12986SJohn.Zolnowsky@Sun.COM 
293*12986SJohn.Zolnowsky@Sun.COM 		if (ret == 1 && opts && opts_optarg(opts, "P") != NULL)
294*12986SJohn.Zolnowsky@Sun.COM 			ret = 3;
295*12986SJohn.Zolnowsky@Sun.COM 	}
296*12986SJohn.Zolnowsky@Sun.COM 
297*12986SJohn.Zolnowsky@Sun.COM 	err_fileline(NULL, 0);
298*12986SJohn.Zolnowsky@Sun.COM 	return (ret);
299*12986SJohn.Zolnowsky@Sun.COM }
300*12986SJohn.Zolnowsky@Sun.COM 
301*12986SJohn.Zolnowsky@Sun.COM /*
302*12986SJohn.Zolnowsky@Sun.COM  * conf_open -- open the configuration file, lock it if we have write perms
303*12986SJohn.Zolnowsky@Sun.COM  */
304*12986SJohn.Zolnowsky@Sun.COM int
conf_open(const char * cfname,const char * tfname,struct opts * cliopts)305*12986SJohn.Zolnowsky@Sun.COM conf_open(const char *cfname, const char *tfname, struct opts *cliopts)
306*12986SJohn.Zolnowsky@Sun.COM {
307*12986SJohn.Zolnowsky@Sun.COM 	struct stat stbuf1, stbuf2, stbuf3;
308*12986SJohn.Zolnowsky@Sun.COM 	struct flock	flock;
309*12986SJohn.Zolnowsky@Sun.COM 	int ret;
310*12986SJohn.Zolnowsky@Sun.COM 
311*12986SJohn.Zolnowsky@Sun.COM 	Confname = cfname;
312*12986SJohn.Zolnowsky@Sun.COM 	Timesname = tfname;
313*12986SJohn.Zolnowsky@Sun.COM 	Confentries = fn_list_new(NULL);
314*12986SJohn.Zolnowsky@Sun.COM 	Changed = CHG_NONE;
315*12986SJohn.Zolnowsky@Sun.COM 
316*12986SJohn.Zolnowsky@Sun.COM 	Changing = CHG_TIMES;
317*12986SJohn.Zolnowsky@Sun.COM 	if (opts_count(cliopts, "Vn") != 0)
318*12986SJohn.Zolnowsky@Sun.COM 		Changing = CHG_NONE;
319*12986SJohn.Zolnowsky@Sun.COM 	else if (opts_count(cliopts, "rw") != 0)
320*12986SJohn.Zolnowsky@Sun.COM 		Changing = CHG_BOTH;
321*12986SJohn.Zolnowsky@Sun.COM 
322*12986SJohn.Zolnowsky@Sun.COM 	Singlefile = strcmp(Confname, Timesname) == 0;
323*12986SJohn.Zolnowsky@Sun.COM 	if (Singlefile && Changing == CHG_TIMES)
324*12986SJohn.Zolnowsky@Sun.COM 		Changing = CHG_BOTH;
325*12986SJohn.Zolnowsky@Sun.COM 
326*12986SJohn.Zolnowsky@Sun.COM 	/* special case this so we don't even try locking the file */
327*12986SJohn.Zolnowsky@Sun.COM 	if (strcmp(Confname, "/dev/null") == 0)
328*12986SJohn.Zolnowsky@Sun.COM 		return (0);
329*12986SJohn.Zolnowsky@Sun.COM 
330*12986SJohn.Zolnowsky@Sun.COM 	while (Conffd == -1) {
331*12986SJohn.Zolnowsky@Sun.COM 		Canchange = CHG_BOTH;
332*12986SJohn.Zolnowsky@Sun.COM 		if ((Conffd = open(Confname, O_RDWR)) < 0) {
333*12986SJohn.Zolnowsky@Sun.COM 			if (Changing == CHG_BOTH)
334*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Confname);
335*12986SJohn.Zolnowsky@Sun.COM 			Canchange = CHG_TIMES;
336*12986SJohn.Zolnowsky@Sun.COM 			if ((Conffd = open(Confname, O_RDONLY)) < 0)
337*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Confname);
338*12986SJohn.Zolnowsky@Sun.COM 		}
3390Sstevel@tonic-gate 
340*12986SJohn.Zolnowsky@Sun.COM 		flock.l_type = (Canchange == CHG_BOTH) ? F_WRLCK : F_RDLCK;
341*12986SJohn.Zolnowsky@Sun.COM 		flock.l_whence = SEEK_SET;
342*12986SJohn.Zolnowsky@Sun.COM 		flock.l_start = 0;
343*12986SJohn.Zolnowsky@Sun.COM 		flock.l_len = 1;
344*12986SJohn.Zolnowsky@Sun.COM 		if (fcntl(Conffd, F_SETLKW, &flock) < 0)
345*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "flock on %s", Confname);
346*12986SJohn.Zolnowsky@Sun.COM 
347*12986SJohn.Zolnowsky@Sun.COM 		/* wait until after file is locked to get filesize */
348*12986SJohn.Zolnowsky@Sun.COM 		if (fstat(Conffd, &stbuf1) < 0)
349*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "fstat on %s", Confname);
350*12986SJohn.Zolnowsky@Sun.COM 
351*12986SJohn.Zolnowsky@Sun.COM 		/* verify that we've got a lock on the active file */
352*12986SJohn.Zolnowsky@Sun.COM 		if (stat(Confname, &stbuf2) < 0 ||
353*12986SJohn.Zolnowsky@Sun.COM 		    !(stbuf2.st_dev == stbuf1.st_dev &&
354*12986SJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf1.st_ino)) {
355*12986SJohn.Zolnowsky@Sun.COM 			/* wrong config file, try again */
356*12986SJohn.Zolnowsky@Sun.COM 			(void) close(Conffd);
357*12986SJohn.Zolnowsky@Sun.COM 			Conffd = -1;
358*12986SJohn.Zolnowsky@Sun.COM 		}
359*12986SJohn.Zolnowsky@Sun.COM 	}
360*12986SJohn.Zolnowsky@Sun.COM 
361*12986SJohn.Zolnowsky@Sun.COM 	while (!Singlefile && Timesfd == -1) {
362*12986SJohn.Zolnowsky@Sun.COM 		if ((Timesfd = open(Timesname, O_CREAT|O_RDWR, 0644)) < 0) {
363*12986SJohn.Zolnowsky@Sun.COM 			if (Changing != CHG_NONE)
364*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Timesname);
365*12986SJohn.Zolnowsky@Sun.COM 			Canchange = CHG_NONE;
366*12986SJohn.Zolnowsky@Sun.COM 			if ((Timesfd = open(Timesname, O_RDONLY)) < 0)
367*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Timesname);
3680Sstevel@tonic-gate 		}
369*12986SJohn.Zolnowsky@Sun.COM 
370*12986SJohn.Zolnowsky@Sun.COM 		flock.l_type = (Canchange != CHG_NONE) ? F_WRLCK : F_RDLCK;
371*12986SJohn.Zolnowsky@Sun.COM 		flock.l_whence = SEEK_SET;
372*12986SJohn.Zolnowsky@Sun.COM 		flock.l_start = 0;
373*12986SJohn.Zolnowsky@Sun.COM 		flock.l_len = 1;
374*12986SJohn.Zolnowsky@Sun.COM 		if (fcntl(Timesfd, F_SETLKW, &flock) < 0)
375*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "flock on %s", Timesname);
376*12986SJohn.Zolnowsky@Sun.COM 
377*12986SJohn.Zolnowsky@Sun.COM 		/* wait until after file is locked to get filesize */
378*12986SJohn.Zolnowsky@Sun.COM 		if (fstat(Timesfd, &stbuf2) < 0)
379*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "fstat on %s", Timesname);
380*12986SJohn.Zolnowsky@Sun.COM 
381*12986SJohn.Zolnowsky@Sun.COM 		/* verify that we've got a lock on the active file */
382*12986SJohn.Zolnowsky@Sun.COM 		if (stat(Timesname, &stbuf3) < 0 ||
383*12986SJohn.Zolnowsky@Sun.COM 		    !(stbuf2.st_dev == stbuf3.st_dev &&
384*12986SJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf3.st_ino)) {
385*12986SJohn.Zolnowsky@Sun.COM 			/* wrong timestamp file, try again */
386*12986SJohn.Zolnowsky@Sun.COM 			(void) close(Timesfd);
387*12986SJohn.Zolnowsky@Sun.COM 			Timesfd = -1;
388*12986SJohn.Zolnowsky@Sun.COM 			continue;
389*12986SJohn.Zolnowsky@Sun.COM 		}
390*12986SJohn.Zolnowsky@Sun.COM 
391*12986SJohn.Zolnowsky@Sun.COM 		/* check that Timesname isn't an alias for Confname */
392*12986SJohn.Zolnowsky@Sun.COM 		if (stbuf2.st_dev == stbuf1.st_dev &&
393*12986SJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf1.st_ino)
394*12986SJohn.Zolnowsky@Sun.COM 			err(0, "Timestamp file %s can't refer to "
395*12986SJohn.Zolnowsky@Sun.COM 			    "Configuration file %s", Timesname, Confname);
3960Sstevel@tonic-gate 	}
397*12986SJohn.Zolnowsky@Sun.COM 
398*12986SJohn.Zolnowsky@Sun.COM 	Conflen = stbuf1.st_size;
399*12986SJohn.Zolnowsky@Sun.COM 	Timeslen = stbuf2.st_size;
400*12986SJohn.Zolnowsky@Sun.COM 
401*12986SJohn.Zolnowsky@Sun.COM 	if (Conflen == 0)
402*12986SJohn.Zolnowsky@Sun.COM 		return (1);	/* empty file, don't bother parsing it */
403*12986SJohn.Zolnowsky@Sun.COM 
404*12986SJohn.Zolnowsky@Sun.COM 	if ((Confbuf = (char *)mmap(0, Conflen,
405*12986SJohn.Zolnowsky@Sun.COM 	    PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1)
406*12986SJohn.Zolnowsky@Sun.COM 		err(EF_SYS, "mmap on %s", Confname);
407*12986SJohn.Zolnowsky@Sun.COM 
408*12986SJohn.Zolnowsky@Sun.COM 	ret = conf_scan(Confname, Confbuf, Conflen, 0, cliopts);
409*12986SJohn.Zolnowsky@Sun.COM 	if (ret == 3 && !Singlefile && Canchange == CHG_BOTH) {
410*12986SJohn.Zolnowsky@Sun.COM 		/*
411*12986SJohn.Zolnowsky@Sun.COM 		 * arrange to transfer any timestamps
412*12986SJohn.Zolnowsky@Sun.COM 		 * from conf_file to timestamps_file
413*12986SJohn.Zolnowsky@Sun.COM 		 */
414*12986SJohn.Zolnowsky@Sun.COM 		Changing = Changed = CHG_BOTH;
415*12986SJohn.Zolnowsky@Sun.COM 	}
416*12986SJohn.Zolnowsky@Sun.COM 
417*12986SJohn.Zolnowsky@Sun.COM 	if (Timesfd != -1 && Timeslen != 0) {
418*12986SJohn.Zolnowsky@Sun.COM 		if ((Timesbuf = (char *)mmap(0, Timeslen,
419*12986SJohn.Zolnowsky@Sun.COM 		    PROT_READ | PROT_WRITE, MAP_PRIVATE,
420*12986SJohn.Zolnowsky@Sun.COM 		    Timesfd, 0)) == (char *)-1)
421*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "mmap on %s", Timesname);
422*12986SJohn.Zolnowsky@Sun.COM 		ret &= conf_scan(Timesname, Timesbuf, Timeslen, 1, cliopts);
423*12986SJohn.Zolnowsky@Sun.COM 	}
424*12986SJohn.Zolnowsky@Sun.COM 
4250Sstevel@tonic-gate 	/*
4260Sstevel@tonic-gate 	 * possible future enhancement:  go through and mark any entries:
4270Sstevel@tonic-gate 	 * 		logfile -P <date>
4280Sstevel@tonic-gate 	 * as DELETED if the logfile doesn't exist
4290Sstevel@tonic-gate 	 */
430*12986SJohn.Zolnowsky@Sun.COM 
431*12986SJohn.Zolnowsky@Sun.COM 	return (ret);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate  * conf_close -- close the configuration file
4360Sstevel@tonic-gate  */
4370Sstevel@tonic-gate void
conf_close(struct opts * opts)4380Sstevel@tonic-gate conf_close(struct opts *opts)
4390Sstevel@tonic-gate {
440*12986SJohn.Zolnowsky@Sun.COM 	char cuname[PATH_MAX], tuname[PATH_MAX];
441*12986SJohn.Zolnowsky@Sun.COM 	int cfd, tfd;
442*12986SJohn.Zolnowsky@Sun.COM 	FILE *cfp = NULL, *tfp = NULL;
443*12986SJohn.Zolnowsky@Sun.COM 	boolean_t safe_update = B_TRUE;
4440Sstevel@tonic-gate 
445*12986SJohn.Zolnowsky@Sun.COM 	if (Changed == CHG_NONE || opts_count(opts, "n") != 0) {
4460Sstevel@tonic-gate 		if (opts_count(opts, "v"))
447*12986SJohn.Zolnowsky@Sun.COM 			(void) out("# %s and %s unchanged\n",
448*12986SJohn.Zolnowsky@Sun.COM 			    Confname, Timesname);
449*12986SJohn.Zolnowsky@Sun.COM 		goto cleanup;
450*12986SJohn.Zolnowsky@Sun.COM 	}
451*12986SJohn.Zolnowsky@Sun.COM 
452*12986SJohn.Zolnowsky@Sun.COM 	if (Debug > 1) {
453*12986SJohn.Zolnowsky@Sun.COM 		(void) fprintf(stderr, "conf_close, saving logadm context:\n");
454*12986SJohn.Zolnowsky@Sun.COM 		conf_print(stderr, NULL);
4550Sstevel@tonic-gate 	}
4560Sstevel@tonic-gate 
457*12986SJohn.Zolnowsky@Sun.COM 	cuname[0] = tuname[0] = '\0';
458*12986SJohn.Zolnowsky@Sun.COM 	LOCAL_ERR_BEGIN {
459*12986SJohn.Zolnowsky@Sun.COM 		if (SETJMP) {
460*12986SJohn.Zolnowsky@Sun.COM 			safe_update = B_FALSE;
461*12986SJohn.Zolnowsky@Sun.COM 			LOCAL_ERR_BREAK;
462*12986SJohn.Zolnowsky@Sun.COM 		}
463*12986SJohn.Zolnowsky@Sun.COM 		if (Changed == CHG_BOTH) {
464*12986SJohn.Zolnowsky@Sun.COM 			if (Canchange != CHG_BOTH)
465*12986SJohn.Zolnowsky@Sun.COM 				err(EF_JMP, "internal error: attempting "
466*12986SJohn.Zolnowsky@Sun.COM 				    "to update %s without locking", Confname);
467*12986SJohn.Zolnowsky@Sun.COM 			(void) snprintf(cuname, sizeof (cuname), "%sXXXXXX",
468*12986SJohn.Zolnowsky@Sun.COM 			    Confname);
469*12986SJohn.Zolnowsky@Sun.COM 			if ((cfd = mkstemp(cuname)) == -1)
470*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "open %s replacement",
471*12986SJohn.Zolnowsky@Sun.COM 				    Confname);
472*12986SJohn.Zolnowsky@Sun.COM 			if (opts_count(opts, "v"))
473*12986SJohn.Zolnowsky@Sun.COM 				(void) out("# writing changes to %s\n", cuname);
474*12986SJohn.Zolnowsky@Sun.COM 			if (fchmod(cfd, 0644) == -1)
475*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "chmod %s", cuname);
476*12986SJohn.Zolnowsky@Sun.COM 			if ((cfp = fdopen(cfd, "w")) == NULL)
477*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "fdopen on %s", cuname);
478*12986SJohn.Zolnowsky@Sun.COM 		} else {
479*12986SJohn.Zolnowsky@Sun.COM 			/* just toss away the configuration data */
480*12986SJohn.Zolnowsky@Sun.COM 			cfp = fopen("/dev/null", "w");
481*12986SJohn.Zolnowsky@Sun.COM 		}
482*12986SJohn.Zolnowsky@Sun.COM 		if (!Singlefile) {
483*12986SJohn.Zolnowsky@Sun.COM 			if (Canchange == CHG_NONE)
484*12986SJohn.Zolnowsky@Sun.COM 				err(EF_JMP, "internal error: attempting "
485*12986SJohn.Zolnowsky@Sun.COM 				    "to update %s without locking", Timesname);
486*12986SJohn.Zolnowsky@Sun.COM 			(void) snprintf(tuname, sizeof (tuname), "%sXXXXXX",
487*12986SJohn.Zolnowsky@Sun.COM 			    Timesname);
488*12986SJohn.Zolnowsky@Sun.COM 			if ((tfd = mkstemp(tuname)) == -1)
489*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "open %s replacement",
490*12986SJohn.Zolnowsky@Sun.COM 				    Timesname);
491*12986SJohn.Zolnowsky@Sun.COM 			if (opts_count(opts, "v"))
492*12986SJohn.Zolnowsky@Sun.COM 				(void) out("# writing changes to %s\n", tuname);
493*12986SJohn.Zolnowsky@Sun.COM 			if (fchmod(tfd, 0644) == -1)
494*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "chmod %s", tuname);
495*12986SJohn.Zolnowsky@Sun.COM 			if ((tfp = fdopen(tfd, "w")) == NULL)
496*12986SJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "fdopen on %s", tuname);
497*12986SJohn.Zolnowsky@Sun.COM 		}
498*12986SJohn.Zolnowsky@Sun.COM 
499*12986SJohn.Zolnowsky@Sun.COM 		conf_print(cfp, tfp);
500*12986SJohn.Zolnowsky@Sun.COM 		if (fclose(cfp) < 0)
501*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS|EF_JMP, "fclose on %s", Confname);
502*12986SJohn.Zolnowsky@Sun.COM 		if (tfp != NULL && fclose(tfp) < 0)
503*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS|EF_JMP, "fclose on %s", Timesname);
504*12986SJohn.Zolnowsky@Sun.COM 	LOCAL_ERR_END }
505*12986SJohn.Zolnowsky@Sun.COM 
506*12986SJohn.Zolnowsky@Sun.COM 	if (!safe_update) {
507*12986SJohn.Zolnowsky@Sun.COM 		if (cuname[0] != 0)
508*12986SJohn.Zolnowsky@Sun.COM 			(void) unlink(cuname);
509*12986SJohn.Zolnowsky@Sun.COM 		if (tuname[0] != 0)
510*12986SJohn.Zolnowsky@Sun.COM 			(void) unlink(tuname);
511*12986SJohn.Zolnowsky@Sun.COM 		err(EF_JMP, "unsafe to update configuration file "
512*12986SJohn.Zolnowsky@Sun.COM 		    "or timestamps");
513*12986SJohn.Zolnowsky@Sun.COM 		return;
514*12986SJohn.Zolnowsky@Sun.COM 	}
515*12986SJohn.Zolnowsky@Sun.COM 
516*12986SJohn.Zolnowsky@Sun.COM 	/* rename updated files into place */
517*12986SJohn.Zolnowsky@Sun.COM 	if (cuname[0] != '\0')
518*12986SJohn.Zolnowsky@Sun.COM 		if (rename(cuname, Confname) < 0)
519*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "rename %s to %s", cuname, Confname);
520*12986SJohn.Zolnowsky@Sun.COM 	if (tuname[0] != '\0')
521*12986SJohn.Zolnowsky@Sun.COM 		if (rename(tuname, Timesname) < 0)
522*12986SJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "rename %s to %s", tuname, Timesname);
523*12986SJohn.Zolnowsky@Sun.COM 	Changed = CHG_NONE;
524*12986SJohn.Zolnowsky@Sun.COM 
525*12986SJohn.Zolnowsky@Sun.COM cleanup:
5260Sstevel@tonic-gate 	if (Conffd != -1) {
5270Sstevel@tonic-gate 		(void) close(Conffd);
5280Sstevel@tonic-gate 		Conffd = -1;
5290Sstevel@tonic-gate 	}
530*12986SJohn.Zolnowsky@Sun.COM 	if (Timesfd != -1) {
531*12986SJohn.Zolnowsky@Sun.COM 		(void) close(Timesfd);
532*12986SJohn.Zolnowsky@Sun.COM 		Timesfd = -1;
533*12986SJohn.Zolnowsky@Sun.COM 	}
5340Sstevel@tonic-gate 	if (Conflut) {
5350Sstevel@tonic-gate 		lut_free(Conflut, free);
5360Sstevel@tonic-gate 		Conflut = NULL;
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 	if (Confentries) {
5390Sstevel@tonic-gate 		fn_list_free(Confentries);
5400Sstevel@tonic-gate 		Confentries = NULL;
5410Sstevel@tonic-gate 	}
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate 
5440Sstevel@tonic-gate /*
5450Sstevel@tonic-gate  * conf_lookup -- lookup an entry in the config file
5460Sstevel@tonic-gate  */
547*12986SJohn.Zolnowsky@Sun.COM void *
conf_lookup(const char * lhs)5480Sstevel@tonic-gate conf_lookup(const char *lhs)
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5510Sstevel@tonic-gate 
552*12986SJohn.Zolnowsky@Sun.COM 	if (cp != NULL)
5530Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
554*12986SJohn.Zolnowsky@Sun.COM 	return (cp);
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate  * conf_opts -- return the parsed opts for an entry
5590Sstevel@tonic-gate  */
5600Sstevel@tonic-gate struct opts *
conf_opts(const char * lhs)5610Sstevel@tonic-gate conf_opts(const char *lhs)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5640Sstevel@tonic-gate 
565*12986SJohn.Zolnowsky@Sun.COM 	if (cp != NULL)
5660Sstevel@tonic-gate 		return (cp->cf_opts);
567*12986SJohn.Zolnowsky@Sun.COM 	return (opts_parse(NULL, NULL, OPTF_CONF));
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate  * conf_replace -- replace an entry in the config file
5720Sstevel@tonic-gate  */
5730Sstevel@tonic-gate void
conf_replace(const char * lhs,struct opts * newopts)5740Sstevel@tonic-gate conf_replace(const char *lhs, struct opts *newopts)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	if (Conffd == -1)
5790Sstevel@tonic-gate 		return;
5800Sstevel@tonic-gate 
5812397Sbasabi 	if (cp != NULL) {
5820Sstevel@tonic-gate 		cp->cf_opts = newopts;
583*12986SJohn.Zolnowsky@Sun.COM 		/* cp->cf_args = NULL; */
5840Sstevel@tonic-gate 		if (newopts == NULL)
5850Sstevel@tonic-gate 			cp->cf_flags |= CONFF_DELETED;
5860Sstevel@tonic-gate 	} else
587*12986SJohn.Zolnowsky@Sun.COM 		fillconflist(0, lhs, newopts, NULL, 0);
588*12986SJohn.Zolnowsky@Sun.COM 
589*12986SJohn.Zolnowsky@Sun.COM 	Changed = CHG_BOTH;
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate /*
5930Sstevel@tonic-gate  * conf_set -- set options for an entry in the config file
5940Sstevel@tonic-gate  */
5950Sstevel@tonic-gate void
conf_set(const char * entry,char * o,const char * optarg)5960Sstevel@tonic-gate conf_set(const char *entry, char *o, const char *optarg)
5970Sstevel@tonic-gate {
5980Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, entry);
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	if (Conffd == -1)
6010Sstevel@tonic-gate 		return;
6020Sstevel@tonic-gate 
6032397Sbasabi 	if (cp != NULL) {
6040Sstevel@tonic-gate 		cp->cf_flags &= ~CONFF_DELETED;
6050Sstevel@tonic-gate 	} else {
606*12986SJohn.Zolnowsky@Sun.COM 		fillconflist(0, STRDUP(entry),
607*12986SJohn.Zolnowsky@Sun.COM 		    opts_parse(NULL, NULL, OPTF_CONF), NULL, 0);
6080Sstevel@tonic-gate 		if ((cp = lut_lookup(Conflut, entry)) == NULL)
6090Sstevel@tonic-gate 			err(0, "conf_set internal error");
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 	(void) opts_set(cp->cf_opts, o, optarg);
612*12986SJohn.Zolnowsky@Sun.COM 	if (strcmp(o, "P") == 0)
613*12986SJohn.Zolnowsky@Sun.COM 		Changed |= CHG_TIMES;
614*12986SJohn.Zolnowsky@Sun.COM 	else
615*12986SJohn.Zolnowsky@Sun.COM 		Changed = CHG_BOTH;
6160Sstevel@tonic-gate }
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate /*
6190Sstevel@tonic-gate  * conf_entries -- list all the entry names
6200Sstevel@tonic-gate  */
6210Sstevel@tonic-gate struct fn_list *
conf_entries(void)6220Sstevel@tonic-gate conf_entries(void)
6230Sstevel@tonic-gate {
6240Sstevel@tonic-gate 	return (Confentries);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate 
6270Sstevel@tonic-gate /* print the config file */
6280Sstevel@tonic-gate static void
conf_print(FILE * cstream,FILE * tstream)629*12986SJohn.Zolnowsky@Sun.COM conf_print(FILE *cstream, FILE *tstream)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate 	struct confinfo *cp;
632*12986SJohn.Zolnowsky@Sun.COM 	char *exclude_opts = "PFfhnrvVw";
633*12986SJohn.Zolnowsky@Sun.COM 	const char *timestamp;
6340Sstevel@tonic-gate 
635*12986SJohn.Zolnowsky@Sun.COM 	if (tstream == NULL) {
636*12986SJohn.Zolnowsky@Sun.COM 		exclude_opts++;		/* -P option goes to config file */
637*12986SJohn.Zolnowsky@Sun.COM 	} else {
638*12986SJohn.Zolnowsky@Sun.COM 		(void) fprintf(tstream, gettext(
639*12986SJohn.Zolnowsky@Sun.COM 		    "# This file holds internal data for logadm(1M).\n"
640*12986SJohn.Zolnowsky@Sun.COM 		    "# Do not edit.\n"));
641*12986SJohn.Zolnowsky@Sun.COM 	}
6420Sstevel@tonic-gate 	for (cp = Confinfo; cp; cp = cp->cf_next) {
6430Sstevel@tonic-gate 		if (cp->cf_flags & CONFF_DELETED)
6440Sstevel@tonic-gate 			continue;
6450Sstevel@tonic-gate 		if (cp->cf_entry) {
646*12986SJohn.Zolnowsky@Sun.COM 			opts_printword(cp->cf_entry, cstream);
647*12986SJohn.Zolnowsky@Sun.COM 			if (cp->cf_opts)
648*12986SJohn.Zolnowsky@Sun.COM 				opts_print(cp->cf_opts, cstream, exclude_opts);
649*12986SJohn.Zolnowsky@Sun.COM 			/* output timestamps to tstream */
650*12986SJohn.Zolnowsky@Sun.COM 			if (tstream != NULL && (timestamp =
651*12986SJohn.Zolnowsky@Sun.COM 			    opts_optarg(cp->cf_opts, "P")) != NULL) {
652*12986SJohn.Zolnowsky@Sun.COM 				opts_printword(cp->cf_entry, tstream);
653*12986SJohn.Zolnowsky@Sun.COM 				(void) fprintf(tstream, " -P ");
654*12986SJohn.Zolnowsky@Sun.COM 				opts_printword(timestamp, tstream);
655*12986SJohn.Zolnowsky@Sun.COM 				(void) fprintf(tstream, "\n");
6560Sstevel@tonic-gate 			}
6570Sstevel@tonic-gate 		}
6580Sstevel@tonic-gate 		if (cp->cf_com) {
6590Sstevel@tonic-gate 			if (cp->cf_entry)
660*12986SJohn.Zolnowsky@Sun.COM 				(void) fprintf(cstream, " ");
661*12986SJohn.Zolnowsky@Sun.COM 			(void) fprintf(cstream, "#%s", cp->cf_com);
6620Sstevel@tonic-gate 		}
663*12986SJohn.Zolnowsky@Sun.COM 		(void) fprintf(cstream, "\n");
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate #ifdef	TESTMODULE
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate  * test main for conf module, usage: a.out conffile
6710Sstevel@tonic-gate  */
6722397Sbasabi int
main(int argc,char * argv[])6730Sstevel@tonic-gate main(int argc, char *argv[])
6740Sstevel@tonic-gate {
675*12986SJohn.Zolnowsky@Sun.COM 	struct opts *opts;
676*12986SJohn.Zolnowsky@Sun.COM 
6770Sstevel@tonic-gate 	err_init(argv[0]);
6780Sstevel@tonic-gate 	setbuf(stdout, NULL);
679*12986SJohn.Zolnowsky@Sun.COM 	opts_init(Opttable, Opttable_cnt);
680*12986SJohn.Zolnowsky@Sun.COM 
681*12986SJohn.Zolnowsky@Sun.COM 	opts = opts_parse(NULL, NULL, 0);
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	if (argc != 2)
6840Sstevel@tonic-gate 		err(EF_RAW, "usage: %s conffile\n", argv[0]);
6850Sstevel@tonic-gate 
686*12986SJohn.Zolnowsky@Sun.COM 	conf_open(argv[1], argv[1], opts);
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 	printf("conffile <%s>:\n", argv[1]);
689*12986SJohn.Zolnowsky@Sun.COM 	conf_print(stdout, NULL);
6900Sstevel@tonic-gate 
691*12986SJohn.Zolnowsky@Sun.COM 	conf_close(opts);
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	err_done(0);
6942397Sbasabi 	/* NOTREACHED */
6952397Sbasabi 	return (0);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate #endif	/* TESTMODULE */
699