1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <ctype.h> 30*7c478bd9Sstevel@tonic-gate #include <errno.h> 31*7c478bd9Sstevel@tonic-gate #include <locale.h> 32*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 33*7c478bd9Sstevel@tonic-gate #include <stdio.h> 34*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 35*7c478bd9Sstevel@tonic-gate #include <strings.h> 36*7c478bd9Sstevel@tonic-gate #include <string.h> 37*7c478bd9Sstevel@tonic-gate #include <syslog.h> 38*7c478bd9Sstevel@tonic-gate #include <nfs/nfs.h> 39*7c478bd9Sstevel@tonic-gate #include <assert.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 42*7c478bd9Sstevel@tonic-gate #include <unistd.h> 43*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 44*7c478bd9Sstevel@tonic-gate #include "nfslog_config.h" 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate #define ERROR_BUFSZ 100 47*7c478bd9Sstevel@tonic-gate 48*7c478bd9Sstevel@tonic-gate /* 49*7c478bd9Sstevel@tonic-gate * This flag controls where error messages go. 50*7c478bd9Sstevel@tonic-gate * Zero means that messages go to stderr. 51*7c478bd9Sstevel@tonic-gate * Non-zero means that messages go to syslog. 52*7c478bd9Sstevel@tonic-gate */ 53*7c478bd9Sstevel@tonic-gate boolean_t nfsl_errs_to_syslog; 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate /* 56*7c478bd9Sstevel@tonic-gate * Pointer to the global entry in the list 57*7c478bd9Sstevel@tonic-gate */ 58*7c478bd9Sstevel@tonic-gate static nfsl_config_t *global = NULL; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* 61*7c478bd9Sstevel@tonic-gate * Pointer to the raw global entry in the list, this is the 62*7c478bd9Sstevel@tonic-gate * global entry without the expanded paths. This is used to 63*7c478bd9Sstevel@tonic-gate * complete configurations. 64*7c478bd9Sstevel@tonic-gate */ 65*7c478bd9Sstevel@tonic-gate static nfsl_config_t *global_raw = NULL; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * Last modification time to config file. 69*7c478bd9Sstevel@tonic-gate */ 70*7c478bd9Sstevel@tonic-gate static timestruc_t config_last_modification = { 0 }; 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate /* 73*7c478bd9Sstevel@tonic-gate * Whitespace characters to delimit fields in a line. 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate static const char *whitespace = " \t"; 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate static int getconfiglist(nfsl_config_t **, boolean_t); 78*7c478bd9Sstevel@tonic-gate static nfsl_config_t *create_config(char *, char *, char *, char *, char *, 79*7c478bd9Sstevel@tonic-gate char *, int, boolean_t, int *); 80*7c478bd9Sstevel@tonic-gate static nfsl_config_t *create_global_raw(int *); 81*7c478bd9Sstevel@tonic-gate static int update_config(nfsl_config_t *, char *, char *, char *, 82*7c478bd9Sstevel@tonic-gate char *, char *, char *, int, boolean_t, boolean_t); 83*7c478bd9Sstevel@tonic-gate static int update_field(char **, char *, char *, boolean_t *); 84*7c478bd9Sstevel@tonic-gate static nfsl_config_t *findconfig(nfsl_config_t **, char *, boolean_t, 85*7c478bd9Sstevel@tonic-gate nfsl_config_t **); 86*7c478bd9Sstevel@tonic-gate static nfsl_config_t *getlastconfig(nfsl_config_t *); 87*7c478bd9Sstevel@tonic-gate static void complete_with_global(char **, char **, char **, char **, 88*7c478bd9Sstevel@tonic-gate char **, int *); 89*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 90*7c478bd9Sstevel@tonic-gate static void remove_config(nfsl_config_t **, nfsl_config_t *, nfsl_config_t **); 91*7c478bd9Sstevel@tonic-gate void nfsl_printconfig(nfsl_config_t *); 92*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 93*7c478bd9Sstevel@tonic-gate static char *getline(FILE *, char *, char *, int); 94*7c478bd9Sstevel@tonic-gate static int get_info(char *, char **, char **, char **, char **, char **, 95*7c478bd9Sstevel@tonic-gate char **, int *); 96*7c478bd9Sstevel@tonic-gate static void free_config(nfsl_config_t *); 97*7c478bd9Sstevel@tonic-gate static int is_legal_tag(char *); 98*7c478bd9Sstevel@tonic-gate static boolean_t is_complete_config(char *, char *, char *, char *); 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* 101*7c478bd9Sstevel@tonic-gate * Read the configuration file and create a list of configuration 102*7c478bd9Sstevel@tonic-gate * parameters. Returns zero for success or an errno value. 103*7c478bd9Sstevel@tonic-gate * The caller is responsible for freeing the returned configlist by calling 104*7c478bd9Sstevel@tonic-gate * nfsl_freeconfig_list(). 105*7c478bd9Sstevel@tonic-gate * 106*7c478bd9Sstevel@tonic-gate * If the configuration file does not exist, *listpp points to a config entry 107*7c478bd9Sstevel@tonic-gate * containing the hardwired defaults. 108*7c478bd9Sstevel@tonic-gate */ 109*7c478bd9Sstevel@tonic-gate int 110*7c478bd9Sstevel@tonic-gate nfsl_getconfig_list(nfsl_config_t **listpp) 111*7c478bd9Sstevel@tonic-gate { 112*7c478bd9Sstevel@tonic-gate int error = 0; 113*7c478bd9Sstevel@tonic-gate char *locale; 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate /* 116*7c478bd9Sstevel@tonic-gate * Set the locale correctly so that we can correctly identify 117*7c478bd9Sstevel@tonic-gate * alphabetic characters. 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate if ((locale = getenv("LC_ALL")) != NULL) 120*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, locale); 121*7c478bd9Sstevel@tonic-gate else if ((locale = getenv("LC_CTYPE")) != NULL) 122*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_CTYPE, locale); 123*7c478bd9Sstevel@tonic-gate else if ((locale = getenv("LANG")) != NULL) 124*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_CTYPE, locale); 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate /* 127*7c478bd9Sstevel@tonic-gate * Allocate 'global_raw' structure, its contents are 128*7c478bd9Sstevel@tonic-gate * indirectly allocated by create_config(). 129*7c478bd9Sstevel@tonic-gate */ 130*7c478bd9Sstevel@tonic-gate assert(global_raw == NULL); 131*7c478bd9Sstevel@tonic-gate global_raw = create_global_raw(&error); 132*7c478bd9Sstevel@tonic-gate if (global_raw == NULL) 133*7c478bd9Sstevel@tonic-gate return (error); 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate /* 136*7c478bd9Sstevel@tonic-gate * Build global entry with hardwired defaults first. 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate assert(global == NULL); 139*7c478bd9Sstevel@tonic-gate global = create_config(DEFAULTTAG, DEFAULTDIR, BUFFERPATH, NULL, 140*7c478bd9Sstevel@tonic-gate FHPATH, LOGPATH, TRANSLOG_BASIC, B_TRUE, &error); 141*7c478bd9Sstevel@tonic-gate *listpp = global; 142*7c478bd9Sstevel@tonic-gate if (global == NULL) { 143*7c478bd9Sstevel@tonic-gate free_config(global_raw); 144*7c478bd9Sstevel@tonic-gate return (error); 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate if (error = getconfiglist(listpp, B_FALSE)) 148*7c478bd9Sstevel@tonic-gate nfsl_freeconfig_list(listpp); 149*7c478bd9Sstevel@tonic-gate else { 150*7c478bd9Sstevel@tonic-gate assert(global != NULL); 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * The global entry was replaced with the one in the file, 153*7c478bd9Sstevel@tonic-gate * clear the UPDATED flag 154*7c478bd9Sstevel@tonic-gate */ 155*7c478bd9Sstevel@tonic-gate global->nc_flags &= ~NC_UPDATED; 156*7c478bd9Sstevel@tonic-gate } 157*7c478bd9Sstevel@tonic-gate return (error); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate /* 161*7c478bd9Sstevel@tonic-gate * Allocates memory for the 'global_raw' structure. 162*7c478bd9Sstevel@tonic-gate * The actual allocation of values for its components happens in 163*7c478bd9Sstevel@tonic-gate * update_config(). 164*7c478bd9Sstevel@tonic-gate */ 165*7c478bd9Sstevel@tonic-gate static nfsl_config_t * 166*7c478bd9Sstevel@tonic-gate create_global_raw(int *error) 167*7c478bd9Sstevel@tonic-gate { 168*7c478bd9Sstevel@tonic-gate nfsl_config_t *p; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate *error = 0; 171*7c478bd9Sstevel@tonic-gate if (p = (nfsl_config_t *)malloc(sizeof (*p))) 172*7c478bd9Sstevel@tonic-gate (void) memset((void *)p, 0, sizeof (*p)); 173*7c478bd9Sstevel@tonic-gate else 174*7c478bd9Sstevel@tonic-gate *error = ENOMEM; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate return (p); 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* 180*7c478bd9Sstevel@tonic-gate * Checks if the the configuration file has been modified since we last 181*7c478bd9Sstevel@tonic-gate * read it, if not simply returns, otherwise it re-reads it adding new 182*7c478bd9Sstevel@tonic-gate * configuration entries. Note that existing entries that no longer 183*7c478bd9Sstevel@tonic-gate * exist in the configuration file are not removed. Existing entries 184*7c478bd9Sstevel@tonic-gate * that are modified in the configuration file are updated in the list 185*7c478bd9Sstevel@tonic-gate * as well. 186*7c478bd9Sstevel@tonic-gate * if 'updated' is defined then it is set to TRUE if the list was modified. 187*7c478bd9Sstevel@tonic-gate * 188*7c478bd9Sstevel@tonic-gate * Note that if an error occurs, the list may be corrupted. 189*7c478bd9Sstevel@tonic-gate * It is the responsibility of the caller to free the list. 190*7c478bd9Sstevel@tonic-gate * If the configuration file does not exist, we simply return the list 191*7c478bd9Sstevel@tonic-gate * that we previously had, log a message and return success. 192*7c478bd9Sstevel@tonic-gate */ 193*7c478bd9Sstevel@tonic-gate int 194*7c478bd9Sstevel@tonic-gate nfsl_checkconfig_list(nfsl_config_t **listpp, boolean_t *updated) 195*7c478bd9Sstevel@tonic-gate { 196*7c478bd9Sstevel@tonic-gate struct stat st; 197*7c478bd9Sstevel@tonic-gate int error = 0; 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate if (updated != NULL) 200*7c478bd9Sstevel@tonic-gate *updated = B_FALSE; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate if (stat(NFSL_CONFIG_FILE_PATH, &st) == -1) { 203*7c478bd9Sstevel@tonic-gate error = errno; 204*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 205*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 206*7c478bd9Sstevel@tonic-gate "Can't stat %s - %s"), NFSL_CONFIG_FILE_PATH, 207*7c478bd9Sstevel@tonic-gate strerror(error)); 208*7c478bd9Sstevel@tonic-gate } else { 209*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 210*7c478bd9Sstevel@tonic-gate "Can't stat %s - %s\n"), NFSL_CONFIG_FILE_PATH, 211*7c478bd9Sstevel@tonic-gate strerror(error)); 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate return (0); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate if (config_last_modification.tv_sec == st.st_mtim.tv_sec && 217*7c478bd9Sstevel@tonic-gate config_last_modification.tv_nsec == st.st_mtim.tv_nsec) 218*7c478bd9Sstevel@tonic-gate return (0); 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate if (updated != NULL) 221*7c478bd9Sstevel@tonic-gate *updated = B_TRUE; 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate return (getconfiglist(listpp, B_TRUE)); 224*7c478bd9Sstevel@tonic-gate } 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* 227*7c478bd9Sstevel@tonic-gate * Does the real work. Reads the configuration file and creates the 228*7c478bd9Sstevel@tonic-gate * list of entries. Assumes that *listpp contains at least one entry. 229*7c478bd9Sstevel@tonic-gate * The caller is responsible for freeing any config entries added to 230*7c478bd9Sstevel@tonic-gate * the list whether this routine returns an error or not. 231*7c478bd9Sstevel@tonic-gate * 232*7c478bd9Sstevel@tonic-gate * Returns 0 on success and updates the '*listpp' config list, 233*7c478bd9Sstevel@tonic-gate * Returns non-zero error value otherwise. 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate static int 236*7c478bd9Sstevel@tonic-gate getconfiglist(nfsl_config_t **listpp, boolean_t updating) 237*7c478bd9Sstevel@tonic-gate { 238*7c478bd9Sstevel@tonic-gate FILE *fp; 239*7c478bd9Sstevel@tonic-gate int error = 0; 240*7c478bd9Sstevel@tonic-gate nfsl_config_t *listp = NULL, *tail = NULL; 241*7c478bd9Sstevel@tonic-gate char linebuf[MAX_LINESZ]; 242*7c478bd9Sstevel@tonic-gate char errorbuf[ERROR_BUFSZ]; 243*7c478bd9Sstevel@tonic-gate char *tag, *defaultdir, *bufferpath, *rpclogpath, *fhpath, *logpath; 244*7c478bd9Sstevel@tonic-gate int logformat; 245*7c478bd9Sstevel@tonic-gate flock_t flock; 246*7c478bd9Sstevel@tonic-gate struct stat st; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate fp = fopen(NFSL_CONFIG_FILE_PATH, "r"); 249*7c478bd9Sstevel@tonic-gate if (fp == NULL) { 250*7c478bd9Sstevel@tonic-gate if (updating) { 251*7c478bd9Sstevel@tonic-gate (void) sprintf(errorbuf, "Can't open %s", 252*7c478bd9Sstevel@tonic-gate NFSL_CONFIG_FILE_PATH); 253*7c478bd9Sstevel@tonic-gate } else { 254*7c478bd9Sstevel@tonic-gate (void) sprintf(errorbuf, 255*7c478bd9Sstevel@tonic-gate "Can't open %s - using hardwired defaults", 256*7c478bd9Sstevel@tonic-gate NFSL_CONFIG_FILE_PATH); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate /* 260*7c478bd9Sstevel@tonic-gate * Use hardwired config. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) 263*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext("%s"), errorbuf); 264*7c478bd9Sstevel@tonic-gate else 265*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("%s\n"), errorbuf); 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate return (0); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate (void) memset((void *) &flock, 0, sizeof (flock)); 271*7c478bd9Sstevel@tonic-gate flock.l_type = F_RDLCK; 272*7c478bd9Sstevel@tonic-gate if (fcntl(fileno(fp), F_SETLKW, &flock) == -1) { 273*7c478bd9Sstevel@tonic-gate error = errno; 274*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 275*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 276*7c478bd9Sstevel@tonic-gate "Can't lock %s - %s"), NFSL_CONFIG_FILE_PATH, 277*7c478bd9Sstevel@tonic-gate strerror(error)); 278*7c478bd9Sstevel@tonic-gate } else { 279*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 280*7c478bd9Sstevel@tonic-gate "Can't lock %s - %s\n"), NFSL_CONFIG_FILE_PATH, 281*7c478bd9Sstevel@tonic-gate strerror(error)); 282*7c478bd9Sstevel@tonic-gate } 283*7c478bd9Sstevel@tonic-gate goto done; 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate assert (*listpp != NULL); 287*7c478bd9Sstevel@tonic-gate tail = getlastconfig(*listpp); 288*7c478bd9Sstevel@tonic-gate 289*7c478bd9Sstevel@tonic-gate while (getline(fp, NFSL_CONFIG_FILE_PATH, linebuf, sizeof (linebuf))) { 290*7c478bd9Sstevel@tonic-gate if (linebuf[0] == '\0') { 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * ignore lines that exceed max size 293*7c478bd9Sstevel@tonic-gate */ 294*7c478bd9Sstevel@tonic-gate continue; 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate if (error = get_info(linebuf, &tag, &defaultdir, &bufferpath, 298*7c478bd9Sstevel@tonic-gate &rpclogpath, &fhpath, &logpath, &logformat)) 299*7c478bd9Sstevel@tonic-gate break; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (listp = findconfig(listpp, tag, B_FALSE, &tail)) { 302*7c478bd9Sstevel@tonic-gate /* 303*7c478bd9Sstevel@tonic-gate * An entry with the same tag name exists, 304*7c478bd9Sstevel@tonic-gate * update the fields that changed. 305*7c478bd9Sstevel@tonic-gate */ 306*7c478bd9Sstevel@tonic-gate error = update_config(listp, tag, defaultdir, 307*7c478bd9Sstevel@tonic-gate bufferpath, rpclogpath, fhpath, logpath, 308*7c478bd9Sstevel@tonic-gate logformat, B_TRUE, B_TRUE); 309*7c478bd9Sstevel@tonic-gate if (error) 310*7c478bd9Sstevel@tonic-gate break; 311*7c478bd9Sstevel@tonic-gate } else { 312*7c478bd9Sstevel@tonic-gate /* 313*7c478bd9Sstevel@tonic-gate * New entry, create it. 314*7c478bd9Sstevel@tonic-gate */ 315*7c478bd9Sstevel@tonic-gate listp = create_config(tag, defaultdir, 316*7c478bd9Sstevel@tonic-gate bufferpath, rpclogpath, fhpath, 317*7c478bd9Sstevel@tonic-gate logpath, logformat, B_TRUE, &error); 318*7c478bd9Sstevel@tonic-gate if (listp == NULL) 319*7c478bd9Sstevel@tonic-gate break; 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate if (*listpp == NULL) 322*7c478bd9Sstevel@tonic-gate *listpp = listp; 323*7c478bd9Sstevel@tonic-gate else 324*7c478bd9Sstevel@tonic-gate tail->nc_next = listp; 325*7c478bd9Sstevel@tonic-gate tail = listp; 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate assert(global != NULL); 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate if (!error) { 332*7c478bd9Sstevel@tonic-gate /* 333*7c478bd9Sstevel@tonic-gate * Get mtime while we have file locked 334*7c478bd9Sstevel@tonic-gate */ 335*7c478bd9Sstevel@tonic-gate if (error = fstat(fileno(fp), &st)) { 336*7c478bd9Sstevel@tonic-gate error = errno; 337*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 338*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 339*7c478bd9Sstevel@tonic-gate "Can't stat %s - %s"), NFSL_CONFIG_FILE_PATH, 340*7c478bd9Sstevel@tonic-gate strerror(error)); 341*7c478bd9Sstevel@tonic-gate } else { 342*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 343*7c478bd9Sstevel@tonic-gate "Can't stat %s - %s\n"), NFSL_CONFIG_FILE_PATH, 344*7c478bd9Sstevel@tonic-gate strerror(error)); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate config_last_modification = st.st_mtim; 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate done: 351*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 352*7c478bd9Sstevel@tonic-gate return (error); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate /* 356*7c478bd9Sstevel@tonic-gate * Creates the config structure with the values specified by the 357*7c478bd9Sstevel@tonic-gate * parameters. If defaultdir has been specified, all relative paths 358*7c478bd9Sstevel@tonic-gate * are prepended with this defaultdir. 359*7c478bd9Sstevel@tonic-gate * If 'complete' is set then this must represent a complete config entry 360*7c478bd9Sstevel@tonic-gate * as specified by is_complete_config(), otherwise no work is perfomed, and 361*7c478bd9Sstevel@tonic-gate * NULL is returned. 362*7c478bd9Sstevel@tonic-gate * 363*7c478bd9Sstevel@tonic-gate * Returns the newly created config structure on success. 364*7c478bd9Sstevel@tonic-gate * Returns NULL on failure and sets error to the appropriate error. 365*7c478bd9Sstevel@tonic-gate */ 366*7c478bd9Sstevel@tonic-gate static nfsl_config_t * 367*7c478bd9Sstevel@tonic-gate create_config( 368*7c478bd9Sstevel@tonic-gate char *tag, 369*7c478bd9Sstevel@tonic-gate char *defaultdir, 370*7c478bd9Sstevel@tonic-gate char *bufferpath, 371*7c478bd9Sstevel@tonic-gate char *rpclogpath, 372*7c478bd9Sstevel@tonic-gate char *fhpath, 373*7c478bd9Sstevel@tonic-gate char *logpath, 374*7c478bd9Sstevel@tonic-gate int logformat, 375*7c478bd9Sstevel@tonic-gate boolean_t complete, 376*7c478bd9Sstevel@tonic-gate int *error) 377*7c478bd9Sstevel@tonic-gate { 378*7c478bd9Sstevel@tonic-gate nfsl_config_t *config; 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate if ((config = (nfsl_config_t *)malloc(sizeof (*config))) == NULL) { 381*7c478bd9Sstevel@tonic-gate *error = ENOMEM; 382*7c478bd9Sstevel@tonic-gate return (NULL); 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate (void) memset((void *)config, 0, sizeof (*config)); 385*7c478bd9Sstevel@tonic-gate 386*7c478bd9Sstevel@tonic-gate *error = update_config(config, tag, defaultdir, bufferpath, rpclogpath, 387*7c478bd9Sstevel@tonic-gate fhpath, logpath, logformat, complete, B_TRUE); 388*7c478bd9Sstevel@tonic-gate if (*error) { 389*7c478bd9Sstevel@tonic-gate free(config); 390*7c478bd9Sstevel@tonic-gate return (NULL); 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate 393*7c478bd9Sstevel@tonic-gate config->nc_flags &= ~NC_UPDATED; /* This is a new entry */ 394*7c478bd9Sstevel@tonic-gate 395*7c478bd9Sstevel@tonic-gate return (config); 396*7c478bd9Sstevel@tonic-gate } 397*7c478bd9Sstevel@tonic-gate 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate /* 400*7c478bd9Sstevel@tonic-gate * Updates the configuration entry with the new information provided, 401*7c478bd9Sstevel@tonic-gate * sets NC_UPDATED to indicate so. The entry is left untouched if all 402*7c478bd9Sstevel@tonic-gate * the fields are the same (except for 'nc_rpccookie', 'nc_transcookie' 403*7c478bd9Sstevel@tonic-gate * and 'nc_next'). 404*7c478bd9Sstevel@tonic-gate * Prepends each path component with 'defauldir' if 'prepend' is set. 405*7c478bd9Sstevel@tonic-gate * 406*7c478bd9Sstevel@tonic-gate * Returns 0 on success, error otherwise. 407*7c478bd9Sstevel@tonic-gate * On error, the config entry is left in an inconsistent state. 408*7c478bd9Sstevel@tonic-gate * The only thing the caller can really do with it is free it. 409*7c478bd9Sstevel@tonic-gate */ 410*7c478bd9Sstevel@tonic-gate static int 411*7c478bd9Sstevel@tonic-gate update_config( 412*7c478bd9Sstevel@tonic-gate nfsl_config_t *config, 413*7c478bd9Sstevel@tonic-gate char *tag, 414*7c478bd9Sstevel@tonic-gate char *defaultdir, 415*7c478bd9Sstevel@tonic-gate char *bufferpath, 416*7c478bd9Sstevel@tonic-gate char *rpclogpath, 417*7c478bd9Sstevel@tonic-gate char *fhpath, 418*7c478bd9Sstevel@tonic-gate char *logpath, 419*7c478bd9Sstevel@tonic-gate int logformat, 420*7c478bd9Sstevel@tonic-gate boolean_t complete, 421*7c478bd9Sstevel@tonic-gate boolean_t prepend) 422*7c478bd9Sstevel@tonic-gate { 423*7c478bd9Sstevel@tonic-gate boolean_t updated, config_updated = B_FALSE; 424*7c478bd9Sstevel@tonic-gate int error = 0; 425*7c478bd9Sstevel@tonic-gate 426*7c478bd9Sstevel@tonic-gate if (complete && !is_complete_config(tag, bufferpath, fhpath, logpath)) { 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate * Not a complete entry 429*7c478bd9Sstevel@tonic-gate */ 430*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 431*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 432*7c478bd9Sstevel@tonic-gate "update_config: \"%s\" not a complete config entry."), 433*7c478bd9Sstevel@tonic-gate tag); 434*7c478bd9Sstevel@tonic-gate } else { 435*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 436*7c478bd9Sstevel@tonic-gate "update_config: \"%s\" not a complete config entry.\n"), 437*7c478bd9Sstevel@tonic-gate tag); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate return (EINVAL); 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate assert(tag != NULL); 443*7c478bd9Sstevel@tonic-gate if (config->nc_name == NULL) { 444*7c478bd9Sstevel@tonic-gate /* 445*7c478bd9Sstevel@tonic-gate * New entry 446*7c478bd9Sstevel@tonic-gate */ 447*7c478bd9Sstevel@tonic-gate if ((config->nc_name = strdup(tag)) == NULL) { 448*7c478bd9Sstevel@tonic-gate error = ENOMEM; 449*7c478bd9Sstevel@tonic-gate goto errout; 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate } else 452*7c478bd9Sstevel@tonic-gate assert(strcmp(config->nc_name, tag) == 0); 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate if (error = update_field( 455*7c478bd9Sstevel@tonic-gate &config->nc_defaultdir, defaultdir, NULL, &updated)) 456*7c478bd9Sstevel@tonic-gate goto errout; 457*7c478bd9Sstevel@tonic-gate if (!prepend) { 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * Do not prepend default directory. 460*7c478bd9Sstevel@tonic-gate */ 461*7c478bd9Sstevel@tonic-gate defaultdir = NULL; 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate config_updated |= updated; 464*7c478bd9Sstevel@tonic-gate if (error = update_field( 465*7c478bd9Sstevel@tonic-gate &config->nc_bufferpath, bufferpath, defaultdir, &updated)) 466*7c478bd9Sstevel@tonic-gate goto errout; 467*7c478bd9Sstevel@tonic-gate config_updated |= updated; 468*7c478bd9Sstevel@tonic-gate if (error = update_field( 469*7c478bd9Sstevel@tonic-gate &config->nc_rpclogpath, rpclogpath, defaultdir, &updated)) 470*7c478bd9Sstevel@tonic-gate goto errout; 471*7c478bd9Sstevel@tonic-gate config_updated |= updated; 472*7c478bd9Sstevel@tonic-gate if (error = update_field( 473*7c478bd9Sstevel@tonic-gate &config->nc_fhpath, fhpath, defaultdir, &updated)) 474*7c478bd9Sstevel@tonic-gate goto errout; 475*7c478bd9Sstevel@tonic-gate config_updated |= updated; 476*7c478bd9Sstevel@tonic-gate if (error = update_field( 477*7c478bd9Sstevel@tonic-gate &config->nc_logpath, logpath, defaultdir, &updated)) 478*7c478bd9Sstevel@tonic-gate goto errout; 479*7c478bd9Sstevel@tonic-gate config_updated |= updated; 480*7c478bd9Sstevel@tonic-gate updated = (config->nc_logformat != logformat); 481*7c478bd9Sstevel@tonic-gate if (updated) 482*7c478bd9Sstevel@tonic-gate config->nc_logformat = logformat; 483*7c478bd9Sstevel@tonic-gate config_updated |= updated; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate if (config_updated) 486*7c478bd9Sstevel@tonic-gate config->nc_flags |= NC_UPDATED; 487*7c478bd9Sstevel@tonic-gate 488*7c478bd9Sstevel@tonic-gate if (strcmp(tag, DEFAULTTAG) == 0) { 489*7c478bd9Sstevel@tonic-gate /* 490*7c478bd9Sstevel@tonic-gate * Have the default global config point to this entry. 491*7c478bd9Sstevel@tonic-gate */ 492*7c478bd9Sstevel@tonic-gate global = config; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate /* 495*7c478bd9Sstevel@tonic-gate * Update the global_raw configuration entry. 496*7c478bd9Sstevel@tonic-gate * Make sure no expanding of paths occurs. 497*7c478bd9Sstevel@tonic-gate */ 498*7c478bd9Sstevel@tonic-gate if (error = update_config(global_raw, DEFAULTRAWTAG, defaultdir, 499*7c478bd9Sstevel@tonic-gate bufferpath, rpclogpath, fhpath, logpath, logformat, 500*7c478bd9Sstevel@tonic-gate complete, B_FALSE)) 501*7c478bd9Sstevel@tonic-gate goto errout; 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate return (error); 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate errout: 507*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 508*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 509*7c478bd9Sstevel@tonic-gate "update_config: Can't process \"%s\" config entry: %s"), 510*7c478bd9Sstevel@tonic-gate tag, strerror(error)); 511*7c478bd9Sstevel@tonic-gate } else { 512*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 513*7c478bd9Sstevel@tonic-gate "update_config: Can't process \"%s\" config entry: %s\n"), 514*7c478bd9Sstevel@tonic-gate tag, strerror(error)); 515*7c478bd9Sstevel@tonic-gate } 516*7c478bd9Sstevel@tonic-gate return (error); 517*7c478bd9Sstevel@tonic-gate } 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate /* 520*7c478bd9Sstevel@tonic-gate * Prepends 'prependir' to 'new' if 'prependir' is defined. 521*7c478bd9Sstevel@tonic-gate * Compares the value of '*old' with 'new', if it has changed, 522*7c478bd9Sstevel@tonic-gate * then sets whatever 'old' references equal to 'new'. 523*7c478bd9Sstevel@tonic-gate * Returns 0 on success, error otherwise. 524*7c478bd9Sstevel@tonic-gate * Sets '*updated' to B_TRUE if field was modified. 525*7c478bd9Sstevel@tonic-gate * The value of '*updated' is undefined on error. 526*7c478bd9Sstevel@tonic-gate */ 527*7c478bd9Sstevel@tonic-gate static int 528*7c478bd9Sstevel@tonic-gate update_field( 529*7c478bd9Sstevel@tonic-gate char **old, /* pointer to config field */ 530*7c478bd9Sstevel@tonic-gate char *new, /* updated value */ 531*7c478bd9Sstevel@tonic-gate char *prependdir, /* prepend this directory to new */ 532*7c478bd9Sstevel@tonic-gate boolean_t *updated) /* field was modified */ 533*7c478bd9Sstevel@tonic-gate { 534*7c478bd9Sstevel@tonic-gate char *tmp_new = NULL; 535*7c478bd9Sstevel@tonic-gate int need_update = 0; 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate if (new != NULL) { 538*7c478bd9Sstevel@tonic-gate if (prependdir != NULL && new[0] != '/') { 539*7c478bd9Sstevel@tonic-gate tmp_new = malloc(strlen(prependdir) + strlen(new) + 2); 540*7c478bd9Sstevel@tonic-gate if (tmp_new == NULL) 541*7c478bd9Sstevel@tonic-gate return (ENOMEM); 542*7c478bd9Sstevel@tonic-gate (void) sprintf(tmp_new, "%s/%s", prependdir, new); 543*7c478bd9Sstevel@tonic-gate } else { 544*7c478bd9Sstevel@tonic-gate if ((tmp_new = strdup(new)) == NULL) 545*7c478bd9Sstevel@tonic-gate return (ENOMEM); 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate if (tmp_new != NULL) { 550*7c478bd9Sstevel@tonic-gate if (*old == NULL) 551*7c478bd9Sstevel@tonic-gate need_update++; 552*7c478bd9Sstevel@tonic-gate else if (strcmp(tmp_new, *old) != 0) { 553*7c478bd9Sstevel@tonic-gate free(*old); 554*7c478bd9Sstevel@tonic-gate need_update++; 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate if (need_update) 557*7c478bd9Sstevel@tonic-gate *old = tmp_new; 558*7c478bd9Sstevel@tonic-gate } else if (*old != NULL) { 559*7c478bd9Sstevel@tonic-gate need_update++; 560*7c478bd9Sstevel@tonic-gate free(*old); 561*7c478bd9Sstevel@tonic-gate *old = NULL; 562*7c478bd9Sstevel@tonic-gate } 563*7c478bd9Sstevel@tonic-gate 564*7c478bd9Sstevel@tonic-gate *updated = need_update != 0; 565*7c478bd9Sstevel@tonic-gate return (0); 566*7c478bd9Sstevel@tonic-gate } 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 569*7c478bd9Sstevel@tonic-gate /* 570*7c478bd9Sstevel@tonic-gate * Removes and frees the 'config' entry from the list 571*7c478bd9Sstevel@tonic-gate * pointed to by '*listpp'. 572*7c478bd9Sstevel@tonic-gate * No error is reported if the entry does not exist. 573*7c478bd9Sstevel@tonic-gate * Updates '*tail' to point to the last item in the list. 574*7c478bd9Sstevel@tonic-gate */ 575*7c478bd9Sstevel@tonic-gate static void 576*7c478bd9Sstevel@tonic-gate remove_config( 577*7c478bd9Sstevel@tonic-gate nfsl_config_t **listpp, 578*7c478bd9Sstevel@tonic-gate nfsl_config_t *config, 579*7c478bd9Sstevel@tonic-gate nfsl_config_t **tail) 580*7c478bd9Sstevel@tonic-gate { 581*7c478bd9Sstevel@tonic-gate nfsl_config_t *p, *prev; 582*7c478bd9Sstevel@tonic-gate 583*7c478bd9Sstevel@tonic-gate prev = *listpp; 584*7c478bd9Sstevel@tonic-gate for (p = *listpp; p != NULL; p = p->nc_next) { 585*7c478bd9Sstevel@tonic-gate if (p == config) { 586*7c478bd9Sstevel@tonic-gate if (p == prev) { 587*7c478bd9Sstevel@tonic-gate /* 588*7c478bd9Sstevel@tonic-gate * first element of the list 589*7c478bd9Sstevel@tonic-gate */ 590*7c478bd9Sstevel@tonic-gate *listpp = prev->nc_next; 591*7c478bd9Sstevel@tonic-gate } else 592*7c478bd9Sstevel@tonic-gate prev->nc_next = p->nc_next; 593*7c478bd9Sstevel@tonic-gate free_config(p); 594*7c478bd9Sstevel@tonic-gate break; 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate prev = p; 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate /* 600*7c478bd9Sstevel@tonic-gate * Find tail of the list. 601*7c478bd9Sstevel@tonic-gate */ 602*7c478bd9Sstevel@tonic-gate for (*tail = prev; (*tail)->nc_next != NULL; *tail = (*tail)->nc_next) 603*7c478bd9Sstevel@tonic-gate ; 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 606*7c478bd9Sstevel@tonic-gate 607*7c478bd9Sstevel@tonic-gate static void 608*7c478bd9Sstevel@tonic-gate free_config(nfsl_config_t *config) 609*7c478bd9Sstevel@tonic-gate { 610*7c478bd9Sstevel@tonic-gate if (config == NULL) 611*7c478bd9Sstevel@tonic-gate return; 612*7c478bd9Sstevel@tonic-gate if (config->nc_name) 613*7c478bd9Sstevel@tonic-gate free(config->nc_name); 614*7c478bd9Sstevel@tonic-gate if (config->nc_defaultdir) 615*7c478bd9Sstevel@tonic-gate free(config->nc_defaultdir); 616*7c478bd9Sstevel@tonic-gate if (config->nc_bufferpath) 617*7c478bd9Sstevel@tonic-gate free(config->nc_bufferpath); 618*7c478bd9Sstevel@tonic-gate if (config->nc_rpclogpath) 619*7c478bd9Sstevel@tonic-gate free(config->nc_rpclogpath); 620*7c478bd9Sstevel@tonic-gate if (config->nc_fhpath) 621*7c478bd9Sstevel@tonic-gate free(config->nc_fhpath); 622*7c478bd9Sstevel@tonic-gate if (config->nc_logpath) 623*7c478bd9Sstevel@tonic-gate free(config->nc_logpath); 624*7c478bd9Sstevel@tonic-gate if (config == global) 625*7c478bd9Sstevel@tonic-gate global = NULL; 626*7c478bd9Sstevel@tonic-gate if (config == global_raw) 627*7c478bd9Sstevel@tonic-gate global_raw = NULL; 628*7c478bd9Sstevel@tonic-gate free(config); 629*7c478bd9Sstevel@tonic-gate } 630*7c478bd9Sstevel@tonic-gate 631*7c478bd9Sstevel@tonic-gate void 632*7c478bd9Sstevel@tonic-gate nfsl_freeconfig_list(nfsl_config_t **listpp) 633*7c478bd9Sstevel@tonic-gate { 634*7c478bd9Sstevel@tonic-gate nfsl_config_t *next; 635*7c478bd9Sstevel@tonic-gate 636*7c478bd9Sstevel@tonic-gate if (*listpp == NULL) 637*7c478bd9Sstevel@tonic-gate return; 638*7c478bd9Sstevel@tonic-gate 639*7c478bd9Sstevel@tonic-gate do { 640*7c478bd9Sstevel@tonic-gate next = (*listpp)->nc_next; 641*7c478bd9Sstevel@tonic-gate free_config(*listpp); 642*7c478bd9Sstevel@tonic-gate *listpp = next; 643*7c478bd9Sstevel@tonic-gate } while (*listpp); 644*7c478bd9Sstevel@tonic-gate 645*7c478bd9Sstevel@tonic-gate free_config(global_raw); 646*7c478bd9Sstevel@tonic-gate } 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate /* 649*7c478bd9Sstevel@tonic-gate * Returns a pointer to the first instance of 'tag' in the list. 650*7c478bd9Sstevel@tonic-gate * If 'remove' is true, then the entry is removed from the list and 651*7c478bd9Sstevel@tonic-gate * a pointer to it is returned. 652*7c478bd9Sstevel@tonic-gate * If '*tail' is not NULL, then it will point to the last element of 653*7c478bd9Sstevel@tonic-gate * the list. Note that this function assumes that *tail already 654*7c478bd9Sstevel@tonic-gate * points at the last element of the list. 655*7c478bd9Sstevel@tonic-gate * Returns NULL if the entry does not exist. 656*7c478bd9Sstevel@tonic-gate */ 657*7c478bd9Sstevel@tonic-gate static nfsl_config_t * 658*7c478bd9Sstevel@tonic-gate findconfig( 659*7c478bd9Sstevel@tonic-gate nfsl_config_t **listpp, 660*7c478bd9Sstevel@tonic-gate char *tag, boolean_t remove, 661*7c478bd9Sstevel@tonic-gate nfsl_config_t **tail) 662*7c478bd9Sstevel@tonic-gate { 663*7c478bd9Sstevel@tonic-gate nfsl_config_t *p, *prev; 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate prev = *listpp; 666*7c478bd9Sstevel@tonic-gate for (p = *listpp; p != NULL; p = p->nc_next) { 667*7c478bd9Sstevel@tonic-gate if (strcmp(p->nc_name, tag) == 0) { 668*7c478bd9Sstevel@tonic-gate if (remove) { 669*7c478bd9Sstevel@tonic-gate if (p == prev) { 670*7c478bd9Sstevel@tonic-gate /* 671*7c478bd9Sstevel@tonic-gate * first element of the list 672*7c478bd9Sstevel@tonic-gate */ 673*7c478bd9Sstevel@tonic-gate *listpp = prev->nc_next; 674*7c478bd9Sstevel@tonic-gate } else 675*7c478bd9Sstevel@tonic-gate prev->nc_next = p->nc_next; 676*7c478bd9Sstevel@tonic-gate 677*7c478bd9Sstevel@tonic-gate if (tail != NULL && p == *tail) { 678*7c478bd9Sstevel@tonic-gate /* 679*7c478bd9Sstevel@tonic-gate * Only update *tail if we removed 680*7c478bd9Sstevel@tonic-gate * the last element of the list, and we 681*7c478bd9Sstevel@tonic-gate * requested *tail to be updated. 682*7c478bd9Sstevel@tonic-gate */ 683*7c478bd9Sstevel@tonic-gate *tail = prev; 684*7c478bd9Sstevel@tonic-gate } 685*7c478bd9Sstevel@tonic-gate } 686*7c478bd9Sstevel@tonic-gate return (p); 687*7c478bd9Sstevel@tonic-gate } 688*7c478bd9Sstevel@tonic-gate prev = p; 689*7c478bd9Sstevel@tonic-gate } 690*7c478bd9Sstevel@tonic-gate 691*7c478bd9Sstevel@tonic-gate return (NULL); 692*7c478bd9Sstevel@tonic-gate } 693*7c478bd9Sstevel@tonic-gate 694*7c478bd9Sstevel@tonic-gate static nfsl_config_t * 695*7c478bd9Sstevel@tonic-gate getlastconfig(nfsl_config_t *listp) 696*7c478bd9Sstevel@tonic-gate { 697*7c478bd9Sstevel@tonic-gate nfsl_config_t *lastp = NULL; 698*7c478bd9Sstevel@tonic-gate 699*7c478bd9Sstevel@tonic-gate for (; listp != NULL; listp = listp->nc_next) 700*7c478bd9Sstevel@tonic-gate lastp = listp; 701*7c478bd9Sstevel@tonic-gate 702*7c478bd9Sstevel@tonic-gate return (lastp); 703*7c478bd9Sstevel@tonic-gate } 704*7c478bd9Sstevel@tonic-gate 705*7c478bd9Sstevel@tonic-gate /* 706*7c478bd9Sstevel@tonic-gate * Returns a pointer to the first instance of 'tag' in the list. 707*7c478bd9Sstevel@tonic-gate * Returns NULL if the entry does not exist. 708*7c478bd9Sstevel@tonic-gate * Sets 'error' if the update of the list failed if necessary, and 709*7c478bd9Sstevel@tonic-gate * returns NULL. 710*7c478bd9Sstevel@tonic-gate */ 711*7c478bd9Sstevel@tonic-gate nfsl_config_t * 712*7c478bd9Sstevel@tonic-gate nfsl_findconfig(nfsl_config_t *listp, char *tag, int *error) 713*7c478bd9Sstevel@tonic-gate { 714*7c478bd9Sstevel@tonic-gate nfsl_config_t *config; 715*7c478bd9Sstevel@tonic-gate boolean_t updated; 716*7c478bd9Sstevel@tonic-gate 717*7c478bd9Sstevel@tonic-gate *error = 0; 718*7c478bd9Sstevel@tonic-gate config = findconfig(&listp, tag, B_FALSE, (nfsl_config_t **)NULL); 719*7c478bd9Sstevel@tonic-gate if (config == NULL) { 720*7c478bd9Sstevel@tonic-gate /* 721*7c478bd9Sstevel@tonic-gate * Rebuild our list if the file has changed. 722*7c478bd9Sstevel@tonic-gate */ 723*7c478bd9Sstevel@tonic-gate if (*error = nfsl_checkconfig_list(&listp, &updated)) { 724*7c478bd9Sstevel@tonic-gate /* 725*7c478bd9Sstevel@tonic-gate * List may be corrupted, notify caller. 726*7c478bd9Sstevel@tonic-gate */ 727*7c478bd9Sstevel@tonic-gate return (NULL); 728*7c478bd9Sstevel@tonic-gate } 729*7c478bd9Sstevel@tonic-gate if (updated) { 730*7c478bd9Sstevel@tonic-gate /* 731*7c478bd9Sstevel@tonic-gate * Search for tag again. 732*7c478bd9Sstevel@tonic-gate */ 733*7c478bd9Sstevel@tonic-gate config = findconfig(&listp, tag, B_FALSE, 734*7c478bd9Sstevel@tonic-gate (nfsl_config_t **)NULL); 735*7c478bd9Sstevel@tonic-gate } 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate return (config); 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate /* 742*7c478bd9Sstevel@tonic-gate * Use the raw global values if any of the parameters is not defined. 743*7c478bd9Sstevel@tonic-gate */ 744*7c478bd9Sstevel@tonic-gate static void 745*7c478bd9Sstevel@tonic-gate complete_with_global( 746*7c478bd9Sstevel@tonic-gate char **defaultdir, 747*7c478bd9Sstevel@tonic-gate char **bufferpath, 748*7c478bd9Sstevel@tonic-gate char **rpclogpath, 749*7c478bd9Sstevel@tonic-gate char **fhpath, 750*7c478bd9Sstevel@tonic-gate char **logpath, 751*7c478bd9Sstevel@tonic-gate int *logformat) 752*7c478bd9Sstevel@tonic-gate { 753*7c478bd9Sstevel@tonic-gate if (*defaultdir == NULL) 754*7c478bd9Sstevel@tonic-gate *defaultdir = global_raw->nc_defaultdir; 755*7c478bd9Sstevel@tonic-gate if (*bufferpath == NULL) 756*7c478bd9Sstevel@tonic-gate *bufferpath = global_raw->nc_bufferpath; 757*7c478bd9Sstevel@tonic-gate if (*rpclogpath == NULL) 758*7c478bd9Sstevel@tonic-gate *rpclogpath = global_raw->nc_rpclogpath; 759*7c478bd9Sstevel@tonic-gate if (*fhpath == NULL) 760*7c478bd9Sstevel@tonic-gate *fhpath = global_raw->nc_fhpath; 761*7c478bd9Sstevel@tonic-gate if (*logpath == NULL) 762*7c478bd9Sstevel@tonic-gate *logpath = global_raw->nc_logpath; 763*7c478bd9Sstevel@tonic-gate if (*logformat == 0) 764*7c478bd9Sstevel@tonic-gate *logformat = global_raw->nc_logformat; 765*7c478bd9Sstevel@tonic-gate } 766*7c478bd9Sstevel@tonic-gate 767*7c478bd9Sstevel@tonic-gate /* 768*7c478bd9Sstevel@tonic-gate * Parses 'linebuf'. Returns 0 if a valid tag is found, otherwise non-zero. 769*7c478bd9Sstevel@tonic-gate * Unknown tokens are silently ignored. 770*7c478bd9Sstevel@tonic-gate * It is the responsibility of the caller to make a copy of the non-NULL 771*7c478bd9Sstevel@tonic-gate * parameters if they need to be used before linebuf is freed. 772*7c478bd9Sstevel@tonic-gate */ 773*7c478bd9Sstevel@tonic-gate static int 774*7c478bd9Sstevel@tonic-gate get_info( 775*7c478bd9Sstevel@tonic-gate char *linebuf, 776*7c478bd9Sstevel@tonic-gate char **tag, 777*7c478bd9Sstevel@tonic-gate char **defaultdir, 778*7c478bd9Sstevel@tonic-gate char **bufferpath, 779*7c478bd9Sstevel@tonic-gate char **rpclogpath, 780*7c478bd9Sstevel@tonic-gate char **fhpath, 781*7c478bd9Sstevel@tonic-gate char **logpath, 782*7c478bd9Sstevel@tonic-gate int *logformat) 783*7c478bd9Sstevel@tonic-gate { 784*7c478bd9Sstevel@tonic-gate char *tok; 785*7c478bd9Sstevel@tonic-gate char *tmp; 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate /* tag */ 788*7c478bd9Sstevel@tonic-gate *tag = NULL; 789*7c478bd9Sstevel@tonic-gate tok = strtok(linebuf, whitespace); 790*7c478bd9Sstevel@tonic-gate if (tok == NULL) 791*7c478bd9Sstevel@tonic-gate goto badtag; 792*7c478bd9Sstevel@tonic-gate if (!is_legal_tag(tok)) 793*7c478bd9Sstevel@tonic-gate goto badtag; 794*7c478bd9Sstevel@tonic-gate *tag = tok; 795*7c478bd9Sstevel@tonic-gate 796*7c478bd9Sstevel@tonic-gate *defaultdir = *bufferpath = *rpclogpath = NULL; 797*7c478bd9Sstevel@tonic-gate *fhpath = *logpath = NULL; 798*7c478bd9Sstevel@tonic-gate *logformat = 0; 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate while (tok = strtok(NULL, whitespace)) { 801*7c478bd9Sstevel@tonic-gate if (strncmp(tok, "defaultdir=", strlen("defaultdir=")) == 0) { 802*7c478bd9Sstevel@tonic-gate *defaultdir = tok + strlen("defaultdir="); 803*7c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "buffer=", strlen("buffer=")) == 0) { 804*7c478bd9Sstevel@tonic-gate *bufferpath = tok + strlen("buffer="); 805*7c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "rpclog=", strlen("rpclog=")) == 0) { 806*7c478bd9Sstevel@tonic-gate *rpclogpath = tok + strlen("rpclog="); 807*7c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "fhtable=", strlen("fhtable=")) == 0) { 808*7c478bd9Sstevel@tonic-gate *fhpath = tok + strlen("fhtable="); 809*7c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "log=", strlen("log=")) == 0) { 810*7c478bd9Sstevel@tonic-gate *logpath = tok + strlen("log="); 811*7c478bd9Sstevel@tonic-gate } else if (strncmp(tok, "logformat=", 812*7c478bd9Sstevel@tonic-gate strlen("logformat=")) == 0) { 813*7c478bd9Sstevel@tonic-gate tmp = tok + strlen("logformat="); 814*7c478bd9Sstevel@tonic-gate if (strncmp(tmp, "extended", strlen("extended")) == 0) { 815*7c478bd9Sstevel@tonic-gate *logformat = TRANSLOG_EXTENDED; 816*7c478bd9Sstevel@tonic-gate } else { 817*7c478bd9Sstevel@tonic-gate /* 818*7c478bd9Sstevel@tonic-gate * Use transaction log basic format if 819*7c478bd9Sstevel@tonic-gate * 'extended' was not specified. 820*7c478bd9Sstevel@tonic-gate */ 821*7c478bd9Sstevel@tonic-gate *logformat = TRANSLOG_BASIC; 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate } 824*7c478bd9Sstevel@tonic-gate } 825*7c478bd9Sstevel@tonic-gate 826*7c478bd9Sstevel@tonic-gate if (strcmp(*tag, DEFAULTTAG) != 0) { 827*7c478bd9Sstevel@tonic-gate /* 828*7c478bd9Sstevel@tonic-gate * Use global values for fields not specified if 829*7c478bd9Sstevel@tonic-gate * this tag is not the global tag. 830*7c478bd9Sstevel@tonic-gate */ 831*7c478bd9Sstevel@tonic-gate complete_with_global(defaultdir, bufferpath, 832*7c478bd9Sstevel@tonic-gate rpclogpath, fhpath, logpath, logformat); 833*7c478bd9Sstevel@tonic-gate } 834*7c478bd9Sstevel@tonic-gate 835*7c478bd9Sstevel@tonic-gate return (0); 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate badtag: 838*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 839*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 840*7c478bd9Sstevel@tonic-gate "Bad tag found in config file.")); 841*7c478bd9Sstevel@tonic-gate } else { 842*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 843*7c478bd9Sstevel@tonic-gate "Bad tag found in config file.\n")); 844*7c478bd9Sstevel@tonic-gate } 845*7c478bd9Sstevel@tonic-gate return (-1); 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate /* 849*7c478bd9Sstevel@tonic-gate * Returns True if we have all the elements of a complete configuration 850*7c478bd9Sstevel@tonic-gate * entry. A complete configuration has tag, bufferpath, fhpath and logpath 851*7c478bd9Sstevel@tonic-gate * defined to non-zero strings. 852*7c478bd9Sstevel@tonic-gate */ 853*7c478bd9Sstevel@tonic-gate static boolean_t 854*7c478bd9Sstevel@tonic-gate is_complete_config( 855*7c478bd9Sstevel@tonic-gate char *tag, 856*7c478bd9Sstevel@tonic-gate char *bufferpath, 857*7c478bd9Sstevel@tonic-gate char *fhpath, 858*7c478bd9Sstevel@tonic-gate char *logpath) 859*7c478bd9Sstevel@tonic-gate { 860*7c478bd9Sstevel@tonic-gate assert(tag != NULL); 861*7c478bd9Sstevel@tonic-gate assert(strlen(tag) > 0); 862*7c478bd9Sstevel@tonic-gate 863*7c478bd9Sstevel@tonic-gate if ((bufferpath != NULL && strlen(bufferpath) > 0) && 864*7c478bd9Sstevel@tonic-gate (fhpath != NULL && strlen(fhpath) > 0) && 865*7c478bd9Sstevel@tonic-gate (logpath != NULL && strlen(logpath) > 0)) 866*7c478bd9Sstevel@tonic-gate return (B_TRUE); 867*7c478bd9Sstevel@tonic-gate return (B_FALSE); 868*7c478bd9Sstevel@tonic-gate } 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 871*7c478bd9Sstevel@tonic-gate /* 872*7c478bd9Sstevel@tonic-gate * Prints the configuration entry to stdout. 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate void 875*7c478bd9Sstevel@tonic-gate nfsl_printconfig(nfsl_config_t *config) 876*7c478bd9Sstevel@tonic-gate { 877*7c478bd9Sstevel@tonic-gate if (config->nc_name) 878*7c478bd9Sstevel@tonic-gate (void) printf("tag=%s\t", config->nc_name); 879*7c478bd9Sstevel@tonic-gate if (config->nc_defaultdir) 880*7c478bd9Sstevel@tonic-gate (void) printf("defaultdir=%s\t", config->nc_defaultdir); 881*7c478bd9Sstevel@tonic-gate if (config->nc_logpath) 882*7c478bd9Sstevel@tonic-gate (void) printf("logpath=%s\t", config->nc_logpath); 883*7c478bd9Sstevel@tonic-gate if (config->nc_fhpath) 884*7c478bd9Sstevel@tonic-gate (void) printf("fhpath=%s\t", config->nc_fhpath); 885*7c478bd9Sstevel@tonic-gate if (config->nc_bufferpath) 886*7c478bd9Sstevel@tonic-gate (void) printf("bufpath=%s\t", config->nc_bufferpath); 887*7c478bd9Sstevel@tonic-gate if (config->nc_rpclogpath) 888*7c478bd9Sstevel@tonic-gate (void) printf("rpclogpath=%s\t", config->nc_rpclogpath); 889*7c478bd9Sstevel@tonic-gate if (config->nc_logformat == TRANSLOG_BASIC) 890*7c478bd9Sstevel@tonic-gate (void) printf("logformat=basic"); 891*7c478bd9Sstevel@tonic-gate else if (config->nc_logformat == TRANSLOG_EXTENDED) 892*7c478bd9Sstevel@tonic-gate (void) printf("logformat=extended"); 893*7c478bd9Sstevel@tonic-gate else 894*7c478bd9Sstevel@tonic-gate (void) printf("config->nc_logformat=UNKNOWN"); 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (config->nc_flags & NC_UPDATED) 897*7c478bd9Sstevel@tonic-gate (void) printf("\tflags=NC_UPDATED"); 898*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate 901*7c478bd9Sstevel@tonic-gate /* 902*7c478bd9Sstevel@tonic-gate * Prints the configuration list to stdout. 903*7c478bd9Sstevel@tonic-gate */ 904*7c478bd9Sstevel@tonic-gate void 905*7c478bd9Sstevel@tonic-gate nfsl_printconfig_list(nfsl_config_t *listp) 906*7c478bd9Sstevel@tonic-gate { 907*7c478bd9Sstevel@tonic-gate for (; listp != NULL; listp = listp->nc_next) { 908*7c478bd9Sstevel@tonic-gate nfsl_printconfig(listp); 909*7c478bd9Sstevel@tonic-gate (void) printf("\n"); 910*7c478bd9Sstevel@tonic-gate } 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* 915*7c478bd9Sstevel@tonic-gate * Returns non-zero if the given string is allowable for a tag, zero if 916*7c478bd9Sstevel@tonic-gate * not. 917*7c478bd9Sstevel@tonic-gate */ 918*7c478bd9Sstevel@tonic-gate static int 919*7c478bd9Sstevel@tonic-gate is_legal_tag(char *tag) 920*7c478bd9Sstevel@tonic-gate { 921*7c478bd9Sstevel@tonic-gate int i; 922*7c478bd9Sstevel@tonic-gate int len; 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate if (tag == NULL) 925*7c478bd9Sstevel@tonic-gate return (0); 926*7c478bd9Sstevel@tonic-gate len = strlen(tag); 927*7c478bd9Sstevel@tonic-gate if (len == 0) 928*7c478bd9Sstevel@tonic-gate return (0); 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 931*7c478bd9Sstevel@tonic-gate char c; 932*7c478bd9Sstevel@tonic-gate 933*7c478bd9Sstevel@tonic-gate c = tag[i]; 934*7c478bd9Sstevel@tonic-gate if (!(isalnum((unsigned char)c) || c == '_')) 935*7c478bd9Sstevel@tonic-gate return (0); 936*7c478bd9Sstevel@tonic-gate } 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate return (1); 939*7c478bd9Sstevel@tonic-gate } 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate /* 942*7c478bd9Sstevel@tonic-gate * getline attempts to get a line from the configuration file, 943*7c478bd9Sstevel@tonic-gate * upto LINESZ. A line in the file is a concatenation of lines if the 944*7c478bd9Sstevel@tonic-gate * continuation symbol '\' is used at the end of the line. Returns 945*7c478bd9Sstevel@tonic-gate * line on success, a NULL on EOF, and an empty string on lines > linesz. 946*7c478bd9Sstevel@tonic-gate */ 947*7c478bd9Sstevel@tonic-gate static char * 948*7c478bd9Sstevel@tonic-gate getline(FILE *fp, char *path, char *line, int linesz) { 949*7c478bd9Sstevel@tonic-gate register char *p = line; 950*7c478bd9Sstevel@tonic-gate register int len; 951*7c478bd9Sstevel@tonic-gate int excess = 0; 952*7c478bd9Sstevel@tonic-gate 953*7c478bd9Sstevel@tonic-gate *p = '\0'; 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate for (;;) { 956*7c478bd9Sstevel@tonic-gate if (fgets(p, linesz - (p-line), fp) == NULL) { 957*7c478bd9Sstevel@tonic-gate return (*line ? line : NULL); /* EOF */ 958*7c478bd9Sstevel@tonic-gate } 959*7c478bd9Sstevel@tonic-gate 960*7c478bd9Sstevel@tonic-gate len = strlen(line); 961*7c478bd9Sstevel@tonic-gate if (len <= 0) { 962*7c478bd9Sstevel@tonic-gate p = line; 963*7c478bd9Sstevel@tonic-gate continue; 964*7c478bd9Sstevel@tonic-gate } 965*7c478bd9Sstevel@tonic-gate p = &line[len - 1]; 966*7c478bd9Sstevel@tonic-gate 967*7c478bd9Sstevel@tonic-gate /* 968*7c478bd9Sstevel@tonic-gate * Is input line too long? 969*7c478bd9Sstevel@tonic-gate */ 970*7c478bd9Sstevel@tonic-gate if (*p != '\n') { 971*7c478bd9Sstevel@tonic-gate excess = 1; 972*7c478bd9Sstevel@tonic-gate /* 973*7c478bd9Sstevel@tonic-gate * Perhaps last char read was '\'. Reinsert it 974*7c478bd9Sstevel@tonic-gate * into the stream to ease the parsing when we 975*7c478bd9Sstevel@tonic-gate * read the rest of the line to discard. 976*7c478bd9Sstevel@tonic-gate */ 977*7c478bd9Sstevel@tonic-gate (void) ungetc(*p, fp); 978*7c478bd9Sstevel@tonic-gate break; 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate trim: 981*7c478bd9Sstevel@tonic-gate 982*7c478bd9Sstevel@tonic-gate /* trim trailing white space */ 983*7c478bd9Sstevel@tonic-gate while (p >= line && isspace(*(uchar_t *)p)) 984*7c478bd9Sstevel@tonic-gate *p-- = '\0'; 985*7c478bd9Sstevel@tonic-gate if (p < line) { /* empty line */ 986*7c478bd9Sstevel@tonic-gate p = line; 987*7c478bd9Sstevel@tonic-gate continue; 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate if (*p == '\\') { /* continuation */ 991*7c478bd9Sstevel@tonic-gate *p = '\0'; 992*7c478bd9Sstevel@tonic-gate continue; 993*7c478bd9Sstevel@tonic-gate } 994*7c478bd9Sstevel@tonic-gate 995*7c478bd9Sstevel@tonic-gate /* 996*7c478bd9Sstevel@tonic-gate * Ignore comments. Comments start with '#' 997*7c478bd9Sstevel@tonic-gate * which must be preceded by a whitespace, unless 998*7c478bd9Sstevel@tonic-gate * '#' is the first character in the line. 999*7c478bd9Sstevel@tonic-gate */ 1000*7c478bd9Sstevel@tonic-gate p = line; 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate while (p = strchr(p, '#')) { 1003*7c478bd9Sstevel@tonic-gate if (p == line || isspace(*(p-1))) { 1004*7c478bd9Sstevel@tonic-gate *p-- = '\0'; 1005*7c478bd9Sstevel@tonic-gate goto trim; 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate p++; 1008*7c478bd9Sstevel@tonic-gate } 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate break; 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate if (excess) { 1013*7c478bd9Sstevel@tonic-gate int c; 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate * discard rest of line and return an empty string. 1017*7c478bd9Sstevel@tonic-gate * done to set the stream to the correct place when 1018*7c478bd9Sstevel@tonic-gate * we are done with this line. 1019*7c478bd9Sstevel@tonic-gate */ 1020*7c478bd9Sstevel@tonic-gate while ((c = getc(fp)) != EOF) { 1021*7c478bd9Sstevel@tonic-gate *p = c; 1022*7c478bd9Sstevel@tonic-gate if (*p == '\n') /* end of the long line */ 1023*7c478bd9Sstevel@tonic-gate break; 1024*7c478bd9Sstevel@tonic-gate else if (*p == '\\') { /* continuation */ 1025*7c478bd9Sstevel@tonic-gate if (getc(fp) == EOF) /* ignore next char */ 1026*7c478bd9Sstevel@tonic-gate break; 1027*7c478bd9Sstevel@tonic-gate } 1028*7c478bd9Sstevel@tonic-gate } 1029*7c478bd9Sstevel@tonic-gate if (nfsl_errs_to_syslog) { 1030*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, gettext( 1031*7c478bd9Sstevel@tonic-gate "%s: line too long - ignored (max %d chars)"), 1032*7c478bd9Sstevel@tonic-gate path, linesz-1); 1033*7c478bd9Sstevel@tonic-gate } else { 1034*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext( 1035*7c478bd9Sstevel@tonic-gate "%s: line too long - ignored (max %d chars)\n"), 1036*7c478bd9Sstevel@tonic-gate path, linesz-1); 1037*7c478bd9Sstevel@tonic-gate } 1038*7c478bd9Sstevel@tonic-gate *line = '\0'; 1039*7c478bd9Sstevel@tonic-gate } 1040*7c478bd9Sstevel@tonic-gate 1041*7c478bd9Sstevel@tonic-gate return (line); 1042*7c478bd9Sstevel@tonic-gate } 1043