Commit | Line | Data |
---|---|---|
e677da31 | 1 | #ifndef lint |
a49a6aba | 2 | static char sccsid[] = "@(#)syslogd.c 4.8 (Berkeley) %G%"; |
e677da31 RC |
3 | #endif |
4 | ||
5 | /* | |
6 | * syslogd -- log system messages | |
7 | * | |
8 | * This program implements a system log. It takes a series of lines. | |
9 | * Each line may have a priority, signified as "<n>" as | |
a49a6aba RC |
10 | * the first characters of the line. If this is |
11 | * not present, a default priority is used. | |
e677da31 RC |
12 | * |
13 | * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will | |
14 | * cause it to reread its configuration file. | |
15 | * | |
16 | * Defined Constants: | |
17 | * | |
e677da31 | 18 | * MAXLINE -- the maximimum line length that can be handled. |
a49a6aba RC |
19 | * NLOGS -- the maximum number of simultaneous log files. |
20 | * NUSERS -- the maximum number of people that can | |
21 | * be designated as "superusers" on your system. | |
22 | * DEFUPRI -- the default priority for user messages | |
23 | * DEFSPRI -- the default priority for kernel messages | |
ada83039 RC |
24 | * |
25 | * Author: Eric Allman | |
a49a6aba | 26 | * extensive changes by Ralph Campbell |
e677da31 RC |
27 | */ |
28 | ||
a49a6aba RC |
29 | #define NLOGS 10 /* max number of log files */ |
30 | #define NSUSERS 10 /* max number of special users */ | |
31 | #define MAXLINE 1024 /* maximum line length */ | |
32 | #define DEFUPRI LOG_NOTICE | |
33 | #define DEFSPRI LOG_EMERG | |
e677da31 RC |
34 | |
35 | #include <syslog.h> | |
36 | #include <errno.h> | |
37 | #include <stdio.h> | |
38 | #include <utmp.h> | |
39 | #include <ctype.h> | |
a24c481a RC |
40 | #include <signal.h> |
41 | #include <sysexits.h> | |
42 | #include <strings.h> | |
43 | ||
e677da31 RC |
44 | #include <sys/types.h> |
45 | #include <sys/ioctl.h> | |
46 | #include <sys/stat.h> | |
e677da31 RC |
47 | #include <sys/socket.h> |
48 | #include <sys/file.h> | |
63cb489e | 49 | #include <sys/msgbuf.h> |
ada83039 | 50 | #include <sys/uio.h> |
e677da31 | 51 | #include <sys/un.h> |
a24c481a | 52 | |
e677da31 RC |
53 | #include <netinet/in.h> |
54 | #include <netdb.h> | |
55 | ||
56 | char logname[] = "/dev/log"; | |
57 | char defconf[] = "/etc/syslog.conf"; | |
58 | char defpid[] = "/etc/syslog.pid"; | |
59 | char ctty[] = "/dev/console"; | |
60 | ||
e677da31 RC |
61 | #define dprintf if (Debug) printf |
62 | ||
63 | #define UNAMESZ 8 /* length of a login name */ | |
64 | ||
a49a6aba RC |
65 | #define mask(x) (1 << (x)) |
66 | ||
8a7154b1 RC |
67 | /* |
68 | * Flags to logmsg(). | |
69 | */ | |
70 | #define IGN_CONS 0x1 | |
71 | #define SYNC_FILE 0x2 | |
a49a6aba RC |
72 | #define NOCOPY 0x4 |
73 | #define ISMARK 0x10 | |
8a7154b1 | 74 | |
e677da31 RC |
75 | /* |
76 | * This structure represents the files that will have log | |
77 | * copies printed. | |
78 | */ | |
79 | ||
80 | struct filed { | |
81 | int f_file; /* file descriptor */ | |
a49a6aba RC |
82 | u_int f_pmask; /* priority mask */ |
83 | u_int f_flags; /* see #defines below */ | |
e677da31 RC |
84 | struct sockaddr_in f_addr; /* forwarding address */ |
85 | char f_name[248]; /* filename */ | |
86 | }; | |
87 | ||
1386dfed RC |
88 | #define F_TTY 001 /* file is a tty */ |
89 | #define F_MARK 002 /* write to the file periodically */ | |
90 | #define F_FORW 004 /* forward message to another host */ | |
91 | #define F_CONS 010 /* file is the console */ | |
e677da31 RC |
92 | |
93 | struct filed Files[NLOGS]; | |
94 | ||
95 | /* list of superusers */ | |
96 | struct susers { | |
a49a6aba | 97 | u_int s_pmask; /* priority mask */ |
e677da31 RC |
98 | char s_name[UNAMESZ+1]; |
99 | }; | |
100 | ||
101 | struct susers Susers[NSUSERS]; | |
102 | ||
103 | int Debug; /* debug flag */ | |
104 | int LogFile; /* log file descriptor */ | |
a49a6aba | 105 | u_int Sumask; /* priorities written to super-users */ |
e677da31 RC |
106 | int MarkIntvl = 15; /* mark interval in minutes */ |
107 | char *ConfFile = defconf; /* configuration file */ | |
ada83039 | 108 | char host[32]; /* our hostname */ |
e677da31 | 109 | char rhost[32]; /* hostname of sender (forwarded messages) */ |
ada83039 RC |
110 | int inet = 0; /* non-zero if INET sockets are being used */ |
111 | int port; /* port number for INET connections */ | |
a49a6aba RC |
112 | u_int Copymask = 0xffffffff; /* priorities to supress multiple copies */ |
113 | char prevline[MAXLINE + 1]; /* copy of last line to supress repeats */ | |
114 | char *prevdate; /* pointer to the date in prevline */ | |
115 | char prevhost[32]; /* previous host */ | |
116 | int prevflags; | |
117 | int prevpri; | |
118 | int count = 0; /* number of times seen */ | |
e677da31 RC |
119 | |
120 | extern int errno, sys_nerr; | |
121 | extern char *sys_errlist[]; | |
a49a6aba | 122 | extern char *ctime(), *index(); |
e677da31 RC |
123 | |
124 | main(argc, argv) | |
125 | int argc; | |
126 | char **argv; | |
127 | { | |
128 | register int i; | |
129 | register char *p; | |
a49a6aba | 130 | int klog, funix, finet, defreadfds, klogm, len; |
e677da31 RC |
131 | struct sockaddr_un sun, fromunix; |
132 | struct sockaddr_in sin, frominet; | |
133 | FILE *fp; | |
63cb489e | 134 | char line[MSG_BSIZE + 1]; |
ada83039 | 135 | extern int die(), domark(); |
e677da31 RC |
136 | |
137 | sun.sun_family = AF_UNIX; | |
138 | strncpy(sun.sun_path, logname, sizeof sun.sun_path); | |
ada83039 | 139 | gethostname(host, sizeof host); |
e677da31 RC |
140 | |
141 | while (--argc > 0) { | |
142 | p = *++argv; | |
a49a6aba RC |
143 | if (p[0] != '-') |
144 | usage(); | |
145 | switch (p[1]) { | |
146 | case 'm': /* set mark interval */ | |
147 | MarkIntvl = atoi(&p[2]); | |
148 | if (MarkIntvl <= 0) | |
149 | MarkIntvl = 1; | |
150 | break; | |
151 | ||
152 | case 'f': /* configuration file */ | |
153 | if (p[2] != '\0') | |
154 | ConfFile = &p[2]; | |
155 | break; | |
156 | ||
157 | case 'd': /* debug */ | |
158 | Debug++; | |
159 | break; | |
160 | ||
161 | case 'p': /* path */ | |
162 | if (p[2] != '\0') | |
163 | strncpy(sun.sun_path, &p[2], | |
164 | sizeof sun.sun_path); | |
165 | break; | |
166 | ||
167 | default: | |
168 | usage(); | |
e677da31 RC |
169 | } |
170 | } | |
171 | ||
172 | if (!Debug) { | |
173 | if (fork()) | |
174 | exit(0); | |
175 | for (i = 0; i < 10; i++) | |
176 | (void) close(i); | |
177 | (void) open("/", 0); | |
178 | (void) dup2(0, 1); | |
179 | (void) dup2(0, 2); | |
a49a6aba | 180 | untty(); |
e677da31 RC |
181 | } |
182 | signal(SIGTERM, die); | |
a49a6aba | 183 | signal(SIGINT, die); |
e677da31 RC |
184 | funix = socket(AF_UNIX, SOCK_DGRAM, 0); |
185 | if (funix >= 0 && bind(funix, &sun, | |
186 | sizeof(sun.sun_family)+strlen(sun.sun_path)) < 0) { | |
187 | close(funix); | |
188 | funix = -1; | |
189 | } | |
190 | if (funix < 0) { | |
191 | fp = fopen(ctty, "w"); | |
a49a6aba | 192 | fprintf(fp, "\r\nsyslogd: cannot create %s (%d)\r\n", logname, errno); |
e677da31 RC |
193 | dprintf("cannot create %s (%d)\n", logname, errno); |
194 | exit(1); | |
195 | } | |
a49a6aba | 196 | defreadfds = mask(funix); |
e677da31 RC |
197 | finet = socket(AF_INET, SOCK_DGRAM, 0); |
198 | if (finet >= 0) { | |
199 | struct servent *sp; | |
200 | ||
201 | sp = getservbyname("syslog", "udp"); | |
202 | if (sp == NULL) { | |
203 | errno = 0; | |
204 | logerror("syslog/udp: unknown service"); | |
205 | die(); | |
206 | } | |
207 | sin.sin_family = AF_INET; | |
ada83039 | 208 | sin.sin_port = port = sp->s_port; |
e677da31 RC |
209 | if (bind(finet, &sin, sizeof(sin), 0) < 0) { |
210 | logerror("bind"); | |
211 | die(); | |
212 | } | |
a49a6aba | 213 | defreadfds |= mask(finet); |
ada83039 | 214 | inet = 1; |
e677da31 | 215 | } |
a49a6aba RC |
216 | if ((klog = open("/dev/klog", O_RDONLY)) >= 0) { |
217 | klogm = mask(klog); | |
218 | defreadfds |= klogm; | |
219 | } else { | |
63cb489e | 220 | dprintf("can't open /dev/klog (%d)\n", errno); |
a49a6aba RC |
221 | klogm = 0; |
222 | } | |
e677da31 RC |
223 | |
224 | /* tuck my process id away */ | |
225 | fp = fopen(defpid, "w"); | |
226 | if (fp != NULL) { | |
227 | fprintf(fp, "%d\n", getpid()); | |
228 | fclose(fp); | |
229 | } | |
230 | ||
231 | dprintf("off & running....\n"); | |
232 | ||
233 | for (i = 0; i < NLOGS; i++) | |
234 | Files[i].f_file = -1; | |
235 | init(); | |
454c883a RC |
236 | signal(SIGALRM, domark); |
237 | alarm(MarkIntvl * 60); | |
238 | ||
e677da31 | 239 | for (;;) { |
a24c481a | 240 | int nfds, readfds = defreadfds; |
e677da31 RC |
241 | |
242 | nfds = select(20, &readfds, 0, 0, 0); | |
a49a6aba | 243 | dprintf("got a message (%d, %#x)\n", nfds, readfds); |
e677da31 RC |
244 | if (nfds == 0) |
245 | continue; | |
246 | if (nfds < 0) { | |
247 | if (errno == EINTR) | |
248 | continue; | |
249 | logerror("select"); | |
250 | continue; | |
251 | } | |
a49a6aba | 252 | if (readfds & klogm) { |
8a7154b1 RC |
253 | i = read(klog, line, sizeof(line) - 1); |
254 | if (i > 0) { | |
255 | line[i] = '\0'; | |
256 | printsys(line); | |
a49a6aba | 257 | } else if (i < 0 && errno != EINTR) { |
8a7154b1 | 258 | logerror("read"); |
a49a6aba RC |
259 | defreadfds &= ~klogm; |
260 | klog = -1; | |
261 | klogm = 0; | |
262 | } | |
8a7154b1 | 263 | } |
a49a6aba | 264 | if (readfds & mask(funix)) { |
e677da31 RC |
265 | len = sizeof fromunix; |
266 | i = recvfrom(funix, line, MAXLINE, 0, &fromunix, &len); | |
a24c481a RC |
267 | if (i > 0) { |
268 | line[i] = '\0'; | |
269 | printline(1, line); | |
270 | } else if (i < 0 && errno != EINTR) | |
271 | logerror("recvfrom"); | |
272 | } | |
a49a6aba | 273 | if (readfds & mask(finet)) { |
e677da31 RC |
274 | len = sizeof frominet; |
275 | i = recvfrom(finet, line, MAXLINE, 0, &frominet, &len); | |
a24c481a RC |
276 | if (i > 0 && chkhost(&frominet)) { |
277 | line[i] = '\0'; | |
278 | printline(0, line); | |
279 | } else if (i < 0 && errno != EINTR) | |
280 | logerror("recvfrom"); | |
281 | } | |
e677da31 RC |
282 | } |
283 | } | |
284 | ||
a49a6aba RC |
285 | usage() |
286 | { | |
287 | fprintf(stderr, "usage: syslogd [-m#] [-d] [-ppath] [-fconffile]\n"); | |
288 | exit(1); | |
289 | } | |
290 | ||
291 | untty() | |
292 | { | |
293 | int i; | |
294 | ||
295 | if (!Debug) { | |
296 | i = open("/dev/tty", O_RDWR); | |
297 | if (i >= 0) { | |
298 | ioctl(i, TIOCNOTTY, (char *)0); | |
299 | (void) close(i); | |
300 | } | |
301 | } | |
302 | } | |
303 | ||
e677da31 RC |
304 | /* |
305 | * Take a raw input line, decode the message, and print the message | |
306 | * on the appropriate log files. | |
307 | */ | |
308 | ||
309 | printline(local, msg) | |
310 | int local; | |
311 | char *msg; | |
312 | { | |
313 | register char *p, *q; | |
314 | register int c; | |
63cb489e | 315 | char line[MAXLINE + 1]; |
e677da31 RC |
316 | int pri; |
317 | ||
318 | /* test for special codes */ | |
a49a6aba | 319 | pri = DEFUPRI; |
e677da31 | 320 | p = msg; |
a49a6aba RC |
321 | if (*p == '<') { |
322 | pri = 0; | |
323 | while (isdigit(*++p)) | |
324 | pri = 10 * pri + (*p - '0'); | |
325 | if (*p == '>') | |
326 | ++p; | |
327 | if (pri <= 0 || pri >= 32) | |
328 | pri = DEFUPRI; | |
e677da31 RC |
329 | } |
330 | ||
331 | q = line; | |
e677da31 | 332 | while ((c = *p++ & 0177) != '\0' && c != '\n' && |
63cb489e | 333 | q < &line[sizeof(line) - 1]) { |
e677da31 RC |
334 | if (iscntrl(c)) { |
335 | *q++ = '^'; | |
336 | *q++ = c ^ 0100; | |
337 | } else | |
338 | *q++ = c; | |
339 | } | |
e677da31 RC |
340 | *q = '\0'; |
341 | ||
1386dfed | 342 | logmsg(pri, line, local ? host : rhost, 0); |
e677da31 RC |
343 | } |
344 | ||
63cb489e RC |
345 | /* |
346 | * Take a raw input line from /dev/klog, split and format similar to syslog(). | |
347 | */ | |
348 | ||
349 | printsys(msg) | |
350 | char *msg; | |
351 | { | |
352 | register char *p, *q; | |
353 | register int c; | |
354 | char line[MAXLINE + 1]; | |
8a7154b1 | 355 | int pri, flags; |
a49a6aba | 356 | char *lp; |
63cb489e RC |
357 | long now; |
358 | ||
359 | time(&now); | |
a49a6aba RC |
360 | sprintf(line, "vmunix: %.15s-- ", ctime(&now) + 4); |
361 | lp = line + strlen(line); | |
63cb489e | 362 | for (p = msg; *p != '\0'; ) { |
8a7154b1 | 363 | flags = SYNC_FILE; /* fsync file after write */ |
a49a6aba RC |
364 | pri = DEFSPRI; |
365 | if (*p == '<') { | |
366 | pri = 0; | |
367 | while (isdigit(*++p)) | |
368 | pri = 10 * pri + (*p - '0'); | |
369 | if (*p == '>') | |
370 | ++p; | |
371 | if (pri <= 0 || pri >= 32) | |
372 | pri = DEFSPRI; | |
8a7154b1 RC |
373 | } else { |
374 | /* kernel printf's come out on console */ | |
375 | flags |= IGN_CONS; | |
376 | } | |
a49a6aba RC |
377 | q = lp; |
378 | while (*p != '\0' && (c = *p++) != '\n' && | |
379 | q < &line[MAXLINE]) | |
63cb489e RC |
380 | *q++ = c; |
381 | *q = '\0'; | |
8a7154b1 | 382 | logmsg(pri, line, host, flags); |
63cb489e RC |
383 | } |
384 | } | |
385 | ||
e677da31 RC |
386 | /* |
387 | * Log a message to the appropriate log files, users, etc. based on | |
388 | * the priority. | |
389 | */ | |
390 | ||
8a7154b1 | 391 | logmsg(pri, msg, from, flags) |
e677da31 | 392 | int pri; |
ada83039 | 393 | char *msg, *from; |
8a7154b1 | 394 | int flags; |
e677da31 RC |
395 | { |
396 | char line[MAXLINE + 1]; | |
397 | register struct filed *f; | |
398 | register int l; | |
ada83039 RC |
399 | struct iovec iov[4]; |
400 | register struct iovec *v = iov; | |
401 | ||
a49a6aba RC |
402 | if ((flags & NOCOPY) == 0) { |
403 | register char *cp; | |
404 | ||
405 | /* | |
406 | * Check to see if copies should be supressed or | |
407 | * msg looks non-standard (e.g., 'prog: Feb 16 13:23:56-- '). | |
408 | */ | |
409 | if ((Copymask & mask(pri)) == 0 || | |
410 | (cp = index(msg, ':')) == NULL || strlen(cp) < 20 || | |
411 | cp[5] != ' ' || cp[8] != ' ' || cp[11] != ':' || | |
412 | cp[14] != ':' || cp[17] != '-' || cp[18] != '-' || | |
413 | cp[19] != ' ') | |
414 | flushmsg(); | |
415 | else if (!strncmp(msg, prevline, cp-msg) && | |
416 | !strcmp(cp+20, prevdate+18)) { | |
417 | /* we found a match, update the time */ | |
418 | strncpy(prevdate, cp+2, 15); | |
419 | count++; | |
420 | return; | |
421 | } else { | |
422 | /* new line, save it */ | |
423 | flushmsg(); | |
424 | strcpy(prevline, msg); | |
425 | strcpy(prevhost, from); | |
426 | prevdate = prevline + (cp - msg) + 2; | |
427 | prevflags = flags; | |
428 | prevpri = pri; | |
429 | } | |
430 | } | |
431 | ||
ada83039 RC |
432 | v->iov_base = from; |
433 | v->iov_len = strlen(v->iov_base); | |
434 | v++; | |
435 | v->iov_base = " "; | |
436 | v->iov_len = 1; | |
437 | v++; | |
438 | v->iov_base = msg; | |
439 | v->iov_len = strlen(v->iov_base); | |
440 | v++; | |
e677da31 RC |
441 | /* log the message to the particular outputs */ |
442 | for (f = Files; f < &Files[NLOGS]; f++) { | |
a49a6aba | 443 | if (f->f_file < 0) |
1386dfed | 444 | continue; |
a49a6aba | 445 | if (flags & ISMARK) { /* mark message */ |
1386dfed RC |
446 | struct stat stb; |
447 | long now; | |
448 | ||
449 | if (!(f->f_flags & F_MARK)) | |
450 | continue; | |
451 | if (fstat(f->f_file, &stb) < 0) | |
452 | continue; | |
453 | time(&now); | |
454 | if (!(f->f_flags & F_CONS) && | |
455 | stb.st_mtime > now - MarkIntvl * 60) | |
456 | continue; | |
a49a6aba RC |
457 | } else if ((f->f_pmask & mask(pri)) == 0 || |
458 | (flags & IGN_CONS) && (f->f_flags & F_CONS)) | |
459 | continue; | |
e677da31 RC |
460 | if (f->f_flags & F_FORW) { |
461 | sprintf(line, "<%d>%s", pri, msg); | |
462 | l = strlen(line); | |
463 | if (l > MAXLINE) | |
464 | l = MAXLINE; | |
465 | if (sendto(f->f_file, line, l, 0, | |
8a7154b1 RC |
466 | &f->f_addr, sizeof f->f_addr) != l) { |
467 | int e = errno; | |
468 | (void) close(f->f_file); | |
469 | f->f_file = -1; | |
470 | errno = e; | |
e677da31 | 471 | logerror("sendto"); |
8a7154b1 | 472 | } |
e677da31 RC |
473 | continue; |
474 | } | |
ada83039 RC |
475 | if (f->f_flags & F_TTY) { |
476 | v->iov_base = "\r\n"; | |
477 | v->iov_len = 2; | |
478 | } else { | |
479 | v->iov_base = "\n"; | |
480 | v->iov_len = 1; | |
e677da31 | 481 | } |
ada83039 | 482 | if (writev(f->f_file, iov, 4) < 0) { |
8a7154b1 | 483 | int e = errno; |
e677da31 RC |
484 | (void) close(f->f_file); |
485 | f->f_file = -1; | |
8a7154b1 RC |
486 | errno = e; |
487 | logerror(f->f_name); | |
488 | } else if (flags & SYNC_FILE) | |
489 | (void) fsync(f->f_file); | |
e677da31 RC |
490 | } |
491 | ||
492 | /* | |
493 | * Output high priority messages to terminals. | |
494 | */ | |
a49a6aba | 495 | if (mask(pri) & Sumask) |
ada83039 | 496 | wallmsg(pri, msg, from); |
e677da31 RC |
497 | } |
498 | ||
499 | /* | |
a49a6aba | 500 | * INIT -- Initialize syslogd from configuration table |
e677da31 | 501 | * |
a49a6aba RC |
502 | * The configuration table consists of a series of lines broken |
503 | * into two sections by a blank line. The first section gives a | |
504 | * list of files to log on. Each line begins with a | |
505 | * comma-separated list of digits or ranges of digits (pairs of | |
506 | * digits separated by a dash); if the priority of a message falls | |
507 | * in the set of digits defined by this list, then the message is | |
508 | * logged in the file corresponding to this line. If the | |
509 | * following character is an asterisk, then syslogd arranges for | |
510 | * something to be printed every fifteen minutes (even if only a | |
511 | * null line), so that crashes and other events can be localized. | |
512 | * The rest of the line is the pathname of the log file. The | |
513 | * second section is a list of user names; these people are all | |
514 | * notified when subalert messages occur (if they are logged on). | |
515 | * These lines may also have associated priority lists. | |
e677da31 | 516 | * |
a49a6aba RC |
517 | * The configuration table will be reread by this routine if a |
518 | * SIGHUP signal occurs; for that reason, it is tricky about not | |
519 | * re-opening files and closing files it will not be using. | |
e677da31 RC |
520 | */ |
521 | ||
522 | init() | |
523 | { | |
524 | register int i; | |
525 | register FILE *cf; | |
526 | register struct filed *f; | |
527 | register char *p; | |
528 | char cline[BUFSIZ]; | |
e677da31 RC |
529 | struct hostent *hp; |
530 | int pmask, flags; | |
531 | long now; | |
a49a6aba | 532 | char *getpmask(); |
e677da31 RC |
533 | |
534 | dprintf("init\n"); | |
535 | ||
536 | /* ignore interrupts during this routine */ | |
537 | signal(SIGHUP, SIG_IGN); | |
538 | ||
a49a6aba RC |
539 | /* flush any pending output */ |
540 | flushmsg(); | |
541 | ||
e677da31 RC |
542 | /* |
543 | * Close all open log files. | |
544 | */ | |
545 | for (f = Files; f < &Files[NLOGS]; f++) { | |
1386dfed | 546 | if (f->f_file >= 0) |
e677da31 RC |
547 | (void) close(f->f_file); |
548 | f->f_file = -1; | |
549 | } | |
550 | ||
551 | /* open the configuration file */ | |
552 | if ((cf = fopen(ConfFile, "r")) == NULL) { | |
553 | dprintf("cannot open %s\n", ConfFile); | |
554 | f = Files; | |
555 | if ((f->f_file = open(ctty, O_WRONLY)) >= 0) { | |
556 | strncpy(f->f_name, ctty, sizeof(f->f_name)-1); | |
a49a6aba | 557 | f->f_pmask = mask(LOG_CRIT); |
1386dfed | 558 | f->f_flags = F_TTY|F_MARK|F_CONS; |
a49a6aba | 559 | untty(); |
e677da31 RC |
560 | } |
561 | return; | |
562 | } | |
563 | ||
564 | /* | |
565 | * Foreach line in the conf table, open that file. | |
566 | */ | |
567 | f = Files; | |
e677da31 RC |
568 | while (fgets(cline, sizeof cline, cf) != NULL) { |
569 | /* check for end-of-section */ | |
570 | if (cline[0] == '\n') | |
571 | break; | |
572 | ||
573 | /* strip off newline character */ | |
a24c481a RC |
574 | p = index(cline, '\n'); |
575 | if (p) | |
576 | *p = '\0'; | |
e677da31 RC |
577 | |
578 | dprintf("F: got line '%s'\n", cline); | |
579 | ||
580 | /* extract priority mask and mark flag */ | |
581 | p = cline; | |
582 | flags = 0; | |
a49a6aba | 583 | p = getpmask(p, &pmask); |
e677da31 RC |
584 | if (*p == '*') { |
585 | p++; | |
586 | flags |= F_MARK; | |
587 | } | |
588 | ||
589 | if (f >= &Files[NLOGS]) | |
590 | continue; | |
591 | ||
592 | /* mark entry as used and update flags */ | |
593 | if (*p == '@') { | |
ada83039 RC |
594 | if (!inet) |
595 | continue; | |
e677da31 | 596 | hp = gethostbyname(++p); |
ada83039 RC |
597 | if (hp == NULL) { |
598 | char buf[100]; | |
599 | ||
600 | sprintf(buf, "unknown host %s", p); | |
601 | errno = 0; | |
602 | logerror(buf); | |
603 | continue; | |
604 | } | |
605 | bzero(&f->f_addr, sizeof f->f_addr); | |
606 | f->f_addr.sin_family = AF_INET; | |
607 | f->f_addr.sin_port = port; | |
608 | bcopy(hp->h_addr, (char *) &f->f_addr.sin_addr, hp->h_length); | |
609 | f->f_file = socket(AF_INET, SOCK_DGRAM, 0); | |
610 | if (f->f_file < 0) { | |
611 | logerror("socket"); | |
612 | continue; | |
e677da31 RC |
613 | } |
614 | flags |= F_FORW; | |
615 | f->f_pmask = pmask; | |
616 | f->f_flags = flags; | |
a49a6aba | 617 | dprintf("Host %s pmask %#x flags %#x\n", p, pmask, flags); |
e677da31 RC |
618 | f++; |
619 | continue; | |
620 | } | |
621 | strncpy(f->f_name, p, sizeof(f->f_name)-1); | |
1386dfed | 622 | if ((f->f_file = open(p, O_WRONLY|O_APPEND|O_NDELAY)) < 0) { |
e677da31 RC |
623 | logerror(p); |
624 | continue; | |
625 | } | |
a49a6aba | 626 | if (isatty(f->f_file)) { |
e677da31 | 627 | flags |= F_TTY; |
a49a6aba RC |
628 | untty(); |
629 | } | |
1386dfed RC |
630 | if (strcmp(p, ctty) == 0) |
631 | flags |= F_CONS; | |
e677da31 RC |
632 | f->f_pmask = pmask; |
633 | f->f_flags = flags; | |
a49a6aba | 634 | dprintf("File %s pmask %#x flags %#x\n", p, pmask, flags); |
e677da31 RC |
635 | f++; |
636 | } | |
637 | ||
638 | /* | |
639 | * Read the list of users. | |
640 | * | |
641 | * Anyone in this list is informed directly if s/he | |
642 | * is logged in when a high priority message comes through. | |
643 | */ | |
a49a6aba | 644 | Sumask = mask(LOG_SALERT); |
e677da31 RC |
645 | for (i = 0; i < NSUSERS && fgets(cline, sizeof cline, cf) != NULL; i++) { |
646 | /* strip off newline */ | |
a24c481a RC |
647 | p = index(cline, '\n'); |
648 | if (p) | |
649 | *p = '\0'; | |
e677da31 RC |
650 | dprintf("U: got line '%s'\n", cline); |
651 | p = cline; | |
652 | if (isdigit(*p)) { | |
a49a6aba RC |
653 | p = getpmask(p, &pmask); |
654 | Sumask |= pmask; | |
655 | Susers[i].s_pmask = pmask; | |
e677da31 | 656 | } else |
a49a6aba | 657 | Susers[i].s_pmask = pmask = mask(LOG_SALERT); |
e677da31 | 658 | strncpy(Susers[i].s_name, p, UNAMESZ); |
a49a6aba | 659 | dprintf("Suser %s pmask %#x\n", p, pmask); |
e677da31 RC |
660 | } |
661 | ||
662 | /* zero the rest of the old superusers */ | |
663 | while (i < NSUSERS) | |
664 | Susers[i++].s_name[0] = '\0'; | |
665 | ||
666 | /* close the configuration file */ | |
667 | (void) fclose(cf); | |
668 | ||
ada83039 | 669 | dprintf("syslogd: restarted\n"); |
e677da31 RC |
670 | |
671 | /* arrange for signal 1 to reconfigure */ | |
672 | signal(SIGHUP, init); | |
673 | } | |
674 | ||
675 | /* | |
676 | * WALLMSG -- Write a message to the world at large | |
677 | * | |
678 | * Write the specified message to either the entire | |
679 | * world, or a list of approved users. | |
680 | */ | |
681 | ||
ada83039 | 682 | wallmsg(pri, msg, from) |
e677da31 | 683 | int pri; |
ada83039 | 684 | char *msg, *from; |
e677da31 RC |
685 | { |
686 | register char *p; | |
687 | register int i; | |
ada83039 RC |
688 | int f, flags, len, e; |
689 | FILE *uf; | |
e677da31 RC |
690 | struct utmp ut; |
691 | long now; | |
692 | char line[MAXLINE + 100]; | |
e677da31 RC |
693 | |
694 | /* open the user login file */ | |
ada83039 RC |
695 | if ((uf = fopen("/etc/utmp", "r")) == NULL) { |
696 | logerror("/etc/utmp"); | |
e677da31 | 697 | return; |
ada83039 | 698 | } |
e677da31 RC |
699 | |
700 | time(&now); | |
e677da31 | 701 | sprintf(line, |
ada83039 RC |
702 | "\r\n\7Message from syslogd@%s at %.24s ...\r\n%s\r\n", |
703 | from, ctime(&now), msg); | |
e677da31 RC |
704 | len = strlen(line); |
705 | ||
706 | /* scan the user login file */ | |
ada83039 | 707 | while (fread(&ut, sizeof ut, 1, uf) == 1) { |
e677da31 RC |
708 | /* is this slot used? */ |
709 | if (ut.ut_name[0] == '\0') | |
710 | continue; | |
711 | ||
712 | /* should we send the message to this user? */ | |
713 | if (pri != LOG_ALERT) { | |
714 | for (i = 0; i < NSUSERS; i++) { | |
a49a6aba | 715 | if ((mask(pri) & Susers[i].s_pmask) == 0) |
e677da31 RC |
716 | continue; |
717 | if (strncmp(Susers[i].s_name, ut.ut_name, | |
718 | sizeof ut.ut_name) == 0) | |
719 | goto prmsg; | |
720 | } | |
721 | continue; | |
722 | } | |
1386dfed | 723 | prmsg: |
e677da31 RC |
724 | |
725 | /* compute the device name */ | |
726 | p = "/dev/12345678"; | |
727 | strcpyn(&p[5], ut.ut_line, UNAMESZ); | |
728 | ||
729 | /* open the terminal */ | |
730 | f = open(p, O_WRONLY|O_NDELAY); | |
731 | if (f < 0) | |
732 | continue; | |
1386dfed RC |
733 | if ((flags = fcntl(f, F_GETFL, 0)) == -1) { |
734 | (void) close(f); | |
e677da31 | 735 | continue; |
1386dfed | 736 | } |
e677da31 RC |
737 | if (fcntl(f, F_SETFL, flags | FNDELAY) == -1) |
738 | goto oldway; | |
739 | i = write(f, line, len); | |
740 | e = errno; | |
741 | (void) fcntl(f, F_SETFL, flags); | |
742 | if (i == len || e != EWOULDBLOCK) { | |
743 | (void) close(f); | |
744 | continue; | |
745 | } | |
746 | oldway: | |
747 | if (fork() == 0) { | |
748 | (void) write(f, line, len); | |
749 | exit(0); | |
750 | } | |
751 | (void) close(f); | |
752 | } | |
753 | ||
754 | /* close the user login file */ | |
755 | (void) close(uf); | |
756 | } | |
757 | ||
758 | /* | |
759 | * Make sure every marked file gets written to periodically. | |
760 | * Reset the alarm clock to call itself after MarkIntvl minutes. | |
761 | */ | |
762 | domark() | |
763 | { | |
e677da31 RC |
764 | char buf[40]; |
765 | long now; | |
766 | ||
767 | dprintf("domark\n"); | |
768 | ||
769 | time(&now); | |
1386dfed | 770 | sprintf(buf, "syslogd: %.24s-- MARK", ctime(&now)); |
a49a6aba RC |
771 | flushmsg(); |
772 | logmsg(0, buf, host, NOCOPY|ISMARK); | |
e677da31 RC |
773 | alarm(MarkIntvl * 60); |
774 | } | |
775 | ||
776 | /* | |
777 | * Check to see if we should log this message. | |
778 | */ | |
779 | chkhost(f) | |
780 | struct sockaddr_in *f; | |
781 | { | |
782 | struct hostent *hp; | |
783 | extern char *inet_ntoa(); | |
784 | ||
785 | dprintf("chkhost\n"); | |
786 | ||
787 | if (f->sin_family != AF_INET) { | |
788 | dprintf("Malformed from address\n"); | |
789 | return (0); | |
790 | } | |
791 | hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family); | |
792 | if (hp == 0) { | |
793 | dprintf("Host name for your address (%s) unknown\n", | |
794 | inet_ntoa(f->sin_addr)); | |
795 | return (0); | |
796 | } | |
797 | strncpy(rhost, hp->h_name, sizeof rhost); | |
798 | return (1); | |
799 | } | |
800 | ||
a49a6aba RC |
801 | /* |
802 | * Compare current message with previous and return true if match. | |
803 | * Side effect is to update the time in the previous message. | |
804 | */ | |
805 | match(msg) | |
806 | char *msg; | |
807 | { | |
808 | register char *cp; | |
809 | ||
810 | } | |
811 | ||
812 | flushmsg() | |
813 | { | |
814 | if (count == 0) | |
815 | return; | |
816 | if (count > 1) | |
817 | sprintf(prevdate+18, "last message repeated %d times", count); | |
818 | logmsg(prevpri, prevline, prevhost, prevflags|NOCOPY); | |
819 | prevline[0] = '\0'; | |
820 | count = 0; | |
821 | } | |
822 | ||
e677da31 RC |
823 | /* |
824 | * Print syslogd errors some place. | |
825 | */ | |
826 | logerror(type) | |
827 | char *type; | |
828 | { | |
829 | char buf[100]; | |
ada83039 | 830 | long now; |
e677da31 | 831 | |
ada83039 | 832 | time(&now); |
e677da31 | 833 | if (errno == 0) |
ada83039 | 834 | sprintf(buf, "syslogd: %.24s-- %s", ctime(&now), type); |
e677da31 | 835 | else if ((unsigned) errno > sys_nerr) |
ada83039 RC |
836 | sprintf(buf, "syslogd: %.24s-- %s: error %d", |
837 | ctime(&now), type, errno); | |
e677da31 | 838 | else |
ada83039 RC |
839 | sprintf(buf, "syslogd: %.24s-- %s: %s", |
840 | ctime(&now), type, sys_errlist[errno]); | |
e677da31 | 841 | errno = 0; |
ada83039 | 842 | dprintf("%s\n", buf); |
1386dfed | 843 | logmsg(LOG_ERR, buf, host, 0); |
e677da31 RC |
844 | } |
845 | ||
846 | die() | |
847 | { | |
ada83039 | 848 | |
a49a6aba | 849 | flushmsg(); |
ada83039 | 850 | dprintf("syslogd: going down\n"); |
e677da31 RC |
851 | (void) unlink(logname); |
852 | exit(0); | |
853 | } | |
a49a6aba RC |
854 | |
855 | /* | |
856 | * getpmask() parses a string cp looking for a set of numbers like | |
857 | * '1-5,8,16' and returns in *ppmask the set of bits represented by | |
858 | * these numbers. A notation '1-5' is interpreted to mean 'turn on | |
859 | * bits 1 through 5 inclusive'. getpmask() returns the address of | |
860 | * first byte after the number set. | |
861 | */ | |
862 | char * | |
863 | getpmask(cp, ppmask) | |
864 | register char *cp; | |
865 | unsigned *ppmask; | |
866 | { | |
867 | int count1, count2; | |
868 | register int i; | |
869 | ||
870 | *ppmask = 0; | |
871 | while (isdigit(*cp)) { | |
872 | count1 = count2 = 0; | |
873 | do { | |
874 | count1 = 10 * count1 + (*cp++ - '0'); | |
875 | } while (isdigit(*cp)); | |
876 | switch (*cp) { | |
877 | case ',': | |
878 | ++cp; | |
879 | /* FALL THRU */ | |
880 | default: | |
881 | *ppmask |= mask(count1); | |
882 | continue; | |
883 | ||
884 | case '-': | |
885 | while (isdigit(*++cp)) | |
886 | count2 = 10 * count2 + (*cp - '0'); | |
887 | for (i = count1; i <= count2; ++i) | |
888 | *ppmask |= mask(i); | |
889 | if (*cp == ',') | |
890 | ++cp; | |
891 | continue; | |
892 | } | |
893 | } | |
894 | ||
895 | return (cp); | |
896 | } |