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