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