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
5*23a1cceaSRoger A. Faulkner * Common Development and Distribution License (the "License").
6*23a1cceaSRoger 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 */
217c478bd9Sstevel@tonic-gate
22*23a1cceaSRoger A. Faulkner /*
23*23a1cceaSRoger A. Faulkner * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
24*23a1cceaSRoger A. Faulkner */
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 */
90*23a1cceaSRoger 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,
1377c478bd9Sstevel@tonic-gate 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
1447c478bd9Sstevel@tonic-gate if (error = getconfiglist(listpp, B_FALSE))
1457c478bd9Sstevel@tonic-gate nfsl_freeconfig_list(listpp);
1467c478bd9Sstevel@tonic-gate else {
1477c478bd9Sstevel@tonic-gate assert(global != NULL);
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate * The global entry was replaced with the one in the file,
1507c478bd9Sstevel@tonic-gate * clear the UPDATED flag
1517c478bd9Sstevel@tonic-gate */
1527c478bd9Sstevel@tonic-gate global->nc_flags &= ~NC_UPDATED;
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate return (error);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate * Allocates memory for the 'global_raw' structure.
1597c478bd9Sstevel@tonic-gate * The actual allocation of values for its components happens in
1607c478bd9Sstevel@tonic-gate * update_config().
1617c478bd9Sstevel@tonic-gate */
1627c478bd9Sstevel@tonic-gate static nfsl_config_t *
create_global_raw(int * error)1637c478bd9Sstevel@tonic-gate create_global_raw(int *error)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate nfsl_config_t *p;
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate *error = 0;
1687c478bd9Sstevel@tonic-gate if (p = (nfsl_config_t *)malloc(sizeof (*p)))
1697c478bd9Sstevel@tonic-gate (void) memset((void *)p, 0, sizeof (*p));
1707c478bd9Sstevel@tonic-gate else
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(
2037c478bd9Sstevel@tonic-gate "Can't stat %s - %s"), NFSL_CONFIG_FILE_PATH,
2047c478bd9Sstevel@tonic-gate strerror(error));
2057c478bd9Sstevel@tonic-gate } else {
2067c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2077c478bd9Sstevel@tonic-gate "Can't stat %s - %s\n"), NFSL_CONFIG_FILE_PATH,
2087c478bd9Sstevel@tonic-gate 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",
2497c478bd9Sstevel@tonic-gate NFSL_CONFIG_FILE_PATH);
2507c478bd9Sstevel@tonic-gate } else {
2517c478bd9Sstevel@tonic-gate (void) sprintf(errorbuf,
2527c478bd9Sstevel@tonic-gate "Can't open %s - using hardwired defaults",
2537c478bd9Sstevel@tonic-gate 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(
2737c478bd9Sstevel@tonic-gate "Can't lock %s - %s"), NFSL_CONFIG_FILE_PATH,
2747c478bd9Sstevel@tonic-gate strerror(error));
2757c478bd9Sstevel@tonic-gate } else {
2767c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
2777c478bd9Sstevel@tonic-gate "Can't lock %s - %s\n"), NFSL_CONFIG_FILE_PATH,
2787c478bd9Sstevel@tonic-gate 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
286*23a1cceaSRoger 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
2947c478bd9Sstevel@tonic-gate if (error = get_info(linebuf, &tag, &defaultdir, &bufferpath,
2957c478bd9Sstevel@tonic-gate &rpclogpath, &fhpath, &logpath, &logformat))
2967c478bd9Sstevel@tonic-gate break;
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate if (listp = findconfig(listpp, tag, B_FALSE, &tail)) {
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate * An entry with the same tag name exists,
3017c478bd9Sstevel@tonic-gate * update the fields that changed.
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate error = update_config(listp, tag, defaultdir,
3047c478bd9Sstevel@tonic-gate bufferpath, rpclogpath, fhpath, logpath,
3057c478bd9Sstevel@tonic-gate logformat, B_TRUE, B_TRUE);
3067c478bd9Sstevel@tonic-gate if (error)
3077c478bd9Sstevel@tonic-gate break;
3087c478bd9Sstevel@tonic-gate } else {
3097c478bd9Sstevel@tonic-gate /*
3107c478bd9Sstevel@tonic-gate * New entry, create it.
3117c478bd9Sstevel@tonic-gate */
3127c478bd9Sstevel@tonic-gate listp = create_config(tag, defaultdir,
3137c478bd9Sstevel@tonic-gate bufferpath, rpclogpath, fhpath,
3147c478bd9Sstevel@tonic-gate logpath, logformat, B_TRUE, &error);
3157c478bd9Sstevel@tonic-gate if (listp == NULL)
3167c478bd9Sstevel@tonic-gate break;
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate if (*listpp == NULL)
3197c478bd9Sstevel@tonic-gate *listpp = listp;
3207c478bd9Sstevel@tonic-gate else
3217c478bd9Sstevel@tonic-gate tail->nc_next = listp;
3227c478bd9Sstevel@tonic-gate tail = listp;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate assert(global != NULL);
3267c478bd9Sstevel@tonic-gate }
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate if (!error) {
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * Get mtime while we have file locked
3317c478bd9Sstevel@tonic-gate */
3327c478bd9Sstevel@tonic-gate if (error = fstat(fileno(fp), &st)) {
3337c478bd9Sstevel@tonic-gate error = errno;
3347c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) {
3357c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
3367c478bd9Sstevel@tonic-gate "Can't stat %s - %s"), NFSL_CONFIG_FILE_PATH,
3377c478bd9Sstevel@tonic-gate strerror(error));
3387c478bd9Sstevel@tonic-gate } else {
3397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
3407c478bd9Sstevel@tonic-gate "Can't stat %s - %s\n"), NFSL_CONFIG_FILE_PATH,
3417c478bd9Sstevel@tonic-gate strerror(error));
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate config_last_modification = st.st_mtim;
3457c478bd9Sstevel@tonic-gate }
3467c478bd9Sstevel@tonic-gate
3477c478bd9Sstevel@tonic-gate done:
3487c478bd9Sstevel@tonic-gate (void) fclose(fp);
3497c478bd9Sstevel@tonic-gate return (error);
3507c478bd9Sstevel@tonic-gate }
3517c478bd9Sstevel@tonic-gate
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate * Creates the config structure with the values specified by the
3547c478bd9Sstevel@tonic-gate * parameters. If defaultdir has been specified, all relative paths
3557c478bd9Sstevel@tonic-gate * are prepended with this defaultdir.
3567c478bd9Sstevel@tonic-gate * If 'complete' is set then this must represent a complete config entry
3577c478bd9Sstevel@tonic-gate * as specified by is_complete_config(), otherwise no work is perfomed, and
3587c478bd9Sstevel@tonic-gate * NULL is returned.
3597c478bd9Sstevel@tonic-gate *
3607c478bd9Sstevel@tonic-gate * Returns the newly created config structure on success.
3617c478bd9Sstevel@tonic-gate * Returns NULL on failure and sets error to the appropriate error.
3627c478bd9Sstevel@tonic-gate */
3637c478bd9Sstevel@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)3647c478bd9Sstevel@tonic-gate create_config(
3657c478bd9Sstevel@tonic-gate char *tag,
3667c478bd9Sstevel@tonic-gate char *defaultdir,
3677c478bd9Sstevel@tonic-gate char *bufferpath,
3687c478bd9Sstevel@tonic-gate char *rpclogpath,
3697c478bd9Sstevel@tonic-gate char *fhpath,
3707c478bd9Sstevel@tonic-gate char *logpath,
3717c478bd9Sstevel@tonic-gate int logformat,
3727c478bd9Sstevel@tonic-gate boolean_t complete,
3737c478bd9Sstevel@tonic-gate int *error)
3747c478bd9Sstevel@tonic-gate {
3757c478bd9Sstevel@tonic-gate nfsl_config_t *config;
3767c478bd9Sstevel@tonic-gate
3777c478bd9Sstevel@tonic-gate if ((config = (nfsl_config_t *)malloc(sizeof (*config))) == NULL) {
3787c478bd9Sstevel@tonic-gate *error = ENOMEM;
3797c478bd9Sstevel@tonic-gate return (NULL);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate (void) memset((void *)config, 0, sizeof (*config));
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate *error = update_config(config, tag, defaultdir, bufferpath, rpclogpath,
3847c478bd9Sstevel@tonic-gate fhpath, logpath, logformat, complete, B_TRUE);
3857c478bd9Sstevel@tonic-gate if (*error) {
3867c478bd9Sstevel@tonic-gate free(config);
3877c478bd9Sstevel@tonic-gate return (NULL);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate config->nc_flags &= ~NC_UPDATED; /* This is a new entry */
3917c478bd9Sstevel@tonic-gate
3927c478bd9Sstevel@tonic-gate return (config);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate
3967c478bd9Sstevel@tonic-gate /*
3977c478bd9Sstevel@tonic-gate * Updates the configuration entry with the new information provided,
3987c478bd9Sstevel@tonic-gate * sets NC_UPDATED to indicate so. The entry is left untouched if all
3997c478bd9Sstevel@tonic-gate * the fields are the same (except for 'nc_rpccookie', 'nc_transcookie'
4007c478bd9Sstevel@tonic-gate * and 'nc_next').
4017c478bd9Sstevel@tonic-gate * Prepends each path component with 'defauldir' if 'prepend' is set.
4027c478bd9Sstevel@tonic-gate *
4037c478bd9Sstevel@tonic-gate * Returns 0 on success, error otherwise.
4047c478bd9Sstevel@tonic-gate * On error, the config entry is left in an inconsistent state.
4057c478bd9Sstevel@tonic-gate * The only thing the caller can really do with it is free it.
4067c478bd9Sstevel@tonic-gate */
4077c478bd9Sstevel@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)4087c478bd9Sstevel@tonic-gate update_config(
4097c478bd9Sstevel@tonic-gate nfsl_config_t *config,
4107c478bd9Sstevel@tonic-gate char *tag,
4117c478bd9Sstevel@tonic-gate char *defaultdir,
4127c478bd9Sstevel@tonic-gate char *bufferpath,
4137c478bd9Sstevel@tonic-gate char *rpclogpath,
4147c478bd9Sstevel@tonic-gate char *fhpath,
4157c478bd9Sstevel@tonic-gate char *logpath,
4167c478bd9Sstevel@tonic-gate int logformat,
4177c478bd9Sstevel@tonic-gate boolean_t complete,
4187c478bd9Sstevel@tonic-gate boolean_t prepend)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate boolean_t updated, config_updated = B_FALSE;
4217c478bd9Sstevel@tonic-gate int error = 0;
4227c478bd9Sstevel@tonic-gate
4237c478bd9Sstevel@tonic-gate if (complete && !is_complete_config(tag, bufferpath, fhpath, logpath)) {
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate * Not a complete entry
4267c478bd9Sstevel@tonic-gate */
4277c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) {
4287c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
4297c478bd9Sstevel@tonic-gate "update_config: \"%s\" not a complete config entry."),
4307c478bd9Sstevel@tonic-gate tag);
4317c478bd9Sstevel@tonic-gate } else {
4327c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
4337c478bd9Sstevel@tonic-gate "update_config: \"%s\" not a complete config entry.\n"),
4347c478bd9Sstevel@tonic-gate tag);
4357c478bd9Sstevel@tonic-gate }
4367c478bd9Sstevel@tonic-gate return (EINVAL);
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate assert(tag != NULL);
4407c478bd9Sstevel@tonic-gate if (config->nc_name == NULL) {
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate * New entry
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate if ((config->nc_name = strdup(tag)) == NULL) {
4457c478bd9Sstevel@tonic-gate error = ENOMEM;
4467c478bd9Sstevel@tonic-gate goto errout;
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate } else
4497c478bd9Sstevel@tonic-gate assert(strcmp(config->nc_name, tag) == 0);
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate if (error = update_field(
4527c478bd9Sstevel@tonic-gate &config->nc_defaultdir, defaultdir, NULL, &updated))
4537c478bd9Sstevel@tonic-gate goto errout;
4547c478bd9Sstevel@tonic-gate if (!prepend) {
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate * Do not prepend default directory.
4577c478bd9Sstevel@tonic-gate */
4587c478bd9Sstevel@tonic-gate defaultdir = NULL;
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate config_updated |= updated;
4617c478bd9Sstevel@tonic-gate if (error = update_field(
4627c478bd9Sstevel@tonic-gate &config->nc_bufferpath, bufferpath, defaultdir, &updated))
4637c478bd9Sstevel@tonic-gate goto errout;
4647c478bd9Sstevel@tonic-gate config_updated |= updated;
4657c478bd9Sstevel@tonic-gate if (error = update_field(
4667c478bd9Sstevel@tonic-gate &config->nc_rpclogpath, rpclogpath, defaultdir, &updated))
4677c478bd9Sstevel@tonic-gate goto errout;
4687c478bd9Sstevel@tonic-gate config_updated |= updated;
4697c478bd9Sstevel@tonic-gate if (error = update_field(
4707c478bd9Sstevel@tonic-gate &config->nc_fhpath, fhpath, defaultdir, &updated))
4717c478bd9Sstevel@tonic-gate goto errout;
4727c478bd9Sstevel@tonic-gate config_updated |= updated;
4737c478bd9Sstevel@tonic-gate if (error = update_field(
4747c478bd9Sstevel@tonic-gate &config->nc_logpath, logpath, defaultdir, &updated))
4757c478bd9Sstevel@tonic-gate goto errout;
4767c478bd9Sstevel@tonic-gate config_updated |= updated;
4777c478bd9Sstevel@tonic-gate updated = (config->nc_logformat != logformat);
4787c478bd9Sstevel@tonic-gate if (updated)
4797c478bd9Sstevel@tonic-gate config->nc_logformat = logformat;
4807c478bd9Sstevel@tonic-gate config_updated |= updated;
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate if (config_updated)
4837c478bd9Sstevel@tonic-gate config->nc_flags |= NC_UPDATED;
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate if (strcmp(tag, DEFAULTTAG) == 0) {
4867c478bd9Sstevel@tonic-gate /*
4877c478bd9Sstevel@tonic-gate * Have the default global config point to this entry.
4887c478bd9Sstevel@tonic-gate */
4897c478bd9Sstevel@tonic-gate global = config;
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate /*
4927c478bd9Sstevel@tonic-gate * Update the global_raw configuration entry.
4937c478bd9Sstevel@tonic-gate * Make sure no expanding of paths occurs.
4947c478bd9Sstevel@tonic-gate */
4957c478bd9Sstevel@tonic-gate if (error = update_config(global_raw, DEFAULTRAWTAG, defaultdir,
4967c478bd9Sstevel@tonic-gate bufferpath, rpclogpath, fhpath, logpath, logformat,
4977c478bd9Sstevel@tonic-gate complete, B_FALSE))
4987c478bd9Sstevel@tonic-gate goto errout;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate return (error);
5027c478bd9Sstevel@tonic-gate
5037c478bd9Sstevel@tonic-gate errout:
5047c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) {
5057c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
5067c478bd9Sstevel@tonic-gate "update_config: Can't process \"%s\" config entry: %s"),
5077c478bd9Sstevel@tonic-gate tag, strerror(error));
5087c478bd9Sstevel@tonic-gate } else {
5097c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
5107c478bd9Sstevel@tonic-gate "update_config: Can't process \"%s\" config entry: %s\n"),
5117c478bd9Sstevel@tonic-gate tag, strerror(error));
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate return (error);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate * Prepends 'prependir' to 'new' if 'prependir' is defined.
5187c478bd9Sstevel@tonic-gate * Compares the value of '*old' with 'new', if it has changed,
5197c478bd9Sstevel@tonic-gate * then sets whatever 'old' references equal to 'new'.
5207c478bd9Sstevel@tonic-gate * Returns 0 on success, error otherwise.
5217c478bd9Sstevel@tonic-gate * Sets '*updated' to B_TRUE if field was modified.
5227c478bd9Sstevel@tonic-gate * The value of '*updated' is undefined on error.
5237c478bd9Sstevel@tonic-gate */
5247c478bd9Sstevel@tonic-gate static int
update_field(char ** old,char * new,char * prependdir,boolean_t * updated)5257c478bd9Sstevel@tonic-gate update_field(
5267c478bd9Sstevel@tonic-gate char **old, /* pointer to config field */
5277c478bd9Sstevel@tonic-gate char *new, /* updated value */
5287c478bd9Sstevel@tonic-gate char *prependdir, /* prepend this directory to new */
5297c478bd9Sstevel@tonic-gate boolean_t *updated) /* field was modified */
5307c478bd9Sstevel@tonic-gate {
5317c478bd9Sstevel@tonic-gate char *tmp_new = NULL;
5327c478bd9Sstevel@tonic-gate int need_update = 0;
5337c478bd9Sstevel@tonic-gate
5347c478bd9Sstevel@tonic-gate if (new != NULL) {
5357c478bd9Sstevel@tonic-gate if (prependdir != NULL && new[0] != '/') {
5367c478bd9Sstevel@tonic-gate tmp_new = malloc(strlen(prependdir) + strlen(new) + 2);
5377c478bd9Sstevel@tonic-gate if (tmp_new == NULL)
5387c478bd9Sstevel@tonic-gate return (ENOMEM);
5397c478bd9Sstevel@tonic-gate (void) sprintf(tmp_new, "%s/%s", prependdir, new);
5407c478bd9Sstevel@tonic-gate } else {
5417c478bd9Sstevel@tonic-gate if ((tmp_new = strdup(new)) == NULL)
5427c478bd9Sstevel@tonic-gate return (ENOMEM);
5437c478bd9Sstevel@tonic-gate }
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate
5467c478bd9Sstevel@tonic-gate if (tmp_new != NULL) {
5477c478bd9Sstevel@tonic-gate if (*old == NULL)
5487c478bd9Sstevel@tonic-gate need_update++;
5497c478bd9Sstevel@tonic-gate else if (strcmp(tmp_new, *old) != 0) {
5507c478bd9Sstevel@tonic-gate free(*old);
5517c478bd9Sstevel@tonic-gate need_update++;
5527c478bd9Sstevel@tonic-gate }
5537c478bd9Sstevel@tonic-gate if (need_update)
5547c478bd9Sstevel@tonic-gate *old = tmp_new;
5557c478bd9Sstevel@tonic-gate } else if (*old != NULL) {
5567c478bd9Sstevel@tonic-gate need_update++;
5577c478bd9Sstevel@tonic-gate free(*old);
5587c478bd9Sstevel@tonic-gate *old = NULL;
5597c478bd9Sstevel@tonic-gate }
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate *updated = need_update != 0;
5627c478bd9Sstevel@tonic-gate return (0);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate
5657c478bd9Sstevel@tonic-gate #ifdef DEBUG
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate * Removes and frees the 'config' entry from the list
5687c478bd9Sstevel@tonic-gate * pointed to by '*listpp'.
5697c478bd9Sstevel@tonic-gate * No error is reported if the entry does not exist.
5707c478bd9Sstevel@tonic-gate * Updates '*tail' to point to the last item in the list.
5717c478bd9Sstevel@tonic-gate */
5727c478bd9Sstevel@tonic-gate static void
remove_config(nfsl_config_t ** listpp,nfsl_config_t * config,nfsl_config_t ** tail)5737c478bd9Sstevel@tonic-gate remove_config(
5747c478bd9Sstevel@tonic-gate nfsl_config_t **listpp,
5757c478bd9Sstevel@tonic-gate nfsl_config_t *config,
5767c478bd9Sstevel@tonic-gate nfsl_config_t **tail)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate nfsl_config_t *p, *prev;
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate prev = *listpp;
5817c478bd9Sstevel@tonic-gate for (p = *listpp; p != NULL; p = p->nc_next) {
5827c478bd9Sstevel@tonic-gate if (p == config) {
5837c478bd9Sstevel@tonic-gate if (p == prev) {
5847c478bd9Sstevel@tonic-gate /*
5857c478bd9Sstevel@tonic-gate * first element of the list
5867c478bd9Sstevel@tonic-gate */
5877c478bd9Sstevel@tonic-gate *listpp = prev->nc_next;
5887c478bd9Sstevel@tonic-gate } else
5897c478bd9Sstevel@tonic-gate prev->nc_next = p->nc_next;
5907c478bd9Sstevel@tonic-gate free_config(p);
5917c478bd9Sstevel@tonic-gate break;
5927c478bd9Sstevel@tonic-gate }
5937c478bd9Sstevel@tonic-gate prev = p;
5947c478bd9Sstevel@tonic-gate }
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate /*
5977c478bd9Sstevel@tonic-gate * Find tail of the list.
5987c478bd9Sstevel@tonic-gate */
5997c478bd9Sstevel@tonic-gate for (*tail = prev; (*tail)->nc_next != NULL; *tail = (*tail)->nc_next)
6007c478bd9Sstevel@tonic-gate ;
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate #endif /* DEBUG */
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate static void
free_config(nfsl_config_t * config)6057c478bd9Sstevel@tonic-gate free_config(nfsl_config_t *config)
6067c478bd9Sstevel@tonic-gate {
6077c478bd9Sstevel@tonic-gate if (config == NULL)
6087c478bd9Sstevel@tonic-gate return;
6097c478bd9Sstevel@tonic-gate if (config->nc_name)
6107c478bd9Sstevel@tonic-gate free(config->nc_name);
6117c478bd9Sstevel@tonic-gate if (config->nc_defaultdir)
6127c478bd9Sstevel@tonic-gate free(config->nc_defaultdir);
6137c478bd9Sstevel@tonic-gate if (config->nc_bufferpath)
6147c478bd9Sstevel@tonic-gate free(config->nc_bufferpath);
6157c478bd9Sstevel@tonic-gate if (config->nc_rpclogpath)
6167c478bd9Sstevel@tonic-gate free(config->nc_rpclogpath);
6177c478bd9Sstevel@tonic-gate if (config->nc_fhpath)
6187c478bd9Sstevel@tonic-gate free(config->nc_fhpath);
6197c478bd9Sstevel@tonic-gate if (config->nc_logpath)
6207c478bd9Sstevel@tonic-gate free(config->nc_logpath);
6217c478bd9Sstevel@tonic-gate if (config == global)
6227c478bd9Sstevel@tonic-gate global = NULL;
6237c478bd9Sstevel@tonic-gate if (config == global_raw)
6247c478bd9Sstevel@tonic-gate global_raw = NULL;
6257c478bd9Sstevel@tonic-gate free(config);
6267c478bd9Sstevel@tonic-gate }
6277c478bd9Sstevel@tonic-gate
6287c478bd9Sstevel@tonic-gate void
nfsl_freeconfig_list(nfsl_config_t ** listpp)6297c478bd9Sstevel@tonic-gate nfsl_freeconfig_list(nfsl_config_t **listpp)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate nfsl_config_t *next;
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate if (*listpp == NULL)
6347c478bd9Sstevel@tonic-gate return;
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate do {
6377c478bd9Sstevel@tonic-gate next = (*listpp)->nc_next;
6387c478bd9Sstevel@tonic-gate free_config(*listpp);
6397c478bd9Sstevel@tonic-gate *listpp = next;
6407c478bd9Sstevel@tonic-gate } while (*listpp);
6417c478bd9Sstevel@tonic-gate
6427c478bd9Sstevel@tonic-gate free_config(global_raw);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate /*
6467c478bd9Sstevel@tonic-gate * Returns a pointer to the first instance of 'tag' in the list.
6477c478bd9Sstevel@tonic-gate * If 'remove' is true, then the entry is removed from the list and
6487c478bd9Sstevel@tonic-gate * a pointer to it is returned.
6497c478bd9Sstevel@tonic-gate * If '*tail' is not NULL, then it will point to the last element of
6507c478bd9Sstevel@tonic-gate * the list. Note that this function assumes that *tail already
6517c478bd9Sstevel@tonic-gate * points at the last element of the list.
6527c478bd9Sstevel@tonic-gate * Returns NULL if the entry does not exist.
6537c478bd9Sstevel@tonic-gate */
6547c478bd9Sstevel@tonic-gate static nfsl_config_t *
findconfig(nfsl_config_t ** listpp,char * tag,boolean_t remove,nfsl_config_t ** tail)6557c478bd9Sstevel@tonic-gate findconfig(
6567c478bd9Sstevel@tonic-gate nfsl_config_t **listpp,
6577c478bd9Sstevel@tonic-gate char *tag, boolean_t remove,
6587c478bd9Sstevel@tonic-gate nfsl_config_t **tail)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate nfsl_config_t *p, *prev;
6617c478bd9Sstevel@tonic-gate
6627c478bd9Sstevel@tonic-gate prev = *listpp;
6637c478bd9Sstevel@tonic-gate for (p = *listpp; p != NULL; p = p->nc_next) {
6647c478bd9Sstevel@tonic-gate if (strcmp(p->nc_name, tag) == 0) {
6657c478bd9Sstevel@tonic-gate if (remove) {
6667c478bd9Sstevel@tonic-gate if (p == prev) {
6677c478bd9Sstevel@tonic-gate /*
6687c478bd9Sstevel@tonic-gate * first element of the list
6697c478bd9Sstevel@tonic-gate */
6707c478bd9Sstevel@tonic-gate *listpp = prev->nc_next;
6717c478bd9Sstevel@tonic-gate } else
6727c478bd9Sstevel@tonic-gate prev->nc_next = p->nc_next;
6737c478bd9Sstevel@tonic-gate
6747c478bd9Sstevel@tonic-gate if (tail != NULL && p == *tail) {
6757c478bd9Sstevel@tonic-gate /*
6767c478bd9Sstevel@tonic-gate * Only update *tail if we removed
6777c478bd9Sstevel@tonic-gate * the last element of the list, and we
6787c478bd9Sstevel@tonic-gate * requested *tail to be updated.
6797c478bd9Sstevel@tonic-gate */
6807c478bd9Sstevel@tonic-gate *tail = prev;
6817c478bd9Sstevel@tonic-gate }
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate return (p);
6847c478bd9Sstevel@tonic-gate }
6857c478bd9Sstevel@tonic-gate prev = p;
6867c478bd9Sstevel@tonic-gate }
6877c478bd9Sstevel@tonic-gate
6887c478bd9Sstevel@tonic-gate return (NULL);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate
6917c478bd9Sstevel@tonic-gate static nfsl_config_t *
getlastconfig(nfsl_config_t * listp)6927c478bd9Sstevel@tonic-gate getlastconfig(nfsl_config_t *listp)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate nfsl_config_t *lastp = NULL;
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate for (; listp != NULL; listp = listp->nc_next)
6977c478bd9Sstevel@tonic-gate lastp = listp;
6987c478bd9Sstevel@tonic-gate
6997c478bd9Sstevel@tonic-gate return (lastp);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate * Returns a pointer to the first instance of 'tag' in the list.
7047c478bd9Sstevel@tonic-gate * Returns NULL if the entry does not exist.
7057c478bd9Sstevel@tonic-gate * Sets 'error' if the update of the list failed if necessary, and
7067c478bd9Sstevel@tonic-gate * returns NULL.
7077c478bd9Sstevel@tonic-gate */
7087c478bd9Sstevel@tonic-gate nfsl_config_t *
nfsl_findconfig(nfsl_config_t * listp,char * tag,int * error)7097c478bd9Sstevel@tonic-gate nfsl_findconfig(nfsl_config_t *listp, char *tag, int *error)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate nfsl_config_t *config;
7127c478bd9Sstevel@tonic-gate boolean_t updated;
7137c478bd9Sstevel@tonic-gate
7147c478bd9Sstevel@tonic-gate *error = 0;
7157c478bd9Sstevel@tonic-gate config = findconfig(&listp, tag, B_FALSE, (nfsl_config_t **)NULL);
7167c478bd9Sstevel@tonic-gate if (config == NULL) {
7177c478bd9Sstevel@tonic-gate /*
7187c478bd9Sstevel@tonic-gate * Rebuild our list if the file has changed.
7197c478bd9Sstevel@tonic-gate */
7207c478bd9Sstevel@tonic-gate if (*error = nfsl_checkconfig_list(&listp, &updated)) {
7217c478bd9Sstevel@tonic-gate /*
7227c478bd9Sstevel@tonic-gate * List may be corrupted, notify caller.
7237c478bd9Sstevel@tonic-gate */
7247c478bd9Sstevel@tonic-gate return (NULL);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate if (updated) {
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate * Search for tag again.
7297c478bd9Sstevel@tonic-gate */
7307c478bd9Sstevel@tonic-gate config = findconfig(&listp, tag, B_FALSE,
7317c478bd9Sstevel@tonic-gate (nfsl_config_t **)NULL);
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate }
7347c478bd9Sstevel@tonic-gate
7357c478bd9Sstevel@tonic-gate return (config);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate /*
7397c478bd9Sstevel@tonic-gate * Use the raw global values if any of the parameters is not defined.
7407c478bd9Sstevel@tonic-gate */
7417c478bd9Sstevel@tonic-gate static void
complete_with_global(char ** defaultdir,char ** bufferpath,char ** rpclogpath,char ** fhpath,char ** logpath,int * logformat)7427c478bd9Sstevel@tonic-gate complete_with_global(
7437c478bd9Sstevel@tonic-gate char **defaultdir,
7447c478bd9Sstevel@tonic-gate char **bufferpath,
7457c478bd9Sstevel@tonic-gate char **rpclogpath,
7467c478bd9Sstevel@tonic-gate char **fhpath,
7477c478bd9Sstevel@tonic-gate char **logpath,
7487c478bd9Sstevel@tonic-gate int *logformat)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate if (*defaultdir == NULL)
7517c478bd9Sstevel@tonic-gate *defaultdir = global_raw->nc_defaultdir;
7527c478bd9Sstevel@tonic-gate if (*bufferpath == NULL)
7537c478bd9Sstevel@tonic-gate *bufferpath = global_raw->nc_bufferpath;
7547c478bd9Sstevel@tonic-gate if (*rpclogpath == NULL)
7557c478bd9Sstevel@tonic-gate *rpclogpath = global_raw->nc_rpclogpath;
7567c478bd9Sstevel@tonic-gate if (*fhpath == NULL)
7577c478bd9Sstevel@tonic-gate *fhpath = global_raw->nc_fhpath;
7587c478bd9Sstevel@tonic-gate if (*logpath == NULL)
7597c478bd9Sstevel@tonic-gate *logpath = global_raw->nc_logpath;
7607c478bd9Sstevel@tonic-gate if (*logformat == 0)
7617c478bd9Sstevel@tonic-gate *logformat = global_raw->nc_logformat;
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate
7647c478bd9Sstevel@tonic-gate /*
7657c478bd9Sstevel@tonic-gate * Parses 'linebuf'. Returns 0 if a valid tag is found, otherwise non-zero.
7667c478bd9Sstevel@tonic-gate * Unknown tokens are silently ignored.
7677c478bd9Sstevel@tonic-gate * It is the responsibility of the caller to make a copy of the non-NULL
7687c478bd9Sstevel@tonic-gate * parameters if they need to be used before linebuf is freed.
7697c478bd9Sstevel@tonic-gate */
7707c478bd9Sstevel@tonic-gate static int
get_info(char * linebuf,char ** tag,char ** defaultdir,char ** bufferpath,char ** rpclogpath,char ** fhpath,char ** logpath,int * logformat)7717c478bd9Sstevel@tonic-gate get_info(
7727c478bd9Sstevel@tonic-gate char *linebuf,
7737c478bd9Sstevel@tonic-gate char **tag,
7747c478bd9Sstevel@tonic-gate char **defaultdir,
7757c478bd9Sstevel@tonic-gate char **bufferpath,
7767c478bd9Sstevel@tonic-gate char **rpclogpath,
7777c478bd9Sstevel@tonic-gate char **fhpath,
7787c478bd9Sstevel@tonic-gate char **logpath,
7797c478bd9Sstevel@tonic-gate int *logformat)
7807c478bd9Sstevel@tonic-gate {
7817c478bd9Sstevel@tonic-gate char *tok;
7827c478bd9Sstevel@tonic-gate char *tmp;
7837c478bd9Sstevel@tonic-gate
7847c478bd9Sstevel@tonic-gate /* tag */
7857c478bd9Sstevel@tonic-gate *tag = NULL;
7867c478bd9Sstevel@tonic-gate tok = strtok(linebuf, whitespace);
7877c478bd9Sstevel@tonic-gate if (tok == NULL)
7887c478bd9Sstevel@tonic-gate goto badtag;
7897c478bd9Sstevel@tonic-gate if (!is_legal_tag(tok))
7907c478bd9Sstevel@tonic-gate goto badtag;
7917c478bd9Sstevel@tonic-gate *tag = tok;
7927c478bd9Sstevel@tonic-gate
7937c478bd9Sstevel@tonic-gate *defaultdir = *bufferpath = *rpclogpath = NULL;
7947c478bd9Sstevel@tonic-gate *fhpath = *logpath = NULL;
7957c478bd9Sstevel@tonic-gate *logformat = 0;
7967c478bd9Sstevel@tonic-gate
7977c478bd9Sstevel@tonic-gate while (tok = strtok(NULL, whitespace)) {
7987c478bd9Sstevel@tonic-gate if (strncmp(tok, "defaultdir=", strlen("defaultdir=")) == 0) {
7997c478bd9Sstevel@tonic-gate *defaultdir = tok + strlen("defaultdir=");
8007c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "buffer=", strlen("buffer=")) == 0) {
8017c478bd9Sstevel@tonic-gate *bufferpath = tok + strlen("buffer=");
8027c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "rpclog=", strlen("rpclog=")) == 0) {
8037c478bd9Sstevel@tonic-gate *rpclogpath = tok + strlen("rpclog=");
8047c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "fhtable=", strlen("fhtable=")) == 0) {
8057c478bd9Sstevel@tonic-gate *fhpath = tok + strlen("fhtable=");
8067c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "log=", strlen("log=")) == 0) {
8077c478bd9Sstevel@tonic-gate *logpath = tok + strlen("log=");
8087c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "logformat=",
8097c478bd9Sstevel@tonic-gate strlen("logformat=")) == 0) {
8107c478bd9Sstevel@tonic-gate tmp = tok + strlen("logformat=");
8117c478bd9Sstevel@tonic-gate if (strncmp(tmp, "extended", strlen("extended")) == 0) {
8127c478bd9Sstevel@tonic-gate *logformat = TRANSLOG_EXTENDED;
8137c478bd9Sstevel@tonic-gate } else {
8147c478bd9Sstevel@tonic-gate /*
8157c478bd9Sstevel@tonic-gate * Use transaction log basic format if
8167c478bd9Sstevel@tonic-gate * 'extended' was not specified.
8177c478bd9Sstevel@tonic-gate */
8187c478bd9Sstevel@tonic-gate *logformat = TRANSLOG_BASIC;
8197c478bd9Sstevel@tonic-gate }
8207c478bd9Sstevel@tonic-gate }
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate if (strcmp(*tag, DEFAULTTAG) != 0) {
8247c478bd9Sstevel@tonic-gate /*
8257c478bd9Sstevel@tonic-gate * Use global values for fields not specified if
8267c478bd9Sstevel@tonic-gate * this tag is not the global tag.
8277c478bd9Sstevel@tonic-gate */
8287c478bd9Sstevel@tonic-gate complete_with_global(defaultdir, bufferpath,
8297c478bd9Sstevel@tonic-gate rpclogpath, fhpath, logpath, logformat);
8307c478bd9Sstevel@tonic-gate }
8317c478bd9Sstevel@tonic-gate
8327c478bd9Sstevel@tonic-gate return (0);
8337c478bd9Sstevel@tonic-gate
8347c478bd9Sstevel@tonic-gate badtag:
8357c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) {
8367c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
8377c478bd9Sstevel@tonic-gate "Bad tag found in config file."));
8387c478bd9Sstevel@tonic-gate } else {
8397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
8407c478bd9Sstevel@tonic-gate "Bad tag found in config file.\n"));
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate return (-1);
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate /*
8467c478bd9Sstevel@tonic-gate * Returns True if we have all the elements of a complete configuration
8477c478bd9Sstevel@tonic-gate * entry. A complete configuration has tag, bufferpath, fhpath and logpath
8487c478bd9Sstevel@tonic-gate * defined to non-zero strings.
8497c478bd9Sstevel@tonic-gate */
8507c478bd9Sstevel@tonic-gate static boolean_t
is_complete_config(char * tag,char * bufferpath,char * fhpath,char * logpath)8517c478bd9Sstevel@tonic-gate is_complete_config(
8527c478bd9Sstevel@tonic-gate char *tag,
8537c478bd9Sstevel@tonic-gate char *bufferpath,
8547c478bd9Sstevel@tonic-gate char *fhpath,
8557c478bd9Sstevel@tonic-gate char *logpath)
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate assert(tag != NULL);
8587c478bd9Sstevel@tonic-gate assert(strlen(tag) > 0);
8597c478bd9Sstevel@tonic-gate
8607c478bd9Sstevel@tonic-gate if ((bufferpath != NULL && strlen(bufferpath) > 0) &&
8617c478bd9Sstevel@tonic-gate (fhpath != NULL && strlen(fhpath) > 0) &&
8627c478bd9Sstevel@tonic-gate (logpath != NULL && strlen(logpath) > 0))
8637c478bd9Sstevel@tonic-gate return (B_TRUE);
8647c478bd9Sstevel@tonic-gate return (B_FALSE);
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate
8677c478bd9Sstevel@tonic-gate #ifdef DEBUG
8687c478bd9Sstevel@tonic-gate /*
8697c478bd9Sstevel@tonic-gate * Prints the configuration entry to stdout.
8707c478bd9Sstevel@tonic-gate */
8717c478bd9Sstevel@tonic-gate void
nfsl_printconfig(nfsl_config_t * config)8727c478bd9Sstevel@tonic-gate nfsl_printconfig(nfsl_config_t *config)
8737c478bd9Sstevel@tonic-gate {
8747c478bd9Sstevel@tonic-gate if (config->nc_name)
8757c478bd9Sstevel@tonic-gate (void) printf("tag=%s\t", config->nc_name);
8767c478bd9Sstevel@tonic-gate if (config->nc_defaultdir)
8777c478bd9Sstevel@tonic-gate (void) printf("defaultdir=%s\t", config->nc_defaultdir);
8787c478bd9Sstevel@tonic-gate if (config->nc_logpath)
8797c478bd9Sstevel@tonic-gate (void) printf("logpath=%s\t", config->nc_logpath);
8807c478bd9Sstevel@tonic-gate if (config->nc_fhpath)
8817c478bd9Sstevel@tonic-gate (void) printf("fhpath=%s\t", config->nc_fhpath);
8827c478bd9Sstevel@tonic-gate if (config->nc_bufferpath)
8837c478bd9Sstevel@tonic-gate (void) printf("bufpath=%s\t", config->nc_bufferpath);
8847c478bd9Sstevel@tonic-gate if (config->nc_rpclogpath)
8857c478bd9Sstevel@tonic-gate (void) printf("rpclogpath=%s\t", config->nc_rpclogpath);
8867c478bd9Sstevel@tonic-gate if (config->nc_logformat == TRANSLOG_BASIC)
8877c478bd9Sstevel@tonic-gate (void) printf("logformat=basic");
8887c478bd9Sstevel@tonic-gate else if (config->nc_logformat == TRANSLOG_EXTENDED)
8897c478bd9Sstevel@tonic-gate (void) printf("logformat=extended");
8907c478bd9Sstevel@tonic-gate else
8917c478bd9Sstevel@tonic-gate (void) printf("config->nc_logformat=UNKNOWN");
8927c478bd9Sstevel@tonic-gate
8937c478bd9Sstevel@tonic-gate if (config->nc_flags & NC_UPDATED)
8947c478bd9Sstevel@tonic-gate (void) printf("\tflags=NC_UPDATED");
8957c478bd9Sstevel@tonic-gate (void) printf("\n");
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate * Prints the configuration list to stdout.
9007c478bd9Sstevel@tonic-gate */
9017c478bd9Sstevel@tonic-gate void
nfsl_printconfig_list(nfsl_config_t * listp)9027c478bd9Sstevel@tonic-gate nfsl_printconfig_list(nfsl_config_t *listp)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate for (; listp != NULL; listp = listp->nc_next) {
9057c478bd9Sstevel@tonic-gate nfsl_printconfig(listp);
9067c478bd9Sstevel@tonic-gate (void) printf("\n");
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate }
9097c478bd9Sstevel@tonic-gate #endif /* DEBUG */
9107c478bd9Sstevel@tonic-gate
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate * Returns non-zero if the given string is allowable for a tag, zero if
9137c478bd9Sstevel@tonic-gate * not.
9147c478bd9Sstevel@tonic-gate */
9157c478bd9Sstevel@tonic-gate static int
is_legal_tag(char * tag)9167c478bd9Sstevel@tonic-gate is_legal_tag(char *tag)
9177c478bd9Sstevel@tonic-gate {
9187c478bd9Sstevel@tonic-gate int i;
9197c478bd9Sstevel@tonic-gate int len;
9207c478bd9Sstevel@tonic-gate
9217c478bd9Sstevel@tonic-gate if (tag == NULL)
9227c478bd9Sstevel@tonic-gate return (0);
9237c478bd9Sstevel@tonic-gate len = strlen(tag);
9247c478bd9Sstevel@tonic-gate if (len == 0)
9257c478bd9Sstevel@tonic-gate return (0);
9267c478bd9Sstevel@tonic-gate
9277c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) {
9287c478bd9Sstevel@tonic-gate char c;
9297c478bd9Sstevel@tonic-gate
9307c478bd9Sstevel@tonic-gate c = tag[i];
9317c478bd9Sstevel@tonic-gate if (!(isalnum((unsigned char)c) || c == '_'))
9327c478bd9Sstevel@tonic-gate return (0);
9337c478bd9Sstevel@tonic-gate }
9347c478bd9Sstevel@tonic-gate
9357c478bd9Sstevel@tonic-gate return (1);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate
9387c478bd9Sstevel@tonic-gate /*
939*23a1cceaSRoger A. Faulkner * gataline attempts to get a line from the configuration file,
9407c478bd9Sstevel@tonic-gate * upto LINESZ. A line in the file is a concatenation of lines if the
9417c478bd9Sstevel@tonic-gate * continuation symbol '\' is used at the end of the line. Returns
9427c478bd9Sstevel@tonic-gate * line on success, a NULL on EOF, and an empty string on lines > linesz.
9437c478bd9Sstevel@tonic-gate */
9447c478bd9Sstevel@tonic-gate static char *
gataline(FILE * fp,char * path,char * line,int linesz)945*23a1cceaSRoger A. Faulkner gataline(FILE *fp, char *path, char *line, int linesz) {
9467c478bd9Sstevel@tonic-gate register char *p = line;
9477c478bd9Sstevel@tonic-gate register int len;
9487c478bd9Sstevel@tonic-gate int excess = 0;
9497c478bd9Sstevel@tonic-gate
9507c478bd9Sstevel@tonic-gate *p = '\0';
9517c478bd9Sstevel@tonic-gate
9527c478bd9Sstevel@tonic-gate for (;;) {
9537c478bd9Sstevel@tonic-gate if (fgets(p, linesz - (p-line), fp) == NULL) {
9547c478bd9Sstevel@tonic-gate return (*line ? line : NULL); /* EOF */
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate len = strlen(line);
9587c478bd9Sstevel@tonic-gate if (len <= 0) {
9597c478bd9Sstevel@tonic-gate p = line;
9607c478bd9Sstevel@tonic-gate continue;
9617c478bd9Sstevel@tonic-gate }
9627c478bd9Sstevel@tonic-gate p = &line[len - 1];
9637c478bd9Sstevel@tonic-gate
9647c478bd9Sstevel@tonic-gate /*
9657c478bd9Sstevel@tonic-gate * Is input line too long?
9667c478bd9Sstevel@tonic-gate */
9677c478bd9Sstevel@tonic-gate if (*p != '\n') {
9687c478bd9Sstevel@tonic-gate excess = 1;
9697c478bd9Sstevel@tonic-gate /*
9707c478bd9Sstevel@tonic-gate * Perhaps last char read was '\'. Reinsert it
9717c478bd9Sstevel@tonic-gate * into the stream to ease the parsing when we
9727c478bd9Sstevel@tonic-gate * read the rest of the line to discard.
9737c478bd9Sstevel@tonic-gate */
9747c478bd9Sstevel@tonic-gate (void) ungetc(*p, fp);
9757c478bd9Sstevel@tonic-gate break;
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate trim:
9787c478bd9Sstevel@tonic-gate
9797c478bd9Sstevel@tonic-gate /* trim trailing white space */
9807c478bd9Sstevel@tonic-gate while (p >= line && isspace(*(uchar_t *)p))
9817c478bd9Sstevel@tonic-gate *p-- = '\0';
9827c478bd9Sstevel@tonic-gate if (p < line) { /* empty line */
9837c478bd9Sstevel@tonic-gate p = line;
9847c478bd9Sstevel@tonic-gate continue;
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate
9877c478bd9Sstevel@tonic-gate if (*p == '\\') { /* continuation */
9887c478bd9Sstevel@tonic-gate *p = '\0';
9897c478bd9Sstevel@tonic-gate continue;
9907c478bd9Sstevel@tonic-gate }
9917c478bd9Sstevel@tonic-gate
9927c478bd9Sstevel@tonic-gate /*
9937c478bd9Sstevel@tonic-gate * Ignore comments. Comments start with '#'
9947c478bd9Sstevel@tonic-gate * which must be preceded by a whitespace, unless
9957c478bd9Sstevel@tonic-gate * '#' is the first character in the line.
9967c478bd9Sstevel@tonic-gate */
9977c478bd9Sstevel@tonic-gate p = line;
9987c478bd9Sstevel@tonic-gate
9997c478bd9Sstevel@tonic-gate while (p = strchr(p, '#')) {
10007c478bd9Sstevel@tonic-gate if (p == line || isspace(*(p-1))) {
10017c478bd9Sstevel@tonic-gate *p-- = '\0';
10027c478bd9Sstevel@tonic-gate goto trim;
10037c478bd9Sstevel@tonic-gate }
10047c478bd9Sstevel@tonic-gate p++;
10057c478bd9Sstevel@tonic-gate }
10067c478bd9Sstevel@tonic-gate
10077c478bd9Sstevel@tonic-gate break;
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate if (excess) {
10107c478bd9Sstevel@tonic-gate int c;
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate /*
10137c478bd9Sstevel@tonic-gate * discard rest of line and return an empty string.
10147c478bd9Sstevel@tonic-gate * done to set the stream to the correct place when
10157c478bd9Sstevel@tonic-gate * we are done with this line.
10167c478bd9Sstevel@tonic-gate */
10177c478bd9Sstevel@tonic-gate while ((c = getc(fp)) != EOF) {
10187c478bd9Sstevel@tonic-gate *p = c;
10197c478bd9Sstevel@tonic-gate if (*p == '\n') /* end of the long line */
10207c478bd9Sstevel@tonic-gate break;
10217c478bd9Sstevel@tonic-gate else if (*p == '\\') { /* continuation */
10227c478bd9Sstevel@tonic-gate if (getc(fp) == EOF) /* ignore next char */
10237c478bd9Sstevel@tonic-gate break;
10247c478bd9Sstevel@tonic-gate }
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) {
10277c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext(
10287c478bd9Sstevel@tonic-gate "%s: line too long - ignored (max %d chars)"),
10297c478bd9Sstevel@tonic-gate path, linesz-1);
10307c478bd9Sstevel@tonic-gate } else {
10317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext(
10327c478bd9Sstevel@tonic-gate "%s: line too long - ignored (max %d chars)\n"),
10337c478bd9Sstevel@tonic-gate path, linesz-1);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate *line = '\0';
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate
10387c478bd9Sstevel@tonic-gate return (line);
10397c478bd9Sstevel@tonic-gate }
1040