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) 2001 by Sun Microsystems, Inc. 24*7c478bd9Sstevel@tonic-gate * All rights reserved. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * logadm/conf.c -- configuration file module 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #include <stdio.h> 32*7c478bd9Sstevel@tonic-gate #include <libintl.h> 33*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 36*7c478bd9Sstevel@tonic-gate #include <sys/mman.h> 37*7c478bd9Sstevel@tonic-gate #include <ctype.h> 38*7c478bd9Sstevel@tonic-gate #include <strings.h> 39*7c478bd9Sstevel@tonic-gate #include <unistd.h> 40*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 41*7c478bd9Sstevel@tonic-gate #include "err.h" 42*7c478bd9Sstevel@tonic-gate #include "lut.h" 43*7c478bd9Sstevel@tonic-gate #include "fn.h" 44*7c478bd9Sstevel@tonic-gate #include "opts.h" 45*7c478bd9Sstevel@tonic-gate #include "conf.h" 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* forward declarations of functions private to this module */ 48*7c478bd9Sstevel@tonic-gate static void fillconflist(int lineno, const char *entry, char **args, 49*7c478bd9Sstevel@tonic-gate struct opts *opts, const char *com, int flags); 50*7c478bd9Sstevel@tonic-gate static void fillargs(char *arg); 51*7c478bd9Sstevel@tonic-gate static char *nexttok(char **ptrptr); 52*7c478bd9Sstevel@tonic-gate static void conf_print(FILE *stream); 53*7c478bd9Sstevel@tonic-gate 54*7c478bd9Sstevel@tonic-gate static const char *Confname; /* name of the confile file */ 55*7c478bd9Sstevel@tonic-gate static char *Confbuf; /* copy of the config file (a la mmap()) */ 56*7c478bd9Sstevel@tonic-gate static int Conflen; /* length of mmap'd area */ 57*7c478bd9Sstevel@tonic-gate static int Conffd = -1; /* file descriptor for config file */ 58*7c478bd9Sstevel@tonic-gate static boolean_t Confchanged; /* true if we need to write changes back */ 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate /* 61*7c478bd9Sstevel@tonic-gate * our structured representation of the configuration file 62*7c478bd9Sstevel@tonic-gate * is made up of a list of these 63*7c478bd9Sstevel@tonic-gate */ 64*7c478bd9Sstevel@tonic-gate static struct confinfo { 65*7c478bd9Sstevel@tonic-gate struct confinfo *cf_next; 66*7c478bd9Sstevel@tonic-gate int cf_lineno; /* line number in file */ 67*7c478bd9Sstevel@tonic-gate const char *cf_entry; /* name of entry, if line has an entry */ 68*7c478bd9Sstevel@tonic-gate char **cf_args; /* raw rhs of entry */ 69*7c478bd9Sstevel@tonic-gate struct opts *cf_opts; /* parsed rhs of entry */ 70*7c478bd9Sstevel@tonic-gate const char *cf_com; /* any comment text found */ 71*7c478bd9Sstevel@tonic-gate int cf_flags; 72*7c478bd9Sstevel@tonic-gate }; 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate #define CONFF_DELETED 1 /* entry should be deleted on write back */ 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate static struct confinfo *Confinfo; /* the entries in the config file */ 77*7c478bd9Sstevel@tonic-gate static struct confinfo *Confinfolast; /* end of list */ 78*7c478bd9Sstevel@tonic-gate static struct lut *Conflut; /* lookup table keyed by entry name */ 79*7c478bd9Sstevel@tonic-gate static struct fn_list *Confentries; /* list of valid entry names */ 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* allocate & fill in another entry in our list */ 82*7c478bd9Sstevel@tonic-gate static void 83*7c478bd9Sstevel@tonic-gate fillconflist(int lineno, const char *entry, char **args, 84*7c478bd9Sstevel@tonic-gate struct opts *opts, const char *com, int flags) 85*7c478bd9Sstevel@tonic-gate { 86*7c478bd9Sstevel@tonic-gate struct confinfo *cp = MALLOC(sizeof (*cp)); 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate cp->cf_next = NULL; 89*7c478bd9Sstevel@tonic-gate cp->cf_lineno = lineno; 90*7c478bd9Sstevel@tonic-gate cp->cf_entry = entry; 91*7c478bd9Sstevel@tonic-gate cp->cf_args = args; 92*7c478bd9Sstevel@tonic-gate cp->cf_opts = opts; 93*7c478bd9Sstevel@tonic-gate cp->cf_com = com; 94*7c478bd9Sstevel@tonic-gate cp->cf_flags = flags; 95*7c478bd9Sstevel@tonic-gate if (entry) { 96*7c478bd9Sstevel@tonic-gate Conflut = lut_add(Conflut, entry, cp); 97*7c478bd9Sstevel@tonic-gate fn_list_adds(Confentries, entry); 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate if (Confinfo == NULL) 100*7c478bd9Sstevel@tonic-gate Confinfo = Confinfolast = cp; 101*7c478bd9Sstevel@tonic-gate else { 102*7c478bd9Sstevel@tonic-gate Confinfolast->cf_next = cp; 103*7c478bd9Sstevel@tonic-gate Confinfolast = cp; 104*7c478bd9Sstevel@tonic-gate } 105*7c478bd9Sstevel@tonic-gate } 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate static char **Args; /* static buffer for args */ 108*7c478bd9Sstevel@tonic-gate static int ArgsN; /* size of our static buffer */ 109*7c478bd9Sstevel@tonic-gate static int ArgsI; /* index into Cmdargs as we walk table */ 110*7c478bd9Sstevel@tonic-gate #define CONF_ARGS_INC 1024 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* callback for lut_walk to build a cmdargs vector */ 113*7c478bd9Sstevel@tonic-gate static void 114*7c478bd9Sstevel@tonic-gate fillargs(char *arg) 115*7c478bd9Sstevel@tonic-gate { 116*7c478bd9Sstevel@tonic-gate if (ArgsI >= ArgsN) { 117*7c478bd9Sstevel@tonic-gate /* need bigger table */ 118*7c478bd9Sstevel@tonic-gate Args = REALLOC(Args, sizeof (char *) * (ArgsN + CONF_ARGS_INC)); 119*7c478bd9Sstevel@tonic-gate ArgsN += CONF_ARGS_INC; 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate Args[ArgsI++] = arg; 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate /* isolate and return the next token */ 125*7c478bd9Sstevel@tonic-gate static char * 126*7c478bd9Sstevel@tonic-gate nexttok(char **ptrptr) 127*7c478bd9Sstevel@tonic-gate { 128*7c478bd9Sstevel@tonic-gate char *ptr = *ptrptr; 129*7c478bd9Sstevel@tonic-gate char *eptr; 130*7c478bd9Sstevel@tonic-gate char *quote = NULL; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate while (*ptr && isspace(*ptr)) 133*7c478bd9Sstevel@tonic-gate ptr++; 134*7c478bd9Sstevel@tonic-gate 135*7c478bd9Sstevel@tonic-gate if (*ptr == '"' || *ptr == '\'') 136*7c478bd9Sstevel@tonic-gate quote = ptr++; 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate for (eptr = ptr; *eptr; eptr++) 139*7c478bd9Sstevel@tonic-gate if (quote && *eptr == *quote) { 140*7c478bd9Sstevel@tonic-gate /* found end quote */ 141*7c478bd9Sstevel@tonic-gate *eptr++ = '\0'; 142*7c478bd9Sstevel@tonic-gate *ptrptr = eptr; 143*7c478bd9Sstevel@tonic-gate return (ptr); 144*7c478bd9Sstevel@tonic-gate } else if (!quote && isspace(*eptr)) { 145*7c478bd9Sstevel@tonic-gate /* found end of unquoted area */ 146*7c478bd9Sstevel@tonic-gate *eptr++ = '\0'; 147*7c478bd9Sstevel@tonic-gate *ptrptr = eptr; 148*7c478bd9Sstevel@tonic-gate return (ptr); 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate if (quote) 152*7c478bd9Sstevel@tonic-gate err(EF_FILE|EF_JMP, "Unbalanced %c quote", *quote); 153*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate *ptrptr = eptr; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate if (ptr == eptr) 158*7c478bd9Sstevel@tonic-gate return (NULL); 159*7c478bd9Sstevel@tonic-gate else 160*7c478bd9Sstevel@tonic-gate return (ptr); 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate /* 164*7c478bd9Sstevel@tonic-gate * conf_open -- open the configuration file, lock it if we have write perms 165*7c478bd9Sstevel@tonic-gate */ 166*7c478bd9Sstevel@tonic-gate void 167*7c478bd9Sstevel@tonic-gate conf_open(const char *fname, int needwrite) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate struct stat stbuf; 170*7c478bd9Sstevel@tonic-gate int lineno = 0; 171*7c478bd9Sstevel@tonic-gate char *line; 172*7c478bd9Sstevel@tonic-gate char *eline; 173*7c478bd9Sstevel@tonic-gate char *ebuf; 174*7c478bd9Sstevel@tonic-gate char *comment; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate Confname = fname; 177*7c478bd9Sstevel@tonic-gate Confentries = fn_list_new(NULL); 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* special case this so we don't even try locking the file */ 180*7c478bd9Sstevel@tonic-gate if (strcmp(Confname, "/dev/null") == 0) 181*7c478bd9Sstevel@tonic-gate return; 182*7c478bd9Sstevel@tonic-gate 183*7c478bd9Sstevel@tonic-gate if ((Conffd = open(Confname, (needwrite) ? O_RDWR : O_RDONLY)) < 0) 184*7c478bd9Sstevel@tonic-gate err(EF_SYS, "%s", Confname); 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate if (fstat(Conffd, &stbuf) < 0) 187*7c478bd9Sstevel@tonic-gate err(EF_SYS, "fstat on %s", Confname); 188*7c478bd9Sstevel@tonic-gate 189*7c478bd9Sstevel@tonic-gate if (needwrite && lockf(Conffd, F_LOCK, 0) < 0) 190*7c478bd9Sstevel@tonic-gate err(EF_SYS, "lockf on %s", Confname); 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate if (stbuf.st_size == 0) 193*7c478bd9Sstevel@tonic-gate return; /* empty file, don't bother parsing it */ 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate if ((Confbuf = (char *)mmap(0, stbuf.st_size, 196*7c478bd9Sstevel@tonic-gate PROT_READ | PROT_WRITE, MAP_PRIVATE, Conffd, 0)) == (char *)-1) 197*7c478bd9Sstevel@tonic-gate err(EF_SYS, "mmap on %s", Confname); 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate Conflen = stbuf.st_size; 200*7c478bd9Sstevel@tonic-gate Confchanged = B_FALSE; 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate ebuf = &Confbuf[Conflen]; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate if (Confbuf[Conflen - 1] != '\n') 205*7c478bd9Sstevel@tonic-gate err(EF_WARN|EF_FILE, "config file doesn't end with " 206*7c478bd9Sstevel@tonic-gate "newline, last line ignored."); 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate line = Confbuf; 209*7c478bd9Sstevel@tonic-gate while (line < ebuf) { 210*7c478bd9Sstevel@tonic-gate lineno++; 211*7c478bd9Sstevel@tonic-gate err_fileline(Confname, lineno); 212*7c478bd9Sstevel@tonic-gate eline = line; 213*7c478bd9Sstevel@tonic-gate comment = NULL; 214*7c478bd9Sstevel@tonic-gate for (; eline < ebuf; eline++) { 215*7c478bd9Sstevel@tonic-gate /* check for continued lines */ 216*7c478bd9Sstevel@tonic-gate if (comment == NULL && *eline == '\\' && 217*7c478bd9Sstevel@tonic-gate eline + 1 < ebuf && *(eline + 1) == '\n') { 218*7c478bd9Sstevel@tonic-gate *eline = ' '; 219*7c478bd9Sstevel@tonic-gate *(eline + 1) = ' '; 220*7c478bd9Sstevel@tonic-gate lineno++; 221*7c478bd9Sstevel@tonic-gate err_fileline(Confname, lineno); 222*7c478bd9Sstevel@tonic-gate continue; 223*7c478bd9Sstevel@tonic-gate } 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate /* check for comments */ 226*7c478bd9Sstevel@tonic-gate if (comment == NULL && *eline == '#') { 227*7c478bd9Sstevel@tonic-gate *eline = '\0'; 228*7c478bd9Sstevel@tonic-gate comment = (eline + 1); 229*7c478bd9Sstevel@tonic-gate continue; 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* check for end of line */ 233*7c478bd9Sstevel@tonic-gate if (*eline == '\n') 234*7c478bd9Sstevel@tonic-gate break; 235*7c478bd9Sstevel@tonic-gate } 236*7c478bd9Sstevel@tonic-gate if (comment >= ebuf) 237*7c478bd9Sstevel@tonic-gate comment = NULL; 238*7c478bd9Sstevel@tonic-gate if (eline < ebuf) { 239*7c478bd9Sstevel@tonic-gate char *entry; 240*7c478bd9Sstevel@tonic-gate 241*7c478bd9Sstevel@tonic-gate *eline++ = '\0'; 242*7c478bd9Sstevel@tonic-gate 243*7c478bd9Sstevel@tonic-gate /* 244*7c478bd9Sstevel@tonic-gate * now we have the entry, if any, at "line" 245*7c478bd9Sstevel@tonic-gate * and the comment, if any, at "comment" 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate /* entry is first token */ 249*7c478bd9Sstevel@tonic-gate if ((entry = nexttok(&line)) != NULL && 250*7c478bd9Sstevel@tonic-gate strcmp(entry, "logadm-version") == 0) { 251*7c478bd9Sstevel@tonic-gate /* 252*7c478bd9Sstevel@tonic-gate * we somehow opened some future format 253*7c478bd9Sstevel@tonic-gate * conffile that we likely don't understand. 254*7c478bd9Sstevel@tonic-gate * if the given version is "1" then go on, 255*7c478bd9Sstevel@tonic-gate * otherwise someone is mixing versions 256*7c478bd9Sstevel@tonic-gate * and we can't help them other than to 257*7c478bd9Sstevel@tonic-gate * print an error and exit. 258*7c478bd9Sstevel@tonic-gate */ 259*7c478bd9Sstevel@tonic-gate if ((entry = nexttok(&line)) != NULL && 260*7c478bd9Sstevel@tonic-gate strcmp(entry, "1") != 0) 261*7c478bd9Sstevel@tonic-gate err(0, "%s version not " 262*7c478bd9Sstevel@tonic-gate "supported by " 263*7c478bd9Sstevel@tonic-gate "this version of logadm.", 264*7c478bd9Sstevel@tonic-gate Confname); 265*7c478bd9Sstevel@tonic-gate } else if (entry) { 266*7c478bd9Sstevel@tonic-gate char *ap; 267*7c478bd9Sstevel@tonic-gate char **args; 268*7c478bd9Sstevel@tonic-gate int i; 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate ArgsI = 0; 271*7c478bd9Sstevel@tonic-gate while (ap = nexttok(&line)) 272*7c478bd9Sstevel@tonic-gate fillargs(ap); 273*7c478bd9Sstevel@tonic-gate if (ArgsI == 0) { 274*7c478bd9Sstevel@tonic-gate /* short entry allowed */ 275*7c478bd9Sstevel@tonic-gate fillconflist(lineno, entry, 276*7c478bd9Sstevel@tonic-gate NULL, NULL, comment, 0); 277*7c478bd9Sstevel@tonic-gate } else { 278*7c478bd9Sstevel@tonic-gate Args[ArgsI++] = NULL; 279*7c478bd9Sstevel@tonic-gate args = MALLOC(sizeof (char *) * ArgsI); 280*7c478bd9Sstevel@tonic-gate for (i = 0; i < ArgsI; i++) 281*7c478bd9Sstevel@tonic-gate args[i] = Args[i]; 282*7c478bd9Sstevel@tonic-gate fillconflist(lineno, entry, 283*7c478bd9Sstevel@tonic-gate args, NULL, comment, 0); 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate } else 286*7c478bd9Sstevel@tonic-gate fillconflist(lineno, entry, NULL, NULL, 287*7c478bd9Sstevel@tonic-gate comment, 0); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate line = eline; 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate /* 292*7c478bd9Sstevel@tonic-gate * possible future enhancement: go through and mark any entries: 293*7c478bd9Sstevel@tonic-gate * logfile -P <date> 294*7c478bd9Sstevel@tonic-gate * as DELETED if the logfile doesn't exist 295*7c478bd9Sstevel@tonic-gate */ 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * conf_close -- close the configuration file 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate void 302*7c478bd9Sstevel@tonic-gate conf_close(struct opts *opts) 303*7c478bd9Sstevel@tonic-gate { 304*7c478bd9Sstevel@tonic-gate FILE *fp; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate if (Confchanged && opts_count(opts, "n") == 0 && Conffd != -1) { 307*7c478bd9Sstevel@tonic-gate if (opts_count(opts, "v")) 308*7c478bd9Sstevel@tonic-gate (void) out("# writing changes to %s\n", Confname); 309*7c478bd9Sstevel@tonic-gate if (Debug > 1) { 310*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "conf_close, %s changed to:\n", 311*7c478bd9Sstevel@tonic-gate Confname); 312*7c478bd9Sstevel@tonic-gate conf_print(stderr); 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate if (lseek(Conffd, (off_t)0, SEEK_SET) < 0) 315*7c478bd9Sstevel@tonic-gate err(EF_SYS, "lseek on %s", Confname); 316*7c478bd9Sstevel@tonic-gate if (ftruncate(Conffd, (off_t)0) < 0) 317*7c478bd9Sstevel@tonic-gate err(EF_SYS, "ftruncate on %s", Confname); 318*7c478bd9Sstevel@tonic-gate if ((fp = fdopen(Conffd, "w")) == NULL) 319*7c478bd9Sstevel@tonic-gate err(EF_SYS, "fdopen on %s", Confname); 320*7c478bd9Sstevel@tonic-gate conf_print(fp); 321*7c478bd9Sstevel@tonic-gate if (fclose(fp) < 0) 322*7c478bd9Sstevel@tonic-gate err(EF_SYS, "fclose on %s", Confname); 323*7c478bd9Sstevel@tonic-gate Conffd = -1; 324*7c478bd9Sstevel@tonic-gate Confchanged = B_FALSE; 325*7c478bd9Sstevel@tonic-gate } else if (opts_count(opts, "v")) { 326*7c478bd9Sstevel@tonic-gate (void) out("# %s unchanged\n", Confname); 327*7c478bd9Sstevel@tonic-gate } 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate if (Conffd != -1) { 330*7c478bd9Sstevel@tonic-gate (void) close(Conffd); 331*7c478bd9Sstevel@tonic-gate Conffd = -1; 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate if (Conflut) { 334*7c478bd9Sstevel@tonic-gate lut_free(Conflut, free); 335*7c478bd9Sstevel@tonic-gate Conflut = NULL; 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate if (Confentries) { 338*7c478bd9Sstevel@tonic-gate fn_list_free(Confentries); 339*7c478bd9Sstevel@tonic-gate Confentries = NULL; 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate } 342*7c478bd9Sstevel@tonic-gate 343*7c478bd9Sstevel@tonic-gate /* 344*7c478bd9Sstevel@tonic-gate * conf_lookup -- lookup an entry in the config file 345*7c478bd9Sstevel@tonic-gate */ 346*7c478bd9Sstevel@tonic-gate char ** 347*7c478bd9Sstevel@tonic-gate conf_lookup(const char *lhs) 348*7c478bd9Sstevel@tonic-gate { 349*7c478bd9Sstevel@tonic-gate struct confinfo *cp = lut_lookup(Conflut, lhs); 350*7c478bd9Sstevel@tonic-gate 351*7c478bd9Sstevel@tonic-gate if (cp) { 352*7c478bd9Sstevel@tonic-gate err_fileline(Confname, cp->cf_lineno); 353*7c478bd9Sstevel@tonic-gate return (cp->cf_args); 354*7c478bd9Sstevel@tonic-gate } else 355*7c478bd9Sstevel@tonic-gate return (NULL); 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* 359*7c478bd9Sstevel@tonic-gate * conf_opts -- return the parsed opts for an entry 360*7c478bd9Sstevel@tonic-gate */ 361*7c478bd9Sstevel@tonic-gate struct opts * 362*7c478bd9Sstevel@tonic-gate conf_opts(const char *lhs) 363*7c478bd9Sstevel@tonic-gate { 364*7c478bd9Sstevel@tonic-gate struct confinfo *cp = lut_lookup(Conflut, lhs); 365*7c478bd9Sstevel@tonic-gate 366*7c478bd9Sstevel@tonic-gate if (cp) { 367*7c478bd9Sstevel@tonic-gate if (cp->cf_opts) 368*7c478bd9Sstevel@tonic-gate return (cp->cf_opts); /* already parsed */ 369*7c478bd9Sstevel@tonic-gate err_fileline(Confname, cp->cf_lineno); 370*7c478bd9Sstevel@tonic-gate cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF); 371*7c478bd9Sstevel@tonic-gate return (cp->cf_opts); 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate return (opts_parse(NULL, OPTF_CONF)); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate /* 377*7c478bd9Sstevel@tonic-gate * conf_replace -- replace an entry in the config file 378*7c478bd9Sstevel@tonic-gate */ 379*7c478bd9Sstevel@tonic-gate void 380*7c478bd9Sstevel@tonic-gate conf_replace(const char *lhs, struct opts *newopts) 381*7c478bd9Sstevel@tonic-gate { 382*7c478bd9Sstevel@tonic-gate struct confinfo *cp = lut_lookup(Conflut, lhs); 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate if (Conffd == -1) 385*7c478bd9Sstevel@tonic-gate return; 386*7c478bd9Sstevel@tonic-gate 387*7c478bd9Sstevel@tonic-gate if (cp) { 388*7c478bd9Sstevel@tonic-gate cp->cf_opts = newopts; 389*7c478bd9Sstevel@tonic-gate cp->cf_args = NULL; 390*7c478bd9Sstevel@tonic-gate if (newopts == NULL) 391*7c478bd9Sstevel@tonic-gate cp->cf_flags |= CONFF_DELETED; 392*7c478bd9Sstevel@tonic-gate } else 393*7c478bd9Sstevel@tonic-gate fillconflist(0, lhs, NULL, newopts, NULL, 0); 394*7c478bd9Sstevel@tonic-gate Confchanged = B_TRUE; 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate /* 398*7c478bd9Sstevel@tonic-gate * conf_set -- set options for an entry in the config file 399*7c478bd9Sstevel@tonic-gate */ 400*7c478bd9Sstevel@tonic-gate void 401*7c478bd9Sstevel@tonic-gate conf_set(const char *entry, char *o, const char *optarg) 402*7c478bd9Sstevel@tonic-gate { 403*7c478bd9Sstevel@tonic-gate struct confinfo *cp = lut_lookup(Conflut, entry); 404*7c478bd9Sstevel@tonic-gate 405*7c478bd9Sstevel@tonic-gate if (Conffd == -1) 406*7c478bd9Sstevel@tonic-gate return; 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate if (cp) { 409*7c478bd9Sstevel@tonic-gate if (cp->cf_opts == NULL) 410*7c478bd9Sstevel@tonic-gate cp->cf_opts = opts_parse(cp->cf_args, OPTF_CONF); 411*7c478bd9Sstevel@tonic-gate cp->cf_flags &= ~CONFF_DELETED; 412*7c478bd9Sstevel@tonic-gate } else { 413*7c478bd9Sstevel@tonic-gate fillconflist(0, STRDUP(entry), NULL, 414*7c478bd9Sstevel@tonic-gate opts_parse(NULL, OPTF_CONF), NULL, 0); 415*7c478bd9Sstevel@tonic-gate if ((cp = lut_lookup(Conflut, entry)) == NULL) 416*7c478bd9Sstevel@tonic-gate err(0, "conf_set internal error"); 417*7c478bd9Sstevel@tonic-gate } 418*7c478bd9Sstevel@tonic-gate (void) opts_set(cp->cf_opts, o, optarg); 419*7c478bd9Sstevel@tonic-gate Confchanged = B_TRUE; 420*7c478bd9Sstevel@tonic-gate } 421*7c478bd9Sstevel@tonic-gate 422*7c478bd9Sstevel@tonic-gate /* 423*7c478bd9Sstevel@tonic-gate * conf_entries -- list all the entry names 424*7c478bd9Sstevel@tonic-gate */ 425*7c478bd9Sstevel@tonic-gate struct fn_list * 426*7c478bd9Sstevel@tonic-gate conf_entries(void) 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate return (Confentries); 429*7c478bd9Sstevel@tonic-gate } 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate /* print the config file */ 432*7c478bd9Sstevel@tonic-gate static void 433*7c478bd9Sstevel@tonic-gate conf_print(FILE *stream) 434*7c478bd9Sstevel@tonic-gate { 435*7c478bd9Sstevel@tonic-gate struct confinfo *cp; 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate for (cp = Confinfo; cp; cp = cp->cf_next) { 438*7c478bd9Sstevel@tonic-gate if (cp->cf_flags & CONFF_DELETED) 439*7c478bd9Sstevel@tonic-gate continue; 440*7c478bd9Sstevel@tonic-gate if (cp->cf_entry) { 441*7c478bd9Sstevel@tonic-gate char **p; 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate opts_printword(cp->cf_entry, stream); 444*7c478bd9Sstevel@tonic-gate if (cp->cf_opts) { 445*7c478bd9Sstevel@tonic-gate /* existence of opts overrides args */ 446*7c478bd9Sstevel@tonic-gate opts_print(cp->cf_opts, stream, "fhnrvVw"); 447*7c478bd9Sstevel@tonic-gate } else if (cp->cf_args) { 448*7c478bd9Sstevel@tonic-gate for (p = cp->cf_args; *p; p++) { 449*7c478bd9Sstevel@tonic-gate (void) fprintf(stream, " "); 450*7c478bd9Sstevel@tonic-gate opts_printword(*p, stream); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate } 454*7c478bd9Sstevel@tonic-gate if (cp->cf_com) { 455*7c478bd9Sstevel@tonic-gate if (cp->cf_entry) 456*7c478bd9Sstevel@tonic-gate (void) fprintf(stream, " "); 457*7c478bd9Sstevel@tonic-gate (void) fprintf(stream, "#%s", cp->cf_com); 458*7c478bd9Sstevel@tonic-gate } 459*7c478bd9Sstevel@tonic-gate (void) fprintf(stream, "\n"); 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate #ifdef TESTMODULE 464*7c478bd9Sstevel@tonic-gate 465*7c478bd9Sstevel@tonic-gate /* 466*7c478bd9Sstevel@tonic-gate * test main for conf module, usage: a.out conffile 467*7c478bd9Sstevel@tonic-gate */ 468*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 469*7c478bd9Sstevel@tonic-gate { 470*7c478bd9Sstevel@tonic-gate err_init(argv[0]); 471*7c478bd9Sstevel@tonic-gate setbuf(stdout, NULL); 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate if (argc != 2) 474*7c478bd9Sstevel@tonic-gate err(EF_RAW, "usage: %s conffile\n", argv[0]); 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate conf_open(argv[1], 1); 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate printf("conffile <%s>:\n", argv[1]); 479*7c478bd9Sstevel@tonic-gate conf_print(stdout); 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate conf_close(opts_parse(NULL, 0)); 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate err_done(0); 484*7c478bd9Sstevel@tonic-gate } 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate #endif /* TESTMODULE */ 487