xref: /titanic_50/usr/src/cmd/logadm/conf.c (revision e9a193fce9f1bf8520f55929577e0175e1e7625b)
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
5b493790cSbasabi  * Common Development and Distribution License (the "License").
6b493790cSbasabi  * 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*e9a193fcSJohn.Zolnowsky@Sun.COM  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
2678eb75caSchin /*
2778eb75caSchin  * logadm/conf.c -- configuration file module
2878eb75caSchin  */
2978eb75caSchin 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <libintl.h>
327c478bd9Sstevel@tonic-gate #include <fcntl.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/stat.h>
357c478bd9Sstevel@tonic-gate #include <sys/mman.h>
367c478bd9Sstevel@tonic-gate #include <ctype.h>
377c478bd9Sstevel@tonic-gate #include <strings.h>
387c478bd9Sstevel@tonic-gate #include <unistd.h>
397c478bd9Sstevel@tonic-gate #include <stdlib.h>
40*e9a193fcSJohn.Zolnowsky@Sun.COM #include <limits.h>
417c478bd9Sstevel@tonic-gate #include "err.h"
427c478bd9Sstevel@tonic-gate #include "lut.h"
437c478bd9Sstevel@tonic-gate #include "fn.h"
447c478bd9Sstevel@tonic-gate #include "opts.h"
457c478bd9Sstevel@tonic-gate #include "conf.h"
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* forward declarations of functions private to this module */
48*e9a193fcSJohn.Zolnowsky@Sun.COM static void fillconflist(int lineno, const char *entry,
497c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags);
507c478bd9Sstevel@tonic-gate static void fillargs(char *arg);
517c478bd9Sstevel@tonic-gate static char *nexttok(char **ptrptr);
52*e9a193fcSJohn.Zolnowsky@Sun.COM static void conf_print(FILE *cstream, FILE *tstream);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static const char *Confname;	/* name of the confile file */
557c478bd9Sstevel@tonic-gate static int Conffd = -1;		/* file descriptor for config file */
56*e9a193fcSJohn.Zolnowsky@Sun.COM static char *Confbuf;		/* copy of the config file (a la mmap()) */
57*e9a193fcSJohn.Zolnowsky@Sun.COM static int Conflen;		/* length of mmap'd config file area */
58*e9a193fcSJohn.Zolnowsky@Sun.COM static const char *Timesname;	/* name of the timestamps file */
59*e9a193fcSJohn.Zolnowsky@Sun.COM static int Timesfd = -1;	/* file descriptor for timestamps file */
60*e9a193fcSJohn.Zolnowsky@Sun.COM static char *Timesbuf;		/* copy of the timestamps file (a la mmap()) */
61*e9a193fcSJohn.Zolnowsky@Sun.COM static int Timeslen;		/* length of mmap'd timestamps area */
62*e9a193fcSJohn.Zolnowsky@Sun.COM static int Singlefile;		/* Conf and Times in the same file */
63*e9a193fcSJohn.Zolnowsky@Sun.COM static int Changed;		/* what changes need to be written back */
64*e9a193fcSJohn.Zolnowsky@Sun.COM static int Canchange;		/* what changes can be written back */
65*e9a193fcSJohn.Zolnowsky@Sun.COM static int Changing;		/* what changes have been requested */
66*e9a193fcSJohn.Zolnowsky@Sun.COM #define	CHG_NONE	0
67*e9a193fcSJohn.Zolnowsky@Sun.COM #define	CHG_TIMES	1
68*e9a193fcSJohn.Zolnowsky@Sun.COM #define	CHG_BOTH	3
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * our structured representation of the configuration file
727c478bd9Sstevel@tonic-gate  * is made up of a list of these
737c478bd9Sstevel@tonic-gate  */
7478eb75caSchin struct confinfo {
757c478bd9Sstevel@tonic-gate 	struct confinfo *cf_next;
767c478bd9Sstevel@tonic-gate 	int cf_lineno;		/* line number in file */
777c478bd9Sstevel@tonic-gate 	const char *cf_entry;	/* name of entry, if line has an entry */
787c478bd9Sstevel@tonic-gate 	struct opts *cf_opts;	/* parsed rhs of entry */
797c478bd9Sstevel@tonic-gate 	const char *cf_com;	/* any comment text found */
807c478bd9Sstevel@tonic-gate 	int cf_flags;
817c478bd9Sstevel@tonic-gate };
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #define	CONFF_DELETED	1	/* entry should be deleted on write back */
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static struct confinfo *Confinfo;	/* the entries in the config file */
867c478bd9Sstevel@tonic-gate static struct confinfo *Confinfolast;	/* end of list */
877c478bd9Sstevel@tonic-gate static struct lut *Conflut;		/* lookup table keyed by entry name */
887c478bd9Sstevel@tonic-gate static struct fn_list *Confentries;	/* list of valid entry names */
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /* allocate & fill in another entry in our list */
917c478bd9Sstevel@tonic-gate static void
92*e9a193fcSJohn.Zolnowsky@Sun.COM fillconflist(int lineno, const char *entry,
937c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags)
947c478bd9Sstevel@tonic-gate {
957c478bd9Sstevel@tonic-gate 	struct confinfo *cp = MALLOC(sizeof (*cp));
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	cp->cf_next = NULL;
987c478bd9Sstevel@tonic-gate 	cp->cf_lineno = lineno;
997c478bd9Sstevel@tonic-gate 	cp->cf_entry = entry;
1007c478bd9Sstevel@tonic-gate 	cp->cf_opts = opts;
1017c478bd9Sstevel@tonic-gate 	cp->cf_com = com;
1027c478bd9Sstevel@tonic-gate 	cp->cf_flags = flags;
103b493790cSbasabi 	if (entry != NULL) {
1047c478bd9Sstevel@tonic-gate 		Conflut = lut_add(Conflut, entry, cp);
1057c478bd9Sstevel@tonic-gate 		fn_list_adds(Confentries, entry);
1067c478bd9Sstevel@tonic-gate 	}
1077c478bd9Sstevel@tonic-gate 	if (Confinfo == NULL)
1087c478bd9Sstevel@tonic-gate 		Confinfo = Confinfolast = cp;
1097c478bd9Sstevel@tonic-gate 	else {
1107c478bd9Sstevel@tonic-gate 		Confinfolast->cf_next = cp;
1117c478bd9Sstevel@tonic-gate 		Confinfolast = cp;
1127c478bd9Sstevel@tonic-gate 	}
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static char **Args;	/* static buffer for args */
1167c478bd9Sstevel@tonic-gate static int ArgsN;	/* size of our static buffer */
1177c478bd9Sstevel@tonic-gate static int ArgsI;	/* index into Cmdargs as we walk table */
1187c478bd9Sstevel@tonic-gate #define	CONF_ARGS_INC	1024
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /* callback for lut_walk to build a cmdargs vector */
1217c478bd9Sstevel@tonic-gate static void
1227c478bd9Sstevel@tonic-gate fillargs(char *arg)
1237c478bd9Sstevel@tonic-gate {
1247c478bd9Sstevel@tonic-gate 	if (ArgsI >= ArgsN) {
1257c478bd9Sstevel@tonic-gate 		/* need bigger table */
1267c478bd9Sstevel@tonic-gate 		Args = REALLOC(Args, sizeof (char *) * (ArgsN + CONF_ARGS_INC));
1277c478bd9Sstevel@tonic-gate 		ArgsN += CONF_ARGS_INC;
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 	Args[ArgsI++] = arg;
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /* isolate and return the next token */
1337c478bd9Sstevel@tonic-gate static char *
1347c478bd9Sstevel@tonic-gate nexttok(char **ptrptr)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	char *ptr = *ptrptr;
1377c478bd9Sstevel@tonic-gate 	char *eptr;
1387c478bd9Sstevel@tonic-gate 	char *quote = NULL;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	while (*ptr && isspace(*ptr))
1417c478bd9Sstevel@tonic-gate 		ptr++;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	if (*ptr == '"' || *ptr == '\'')
1447c478bd9Sstevel@tonic-gate 		quote = ptr++;
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 	for (eptr = ptr; *eptr; eptr++)
1477c478bd9Sstevel@tonic-gate 		if (quote && *eptr == *quote) {
1487c478bd9Sstevel@tonic-gate 			/* found end quote */
1497c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
1507c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
1517c478bd9Sstevel@tonic-gate 			return (ptr);
1527c478bd9Sstevel@tonic-gate 		} else if (!quote && isspace(*eptr)) {
1537c478bd9Sstevel@tonic-gate 			/* found end of unquoted area */
1547c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
1557c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
1567c478bd9Sstevel@tonic-gate 			return (ptr);
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 
159b493790cSbasabi 	if (quote != NULL)
1607c478bd9Sstevel@tonic-gate 		err(EF_FILE|EF_JMP, "Unbalanced %c quote", *quote);
1617c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	*ptrptr = eptr;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (ptr == eptr)
1667c478bd9Sstevel@tonic-gate 		return (NULL);
1677c478bd9Sstevel@tonic-gate 	else
1687c478bd9Sstevel@tonic-gate 		return (ptr);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
172*e9a193fcSJohn.Zolnowsky@Sun.COM  * scan the memory image of a file
173*e9a193fcSJohn.Zolnowsky@Sun.COM  *	returns: 0: error, 1: ok, 3: -P option found
1747c478bd9Sstevel@tonic-gate  */
175*e9a193fcSJohn.Zolnowsky@Sun.COM static int
176*e9a193fcSJohn.Zolnowsky@Sun.COM conf_scan(const char *fname, char *buf, int buflen, int timescan,
177*e9a193fcSJohn.Zolnowsky@Sun.COM     struct opts *cliopts)
1787c478bd9Sstevel@tonic-gate {
179*e9a193fcSJohn.Zolnowsky@Sun.COM 	int ret = 1;
1807c478bd9Sstevel@tonic-gate 	int lineno = 0;
1817c478bd9Sstevel@tonic-gate 	char *line;
1827c478bd9Sstevel@tonic-gate 	char *eline;
1837c478bd9Sstevel@tonic-gate 	char *ebuf;
184*e9a193fcSJohn.Zolnowsky@Sun.COM 	char *entry, *comment;
1857c478bd9Sstevel@tonic-gate 
186*e9a193fcSJohn.Zolnowsky@Sun.COM 	ebuf = &buf[buflen];
1877c478bd9Sstevel@tonic-gate 
188*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (buf[buflen - 1] != '\n')
189*e9a193fcSJohn.Zolnowsky@Sun.COM 		err(EF_WARN|EF_FILE, "file %s doesn't end with newline, "
190*e9a193fcSJohn.Zolnowsky@Sun.COM 		    "last line ignored.", fname);
1917c478bd9Sstevel@tonic-gate 
192*e9a193fcSJohn.Zolnowsky@Sun.COM 	for (line = buf; line < ebuf; line = eline) {
193*e9a193fcSJohn.Zolnowsky@Sun.COM 		char *ap;
194*e9a193fcSJohn.Zolnowsky@Sun.COM 		struct opts *opts = NULL;
195*e9a193fcSJohn.Zolnowsky@Sun.COM 		struct confinfo *cp;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		lineno++;
198*e9a193fcSJohn.Zolnowsky@Sun.COM 		err_fileline(fname, lineno);
1997c478bd9Sstevel@tonic-gate 		eline = line;
2007c478bd9Sstevel@tonic-gate 		comment = NULL;
2017c478bd9Sstevel@tonic-gate 		for (; eline < ebuf; eline++) {
2027c478bd9Sstevel@tonic-gate 			/* check for continued lines */
2037c478bd9Sstevel@tonic-gate 			if (comment == NULL && *eline == '\\' &&
2047c478bd9Sstevel@tonic-gate 			    eline + 1 < ebuf && *(eline + 1) == '\n') {
2057c478bd9Sstevel@tonic-gate 				*eline = ' ';
2067c478bd9Sstevel@tonic-gate 				*(eline + 1) = ' ';
2077c478bd9Sstevel@tonic-gate 				lineno++;
208*e9a193fcSJohn.Zolnowsky@Sun.COM 				err_fileline(fname, lineno);
2097c478bd9Sstevel@tonic-gate 				continue;
2107c478bd9Sstevel@tonic-gate 			}
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 			/* check for comments */
2137c478bd9Sstevel@tonic-gate 			if (comment == NULL && *eline == '#') {
2147c478bd9Sstevel@tonic-gate 				*eline = '\0';
2157c478bd9Sstevel@tonic-gate 				comment = (eline + 1);
2167c478bd9Sstevel@tonic-gate 				continue;
2177c478bd9Sstevel@tonic-gate 			}
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 			/* check for end of line */
2207c478bd9Sstevel@tonic-gate 			if (*eline == '\n')
2217c478bd9Sstevel@tonic-gate 				break;
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 		if (comment >= ebuf)
2247c478bd9Sstevel@tonic-gate 			comment = NULL;
225*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (eline >= ebuf) {
226*e9a193fcSJohn.Zolnowsky@Sun.COM 			/* discard trailing unterminated line */
227*e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
228*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
2297c478bd9Sstevel@tonic-gate 		*eline++ = '\0';
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 		/*
2327c478bd9Sstevel@tonic-gate 		 * now we have the entry, if any, at "line"
2337c478bd9Sstevel@tonic-gate 		 * and the comment, if any, at "comment"
2347c478bd9Sstevel@tonic-gate 		 */
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 		/* entry is first token */
237*e9a193fcSJohn.Zolnowsky@Sun.COM 		entry = nexttok(&line);
238*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (entry == NULL) {
239*e9a193fcSJohn.Zolnowsky@Sun.COM 			/* it's just a comment line */
240*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (!timescan)
241*e9a193fcSJohn.Zolnowsky@Sun.COM 				fillconflist(lineno, entry, NULL, comment, 0);
242*e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
243*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
244*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (strcmp(entry, "logadm-version") == 0) {
2457c478bd9Sstevel@tonic-gate 			/*
2467c478bd9Sstevel@tonic-gate 			 * we somehow opened some future format
2477c478bd9Sstevel@tonic-gate 			 * conffile that we likely don't understand.
2487c478bd9Sstevel@tonic-gate 			 * if the given version is "1" then go on,
2497c478bd9Sstevel@tonic-gate 			 * otherwise someone is mixing versions
2507c478bd9Sstevel@tonic-gate 			 * and we can't help them other than to
2517c478bd9Sstevel@tonic-gate 			 * print an error and exit.
2527c478bd9Sstevel@tonic-gate 			 */
2537c478bd9Sstevel@tonic-gate 			if ((entry = nexttok(&line)) != NULL &&
2547c478bd9Sstevel@tonic-gate 			    strcmp(entry, "1") != 0)
255*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(0, "%s version not supported "
256*e9a193fcSJohn.Zolnowsky@Sun.COM 				    "by this version of logadm.",
257*e9a193fcSJohn.Zolnowsky@Sun.COM 				    fname);
258*e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
259*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
2607c478bd9Sstevel@tonic-gate 
261*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* form an argv array */
2627c478bd9Sstevel@tonic-gate 		ArgsI = 0;
2637c478bd9Sstevel@tonic-gate 		while (ap = nexttok(&line))
2647c478bd9Sstevel@tonic-gate 			fillargs(ap);
265*e9a193fcSJohn.Zolnowsky@Sun.COM 		Args[ArgsI] = NULL;
266*e9a193fcSJohn.Zolnowsky@Sun.COM 
267*e9a193fcSJohn.Zolnowsky@Sun.COM 		LOCAL_ERR_BEGIN {
268*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (SETJMP) {
269*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_FILE, "cannot process invalid entry %s",
270*e9a193fcSJohn.Zolnowsky@Sun.COM 				    entry);
271*e9a193fcSJohn.Zolnowsky@Sun.COM 				ret = 0;
272*e9a193fcSJohn.Zolnowsky@Sun.COM 				LOCAL_ERR_BREAK;
2737c478bd9Sstevel@tonic-gate 			}
274*e9a193fcSJohn.Zolnowsky@Sun.COM 
275*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (timescan) {
276*e9a193fcSJohn.Zolnowsky@Sun.COM 				/* append to config options */
277*e9a193fcSJohn.Zolnowsky@Sun.COM 				cp = lut_lookup(Conflut, entry);
278*e9a193fcSJohn.Zolnowsky@Sun.COM 				if (cp == NULL) {
279*e9a193fcSJohn.Zolnowsky@Sun.COM 					/* orphaned entry */
280*e9a193fcSJohn.Zolnowsky@Sun.COM 					if (opts_count(cliopts, "v"))
281*e9a193fcSJohn.Zolnowsky@Sun.COM 						err(EF_FILE, "stale timestamp "
282*e9a193fcSJohn.Zolnowsky@Sun.COM 						    "for %s", entry);
283*e9a193fcSJohn.Zolnowsky@Sun.COM 					LOCAL_ERR_BREAK;
2847c478bd9Sstevel@tonic-gate 				}
285*e9a193fcSJohn.Zolnowsky@Sun.COM 				opts = cp->cf_opts;
2867c478bd9Sstevel@tonic-gate 			}
287*e9a193fcSJohn.Zolnowsky@Sun.COM 			opts = opts_parse(opts, Args, OPTF_CONF);
288*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (!timescan) {
289*e9a193fcSJohn.Zolnowsky@Sun.COM 				fillconflist(lineno, entry, opts, comment, 0);
290*e9a193fcSJohn.Zolnowsky@Sun.COM 			}
291*e9a193fcSJohn.Zolnowsky@Sun.COM 		LOCAL_ERR_END }
292*e9a193fcSJohn.Zolnowsky@Sun.COM 
293*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (ret == 1 && opts && opts_optarg(opts, "P") != NULL)
294*e9a193fcSJohn.Zolnowsky@Sun.COM 			ret = 3;
295*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
296*e9a193fcSJohn.Zolnowsky@Sun.COM 
297*e9a193fcSJohn.Zolnowsky@Sun.COM 	err_fileline(NULL, 0);
298*e9a193fcSJohn.Zolnowsky@Sun.COM 	return (ret);
299*e9a193fcSJohn.Zolnowsky@Sun.COM }
300*e9a193fcSJohn.Zolnowsky@Sun.COM 
301*e9a193fcSJohn.Zolnowsky@Sun.COM /*
302*e9a193fcSJohn.Zolnowsky@Sun.COM  * conf_open -- open the configuration file, lock it if we have write perms
303*e9a193fcSJohn.Zolnowsky@Sun.COM  */
304*e9a193fcSJohn.Zolnowsky@Sun.COM int
305*e9a193fcSJohn.Zolnowsky@Sun.COM conf_open(const char *cfname, const char *tfname, struct opts *cliopts)
306*e9a193fcSJohn.Zolnowsky@Sun.COM {
307*e9a193fcSJohn.Zolnowsky@Sun.COM 	struct stat stbuf1, stbuf2, stbuf3;
308*e9a193fcSJohn.Zolnowsky@Sun.COM 	struct flock	flock;
309*e9a193fcSJohn.Zolnowsky@Sun.COM 	int ret;
310*e9a193fcSJohn.Zolnowsky@Sun.COM 
311*e9a193fcSJohn.Zolnowsky@Sun.COM 	Confname = cfname;
312*e9a193fcSJohn.Zolnowsky@Sun.COM 	Timesname = tfname;
313*e9a193fcSJohn.Zolnowsky@Sun.COM 	Confentries = fn_list_new(NULL);
314*e9a193fcSJohn.Zolnowsky@Sun.COM 	Changed = CHG_NONE;
315*e9a193fcSJohn.Zolnowsky@Sun.COM 
316*e9a193fcSJohn.Zolnowsky@Sun.COM 	Changing = CHG_TIMES;
317*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (opts_count(cliopts, "Vn") != 0)
318*e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = CHG_NONE;
319*e9a193fcSJohn.Zolnowsky@Sun.COM 	else if (opts_count(cliopts, "rw") != 0)
320*e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = CHG_BOTH;
321*e9a193fcSJohn.Zolnowsky@Sun.COM 
322*e9a193fcSJohn.Zolnowsky@Sun.COM 	Singlefile = strcmp(Confname, Timesname) == 0;
323*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Singlefile && Changing == CHG_TIMES)
324*e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = CHG_BOTH;
325*e9a193fcSJohn.Zolnowsky@Sun.COM 
326*e9a193fcSJohn.Zolnowsky@Sun.COM 	/* special case this so we don't even try locking the file */
327*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (strcmp(Confname, "/dev/null") == 0)
328*e9a193fcSJohn.Zolnowsky@Sun.COM 		return (0);
329*e9a193fcSJohn.Zolnowsky@Sun.COM 
330*e9a193fcSJohn.Zolnowsky@Sun.COM 	while (Conffd == -1) {
331*e9a193fcSJohn.Zolnowsky@Sun.COM 		Canchange = CHG_BOTH;
332*e9a193fcSJohn.Zolnowsky@Sun.COM 		if ((Conffd = open(Confname, O_RDWR)) < 0) {
333*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Changing == CHG_BOTH)
334*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Confname);
335*e9a193fcSJohn.Zolnowsky@Sun.COM 			Canchange = CHG_TIMES;
336*e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((Conffd = open(Confname, O_RDONLY)) < 0)
337*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Confname);
338*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
339*e9a193fcSJohn.Zolnowsky@Sun.COM 
340*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_type = (Canchange == CHG_BOTH) ? F_WRLCK : F_RDLCK;
341*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_whence = SEEK_SET;
342*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_start = 0;
343*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_len = 1;
344*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fcntl(Conffd, F_SETLKW, &flock) < 0)
345*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "flock on %s", Confname);
346*e9a193fcSJohn.Zolnowsky@Sun.COM 
347*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* wait until after file is locked to get filesize */
348*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fstat(Conffd, &stbuf1) < 0)
349*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "fstat on %s", Confname);
350*e9a193fcSJohn.Zolnowsky@Sun.COM 
351*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* verify that we've got a lock on the active file */
352*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (stat(Confname, &stbuf2) < 0 ||
353*e9a193fcSJohn.Zolnowsky@Sun.COM 		    !(stbuf2.st_dev == stbuf1.st_dev &&
354*e9a193fcSJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf1.st_ino)) {
355*e9a193fcSJohn.Zolnowsky@Sun.COM 			/* wrong config file, try again */
356*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) close(Conffd);
357*e9a193fcSJohn.Zolnowsky@Sun.COM 			Conffd = -1;
358*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
359*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
360*e9a193fcSJohn.Zolnowsky@Sun.COM 
361*e9a193fcSJohn.Zolnowsky@Sun.COM 	while (!Singlefile && Timesfd == -1) {
362*e9a193fcSJohn.Zolnowsky@Sun.COM 		if ((Timesfd = open(Timesname, O_CREAT|O_RDWR, 0644)) < 0) {
363*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Changing != CHG_NONE)
364*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Timesname);
365*e9a193fcSJohn.Zolnowsky@Sun.COM 			Canchange = CHG_NONE;
366*e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((Timesfd = open(Timesname, O_RDONLY)) < 0)
367*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Timesname);
368*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
369*e9a193fcSJohn.Zolnowsky@Sun.COM 
370*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_type = (Canchange != CHG_NONE) ? F_WRLCK : F_RDLCK;
371*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_whence = SEEK_SET;
372*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_start = 0;
373*e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_len = 1;
374*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fcntl(Timesfd, F_SETLKW, &flock) < 0)
375*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "flock on %s", Timesname);
376*e9a193fcSJohn.Zolnowsky@Sun.COM 
377*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* wait until after file is locked to get filesize */
378*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fstat(Timesfd, &stbuf2) < 0)
379*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "fstat on %s", Timesname);
380*e9a193fcSJohn.Zolnowsky@Sun.COM 
381*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* verify that we've got a lock on the active file */
382*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (stat(Timesname, &stbuf3) < 0 ||
383*e9a193fcSJohn.Zolnowsky@Sun.COM 		    !(stbuf2.st_dev == stbuf3.st_dev &&
384*e9a193fcSJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf3.st_ino)) {
385*e9a193fcSJohn.Zolnowsky@Sun.COM 			/* wrong timestamp file, try again */
386*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) close(Timesfd);
387*e9a193fcSJohn.Zolnowsky@Sun.COM 			Timesfd = -1;
388*e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
389*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
390*e9a193fcSJohn.Zolnowsky@Sun.COM 
391*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* check that Timesname isn't an alias for Confname */
392*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (stbuf2.st_dev == stbuf1.st_dev &&
393*e9a193fcSJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf1.st_ino)
394*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(0, "Timestamp file %s can't refer to "
395*e9a193fcSJohn.Zolnowsky@Sun.COM 			    "Configuration file %s", Timesname, Confname);
396*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
397*e9a193fcSJohn.Zolnowsky@Sun.COM 
398*e9a193fcSJohn.Zolnowsky@Sun.COM 	Conflen = stbuf1.st_size;
399*e9a193fcSJohn.Zolnowsky@Sun.COM 	Timeslen = stbuf2.st_size;
400*e9a193fcSJohn.Zolnowsky@Sun.COM 
401*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Conflen == 0)
402*e9a193fcSJohn.Zolnowsky@Sun.COM 		return (1);	/* empty file, don't bother parsing it */
403*e9a193fcSJohn.Zolnowsky@Sun.COM 
404*e9a193fcSJohn.Zolnowsky@Sun.COM 	if ((Confbuf = (char *)mmap(0, Conflen,
405*e9a193fcSJohn.Zolnowsky@Sun.COM 	    PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1)
406*e9a193fcSJohn.Zolnowsky@Sun.COM 		err(EF_SYS, "mmap on %s", Confname);
407*e9a193fcSJohn.Zolnowsky@Sun.COM 
408*e9a193fcSJohn.Zolnowsky@Sun.COM 	ret = conf_scan(Confname, Confbuf, Conflen, 0, cliopts);
409*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (ret == 3 && !Singlefile && Canchange == CHG_BOTH) {
410*e9a193fcSJohn.Zolnowsky@Sun.COM 		/*
411*e9a193fcSJohn.Zolnowsky@Sun.COM 		 * arrange to transfer any timestamps
412*e9a193fcSJohn.Zolnowsky@Sun.COM 		 * from conf_file to timestamps_file
413*e9a193fcSJohn.Zolnowsky@Sun.COM 		 */
414*e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = Changed = CHG_BOTH;
415*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
416*e9a193fcSJohn.Zolnowsky@Sun.COM 
417*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Timesfd != -1 && Timeslen != 0) {
418*e9a193fcSJohn.Zolnowsky@Sun.COM 		if ((Timesbuf = (char *)mmap(0, Timeslen,
419*e9a193fcSJohn.Zolnowsky@Sun.COM 		    PROT_READ | PROT_WRITE, MAP_PRIVATE,
420*e9a193fcSJohn.Zolnowsky@Sun.COM 		    Timesfd, 0)) == (char *)-1)
421*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "mmap on %s", Timesname);
422*e9a193fcSJohn.Zolnowsky@Sun.COM 		ret &= conf_scan(Timesname, Timesbuf, Timeslen, 1, cliopts);
423*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
424*e9a193fcSJohn.Zolnowsky@Sun.COM 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * possible future enhancement:  go through and mark any entries:
4277c478bd9Sstevel@tonic-gate 	 * 		logfile -P <date>
4287c478bd9Sstevel@tonic-gate 	 * as DELETED if the logfile doesn't exist
4297c478bd9Sstevel@tonic-gate 	 */
430*e9a193fcSJohn.Zolnowsky@Sun.COM 
431*e9a193fcSJohn.Zolnowsky@Sun.COM 	return (ret);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate  * conf_close -- close the configuration file
4367c478bd9Sstevel@tonic-gate  */
4377c478bd9Sstevel@tonic-gate void
4387c478bd9Sstevel@tonic-gate conf_close(struct opts *opts)
4397c478bd9Sstevel@tonic-gate {
440*e9a193fcSJohn.Zolnowsky@Sun.COM 	char cuname[PATH_MAX], tuname[PATH_MAX];
441*e9a193fcSJohn.Zolnowsky@Sun.COM 	int cfd, tfd;
442*e9a193fcSJohn.Zolnowsky@Sun.COM 	FILE *cfp = NULL, *tfp = NULL;
443*e9a193fcSJohn.Zolnowsky@Sun.COM 	boolean_t safe_update = B_TRUE;
4447c478bd9Sstevel@tonic-gate 
445*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Changed == CHG_NONE || opts_count(opts, "n") != 0) {
4467c478bd9Sstevel@tonic-gate 		if (opts_count(opts, "v"))
447*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) out("# %s and %s unchanged\n",
448*e9a193fcSJohn.Zolnowsky@Sun.COM 			    Confname, Timesname);
449*e9a193fcSJohn.Zolnowsky@Sun.COM 		goto cleanup;
4507c478bd9Sstevel@tonic-gate 	}
4517c478bd9Sstevel@tonic-gate 
452*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Debug > 1) {
453*e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) fprintf(stderr, "conf_close, saving logadm context:\n");
454*e9a193fcSJohn.Zolnowsky@Sun.COM 		conf_print(stderr, NULL);
455*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
456*e9a193fcSJohn.Zolnowsky@Sun.COM 
457*e9a193fcSJohn.Zolnowsky@Sun.COM 	cuname[0] = tuname[0] = '\0';
458*e9a193fcSJohn.Zolnowsky@Sun.COM 	LOCAL_ERR_BEGIN {
459*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (SETJMP) {
460*e9a193fcSJohn.Zolnowsky@Sun.COM 			safe_update = B_FALSE;
461*e9a193fcSJohn.Zolnowsky@Sun.COM 			LOCAL_ERR_BREAK;
462*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
463*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (Changed == CHG_BOTH) {
464*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Canchange != CHG_BOTH)
465*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_JMP, "internal error: attempting "
466*e9a193fcSJohn.Zolnowsky@Sun.COM 				    "to update %s without locking", Confname);
467*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) snprintf(cuname, sizeof (cuname), "%sXXXXXX",
468*e9a193fcSJohn.Zolnowsky@Sun.COM 			    Confname);
469*e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((cfd = mkstemp(cuname)) == -1)
470*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "open %s replacement",
471*e9a193fcSJohn.Zolnowsky@Sun.COM 				    Confname);
472*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (opts_count(opts, "v"))
473*e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) out("# writing changes to %s\n", cuname);
474*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (fchmod(cfd, 0644) == -1)
475*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "chmod %s", cuname);
476*e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((cfp = fdopen(cfd, "w")) == NULL)
477*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "fdopen on %s", cuname);
478*e9a193fcSJohn.Zolnowsky@Sun.COM 		} else {
479*e9a193fcSJohn.Zolnowsky@Sun.COM 			/* just toss away the configuration data */
480*e9a193fcSJohn.Zolnowsky@Sun.COM 			cfp = fopen("/dev/null", "w");
481*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
482*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (!Singlefile) {
483*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Canchange == CHG_NONE)
484*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_JMP, "internal error: attempting "
485*e9a193fcSJohn.Zolnowsky@Sun.COM 				    "to update %s without locking", Timesname);
486*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) snprintf(tuname, sizeof (tuname), "%sXXXXXX",
487*e9a193fcSJohn.Zolnowsky@Sun.COM 			    Timesname);
488*e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((tfd = mkstemp(tuname)) == -1)
489*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "open %s replacement",
490*e9a193fcSJohn.Zolnowsky@Sun.COM 				    Timesname);
491*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (opts_count(opts, "v"))
492*e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) out("# writing changes to %s\n", tuname);
493*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (fchmod(tfd, 0644) == -1)
494*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "chmod %s", tuname);
495*e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((tfp = fdopen(tfd, "w")) == NULL)
496*e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "fdopen on %s", tuname);
497*e9a193fcSJohn.Zolnowsky@Sun.COM 		}
498*e9a193fcSJohn.Zolnowsky@Sun.COM 
499*e9a193fcSJohn.Zolnowsky@Sun.COM 		conf_print(cfp, tfp);
500*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fclose(cfp) < 0)
501*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS|EF_JMP, "fclose on %s", Confname);
502*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (tfp != NULL && fclose(tfp) < 0)
503*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS|EF_JMP, "fclose on %s", Timesname);
504*e9a193fcSJohn.Zolnowsky@Sun.COM 	LOCAL_ERR_END }
505*e9a193fcSJohn.Zolnowsky@Sun.COM 
506*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (!safe_update) {
507*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (cuname[0] != 0)
508*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) unlink(cuname);
509*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (tuname[0] != 0)
510*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) unlink(tuname);
511*e9a193fcSJohn.Zolnowsky@Sun.COM 		err(EF_JMP, "unsafe to update configuration file "
512*e9a193fcSJohn.Zolnowsky@Sun.COM 		    "or timestamps");
513*e9a193fcSJohn.Zolnowsky@Sun.COM 		return;
514*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
515*e9a193fcSJohn.Zolnowsky@Sun.COM 
516*e9a193fcSJohn.Zolnowsky@Sun.COM 	/* rename updated files into place */
517*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (cuname[0] != '\0')
518*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (rename(cuname, Confname) < 0)
519*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "rename %s to %s", cuname, Confname);
520*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (tuname[0] != '\0')
521*e9a193fcSJohn.Zolnowsky@Sun.COM 		if (rename(tuname, Timesname) < 0)
522*e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "rename %s to %s", tuname, Timesname);
523*e9a193fcSJohn.Zolnowsky@Sun.COM 	Changed = CHG_NONE;
524*e9a193fcSJohn.Zolnowsky@Sun.COM 
525*e9a193fcSJohn.Zolnowsky@Sun.COM cleanup:
5267c478bd9Sstevel@tonic-gate 	if (Conffd != -1) {
5277c478bd9Sstevel@tonic-gate 		(void) close(Conffd);
5287c478bd9Sstevel@tonic-gate 		Conffd = -1;
5297c478bd9Sstevel@tonic-gate 	}
530*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Timesfd != -1) {
531*e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) close(Timesfd);
532*e9a193fcSJohn.Zolnowsky@Sun.COM 		Timesfd = -1;
533*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
5347c478bd9Sstevel@tonic-gate 	if (Conflut) {
5357c478bd9Sstevel@tonic-gate 		lut_free(Conflut, free);
5367c478bd9Sstevel@tonic-gate 		Conflut = NULL;
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 	if (Confentries) {
5397c478bd9Sstevel@tonic-gate 		fn_list_free(Confentries);
5407c478bd9Sstevel@tonic-gate 		Confentries = NULL;
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate }
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate /*
5457c478bd9Sstevel@tonic-gate  * conf_lookup -- lookup an entry in the config file
5467c478bd9Sstevel@tonic-gate  */
547*e9a193fcSJohn.Zolnowsky@Sun.COM void *
5487c478bd9Sstevel@tonic-gate conf_lookup(const char *lhs)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5517c478bd9Sstevel@tonic-gate 
552*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (cp != NULL)
5537c478bd9Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
554*e9a193fcSJohn.Zolnowsky@Sun.COM 	return (cp);
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate  * conf_opts -- return the parsed opts for an entry
5597c478bd9Sstevel@tonic-gate  */
5607c478bd9Sstevel@tonic-gate struct opts *
5617c478bd9Sstevel@tonic-gate conf_opts(const char *lhs)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5647c478bd9Sstevel@tonic-gate 
565*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (cp != NULL)
5667c478bd9Sstevel@tonic-gate 		return (cp->cf_opts);
567*e9a193fcSJohn.Zolnowsky@Sun.COM 	return (opts_parse(NULL, NULL, OPTF_CONF));
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate  * conf_replace -- replace an entry in the config file
5727c478bd9Sstevel@tonic-gate  */
5737c478bd9Sstevel@tonic-gate void
5747c478bd9Sstevel@tonic-gate conf_replace(const char *lhs, struct opts *newopts)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
5797c478bd9Sstevel@tonic-gate 		return;
5807c478bd9Sstevel@tonic-gate 
581b493790cSbasabi 	if (cp != NULL) {
5827c478bd9Sstevel@tonic-gate 		cp->cf_opts = newopts;
583*e9a193fcSJohn.Zolnowsky@Sun.COM 		/* cp->cf_args = NULL; */
5847c478bd9Sstevel@tonic-gate 		if (newopts == NULL)
5857c478bd9Sstevel@tonic-gate 			cp->cf_flags |= CONFF_DELETED;
5867c478bd9Sstevel@tonic-gate 	} else
587*e9a193fcSJohn.Zolnowsky@Sun.COM 		fillconflist(0, lhs, newopts, NULL, 0);
588*e9a193fcSJohn.Zolnowsky@Sun.COM 
589*e9a193fcSJohn.Zolnowsky@Sun.COM 	Changed = CHG_BOTH;
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate  * conf_set -- set options for an entry in the config file
5947c478bd9Sstevel@tonic-gate  */
5957c478bd9Sstevel@tonic-gate void
5967c478bd9Sstevel@tonic-gate conf_set(const char *entry, char *o, const char *optarg)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, entry);
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
6017c478bd9Sstevel@tonic-gate 		return;
6027c478bd9Sstevel@tonic-gate 
603b493790cSbasabi 	if (cp != NULL) {
6047c478bd9Sstevel@tonic-gate 		cp->cf_flags &= ~CONFF_DELETED;
6057c478bd9Sstevel@tonic-gate 	} else {
606*e9a193fcSJohn.Zolnowsky@Sun.COM 		fillconflist(0, STRDUP(entry),
607*e9a193fcSJohn.Zolnowsky@Sun.COM 		    opts_parse(NULL, NULL, OPTF_CONF), NULL, 0);
6087c478bd9Sstevel@tonic-gate 		if ((cp = lut_lookup(Conflut, entry)) == NULL)
6097c478bd9Sstevel@tonic-gate 			err(0, "conf_set internal error");
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 	(void) opts_set(cp->cf_opts, o, optarg);
612*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (strcmp(o, "P") == 0)
613*e9a193fcSJohn.Zolnowsky@Sun.COM 		Changed |= CHG_TIMES;
614*e9a193fcSJohn.Zolnowsky@Sun.COM 	else
615*e9a193fcSJohn.Zolnowsky@Sun.COM 		Changed = CHG_BOTH;
6167c478bd9Sstevel@tonic-gate }
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate /*
6197c478bd9Sstevel@tonic-gate  * conf_entries -- list all the entry names
6207c478bd9Sstevel@tonic-gate  */
6217c478bd9Sstevel@tonic-gate struct fn_list *
6227c478bd9Sstevel@tonic-gate conf_entries(void)
6237c478bd9Sstevel@tonic-gate {
6247c478bd9Sstevel@tonic-gate 	return (Confentries);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /* print the config file */
6287c478bd9Sstevel@tonic-gate static void
629*e9a193fcSJohn.Zolnowsky@Sun.COM conf_print(FILE *cstream, FILE *tstream)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	struct confinfo *cp;
632*e9a193fcSJohn.Zolnowsky@Sun.COM 	char *exclude_opts = "PFfhnrvVw";
633*e9a193fcSJohn.Zolnowsky@Sun.COM 	const char *timestamp;
6347c478bd9Sstevel@tonic-gate 
635*e9a193fcSJohn.Zolnowsky@Sun.COM 	if (tstream == NULL) {
636*e9a193fcSJohn.Zolnowsky@Sun.COM 		exclude_opts++;		/* -P option goes to config file */
637*e9a193fcSJohn.Zolnowsky@Sun.COM 	} else {
638*e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) fprintf(tstream, gettext(
639*e9a193fcSJohn.Zolnowsky@Sun.COM 		    "# This file holds internal data for logadm(1M).\n"
640*e9a193fcSJohn.Zolnowsky@Sun.COM 		    "# Do not edit.\n"));
641*e9a193fcSJohn.Zolnowsky@Sun.COM 	}
6427c478bd9Sstevel@tonic-gate 	for (cp = Confinfo; cp; cp = cp->cf_next) {
6437c478bd9Sstevel@tonic-gate 		if (cp->cf_flags & CONFF_DELETED)
6447c478bd9Sstevel@tonic-gate 			continue;
6457c478bd9Sstevel@tonic-gate 		if (cp->cf_entry) {
646*e9a193fcSJohn.Zolnowsky@Sun.COM 			opts_printword(cp->cf_entry, cstream);
647*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (cp->cf_opts)
648*e9a193fcSJohn.Zolnowsky@Sun.COM 				opts_print(cp->cf_opts, cstream, exclude_opts);
649*e9a193fcSJohn.Zolnowsky@Sun.COM 			/* output timestamps to tstream */
650*e9a193fcSJohn.Zolnowsky@Sun.COM 			if (tstream != NULL && (timestamp =
651*e9a193fcSJohn.Zolnowsky@Sun.COM 			    opts_optarg(cp->cf_opts, "P")) != NULL) {
652*e9a193fcSJohn.Zolnowsky@Sun.COM 				opts_printword(cp->cf_entry, tstream);
653*e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) fprintf(tstream, " -P ");
654*e9a193fcSJohn.Zolnowsky@Sun.COM 				opts_printword(timestamp, tstream);
655*e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) fprintf(tstream, "\n");
6567c478bd9Sstevel@tonic-gate 			}
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 		if (cp->cf_com) {
6597c478bd9Sstevel@tonic-gate 			if (cp->cf_entry)
660*e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) fprintf(cstream, " ");
661*e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) fprintf(cstream, "#%s", cp->cf_com);
6627c478bd9Sstevel@tonic-gate 		}
663*e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) fprintf(cstream, "\n");
6647c478bd9Sstevel@tonic-gate 	}
6657c478bd9Sstevel@tonic-gate }
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate #ifdef	TESTMODULE
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate  * test main for conf module, usage: a.out conffile
6717c478bd9Sstevel@tonic-gate  */
672b493790cSbasabi int
6737c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
6747c478bd9Sstevel@tonic-gate {
675*e9a193fcSJohn.Zolnowsky@Sun.COM 	struct opts *opts;
676*e9a193fcSJohn.Zolnowsky@Sun.COM 
6777c478bd9Sstevel@tonic-gate 	err_init(argv[0]);
6787c478bd9Sstevel@tonic-gate 	setbuf(stdout, NULL);
679*e9a193fcSJohn.Zolnowsky@Sun.COM 	opts_init(Opttable, Opttable_cnt);
680*e9a193fcSJohn.Zolnowsky@Sun.COM 
681*e9a193fcSJohn.Zolnowsky@Sun.COM 	opts = opts_parse(NULL, NULL, 0);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	if (argc != 2)
6847c478bd9Sstevel@tonic-gate 		err(EF_RAW, "usage: %s conffile\n", argv[0]);
6857c478bd9Sstevel@tonic-gate 
686*e9a193fcSJohn.Zolnowsky@Sun.COM 	conf_open(argv[1], argv[1], opts);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	printf("conffile <%s>:\n", argv[1]);
689*e9a193fcSJohn.Zolnowsky@Sun.COM 	conf_print(stdout, NULL);
6907c478bd9Sstevel@tonic-gate 
691*e9a193fcSJohn.Zolnowsky@Sun.COM 	conf_close(opts);
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	err_done(0);
694b493790cSbasabi 	/* NOTREACHED */
695b493790cSbasabi 	return (0);
6967c478bd9Sstevel@tonic-gate }
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate #endif	/* TESTMODULE */
699