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