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