1*55572Sbostic /* 2*55572Sbostic * Copyright (c) 1992 Regents of the University of California. 3*55572Sbostic * Copyright (c) 1988, 1992 The University of Utah and the Center 4*55572Sbostic * for Software Science (CSS). 5*55572Sbostic * All rights reserved. 6*55572Sbostic * 7*55572Sbostic * This code is derived from software contributed to Berkeley by 8*55572Sbostic * the Center for Software Science of the University of Utah Computer 9*55572Sbostic * Science Department. CSS requests users of this software to return 10*55572Sbostic * to css-dist@cs.utah.edu any improvements that they make and grant 11*55572Sbostic * CSS redistribution rights. 12*55572Sbostic * 13*55572Sbostic * %sccs.include.redist.c% 14*55572Sbostic * 15*55572Sbostic * @(#)parseconf.c 5.1 (Berkeley) 07/23/92 16*55572Sbostic * 17*55572Sbostic * Utah $Hdr: parseconf.c 3.1 92/07/06$ 18*55572Sbostic * Author: Jeff Forys, University of Utah CSS 19*55572Sbostic */ 20*55572Sbostic 21*55572Sbostic #ifndef lint 22*55572Sbostic static char sccsid[] = "@(#)parseconf.c 5.1 (Berkeley) 07/23/92"; 23*55572Sbostic #endif /* not lint */ 24*55572Sbostic 25*55572Sbostic #include "defs.h" 26*55572Sbostic 27*55572Sbostic #include <sys/stat.h> 28*55572Sbostic #include <sys/dir.h> 29*55572Sbostic #include <sys/file.h> 30*55572Sbostic 31*55572Sbostic #include <syslog.h> 32*55572Sbostic #include <strings.h> 33*55572Sbostic #include <ctype.h> 34*55572Sbostic 35*55572Sbostic /* 36*55572Sbostic ** ParseConfig -- parse the config file into linked list of clients. 37*55572Sbostic ** 38*55572Sbostic ** Parameters: 39*55572Sbostic ** None. 40*55572Sbostic ** 41*55572Sbostic ** Returns: 42*55572Sbostic ** 1 on success, 0 otherwise. 43*55572Sbostic ** 44*55572Sbostic ** Side Effects: 45*55572Sbostic ** - Linked list of clients will be (re)allocated. 46*55572Sbostic ** 47*55572Sbostic ** Warnings: 48*55572Sbostic ** - GetBootFiles() must be called before this routine 49*55572Sbostic ** to create a linked list of default boot files. 50*55572Sbostic */ 51*55572Sbostic 52*55572Sbostic int 53*55572Sbostic ParseConfig() 54*55572Sbostic { 55*55572Sbostic FILE *fp; 56*55572Sbostic CLIENT *client, *NewClient(); 57*55572Sbostic u_char *addr, *ParseAddr(); 58*55572Sbostic char *NewStr(), line[C_LINELEN]; 59*55572Sbostic register char *cp, *bcp; 60*55572Sbostic register int i, j; 61*55572Sbostic int omask, linecnt = 0; 62*55572Sbostic 63*55572Sbostic if (BootAny) /* ignore config file */ 64*55572Sbostic return(1); 65*55572Sbostic 66*55572Sbostic FreeClients(); /* delete old list of clients */ 67*55572Sbostic 68*55572Sbostic if ((fp = fopen(ConfigFile, "r")) == NULL) { 69*55572Sbostic syslog(LOG_ERR, "ParseConfig: can't open config file (%s)", 70*55572Sbostic ConfigFile); 71*55572Sbostic return(0); 72*55572Sbostic } 73*55572Sbostic 74*55572Sbostic /* 75*55572Sbostic * We've got to block SIGHUP to prevent reconfiguration while 76*55572Sbostic * dealing with the linked list of Clients. This can be done 77*55572Sbostic * when actually linking the new client into the list, but 78*55572Sbostic * this could have unexpected results if the server was HUP'd 79*55572Sbostic * whilst reconfiguring. Hence, it is done here. 80*55572Sbostic */ 81*55572Sbostic omask = sigblock(sigmask(SIGHUP)); 82*55572Sbostic 83*55572Sbostic /* 84*55572Sbostic * GETSTR positions `bcp' at the start of the current token, 85*55572Sbostic * and null terminates it. `cp' is positioned at the start 86*55572Sbostic * of the next token. spaces & commas are separators. 87*55572Sbostic */ 88*55572Sbostic #define GETSTR while (isspace(*cp) || *cp == ',') cp++; \ 89*55572Sbostic bcp = cp; \ 90*55572Sbostic while (*cp && *cp!=',' && !isspace(*cp)) cp++; \ 91*55572Sbostic if (*cp) *cp++ = '\0' 92*55572Sbostic 93*55572Sbostic /* 94*55572Sbostic * For each line, parse it into a new CLIENT struct. 95*55572Sbostic */ 96*55572Sbostic while (fgets(line, C_LINELEN, fp) != NULL) { 97*55572Sbostic linecnt++; /* line counter */ 98*55572Sbostic 99*55572Sbostic if (*line == '\0' || *line == '#') /* ignore comment */ 100*55572Sbostic continue; 101*55572Sbostic 102*55572Sbostic if ((cp = index(line,'#')) != NULL) /* trash comments */ 103*55572Sbostic *cp = '\0'; 104*55572Sbostic 105*55572Sbostic cp = line; /* init `cp' */ 106*55572Sbostic GETSTR; /* get RMP addr */ 107*55572Sbostic if (bcp == cp) /* all delimiters */ 108*55572Sbostic continue; 109*55572Sbostic 110*55572Sbostic /* 111*55572Sbostic * Get an RMP address from a string. Abort on failure. 112*55572Sbostic */ 113*55572Sbostic if ((addr = ParseAddr(bcp)) == NULL) { 114*55572Sbostic syslog(LOG_ERR, 115*55572Sbostic "ParseConfig: line %d: cant parse <%s>", 116*55572Sbostic linecnt, bcp); 117*55572Sbostic continue; 118*55572Sbostic } 119*55572Sbostic 120*55572Sbostic if ((client = NewClient(addr)) == NULL) /* alloc new client */ 121*55572Sbostic continue; 122*55572Sbostic 123*55572Sbostic GETSTR; /* get first file */ 124*55572Sbostic 125*55572Sbostic /* 126*55572Sbostic * If no boot files are spec'd, use the default list. 127*55572Sbostic * Otherwise, validate each file (`bcp') against the 128*55572Sbostic * list of boot-able files. 129*55572Sbostic */ 130*55572Sbostic i = 0; 131*55572Sbostic if (bcp == cp) /* no files spec'd */ 132*55572Sbostic for (; i < C_MAXFILE && BootFiles[i] != NULL; i++) 133*55572Sbostic client->files[i] = BootFiles[i]; 134*55572Sbostic else { 135*55572Sbostic do { 136*55572Sbostic /* 137*55572Sbostic * For each boot file spec'd, make sure it's 138*55572Sbostic * in our list. If so, include a pointer to 139*55572Sbostic * it in the CLIENT's list of boot files. 140*55572Sbostic */ 141*55572Sbostic for (j = 0; ; j++) { 142*55572Sbostic if (j==C_MAXFILE||BootFiles[j]==NULL) { 143*55572Sbostic syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)", 144*55572Sbostic linecnt, bcp); 145*55572Sbostic break; 146*55572Sbostic } 147*55572Sbostic if (STREQN(BootFiles[j], bcp)) { 148*55572Sbostic if (i < C_MAXFILE) 149*55572Sbostic client->files[i++] = 150*55572Sbostic BootFiles[j]; 151*55572Sbostic else 152*55572Sbostic syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)", 153*55572Sbostic linecnt, bcp); 154*55572Sbostic break; 155*55572Sbostic } 156*55572Sbostic } 157*55572Sbostic GETSTR; /* get next file */ 158*55572Sbostic } while (bcp != cp); 159*55572Sbostic 160*55572Sbostic /* 161*55572Sbostic * Restricted list of boot files were spec'd, 162*55572Sbostic * however, none of them were found. Since we 163*55572Sbostic * apparently cant let them boot "just anything", 164*55572Sbostic * the entire record is invalidated. 165*55572Sbostic */ 166*55572Sbostic if (i == 0) { 167*55572Sbostic FreeClient(client); 168*55572Sbostic continue; 169*55572Sbostic } 170*55572Sbostic } 171*55572Sbostic 172*55572Sbostic /* 173*55572Sbostic * Link this client into the linked list of clients. 174*55572Sbostic * SIGHUP has already been blocked. 175*55572Sbostic */ 176*55572Sbostic if (Clients) 177*55572Sbostic client->next = Clients; 178*55572Sbostic Clients = client; 179*55572Sbostic } 180*55572Sbostic 181*55572Sbostic (void) fclose(fp); /* close config file */ 182*55572Sbostic 183*55572Sbostic (void) sigsetmask(omask); /* reset signal mask */ 184*55572Sbostic 185*55572Sbostic return(1); /* return success */ 186*55572Sbostic } 187*55572Sbostic 188*55572Sbostic /* 189*55572Sbostic ** ParseAddr -- Parse a string containing an RMP address. 190*55572Sbostic ** 191*55572Sbostic ** This routine is fairly liberal at parsing an RMP address. The 192*55572Sbostic ** address must contain 6 octets consisting of between 0 and 2 hex 193*55572Sbostic ** chars (upper/lower case) separated by colons. If two colons are 194*55572Sbostic ** together (e.g. "::", the octet between them is recorded as being 195*55572Sbostic ** zero. Hence, the following addrs are all valid and parse to the 196*55572Sbostic ** same thing: 197*55572Sbostic ** 198*55572Sbostic ** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD 199*55572Sbostic ** 200*55572Sbostic ** For clarity, an RMP address is really an Ethernet address, but 201*55572Sbostic ** since the HP boot code uses IEEE 802.3, it's really an IEEE 202*55572Sbostic ** 802.3 address. Of course, all of these are identical. 203*55572Sbostic ** 204*55572Sbostic ** Parameters: 205*55572Sbostic ** str - string representation of an RMP address. 206*55572Sbostic ** 207*55572Sbostic ** Returns: 208*55572Sbostic ** pointer to a static array of RMP_ADDRLEN bytes. 209*55572Sbostic ** 210*55572Sbostic ** Side Effects: 211*55572Sbostic ** None. 212*55572Sbostic ** 213*55572Sbostic ** Warnings: 214*55572Sbostic ** - The return value points to a static buffer; it must 215*55572Sbostic ** be copied if it's to be saved. 216*55572Sbostic ** - For speed, we assume a u_char consists of 8 bits. 217*55572Sbostic */ 218*55572Sbostic 219*55572Sbostic u_char * 220*55572Sbostic ParseAddr(str) 221*55572Sbostic char *str; 222*55572Sbostic { 223*55572Sbostic static u_char addr[RMP_ADDRLEN]; 224*55572Sbostic register char *cp; 225*55572Sbostic register unsigned i; 226*55572Sbostic register int part, subpart; 227*55572Sbostic 228*55572Sbostic bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */ 229*55572Sbostic 230*55572Sbostic part = subpart = 0; 231*55572Sbostic for (cp = str; *cp; cp++) { 232*55572Sbostic /* 233*55572Sbostic * A colon (`:') must be used to delimit each octet. 234*55572Sbostic */ 235*55572Sbostic if (*cp == ':') { 236*55572Sbostic if (++part == RMP_ADDRLEN) /* too many parts */ 237*55572Sbostic return(NULL); 238*55572Sbostic subpart = 0; 239*55572Sbostic continue; 240*55572Sbostic } 241*55572Sbostic 242*55572Sbostic /* 243*55572Sbostic * Convert hex character to an integer. 244*55572Sbostic */ 245*55572Sbostic if (isdigit(*cp)) 246*55572Sbostic i = *cp - '0'; 247*55572Sbostic else { 248*55572Sbostic i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10; 249*55572Sbostic if (i < 10 || i > 15) /* not a hex char */ 250*55572Sbostic return(NULL); 251*55572Sbostic } 252*55572Sbostic 253*55572Sbostic if (subpart++) { 254*55572Sbostic if (subpart > 2) /* too many hex chars */ 255*55572Sbostic return(NULL); 256*55572Sbostic addr[part] <<= 4; 257*55572Sbostic } 258*55572Sbostic addr[part] |= i; 259*55572Sbostic } 260*55572Sbostic 261*55572Sbostic if (part != (RMP_ADDRLEN-1)) /* too few parts */ 262*55572Sbostic return(NULL); 263*55572Sbostic 264*55572Sbostic return(&addr[0]); 265*55572Sbostic } 266*55572Sbostic 267*55572Sbostic /* 268*55572Sbostic ** GetBootFiles -- record list of files in current (boot) directory. 269*55572Sbostic ** 270*55572Sbostic ** Parameters: 271*55572Sbostic ** None. 272*55572Sbostic ** 273*55572Sbostic ** Returns: 274*55572Sbostic ** Number of boot files on success, 0 on failure. 275*55572Sbostic ** 276*55572Sbostic ** Side Effects: 277*55572Sbostic ** Strings in `BootFiles' are freed/allocated. 278*55572Sbostic ** 279*55572Sbostic ** Warnings: 280*55572Sbostic ** - After this routine is called, ParseConfig() must be 281*55572Sbostic ** called to re-order it's list of boot file pointers. 282*55572Sbostic */ 283*55572Sbostic 284*55572Sbostic int 285*55572Sbostic GetBootFiles() 286*55572Sbostic { 287*55572Sbostic DIR *dfd; 288*55572Sbostic struct stat statb; 289*55572Sbostic register struct direct *dp; 290*55572Sbostic register int i; 291*55572Sbostic char *NewStr(); 292*55572Sbostic 293*55572Sbostic /* 294*55572Sbostic * Free the current list of boot files. 295*55572Sbostic */ 296*55572Sbostic for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) { 297*55572Sbostic FreeStr(BootFiles[i]); 298*55572Sbostic BootFiles[i] = NULL; 299*55572Sbostic } 300*55572Sbostic 301*55572Sbostic /* 302*55572Sbostic * Open current directory to read boot file names. 303*55572Sbostic */ 304*55572Sbostic if ((dfd = opendir(".")) == NULL) { /* open BootDir */ 305*55572Sbostic syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n", 306*55572Sbostic BootDir); 307*55572Sbostic return(0); 308*55572Sbostic } 309*55572Sbostic 310*55572Sbostic /* 311*55572Sbostic * Read each boot file name and allocate space for it in the 312*55572Sbostic * list of boot files (BootFiles). All boot files read after 313*55572Sbostic * C_MAXFILE will be ignored. 314*55572Sbostic */ 315*55572Sbostic i = 0; 316*55572Sbostic for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) { 317*55572Sbostic if (stat(dp->d_name, &statb) < 0 || 318*55572Sbostic (statb.st_mode & S_IFMT) != S_IFREG) 319*55572Sbostic continue; 320*55572Sbostic if (i == C_MAXFILE) 321*55572Sbostic syslog(LOG_ERR, 322*55572Sbostic "GetBootFiles: too many boot files (%s ignored)", 323*55572Sbostic dp->d_name); 324*55572Sbostic else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL) 325*55572Sbostic i++; 326*55572Sbostic } 327*55572Sbostic 328*55572Sbostic (void) closedir(dfd); /* close BootDir */ 329*55572Sbostic 330*55572Sbostic if (i == 0) /* cant find any boot files */ 331*55572Sbostic syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir); 332*55572Sbostic 333*55572Sbostic return(i); 334*55572Sbostic } 335