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