rbootd.c revision 90377
11592Srgrimes/* 21592Srgrimes * Copyright (c) 1988, 1992 The University of Utah and the Center 31592Srgrimes * for Software Science (CSS). 41592Srgrimes * Copyright (c) 1992, 1993 51592Srgrimes * The Regents of the University of California. All rights reserved. 61592Srgrimes * 71592Srgrimes * This code is derived from software contributed to Berkeley by 81592Srgrimes * the Center for Software Science of the University of Utah Computer 91592Srgrimes * Science Department. CSS requests users of this software to return 101592Srgrimes * to css-dist@cs.utah.edu any improvements that they make and grant 111592Srgrimes * CSS redistribution rights. 121592Srgrimes * 131592Srgrimes * Redistribution and use in source and binary forms, with or without 141592Srgrimes * modification, are permitted provided that the following conditions 151592Srgrimes * are met: 161592Srgrimes * 1. Redistributions of source code must retain the above copyright 171592Srgrimes * notice, this list of conditions and the following disclaimer. 181592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 191592Srgrimes * notice, this list of conditions and the following disclaimer in the 201592Srgrimes * documentation and/or other materials provided with the distribution. 211592Srgrimes * 3. All advertising materials mentioning features or use of this software 221592Srgrimes * must display the following acknowledgement: 231592Srgrimes * This product includes software developed by the University of 241592Srgrimes * California, Berkeley and its contributors. 251592Srgrimes * 4. Neither the name of the University nor the names of its contributors 261592Srgrimes * may be used to endorse or promote products derived from this software 271592Srgrimes * without specific prior written permission. 281592Srgrimes * 291592Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 301592Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 311592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 321592Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 331592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 341592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 351592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 361592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 371592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 381592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 391592Srgrimes * SUCH DAMAGE. 401592Srgrimes * 4127077Ssteve * from: @(#)rbootd.c 8.1 (Berkeley) 6/4/93 421592Srgrimes * 4327077Ssteve * From: Utah Hdr: rbootd.c 3.1 92/07/06 441592Srgrimes * Author: Jeff Forys, University of Utah CSS 451592Srgrimes */ 461592Srgrimes 471592Srgrimes#ifndef lint 4827077Sstevestatic const char copyright[] = 491592Srgrimes"@(#) Copyright (c) 1992, 1993\n\ 501592Srgrimes The Regents of the University of California. All rights reserved.\n"; 511592Srgrimes#endif /* not lint */ 521592Srgrimes 531592Srgrimes#ifndef lint 5431386Scharnier#if 0 5527077Sstevestatic const char sccsid[] = "@(#)rbootd.c 8.1 (Berkeley) 6/4/93"; 5631386Scharnier#endif 5731386Scharnierstatic const char rcsid[] = 5850476Speter "$FreeBSD: head/libexec/rbootd/rbootd.c 90377 2002-02-07 23:57:01Z imp $"; 591592Srgrimes#endif /* not lint */ 601592Srgrimes 611592Srgrimes#include <sys/param.h> 621592Srgrimes#include <sys/time.h> 631592Srgrimes#include <ctype.h> 6427077Ssteve#include <err.h> 651592Srgrimes#include <errno.h> 661592Srgrimes#include <fcntl.h> 671592Srgrimes#include <signal.h> 681592Srgrimes#include <stdio.h> 691592Srgrimes#include <stdlib.h> 701592Srgrimes#include <string.h> 711592Srgrimes#include <syslog.h> 721592Srgrimes#include <unistd.h> 731592Srgrimes#include "defs.h" 741592Srgrimes 7590377Simpstatic void usage(void); 761592Srgrimes 771592Srgrimesint 7890377Simpmain(int argc, char *argv[]) 791592Srgrimes{ 801592Srgrimes int c, fd, omask, maxfds; 811592Srgrimes fd_set rset; 821592Srgrimes 831592Srgrimes /* 841592Srgrimes * Close any open file descriptors. 851592Srgrimes * Temporarily leave stdin & stdout open for `-d', 861592Srgrimes * and stderr open for any pre-syslog error messages. 871592Srgrimes */ 881592Srgrimes { 891592Srgrimes int i, nfds = getdtablesize(); 901592Srgrimes 911592Srgrimes for (i = 0; i < nfds; i++) 921592Srgrimes if (i != fileno(stdin) && i != fileno(stdout) && 931592Srgrimes i != fileno(stderr)) 941592Srgrimes (void) close(i); 951592Srgrimes } 961592Srgrimes 971592Srgrimes /* 981592Srgrimes * Parse any arguments. 991592Srgrimes */ 10024349Simp while ((c = getopt(argc, argv, "adi:")) != -1) 1011592Srgrimes switch(c) { 1021592Srgrimes case 'a': 1031592Srgrimes BootAny++; 1041592Srgrimes break; 1051592Srgrimes case 'd': 1061592Srgrimes DebugFlg++; 1071592Srgrimes break; 1081592Srgrimes case 'i': 1091592Srgrimes IntfName = optarg; 1101592Srgrimes break; 11131386Scharnier default: 11231386Scharnier usage(); 1131592Srgrimes } 1141592Srgrimes for (; optind < argc; optind++) { 1151592Srgrimes if (ConfigFile == NULL) 1161592Srgrimes ConfigFile = argv[optind]; 1171592Srgrimes else { 11831386Scharnier warnx("too many config files (`%s' ignored)", 11927077Ssteve argv[optind]); 1201592Srgrimes } 1211592Srgrimes } 1221592Srgrimes 1231592Srgrimes if (ConfigFile == NULL) /* use default config file */ 1241592Srgrimes ConfigFile = DfltConfig; 1251592Srgrimes 1261592Srgrimes if (DebugFlg) { 1271592Srgrimes DbgFp = stdout; /* output to stdout */ 1281592Srgrimes 1291592Srgrimes (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */ 1301592Srgrimes (void) signal(SIGUSR2, SIG_IGN); 13127077Ssteve (void) fclose(stderr); /* finished with it */ 1321592Srgrimes } else { 13327077Ssteve if (daemon(0, 0)) 13427077Ssteve err(1, "can't detach from terminal"); 1351592Srgrimes 1361592Srgrimes (void) signal(SIGUSR1, DebugOn); 1371592Srgrimes (void) signal(SIGUSR2, DebugOff); 1381592Srgrimes } 1391592Srgrimes 14031386Scharnier openlog("rbootd", LOG_PID, LOG_DAEMON); 1411592Srgrimes 1421592Srgrimes /* 1431592Srgrimes * If no interface was specified, get one now. 1441592Srgrimes * 1451592Srgrimes * This is convoluted because we want to get the default interface 1461592Srgrimes * name for the syslog("restarted") message. If BpfGetIntfName() 1471592Srgrimes * runs into an error, it will return a syslog-able error message 1481592Srgrimes * (in `errmsg') which will be displayed here. 1491592Srgrimes */ 1501592Srgrimes if (IntfName == NULL) { 1511592Srgrimes char *errmsg; 1521592Srgrimes 1531592Srgrimes if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) { 1541592Srgrimes syslog(LOG_NOTICE, "restarted (??)"); 15568894Skris /* BpfGetIntfName() returns safe names, using %m */ 15668894Skris syslog(LOG_ERR, "%s", errmsg); 1571592Srgrimes Exit(0); 1581592Srgrimes } 1591592Srgrimes } 1601592Srgrimes 1611592Srgrimes syslog(LOG_NOTICE, "restarted (%s)", IntfName); 1621592Srgrimes 1631592Srgrimes (void) signal(SIGHUP, ReConfig); 1641592Srgrimes (void) signal(SIGINT, Exit); 1651592Srgrimes (void) signal(SIGTERM, Exit); 1661592Srgrimes 1671592Srgrimes /* 1681592Srgrimes * Grab our host name and pid. 1691592Srgrimes */ 17045422Sbrian if (gethostname(MyHost, MAXHOSTNAMELEN - 1) < 0) { 1711592Srgrimes syslog(LOG_ERR, "gethostname: %m"); 1721592Srgrimes Exit(0); 1731592Srgrimes } 17445422Sbrian MyHost[MAXHOSTNAMELEN - 1] = '\0'; 1751592Srgrimes 1761592Srgrimes MyPid = getpid(); 1771592Srgrimes 1781592Srgrimes /* 1791592Srgrimes * Write proc's pid to a file. 1801592Srgrimes */ 1811592Srgrimes { 1821592Srgrimes FILE *fp; 1831592Srgrimes 1841592Srgrimes if ((fp = fopen(PidFile, "w")) != NULL) { 18527077Ssteve (void) fprintf(fp, "%d\n", (int) MyPid); 1861592Srgrimes (void) fclose(fp); 1871592Srgrimes } else { 1881592Srgrimes syslog(LOG_WARNING, "fopen: failed (%s)", PidFile); 1891592Srgrimes } 1901592Srgrimes } 1911592Srgrimes 1921592Srgrimes /* 1931592Srgrimes * All boot files are relative to the boot directory, we might 1941592Srgrimes * as well chdir() there to make life easier. 1951592Srgrimes */ 1961592Srgrimes if (chdir(BootDir) < 0) { 1971592Srgrimes syslog(LOG_ERR, "chdir: %m (%s)", BootDir); 1981592Srgrimes Exit(0); 1991592Srgrimes } 2001592Srgrimes 2011592Srgrimes /* 2021592Srgrimes * Initial configuration. 2031592Srgrimes */ 2041592Srgrimes omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */ 2051592Srgrimes if (GetBootFiles() == 0) /* get list of boot files */ 2061592Srgrimes Exit(0); 2071592Srgrimes if (ParseConfig() == 0) /* parse config file */ 2081592Srgrimes Exit(0); 2091592Srgrimes 2101592Srgrimes /* 2111592Srgrimes * Open and initialize a BPF device for the appropriate interface. 2121592Srgrimes * If an error is encountered, a message is displayed and Exit() 2131592Srgrimes * is called. 2141592Srgrimes */ 2151592Srgrimes fd = BpfOpen(); 2161592Srgrimes 2171592Srgrimes (void) sigsetmask(omask); /* allow reconfig's */ 2181592Srgrimes 2191592Srgrimes /* 2201592Srgrimes * Main loop: receive a packet, determine where it came from, 2211592Srgrimes * and if we service this host, call routine to handle request. 2221592Srgrimes */ 2231592Srgrimes maxfds = fd + 1; 2241592Srgrimes FD_ZERO(&rset); 2251592Srgrimes FD_SET(fd, &rset); 2261592Srgrimes for (;;) { 2271592Srgrimes struct timeval timeout; 2281592Srgrimes fd_set r; 2291592Srgrimes int nsel; 2301592Srgrimes 2311592Srgrimes r = rset; 2321592Srgrimes 2331592Srgrimes if (RmpConns == NULL) { /* timeout isnt necessary */ 23427077Ssteve nsel = select(maxfds, &r, NULL, NULL, NULL); 2351592Srgrimes } else { 2361592Srgrimes timeout.tv_sec = RMP_TIMEOUT; 2371592Srgrimes timeout.tv_usec = 0; 23827077Ssteve nsel = select(maxfds, &r, NULL, NULL, &timeout); 2391592Srgrimes } 2401592Srgrimes 2411592Srgrimes if (nsel < 0) { 2421592Srgrimes if (errno == EINTR) 2431592Srgrimes continue; 2441592Srgrimes syslog(LOG_ERR, "select: %m"); 2451592Srgrimes Exit(0); 2461592Srgrimes } else if (nsel == 0) { /* timeout */ 2471592Srgrimes DoTimeout(); /* clear stale conns */ 2481592Srgrimes continue; 2491592Srgrimes } 2501592Srgrimes 2511592Srgrimes if (FD_ISSET(fd, &r)) { 2521592Srgrimes RMPCONN rconn; 2531592Srgrimes CLIENT *client, *FindClient(); 2541592Srgrimes int doread = 1; 2551592Srgrimes 2561592Srgrimes while (BpfRead(&rconn, doread)) { 2571592Srgrimes doread = 0; 2581592Srgrimes 2591592Srgrimes if (DbgFp != NULL) /* display packet */ 2601592Srgrimes DispPkt(&rconn,DIR_RCVD); 2611592Srgrimes 2621592Srgrimes omask = sigblock(sigmask(SIGHUP)); 2631592Srgrimes 2641592Srgrimes /* 2651592Srgrimes * If we do not restrict service, set the 2661592Srgrimes * client to NULL (ProcessPacket() handles 2671592Srgrimes * this). Otherwise, check that we can 2681592Srgrimes * service this host; if not, log a message 2691592Srgrimes * and ignore the packet. 2701592Srgrimes */ 2711592Srgrimes if (BootAny) { 2721592Srgrimes client = NULL; 2731592Srgrimes } else if ((client=FindClient(&rconn))==NULL) { 2741592Srgrimes syslog(LOG_INFO, 2751592Srgrimes "%s: boot packet ignored", 2761592Srgrimes EnetStr(&rconn)); 2771592Srgrimes (void) sigsetmask(omask); 2781592Srgrimes continue; 2791592Srgrimes } 2801592Srgrimes 2811592Srgrimes ProcessPacket(&rconn,client); 2821592Srgrimes 2831592Srgrimes (void) sigsetmask(omask); 2841592Srgrimes } 2851592Srgrimes } 2861592Srgrimes } 2871592Srgrimes} 2881592Srgrimes 28931386Scharnierstatic void 29090377Simpusage(void) 29131386Scharnier{ 29231386Scharnier fprintf(stderr, "usage: rbootd [-ad] [-i interface] [config_file]\n"); 29331386Scharnier exit (1); 29431386Scharnier} 29531386Scharnier 2961592Srgrimes/* 2971592Srgrimes** DoTimeout -- Free any connections that have timed out. 2981592Srgrimes** 2991592Srgrimes** Parameters: 3001592Srgrimes** None. 3011592Srgrimes** 3021592Srgrimes** Returns: 3031592Srgrimes** Nothing. 3041592Srgrimes** 3051592Srgrimes** Side Effects: 3061592Srgrimes** - Timed out connections in `RmpConns' will be freed. 3071592Srgrimes*/ 3081592Srgrimesvoid 30990377SimpDoTimeout(void) 3101592Srgrimes{ 31127079Ssteve RMPCONN *rtmp; 3121592Srgrimes struct timeval now; 3131592Srgrimes 3141592Srgrimes (void) gettimeofday(&now, (struct timezone *)0); 3151592Srgrimes 3161592Srgrimes /* 3171592Srgrimes * For each active connection, if RMP_TIMEOUT seconds have passed 3181592Srgrimes * since the last packet was sent, delete the connection. 3191592Srgrimes */ 3201592Srgrimes for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next) 3211592Srgrimes if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) { 3221592Srgrimes syslog(LOG_WARNING, "%s: connection timed out (%u)", 3231592Srgrimes EnetStr(rtmp), rtmp->rmp.r_type); 3241592Srgrimes RemoveConn(rtmp); 3251592Srgrimes } 3261592Srgrimes} 3271592Srgrimes 3281592Srgrimes/* 3291592Srgrimes** FindClient -- Find client associated with a packet. 3301592Srgrimes** 3311592Srgrimes** Parameters: 3328870Srgrimes** rconn - the new packet. 3331592Srgrimes** 3341592Srgrimes** Returns: 3351592Srgrimes** Pointer to client info if found, NULL otherwise. 3361592Srgrimes** 3371592Srgrimes** Side Effects: 3381592Srgrimes** None. 3391592Srgrimes** 3401592Srgrimes** Warnings: 3411592Srgrimes** - This routine must be called with SIGHUP blocked since 3421592Srgrimes** a reconfigure can invalidate the information returned. 3431592Srgrimes*/ 3441592Srgrimes 3451592SrgrimesCLIENT * 34690377SimpFindClient(RMPCONN *rconn) 3471592Srgrimes{ 34827079Ssteve CLIENT *ctmp; 3491592Srgrimes 3501592Srgrimes for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next) 3511592Srgrimes if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0], 3521592Srgrimes (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0) 3531592Srgrimes break; 3541592Srgrimes 3551592Srgrimes return(ctmp); 3561592Srgrimes} 3571592Srgrimes 3581592Srgrimes/* 3591592Srgrimes** Exit -- Log an error message and exit. 3601592Srgrimes** 3611592Srgrimes** Parameters: 3621592Srgrimes** sig - caught signal (or zero if not dying on a signal). 3631592Srgrimes** 3641592Srgrimes** Returns: 3651592Srgrimes** Does not return. 3661592Srgrimes** 3671592Srgrimes** Side Effects: 3681592Srgrimes** - This process ceases to exist. 3691592Srgrimes*/ 3701592Srgrimesvoid 37190377SimpExit(int sig) 3721592Srgrimes{ 3731592Srgrimes if (sig > 0) 3741592Srgrimes syslog(LOG_ERR, "going down on signal %d", sig); 3751592Srgrimes else 3761592Srgrimes syslog(LOG_ERR, "going down with fatal error"); 3771592Srgrimes BpfClose(); 3781592Srgrimes exit(1); 3791592Srgrimes} 3801592Srgrimes 3811592Srgrimes/* 3821592Srgrimes** ReConfig -- Get new list of boot files and reread config files. 3831592Srgrimes** 3841592Srgrimes** Parameters: 3851592Srgrimes** None. 3861592Srgrimes** 3871592Srgrimes** Returns: 3881592Srgrimes** Nothing. 3891592Srgrimes** 3901592Srgrimes** Side Effects: 3911592Srgrimes** - All active connections are dropped. 3921592Srgrimes** - List of boot-able files is changed. 3931592Srgrimes** - List of clients is changed. 3941592Srgrimes** 3951592Srgrimes** Warnings: 3961592Srgrimes** - This routine must be called with SIGHUP blocked. 3971592Srgrimes*/ 3981592Srgrimesvoid 39990377SimpReConfig(int signo) 4001592Srgrimes{ 4011592Srgrimes syslog(LOG_NOTICE, "reconfiguring boot server"); 4021592Srgrimes 4031592Srgrimes FreeConns(); 4041592Srgrimes 4051592Srgrimes if (GetBootFiles() == 0) 4061592Srgrimes Exit(0); 4071592Srgrimes 4081592Srgrimes if (ParseConfig() == 0) 4091592Srgrimes Exit(0); 4101592Srgrimes} 4111592Srgrimes 4121592Srgrimes/* 4131592Srgrimes** DebugOff -- Turn off debugging. 4141592Srgrimes** 4151592Srgrimes** Parameters: 4161592Srgrimes** None. 4171592Srgrimes** 4181592Srgrimes** Returns: 4191592Srgrimes** Nothing. 4201592Srgrimes** 4211592Srgrimes** Side Effects: 4221592Srgrimes** - Debug file is closed. 4231592Srgrimes*/ 4241592Srgrimesvoid 42590377SimpDebugOff(int signo) 4261592Srgrimes{ 4271592Srgrimes if (DbgFp != NULL) 4281592Srgrimes (void) fclose(DbgFp); 4291592Srgrimes 4301592Srgrimes DbgFp = NULL; 4311592Srgrimes} 4321592Srgrimes 4331592Srgrimes/* 4341592Srgrimes** DebugOn -- Turn on debugging. 4351592Srgrimes** 4361592Srgrimes** Parameters: 4371592Srgrimes** None. 4381592Srgrimes** 4391592Srgrimes** Returns: 4401592Srgrimes** Nothing. 4411592Srgrimes** 4421592Srgrimes** Side Effects: 4431592Srgrimes** - Debug file is opened/truncated if not already opened, 4441592Srgrimes** otherwise do nothing. 4451592Srgrimes*/ 4461592Srgrimesvoid 44790377SimpDebugOn(int signo) 4481592Srgrimes{ 4491592Srgrimes if (DbgFp == NULL) { 4501592Srgrimes if ((DbgFp = fopen(DbgFile, "w")) == NULL) 4511592Srgrimes syslog(LOG_ERR, "can't open debug file (%s)", DbgFile); 4521592Srgrimes } 4531592Srgrimes} 454