rbootd.c revision 1.18
1/*	$NetBSD: rbootd.c,v 1.18 2002/09/23 12:48:07 mycroft 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@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
58static char sccsid[] = "@(#)rbootd.c	8.1 (Berkeley) 6/4/93";
59#else
60__RCSID("$NetBSD: rbootd.c,v 1.18 2002/09/23 12:48:07 mycroft Exp $");
61#endif
62#endif /* not lint */
63
64#include <sys/param.h>
65#include <sys/time.h>
66#include <poll.h>
67#include <ctype.h>
68#include <err.h>
69#include <errno.h>
70#include <fcntl.h>
71#include <signal.h>
72#include <stdio.h>
73#include <stdlib.h>
74#include <string.h>
75#include <syslog.h>
76#include <unistd.h>
77#include <util.h>
78#include "defs.h"
79
80int	main __P((int, char *[]));
81
82int
83main(argc, argv)
84	int argc;
85	char *argv[];
86{
87	int c, fd, omask;
88	struct pollfd set[1];
89
90	/*
91	 *  Close any open file descriptors.
92	 *  Temporarily leave stdin & stdout open for `-d',
93	 *  and stderr open for any pre-syslog error messages.
94	 */
95	{
96		int i, nfds = getdtablesize();
97
98		for (i = 0; i < nfds; i++)
99			if (i != STDIN_FILENO && i != STDOUT_FILENO &&
100			    i != STDERR_FILENO)
101				(void) close(i);
102	}
103
104	/*
105	 *  Parse any arguments.
106	 */
107	while ((c = getopt(argc, argv, "adi:")) != -1)
108		switch(c) {
109		    case 'a':
110			BootAny++;
111			break;
112		    case 'd':
113			DebugFlg++;
114			break;
115		    case 'i':
116			IntfName = optarg;
117			break;
118		}
119	for (; optind < argc; optind++) {
120		if (ConfigFile == NULL)
121			ConfigFile = argv[optind];
122		else {
123			warnx("too many config files (`%s' ignored)",
124			    argv[optind]);
125		}
126	}
127
128	if (ConfigFile == NULL)			/* use default config file */
129		ConfigFile = DfltConfig;
130
131	if (DebugFlg) {
132		DbgFp = stdout;				/* output to stdout */
133
134		(void) signal(SIGUSR1, SIG_IGN);	/* dont muck w/DbgFp */
135		(void) signal(SIGUSR2, SIG_IGN);
136		(void) fclose(stderr);			/* finished with it */
137	} else {
138		if (daemon(0, 0))
139			err(1, "can't detach from terminal");
140		pidfile(NULL);
141
142		(void) signal(SIGUSR1, DebugOn);
143		(void) signal(SIGUSR2, DebugOff);
144	}
145
146	openlog("rbootd", LOG_PID, LOG_DAEMON);
147
148	/*
149	 *  If no interface was specified, get one now.
150	 *
151	 *  This is convoluted because we want to get the default interface
152	 *  name for the syslog("restarted") message.  If BpfGetIntfName()
153	 *  runs into an error, it will return a syslog-able error message
154	 *  (in `errmsg') which will be displayed here.
155	 */
156	if (IntfName == NULL) {
157		char *errmsg;
158
159		if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
160			/* backslash to avoid trigraph ??) */
161			syslog(LOG_NOTICE, "restarted (?\?)");
162			syslog(LOG_ERR, errmsg);
163			Exit(0);
164		}
165	}
166
167	syslog(LOG_NOTICE, "restarted (%s)", IntfName);
168
169	(void) signal(SIGHUP, ReConfig);
170	(void) signal(SIGINT, Exit);
171	(void) signal(SIGTERM, Exit);
172
173	/*
174	 *  Grab our host name and pid.
175	 */
176	if (gethostname(MyHost, sizeof MyHost) < 0) {
177		syslog(LOG_ERR, "gethostname: %m");
178		Exit(0);
179	}
180	MyHost[sizeof(MyHost) - 1] = '\0';
181
182	/*
183	 *  All boot files are relative to the boot directory, we might
184	 *  as well chdir() there to make life easier.
185	 */
186	if (chdir(BootDir) < 0) {
187		syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
188		Exit(0);
189	}
190
191	/*
192	 *  Initial configuration.
193	 */
194	omask = sigblock(sigmask(SIGHUP));	/* prevent reconfig's */
195	if (GetBootFiles() == 0)		/* get list of boot files */
196		Exit(0);
197	if (ParseConfig() == 0)			/* parse config file */
198		Exit(0);
199
200	/*
201	 *  Open and initialize a BPF device for the appropriate interface.
202	 *  If an error is encountered, a message is displayed and Exit()
203	 *  is called.
204	 */
205	fd = BpfOpen();
206
207	(void) sigsetmask(omask);		/* allow reconfig's */
208
209	/*
210	 *  Main loop: receive a packet, determine where it came from,
211	 *  and if we service this host, call routine to handle request.
212	 */
213	set[0].fd = fd;
214	set[0].events = POLLIN;
215	for (;;) {
216		int nsel;
217
218		nsel = poll(set, 1, RmpConns ? RMP_TIMEOUT * 1000 : INFTIM);
219
220		if (nsel < 0) {
221			if (errno == EINTR)
222				continue;
223			syslog(LOG_ERR, "poll: %m");
224			Exit(0);
225		} else if (nsel == 0) {		/* timeout */
226			DoTimeout();			/* clear stale conns */
227			continue;
228		}
229
230		if (set[0].revents & POLLIN) {
231			RMPCONN rconn;
232			CLIENT *client;
233			int doread = 1;
234
235			while (BpfRead(&rconn, doread)) {
236				doread = 0;
237
238				if (DbgFp != NULL)	/* display packet */
239					DispPkt(&rconn,DIR_RCVD);
240
241				omask = sigblock(sigmask(SIGHUP));
242
243				/*
244				 *  If we do not restrict service, set the
245				 *  client to NULL (ProcessPacket() handles
246				 *  this).  Otherwise, check that we can
247				 *  service this host; if not, log a message
248				 *  and ignore the packet.
249				 */
250				if (BootAny) {
251					client = NULL;
252				} else if ((client=FindClient(&rconn))==NULL) {
253					syslog(LOG_INFO,
254					       "%s: boot packet ignored",
255					       EnetStr(&rconn));
256					(void) sigsetmask(omask);
257					continue;
258				}
259
260				ProcessPacket(&rconn,client);
261
262				(void) sigsetmask(omask);
263			}
264		}
265	}
266}
267
268/*
269**  DoTimeout -- Free any connections that have timed out.
270**
271**	Parameters:
272**		None.
273**
274**	Returns:
275**		Nothing.
276**
277**	Side Effects:
278**		- Timed out connections in `RmpConns' will be freed.
279*/
280void
281DoTimeout()
282{
283	RMPCONN *rtmp;
284	struct timeval now;
285
286	(void) gettimeofday(&now, (struct timezone *)0);
287
288	/*
289	 *  For each active connection, if RMP_TIMEOUT seconds have passed
290	 *  since the last packet was sent, delete the connection.
291	 */
292	for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
293		if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
294			syslog(LOG_WARNING, "%s: connection timed out (%u)",
295			       EnetStr(rtmp), rtmp->rmp.r_type);
296			RemoveConn(rtmp);
297		}
298}
299
300/*
301**  FindClient -- Find client associated with a packet.
302**
303**	Parameters:
304**		rconn - the new packet.
305**
306**	Returns:
307**		Pointer to client info if found, NULL otherwise.
308**
309**	Side Effects:
310**		None.
311**
312**	Warnings:
313**		- This routine must be called with SIGHUP blocked since
314**		  a reconfigure can invalidate the information returned.
315*/
316
317CLIENT *
318FindClient(rconn)
319	RMPCONN *rconn;
320{
321	CLIENT *ctmp;
322
323	for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
324		if (memcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
325		         (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
326			break;
327
328	return(ctmp);
329}
330
331/*
332**  Exit -- Log an error message and exit.
333**
334**	Parameters:
335**		sig - caught signal (or zero if not dying on a signal).
336**
337**	Returns:
338**		Does not return.
339**
340**	Side Effects:
341**		- This process ceases to exist.
342*/
343void
344Exit(sig)
345	int sig;
346{
347	if (sig > 0)
348		syslog(LOG_ERR, "going down on signal %d", sig);
349	else
350		syslog(LOG_ERR, "going down with fatal error");
351	BpfClose();
352	exit(1);
353}
354
355/*
356**  ReConfig -- Get new list of boot files and reread config files.
357**
358**	Parameters:
359**		None.
360**
361**	Returns:
362**		Nothing.
363**
364**	Side Effects:
365**		- All active connections are dropped.
366**		- List of boot-able files is changed.
367**		- List of clients is changed.
368**
369**	Warnings:
370**		- This routine must be called with SIGHUP blocked.
371*/
372void
373ReConfig(signo)
374	int signo;
375{
376	syslog(LOG_NOTICE, "reconfiguring boot server");
377
378	FreeConns();
379
380	if (GetBootFiles() == 0)
381		Exit(0);
382
383	if (ParseConfig() == 0)
384		Exit(0);
385}
386
387/*
388**  DebugOff -- Turn off debugging.
389**
390**	Parameters:
391**		None.
392**
393**	Returns:
394**		Nothing.
395**
396**	Side Effects:
397**		- Debug file is closed.
398*/
399void
400DebugOff(signo)
401	int signo;
402{
403	if (DbgFp != NULL)
404		(void) fclose(DbgFp);
405
406	DbgFp = NULL;
407}
408
409/*
410**  DebugOn -- Turn on debugging.
411**
412**	Parameters:
413**		None.
414**
415**	Returns:
416**		Nothing.
417**
418**	Side Effects:
419**		- Debug file is opened/truncated if not already opened,
420**		  otherwise do nothing.
421*/
422void
423DebugOn(signo)
424	int signo;
425{
426	if (DbgFp == NULL) {
427		if ((DbgFp = fopen(DbgFile, "w")) == NULL)
428			syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
429	}
430}
431