1 /* 2 * Copyright (c) 1988, 1992 The University of Utah and the Center 3 * for Software Science (CSS). 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. 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 * @(#)rbootd.c 8.2 (Berkeley) 02/22/94 16 * 17 * Utah $Hdr: rbootd.c 3.1 92/07/06$ 18 * Author: Jeff Forys, University of Utah CSS 19 */ 20 21 #ifndef lint 22 static char copyright[] = 23 "@(#) Copyright (c) 1992, 1993\n\ 24 The Regents of the University of California. All rights reserved.\n"; 25 #endif /* not lint */ 26 27 #ifndef lint 28 static char sccsid[] = "@(#)rbootd.c 8.2 (Berkeley) 02/22/94"; 29 #endif /* not lint */ 30 31 #include <sys/param.h> 32 #include <sys/ioctl.h> 33 #include <sys/time.h> 34 35 #include <ctype.h> 36 #include <errno.h> 37 #include <fcntl.h> 38 #include <signal.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <unistd.h> 44 #include "defs.h" 45 46 47 /* fd mask macros (backward compatibility with 4.2BSD) */ 48 #ifndef FD_SET 49 #ifdef notdef 50 typedef struct fd_set { /* this should already be in 4.2 */ 51 int fds_bits[1]; 52 } fd_set; 53 #endif 54 #define FD_ZERO(p) ((p)->fds_bits[0] = 0) 55 #define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n))) 56 #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n))) 57 #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n))) 58 #endif 59 60 int 61 main(argc, argv) 62 int argc; 63 char *argv[]; 64 { 65 int c, fd, omask, maxfds; 66 fd_set rset; 67 68 /* 69 * Find what name we are running under. 70 */ 71 ProgName = (ProgName = rindex(argv[0],'/')) ? ++ProgName : *argv; 72 73 /* 74 * Close any open file descriptors. 75 * Temporarily leave stdin & stdout open for `-d', 76 * and stderr open for any pre-syslog error messages. 77 */ 78 { 79 int i, nfds = getdtablesize(); 80 81 for (i = 0; i < nfds; i++) 82 if (i != fileno(stdin) && i != fileno(stdout) && 83 i != fileno(stderr)) 84 (void) close(i); 85 } 86 87 /* 88 * Parse any arguments. 89 */ 90 while ((c = getopt(argc, argv, "adi:")) != EOF) 91 switch(c) { 92 case 'a': 93 BootAny++; 94 break; 95 case 'd': 96 DebugFlg++; 97 break; 98 case 'i': 99 IntfName = optarg; 100 break; 101 } 102 for (; optind < argc; optind++) { 103 if (ConfigFile == NULL) 104 ConfigFile = argv[optind]; 105 else { 106 fprintf(stderr, 107 "%s: too many config files (`%s' ignored)\n", 108 ProgName, argv[optind]); 109 } 110 } 111 112 if (ConfigFile == NULL) /* use default config file */ 113 ConfigFile = DfltConfig; 114 115 if (DebugFlg) { 116 DbgFp = stdout; /* output to stdout */ 117 118 (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ 119 (void) signal(SIGUSR2, SIG_IGN); 120 } else { 121 (void) fclose(stdin); /* dont need these */ 122 (void) fclose(stdout); 123 124 /* 125 * Fork off a child to do the work & exit. 126 */ 127 switch(fork()) { 128 case -1: /* fork failed */ 129 fprintf(stderr, "%s: ", ProgName); 130 perror("fork"); 131 Exit(0); 132 case 0: /* this is the CHILD */ 133 break; 134 default: /* this is the PARENT */ 135 _exit(0); 136 } 137 138 /* 139 * Try to disassociate from the current tty. 140 */ 141 { 142 char *devtty = "/dev/tty"; 143 int i; 144 145 if ((i = open(devtty, O_RDWR)) < 0) { 146 /* probably already disassociated */ 147 if (setpgrp(0, 0) < 0) { 148 fprintf(stderr, "%s: ", ProgName); 149 perror("setpgrp"); 150 } 151 } else { 152 if (ioctl(i, (u_long)TIOCNOTTY, (char *)0) < 0){ 153 fprintf(stderr, "%s: ", ProgName); 154 perror("ioctl"); 155 } 156 (void) close(i); 157 } 158 } 159 160 (void) signal(SIGUSR1, DebugOn); 161 (void) signal(SIGUSR2, DebugOff); 162 } 163 164 (void) fclose(stderr); /* finished with it */ 165 166 #ifdef SYSLOG4_2 167 openlog(ProgName, LOG_PID); 168 #else 169 openlog(ProgName, LOG_PID, LOG_DAEMON); 170 #endif 171 172 /* 173 * If no interface was specified, get one now. 174 * 175 * This is convoluted because we want to get the default interface 176 * name for the syslog("restarted") message. If BpfGetIntfName() 177 * runs into an error, it will return a syslog-able error message 178 * (in `errmsg') which will be displayed here. 179 */ 180 if (IntfName == NULL) { 181 char *errmsg; 182 183 if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { 184 syslog(LOG_NOTICE, "restarted (??)"); 185 syslog(LOG_ERR, errmsg); 186 Exit(0); 187 } 188 } 189 190 syslog(LOG_NOTICE, "restarted (%s)", IntfName); 191 192 (void) signal(SIGHUP, ReConfig); 193 (void) signal(SIGINT, Exit); 194 (void) signal(SIGTERM, Exit); 195 196 /* 197 * Grab our host name and pid. 198 */ 199 if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) { 200 syslog(LOG_ERR, "gethostname: %m"); 201 Exit(0); 202 } 203 MyHost[MAXHOSTNAMELEN] = '\0'; 204 205 MyPid = getpid(); 206 207 /* 208 * Write proc's pid to a file. 209 */ 210 { 211 FILE *fp; 212 213 if ((fp = fopen(PidFile, "w")) != NULL) { 214 (void) fprintf(fp, "%d\n", MyPid); 215 (void) fclose(fp); 216 } else { 217 syslog(LOG_WARNING, "fopen: failed (%s)", PidFile); 218 } 219 } 220 221 /* 222 * All boot files are relative to the boot directory, we might 223 * as well chdir() there to make life easier. 224 */ 225 if (chdir(BootDir) < 0) { 226 syslog(LOG_ERR, "chdir: %m (%s)", BootDir); 227 Exit(0); 228 } 229 230 /* 231 * Initial configuration. 232 */ 233 omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */ 234 if (GetBootFiles() == 0) /* get list of boot files */ 235 Exit(0); 236 if (ParseConfig() == 0) /* parse config file */ 237 Exit(0); 238 239 /* 240 * Open and initialize a BPF device for the appropriate interface. 241 * If an error is encountered, a message is displayed and Exit() 242 * is called. 243 */ 244 fd = BpfOpen(); 245 246 (void) sigsetmask(omask); /* allow reconfig's */ 247 248 /* 249 * Main loop: receive a packet, determine where it came from, 250 * and if we service this host, call routine to handle request. 251 */ 252 maxfds = fd + 1; 253 FD_ZERO(&rset); 254 FD_SET(fd, &rset); 255 for (;;) { 256 struct timeval timeout; 257 fd_set r; 258 int nsel; 259 260 r = rset; 261 262 if (RmpConns == NULL) { /* timeout isnt necessary */ 263 nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0, 264 (struct timeval *)0); 265 } else { 266 timeout.tv_sec = RMP_TIMEOUT; 267 timeout.tv_usec = 0; 268 nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0, 269 &timeout); 270 } 271 272 if (nsel < 0) { 273 if (errno == EINTR) 274 continue; 275 syslog(LOG_ERR, "select: %m"); 276 Exit(0); 277 } else if (nsel == 0) { /* timeout */ 278 DoTimeout(); /* clear stale conns */ 279 continue; 280 } 281 282 if (FD_ISSET(fd, &r)) { 283 RMPCONN rconn; 284 CLIENT *client, *FindClient(); 285 int doread = 1; 286 287 while (BpfRead(&rconn, doread)) { 288 doread = 0; 289 290 if (DbgFp != NULL) /* display packet */ 291 DispPkt(&rconn,DIR_RCVD); 292 293 omask = sigblock(sigmask(SIGHUP)); 294 295 /* 296 * If we do not restrict service, set the 297 * client to NULL (ProcessPacket() handles 298 * this). Otherwise, check that we can 299 * service this host; if not, log a message 300 * and ignore the packet. 301 */ 302 if (BootAny) { 303 client = NULL; 304 } else if ((client=FindClient(&rconn))==NULL) { 305 syslog(LOG_INFO, 306 "%s: boot packet ignored", 307 EnetStr(&rconn)); 308 (void) sigsetmask(omask); 309 continue; 310 } 311 312 ProcessPacket(&rconn,client); 313 314 (void) sigsetmask(omask); 315 } 316 } 317 } 318 } 319 320 /* 321 ** DoTimeout -- Free any connections that have timed out. 322 ** 323 ** Parameters: 324 ** None. 325 ** 326 ** Returns: 327 ** Nothing. 328 ** 329 ** Side Effects: 330 ** - Timed out connections in `RmpConns' will be freed. 331 */ 332 void 333 DoTimeout() 334 { 335 register RMPCONN *rtmp; 336 struct timeval now; 337 338 (void) gettimeofday(&now, (struct timezone *)0); 339 340 /* 341 * For each active connection, if RMP_TIMEOUT seconds have passed 342 * since the last packet was sent, delete the connection. 343 */ 344 for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) 345 if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) { 346 syslog(LOG_WARNING, "%s: connection timed out (%u)", 347 EnetStr(rtmp), rtmp->rmp.r_type); 348 RemoveConn(rtmp); 349 } 350 } 351 352 /* 353 ** FindClient -- Find client associated with a packet. 354 ** 355 ** Parameters: 356 ** rconn - the new packet. 357 ** 358 ** Returns: 359 ** Pointer to client info if found, NULL otherwise. 360 ** 361 ** Side Effects: 362 ** None. 363 ** 364 ** Warnings: 365 ** - This routine must be called with SIGHUP blocked since 366 ** a reconfigure can invalidate the information returned. 367 */ 368 369 CLIENT * 370 FindClient(rconn) 371 register RMPCONN *rconn; 372 { 373 register CLIENT *ctmp; 374 375 for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) 376 if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], 377 (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) 378 break; 379 380 return(ctmp); 381 } 382 383 /* 384 ** Exit -- Log an error message and exit. 385 ** 386 ** Parameters: 387 ** sig - caught signal (or zero if not dying on a signal). 388 ** 389 ** Returns: 390 ** Does not return. 391 ** 392 ** Side Effects: 393 ** - This process ceases to exist. 394 */ 395 void 396 Exit(sig) 397 int sig; 398 { 399 if (sig > 0) 400 syslog(LOG_ERR, "going down on signal %d", sig); 401 else 402 syslog(LOG_ERR, "going down with fatal error"); 403 BpfClose(); 404 exit(1); 405 } 406 407 /* 408 ** ReConfig -- Get new list of boot files and reread config files. 409 ** 410 ** Parameters: 411 ** None. 412 ** 413 ** Returns: 414 ** Nothing. 415 ** 416 ** Side Effects: 417 ** - All active connections are dropped. 418 ** - List of boot-able files is changed. 419 ** - List of clients is changed. 420 ** 421 ** Warnings: 422 ** - This routine must be called with SIGHUP blocked. 423 */ 424 void 425 ReConfig(signo) 426 int signo; 427 { 428 syslog(LOG_NOTICE, "reconfiguring boot server"); 429 430 FreeConns(); 431 432 if (GetBootFiles() == 0) 433 Exit(0); 434 435 if (ParseConfig() == 0) 436 Exit(0); 437 } 438 439 /* 440 ** DebugOff -- Turn off debugging. 441 ** 442 ** Parameters: 443 ** None. 444 ** 445 ** Returns: 446 ** Nothing. 447 ** 448 ** Side Effects: 449 ** - Debug file is closed. 450 */ 451 void 452 DebugOff(signo) 453 int signo; 454 { 455 if (DbgFp != NULL) 456 (void) fclose(DbgFp); 457 458 DbgFp = NULL; 459 } 460 461 /* 462 ** DebugOn -- Turn on debugging. 463 ** 464 ** Parameters: 465 ** None. 466 ** 467 ** Returns: 468 ** Nothing. 469 ** 470 ** Side Effects: 471 ** - Debug file is opened/truncated if not already opened, 472 ** otherwise do nothing. 473 */ 474 void 475 DebugOn(signo) 476 int signo; 477 { 478 if (DbgFp == NULL) { 479 if ((DbgFp = fopen(DbgFile, "w")) == NULL) 480 syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); 481 } 482 } 483