155572Sbostic /* 255572Sbostic * Copyright (c) 1992 Regents of the University of California. 355572Sbostic * Copyright (c) 1988, 1992 The University of Utah and the Center 455572Sbostic * for Software Science (CSS). 555572Sbostic * All rights reserved. 655572Sbostic * 755572Sbostic * This code is derived from software contributed to Berkeley by 855572Sbostic * the Center for Software Science of the University of Utah Computer 955572Sbostic * Science Department. CSS requests users of this software to return 1055572Sbostic * to css-dist@cs.utah.edu any improvements that they make and grant 1155572Sbostic * CSS redistribution rights. 1255572Sbostic * 1355572Sbostic * %sccs.include.redist.c% 1455572Sbostic * 15*55600Sbostic * @(#)parseconf.c 5.2 (Berkeley) 07/23/92 1655572Sbostic * 1755572Sbostic * Utah $Hdr: parseconf.c 3.1 92/07/06$ 1855572Sbostic * Author: Jeff Forys, University of Utah CSS 1955572Sbostic */ 2055572Sbostic 2155572Sbostic #ifndef lint 22*55600Sbostic static char sccsid[] = "@(#)parseconf.c 5.2 (Berkeley) 07/23/92"; 2355572Sbostic #endif /* not lint */ 2455572Sbostic 25*55600Sbostic #include <sys/param.h> 2655572Sbostic #include <sys/stat.h> 2755572Sbostic 28*55600Sbostic #include <ctype.h> 29*55600Sbostic #include <dirent.h> 30*55600Sbostic #include <fcntl.h> 31*55600Sbostic #include <signal.h> 32*55600Sbostic #include <stdio.h> 33*55600Sbostic #include <stdlib.h> 34*55600Sbostic #include <string.h> 3555572Sbostic #include <syslog.h> 36*55600Sbostic #include "defs.h" 3755572Sbostic 3855572Sbostic /* 3955572Sbostic ** ParseConfig -- parse the config file into linked list of clients. 4055572Sbostic ** 4155572Sbostic ** Parameters: 4255572Sbostic ** None. 4355572Sbostic ** 4455572Sbostic ** Returns: 4555572Sbostic ** 1 on success, 0 otherwise. 4655572Sbostic ** 4755572Sbostic ** Side Effects: 4855572Sbostic ** - Linked list of clients will be (re)allocated. 4955572Sbostic ** 5055572Sbostic ** Warnings: 5155572Sbostic ** - GetBootFiles() must be called before this routine 5255572Sbostic ** to create a linked list of default boot files. 5355572Sbostic */ 5455572Sbostic int 5555572Sbostic ParseConfig() 5655572Sbostic { 5755572Sbostic FILE *fp; 58*55600Sbostic CLIENT *client; 59*55600Sbostic u_char *addr; 60*55600Sbostic char line[C_LINELEN]; 6155572Sbostic register char *cp, *bcp; 6255572Sbostic register int i, j; 6355572Sbostic int omask, linecnt = 0; 6455572Sbostic 6555572Sbostic if (BootAny) /* ignore config file */ 6655572Sbostic return(1); 6755572Sbostic 6855572Sbostic FreeClients(); /* delete old list of clients */ 6955572Sbostic 7055572Sbostic if ((fp = fopen(ConfigFile, "r")) == NULL) { 7155572Sbostic syslog(LOG_ERR, "ParseConfig: can't open config file (%s)", 7255572Sbostic ConfigFile); 7355572Sbostic return(0); 7455572Sbostic } 7555572Sbostic 7655572Sbostic /* 7755572Sbostic * We've got to block SIGHUP to prevent reconfiguration while 7855572Sbostic * dealing with the linked list of Clients. This can be done 7955572Sbostic * when actually linking the new client into the list, but 8055572Sbostic * this could have unexpected results if the server was HUP'd 8155572Sbostic * whilst reconfiguring. Hence, it is done here. 8255572Sbostic */ 8355572Sbostic omask = sigblock(sigmask(SIGHUP)); 8455572Sbostic 8555572Sbostic /* 8655572Sbostic * GETSTR positions `bcp' at the start of the current token, 8755572Sbostic * and null terminates it. `cp' is positioned at the start 8855572Sbostic * of the next token. spaces & commas are separators. 8955572Sbostic */ 9055572Sbostic #define GETSTR while (isspace(*cp) || *cp == ',') cp++; \ 9155572Sbostic bcp = cp; \ 9255572Sbostic while (*cp && *cp!=',' && !isspace(*cp)) cp++; \ 9355572Sbostic if (*cp) *cp++ = '\0' 9455572Sbostic 9555572Sbostic /* 9655572Sbostic * For each line, parse it into a new CLIENT struct. 9755572Sbostic */ 9855572Sbostic while (fgets(line, C_LINELEN, fp) != NULL) { 9955572Sbostic linecnt++; /* line counter */ 10055572Sbostic 10155572Sbostic if (*line == '\0' || *line == '#') /* ignore comment */ 10255572Sbostic continue; 10355572Sbostic 10455572Sbostic if ((cp = index(line,'#')) != NULL) /* trash comments */ 10555572Sbostic *cp = '\0'; 10655572Sbostic 10755572Sbostic cp = line; /* init `cp' */ 10855572Sbostic GETSTR; /* get RMP addr */ 10955572Sbostic if (bcp == cp) /* all delimiters */ 11055572Sbostic continue; 11155572Sbostic 11255572Sbostic /* 11355572Sbostic * Get an RMP address from a string. Abort on failure. 11455572Sbostic */ 11555572Sbostic if ((addr = ParseAddr(bcp)) == NULL) { 11655572Sbostic syslog(LOG_ERR, 11755572Sbostic "ParseConfig: line %d: cant parse <%s>", 11855572Sbostic linecnt, bcp); 11955572Sbostic continue; 12055572Sbostic } 12155572Sbostic 12255572Sbostic if ((client = NewClient(addr)) == NULL) /* alloc new client */ 12355572Sbostic continue; 12455572Sbostic 12555572Sbostic GETSTR; /* get first file */ 12655572Sbostic 12755572Sbostic /* 12855572Sbostic * If no boot files are spec'd, use the default list. 12955572Sbostic * Otherwise, validate each file (`bcp') against the 13055572Sbostic * list of boot-able files. 13155572Sbostic */ 13255572Sbostic i = 0; 13355572Sbostic if (bcp == cp) /* no files spec'd */ 13455572Sbostic for (; i < C_MAXFILE && BootFiles[i] != NULL; i++) 13555572Sbostic client->files[i] = BootFiles[i]; 13655572Sbostic else { 13755572Sbostic do { 13855572Sbostic /* 13955572Sbostic * For each boot file spec'd, make sure it's 14055572Sbostic * in our list. If so, include a pointer to 14155572Sbostic * it in the CLIENT's list of boot files. 14255572Sbostic */ 14355572Sbostic for (j = 0; ; j++) { 14455572Sbostic if (j==C_MAXFILE||BootFiles[j]==NULL) { 14555572Sbostic syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)", 14655572Sbostic linecnt, bcp); 14755572Sbostic break; 14855572Sbostic } 14955572Sbostic if (STREQN(BootFiles[j], bcp)) { 15055572Sbostic if (i < C_MAXFILE) 15155572Sbostic client->files[i++] = 15255572Sbostic BootFiles[j]; 15355572Sbostic else 15455572Sbostic syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)", 15555572Sbostic linecnt, bcp); 15655572Sbostic break; 15755572Sbostic } 15855572Sbostic } 15955572Sbostic GETSTR; /* get next file */ 16055572Sbostic } while (bcp != cp); 16155572Sbostic 16255572Sbostic /* 16355572Sbostic * Restricted list of boot files were spec'd, 16455572Sbostic * however, none of them were found. Since we 16555572Sbostic * apparently cant let them boot "just anything", 16655572Sbostic * the entire record is invalidated. 16755572Sbostic */ 16855572Sbostic if (i == 0) { 16955572Sbostic FreeClient(client); 17055572Sbostic continue; 17155572Sbostic } 17255572Sbostic } 17355572Sbostic 17455572Sbostic /* 17555572Sbostic * Link this client into the linked list of clients. 17655572Sbostic * SIGHUP has already been blocked. 17755572Sbostic */ 17855572Sbostic if (Clients) 17955572Sbostic client->next = Clients; 18055572Sbostic Clients = client; 18155572Sbostic } 18255572Sbostic 18355572Sbostic (void) fclose(fp); /* close config file */ 18455572Sbostic 18555572Sbostic (void) sigsetmask(omask); /* reset signal mask */ 18655572Sbostic 18755572Sbostic return(1); /* return success */ 18855572Sbostic } 18955572Sbostic 19055572Sbostic /* 19155572Sbostic ** ParseAddr -- Parse a string containing an RMP address. 19255572Sbostic ** 19355572Sbostic ** This routine is fairly liberal at parsing an RMP address. The 19455572Sbostic ** address must contain 6 octets consisting of between 0 and 2 hex 19555572Sbostic ** chars (upper/lower case) separated by colons. If two colons are 19655572Sbostic ** together (e.g. "::", the octet between them is recorded as being 19755572Sbostic ** zero. Hence, the following addrs are all valid and parse to the 19855572Sbostic ** same thing: 19955572Sbostic ** 20055572Sbostic ** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD 20155572Sbostic ** 20255572Sbostic ** For clarity, an RMP address is really an Ethernet address, but 20355572Sbostic ** since the HP boot code uses IEEE 802.3, it's really an IEEE 20455572Sbostic ** 802.3 address. Of course, all of these are identical. 20555572Sbostic ** 20655572Sbostic ** Parameters: 20755572Sbostic ** str - string representation of an RMP address. 20855572Sbostic ** 20955572Sbostic ** Returns: 21055572Sbostic ** pointer to a static array of RMP_ADDRLEN bytes. 21155572Sbostic ** 21255572Sbostic ** Side Effects: 21355572Sbostic ** None. 21455572Sbostic ** 21555572Sbostic ** Warnings: 21655572Sbostic ** - The return value points to a static buffer; it must 21755572Sbostic ** be copied if it's to be saved. 21855572Sbostic ** - For speed, we assume a u_char consists of 8 bits. 21955572Sbostic */ 22055572Sbostic u_char * 22155572Sbostic ParseAddr(str) 222*55600Sbostic char *str; 22355572Sbostic { 22455572Sbostic static u_char addr[RMP_ADDRLEN]; 22555572Sbostic register char *cp; 22655572Sbostic register unsigned i; 22755572Sbostic register int part, subpart; 22855572Sbostic 22955572Sbostic bzero((char *)&addr[0], RMP_ADDRLEN); /* zero static buffer */ 23055572Sbostic 23155572Sbostic part = subpart = 0; 23255572Sbostic for (cp = str; *cp; cp++) { 23355572Sbostic /* 23455572Sbostic * A colon (`:') must be used to delimit each octet. 23555572Sbostic */ 23655572Sbostic if (*cp == ':') { 23755572Sbostic if (++part == RMP_ADDRLEN) /* too many parts */ 23855572Sbostic return(NULL); 23955572Sbostic subpart = 0; 24055572Sbostic continue; 24155572Sbostic } 24255572Sbostic 24355572Sbostic /* 24455572Sbostic * Convert hex character to an integer. 24555572Sbostic */ 24655572Sbostic if (isdigit(*cp)) 24755572Sbostic i = *cp - '0'; 24855572Sbostic else { 24955572Sbostic i = (isupper(*cp)? tolower(*cp): *cp) - 'a' + 10; 25055572Sbostic if (i < 10 || i > 15) /* not a hex char */ 25155572Sbostic return(NULL); 25255572Sbostic } 25355572Sbostic 25455572Sbostic if (subpart++) { 25555572Sbostic if (subpart > 2) /* too many hex chars */ 25655572Sbostic return(NULL); 25755572Sbostic addr[part] <<= 4; 25855572Sbostic } 25955572Sbostic addr[part] |= i; 26055572Sbostic } 26155572Sbostic 26255572Sbostic if (part != (RMP_ADDRLEN-1)) /* too few parts */ 26355572Sbostic return(NULL); 26455572Sbostic 26555572Sbostic return(&addr[0]); 26655572Sbostic } 26755572Sbostic 26855572Sbostic /* 26955572Sbostic ** GetBootFiles -- record list of files in current (boot) directory. 27055572Sbostic ** 27155572Sbostic ** Parameters: 27255572Sbostic ** None. 27355572Sbostic ** 27455572Sbostic ** Returns: 27555572Sbostic ** Number of boot files on success, 0 on failure. 27655572Sbostic ** 27755572Sbostic ** Side Effects: 27855572Sbostic ** Strings in `BootFiles' are freed/allocated. 27955572Sbostic ** 28055572Sbostic ** Warnings: 28155572Sbostic ** - After this routine is called, ParseConfig() must be 28255572Sbostic ** called to re-order it's list of boot file pointers. 28355572Sbostic */ 28455572Sbostic int 28555572Sbostic GetBootFiles() 28655572Sbostic { 28755572Sbostic DIR *dfd; 28855572Sbostic struct stat statb; 289*55600Sbostic register struct dirent *dp; 29055572Sbostic register int i; 29155572Sbostic 29255572Sbostic /* 29355572Sbostic * Free the current list of boot files. 29455572Sbostic */ 29555572Sbostic for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) { 29655572Sbostic FreeStr(BootFiles[i]); 29755572Sbostic BootFiles[i] = NULL; 29855572Sbostic } 29955572Sbostic 30055572Sbostic /* 30155572Sbostic * Open current directory to read boot file names. 30255572Sbostic */ 30355572Sbostic if ((dfd = opendir(".")) == NULL) { /* open BootDir */ 30455572Sbostic syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n", 30555572Sbostic BootDir); 30655572Sbostic return(0); 30755572Sbostic } 30855572Sbostic 30955572Sbostic /* 31055572Sbostic * Read each boot file name and allocate space for it in the 31155572Sbostic * list of boot files (BootFiles). All boot files read after 31255572Sbostic * C_MAXFILE will be ignored. 31355572Sbostic */ 31455572Sbostic i = 0; 31555572Sbostic for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) { 31655572Sbostic if (stat(dp->d_name, &statb) < 0 || 31755572Sbostic (statb.st_mode & S_IFMT) != S_IFREG) 31855572Sbostic continue; 31955572Sbostic if (i == C_MAXFILE) 32055572Sbostic syslog(LOG_ERR, 32155572Sbostic "GetBootFiles: too many boot files (%s ignored)", 32255572Sbostic dp->d_name); 32355572Sbostic else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL) 32455572Sbostic i++; 32555572Sbostic } 32655572Sbostic 32755572Sbostic (void) closedir(dfd); /* close BootDir */ 32855572Sbostic 32955572Sbostic if (i == 0) /* cant find any boot files */ 33055572Sbostic syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir); 33155572Sbostic 33255572Sbostic return(i); 33355572Sbostic } 334