1 1.13 tsutsui /* $NetBSD: parseconf.c,v 1.13 2022/09/03 07:45:08 tsutsui Exp $ */ 2 1.8 agc 3 1.8 agc /* 4 1.11 rmind * Copyright (c) 1988, 1992 The University of Utah and the Center 5 1.11 rmind * for Software Science (CSS). 6 1.8 agc * Copyright (c) 1992, 1993 7 1.8 agc * The Regents of the University of California. All rights reserved. 8 1.8 agc * 9 1.8 agc * This code is derived from software contributed to Berkeley by 10 1.8 agc * the Center for Software Science of the University of Utah Computer 11 1.8 agc * Science Department. CSS requests users of this software to return 12 1.8 agc * to css-dist (at) cs.utah.edu any improvements that they make and grant 13 1.8 agc * CSS redistribution rights. 14 1.8 agc * 15 1.8 agc * Redistribution and use in source and binary forms, with or without 16 1.8 agc * modification, are permitted provided that the following conditions 17 1.8 agc * are met: 18 1.8 agc * 1. Redistributions of source code must retain the above copyright 19 1.8 agc * notice, this list of conditions and the following disclaimer. 20 1.8 agc * 2. Redistributions in binary form must reproduce the above copyright 21 1.8 agc * notice, this list of conditions and the following disclaimer in the 22 1.8 agc * documentation and/or other materials provided with the distribution. 23 1.8 agc * 3. Neither the name of the University nor the names of its contributors 24 1.8 agc * may be used to endorse or promote products derived from this software 25 1.8 agc * without specific prior written permission. 26 1.8 agc * 27 1.8 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 1.8 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 1.8 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 1.8 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 1.8 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 1.8 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 1.8 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 1.8 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 1.8 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 1.8 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 1.8 agc * SUCH DAMAGE. 38 1.8 agc * 39 1.8 agc * from: @(#)parseconf.c 8.1 (Berkeley) 6/4/93 40 1.8 agc * 41 1.8 agc * From: Utah Hdr: parseconf.c 3.1 92/07/06 42 1.8 agc * Author: Jeff Forys, University of Utah CSS 43 1.8 agc */ 44 1.3 thorpej 45 1.5 thorpej #include <sys/cdefs.h> 46 1.1 brezak #ifndef lint 47 1.5 thorpej #if 0 48 1.5 thorpej static char sccsid[] = "@(#)parseconf.c 8.1 (Berkeley) 6/4/93"; 49 1.5 thorpej #else 50 1.13 tsutsui __RCSID("$NetBSD: parseconf.c,v 1.13 2022/09/03 07:45:08 tsutsui Exp $"); 51 1.5 thorpej #endif 52 1.1 brezak #endif /* not lint */ 53 1.1 brezak 54 1.1 brezak #include <sys/param.h> 55 1.1 brezak #include <sys/stat.h> 56 1.1 brezak 57 1.1 brezak #include <ctype.h> 58 1.1 brezak #include <dirent.h> 59 1.1 brezak #include <fcntl.h> 60 1.1 brezak #include <signal.h> 61 1.1 brezak #include <stdio.h> 62 1.1 brezak #include <stdlib.h> 63 1.1 brezak #include <string.h> 64 1.1 brezak #include <syslog.h> 65 1.1 brezak #include "defs.h" 66 1.1 brezak 67 1.1 brezak /* 68 1.1 brezak ** ParseConfig -- parse the config file into linked list of clients. 69 1.1 brezak ** 70 1.1 brezak ** Parameters: 71 1.1 brezak ** None. 72 1.1 brezak ** 73 1.1 brezak ** Returns: 74 1.1 brezak ** 1 on success, 0 otherwise. 75 1.1 brezak ** 76 1.1 brezak ** Side Effects: 77 1.1 brezak ** - Linked list of clients will be (re)allocated. 78 1.1 brezak ** 79 1.1 brezak ** Warnings: 80 1.1 brezak ** - GetBootFiles() must be called before this routine 81 1.1 brezak ** to create a linked list of default boot files. 82 1.1 brezak */ 83 1.1 brezak int 84 1.13 tsutsui ParseConfig(void) 85 1.1 brezak { 86 1.1 brezak FILE *fp; 87 1.1 brezak CLIENT *client; 88 1.4 thorpej u_int8_t *addr; 89 1.1 brezak char line[C_LINELEN]; 90 1.6 lukem char *cp, *bcp; 91 1.6 lukem int i, j; 92 1.1 brezak int omask, linecnt = 0; 93 1.1 brezak 94 1.1 brezak if (BootAny) /* ignore config file */ 95 1.1 brezak return(1); 96 1.1 brezak 97 1.1 brezak FreeClients(); /* delete old list of clients */ 98 1.1 brezak 99 1.1 brezak if ((fp = fopen(ConfigFile, "r")) == NULL) { 100 1.1 brezak syslog(LOG_ERR, "ParseConfig: can't open config file (%s)", 101 1.1 brezak ConfigFile); 102 1.1 brezak return(0); 103 1.1 brezak } 104 1.1 brezak 105 1.1 brezak /* 106 1.1 brezak * We've got to block SIGHUP to prevent reconfiguration while 107 1.1 brezak * dealing with the linked list of Clients. This can be done 108 1.1 brezak * when actually linking the new client into the list, but 109 1.1 brezak * this could have unexpected results if the server was HUP'd 110 1.1 brezak * whilst reconfiguring. Hence, it is done here. 111 1.1 brezak */ 112 1.1 brezak omask = sigblock(sigmask(SIGHUP)); 113 1.1 brezak 114 1.1 brezak /* 115 1.1 brezak * GETSTR positions `bcp' at the start of the current token, 116 1.1 brezak * and null terminates it. `cp' is positioned at the start 117 1.1 brezak * of the next token. spaces & commas are separators. 118 1.1 brezak */ 119 1.9 dsl #define GETSTR while (isspace((unsigned char)*cp) || *cp == ',') cp++; \ 120 1.9 dsl bcp = cp; \ 121 1.9 dsl while (*cp && *cp!=',' && !isspace((unsigned char)*cp)) cp++;\ 122 1.1 brezak if (*cp) *cp++ = '\0' 123 1.1 brezak 124 1.1 brezak /* 125 1.1 brezak * For each line, parse it into a new CLIENT struct. 126 1.1 brezak */ 127 1.1 brezak while (fgets(line, C_LINELEN, fp) != NULL) { 128 1.1 brezak linecnt++; /* line counter */ 129 1.1 brezak 130 1.1 brezak if (*line == '\0' || *line == '#') /* ignore comment */ 131 1.1 brezak continue; 132 1.1 brezak 133 1.6 lukem if ((cp = strchr(line,'#')) != NULL) /* trash comments */ 134 1.1 brezak *cp = '\0'; 135 1.1 brezak 136 1.1 brezak cp = line; /* init `cp' */ 137 1.1 brezak GETSTR; /* get RMP addr */ 138 1.1 brezak if (bcp == cp) /* all delimiters */ 139 1.1 brezak continue; 140 1.1 brezak 141 1.1 brezak /* 142 1.1 brezak * Get an RMP address from a string. Abort on failure. 143 1.1 brezak */ 144 1.1 brezak if ((addr = ParseAddr(bcp)) == NULL) { 145 1.1 brezak syslog(LOG_ERR, 146 1.1 brezak "ParseConfig: line %d: cant parse <%s>", 147 1.1 brezak linecnt, bcp); 148 1.1 brezak continue; 149 1.1 brezak } 150 1.1 brezak 151 1.1 brezak if ((client = NewClient(addr)) == NULL) /* alloc new client */ 152 1.1 brezak continue; 153 1.1 brezak 154 1.1 brezak GETSTR; /* get first file */ 155 1.1 brezak 156 1.1 brezak /* 157 1.1 brezak * If no boot files are spec'd, use the default list. 158 1.1 brezak * Otherwise, validate each file (`bcp') against the 159 1.1 brezak * list of boot-able files. 160 1.1 brezak */ 161 1.1 brezak i = 0; 162 1.1 brezak if (bcp == cp) /* no files spec'd */ 163 1.1 brezak for (; i < C_MAXFILE && BootFiles[i] != NULL; i++) 164 1.1 brezak client->files[i] = BootFiles[i]; 165 1.1 brezak else { 166 1.1 brezak do { 167 1.1 brezak /* 168 1.1 brezak * For each boot file spec'd, make sure it's 169 1.1 brezak * in our list. If so, include a pointer to 170 1.1 brezak * it in the CLIENT's list of boot files. 171 1.1 brezak */ 172 1.1 brezak for (j = 0; ; j++) { 173 1.1 brezak if (j==C_MAXFILE||BootFiles[j]==NULL) { 174 1.1 brezak syslog(LOG_ERR, "ParseConfig: line %d: no boot file (%s)", 175 1.1 brezak linecnt, bcp); 176 1.1 brezak break; 177 1.1 brezak } 178 1.1 brezak if (STREQN(BootFiles[j], bcp)) { 179 1.1 brezak if (i < C_MAXFILE) 180 1.1 brezak client->files[i++] = 181 1.1 brezak BootFiles[j]; 182 1.1 brezak else 183 1.1 brezak syslog(LOG_ERR, "ParseConfig: line %d: too many boot files (%s)", 184 1.1 brezak linecnt, bcp); 185 1.1 brezak break; 186 1.1 brezak } 187 1.1 brezak } 188 1.1 brezak GETSTR; /* get next file */ 189 1.1 brezak } while (bcp != cp); 190 1.1 brezak 191 1.1 brezak /* 192 1.1 brezak * Restricted list of boot files were spec'd, 193 1.1 brezak * however, none of them were found. Since we 194 1.1 brezak * apparently cant let them boot "just anything", 195 1.1 brezak * the entire record is invalidated. 196 1.1 brezak */ 197 1.1 brezak if (i == 0) { 198 1.1 brezak FreeClient(client); 199 1.1 brezak continue; 200 1.1 brezak } 201 1.1 brezak } 202 1.1 brezak 203 1.1 brezak /* 204 1.1 brezak * Link this client into the linked list of clients. 205 1.1 brezak * SIGHUP has already been blocked. 206 1.1 brezak */ 207 1.1 brezak if (Clients) 208 1.1 brezak client->next = Clients; 209 1.1 brezak Clients = client; 210 1.1 brezak } 211 1.1 brezak 212 1.1 brezak (void) fclose(fp); /* close config file */ 213 1.1 brezak 214 1.1 brezak (void) sigsetmask(omask); /* reset signal mask */ 215 1.1 brezak 216 1.1 brezak return(1); /* return success */ 217 1.1 brezak } 218 1.1 brezak 219 1.1 brezak /* 220 1.1 brezak ** ParseAddr -- Parse a string containing an RMP address. 221 1.1 brezak ** 222 1.1 brezak ** This routine is fairly liberal at parsing an RMP address. The 223 1.1 brezak ** address must contain 6 octets consisting of between 0 and 2 hex 224 1.1 brezak ** chars (upper/lower case) separated by colons. If two colons are 225 1.1 brezak ** together (e.g. "::", the octet between them is recorded as being 226 1.1 brezak ** zero. Hence, the following addrs are all valid and parse to the 227 1.1 brezak ** same thing: 228 1.1 brezak ** 229 1.1 brezak ** 08:00:09:00:66:ad 8::9:0:66:AD 8::9::66:aD 230 1.1 brezak ** 231 1.1 brezak ** For clarity, an RMP address is really an Ethernet address, but 232 1.1 brezak ** since the HP boot code uses IEEE 802.3, it's really an IEEE 233 1.1 brezak ** 802.3 address. Of course, all of these are identical. 234 1.1 brezak ** 235 1.1 brezak ** Parameters: 236 1.1 brezak ** str - string representation of an RMP address. 237 1.1 brezak ** 238 1.1 brezak ** Returns: 239 1.1 brezak ** pointer to a static array of RMP_ADDRLEN bytes. 240 1.1 brezak ** 241 1.1 brezak ** Side Effects: 242 1.1 brezak ** None. 243 1.1 brezak ** 244 1.1 brezak ** Warnings: 245 1.1 brezak ** - The return value points to a static buffer; it must 246 1.1 brezak ** be copied if it's to be saved. 247 1.1 brezak */ 248 1.4 thorpej u_int8_t * 249 1.12 sevan ParseAddr(char *str) 250 1.1 brezak { 251 1.4 thorpej static u_int8_t addr[RMP_ADDRLEN]; 252 1.6 lukem char *cp; 253 1.6 lukem unsigned i; 254 1.6 lukem int part, subpart; 255 1.1 brezak 256 1.6 lukem memset((char *)&addr[0], 0, RMP_ADDRLEN); /* zero static buffer */ 257 1.1 brezak 258 1.1 brezak part = subpart = 0; 259 1.1 brezak for (cp = str; *cp; cp++) { 260 1.1 brezak /* 261 1.1 brezak * A colon (`:') must be used to delimit each octet. 262 1.1 brezak */ 263 1.1 brezak if (*cp == ':') { 264 1.1 brezak if (++part == RMP_ADDRLEN) /* too many parts */ 265 1.1 brezak return(NULL); 266 1.1 brezak subpart = 0; 267 1.1 brezak continue; 268 1.1 brezak } 269 1.1 brezak 270 1.1 brezak /* 271 1.1 brezak * Convert hex character to an integer. 272 1.1 brezak */ 273 1.9 dsl if (isdigit((unsigned char)*cp)) 274 1.1 brezak i = *cp - '0'; 275 1.1 brezak else { 276 1.9 dsl i = tolower((unsigned char)*cp) - 'a' + 10; 277 1.1 brezak if (i < 10 || i > 15) /* not a hex char */ 278 1.1 brezak return(NULL); 279 1.1 brezak } 280 1.1 brezak 281 1.1 brezak if (subpart++) { 282 1.1 brezak if (subpart > 2) /* too many hex chars */ 283 1.1 brezak return(NULL); 284 1.1 brezak addr[part] <<= 4; 285 1.1 brezak } 286 1.1 brezak addr[part] |= i; 287 1.1 brezak } 288 1.1 brezak 289 1.1 brezak if (part != (RMP_ADDRLEN-1)) /* too few parts */ 290 1.1 brezak return(NULL); 291 1.1 brezak 292 1.1 brezak return(&addr[0]); 293 1.1 brezak } 294 1.1 brezak 295 1.1 brezak /* 296 1.1 brezak ** GetBootFiles -- record list of files in current (boot) directory. 297 1.1 brezak ** 298 1.1 brezak ** Parameters: 299 1.1 brezak ** None. 300 1.1 brezak ** 301 1.1 brezak ** Returns: 302 1.1 brezak ** Number of boot files on success, 0 on failure. 303 1.1 brezak ** 304 1.1 brezak ** Side Effects: 305 1.1 brezak ** Strings in `BootFiles' are freed/allocated. 306 1.1 brezak ** 307 1.1 brezak ** Warnings: 308 1.1 brezak ** - After this routine is called, ParseConfig() must be 309 1.10 snj ** called to re-order its list of boot file pointers. 310 1.1 brezak */ 311 1.1 brezak int 312 1.13 tsutsui GetBootFiles(void) 313 1.1 brezak { 314 1.1 brezak DIR *dfd; 315 1.1 brezak struct stat statb; 316 1.6 lukem struct dirent *dp; 317 1.6 lukem int i; 318 1.1 brezak 319 1.1 brezak /* 320 1.1 brezak * Free the current list of boot files. 321 1.1 brezak */ 322 1.1 brezak for (i = 0; i < C_MAXFILE && BootFiles[i] != NULL; i++) { 323 1.1 brezak FreeStr(BootFiles[i]); 324 1.1 brezak BootFiles[i] = NULL; 325 1.1 brezak } 326 1.1 brezak 327 1.1 brezak /* 328 1.1 brezak * Open current directory to read boot file names. 329 1.1 brezak */ 330 1.1 brezak if ((dfd = opendir(".")) == NULL) { /* open BootDir */ 331 1.1 brezak syslog(LOG_ERR, "GetBootFiles: can't open directory (%s)\n", 332 1.1 brezak BootDir); 333 1.1 brezak return(0); 334 1.1 brezak } 335 1.1 brezak 336 1.1 brezak /* 337 1.1 brezak * Read each boot file name and allocate space for it in the 338 1.1 brezak * list of boot files (BootFiles). All boot files read after 339 1.1 brezak * C_MAXFILE will be ignored. 340 1.1 brezak */ 341 1.1 brezak i = 0; 342 1.1 brezak for (dp = readdir(dfd); dp != NULL; dp = readdir(dfd)) { 343 1.7 mycroft if (stat(dp->d_name, &statb) < 0 || !S_ISREG(statb.st_mode)) 344 1.1 brezak continue; 345 1.1 brezak if (i == C_MAXFILE) 346 1.1 brezak syslog(LOG_ERR, 347 1.1 brezak "GetBootFiles: too many boot files (%s ignored)", 348 1.1 brezak dp->d_name); 349 1.1 brezak else if ((BootFiles[i] = NewStr(dp->d_name)) != NULL) 350 1.1 brezak i++; 351 1.1 brezak } 352 1.1 brezak 353 1.1 brezak (void) closedir(dfd); /* close BootDir */ 354 1.1 brezak 355 1.1 brezak if (i == 0) /* cant find any boot files */ 356 1.1 brezak syslog(LOG_ERR, "GetBootFiles: no boot files (%s)\n", BootDir); 357 1.1 brezak 358 1.1 brezak return(i); 359 1.1 brezak } 360