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
523a1cceaSRoger A. Faulkner  * Common Development and Distribution License (the "License").
623a1cceaSRoger A. Faulkner  * 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  */
2123a1cceaSRoger A. Faulkner 
227c478bd9Sstevel@tonic-gate /*
2323a1cceaSRoger A. Faulkner  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <ctype.h>
277c478bd9Sstevel@tonic-gate #include <errno.h>
287c478bd9Sstevel@tonic-gate #include <locale.h>
297c478bd9Sstevel@tonic-gate #include <stdarg.h>
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <syslog.h>
357c478bd9Sstevel@tonic-gate #include <nfs/nfs.h>
367c478bd9Sstevel@tonic-gate #include <assert.h>
377c478bd9Sstevel@tonic-gate #include <sys/types.h>
387c478bd9Sstevel@tonic-gate #include <sys/stat.h>
397c478bd9Sstevel@tonic-gate #include <unistd.h>
407c478bd9Sstevel@tonic-gate #include <fcntl.h>
417c478bd9Sstevel@tonic-gate #include "nfslog_config.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #define	ERROR_BUFSZ	100
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * This flag controls where error messages go.
477c478bd9Sstevel@tonic-gate  * Zero means that messages go to stderr.
487c478bd9Sstevel@tonic-gate  * Non-zero means that messages go to syslog.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate boolean_t nfsl_errs_to_syslog;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Pointer to the global entry in the list
547c478bd9Sstevel@tonic-gate  */
557c478bd9Sstevel@tonic-gate static nfsl_config_t *global = NULL;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Pointer to the raw global entry in the list, this is the
597c478bd9Sstevel@tonic-gate  * global entry without the expanded paths. This is used to
607c478bd9Sstevel@tonic-gate  * complete configurations.
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate static nfsl_config_t *global_raw = NULL;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /*
657c478bd9Sstevel@tonic-gate  * Last modification time to config file.
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate static timestruc_t config_last_modification = { 0 };
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Whitespace characters to delimit fields in a line.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate static const char *whitespace = " \t";
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static int getconfiglist(nfsl_config_t **, boolean_t);
757c478bd9Sstevel@tonic-gate static nfsl_config_t *create_config(char *, char *, char *, char *, char *,
767c478bd9Sstevel@tonic-gate 			char *, int, boolean_t, int *);
777c478bd9Sstevel@tonic-gate static nfsl_config_t *create_global_raw(int *);
787c478bd9Sstevel@tonic-gate static int update_config(nfsl_config_t *, char *, char *, char *,
797c478bd9Sstevel@tonic-gate 			char *, char *, char *, int, boolean_t, boolean_t);
807c478bd9Sstevel@tonic-gate static int update_field(char **, char *, char *, boolean_t *);
817c478bd9Sstevel@tonic-gate static nfsl_config_t *findconfig(nfsl_config_t **, char *, boolean_t,
827c478bd9Sstevel@tonic-gate 			nfsl_config_t **);
837c478bd9Sstevel@tonic-gate static nfsl_config_t *getlastconfig(nfsl_config_t *);
847c478bd9Sstevel@tonic-gate static void complete_with_global(char **, char **, char **, char **,
857c478bd9Sstevel@tonic-gate 			char **, int *);
867c478bd9Sstevel@tonic-gate #ifdef DEBUG
877c478bd9Sstevel@tonic-gate static void remove_config(nfsl_config_t **, nfsl_config_t *, nfsl_config_t **);
887c478bd9Sstevel@tonic-gate void nfsl_printconfig(nfsl_config_t *);
897c478bd9Sstevel@tonic-gate #endif /* DEBUG */
9023a1cceaSRoger A. Faulkner static char *gataline(FILE *, char *, char *, int);
917c478bd9Sstevel@tonic-gate static int get_info(char *, char **, char **, char **, char **, char **,
927c478bd9Sstevel@tonic-gate 			char **, int *);
937c478bd9Sstevel@tonic-gate static void free_config(nfsl_config_t *);
947c478bd9Sstevel@tonic-gate static int is_legal_tag(char *);
957c478bd9Sstevel@tonic-gate static boolean_t is_complete_config(char *, char *, char *, char *);
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * Read the configuration file and create a list of configuration
997c478bd9Sstevel@tonic-gate  * parameters.  Returns zero for success or an errno value.
1007c478bd9Sstevel@tonic-gate  * The caller is responsible for freeing the returned configlist by calling
1017c478bd9Sstevel@tonic-gate  * nfsl_freeconfig_list().
1027c478bd9Sstevel@tonic-gate  *
1037c478bd9Sstevel@tonic-gate  * If the configuration file does not exist, *listpp points to a config entry
1047c478bd9Sstevel@tonic-gate  * containing the hardwired defaults.
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate int
nfsl_getconfig_list(nfsl_config_t ** listpp)1077c478bd9Sstevel@tonic-gate nfsl_getconfig_list(nfsl_config_t **listpp)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	int error = 0;
1107c478bd9Sstevel@tonic-gate 	char *locale;
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 	/*
1137c478bd9Sstevel@tonic-gate 	 * Set the locale correctly so that we can correctly identify
1147c478bd9Sstevel@tonic-gate 	 * alphabetic characters.
1157c478bd9Sstevel@tonic-gate 	 */
1167c478bd9Sstevel@tonic-gate 	if ((locale = getenv("LC_ALL")) != NULL)
1177c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_ALL, locale);
1187c478bd9Sstevel@tonic-gate 	else if ((locale = getenv("LC_CTYPE")) != NULL)
1197c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_CTYPE, locale);
1207c478bd9Sstevel@tonic-gate 	else if ((locale = getenv("LANG")) != NULL)
1217c478bd9Sstevel@tonic-gate 		(void) setlocale(LC_CTYPE, locale);
1227c478bd9Sstevel@tonic-gate 
1237c478bd9Sstevel@tonic-gate 	/*
1247c478bd9Sstevel@tonic-gate 	 * Allocate 'global_raw' structure, its contents are
1257c478bd9Sstevel@tonic-gate 	 * indirectly allocated by create_config().
1267c478bd9Sstevel@tonic-gate 	 */
1277c478bd9Sstevel@tonic-gate 	assert(global_raw == NULL);
1287c478bd9Sstevel@tonic-gate 	global_raw = create_global_raw(&error);
1297c478bd9Sstevel@tonic-gate 	if (global_raw == NULL)
1307c478bd9Sstevel@tonic-gate 		return (error);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	/*
1337c478bd9Sstevel@tonic-gate 	 * Build global entry with hardwired defaults first.
1347c478bd9Sstevel@tonic-gate 	 */
1357c478bd9Sstevel@tonic-gate 	assert(global == NULL);
1367c478bd9Sstevel@tonic-gate 	global = create_config(DEFAULTTAG, DEFAULTDIR, BUFFERPATH, NULL,
137*2bc647a2SToomas Soome 	    FHPATH, LOGPATH, TRANSLOG_BASIC, B_TRUE, &error);
1387c478bd9Sstevel@tonic-gate 	*listpp = global;
1397c478bd9Sstevel@tonic-gate 	if (global == NULL) {
1407c478bd9Sstevel@tonic-gate 		free_config(global_raw);
1417c478bd9Sstevel@tonic-gate 		return (error);
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 
144*2bc647a2SToomas Soome 	error = getconfiglist(listpp, B_FALSE);
145*2bc647a2SToomas Soome 	if (error != 0) {
1467c478bd9Sstevel@tonic-gate 		nfsl_freeconfig_list(listpp);
147*2bc647a2SToomas Soome 	} else {
1487c478bd9Sstevel@tonic-gate 		assert(global != NULL);
1497c478bd9Sstevel@tonic-gate 		/*
1507c478bd9Sstevel@tonic-gate 		 * The global entry was replaced with the one in the file,
1517c478bd9Sstevel@tonic-gate 		 * clear the UPDATED flag
1527c478bd9Sstevel@tonic-gate 		 */
1537c478bd9Sstevel@tonic-gate 		global->nc_flags &= ~NC_UPDATED;
1547c478bd9Sstevel@tonic-gate 	}
1557c478bd9Sstevel@tonic-gate 	return (error);
1567c478bd9Sstevel@tonic-gate }
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /*
1597c478bd9Sstevel@tonic-gate  * Allocates memory for the 'global_raw' structure.
1607c478bd9Sstevel@tonic-gate  * The actual allocation of values for its components happens in
1617c478bd9Sstevel@tonic-gate  * update_config().
1627c478bd9Sstevel@tonic-gate  */
1637c478bd9Sstevel@tonic-gate static nfsl_config_t *
create_global_raw(int * error)1647c478bd9Sstevel@tonic-gate create_global_raw(int *error)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate 	nfsl_config_t *p;
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	*error = 0;
169*2bc647a2SToomas Soome 	p = calloc(1, sizeof (*p));
170*2bc647a2SToomas Soome 	if (p == NULL)
1717c478bd9Sstevel@tonic-gate 		*error = ENOMEM;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	return (p);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * Checks if the the configuration file has been modified since we last
1787c478bd9Sstevel@tonic-gate  * read it, if not simply returns, otherwise it re-reads it adding new
1797c478bd9Sstevel@tonic-gate  * configuration entries. Note that existing entries that no longer
1807c478bd9Sstevel@tonic-gate  * exist in the configuration file are not removed. Existing entries
1817c478bd9Sstevel@tonic-gate  * that are modified in the configuration file are updated in the list
1827c478bd9Sstevel@tonic-gate  * as well.
1837c478bd9Sstevel@tonic-gate  * if 'updated' is defined then it is set to TRUE if the list was modified.
1847c478bd9Sstevel@tonic-gate  *
1857c478bd9Sstevel@tonic-gate  * Note that if an error occurs, the list may be corrupted.
1867c478bd9Sstevel@tonic-gate  * It is the responsibility of the caller to free the list.
1877c478bd9Sstevel@tonic-gate  * If the configuration file does not exist, we simply return the list
1887c478bd9Sstevel@tonic-gate  * that we previously had, log a message and return success.
1897c478bd9Sstevel@tonic-gate  */
1907c478bd9Sstevel@tonic-gate int
nfsl_checkconfig_list(nfsl_config_t ** listpp,boolean_t * updated)1917c478bd9Sstevel@tonic-gate nfsl_checkconfig_list(nfsl_config_t **listpp, boolean_t *updated)
1927c478bd9Sstevel@tonic-gate {
1937c478bd9Sstevel@tonic-gate 	struct stat st;
1947c478bd9Sstevel@tonic-gate 	int error = 0;
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	if (updated != NULL)
1977c478bd9Sstevel@tonic-gate 		*updated = B_FALSE;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (stat(NFSL_CONFIG_FILE_PATH, &st) == -1) {
2007c478bd9Sstevel@tonic-gate 		error = errno;
2017c478bd9Sstevel@tonic-gate 		if (nfsl_errs_to_syslog) {
2027c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext(
203*2bc647a2SToomas Soome 			    "Can't stat %s - %s"), NFSL_CONFIG_FILE_PATH,
204*2bc647a2SToomas Soome 			    strerror(error));
2057c478bd9Sstevel@tonic-gate 		} else {
2067c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
207*2bc647a2SToomas Soome 			    "Can't stat %s - %s\n"), NFSL_CONFIG_FILE_PATH,
208*2bc647a2SToomas Soome 			    strerror(error));
2097c478bd9Sstevel@tonic-gate 		}
2107c478bd9Sstevel@tonic-gate 		return (0);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	if (config_last_modification.tv_sec == st.st_mtim.tv_sec &&
2147c478bd9Sstevel@tonic-gate 	    config_last_modification.tv_nsec == st.st_mtim.tv_nsec)
2157c478bd9Sstevel@tonic-gate 		return (0);
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	if (updated != NULL)
2187c478bd9Sstevel@tonic-gate 		*updated = B_TRUE;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	return (getconfiglist(listpp, B_TRUE));
2217c478bd9Sstevel@tonic-gate }
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate /*
2247c478bd9Sstevel@tonic-gate  * Does the real work. Reads the configuration file and creates the
2257c478bd9Sstevel@tonic-gate  * list of entries. Assumes that *listpp contains at least one entry.
2267c478bd9Sstevel@tonic-gate  * The caller is responsible for freeing any config entries added to
2277c478bd9Sstevel@tonic-gate  * the list whether this routine returns an error or not.
2287c478bd9Sstevel@tonic-gate  *
2297c478bd9Sstevel@tonic-gate  * Returns 0 on success and updates the '*listpp' config list,
2307c478bd9Sstevel@tonic-gate  * Returns non-zero error value otherwise.
2317c478bd9Sstevel@tonic-gate  */
2327c478bd9Sstevel@tonic-gate static int
getconfiglist(nfsl_config_t ** listpp,boolean_t updating)2337c478bd9Sstevel@tonic-gate getconfiglist(nfsl_config_t **listpp, boolean_t updating)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate 	FILE *fp;
2367c478bd9Sstevel@tonic-gate 	int error = 0;
2377c478bd9Sstevel@tonic-gate 	nfsl_config_t *listp = NULL, *tail = NULL;
2387c478bd9Sstevel@tonic-gate 	char linebuf[MAX_LINESZ];
2397c478bd9Sstevel@tonic-gate 	char errorbuf[ERROR_BUFSZ];
2407c478bd9Sstevel@tonic-gate 	char *tag, *defaultdir, *bufferpath, *rpclogpath, *fhpath, *logpath;
2417c478bd9Sstevel@tonic-gate 	int logformat;
2427c478bd9Sstevel@tonic-gate 	flock_t flock;
2437c478bd9Sstevel@tonic-gate 	struct stat st;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	fp = fopen(NFSL_CONFIG_FILE_PATH, "r");
2467c478bd9Sstevel@tonic-gate 	if (fp == NULL) {
2477c478bd9Sstevel@tonic-gate 		if (updating) {
2487c478bd9Sstevel@tonic-gate 			(void) sprintf(errorbuf, "Can't open %s",
249*2bc647a2SToomas Soome 			    NFSL_CONFIG_FILE_PATH);
2507c478bd9Sstevel@tonic-gate 		} else {
2517c478bd9Sstevel@tonic-gate 			(void) sprintf(errorbuf,
252*2bc647a2SToomas Soome 			    "Can't open %s - using hardwired defaults",
253*2bc647a2SToomas Soome 			    NFSL_CONFIG_FILE_PATH);
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 		/*
2577c478bd9Sstevel@tonic-gate 		 * Use hardwired config.
2587c478bd9Sstevel@tonic-gate 		 */
2597c478bd9Sstevel@tonic-gate 		if (nfsl_errs_to_syslog)
2607c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("%s"), errorbuf);
2617c478bd9Sstevel@tonic-gate 		else
2627c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext("%s\n"), errorbuf);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 		return (0);
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	(void) memset((void *) &flock, 0, sizeof (flock));
2687c478bd9Sstevel@tonic-gate 	flock.l_type = F_RDLCK;
2697c478bd9Sstevel@tonic-gate 	if (fcntl(fileno(fp), F_SETLKW, &flock) == -1) {
2707c478bd9Sstevel@tonic-gate 		error = errno;
2717c478bd9Sstevel@tonic-gate 		if (nfsl_errs_to_syslog) {
2727c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext(
273*2bc647a2SToomas Soome 			    "Can't lock %s - %s"), NFSL_CONFIG_FILE_PATH,
274*2bc647a2SToomas Soome 			    strerror(error));
2757c478bd9Sstevel@tonic-gate 		} else {
2767c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
277*2bc647a2SToomas Soome 			    "Can't lock %s - %s\n"), NFSL_CONFIG_FILE_PATH,
278*2bc647a2SToomas Soome 			    strerror(error));
2797c478bd9Sstevel@tonic-gate 		}
2807c478bd9Sstevel@tonic-gate 		goto done;
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	assert (*listpp != NULL);
2847c478bd9Sstevel@tonic-gate 	tail = getlastconfig(*listpp);
2857c478bd9Sstevel@tonic-gate 
28623a1cceaSRoger A. Faulkner 	while (gataline(fp, NFSL_CONFIG_FILE_PATH, linebuf, sizeof (linebuf))) {
2877c478bd9Sstevel@tonic-gate 		if (linebuf[0] == '\0') {
2887c478bd9Sstevel@tonic-gate 			/*
2897c478bd9Sstevel@tonic-gate 			 * ignore lines that exceed max size
2907c478bd9Sstevel@tonic-gate 			 */
2917c478bd9Sstevel@tonic-gate 			continue;
2927c478bd9Sstevel@tonic-gate 		}
2937c478bd9Sstevel@tonic-gate 
294*2bc647a2SToomas Soome 		error = get_info(linebuf, &tag, &defaultdir, &bufferpath,
295*2bc647a2SToomas Soome 		    &rpclogpath, &fhpath, &logpath, &logformat);
296*2bc647a2SToomas Soome 		if (error != 0)
2977c478bd9Sstevel@tonic-gate 			break;
2987c478bd9Sstevel@tonic-gate 
299*2bc647a2SToomas Soome 		listp = findconfig(listpp, tag, B_FALSE, &tail);
300*2bc647a2SToomas Soome 		if (listp != NULL) {
3017c478bd9Sstevel@tonic-gate 			/*
3027c478bd9Sstevel@tonic-gate 			 * An entry with the same tag name exists,
3037c478bd9Sstevel@tonic-gate 			 * update the fields that changed.
3047c478bd9Sstevel@tonic-gate 			 */
3057c478bd9Sstevel@tonic-gate 			error = update_config(listp, tag, defaultdir,
306*2bc647a2SToomas Soome 			    bufferpath, rpclogpath, fhpath, logpath,
307*2bc647a2SToomas Soome 			    logformat, B_TRUE, B_TRUE);
3087c478bd9Sstevel@tonic-gate 			if (error)
3097c478bd9Sstevel@tonic-gate 				break;
3107c478bd9Sstevel@tonic-gate 		} else {
3117c478bd9Sstevel@tonic-gate 			/*
3127c478bd9Sstevel@tonic-gate 			 * New entry, create it.
3137c478bd9Sstevel@tonic-gate 			 */
3147c478bd9Sstevel@tonic-gate 			listp = create_config(tag, defaultdir,
315*2bc647a2SToomas Soome 			    bufferpath, rpclogpath, fhpath,
316*2bc647a2SToomas Soome 			    logpath, logformat, B_TRUE, &error);
3177c478bd9Sstevel@tonic-gate 			if (listp == NULL)
3187c478bd9Sstevel@tonic-gate 				break;
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 			if (*listpp == NULL)
3217c478bd9Sstevel@tonic-gate 				*listpp = listp;
3227c478bd9Sstevel@tonic-gate 			else
3237c478bd9Sstevel@tonic-gate 				tail->nc_next = listp;
3247c478bd9Sstevel@tonic-gate 			tail = listp;
3257c478bd9Sstevel@tonic-gate 		}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 		assert(global != NULL);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
330*2bc647a2SToomas Soome 	if (error == 0) {
3317c478bd9Sstevel@tonic-gate 		/*
3327c478bd9Sstevel@tonic-gate 		 * Get mtime while we have file locked
3337c478bd9Sstevel@tonic-gate 		 */
334*2bc647a2SToomas Soome 		error = fstat(fileno(fp), &st);
335*2bc647a2SToomas Soome 		if (error != 0) {
3367c478bd9Sstevel@tonic-gate 			error = errno;
3377c478bd9Sstevel@tonic-gate 			if (nfsl_errs_to_syslog) {
3387c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, gettext(
339*2bc647a2SToomas Soome 				    "Can't stat %s - %s"),
340*2bc647a2SToomas Soome 				    NFSL_CONFIG_FILE_PATH,
341*2bc647a2SToomas Soome 				    strerror(error));
3427c478bd9Sstevel@tonic-gate 			} else {
3437c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(
344*2bc647a2SToomas Soome 				    "Can't stat %s - %s\n"),
345*2bc647a2SToomas Soome 				    NFSL_CONFIG_FILE_PATH,
346*2bc647a2SToomas Soome 				    strerror(error));
3477c478bd9Sstevel@tonic-gate 			}
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 		config_last_modification = st.st_mtim;
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate done:
3537c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
3547c478bd9Sstevel@tonic-gate 	return (error);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * Creates the config structure with the values specified by the
3597c478bd9Sstevel@tonic-gate  * parameters. If defaultdir has been specified, all relative paths
3607c478bd9Sstevel@tonic-gate  * are prepended with this defaultdir.
3617c478bd9Sstevel@tonic-gate  * If 'complete' is set then this must represent a complete config entry
3627c478bd9Sstevel@tonic-gate  * as specified by is_complete_config(), otherwise no work is perfomed, and
3637c478bd9Sstevel@tonic-gate  * NULL is returned.
3647c478bd9Sstevel@tonic-gate  *
3657c478bd9Sstevel@tonic-gate  * Returns the newly created config structure on success.
3667c478bd9Sstevel@tonic-gate  * Returns NULL on failure and sets error to the appropriate error.
3677c478bd9Sstevel@tonic-gate  */
3687c478bd9Sstevel@tonic-gate static nfsl_config_t *
create_config(char * tag,char * defaultdir,char * bufferpath,char * rpclogpath,char * fhpath,char * logpath,int logformat,boolean_t complete,int * error)3697c478bd9Sstevel@tonic-gate create_config(
370*2bc647a2SToomas Soome     char *tag,
371*2bc647a2SToomas Soome     char *defaultdir,
372*2bc647a2SToomas Soome     char *bufferpath,
373*2bc647a2SToomas Soome     char *rpclogpath,
374*2bc647a2SToomas Soome     char *fhpath,
375*2bc647a2SToomas Soome     char *logpath,
376*2bc647a2SToomas Soome     int   logformat,
377*2bc647a2SToomas Soome     boolean_t complete,
378*2bc647a2SToomas Soome     int  *error)
3797c478bd9Sstevel@tonic-gate {
3807c478bd9Sstevel@tonic-gate 	nfsl_config_t *config;
3817c478bd9Sstevel@tonic-gate 
382*2bc647a2SToomas Soome 	config = calloc(1, sizeof (*config));
383*2bc647a2SToomas Soome 	if (config == NULL) {
3847c478bd9Sstevel@tonic-gate 		*error = ENOMEM;
3857c478bd9Sstevel@tonic-gate 		return (NULL);
3867c478bd9Sstevel@tonic-gate 	}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	*error = update_config(config, tag, defaultdir, bufferpath, rpclogpath,
389*2bc647a2SToomas Soome 	    fhpath, logpath, logformat, complete, B_TRUE);
3907c478bd9Sstevel@tonic-gate 	if (*error) {
3917c478bd9Sstevel@tonic-gate 		free(config);
3927c478bd9Sstevel@tonic-gate 		return (NULL);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	config->nc_flags &= ~NC_UPDATED;	/* This is a new entry */
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	return (config);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate /*
4027c478bd9Sstevel@tonic-gate  * Updates the configuration entry with the new information provided,
4037c478bd9Sstevel@tonic-gate  * sets NC_UPDATED to indicate so. The entry is left untouched if all
4047c478bd9Sstevel@tonic-gate  * the fields are the same (except for 'nc_rpccookie', 'nc_transcookie'
4057c478bd9Sstevel@tonic-gate  * and 'nc_next').
4067c478bd9Sstevel@tonic-gate  * Prepends each path component with 'defauldir' if 'prepend' is set.
4077c478bd9Sstevel@tonic-gate  *
4087c478bd9Sstevel@tonic-gate  * Returns 0 on success, error otherwise.
4097c478bd9Sstevel@tonic-gate  * On error, the config entry is left in an inconsistent state.
4107c478bd9Sstevel@tonic-gate  * The only thing the caller can really do with it is free it.
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate static int
update_config(nfsl_config_t * config,char * tag,char * defaultdir,char * bufferpath,char * rpclogpath,char * fhpath,char * logpath,int logformat,boolean_t complete,boolean_t prepend)4137c478bd9Sstevel@tonic-gate update_config(
4147c478bd9Sstevel@tonic-gate 	nfsl_config_t *config,
4157c478bd9Sstevel@tonic-gate 	char *tag,
4167c478bd9Sstevel@tonic-gate 	char *defaultdir,
4177c478bd9Sstevel@tonic-gate 	char *bufferpath,
4187c478bd9Sstevel@tonic-gate 	char *rpclogpath,
4197c478bd9Sstevel@tonic-gate 	char *fhpath,
4207c478bd9Sstevel@tonic-gate 	char *logpath,
4217c478bd9Sstevel@tonic-gate 	int   logformat,
4227c478bd9Sstevel@tonic-gate 	boolean_t complete,
4237c478bd9Sstevel@tonic-gate 	boolean_t prepend)
4247c478bd9Sstevel@tonic-gate {
4257c478bd9Sstevel@tonic-gate 	boolean_t updated, config_updated = B_FALSE;
4267c478bd9Sstevel@tonic-gate 	int error = 0;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	if (complete && !is_complete_config(tag, bufferpath, fhpath, logpath)) {
4297c478bd9Sstevel@tonic-gate 		/*
4307c478bd9Sstevel@tonic-gate 		 * Not a complete entry
4317c478bd9Sstevel@tonic-gate 		 */
4327c478bd9Sstevel@tonic-gate 		if (nfsl_errs_to_syslog) {
4337c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext(
434*2bc647a2SToomas Soome 			    "update_config: \"%s\" not a complete "
435*2bc647a2SToomas Soome 			    "config entry."), tag);
4367c478bd9Sstevel@tonic-gate 		} else {
4377c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
438*2bc647a2SToomas Soome 			    "update_config: \"%s\" not a complete "
439*2bc647a2SToomas Soome 			    "config entry.\n"), tag);
4407c478bd9Sstevel@tonic-gate 		}
4417c478bd9Sstevel@tonic-gate 		return (EINVAL);
4427c478bd9Sstevel@tonic-gate 	}
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	assert(tag != NULL);
4457c478bd9Sstevel@tonic-gate 	if (config->nc_name == NULL) {
4467c478bd9Sstevel@tonic-gate 		/*
4477c478bd9Sstevel@tonic-gate 		 * New entry
4487c478bd9Sstevel@tonic-gate 		 */
4497c478bd9Sstevel@tonic-gate 		if ((config->nc_name = strdup(tag)) == NULL) {
4507c478bd9Sstevel@tonic-gate 			error = ENOMEM;
4517c478bd9Sstevel@tonic-gate 			goto errout;
4527c478bd9Sstevel@tonic-gate 		}
453*2bc647a2SToomas Soome 	} else {
4547c478bd9Sstevel@tonic-gate 		assert(strcmp(config->nc_name, tag) == 0);
455*2bc647a2SToomas Soome 	}
4567c478bd9Sstevel@tonic-gate 
457*2bc647a2SToomas Soome 	error = update_field(
458*2bc647a2SToomas Soome 	    &config->nc_defaultdir, defaultdir, NULL, &updated);
459*2bc647a2SToomas Soome 	if (error != 0)
4607c478bd9Sstevel@tonic-gate 		goto errout;
4617c478bd9Sstevel@tonic-gate 	if (!prepend) {
4627c478bd9Sstevel@tonic-gate 		/*
4637c478bd9Sstevel@tonic-gate 		 * Do not prepend default directory.
4647c478bd9Sstevel@tonic-gate 		 */
4657c478bd9Sstevel@tonic-gate 		defaultdir = NULL;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	config_updated |= updated;
468*2bc647a2SToomas Soome 	error = update_field(
469*2bc647a2SToomas Soome 	    &config->nc_bufferpath, bufferpath, defaultdir, &updated);
470*2bc647a2SToomas Soome 	if (error != 0)
4717c478bd9Sstevel@tonic-gate 		goto errout;
4727c478bd9Sstevel@tonic-gate 	config_updated |= updated;
473*2bc647a2SToomas Soome 	error = update_field(
474*2bc647a2SToomas Soome 	    &config->nc_rpclogpath, rpclogpath, defaultdir, &updated);
475*2bc647a2SToomas Soome 	if (error != 0)
4767c478bd9Sstevel@tonic-gate 		goto errout;
4777c478bd9Sstevel@tonic-gate 	config_updated |= updated;
478*2bc647a2SToomas Soome 	error = update_field(
479*2bc647a2SToomas Soome 	    &config->nc_fhpath, fhpath, defaultdir, &updated);
480*2bc647a2SToomas Soome 	if (error != 0)
4817c478bd9Sstevel@tonic-gate 		goto errout;
4827c478bd9Sstevel@tonic-gate 	config_updated |= updated;
483*2bc647a2SToomas Soome 	error = update_field(
484*2bc647a2SToomas Soome 	    &config->nc_logpath, logpath, defaultdir, &updated);
485*2bc647a2SToomas Soome 	if (error != 0)
4867c478bd9Sstevel@tonic-gate 		goto errout;
4877c478bd9Sstevel@tonic-gate 	config_updated |= updated;
4887c478bd9Sstevel@tonic-gate 	updated = (config->nc_logformat != logformat);
4897c478bd9Sstevel@tonic-gate 	if (updated)
4907c478bd9Sstevel@tonic-gate 		config->nc_logformat = logformat;
4917c478bd9Sstevel@tonic-gate 	config_updated |= updated;
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	if (config_updated)
4947c478bd9Sstevel@tonic-gate 		config->nc_flags |= NC_UPDATED;
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	if (strcmp(tag, DEFAULTTAG) == 0) {
4977c478bd9Sstevel@tonic-gate 		/*
4987c478bd9Sstevel@tonic-gate 		 * Have the default global config point to this entry.
4997c478bd9Sstevel@tonic-gate 		 */
5007c478bd9Sstevel@tonic-gate 		global = config;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 		/*
5037c478bd9Sstevel@tonic-gate 		 * Update the global_raw configuration entry.
5047c478bd9Sstevel@tonic-gate 		 * Make sure no expanding of paths occurs.
5057c478bd9Sstevel@tonic-gate 		 */
506*2bc647a2SToomas Soome 		error = update_config(global_raw, DEFAULTRAWTAG, defaultdir,
507*2bc647a2SToomas Soome 		    bufferpath, rpclogpath, fhpath, logpath, logformat,
508*2bc647a2SToomas Soome 		    complete, B_FALSE);
509*2bc647a2SToomas Soome 		if (error != 0)
510*2bc647a2SToomas Soome 			goto errout;
5117c478bd9Sstevel@tonic-gate 	}
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	return (error);
5147c478bd9Sstevel@tonic-gate 
5157c478bd9Sstevel@tonic-gate errout:
5167c478bd9Sstevel@tonic-gate 	if (nfsl_errs_to_syslog) {
5177c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, gettext(
518*2bc647a2SToomas Soome 		    "update_config: Can't process \"%s\" config entry: %s"),
519*2bc647a2SToomas Soome 		    tag, strerror(error));
5207c478bd9Sstevel@tonic-gate 	} else {
5217c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
522*2bc647a2SToomas Soome 		    "update_config: Can't process \"%s\" config entry: %s\n"),
523*2bc647a2SToomas Soome 		    tag, strerror(error));
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 	return (error);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate /*
5297c478bd9Sstevel@tonic-gate  * Prepends 'prependir' to 'new' if 'prependir' is defined.
5307c478bd9Sstevel@tonic-gate  * Compares the value of '*old' with 'new', if it has changed,
5317c478bd9Sstevel@tonic-gate  * then sets whatever 'old' references equal to 'new'.
5327c478bd9Sstevel@tonic-gate  * Returns 0 on success, error otherwise.
5337c478bd9Sstevel@tonic-gate  * Sets '*updated' to B_TRUE if field was modified.
5347c478bd9Sstevel@tonic-gate  * The value of '*updated' is undefined on error.
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate static int
update_field(char ** old,char * new,char * prependdir,boolean_t * updated)5377c478bd9Sstevel@tonic-gate update_field(
5387c478bd9Sstevel@tonic-gate 	char **old,		/* pointer to config field */
5397c478bd9Sstevel@tonic-gate 	char *new,		/* updated value */
5407c478bd9Sstevel@tonic-gate 	char *prependdir,	/* prepend this directory to new */
5417c478bd9Sstevel@tonic-gate 	boolean_t *updated)	/* field was modified */
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 	char *tmp_new = NULL;
5447c478bd9Sstevel@tonic-gate 	int need_update = 0;
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (new != NULL) {
5477c478bd9Sstevel@tonic-gate 		if (prependdir != NULL && new[0] != '/') {
5487c478bd9Sstevel@tonic-gate 			tmp_new = malloc(strlen(prependdir) + strlen(new) + 2);
5497c478bd9Sstevel@tonic-gate 			if (tmp_new == NULL)
5507c478bd9Sstevel@tonic-gate 				return (ENOMEM);
5517c478bd9Sstevel@tonic-gate 			(void) sprintf(tmp_new, "%s/%s", prependdir, new);
5527c478bd9Sstevel@tonic-gate 		} else {
5537c478bd9Sstevel@tonic-gate 			if ((tmp_new = strdup(new)) == NULL)
5547c478bd9Sstevel@tonic-gate 				return (ENOMEM);
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 	}
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (tmp_new != NULL) {
5597c478bd9Sstevel@tonic-gate 		if (*old == NULL)
5607c478bd9Sstevel@tonic-gate 			need_update++;
5617c478bd9Sstevel@tonic-gate 		else if (strcmp(tmp_new, *old) != 0) {
5627c478bd9Sstevel@tonic-gate 			free(*old);
5637c478bd9Sstevel@tonic-gate 			need_update++;
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 		if (need_update)
5667c478bd9Sstevel@tonic-gate 			*old = tmp_new;
5677c478bd9Sstevel@tonic-gate 	} else if (*old != NULL) {
5687c478bd9Sstevel@tonic-gate 		need_update++;
5697c478bd9Sstevel@tonic-gate 		free(*old);
5707c478bd9Sstevel@tonic-gate 		*old = NULL;
5717c478bd9Sstevel@tonic-gate 	}
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	*updated = need_update != 0;
5747c478bd9Sstevel@tonic-gate 	return (0);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate #ifdef DEBUG
5787c478bd9Sstevel@tonic-gate /*
5797c478bd9Sstevel@tonic-gate  * Removes and frees the 'config' entry from the list
5807c478bd9Sstevel@tonic-gate  * pointed to by '*listpp'.
5817c478bd9Sstevel@tonic-gate  * No error is reported if the entry does not exist.
5827c478bd9Sstevel@tonic-gate  * Updates '*tail' to point to the last item in the list.
5837c478bd9Sstevel@tonic-gate  */
5847c478bd9Sstevel@tonic-gate static void
remove_config(nfsl_config_t ** listpp,nfsl_config_t * config,nfsl_config_t ** tail)5857c478bd9Sstevel@tonic-gate remove_config(
5867c478bd9Sstevel@tonic-gate 	nfsl_config_t **listpp,
5877c478bd9Sstevel@tonic-gate 	nfsl_config_t *config,
5887c478bd9Sstevel@tonic-gate 	nfsl_config_t **tail)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate 	nfsl_config_t *p, *prev;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	prev = *listpp;
5937c478bd9Sstevel@tonic-gate 	for (p = *listpp; p != NULL; p = p->nc_next) {
5947c478bd9Sstevel@tonic-gate 		if (p == config) {
5957c478bd9Sstevel@tonic-gate 			if (p == prev) {
5967c478bd9Sstevel@tonic-gate 				/*
5977c478bd9Sstevel@tonic-gate 				 * first element of the list
5987c478bd9Sstevel@tonic-gate 				 */
5997c478bd9Sstevel@tonic-gate 				*listpp = prev->nc_next;
6007c478bd9Sstevel@tonic-gate 			} else
6017c478bd9Sstevel@tonic-gate 				prev->nc_next = p->nc_next;
6027c478bd9Sstevel@tonic-gate 			free_config(p);
6037c478bd9Sstevel@tonic-gate 			break;
6047c478bd9Sstevel@tonic-gate 		}
6057c478bd9Sstevel@tonic-gate 		prev = p;
6067c478bd9Sstevel@tonic-gate 	}
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 	/*
6097c478bd9Sstevel@tonic-gate 	 * Find tail of the list.
6107c478bd9Sstevel@tonic-gate 	 */
6117c478bd9Sstevel@tonic-gate 	for (*tail = prev; (*tail)->nc_next != NULL; *tail = (*tail)->nc_next)
6127c478bd9Sstevel@tonic-gate 		;
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate #endif /* DEBUG */
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate static void
free_config(nfsl_config_t * config)6177c478bd9Sstevel@tonic-gate free_config(nfsl_config_t *config)
6187c478bd9Sstevel@tonic-gate {
6197c478bd9Sstevel@tonic-gate 	if (config == NULL)
6207c478bd9Sstevel@tonic-gate 		return;
6217c478bd9Sstevel@tonic-gate 	if (config->nc_name)
6227c478bd9Sstevel@tonic-gate 		free(config->nc_name);
6237c478bd9Sstevel@tonic-gate 	if (config->nc_defaultdir)
6247c478bd9Sstevel@tonic-gate 		free(config->nc_defaultdir);
6257c478bd9Sstevel@tonic-gate 	if (config->nc_bufferpath)
6267c478bd9Sstevel@tonic-gate 		free(config->nc_bufferpath);
6277c478bd9Sstevel@tonic-gate 	if (config->nc_rpclogpath)
6287c478bd9Sstevel@tonic-gate 		free(config->nc_rpclogpath);
6297c478bd9Sstevel@tonic-gate 	if (config->nc_fhpath)
6307c478bd9Sstevel@tonic-gate 		free(config->nc_fhpath);
6317c478bd9Sstevel@tonic-gate 	if (config->nc_logpath)
6327c478bd9Sstevel@tonic-gate 		free(config->nc_logpath);
6337c478bd9Sstevel@tonic-gate 	if (config == global)
6347c478bd9Sstevel@tonic-gate 		global = NULL;
6357c478bd9Sstevel@tonic-gate 	if (config == global_raw)
6367c478bd9Sstevel@tonic-gate 		global_raw = NULL;
6377c478bd9Sstevel@tonic-gate 	free(config);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate void
nfsl_freeconfig_list(nfsl_config_t ** listpp)6417c478bd9Sstevel@tonic-gate nfsl_freeconfig_list(nfsl_config_t **listpp)
6427c478bd9Sstevel@tonic-gate {
6437c478bd9Sstevel@tonic-gate 	nfsl_config_t *next;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	if (*listpp == NULL)
6467c478bd9Sstevel@tonic-gate 		return;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	do {
6497c478bd9Sstevel@tonic-gate 		next = (*listpp)->nc_next;
6507c478bd9Sstevel@tonic-gate 		free_config(*listpp);
6517c478bd9Sstevel@tonic-gate 		*listpp = next;
6527c478bd9Sstevel@tonic-gate 	} while (*listpp);
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	free_config(global_raw);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate /*
6587c478bd9Sstevel@tonic-gate  * Returns a pointer to the first instance of 'tag' in the list.
6597c478bd9Sstevel@tonic-gate  * If 'remove' is true, then the entry is removed from the list and
6607c478bd9Sstevel@tonic-gate  * a pointer to it is returned.
6617c478bd9Sstevel@tonic-gate  * If '*tail' is not NULL, then it will point to the last element of
6627c478bd9Sstevel@tonic-gate  * the list. Note that this function assumes that *tail already
6637c478bd9Sstevel@tonic-gate  * points at the last element of the list.
6647c478bd9Sstevel@tonic-gate  * Returns NULL if the entry does not exist.
6657c478bd9Sstevel@tonic-gate  */
6667c478bd9Sstevel@tonic-gate static nfsl_config_t *
findconfig(nfsl_config_t ** listpp,char * tag,boolean_t remove,nfsl_config_t ** tail)6677c478bd9Sstevel@tonic-gate findconfig(
6687c478bd9Sstevel@tonic-gate 	nfsl_config_t **listpp,
6697c478bd9Sstevel@tonic-gate 	char *tag, boolean_t remove,
6707c478bd9Sstevel@tonic-gate 	nfsl_config_t **tail)
6717c478bd9Sstevel@tonic-gate {
6727c478bd9Sstevel@tonic-gate 	nfsl_config_t *p, *prev;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	prev = *listpp;
6757c478bd9Sstevel@tonic-gate 	for (p = *listpp; p != NULL; p = p->nc_next) {
6767c478bd9Sstevel@tonic-gate 		if (strcmp(p->nc_name, tag) == 0) {
6777c478bd9Sstevel@tonic-gate 			if (remove) {
6787c478bd9Sstevel@tonic-gate 				if (p == prev) {
6797c478bd9Sstevel@tonic-gate 					/*
6807c478bd9Sstevel@tonic-gate 					 * first element of the list
6817c478bd9Sstevel@tonic-gate 					 */
6827c478bd9Sstevel@tonic-gate 					*listpp = prev->nc_next;
6837c478bd9Sstevel@tonic-gate 				} else
6847c478bd9Sstevel@tonic-gate 					prev->nc_next = p->nc_next;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 				if (tail != NULL && p == *tail) {
6877c478bd9Sstevel@tonic-gate 					/*
6887c478bd9Sstevel@tonic-gate 					 * Only update *tail if we removed
6897c478bd9Sstevel@tonic-gate 					 * the last element of the list, and we
6907c478bd9Sstevel@tonic-gate 					 * requested *tail to be updated.
6917c478bd9Sstevel@tonic-gate 					 */
6927c478bd9Sstevel@tonic-gate 					*tail = prev;
6937c478bd9Sstevel@tonic-gate 				}
6947c478bd9Sstevel@tonic-gate 			}
6957c478bd9Sstevel@tonic-gate 			return (p);
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 		prev = p;
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	return (NULL);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate static nfsl_config_t *
getlastconfig(nfsl_config_t * listp)7047c478bd9Sstevel@tonic-gate getlastconfig(nfsl_config_t *listp)
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate 	nfsl_config_t *lastp = NULL;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	for (; listp != NULL; listp = listp->nc_next)
7097c478bd9Sstevel@tonic-gate 		lastp = listp;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 	return (lastp);
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate  * Returns a pointer to the first instance of 'tag' in the list.
7167c478bd9Sstevel@tonic-gate  * Returns NULL if the entry does not exist.
7177c478bd9Sstevel@tonic-gate  * Sets 'error' if the update of the list failed if necessary, and
7187c478bd9Sstevel@tonic-gate  * returns NULL.
7197c478bd9Sstevel@tonic-gate  */
7207c478bd9Sstevel@tonic-gate nfsl_config_t *
nfsl_findconfig(nfsl_config_t * listp,char * tag,int * error)7217c478bd9Sstevel@tonic-gate nfsl_findconfig(nfsl_config_t *listp, char *tag, int *error)
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate 	nfsl_config_t *config;
7247c478bd9Sstevel@tonic-gate 	boolean_t updated;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	*error = 0;
7277c478bd9Sstevel@tonic-gate 	config = findconfig(&listp, tag, B_FALSE, (nfsl_config_t **)NULL);
7287c478bd9Sstevel@tonic-gate 	if (config == NULL) {
7297c478bd9Sstevel@tonic-gate 		/*
7307c478bd9Sstevel@tonic-gate 		 * Rebuild our list if the file has changed.
7317c478bd9Sstevel@tonic-gate 		 */
732*2bc647a2SToomas Soome 		*error = nfsl_checkconfig_list(&listp, &updated);
733*2bc647a2SToomas Soome 		if (*error != 0) {
7347c478bd9Sstevel@tonic-gate 			/*
7357c478bd9Sstevel@tonic-gate 			 * List may be corrupted, notify caller.
7367c478bd9Sstevel@tonic-gate 			 */
7377c478bd9Sstevel@tonic-gate 			return (NULL);
7387c478bd9Sstevel@tonic-gate 		}
7397c478bd9Sstevel@tonic-gate 		if (updated) {
7407c478bd9Sstevel@tonic-gate 			/*
7417c478bd9Sstevel@tonic-gate 			 * Search for tag again.
7427c478bd9Sstevel@tonic-gate 			 */
7437c478bd9Sstevel@tonic-gate 			config = findconfig(&listp, tag, B_FALSE,
744*2bc647a2SToomas Soome 			    (nfsl_config_t **)NULL);
7457c478bd9Sstevel@tonic-gate 		}
7467c478bd9Sstevel@tonic-gate 	}
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	return (config);
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate  * Use the raw global values if any of the parameters is not defined.
7537c478bd9Sstevel@tonic-gate  */
7547c478bd9Sstevel@tonic-gate static void
complete_with_global(char ** defaultdir,char ** bufferpath,char ** rpclogpath,char ** fhpath,char ** logpath,int * logformat)7557c478bd9Sstevel@tonic-gate complete_with_global(
7567c478bd9Sstevel@tonic-gate 	char **defaultdir,
7577c478bd9Sstevel@tonic-gate 	char **bufferpath,
7587c478bd9Sstevel@tonic-gate 	char **rpclogpath,
7597c478bd9Sstevel@tonic-gate 	char **fhpath,
7607c478bd9Sstevel@tonic-gate 	char **logpath,
7617c478bd9Sstevel@tonic-gate 	int  *logformat)
7627c478bd9Sstevel@tonic-gate {
7637c478bd9Sstevel@tonic-gate 	if (*defaultdir == NULL)
7647c478bd9Sstevel@tonic-gate 		*defaultdir = global_raw->nc_defaultdir;
7657c478bd9Sstevel@tonic-gate 	if (*bufferpath == NULL)
7667c478bd9Sstevel@tonic-gate 		*bufferpath = global_raw->nc_bufferpath;
7677c478bd9Sstevel@tonic-gate 	if (*rpclogpath == NULL)
7687c478bd9Sstevel@tonic-gate 		*rpclogpath = global_raw->nc_rpclogpath;
7697c478bd9Sstevel@tonic-gate 	if (*fhpath == NULL)
7707c478bd9Sstevel@tonic-gate 		*fhpath = global_raw->nc_fhpath;
7717c478bd9Sstevel@tonic-gate 	if (*logpath == NULL)
7727c478bd9Sstevel@tonic-gate 		*logpath = global_raw->nc_logpath;
7737c478bd9Sstevel@tonic-gate 	if (*logformat == 0)
7747c478bd9Sstevel@tonic-gate 		*logformat = global_raw->nc_logformat;
7757c478bd9Sstevel@tonic-gate }
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate /*
7787c478bd9Sstevel@tonic-gate  * Parses 'linebuf'. Returns 0 if a valid tag is found, otherwise non-zero.
7797c478bd9Sstevel@tonic-gate  * Unknown tokens are silently ignored.
7807c478bd9Sstevel@tonic-gate  * It is the responsibility of the caller to make a copy of the non-NULL
7817c478bd9Sstevel@tonic-gate  * parameters if they need to be used before linebuf is freed.
7827c478bd9Sstevel@tonic-gate  */
7837c478bd9Sstevel@tonic-gate static int
get_info(char * linebuf,char ** tag,char ** defaultdir,char ** bufferpath,char ** rpclogpath,char ** fhpath,char ** logpath,int * logformat)7847c478bd9Sstevel@tonic-gate get_info(
7857c478bd9Sstevel@tonic-gate 	char *linebuf,
7867c478bd9Sstevel@tonic-gate 	char **tag,
7877c478bd9Sstevel@tonic-gate 	char **defaultdir,
7887c478bd9Sstevel@tonic-gate 	char **bufferpath,
7897c478bd9Sstevel@tonic-gate 	char **rpclogpath,
7907c478bd9Sstevel@tonic-gate 	char **fhpath,
7917c478bd9Sstevel@tonic-gate 	char **logpath,
7927c478bd9Sstevel@tonic-gate 	int  *logformat)
7937c478bd9Sstevel@tonic-gate {
7947c478bd9Sstevel@tonic-gate 	char *tok;
7957c478bd9Sstevel@tonic-gate 	char *tmp;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	/* tag */
7987c478bd9Sstevel@tonic-gate 	*tag = NULL;
7997c478bd9Sstevel@tonic-gate 	tok = strtok(linebuf, whitespace);
8007c478bd9Sstevel@tonic-gate 	if (tok == NULL)
8017c478bd9Sstevel@tonic-gate 		goto badtag;
8027c478bd9Sstevel@tonic-gate 	if (!is_legal_tag(tok))
8037c478bd9Sstevel@tonic-gate 		goto badtag;
8047c478bd9Sstevel@tonic-gate 	*tag = tok;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	*defaultdir = *bufferpath = *rpclogpath = NULL;
8077c478bd9Sstevel@tonic-gate 	*fhpath = *logpath = NULL;
8087c478bd9Sstevel@tonic-gate 	*logformat = 0;
8097c478bd9Sstevel@tonic-gate 
810*2bc647a2SToomas Soome 	while ((tok = strtok(NULL, whitespace)) != NULL) {
8117c478bd9Sstevel@tonic-gate 		if (strncmp(tok, "defaultdir=", strlen("defaultdir=")) == 0) {
8127c478bd9Sstevel@tonic-gate 			*defaultdir = tok + strlen("defaultdir=");
8137c478bd9Sstevel@tonic-gate 		} else if (strncmp(tok, "buffer=", strlen("buffer=")) == 0) {
8147c478bd9Sstevel@tonic-gate 			*bufferpath = tok + strlen("buffer=");
8157c478bd9Sstevel@tonic-gate 		} else if (strncmp(tok, "rpclog=", strlen("rpclog=")) == 0) {
8167c478bd9Sstevel@tonic-gate 			*rpclogpath = tok + strlen("rpclog=");
8177c478bd9Sstevel@tonic-gate 		} else if (strncmp(tok, "fhtable=", strlen("fhtable=")) == 0) {
8187c478bd9Sstevel@tonic-gate 			*fhpath = tok + strlen("fhtable=");
8197c478bd9Sstevel@tonic-gate 		} else if (strncmp(tok, "log=", strlen("log=")) == 0) {
8207c478bd9Sstevel@tonic-gate 			*logpath = tok + strlen("log=");
8217c478bd9Sstevel@tonic-gate 		} else if (strncmp(tok, "logformat=",
822*2bc647a2SToomas Soome 		    strlen("logformat=")) == 0) {
8237c478bd9Sstevel@tonic-gate 			tmp = tok + strlen("logformat=");
8247c478bd9Sstevel@tonic-gate 			if (strncmp(tmp, "extended", strlen("extended")) == 0) {
8257c478bd9Sstevel@tonic-gate 				*logformat = TRANSLOG_EXTENDED;
8267c478bd9Sstevel@tonic-gate 			} else {
8277c478bd9Sstevel@tonic-gate 				/*
8287c478bd9Sstevel@tonic-gate 				 * Use transaction log basic format if
8297c478bd9Sstevel@tonic-gate 				 * 'extended' was not specified.
8307c478bd9Sstevel@tonic-gate 				 */
8317c478bd9Sstevel@tonic-gate 				*logformat = TRANSLOG_BASIC;
8327c478bd9Sstevel@tonic-gate 			}
8337c478bd9Sstevel@tonic-gate 		}
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	if (strcmp(*tag, DEFAULTTAG) != 0) {
8377c478bd9Sstevel@tonic-gate 		/*
8387c478bd9Sstevel@tonic-gate 		 * Use global values for fields not specified if
8397c478bd9Sstevel@tonic-gate 		 * this tag is not the global tag.
8407c478bd9Sstevel@tonic-gate 		 */
8417c478bd9Sstevel@tonic-gate 		complete_with_global(defaultdir, bufferpath,
842*2bc647a2SToomas Soome 		    rpclogpath, fhpath, logpath, logformat);
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	return (0);
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate badtag:
8487c478bd9Sstevel@tonic-gate 	if (nfsl_errs_to_syslog) {
8497c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, gettext(
850*2bc647a2SToomas Soome 		    "Bad tag found in config file."));
8517c478bd9Sstevel@tonic-gate 	} else {
8527c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(
853*2bc647a2SToomas Soome 		    "Bad tag found in config file.\n"));
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 	return (-1);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate /*
8597c478bd9Sstevel@tonic-gate  * Returns True if we have all the elements of a complete configuration
8607c478bd9Sstevel@tonic-gate  * entry. A complete configuration has tag, bufferpath, fhpath and logpath
8617c478bd9Sstevel@tonic-gate  * defined to non-zero strings.
8627c478bd9Sstevel@tonic-gate  */
8637c478bd9Sstevel@tonic-gate static boolean_t
is_complete_config(char * tag,char * bufferpath,char * fhpath,char * logpath)8647c478bd9Sstevel@tonic-gate is_complete_config(
8657c478bd9Sstevel@tonic-gate 	char *tag,
8667c478bd9Sstevel@tonic-gate 	char *bufferpath,
8677c478bd9Sstevel@tonic-gate 	char *fhpath,
8687c478bd9Sstevel@tonic-gate 	char *logpath)
8697c478bd9Sstevel@tonic-gate {
8707c478bd9Sstevel@tonic-gate 	assert(tag != NULL);
8717c478bd9Sstevel@tonic-gate 	assert(strlen(tag) > 0);
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	if ((bufferpath != NULL && strlen(bufferpath) > 0) &&
8747c478bd9Sstevel@tonic-gate 	    (fhpath != NULL && strlen(fhpath) > 0) &&
8757c478bd9Sstevel@tonic-gate 	    (logpath != NULL && strlen(logpath) > 0))
8767c478bd9Sstevel@tonic-gate 		return (B_TRUE);
8777c478bd9Sstevel@tonic-gate 	return (B_FALSE);
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate #ifdef DEBUG
8817c478bd9Sstevel@tonic-gate /*
8827c478bd9Sstevel@tonic-gate  * Prints the configuration entry to stdout.
8837c478bd9Sstevel@tonic-gate  */
8847c478bd9Sstevel@tonic-gate void
nfsl_printconfig(nfsl_config_t * config)8857c478bd9Sstevel@tonic-gate nfsl_printconfig(nfsl_config_t *config)
8867c478bd9Sstevel@tonic-gate {
8877c478bd9Sstevel@tonic-gate 	if (config->nc_name)
8887c478bd9Sstevel@tonic-gate 		(void) printf("tag=%s\t", config->nc_name);
8897c478bd9Sstevel@tonic-gate 	if (config->nc_defaultdir)
8907c478bd9Sstevel@tonic-gate 		(void) printf("defaultdir=%s\t", config->nc_defaultdir);
8917c478bd9Sstevel@tonic-gate 	if (config->nc_logpath)
8927c478bd9Sstevel@tonic-gate 		(void) printf("logpath=%s\t", config->nc_logpath);
8937c478bd9Sstevel@tonic-gate 	if (config->nc_fhpath)
8947c478bd9Sstevel@tonic-gate 		(void) printf("fhpath=%s\t", config->nc_fhpath);
8957c478bd9Sstevel@tonic-gate 	if (config->nc_bufferpath)
8967c478bd9Sstevel@tonic-gate 		(void) printf("bufpath=%s\t", config->nc_bufferpath);
8977c478bd9Sstevel@tonic-gate 	if (config->nc_rpclogpath)
8987c478bd9Sstevel@tonic-gate 		(void) printf("rpclogpath=%s\t", config->nc_rpclogpath);
8997c478bd9Sstevel@tonic-gate 	if (config->nc_logformat == TRANSLOG_BASIC)
9007c478bd9Sstevel@tonic-gate 		(void) printf("logformat=basic");
9017c478bd9Sstevel@tonic-gate 	else if (config->nc_logformat == TRANSLOG_EXTENDED)
9027c478bd9Sstevel@tonic-gate 		(void) printf("logformat=extended");
9037c478bd9Sstevel@tonic-gate 	else
9047c478bd9Sstevel@tonic-gate 		(void) printf("config->nc_logformat=UNKNOWN");
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	if (config->nc_flags & NC_UPDATED)
9077c478bd9Sstevel@tonic-gate 		(void) printf("\tflags=NC_UPDATED");
9087c478bd9Sstevel@tonic-gate 	(void) printf("\n");
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate  * Prints the configuration list to stdout.
9137c478bd9Sstevel@tonic-gate  */
9147c478bd9Sstevel@tonic-gate void
nfsl_printconfig_list(nfsl_config_t * listp)9157c478bd9Sstevel@tonic-gate nfsl_printconfig_list(nfsl_config_t *listp)
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate 	for (; listp != NULL; listp = listp->nc_next) {
9187c478bd9Sstevel@tonic-gate 		nfsl_printconfig(listp);
9197c478bd9Sstevel@tonic-gate 		(void) printf("\n");
9207c478bd9Sstevel@tonic-gate 	}
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate #endif /* DEBUG */
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate /*
9257c478bd9Sstevel@tonic-gate  * Returns non-zero if the given string is allowable for a tag, zero if
9267c478bd9Sstevel@tonic-gate  * not.
9277c478bd9Sstevel@tonic-gate  */
9287c478bd9Sstevel@tonic-gate static int
is_legal_tag(char * tag)9297c478bd9Sstevel@tonic-gate is_legal_tag(char *tag)
9307c478bd9Sstevel@tonic-gate {
9317c478bd9Sstevel@tonic-gate 	int i;
9327c478bd9Sstevel@tonic-gate 	int len;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	if (tag == NULL)
9357c478bd9Sstevel@tonic-gate 		return (0);
9367c478bd9Sstevel@tonic-gate 	len = strlen(tag);
9377c478bd9Sstevel@tonic-gate 	if (len == 0)
9387c478bd9Sstevel@tonic-gate 		return (0);
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
9417c478bd9Sstevel@tonic-gate 		char c;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 		c = tag[i];
9447c478bd9Sstevel@tonic-gate 		if (!(isalnum((unsigned char)c) || c == '_'))
9457c478bd9Sstevel@tonic-gate 			return (0);
9467c478bd9Sstevel@tonic-gate 	}
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	return (1);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /*
95223a1cceaSRoger A. Faulkner  * gataline attempts to get a line from the configuration file,
9537c478bd9Sstevel@tonic-gate  * upto LINESZ. A line in the file is a concatenation of lines if the
9547c478bd9Sstevel@tonic-gate  * continuation symbol '\' is used at the end of the line. Returns
9557c478bd9Sstevel@tonic-gate  * line on success, a NULL on EOF, and an empty string on lines > linesz.
9567c478bd9Sstevel@tonic-gate  */
9577c478bd9Sstevel@tonic-gate static char *
gataline(FILE * fp,char * path,char * line,int linesz)958*2bc647a2SToomas Soome gataline(FILE *fp, char *path, char *line, int linesz)
959*2bc647a2SToomas Soome {
960*2bc647a2SToomas Soome 	char *p = line;
961*2bc647a2SToomas Soome 	int len;
9627c478bd9Sstevel@tonic-gate 	int excess = 0;
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	*p = '\0';
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	for (;;) {
9677c478bd9Sstevel@tonic-gate 		if (fgets(p, linesz - (p-line), fp) == NULL) {
9687c478bd9Sstevel@tonic-gate 			return (*line ? line : NULL);   /* EOF */
9697c478bd9Sstevel@tonic-gate 		}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 		len = strlen(line);
9727c478bd9Sstevel@tonic-gate 		if (len <= 0) {
9737c478bd9Sstevel@tonic-gate 			p = line;
9747c478bd9Sstevel@tonic-gate 			continue;
9757c478bd9Sstevel@tonic-gate 		}
9767c478bd9Sstevel@tonic-gate 		p = &line[len - 1];
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		/*
9797c478bd9Sstevel@tonic-gate 		 * Is input line too long?
9807c478bd9Sstevel@tonic-gate 		 */
9817c478bd9Sstevel@tonic-gate 		if (*p != '\n') {
9827c478bd9Sstevel@tonic-gate 			excess = 1;
9837c478bd9Sstevel@tonic-gate 			/*
9847c478bd9Sstevel@tonic-gate 			 * Perhaps last char read was '\'. Reinsert it
9857c478bd9Sstevel@tonic-gate 			 * into the stream to ease the parsing when we
9867c478bd9Sstevel@tonic-gate 			 * read the rest of the line to discard.
9877c478bd9Sstevel@tonic-gate 			 */
9887c478bd9Sstevel@tonic-gate 			(void) ungetc(*p, fp);
9897c478bd9Sstevel@tonic-gate 			break;
9907c478bd9Sstevel@tonic-gate 		}
9917c478bd9Sstevel@tonic-gate trim:
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 		/* trim trailing white space */
9947c478bd9Sstevel@tonic-gate 		while (p >= line && isspace(*(uchar_t *)p))
995*2bc647a2SToomas Soome 			*p-- = '\0';
9967c478bd9Sstevel@tonic-gate 		if (p < line) {			/* empty line */
9977c478bd9Sstevel@tonic-gate 			p = line;
9987c478bd9Sstevel@tonic-gate 			continue;
9997c478bd9Sstevel@tonic-gate 		}
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		if (*p == '\\') {		/* continuation */
10027c478bd9Sstevel@tonic-gate 			*p = '\0';
10037c478bd9Sstevel@tonic-gate 			continue;
10047c478bd9Sstevel@tonic-gate 		}
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 		/*
10077c478bd9Sstevel@tonic-gate 		 * Ignore comments. Comments start with '#'
10087c478bd9Sstevel@tonic-gate 		 * which must be preceded by a whitespace, unless
10097c478bd9Sstevel@tonic-gate 		 * '#' is the first character in the line.
10107c478bd9Sstevel@tonic-gate 		 */
10117c478bd9Sstevel@tonic-gate 		p = line;
10127c478bd9Sstevel@tonic-gate 
1013*2bc647a2SToomas Soome 		while ((p = strchr(p, '#')) != NULL) {
10147c478bd9Sstevel@tonic-gate 			if (p == line || isspace(*(p-1))) {
10157c478bd9Sstevel@tonic-gate 				*p-- = '\0';
10167c478bd9Sstevel@tonic-gate 				goto trim;
10177c478bd9Sstevel@tonic-gate 			}
10187c478bd9Sstevel@tonic-gate 			p++;
10197c478bd9Sstevel@tonic-gate 		}
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 		break;
10227c478bd9Sstevel@tonic-gate 	}
10237c478bd9Sstevel@tonic-gate 	if (excess) {
10247c478bd9Sstevel@tonic-gate 		int c;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 		/*
10277c478bd9Sstevel@tonic-gate 		 * discard rest of line and return an empty string.
10287c478bd9Sstevel@tonic-gate 		 * done to set the stream to the correct place when
10297c478bd9Sstevel@tonic-gate 		 * we are done with this line.
10307c478bd9Sstevel@tonic-gate 		 */
10317c478bd9Sstevel@tonic-gate 		while ((c = getc(fp)) != EOF) {
10327c478bd9Sstevel@tonic-gate 			*p = c;
10337c478bd9Sstevel@tonic-gate 			if (*p == '\n')		/* end of the long line */
10347c478bd9Sstevel@tonic-gate 				break;
10357c478bd9Sstevel@tonic-gate 			else if (*p == '\\') {		/* continuation */
10367c478bd9Sstevel@tonic-gate 				if (getc(fp) == EOF)	/* ignore next char */
10377c478bd9Sstevel@tonic-gate 					break;
10387c478bd9Sstevel@tonic-gate 			}
10397c478bd9Sstevel@tonic-gate 		}
10407c478bd9Sstevel@tonic-gate 		if (nfsl_errs_to_syslog) {
10417c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, gettext(
1042*2bc647a2SToomas Soome 			    "%s: line too long - ignored (max %d chars)"),
1043*2bc647a2SToomas Soome 			    path, linesz-1);
10447c478bd9Sstevel@tonic-gate 		} else {
10457c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(
1046*2bc647a2SToomas Soome 			    "%s: line too long - ignored (max %d chars)\n"),
1047*2bc647a2SToomas Soome 			    path, linesz-1);
10487c478bd9Sstevel@tonic-gate 		}
10497c478bd9Sstevel@tonic-gate 		*line = '\0';
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	return (line);
10537c478bd9Sstevel@tonic-gate }
1054