155575Sbostic /*
255575Sbostic * Copyright (c) 1988, 1992 The University of Utah and the Center
355575Sbostic * for Software Science (CSS).
461446Sbostic * Copyright (c) 1992, 1993
561446Sbostic * The Regents of the University of California. All rights reserved.
655575Sbostic *
755575Sbostic * This code is derived from software contributed to Berkeley by
855575Sbostic * the Center for Software Science of the University of Utah Computer
955575Sbostic * Science Department. CSS requests users of this software to return
1055575Sbostic * to css-dist@cs.utah.edu any improvements that they make and grant
1155575Sbostic * CSS redistribution rights.
1255575Sbostic *
1355575Sbostic * %sccs.include.redist.c%
1455575Sbostic *
15*66233Sbostic * @(#)rbootd.c 8.2 (Berkeley) 02/22/94
1655575Sbostic *
1755575Sbostic * Utah $Hdr: rbootd.c 3.1 92/07/06$
1855575Sbostic * Author: Jeff Forys, University of Utah CSS
1955575Sbostic */
2055575Sbostic
2155575Sbostic #ifndef lint
2261446Sbostic static char copyright[] =
2361446Sbostic "@(#) Copyright (c) 1992, 1993\n\
2461446Sbostic The Regents of the University of California. All rights reserved.\n";
2555575Sbostic #endif /* not lint */
2655575Sbostic
2761445Sbostic #ifndef lint
28*66233Sbostic static char sccsid[] = "@(#)rbootd.c 8.2 (Berkeley) 02/22/94";
2961445Sbostic #endif /* not lint */
3061445Sbostic
3155600Sbostic #include <sys/param.h>
3255575Sbostic #include <sys/ioctl.h>
33*66233Sbostic #include <sys/time.h>
3455575Sbostic
3555600Sbostic #include <ctype.h>
3655575Sbostic #include <errno.h>
3755600Sbostic #include <fcntl.h>
3855600Sbostic #include <signal.h>
3955600Sbostic #include <stdio.h>
4055600Sbostic #include <stdlib.h>
4155600Sbostic #include <string.h>
4255575Sbostic #include <syslog.h>
4355600Sbostic #include <unistd.h>
4455600Sbostic #include "defs.h"
4555575Sbostic
4655600Sbostic
4755575Sbostic /* fd mask macros (backward compatibility with 4.2BSD) */
4855575Sbostic #ifndef FD_SET
4955575Sbostic #ifdef notdef
5055575Sbostic typedef struct fd_set { /* this should already be in 4.2 */
5155575Sbostic int fds_bits[1];
5255575Sbostic } fd_set;
5355575Sbostic #endif
5455575Sbostic #define FD_ZERO(p) ((p)->fds_bits[0] = 0)
5555575Sbostic #define FD_SET(n, p) ((p)->fds_bits[0] |= (1 << (n)))
5655575Sbostic #define FD_CLR(n, p) ((p)->fds_bits[0] &= ~(1 << (n)))
5755575Sbostic #define FD_ISSET(n, p) ((p)->fds_bits[0] & (1 << (n)))
5855575Sbostic #endif
5955575Sbostic
6055600Sbostic int
main(argc,argv)6155575Sbostic main(argc, argv)
6255600Sbostic int argc;
6355600Sbostic char *argv[];
6455575Sbostic {
6555575Sbostic int c, fd, omask, maxfds;
6655575Sbostic fd_set rset;
6755575Sbostic
6855575Sbostic /*
6955575Sbostic * Find what name we are running under.
7055575Sbostic */
7155575Sbostic ProgName = (ProgName = rindex(argv[0],'/')) ? ++ProgName : *argv;
7255575Sbostic
7355575Sbostic /*
7455575Sbostic * Close any open file descriptors.
7555575Sbostic * Temporarily leave stdin & stdout open for `-d',
7655575Sbostic * and stderr open for any pre-syslog error messages.
7755575Sbostic */
7855575Sbostic {
7955575Sbostic int i, nfds = getdtablesize();
8055575Sbostic
8155575Sbostic for (i = 0; i < nfds; i++)
8255575Sbostic if (i != fileno(stdin) && i != fileno(stdout) &&
8355575Sbostic i != fileno(stderr))
8455575Sbostic (void) close(i);
8555575Sbostic }
8655575Sbostic
8755575Sbostic /*
8855575Sbostic * Parse any arguments.
8955575Sbostic */
9055575Sbostic while ((c = getopt(argc, argv, "adi:")) != EOF)
9155575Sbostic switch(c) {
9255575Sbostic case 'a':
9355575Sbostic BootAny++;
9455575Sbostic break;
9555575Sbostic case 'd':
9655575Sbostic DebugFlg++;
9755575Sbostic break;
9855575Sbostic case 'i':
9955575Sbostic IntfName = optarg;
10055575Sbostic break;
10155575Sbostic }
10255575Sbostic for (; optind < argc; optind++) {
10355575Sbostic if (ConfigFile == NULL)
10455575Sbostic ConfigFile = argv[optind];
10555575Sbostic else {
10655575Sbostic fprintf(stderr,
10755575Sbostic "%s: too many config files (`%s' ignored)\n",
10855575Sbostic ProgName, argv[optind]);
10955575Sbostic }
11055575Sbostic }
11155575Sbostic
11255575Sbostic if (ConfigFile == NULL) /* use default config file */
11355575Sbostic ConfigFile = DfltConfig;
11455575Sbostic
11555575Sbostic if (DebugFlg) {
11655575Sbostic DbgFp = stdout; /* output to stdout */
11755575Sbostic
11855575Sbostic (void) signal(SIGUSR1, SIG_IGN); /* dont muck w/DbgFp */
11955575Sbostic (void) signal(SIGUSR2, SIG_IGN);
12055575Sbostic } else {
12155575Sbostic (void) fclose(stdin); /* dont need these */
12255575Sbostic (void) fclose(stdout);
12355575Sbostic
12455575Sbostic /*
12555575Sbostic * Fork off a child to do the work & exit.
12655575Sbostic */
12755575Sbostic switch(fork()) {
12855575Sbostic case -1: /* fork failed */
12955575Sbostic fprintf(stderr, "%s: ", ProgName);
13055575Sbostic perror("fork");
13155575Sbostic Exit(0);
13255575Sbostic case 0: /* this is the CHILD */
13355575Sbostic break;
13455575Sbostic default: /* this is the PARENT */
13555575Sbostic _exit(0);
13655575Sbostic }
13755575Sbostic
13855575Sbostic /*
13955575Sbostic * Try to disassociate from the current tty.
14055575Sbostic */
14155575Sbostic {
14255575Sbostic char *devtty = "/dev/tty";
14355575Sbostic int i;
14455575Sbostic
14555575Sbostic if ((i = open(devtty, O_RDWR)) < 0) {
14655575Sbostic /* probably already disassociated */
14755575Sbostic if (setpgrp(0, 0) < 0) {
14855575Sbostic fprintf(stderr, "%s: ", ProgName);
14955575Sbostic perror("setpgrp");
15055575Sbostic }
15155575Sbostic } else {
15255575Sbostic if (ioctl(i, (u_long)TIOCNOTTY, (char *)0) < 0){
15355575Sbostic fprintf(stderr, "%s: ", ProgName);
15455575Sbostic perror("ioctl");
15555575Sbostic }
15655575Sbostic (void) close(i);
15755575Sbostic }
15855575Sbostic }
15955575Sbostic
16055575Sbostic (void) signal(SIGUSR1, DebugOn);
16155575Sbostic (void) signal(SIGUSR2, DebugOff);
16255575Sbostic }
16355575Sbostic
16455575Sbostic (void) fclose(stderr); /* finished with it */
16555575Sbostic
16655575Sbostic #ifdef SYSLOG4_2
16755575Sbostic openlog(ProgName, LOG_PID);
16855575Sbostic #else
16955575Sbostic openlog(ProgName, LOG_PID, LOG_DAEMON);
17055575Sbostic #endif
17155575Sbostic
17255575Sbostic /*
17355575Sbostic * If no interface was specified, get one now.
17455575Sbostic *
17555575Sbostic * This is convoluted because we want to get the default interface
17655575Sbostic * name for the syslog("restarted") message. If BpfGetIntfName()
17755575Sbostic * runs into an error, it will return a syslog-able error message
17855575Sbostic * (in `errmsg') which will be displayed here.
17955575Sbostic */
18055575Sbostic if (IntfName == NULL) {
18155600Sbostic char *errmsg;
18255575Sbostic
18355575Sbostic if ((IntfName = BpfGetIntfName(&errmsg)) == NULL) {
18455575Sbostic syslog(LOG_NOTICE, "restarted (??)");
18555575Sbostic syslog(LOG_ERR, errmsg);
18655575Sbostic Exit(0);
18755575Sbostic }
18855575Sbostic }
18955575Sbostic
19055575Sbostic syslog(LOG_NOTICE, "restarted (%s)", IntfName);
19155575Sbostic
19255575Sbostic (void) signal(SIGHUP, ReConfig);
19355575Sbostic (void) signal(SIGINT, Exit);
19455575Sbostic (void) signal(SIGTERM, Exit);
19555575Sbostic
19655575Sbostic /*
19755575Sbostic * Grab our host name and pid.
19855575Sbostic */
19955575Sbostic if (gethostname(MyHost, MAXHOSTNAMELEN) < 0) {
20055575Sbostic syslog(LOG_ERR, "gethostname: %m");
20155575Sbostic Exit(0);
20255575Sbostic }
20355575Sbostic MyHost[MAXHOSTNAMELEN] = '\0';
20455575Sbostic
20555575Sbostic MyPid = getpid();
20655575Sbostic
20755575Sbostic /*
20855575Sbostic * Write proc's pid to a file.
20955575Sbostic */
21055575Sbostic {
21155575Sbostic FILE *fp;
21255575Sbostic
21355575Sbostic if ((fp = fopen(PidFile, "w")) != NULL) {
21455575Sbostic (void) fprintf(fp, "%d\n", MyPid);
21555575Sbostic (void) fclose(fp);
21655575Sbostic } else {
21755575Sbostic syslog(LOG_WARNING, "fopen: failed (%s)", PidFile);
21855575Sbostic }
21955575Sbostic }
22055575Sbostic
22155575Sbostic /*
22255575Sbostic * All boot files are relative to the boot directory, we might
22355575Sbostic * as well chdir() there to make life easier.
22455575Sbostic */
22555575Sbostic if (chdir(BootDir) < 0) {
22655575Sbostic syslog(LOG_ERR, "chdir: %m (%s)", BootDir);
22755575Sbostic Exit(0);
22855575Sbostic }
22955575Sbostic
23055575Sbostic /*
23155575Sbostic * Initial configuration.
23255575Sbostic */
23355575Sbostic omask = sigblock(sigmask(SIGHUP)); /* prevent reconfig's */
23455575Sbostic if (GetBootFiles() == 0) /* get list of boot files */
23555575Sbostic Exit(0);
23655575Sbostic if (ParseConfig() == 0) /* parse config file */
23755575Sbostic Exit(0);
23855575Sbostic
23955575Sbostic /*
24055575Sbostic * Open and initialize a BPF device for the appropriate interface.
24155575Sbostic * If an error is encountered, a message is displayed and Exit()
24255575Sbostic * is called.
24355575Sbostic */
24455575Sbostic fd = BpfOpen();
24555575Sbostic
24655575Sbostic (void) sigsetmask(omask); /* allow reconfig's */
24755575Sbostic
24855575Sbostic /*
24955575Sbostic * Main loop: receive a packet, determine where it came from,
25055575Sbostic * and if we service this host, call routine to handle request.
25155575Sbostic */
25255575Sbostic maxfds = fd + 1;
25355575Sbostic FD_ZERO(&rset);
25455575Sbostic FD_SET(fd, &rset);
25555575Sbostic for (;;) {
25655575Sbostic struct timeval timeout;
25755575Sbostic fd_set r;
25855575Sbostic int nsel;
25955575Sbostic
26055575Sbostic r = rset;
26155575Sbostic
26255575Sbostic if (RmpConns == NULL) { /* timeout isnt necessary */
26355575Sbostic nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0,
26455575Sbostic (struct timeval *)0);
26555575Sbostic } else {
26655575Sbostic timeout.tv_sec = RMP_TIMEOUT;
26755575Sbostic timeout.tv_usec = 0;
26855575Sbostic nsel = select(maxfds, &r, (fd_set *)0, (fd_set *)0,
26955575Sbostic &timeout);
27055575Sbostic }
27155575Sbostic
27255575Sbostic if (nsel < 0) {
27355575Sbostic if (errno == EINTR)
27455575Sbostic continue;
27555575Sbostic syslog(LOG_ERR, "select: %m");
27655575Sbostic Exit(0);
27755575Sbostic } else if (nsel == 0) { /* timeout */
27855575Sbostic DoTimeout(); /* clear stale conns */
27955575Sbostic continue;
28055575Sbostic }
28155575Sbostic
28255575Sbostic if (FD_ISSET(fd, &r)) {
28355575Sbostic RMPCONN rconn;
28455575Sbostic CLIENT *client, *FindClient();
28555575Sbostic int doread = 1;
28655575Sbostic
28755575Sbostic while (BpfRead(&rconn, doread)) {
28855575Sbostic doread = 0;
28955575Sbostic
29055575Sbostic if (DbgFp != NULL) /* display packet */
29155575Sbostic DispPkt(&rconn,DIR_RCVD);
29255575Sbostic
29355575Sbostic omask = sigblock(sigmask(SIGHUP));
29455575Sbostic
29555575Sbostic /*
29655575Sbostic * If we do not restrict service, set the
29755575Sbostic * client to NULL (ProcessPacket() handles
29855575Sbostic * this). Otherwise, check that we can
29955575Sbostic * service this host; if not, log a message
30055575Sbostic * and ignore the packet.
30155575Sbostic */
30255575Sbostic if (BootAny) {
30355575Sbostic client = NULL;
30455575Sbostic } else if ((client=FindClient(&rconn))==NULL) {
30555575Sbostic syslog(LOG_INFO,
30655575Sbostic "%s: boot packet ignored",
30755575Sbostic EnetStr(&rconn));
30855575Sbostic (void) sigsetmask(omask);
30955575Sbostic continue;
31055575Sbostic }
31155575Sbostic
31255575Sbostic ProcessPacket(&rconn,client);
31355575Sbostic
31455575Sbostic (void) sigsetmask(omask);
31555575Sbostic }
31655575Sbostic }
31755575Sbostic }
31855575Sbostic }
31955575Sbostic
32055575Sbostic /*
32155575Sbostic ** DoTimeout -- Free any connections that have timed out.
32255575Sbostic **
32355575Sbostic ** Parameters:
32455575Sbostic ** None.
32555575Sbostic **
32655575Sbostic ** Returns:
32755575Sbostic ** Nothing.
32855575Sbostic **
32955575Sbostic ** Side Effects:
33055575Sbostic ** - Timed out connections in `RmpConns' will be freed.
33155575Sbostic */
33255600Sbostic void
DoTimeout()33355575Sbostic DoTimeout()
33455575Sbostic {
33555575Sbostic register RMPCONN *rtmp;
33655575Sbostic struct timeval now;
33755575Sbostic
33855575Sbostic (void) gettimeofday(&now, (struct timezone *)0);
33955575Sbostic
34055575Sbostic /*
34155575Sbostic * For each active connection, if RMP_TIMEOUT seconds have passed
34255575Sbostic * since the last packet was sent, delete the connection.
34355575Sbostic */
34455575Sbostic for (rtmp = RmpConns; rtmp != NULL; rtmp = rtmp->next)
34555575Sbostic if ((rtmp->tstamp.tv_sec + RMP_TIMEOUT) < now.tv_sec) {
34655575Sbostic syslog(LOG_WARNING, "%s: connection timed out (%u)",
34755575Sbostic EnetStr(rtmp), rtmp->rmp.r_type);
34855575Sbostic RemoveConn(rtmp);
34955575Sbostic }
35055575Sbostic }
35155575Sbostic
35255575Sbostic /*
35355575Sbostic ** FindClient -- Find client associated with a packet.
35455575Sbostic **
35555575Sbostic ** Parameters:
35655575Sbostic ** rconn - the new packet.
35755575Sbostic **
35855575Sbostic ** Returns:
35955575Sbostic ** Pointer to client info if found, NULL otherwise.
36055575Sbostic **
36155575Sbostic ** Side Effects:
36255575Sbostic ** None.
36355575Sbostic **
36455575Sbostic ** Warnings:
36555575Sbostic ** - This routine must be called with SIGHUP blocked since
36655575Sbostic ** a reconfigure can invalidate the information returned.
36755575Sbostic */
36855575Sbostic
36955575Sbostic CLIENT *
FindClient(rconn)37055575Sbostic FindClient(rconn)
37155600Sbostic register RMPCONN *rconn;
37255575Sbostic {
37355575Sbostic register CLIENT *ctmp;
37455575Sbostic
37555575Sbostic for (ctmp = Clients; ctmp != NULL; ctmp = ctmp->next)
37655575Sbostic if (bcmp((char *)&rconn->rmp.hp_hdr.saddr[0],
37755575Sbostic (char *)&ctmp->addr[0], RMP_ADDRLEN) == 0)
37855575Sbostic break;
37955575Sbostic
38055575Sbostic return(ctmp);
38155575Sbostic }
38255575Sbostic
38355575Sbostic /*
38455575Sbostic ** Exit -- Log an error message and exit.
38555575Sbostic **
38655575Sbostic ** Parameters:
38755575Sbostic ** sig - caught signal (or zero if not dying on a signal).
38855575Sbostic **
38955575Sbostic ** Returns:
39055575Sbostic ** Does not return.
39155575Sbostic **
39255575Sbostic ** Side Effects:
39355575Sbostic ** - This process ceases to exist.
39455575Sbostic */
39555600Sbostic void
Exit(sig)39655575Sbostic Exit(sig)
39755575Sbostic int sig;
39855575Sbostic {
39955575Sbostic if (sig > 0)
40055575Sbostic syslog(LOG_ERR, "going down on signal %d", sig);
40155575Sbostic else
40255575Sbostic syslog(LOG_ERR, "going down with fatal error");
40355575Sbostic BpfClose();
40455575Sbostic exit(1);
40555575Sbostic }
40655575Sbostic
40755575Sbostic /*
40855575Sbostic ** ReConfig -- Get new list of boot files and reread config files.
40955575Sbostic **
41055575Sbostic ** Parameters:
41155575Sbostic ** None.
41255575Sbostic **
41355575Sbostic ** Returns:
41455575Sbostic ** Nothing.
41555575Sbostic **
41655575Sbostic ** Side Effects:
41755575Sbostic ** - All active connections are dropped.
41855575Sbostic ** - List of boot-able files is changed.
41955575Sbostic ** - List of clients is changed.
42055575Sbostic **
42155575Sbostic ** Warnings:
42255575Sbostic ** - This routine must be called with SIGHUP blocked.
42355575Sbostic */
42455600Sbostic void
ReConfig(signo)42555600Sbostic ReConfig(signo)
42655600Sbostic int signo;
42755575Sbostic {
42855575Sbostic syslog(LOG_NOTICE, "reconfiguring boot server");
42955575Sbostic
43055575Sbostic FreeConns();
43155575Sbostic
43255575Sbostic if (GetBootFiles() == 0)
43355575Sbostic Exit(0);
43455575Sbostic
43555575Sbostic if (ParseConfig() == 0)
43655575Sbostic Exit(0);
43755575Sbostic }
43855575Sbostic
43955575Sbostic /*
44055575Sbostic ** DebugOff -- Turn off debugging.
44155575Sbostic **
44255575Sbostic ** Parameters:
44355575Sbostic ** None.
44455575Sbostic **
44555575Sbostic ** Returns:
44655575Sbostic ** Nothing.
44755575Sbostic **
44855575Sbostic ** Side Effects:
44955575Sbostic ** - Debug file is closed.
45055575Sbostic */
45155600Sbostic void
DebugOff(signo)45255600Sbostic DebugOff(signo)
45355600Sbostic int signo;
45455575Sbostic {
45555575Sbostic if (DbgFp != NULL)
45655575Sbostic (void) fclose(DbgFp);
45755575Sbostic
45855575Sbostic DbgFp = NULL;
45955575Sbostic }
46055575Sbostic
46155575Sbostic /*
46255575Sbostic ** DebugOn -- Turn on debugging.
46355575Sbostic **
46455575Sbostic ** Parameters:
46555575Sbostic ** None.
46655575Sbostic **
46755575Sbostic ** Returns:
46855575Sbostic ** Nothing.
46955575Sbostic **
47055575Sbostic ** Side Effects:
47155575Sbostic ** - Debug file is opened/truncated if not already opened,
47255575Sbostic ** otherwise do nothing.
47355575Sbostic */
47455600Sbostic void
DebugOn(signo)47555600Sbostic DebugOn(signo)
47655600Sbostic int signo;
47755575Sbostic {
47855575Sbostic if (DbgFp == NULL) {
47955575Sbostic if ((DbgFp = fopen(DbgFile, "w")) == NULL)
48055575Sbostic syslog(LOG_ERR, "can't open debug file (%s)", DbgFile);
48155575Sbostic }
48255575Sbostic }
483