xref: /titanic_51/usr/src/cmd/logadm/conf.c (revision 34969e746608c8170ab540c876836f625f25d8eb)
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 /*
23e9a193fcSJohn.Zolnowsky@Sun.COM  * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
24*34969e74SJerry Jelinek  * Copyright 2013, Joyent, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
2778eb75caSchin /*
2878eb75caSchin  * logadm/conf.c -- configuration file module
2978eb75caSchin  */
3078eb75caSchin 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <libintl.h>
337c478bd9Sstevel@tonic-gate #include <fcntl.h>
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/stat.h>
367c478bd9Sstevel@tonic-gate #include <sys/mman.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <strings.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
41e9a193fcSJohn.Zolnowsky@Sun.COM #include <limits.h>
427c478bd9Sstevel@tonic-gate #include "err.h"
437c478bd9Sstevel@tonic-gate #include "lut.h"
447c478bd9Sstevel@tonic-gate #include "fn.h"
457c478bd9Sstevel@tonic-gate #include "opts.h"
467c478bd9Sstevel@tonic-gate #include "conf.h"
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /* forward declarations of functions private to this module */
49e9a193fcSJohn.Zolnowsky@Sun.COM static void fillconflist(int lineno, const char *entry,
507c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags);
517c478bd9Sstevel@tonic-gate static void fillargs(char *arg);
527c478bd9Sstevel@tonic-gate static char *nexttok(char **ptrptr);
53e9a193fcSJohn.Zolnowsky@Sun.COM static void conf_print(FILE *cstream, FILE *tstream);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate static const char *Confname;	/* name of the confile file */
567c478bd9Sstevel@tonic-gate static int Conffd = -1;		/* file descriptor for config file */
57e9a193fcSJohn.Zolnowsky@Sun.COM static char *Confbuf;		/* copy of the config file (a la mmap()) */
58e9a193fcSJohn.Zolnowsky@Sun.COM static int Conflen;		/* length of mmap'd config file area */
59e9a193fcSJohn.Zolnowsky@Sun.COM static const char *Timesname;	/* name of the timestamps file */
60e9a193fcSJohn.Zolnowsky@Sun.COM static int Timesfd = -1;	/* file descriptor for timestamps file */
61e9a193fcSJohn.Zolnowsky@Sun.COM static char *Timesbuf;		/* copy of the timestamps file (a la mmap()) */
62e9a193fcSJohn.Zolnowsky@Sun.COM static int Timeslen;		/* length of mmap'd timestamps area */
63e9a193fcSJohn.Zolnowsky@Sun.COM static int Singlefile;		/* Conf and Times in the same file */
64e9a193fcSJohn.Zolnowsky@Sun.COM static int Changed;		/* what changes need to be written back */
65e9a193fcSJohn.Zolnowsky@Sun.COM static int Canchange;		/* what changes can be written back */
66e9a193fcSJohn.Zolnowsky@Sun.COM static int Changing;		/* what changes have been requested */
67e9a193fcSJohn.Zolnowsky@Sun.COM #define	CHG_NONE	0
68e9a193fcSJohn.Zolnowsky@Sun.COM #define	CHG_TIMES	1
69e9a193fcSJohn.Zolnowsky@Sun.COM #define	CHG_BOTH	3
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /*
727c478bd9Sstevel@tonic-gate  * our structured representation of the configuration file
737c478bd9Sstevel@tonic-gate  * is made up of a list of these
747c478bd9Sstevel@tonic-gate  */
7578eb75caSchin struct confinfo {
767c478bd9Sstevel@tonic-gate 	struct confinfo *cf_next;
777c478bd9Sstevel@tonic-gate 	int cf_lineno;		/* line number in file */
787c478bd9Sstevel@tonic-gate 	const char *cf_entry;	/* name of entry, if line has an entry */
797c478bd9Sstevel@tonic-gate 	struct opts *cf_opts;	/* parsed rhs of entry */
807c478bd9Sstevel@tonic-gate 	const char *cf_com;	/* any comment text found */
817c478bd9Sstevel@tonic-gate 	int cf_flags;
827c478bd9Sstevel@tonic-gate };
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define	CONFF_DELETED	1	/* entry should be deleted on write back */
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate static struct confinfo *Confinfo;	/* the entries in the config file */
877c478bd9Sstevel@tonic-gate static struct confinfo *Confinfolast;	/* end of list */
887c478bd9Sstevel@tonic-gate static struct lut *Conflut;		/* lookup table keyed by entry name */
897c478bd9Sstevel@tonic-gate static struct fn_list *Confentries;	/* list of valid entry names */
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /* allocate & fill in another entry in our list */
927c478bd9Sstevel@tonic-gate static void
93e9a193fcSJohn.Zolnowsky@Sun.COM fillconflist(int lineno, const char *entry,
947c478bd9Sstevel@tonic-gate     struct opts *opts, const char *com, int flags)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate 	struct confinfo *cp = MALLOC(sizeof (*cp));
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	cp->cf_next = NULL;
997c478bd9Sstevel@tonic-gate 	cp->cf_lineno = lineno;
1007c478bd9Sstevel@tonic-gate 	cp->cf_entry = entry;
1017c478bd9Sstevel@tonic-gate 	cp->cf_opts = opts;
1027c478bd9Sstevel@tonic-gate 	cp->cf_com = com;
1037c478bd9Sstevel@tonic-gate 	cp->cf_flags = flags;
104b493790cSbasabi 	if (entry != NULL) {
1057c478bd9Sstevel@tonic-gate 		Conflut = lut_add(Conflut, entry, cp);
1067c478bd9Sstevel@tonic-gate 		fn_list_adds(Confentries, entry);
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 	if (Confinfo == NULL)
1097c478bd9Sstevel@tonic-gate 		Confinfo = Confinfolast = cp;
1107c478bd9Sstevel@tonic-gate 	else {
1117c478bd9Sstevel@tonic-gate 		Confinfolast->cf_next = cp;
1127c478bd9Sstevel@tonic-gate 		Confinfolast = cp;
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static char **Args;	/* static buffer for args */
1177c478bd9Sstevel@tonic-gate static int ArgsN;	/* size of our static buffer */
1187c478bd9Sstevel@tonic-gate static int ArgsI;	/* index into Cmdargs as we walk table */
1197c478bd9Sstevel@tonic-gate #define	CONF_ARGS_INC	1024
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /* callback for lut_walk to build a cmdargs vector */
1227c478bd9Sstevel@tonic-gate static void
1237c478bd9Sstevel@tonic-gate fillargs(char *arg)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	if (ArgsI >= ArgsN) {
1267c478bd9Sstevel@tonic-gate 		/* need bigger table */
1277c478bd9Sstevel@tonic-gate 		Args = REALLOC(Args, sizeof (char *) * (ArgsN + CONF_ARGS_INC));
1287c478bd9Sstevel@tonic-gate 		ArgsN += CONF_ARGS_INC;
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 	Args[ArgsI++] = arg;
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate /* isolate and return the next token */
1347c478bd9Sstevel@tonic-gate static char *
1357c478bd9Sstevel@tonic-gate nexttok(char **ptrptr)
1367c478bd9Sstevel@tonic-gate {
1377c478bd9Sstevel@tonic-gate 	char *ptr = *ptrptr;
1387c478bd9Sstevel@tonic-gate 	char *eptr;
1397c478bd9Sstevel@tonic-gate 	char *quote = NULL;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	while (*ptr && isspace(*ptr))
1427c478bd9Sstevel@tonic-gate 		ptr++;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	if (*ptr == '"' || *ptr == '\'')
1457c478bd9Sstevel@tonic-gate 		quote = ptr++;
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 	for (eptr = ptr; *eptr; eptr++)
1487c478bd9Sstevel@tonic-gate 		if (quote && *eptr == *quote) {
1497c478bd9Sstevel@tonic-gate 			/* found end quote */
1507c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
1517c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
1527c478bd9Sstevel@tonic-gate 			return (ptr);
1537c478bd9Sstevel@tonic-gate 		} else if (!quote && isspace(*eptr)) {
1547c478bd9Sstevel@tonic-gate 			/* found end of unquoted area */
1557c478bd9Sstevel@tonic-gate 			*eptr++ = '\0';
1567c478bd9Sstevel@tonic-gate 			*ptrptr = eptr;
1577c478bd9Sstevel@tonic-gate 			return (ptr);
1587c478bd9Sstevel@tonic-gate 		}
1597c478bd9Sstevel@tonic-gate 
160b493790cSbasabi 	if (quote != NULL)
1617c478bd9Sstevel@tonic-gate 		err(EF_FILE|EF_JMP, "Unbalanced %c quote", *quote);
1627c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	*ptrptr = eptr;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (ptr == eptr)
1677c478bd9Sstevel@tonic-gate 		return (NULL);
1687c478bd9Sstevel@tonic-gate 	else
1697c478bd9Sstevel@tonic-gate 		return (ptr);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
173e9a193fcSJohn.Zolnowsky@Sun.COM  * scan the memory image of a file
174e9a193fcSJohn.Zolnowsky@Sun.COM  *	returns: 0: error, 1: ok, 3: -P option found
1757c478bd9Sstevel@tonic-gate  */
176e9a193fcSJohn.Zolnowsky@Sun.COM static int
177*34969e74SJerry Jelinek conf_scan(const char *fname, char *buf, int buflen, int timescan)
1787c478bd9Sstevel@tonic-gate {
179e9a193fcSJohn.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;
184e9a193fcSJohn.Zolnowsky@Sun.COM 	char *entry, *comment;
1857c478bd9Sstevel@tonic-gate 
186e9a193fcSJohn.Zolnowsky@Sun.COM 	ebuf = &buf[buflen];
1877c478bd9Sstevel@tonic-gate 
188e9a193fcSJohn.Zolnowsky@Sun.COM 	if (buf[buflen - 1] != '\n')
189e9a193fcSJohn.Zolnowsky@Sun.COM 		err(EF_WARN|EF_FILE, "file %s doesn't end with newline, "
190e9a193fcSJohn.Zolnowsky@Sun.COM 		    "last line ignored.", fname);
1917c478bd9Sstevel@tonic-gate 
192e9a193fcSJohn.Zolnowsky@Sun.COM 	for (line = buf; line < ebuf; line = eline) {
193e9a193fcSJohn.Zolnowsky@Sun.COM 		char *ap;
194e9a193fcSJohn.Zolnowsky@Sun.COM 		struct opts *opts = NULL;
195e9a193fcSJohn.Zolnowsky@Sun.COM 		struct confinfo *cp;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 		lineno++;
198e9a193fcSJohn.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++;
208e9a193fcSJohn.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;
225e9a193fcSJohn.Zolnowsky@Sun.COM 		if (eline >= ebuf) {
226e9a193fcSJohn.Zolnowsky@Sun.COM 			/* discard trailing unterminated line */
227e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
228e9a193fcSJohn.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 */
237e9a193fcSJohn.Zolnowsky@Sun.COM 		entry = nexttok(&line);
238e9a193fcSJohn.Zolnowsky@Sun.COM 		if (entry == NULL) {
239e9a193fcSJohn.Zolnowsky@Sun.COM 			/* it's just a comment line */
240e9a193fcSJohn.Zolnowsky@Sun.COM 			if (!timescan)
241e9a193fcSJohn.Zolnowsky@Sun.COM 				fillconflist(lineno, entry, NULL, comment, 0);
242e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
243e9a193fcSJohn.Zolnowsky@Sun.COM 		}
244e9a193fcSJohn.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)
255e9a193fcSJohn.Zolnowsky@Sun.COM 				err(0, "%s version not supported "
256e9a193fcSJohn.Zolnowsky@Sun.COM 				    "by this version of logadm.",
257e9a193fcSJohn.Zolnowsky@Sun.COM 				    fname);
258e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
259e9a193fcSJohn.Zolnowsky@Sun.COM 		}
2607c478bd9Sstevel@tonic-gate 
261e9a193fcSJohn.Zolnowsky@Sun.COM 		/* form an argv array */
2627c478bd9Sstevel@tonic-gate 		ArgsI = 0;
2637c478bd9Sstevel@tonic-gate 		while (ap = nexttok(&line))
2647c478bd9Sstevel@tonic-gate 			fillargs(ap);
265e9a193fcSJohn.Zolnowsky@Sun.COM 		Args[ArgsI] = NULL;
266e9a193fcSJohn.Zolnowsky@Sun.COM 
267e9a193fcSJohn.Zolnowsky@Sun.COM 		LOCAL_ERR_BEGIN {
268e9a193fcSJohn.Zolnowsky@Sun.COM 			if (SETJMP) {
269e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_FILE, "cannot process invalid entry %s",
270e9a193fcSJohn.Zolnowsky@Sun.COM 				    entry);
271e9a193fcSJohn.Zolnowsky@Sun.COM 				ret = 0;
272e9a193fcSJohn.Zolnowsky@Sun.COM 				LOCAL_ERR_BREAK;
2737c478bd9Sstevel@tonic-gate 			}
274e9a193fcSJohn.Zolnowsky@Sun.COM 
275e9a193fcSJohn.Zolnowsky@Sun.COM 			if (timescan) {
276e9a193fcSJohn.Zolnowsky@Sun.COM 				/* append to config options */
277e9a193fcSJohn.Zolnowsky@Sun.COM 				cp = lut_lookup(Conflut, entry);
278*34969e74SJerry Jelinek 				if (cp != NULL) {
279e9a193fcSJohn.Zolnowsky@Sun.COM 					opts = cp->cf_opts;
2807c478bd9Sstevel@tonic-gate 				}
281*34969e74SJerry Jelinek 			}
282e9a193fcSJohn.Zolnowsky@Sun.COM 			opts = opts_parse(opts, Args, OPTF_CONF);
283*34969e74SJerry Jelinek 			if (!timescan || cp == NULL) {
284*34969e74SJerry Jelinek 				/*
285*34969e74SJerry Jelinek 				 * If we're not doing timescan, we track this
286*34969e74SJerry Jelinek 				 * entry.  If we are doing timescan and have
287*34969e74SJerry Jelinek 				 * what looks like an orphaned entry (cp ==
288*34969e74SJerry Jelinek 				 * NULL) then we also have to track. See the
289*34969e74SJerry Jelinek 				 * comment in rotatelog. We need to allow for
290*34969e74SJerry Jelinek 				 * the case where the logname is not the same as
291*34969e74SJerry Jelinek 				 * the log file name.
292*34969e74SJerry Jelinek 				 */
293e9a193fcSJohn.Zolnowsky@Sun.COM 				fillconflist(lineno, entry, opts, comment, 0);
294e9a193fcSJohn.Zolnowsky@Sun.COM 			}
295e9a193fcSJohn.Zolnowsky@Sun.COM 		LOCAL_ERR_END }
296e9a193fcSJohn.Zolnowsky@Sun.COM 
297e9a193fcSJohn.Zolnowsky@Sun.COM 		if (ret == 1 && opts && opts_optarg(opts, "P") != NULL)
298e9a193fcSJohn.Zolnowsky@Sun.COM 			ret = 3;
299e9a193fcSJohn.Zolnowsky@Sun.COM 	}
300e9a193fcSJohn.Zolnowsky@Sun.COM 
301e9a193fcSJohn.Zolnowsky@Sun.COM 	err_fileline(NULL, 0);
302e9a193fcSJohn.Zolnowsky@Sun.COM 	return (ret);
303e9a193fcSJohn.Zolnowsky@Sun.COM }
304e9a193fcSJohn.Zolnowsky@Sun.COM 
305e9a193fcSJohn.Zolnowsky@Sun.COM /*
306e9a193fcSJohn.Zolnowsky@Sun.COM  * conf_open -- open the configuration file, lock it if we have write perms
307e9a193fcSJohn.Zolnowsky@Sun.COM  */
308e9a193fcSJohn.Zolnowsky@Sun.COM int
309e9a193fcSJohn.Zolnowsky@Sun.COM conf_open(const char *cfname, const char *tfname, struct opts *cliopts)
310e9a193fcSJohn.Zolnowsky@Sun.COM {
311e9a193fcSJohn.Zolnowsky@Sun.COM 	struct stat stbuf1, stbuf2, stbuf3;
312e9a193fcSJohn.Zolnowsky@Sun.COM 	struct flock	flock;
313e9a193fcSJohn.Zolnowsky@Sun.COM 	int ret;
314e9a193fcSJohn.Zolnowsky@Sun.COM 
315e9a193fcSJohn.Zolnowsky@Sun.COM 	Confname = cfname;
316e9a193fcSJohn.Zolnowsky@Sun.COM 	Timesname = tfname;
317e9a193fcSJohn.Zolnowsky@Sun.COM 	Confentries = fn_list_new(NULL);
318e9a193fcSJohn.Zolnowsky@Sun.COM 	Changed = CHG_NONE;
319e9a193fcSJohn.Zolnowsky@Sun.COM 
320e9a193fcSJohn.Zolnowsky@Sun.COM 	Changing = CHG_TIMES;
321e9a193fcSJohn.Zolnowsky@Sun.COM 	if (opts_count(cliopts, "Vn") != 0)
322e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = CHG_NONE;
323e9a193fcSJohn.Zolnowsky@Sun.COM 	else if (opts_count(cliopts, "rw") != 0)
324e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = CHG_BOTH;
325e9a193fcSJohn.Zolnowsky@Sun.COM 
326e9a193fcSJohn.Zolnowsky@Sun.COM 	Singlefile = strcmp(Confname, Timesname) == 0;
327e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Singlefile && Changing == CHG_TIMES)
328e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = CHG_BOTH;
329e9a193fcSJohn.Zolnowsky@Sun.COM 
330e9a193fcSJohn.Zolnowsky@Sun.COM 	/* special case this so we don't even try locking the file */
331e9a193fcSJohn.Zolnowsky@Sun.COM 	if (strcmp(Confname, "/dev/null") == 0)
332e9a193fcSJohn.Zolnowsky@Sun.COM 		return (0);
333e9a193fcSJohn.Zolnowsky@Sun.COM 
334e9a193fcSJohn.Zolnowsky@Sun.COM 	while (Conffd == -1) {
335e9a193fcSJohn.Zolnowsky@Sun.COM 		Canchange = CHG_BOTH;
336e9a193fcSJohn.Zolnowsky@Sun.COM 		if ((Conffd = open(Confname, O_RDWR)) < 0) {
337e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Changing == CHG_BOTH)
338e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Confname);
339e9a193fcSJohn.Zolnowsky@Sun.COM 			Canchange = CHG_TIMES;
340e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((Conffd = open(Confname, O_RDONLY)) < 0)
341e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Confname);
342e9a193fcSJohn.Zolnowsky@Sun.COM 		}
343e9a193fcSJohn.Zolnowsky@Sun.COM 
344e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_type = (Canchange == CHG_BOTH) ? F_WRLCK : F_RDLCK;
345e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_whence = SEEK_SET;
346e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_start = 0;
347e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_len = 1;
348e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fcntl(Conffd, F_SETLKW, &flock) < 0)
349e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "flock on %s", Confname);
350e9a193fcSJohn.Zolnowsky@Sun.COM 
351e9a193fcSJohn.Zolnowsky@Sun.COM 		/* wait until after file is locked to get filesize */
352e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fstat(Conffd, &stbuf1) < 0)
353e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "fstat on %s", Confname);
354e9a193fcSJohn.Zolnowsky@Sun.COM 
355e9a193fcSJohn.Zolnowsky@Sun.COM 		/* verify that we've got a lock on the active file */
356e9a193fcSJohn.Zolnowsky@Sun.COM 		if (stat(Confname, &stbuf2) < 0 ||
357e9a193fcSJohn.Zolnowsky@Sun.COM 		    !(stbuf2.st_dev == stbuf1.st_dev &&
358e9a193fcSJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf1.st_ino)) {
359e9a193fcSJohn.Zolnowsky@Sun.COM 			/* wrong config file, try again */
360e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) close(Conffd);
361e9a193fcSJohn.Zolnowsky@Sun.COM 			Conffd = -1;
362e9a193fcSJohn.Zolnowsky@Sun.COM 		}
363e9a193fcSJohn.Zolnowsky@Sun.COM 	}
364e9a193fcSJohn.Zolnowsky@Sun.COM 
365e9a193fcSJohn.Zolnowsky@Sun.COM 	while (!Singlefile && Timesfd == -1) {
366e9a193fcSJohn.Zolnowsky@Sun.COM 		if ((Timesfd = open(Timesname, O_CREAT|O_RDWR, 0644)) < 0) {
367e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Changing != CHG_NONE)
368e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Timesname);
369e9a193fcSJohn.Zolnowsky@Sun.COM 			Canchange = CHG_NONE;
370e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((Timesfd = open(Timesname, O_RDONLY)) < 0)
371e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS, "open %s", Timesname);
372e9a193fcSJohn.Zolnowsky@Sun.COM 		}
373e9a193fcSJohn.Zolnowsky@Sun.COM 
374e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_type = (Canchange != CHG_NONE) ? F_WRLCK : F_RDLCK;
375e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_whence = SEEK_SET;
376e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_start = 0;
377e9a193fcSJohn.Zolnowsky@Sun.COM 		flock.l_len = 1;
378e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fcntl(Timesfd, F_SETLKW, &flock) < 0)
379e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "flock on %s", Timesname);
380e9a193fcSJohn.Zolnowsky@Sun.COM 
381e9a193fcSJohn.Zolnowsky@Sun.COM 		/* wait until after file is locked to get filesize */
382e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fstat(Timesfd, &stbuf2) < 0)
383e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "fstat on %s", Timesname);
384e9a193fcSJohn.Zolnowsky@Sun.COM 
385e9a193fcSJohn.Zolnowsky@Sun.COM 		/* verify that we've got a lock on the active file */
386e9a193fcSJohn.Zolnowsky@Sun.COM 		if (stat(Timesname, &stbuf3) < 0 ||
387e9a193fcSJohn.Zolnowsky@Sun.COM 		    !(stbuf2.st_dev == stbuf3.st_dev &&
388e9a193fcSJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf3.st_ino)) {
389e9a193fcSJohn.Zolnowsky@Sun.COM 			/* wrong timestamp file, try again */
390e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) close(Timesfd);
391e9a193fcSJohn.Zolnowsky@Sun.COM 			Timesfd = -1;
392e9a193fcSJohn.Zolnowsky@Sun.COM 			continue;
393e9a193fcSJohn.Zolnowsky@Sun.COM 		}
394e9a193fcSJohn.Zolnowsky@Sun.COM 
395e9a193fcSJohn.Zolnowsky@Sun.COM 		/* check that Timesname isn't an alias for Confname */
396e9a193fcSJohn.Zolnowsky@Sun.COM 		if (stbuf2.st_dev == stbuf1.st_dev &&
397e9a193fcSJohn.Zolnowsky@Sun.COM 		    stbuf2.st_ino == stbuf1.st_ino)
398e9a193fcSJohn.Zolnowsky@Sun.COM 			err(0, "Timestamp file %s can't refer to "
399e9a193fcSJohn.Zolnowsky@Sun.COM 			    "Configuration file %s", Timesname, Confname);
400e9a193fcSJohn.Zolnowsky@Sun.COM 	}
401e9a193fcSJohn.Zolnowsky@Sun.COM 
402e9a193fcSJohn.Zolnowsky@Sun.COM 	Conflen = stbuf1.st_size;
403e9a193fcSJohn.Zolnowsky@Sun.COM 	Timeslen = stbuf2.st_size;
404e9a193fcSJohn.Zolnowsky@Sun.COM 
405e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Conflen == 0)
406e9a193fcSJohn.Zolnowsky@Sun.COM 		return (1);	/* empty file, don't bother parsing it */
407e9a193fcSJohn.Zolnowsky@Sun.COM 
408e9a193fcSJohn.Zolnowsky@Sun.COM 	if ((Confbuf = (char *)mmap(0, Conflen,
409e9a193fcSJohn.Zolnowsky@Sun.COM 	    PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1)
410e9a193fcSJohn.Zolnowsky@Sun.COM 		err(EF_SYS, "mmap on %s", Confname);
411e9a193fcSJohn.Zolnowsky@Sun.COM 
412*34969e74SJerry Jelinek 	ret = conf_scan(Confname, Confbuf, Conflen, 0);
413e9a193fcSJohn.Zolnowsky@Sun.COM 	if (ret == 3 && !Singlefile && Canchange == CHG_BOTH) {
414e9a193fcSJohn.Zolnowsky@Sun.COM 		/*
415e9a193fcSJohn.Zolnowsky@Sun.COM 		 * arrange to transfer any timestamps
416e9a193fcSJohn.Zolnowsky@Sun.COM 		 * from conf_file to timestamps_file
417e9a193fcSJohn.Zolnowsky@Sun.COM 		 */
418e9a193fcSJohn.Zolnowsky@Sun.COM 		Changing = Changed = CHG_BOTH;
419e9a193fcSJohn.Zolnowsky@Sun.COM 	}
420e9a193fcSJohn.Zolnowsky@Sun.COM 
421e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Timesfd != -1 && Timeslen != 0) {
422e9a193fcSJohn.Zolnowsky@Sun.COM 		if ((Timesbuf = (char *)mmap(0, Timeslen,
423e9a193fcSJohn.Zolnowsky@Sun.COM 		    PROT_READ | PROT_WRITE, MAP_PRIVATE,
424e9a193fcSJohn.Zolnowsky@Sun.COM 		    Timesfd, 0)) == (char *)-1)
425e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "mmap on %s", Timesname);
426*34969e74SJerry Jelinek 		ret &= conf_scan(Timesname, Timesbuf, Timeslen, 1);
427e9a193fcSJohn.Zolnowsky@Sun.COM 	}
428e9a193fcSJohn.Zolnowsky@Sun.COM 
4297c478bd9Sstevel@tonic-gate 	/*
4307c478bd9Sstevel@tonic-gate 	 * possible future enhancement:  go through and mark any entries:
4317c478bd9Sstevel@tonic-gate 	 * 		logfile -P <date>
4327c478bd9Sstevel@tonic-gate 	 * as DELETED if the logfile doesn't exist
4337c478bd9Sstevel@tonic-gate 	 */
434e9a193fcSJohn.Zolnowsky@Sun.COM 
435e9a193fcSJohn.Zolnowsky@Sun.COM 	return (ret);
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate  * conf_close -- close the configuration file
4407c478bd9Sstevel@tonic-gate  */
4417c478bd9Sstevel@tonic-gate void
4427c478bd9Sstevel@tonic-gate conf_close(struct opts *opts)
4437c478bd9Sstevel@tonic-gate {
444e9a193fcSJohn.Zolnowsky@Sun.COM 	char cuname[PATH_MAX], tuname[PATH_MAX];
445e9a193fcSJohn.Zolnowsky@Sun.COM 	int cfd, tfd;
446e9a193fcSJohn.Zolnowsky@Sun.COM 	FILE *cfp = NULL, *tfp = NULL;
447e9a193fcSJohn.Zolnowsky@Sun.COM 	boolean_t safe_update = B_TRUE;
4487c478bd9Sstevel@tonic-gate 
449e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Changed == CHG_NONE || opts_count(opts, "n") != 0) {
4507c478bd9Sstevel@tonic-gate 		if (opts_count(opts, "v"))
451e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) out("# %s and %s unchanged\n",
452e9a193fcSJohn.Zolnowsky@Sun.COM 			    Confname, Timesname);
453e9a193fcSJohn.Zolnowsky@Sun.COM 		goto cleanup;
4547c478bd9Sstevel@tonic-gate 	}
4557c478bd9Sstevel@tonic-gate 
456e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Debug > 1) {
457e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) fprintf(stderr, "conf_close, saving logadm context:\n");
458e9a193fcSJohn.Zolnowsky@Sun.COM 		conf_print(stderr, NULL);
459e9a193fcSJohn.Zolnowsky@Sun.COM 	}
460e9a193fcSJohn.Zolnowsky@Sun.COM 
461e9a193fcSJohn.Zolnowsky@Sun.COM 	cuname[0] = tuname[0] = '\0';
462e9a193fcSJohn.Zolnowsky@Sun.COM 	LOCAL_ERR_BEGIN {
463e9a193fcSJohn.Zolnowsky@Sun.COM 		if (SETJMP) {
464e9a193fcSJohn.Zolnowsky@Sun.COM 			safe_update = B_FALSE;
465e9a193fcSJohn.Zolnowsky@Sun.COM 			LOCAL_ERR_BREAK;
466e9a193fcSJohn.Zolnowsky@Sun.COM 		}
467e9a193fcSJohn.Zolnowsky@Sun.COM 		if (Changed == CHG_BOTH) {
468e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Canchange != CHG_BOTH)
469e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_JMP, "internal error: attempting "
470e9a193fcSJohn.Zolnowsky@Sun.COM 				    "to update %s without locking", Confname);
471e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) snprintf(cuname, sizeof (cuname), "%sXXXXXX",
472e9a193fcSJohn.Zolnowsky@Sun.COM 			    Confname);
473e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((cfd = mkstemp(cuname)) == -1)
474e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "open %s replacement",
475e9a193fcSJohn.Zolnowsky@Sun.COM 				    Confname);
476e9a193fcSJohn.Zolnowsky@Sun.COM 			if (opts_count(opts, "v"))
477e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) out("# writing changes to %s\n", cuname);
478e9a193fcSJohn.Zolnowsky@Sun.COM 			if (fchmod(cfd, 0644) == -1)
479e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "chmod %s", cuname);
480e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((cfp = fdopen(cfd, "w")) == NULL)
481e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "fdopen on %s", cuname);
482e9a193fcSJohn.Zolnowsky@Sun.COM 		} else {
483e9a193fcSJohn.Zolnowsky@Sun.COM 			/* just toss away the configuration data */
484e9a193fcSJohn.Zolnowsky@Sun.COM 			cfp = fopen("/dev/null", "w");
485e9a193fcSJohn.Zolnowsky@Sun.COM 		}
486e9a193fcSJohn.Zolnowsky@Sun.COM 		if (!Singlefile) {
487e9a193fcSJohn.Zolnowsky@Sun.COM 			if (Canchange == CHG_NONE)
488e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_JMP, "internal error: attempting "
489e9a193fcSJohn.Zolnowsky@Sun.COM 				    "to update %s without locking", Timesname);
490e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) snprintf(tuname, sizeof (tuname), "%sXXXXXX",
491e9a193fcSJohn.Zolnowsky@Sun.COM 			    Timesname);
492e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((tfd = mkstemp(tuname)) == -1)
493e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "open %s replacement",
494e9a193fcSJohn.Zolnowsky@Sun.COM 				    Timesname);
495e9a193fcSJohn.Zolnowsky@Sun.COM 			if (opts_count(opts, "v"))
496e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) out("# writing changes to %s\n", tuname);
497e9a193fcSJohn.Zolnowsky@Sun.COM 			if (fchmod(tfd, 0644) == -1)
498e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "chmod %s", tuname);
499e9a193fcSJohn.Zolnowsky@Sun.COM 			if ((tfp = fdopen(tfd, "w")) == NULL)
500e9a193fcSJohn.Zolnowsky@Sun.COM 				err(EF_SYS|EF_JMP, "fdopen on %s", tuname);
501e9a193fcSJohn.Zolnowsky@Sun.COM 		}
502e9a193fcSJohn.Zolnowsky@Sun.COM 
503e9a193fcSJohn.Zolnowsky@Sun.COM 		conf_print(cfp, tfp);
504e9a193fcSJohn.Zolnowsky@Sun.COM 		if (fclose(cfp) < 0)
505e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS|EF_JMP, "fclose on %s", Confname);
506e9a193fcSJohn.Zolnowsky@Sun.COM 		if (tfp != NULL && fclose(tfp) < 0)
507e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS|EF_JMP, "fclose on %s", Timesname);
508e9a193fcSJohn.Zolnowsky@Sun.COM 	LOCAL_ERR_END }
509e9a193fcSJohn.Zolnowsky@Sun.COM 
510e9a193fcSJohn.Zolnowsky@Sun.COM 	if (!safe_update) {
511e9a193fcSJohn.Zolnowsky@Sun.COM 		if (cuname[0] != 0)
512e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) unlink(cuname);
513e9a193fcSJohn.Zolnowsky@Sun.COM 		if (tuname[0] != 0)
514e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) unlink(tuname);
515e9a193fcSJohn.Zolnowsky@Sun.COM 		err(EF_JMP, "unsafe to update configuration file "
516e9a193fcSJohn.Zolnowsky@Sun.COM 		    "or timestamps");
517e9a193fcSJohn.Zolnowsky@Sun.COM 		return;
518e9a193fcSJohn.Zolnowsky@Sun.COM 	}
519e9a193fcSJohn.Zolnowsky@Sun.COM 
520e9a193fcSJohn.Zolnowsky@Sun.COM 	/* rename updated files into place */
521e9a193fcSJohn.Zolnowsky@Sun.COM 	if (cuname[0] != '\0')
522e9a193fcSJohn.Zolnowsky@Sun.COM 		if (rename(cuname, Confname) < 0)
523e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "rename %s to %s", cuname, Confname);
524e9a193fcSJohn.Zolnowsky@Sun.COM 	if (tuname[0] != '\0')
525e9a193fcSJohn.Zolnowsky@Sun.COM 		if (rename(tuname, Timesname) < 0)
526e9a193fcSJohn.Zolnowsky@Sun.COM 			err(EF_SYS, "rename %s to %s", tuname, Timesname);
527e9a193fcSJohn.Zolnowsky@Sun.COM 	Changed = CHG_NONE;
528e9a193fcSJohn.Zolnowsky@Sun.COM 
529e9a193fcSJohn.Zolnowsky@Sun.COM cleanup:
5307c478bd9Sstevel@tonic-gate 	if (Conffd != -1) {
5317c478bd9Sstevel@tonic-gate 		(void) close(Conffd);
5327c478bd9Sstevel@tonic-gate 		Conffd = -1;
5337c478bd9Sstevel@tonic-gate 	}
534e9a193fcSJohn.Zolnowsky@Sun.COM 	if (Timesfd != -1) {
535e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) close(Timesfd);
536e9a193fcSJohn.Zolnowsky@Sun.COM 		Timesfd = -1;
537e9a193fcSJohn.Zolnowsky@Sun.COM 	}
5387c478bd9Sstevel@tonic-gate 	if (Conflut) {
5397c478bd9Sstevel@tonic-gate 		lut_free(Conflut, free);
5407c478bd9Sstevel@tonic-gate 		Conflut = NULL;
5417c478bd9Sstevel@tonic-gate 	}
5427c478bd9Sstevel@tonic-gate 	if (Confentries) {
5437c478bd9Sstevel@tonic-gate 		fn_list_free(Confentries);
5447c478bd9Sstevel@tonic-gate 		Confentries = NULL;
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate  * conf_lookup -- lookup an entry in the config file
5507c478bd9Sstevel@tonic-gate  */
551e9a193fcSJohn.Zolnowsky@Sun.COM void *
5527c478bd9Sstevel@tonic-gate conf_lookup(const char *lhs)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5557c478bd9Sstevel@tonic-gate 
556e9a193fcSJohn.Zolnowsky@Sun.COM 	if (cp != NULL)
5577c478bd9Sstevel@tonic-gate 		err_fileline(Confname, cp->cf_lineno);
558e9a193fcSJohn.Zolnowsky@Sun.COM 	return (cp);
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate /*
5627c478bd9Sstevel@tonic-gate  * conf_opts -- return the parsed opts for an entry
5637c478bd9Sstevel@tonic-gate  */
5647c478bd9Sstevel@tonic-gate struct opts *
5657c478bd9Sstevel@tonic-gate conf_opts(const char *lhs)
5667c478bd9Sstevel@tonic-gate {
5677c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5687c478bd9Sstevel@tonic-gate 
569e9a193fcSJohn.Zolnowsky@Sun.COM 	if (cp != NULL)
5707c478bd9Sstevel@tonic-gate 		return (cp->cf_opts);
571e9a193fcSJohn.Zolnowsky@Sun.COM 	return (opts_parse(NULL, NULL, OPTF_CONF));
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate  * conf_replace -- replace an entry in the config file
5767c478bd9Sstevel@tonic-gate  */
5777c478bd9Sstevel@tonic-gate void
5787c478bd9Sstevel@tonic-gate conf_replace(const char *lhs, struct opts *newopts)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, lhs);
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
5837c478bd9Sstevel@tonic-gate 		return;
5847c478bd9Sstevel@tonic-gate 
585b493790cSbasabi 	if (cp != NULL) {
5867c478bd9Sstevel@tonic-gate 		cp->cf_opts = newopts;
587e9a193fcSJohn.Zolnowsky@Sun.COM 		/* cp->cf_args = NULL; */
5887c478bd9Sstevel@tonic-gate 		if (newopts == NULL)
5897c478bd9Sstevel@tonic-gate 			cp->cf_flags |= CONFF_DELETED;
5907c478bd9Sstevel@tonic-gate 	} else
591e9a193fcSJohn.Zolnowsky@Sun.COM 		fillconflist(0, lhs, newopts, NULL, 0);
592e9a193fcSJohn.Zolnowsky@Sun.COM 
593e9a193fcSJohn.Zolnowsky@Sun.COM 	Changed = CHG_BOTH;
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate  * conf_set -- set options for an entry in the config file
5987c478bd9Sstevel@tonic-gate  */
5997c478bd9Sstevel@tonic-gate void
6007c478bd9Sstevel@tonic-gate conf_set(const char *entry, char *o, const char *optarg)
6017c478bd9Sstevel@tonic-gate {
6027c478bd9Sstevel@tonic-gate 	struct confinfo *cp = lut_lookup(Conflut, entry);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	if (Conffd == -1)
6057c478bd9Sstevel@tonic-gate 		return;
6067c478bd9Sstevel@tonic-gate 
607b493790cSbasabi 	if (cp != NULL) {
6087c478bd9Sstevel@tonic-gate 		cp->cf_flags &= ~CONFF_DELETED;
6097c478bd9Sstevel@tonic-gate 	} else {
610e9a193fcSJohn.Zolnowsky@Sun.COM 		fillconflist(0, STRDUP(entry),
611e9a193fcSJohn.Zolnowsky@Sun.COM 		    opts_parse(NULL, NULL, OPTF_CONF), NULL, 0);
6127c478bd9Sstevel@tonic-gate 		if ((cp = lut_lookup(Conflut, entry)) == NULL)
6137c478bd9Sstevel@tonic-gate 			err(0, "conf_set internal error");
6147c478bd9Sstevel@tonic-gate 	}
6157c478bd9Sstevel@tonic-gate 	(void) opts_set(cp->cf_opts, o, optarg);
616e9a193fcSJohn.Zolnowsky@Sun.COM 	if (strcmp(o, "P") == 0)
617e9a193fcSJohn.Zolnowsky@Sun.COM 		Changed |= CHG_TIMES;
618e9a193fcSJohn.Zolnowsky@Sun.COM 	else
619e9a193fcSJohn.Zolnowsky@Sun.COM 		Changed = CHG_BOTH;
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate /*
6237c478bd9Sstevel@tonic-gate  * conf_entries -- list all the entry names
6247c478bd9Sstevel@tonic-gate  */
6257c478bd9Sstevel@tonic-gate struct fn_list *
6267c478bd9Sstevel@tonic-gate conf_entries(void)
6277c478bd9Sstevel@tonic-gate {
6287c478bd9Sstevel@tonic-gate 	return (Confentries);
6297c478bd9Sstevel@tonic-gate }
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate /* print the config file */
6327c478bd9Sstevel@tonic-gate static void
633e9a193fcSJohn.Zolnowsky@Sun.COM conf_print(FILE *cstream, FILE *tstream)
6347c478bd9Sstevel@tonic-gate {
6357c478bd9Sstevel@tonic-gate 	struct confinfo *cp;
636e9a193fcSJohn.Zolnowsky@Sun.COM 	char *exclude_opts = "PFfhnrvVw";
637e9a193fcSJohn.Zolnowsky@Sun.COM 	const char *timestamp;
6387c478bd9Sstevel@tonic-gate 
639e9a193fcSJohn.Zolnowsky@Sun.COM 	if (tstream == NULL) {
640e9a193fcSJohn.Zolnowsky@Sun.COM 		exclude_opts++;		/* -P option goes to config file */
641e9a193fcSJohn.Zolnowsky@Sun.COM 	} else {
642e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) fprintf(tstream, gettext(
643e9a193fcSJohn.Zolnowsky@Sun.COM 		    "# This file holds internal data for logadm(1M).\n"
644e9a193fcSJohn.Zolnowsky@Sun.COM 		    "# Do not edit.\n"));
645e9a193fcSJohn.Zolnowsky@Sun.COM 	}
6467c478bd9Sstevel@tonic-gate 	for (cp = Confinfo; cp; cp = cp->cf_next) {
6477c478bd9Sstevel@tonic-gate 		if (cp->cf_flags & CONFF_DELETED)
6487c478bd9Sstevel@tonic-gate 			continue;
6497c478bd9Sstevel@tonic-gate 		if (cp->cf_entry) {
650e9a193fcSJohn.Zolnowsky@Sun.COM 			opts_printword(cp->cf_entry, cstream);
651e9a193fcSJohn.Zolnowsky@Sun.COM 			if (cp->cf_opts)
652e9a193fcSJohn.Zolnowsky@Sun.COM 				opts_print(cp->cf_opts, cstream, exclude_opts);
653e9a193fcSJohn.Zolnowsky@Sun.COM 			/* output timestamps to tstream */
654e9a193fcSJohn.Zolnowsky@Sun.COM 			if (tstream != NULL && (timestamp =
655e9a193fcSJohn.Zolnowsky@Sun.COM 			    opts_optarg(cp->cf_opts, "P")) != NULL) {
656e9a193fcSJohn.Zolnowsky@Sun.COM 				opts_printword(cp->cf_entry, tstream);
657e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) fprintf(tstream, " -P ");
658e9a193fcSJohn.Zolnowsky@Sun.COM 				opts_printword(timestamp, tstream);
659e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) fprintf(tstream, "\n");
6607c478bd9Sstevel@tonic-gate 			}
6617c478bd9Sstevel@tonic-gate 		}
6627c478bd9Sstevel@tonic-gate 		if (cp->cf_com) {
6637c478bd9Sstevel@tonic-gate 			if (cp->cf_entry)
664e9a193fcSJohn.Zolnowsky@Sun.COM 				(void) fprintf(cstream, " ");
665e9a193fcSJohn.Zolnowsky@Sun.COM 			(void) fprintf(cstream, "#%s", cp->cf_com);
6667c478bd9Sstevel@tonic-gate 		}
667e9a193fcSJohn.Zolnowsky@Sun.COM 		(void) fprintf(cstream, "\n");
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate #ifdef	TESTMODULE
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate /*
6747c478bd9Sstevel@tonic-gate  * test main for conf module, usage: a.out conffile
6757c478bd9Sstevel@tonic-gate  */
676b493790cSbasabi int
6777c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
6787c478bd9Sstevel@tonic-gate {
679e9a193fcSJohn.Zolnowsky@Sun.COM 	struct opts *opts;
680e9a193fcSJohn.Zolnowsky@Sun.COM 
6817c478bd9Sstevel@tonic-gate 	err_init(argv[0]);
6827c478bd9Sstevel@tonic-gate 	setbuf(stdout, NULL);
683e9a193fcSJohn.Zolnowsky@Sun.COM 	opts_init(Opttable, Opttable_cnt);
684e9a193fcSJohn.Zolnowsky@Sun.COM 
685e9a193fcSJohn.Zolnowsky@Sun.COM 	opts = opts_parse(NULL, NULL, 0);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (argc != 2)
6887c478bd9Sstevel@tonic-gate 		err(EF_RAW, "usage: %s conffile\n", argv[0]);
6897c478bd9Sstevel@tonic-gate 
690e9a193fcSJohn.Zolnowsky@Sun.COM 	conf_open(argv[1], argv[1], opts);
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	printf("conffile <%s>:\n", argv[1]);
693e9a193fcSJohn.Zolnowsky@Sun.COM 	conf_print(stdout, NULL);
6947c478bd9Sstevel@tonic-gate 
695e9a193fcSJohn.Zolnowsky@Sun.COM 	conf_close(opts);
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	err_done(0);
698b493790cSbasabi 	/* NOTREACHED */
699b493790cSbasabi 	return (0);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate #endif	/* TESTMODULE */
703