Home | History | Annotate | Line # | Download | only in rbootd
rbootd.c revision 1.3
      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 (at) cs.utah.edu any improvements that they make and grant
     11  * CSS redistribution rights.
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  * 3. All advertising materials mentioning features or use of this software
     22  *    must display the following acknowledgement:
     23  *	This product includes software developed by the University of
     24  *	California, Berkeley and its contributors.
     25  * 4. Neither the name of the University nor the names of its contributors
     26  *    may be used to endorse or promote products derived from this software
     27  *    without specific prior written permission.
     28  *
     29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     39  * SUCH DAMAGE.
     40  *
     41  *	from: @(#)rbootd.c	8.1 (Berkeley) 6/4/93
     42  *	      $Id: rbootd.c,v 1.3 1995/08/21 16:57:57 thorpej Exp $
     43  *
     44  * From: Utah Hdr: rbootd.c 3.1 92/07/06
     45  * Author: Jeff Forys, University of Utah CSS
     46  */
     47 
     48 #ifndef lint
     49 static char copyright[] =
     50 "@(#) Copyright (c) 1992, 1993\n\
     51 	The Regents of the University of California.  All rights reserved.\n";
     52 #endif /* not lint */
     53 
     54 #ifndef lint
     55 /*static char sccsid[] = "@(#)rbootd.c	8.1 (Berkeley) 6/4/93";*/
     56 static char rcsid[] = "$Id: rbootd.c,v 1.3 1995/08/21 16:57:57 thorpej Exp $";
     57 #endif /* not lint */
     58 
     59 #include <sys/param.h>
     60 #include <sys/time.h>
     61 #include <ctype.h>
     62 #include <err.h>
     63 #include <errno.h>
     64 #include <fcntl.h>
     65 #include <signal.h>
     66 #include <stdio.h>
     67 #include <stdlib.h>
     68 #include <string.h>
     69 #include <syslog.h>
     70 #include <unistd.h>
     71 #include "defs.h"
     72 
     73 extern	char *__progname;	/* from crt0.o */
     74 
     75 int
     76 main(argc, argv)
     77 	int argc;
     78 	char *argv[];
     79 {
     80 	int c, fd, omask, maxfds;
     81 	fd_set rset;
     82 
     83 	/*
     84 	 *  Close any open file descriptors.
     85 	 *  Temporarily leave stdin & stdout open for `-d',
     86 	 *  and stderr open for any pre-syslog error messages.
     87 	 */
     88 	{
     89 		int i, nfds = getdtablesize();
     90 
     91 		for (i = 0; i < nfds; i++)
     92 			if (i != fileno(stdin) && i != fileno(stdout) &&
     93 			    i != fileno(stderr))
     94 				(void) close(i);
     95 	}
     96 
     97 	/*
     98 	 *  Parse any arguments.
     99 	 */
    100 	while ((c = getopt(argc, argv, "adi:")) != EOF)
    101 		switch(c) {
    102 		    case 'a':
    103 			BootAny++;
    104 			break;
    105 		    case 'd':
    106 			DebugFlg++;
    107 			break;
    108 		    case 'i':
    109 			IntfName = optarg;
    110 			break;
    111 		}
    112 	for (; optind < argc; optind++) {
    113 		if (ConfigFile == NULL)
    114 			ConfigFile = argv[optind];
    115 		else {
    116 			warnx("too many config files (`%s' ignored)\n",
    117 			    argv[optind]);
    118 		}
    119 	}
    120 
    121 	if (ConfigFile == NULL)			/* use default config file */
    122 		ConfigFile = DfltConfig;
    123 
    124 	if (DebugFlg) {
    125 		DbgFp = stdout;				/* output to stdout */
    126 
    127 		(void) signal(SIGUSR1, SIG_IGN);	/* dont muck w/DbgFp */
    128 		(void) signal(SIGUSR2, SIG_IGN);
    129 		(void) fclose(stderr);			/* finished with it */
    130 	} else {
    131 		if (daemon(0, 0))
    132 			err(1, "can't detach from terminal");
    133 
    134 		(void) signal(SIGUSR1, DebugOn);
    135 		(void) signal(SIGUSR2, DebugOff);
    136 	}
    137 
    138 	openlog(__progname, LOG_PID, LOG_DAEMON);
    139 
    140 	/*
    141 	 *  If no interface was specified, get one now.
    142 	 *
    143 	 *  This is convoluted because we want to get the default interface
    144 	 *  name for the syslog("restarted") message.  If BpfGetIntfName()
    145 	 *  runs into an error, it will return a syslog-able error message
    146 	 *  (in `errmsg') which will be displayed here.
    147 	 */
    148 	if (IntfName == NULL) {
    149 		char *errmsg;
    150 
    151 		if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
    152 			syslog(LOG_NOTICE, "restarted (??)");
    153 			syslog(LOG_ERR, errmsg);
    154 			Exit(0);
    155 		}
    156 	}
    157 
    158 	syslog(LOG_NOTICE, "restarted (%s)", IntfName);
    159 
    160 	(void) signal(SIGHUP, ReConfig);
    161 	(void) signal(SIGINT, Exit);
    162 	(void) signal(SIGTERM, Exit);
    163 
    164 	/*
    165 	 *  Grab our host name and pid.
    166 	 */
    167 	if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) {
    168 		syslog(LOG_ERR, "gethostname: %m");
    169 		Exit(0);
    170 	}
    171 	MyHost[MAXHOSTNAMELEN] = '\0';
    172 
    173 	MyPid = getpid();
    174 
    175 	/*
    176 	 *  Write proc's pid to a file.
    177 	 */
    178 	{
    179 		FILE *fp;
    180 
    181 		if ((fp = fopen(PidFile, "w")) != NULL) {
    182 			(void) fprintf(fp, "%d\n", MyPid);
    183 			(void) fclose(fp);
    184 		} else {
    185 			syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
    186 		}
    187 	}
    188 
    189 	/*
    190 	 *  All boot files are relative to the boot directory, we might
    191 	 *  as well chdir() there to make life easier.
    192 	 */
    193 	if (chdir(BootDir) < 0) {
    194 		syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
    195 		Exit(0);
    196 	}
    197 
    198 	/*
    199 	 *  Initial configuration.
    200 	 */
    201 	omask = sigblock(sigmask(SIGHUP));	/* prevent reconfig's */
    202 	if (GetBootFiles() == 0)		/* get list of boot files */
    203 		Exit(0);
    204 	if (ParseConfig() == 0)			/* parse config file */
    205 		Exit(0);
    206 
    207 	/*
    208 	 *  Open and initialize a BPF device for the appropriate interface.
    209 	 *  If an error is encountered, a message is displayed and Exit()
    210 	 *  is called.
    211 	 */
    212 	fd = BpfOpen();
    213 
    214 	(void) sigsetmask(omask);		/* allow reconfig's */
    215 
    216 	/*
    217 	 *  Main loop: receive a packet, determine where it came from,
    218 	 *  and if we service this host, call routine to handle request.
    219 	 */
    220 	maxfds = fd + 1;
    221 	FD_ZERO(&rset);
    222 	FD_SET(fd, &rset);
    223 	for (;;) {
    224 		struct timeval timeout;
    225 		fd_set r;
    226 		int nsel;
    227 
    228 		r = rset;
    229 
    230 		if (RmpConns == NULL) {		/* timeout isnt necessary */
    231 			nsel = select(maxfds, &r, NULL, NULL, NULL);
    232 		} else {
    233 			timeout.tv_sec = RMP_TIMEOUT;
    234 			timeout.tv_usec = 0;
    235 			nsel = select(maxfds, &r, NULL, NULL, &timeout);
    236 		}
    237 
    238 		if (nsel < 0) {
    239 			if (errno == EINTR)
    240 				continue;
    241 			syslog(LOG_ERR, "select: %m");
    242 			Exit(0);
    243 		} else if (nsel == 0) {		/* timeout */
    244 			DoTimeout();			/* clear stale conns */
    245 			continue;
    246 		}
    247 
    248 		if (FD_ISSET(fd, &r)) {
    249 			RMPCONN rconn;
    250 			CLIENT *client, *FindClient();
    251 			int doread = 1;
    252 
    253 			while (BpfRead(&rconn, doread)) {
    254 				doread = 0;
    255 
    256 				if (DbgFp != NULL)	/* display packet */
    257 					DispPkt(&rconn,DIR_RCVD);
    258 
    259 				omask = sigblock(sigmask(SIGHUP));
    260 
    261 				/*
    262 				 *  If we do not restrict service, set the
    263 				 *  client to NULL (ProcessPacket() handles
    264 				 *  this).  Otherwise, check that we can
    265 				 *  service this host; if not, log a message
    266 				 *  and ignore the packet.
    267 				 */
    268 				if (BootAny) {
    269 					client = NULL;
    270 				} else if ((client=FindClient(&rconn))==NULL) {
    271 					syslog(LOG_INFO,
    272 					       "%s: boot packet ignored",
    273 					       EnetStr(&rconn));
    274 					(void) sigsetmask(omask);
    275 					continue;
    276 				}
    277 
    278 				ProcessPacket(&rconn,client);
    279 
    280 				(void) sigsetmask(omask);
    281 			}
    282 		}
    283 	}
    284 }
    285 
    286 /*
    287 **  DoTimeout -- Free any connections that have timed out.
    288 **
    289 **	Parameters:
    290 **		None.
    291 **
    292 **	Returns:
    293 **		Nothing.
    294 **
    295 **	Side Effects:
    296 **		- Timed out connections in `RmpConns' will be freed.
    297 */
    298 void
    299 DoTimeout()
    300 {
    301 	register RMPCONN *rtmp;
    302 	struct timeval now;
    303 
    304 	(void) gettimeofday(&now, (struct timezone *)0);
    305 
    306 	/*
    307 	 *  For each active connection, if RMP_TIMEOUT seconds have passed
    308 	 *  since the last packet was sent, delete the connection.
    309 	 */
    310 	for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
    311 		if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
    312 			syslog(LOG_WARNING, "%s: connection timed out (%u)",
    313 			       EnetStr(rtmp), rtmp->rmp.r_type);
    314 			RemoveConn(rtmp);
    315 		}
    316 }
    317 
    318 /*
    319 **  FindClient -- Find client associated with a packet.
    320 **
    321 **	Parameters:
    322 **		rconn - the new packet.
    323 **
    324 **	Returns:
    325 **		Pointer to client info if found, NULL otherwise.
    326 **
    327 **	Side Effects:
    328 **		None.
    329 **
    330 **	Warnings:
    331 **		- This routine must be called with SIGHUP blocked since
    332 **		  a reconfigure can invalidate the information returned.
    333 */
    334 
    335 CLIENT *
    336 FindClient(rconn)
    337 	register RMPCONN *rconn;
    338 {
    339 	register CLIENT *ctmp;
    340 
    341 	for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
    342 		if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
    343 		         (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
    344 			break;
    345 
    346 	return(ctmp);
    347 }
    348 
    349 /*
    350 **  Exit -- Log an error message and exit.
    351 **
    352 **	Parameters:
    353 **		sig - caught signal (or zero if not dying on a signal).
    354 **
    355 **	Returns:
    356 **		Does not return.
    357 **
    358 **	Side Effects:
    359 **		- This process ceases to exist.
    360 */
    361 void
    362 Exit(sig)
    363 	int sig;
    364 {
    365 	if (sig > 0)
    366 		syslog(LOG_ERR, "going down on signal %d", sig);
    367 	else
    368 		syslog(LOG_ERR, "going down with fatal error");
    369 	BpfClose();
    370 	exit(1);
    371 }
    372 
    373 /*
    374 **  ReConfig -- Get new list of boot files and reread config files.
    375 **
    376 **	Parameters:
    377 **		None.
    378 **
    379 **	Returns:
    380 **		Nothing.
    381 **
    382 **	Side Effects:
    383 **		- All active connections are dropped.
    384 **		- List of boot-able files is changed.
    385 **		- List of clients is changed.
    386 **
    387 **	Warnings:
    388 **		- This routine must be called with SIGHUP blocked.
    389 */
    390 void
    391 ReConfig(signo)
    392 	int signo;
    393 {
    394 	syslog(LOG_NOTICE, "reconfiguring boot server");
    395 
    396 	FreeConns();
    397 
    398 	if (GetBootFiles() == 0)
    399 		Exit(0);
    400 
    401 	if (ParseConfig() == 0)
    402 		Exit(0);
    403 }
    404 
    405 /*
    406 **  DebugOff -- Turn off debugging.
    407 **
    408 **	Parameters:
    409 **		None.
    410 **
    411 **	Returns:
    412 **		Nothing.
    413 **
    414 **	Side Effects:
    415 **		- Debug file is closed.
    416 */
    417 void
    418 DebugOff(signo)
    419 	int signo;
    420 {
    421 	if (DbgFp != NULL)
    422 		(void) fclose(DbgFp);
    423 
    424 	DbgFp = NULL;
    425 }
    426 
    427 /*
    428 **  DebugOn -- Turn on debugging.
    429 **
    430 **	Parameters:
    431 **		None.
    432 **
    433 **	Returns:
    434 **		Nothing.
    435 **
    436 **	Side Effects:
    437 **		- Debug file is opened/truncated if not already opened,
    438 **		  otherwise do nothing.
    439 */
    440 void
    441 DebugOn(signo)
    442 	int signo;
    443 {
    444 	if (DbgFp == NULL) {
    445 		if ((DbgFp = fopen(DbgFile, "w")) == NULL)
    446 			syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
    447 	}
    448 }
    449