Commit | Line | Data |
---|---|---|
ad787160 C |
1 | /* $Revision: 1.9 $ |
2 | ** This file has been modified to get it to compile more easily | |
3 | ** on pre-4.4BSD (e.g., SysVr4 :-) systems. Rich $alz, June 1991. | |
4 | */ | |
5 | ||
6 | /* change these three if you must keep running an old syslog. */ | |
7 | #define _PATH_LOGFILE "/dev/log" | |
8 | #define _PATH_LOGCONF "/etc/syslog.conf" | |
9 | #define _PATH_LOGPID "/etc/syslog.pid" | |
10 | ||
11 | /* #define this to enable verbose debugging of all messages. */ | |
12 | #undef VERBOSE_DEBUG | |
13 | /* #define this to line to listen on the INET port. */ | |
14 | #undef DO_INET_SOCKET | |
15 | /* #undef this to not read kernel syslog messages. */ | |
16 | #define _PATH_KLOG "/dev/klog" | |
17 | #undef _PATH_KLOG | |
18 | /* set this depending on what your sighandler is. */ | |
19 | /* =()<#define SIGHANDLER @<SIGHANDLER>@>()= */ | |
20 | #define SIGHANDLER void | |
21 | /* if you need various BSD functions, set this. */ | |
22 | #define NEED_BZERO_ETC | |
23 | ||
24 | /* Use "union wait" instead of int? */ | |
25 | /* =()<#define @<USE_UNION_WAIT>@_USE_UNION_WAIT>()= */ | |
26 | #define DONT_USE_UNION_WAIT | |
27 | #if defined(DO_USE_UNION_WAIT) | |
28 | #define WAITVALUE union wait | |
29 | #else | |
30 | #define WAITVALUE int | |
31 | #endif /* defined(DO_USE_UNION_WAIT) */ | |
32 | ||
8c5eec2f | 33 | /* |
e15840af KB |
34 | * Copyright (c) 1983, 1988 Regents of the University of California. |
35 | * All rights reserved. | |
36 | * | |
1c15e888 C |
37 | * Redistribution and use in source and binary forms are permitted provided |
38 | * that: (1) source distributions retain this entire copyright notice and | |
39 | * comment, and (2) distributions including binaries display the following | |
40 | * acknowledgement: ``This product includes software developed by the | |
41 | * University of California, Berkeley and its contributors'' in the | |
42 | * documentation or other materials provided with the distribution and in | |
43 | * all advertising materials mentioning features or use of this software. | |
44 | * Neither the name of the University nor the names of its contributors may | |
45 | * be used to endorse or promote products derived from this software without | |
46 | * specific prior written permission. | |
47 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED | |
48 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | |
49 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
8c5eec2f DF |
50 | */ |
51 | ||
52 | #ifndef lint | |
53 | char copyright[] = | |
e15840af | 54 | "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\ |
8c5eec2f | 55 | All rights reserved.\n"; |
e15840af | 56 | #endif /* not lint */ |
8c5eec2f | 57 | |
e677da31 | 58 | #ifndef lint |
1c15e888 | 59 | static char sccsid[] = "@(#)syslogd.c 5.42 (Berkeley) 6/29/90"; |
e15840af | 60 | #endif /* not lint */ |
e677da31 RC |
61 | |
62 | /* | |
63 | * syslogd -- log system messages | |
64 | * | |
65 | * This program implements a system log. It takes a series of lines. | |
66 | * Each line may have a priority, signified as "<n>" as | |
a49a6aba RC |
67 | * the first characters of the line. If this is |
68 | * not present, a default priority is used. | |
e677da31 RC |
69 | * |
70 | * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will | |
71 | * cause it to reread its configuration file. | |
72 | * | |
73 | * Defined Constants: | |
74 | * | |
e677da31 | 75 | * MAXLINE -- the maximimum line length that can be handled. |
a49a6aba RC |
76 | * DEFUPRI -- the default priority for user messages |
77 | * DEFSPRI -- the default priority for kernel messages | |
ada83039 RC |
78 | * |
79 | * Author: Eric Allman | |
a49a6aba | 80 | * extensive changes by Ralph Campbell |
61a57de9 | 81 | * more extensive changes by Eric Allman (again) |
e677da31 RC |
82 | */ |
83 | ||
a49a6aba | 84 | #define MAXLINE 1024 /* maximum line length */ |
35c3f83c | 85 | #define MAXSVLINE 120 /* maximum saved line length */ |
64b300b4 EA |
86 | #define DEFUPRI (LOG_USER|LOG_NOTICE) |
87 | #define DEFSPRI (LOG_KERN|LOG_CRIT) | |
92e73e63 | 88 | #define TIMERINTVL 30 /* interval for checking flush, mark */ |
e677da31 | 89 | |
2f6a4049 | 90 | #include <sys/param.h> |
92e73e63 | 91 | #include <sys/errno.h> |
e677da31 RC |
92 | #include <sys/ioctl.h> |
93 | #include <sys/stat.h> | |
84555b38 | 94 | #include <sys/wait.h> |
e677da31 RC |
95 | #include <sys/socket.h> |
96 | #include <sys/file.h> | |
ada83039 | 97 | #include <sys/uio.h> |
e677da31 | 98 | #include <sys/un.h> |
64b300b4 EA |
99 | #include <sys/time.h> |
100 | #include <sys/resource.h> | |
92e73e63 | 101 | #include <sys/signal.h> |
a24c481a | 102 | |
ad787160 C |
103 | #ifdef MSG_BSIZE |
104 | #undef MSG_BSIZE | |
105 | #endif | |
106 | #define MSG_BSIZE 4096 | |
107 | ||
e677da31 RC |
108 | #include <netinet/in.h> |
109 | #include <netdb.h> | |
110 | ||
61b108ae | 111 | #include <utmp.h> |
61b108ae KB |
112 | #include <stdio.h> |
113 | #include <ctype.h> | |
38dde0cd | 114 | #include <string.h> |
61b108ae | 115 | |
233e81a0 | 116 | #define SYSLOG_NAMES |
ad787160 C |
117 | #include "syslog.h" |
118 | ||
119 | #define UT_NAMESIZE 8 | |
120 | #define _PATH_UTMP "/etc/utmp" | |
121 | #define _PATH_DEV "/dev/" | |
122 | #define _PATH_CONSOLE "/dev/console" | |
233e81a0 | 123 | |
ad787160 C |
124 | #ifndef sigmask |
125 | #define sigmask(m) (1 << ((m)-1)) | |
126 | #endif | |
127 | char *LogName = _PATH_LOGFILE; | |
61b108ae KB |
128 | char *ConfFile = _PATH_LOGCONF; |
129 | char *PidFile = _PATH_LOGPID; | |
130 | char ctty[] = _PATH_CONSOLE; | |
e677da31 | 131 | |
64b300b4 EA |
132 | #define FDMASK(fd) (1 << (fd)) |
133 | ||
e677da31 RC |
134 | #define dprintf if (Debug) printf |
135 | ||
64b300b4 | 136 | #define MAXUNAMES 20 /* maximum number of user names */ |
e677da31 | 137 | |
ad787160 C |
138 | #ifdef NEED_BZERO_ETC |
139 | #include <fcntl.h> | |
140 | bzero(b, length) | |
141 | char *b; | |
142 | int length; | |
143 | { | |
144 | while (--length >= 0) | |
145 | *b++ = '\0'; | |
146 | } | |
147 | bcopy(b1, b2, length) | |
148 | char *b1; | |
149 | char *b2; | |
150 | int length; | |
151 | { | |
152 | while (--length >= 0) | |
153 | *b2++ = *b1++; | |
154 | } | |
155 | setlinebuf(f) | |
156 | FILE *f; | |
157 | { | |
158 | setbuf(f, (char *)NULL); | |
159 | } | |
160 | wait3(status, flags, np) | |
161 | WAITVALUE *status; | |
162 | int flags; | |
163 | struct rusage *np; | |
164 | { | |
165 | return waitpid(-1, status, WNOHANG); | |
166 | } | |
167 | ||
168 | /* Not a general mask handler -- it know what we call, below. */ | |
169 | SIGHANDLER (*oldhup)(), (*oldalrm)(); | |
170 | int | |
171 | sigsetmask(omask) | |
172 | int omask; | |
173 | { | |
174 | if (omask & sigmask(SIGHUP)) | |
175 | (void) signal(SIGHUP, oldhup); | |
176 | if (omask & sigmask(SIGALRM)) | |
177 | (void) signal(SIGALRM, oldalrm); | |
178 | } | |
179 | int | |
180 | sigblock(mask) | |
181 | int mask; | |
182 | { | |
183 | if (mask & sigmask(SIGHUP)) | |
184 | oldhup = signal(SIGHUP, SIG_IGN); | |
185 | if (mask & sigmask(SIGALRM)) | |
186 | oldhup = signal(SIGALRM, SIG_IGN); | |
187 | } | |
188 | #endif | |
189 | ||
8a7154b1 RC |
190 | /* |
191 | * Flags to logmsg(). | |
192 | */ | |
64b300b4 EA |
193 | |
194 | #define IGN_CONS 0x001 /* don't print on console */ | |
195 | #define SYNC_FILE 0x002 /* do fsync on file after printing */ | |
92e73e63 MK |
196 | #define ADDDATE 0x004 /* add a date to the message */ |
197 | #define MARK 0x008 /* this message is a mark */ | |
8a7154b1 | 198 | |
e677da31 RC |
199 | /* |
200 | * This structure represents the files that will have log | |
201 | * copies printed. | |
202 | */ | |
203 | ||
204 | struct filed { | |
ad787160 | 205 | struct filed *f_nextone; /* next in linked list */ |
64b300b4 EA |
206 | short f_type; /* entry type, see below */ |
207 | short f_file; /* file descriptor */ | |
ad58e75e | 208 | time_t f_time; /* time this was last written */ |
c16a39e2 | 209 | u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ |
64b300b4 | 210 | union { |
e185ee1c | 211 | char f_uname[MAXUNAMES][UT_NAMESIZE+1]; |
c16a39e2 | 212 | struct { |
74440133 | 213 | char f_hname[MAXHOSTNAMELEN+1]; |
64b300b4 | 214 | struct sockaddr_in f_addr; |
c16a39e2 | 215 | } f_forw; /* forwarding address */ |
e185ee1c | 216 | char f_fname[MAXPATHLEN]; |
c16a39e2 | 217 | } f_un; |
92e73e63 MK |
218 | char f_prevline[MAXSVLINE]; /* last message logged */ |
219 | char f_lasttime[16]; /* time of last occurrence */ | |
220 | char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ | |
221 | int f_prevpri; /* pri of f_prevline */ | |
222 | int f_prevlen; /* length of f_prevline */ | |
223 | int f_prevcount; /* repetition cnt of prevline */ | |
224 | int f_repeatcount; /* number of "repeated" msgs */ | |
e677da31 RC |
225 | }; |
226 | ||
92e73e63 MK |
227 | /* |
228 | * Intervals at which we flush out "message repeated" messages, | |
229 | * in seconds after previous message is logged. After each flush, | |
230 | * we move to the next interval until we reach the largest. | |
231 | */ | |
232 | int repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ | |
233 | #define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) | |
234 | #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) | |
235 | #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ | |
236 | (f)->f_repeatcount = MAXREPEAT; \ | |
237 | } | |
238 | ||
64b300b4 EA |
239 | /* values for f_type */ |
240 | #define F_UNUSED 0 /* unused entry */ | |
241 | #define F_FILE 1 /* regular file */ | |
242 | #define F_TTY 2 /* terminal */ | |
243 | #define F_CONSOLE 3 /* console terminal */ | |
244 | #define F_FORW 4 /* remote machine */ | |
245 | #define F_USERS 5 /* list of users */ | |
246 | #define F_WALL 6 /* everyone logged on */ | |
247 | ||
248 | char *TypeNames[7] = { | |
249 | "UNUSED", "FILE", "TTY", "CONSOLE", | |
250 | "FORW", "USERS", "WALL" | |
e677da31 RC |
251 | }; |
252 | ||
92e73e63 MK |
253 | struct filed *Files; |
254 | struct filed consfile; | |
e677da31 RC |
255 | |
256 | int Debug; /* debug flag */ | |
74440133 | 257 | char LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ |
ad58e75e | 258 | char *LocalDomain; /* our local domain name */ |
64b300b4 | 259 | int InetInuse = 0; /* non-zero if INET sockets are being used */ |
92e73e63 | 260 | int finet; /* Internet datagram socket */ |
64b300b4 | 261 | int LogPort; /* port number for INET connections */ |
64b300b4 | 262 | int Initialized = 0; /* set when we have initialized ourselves */ |
92e73e63 | 263 | int MarkInterval = 20 * 60; /* interval between marks in seconds */ |
ad58e75e | 264 | int MarkSeq = 0; /* mark sequence number */ |
e677da31 | 265 | |
e185ee1c | 266 | extern int errno; |
ad787160 C |
267 | extern char *ctime(), *strchr(), *malloc(); |
268 | SIGHANDLER die(), domark(), init(), reapchild(); | |
e677da31 | 269 | |
ad787160 | 270 | int |
e677da31 RC |
271 | main(argc, argv) |
272 | int argc; | |
273 | char **argv; | |
274 | { | |
275 | register int i; | |
276 | register char *p; | |
92e73e63 | 277 | int funix, inetm, fklog, klogm, len; |
0d20624e | 278 | struct sockaddr_un sunx, fromunix; |
e677da31 RC |
279 | struct sockaddr_in sin, frominet; |
280 | FILE *fp; | |
953d8fe3 | 281 | int ch; |
63cb489e | 282 | char line[MSG_BSIZE + 1]; |
981fd33c | 283 | extern int optind; |
953d8fe3 | 284 | extern char *optarg; |
a49a6aba | 285 | |
953d8fe3 KB |
286 | while ((ch = getopt(argc, argv, "df:m:p:")) != EOF) |
287 | switch((char)ch) { | |
a49a6aba RC |
288 | case 'd': /* debug */ |
289 | Debug++; | |
290 | break; | |
953d8fe3 KB |
291 | case 'f': /* configuration file */ |
292 | ConfFile = optarg; | |
a49a6aba | 293 | break; |
ad58e75e | 294 | case 'm': /* mark interval */ |
953d8fe3 | 295 | MarkInterval = atoi(optarg) * 60; |
ad58e75e | 296 | break; |
953d8fe3 KB |
297 | case 'p': /* path */ |
298 | LogName = optarg; | |
299 | break; | |
300 | case '?': | |
a49a6aba RC |
301 | default: |
302 | usage(); | |
e677da31 | 303 | } |
953d8fe3 KB |
304 | if (argc -= optind) |
305 | usage(); | |
e677da31 | 306 | |
43d42ac6 MK |
307 | if (!Debug) |
308 | daemon(0, 0); | |
309 | else | |
84555b38 RC |
310 | setlinebuf(stdout); |
311 | ||
92e73e63 MK |
312 | consfile.f_type = F_CONSOLE; |
313 | (void) strcpy(consfile.f_un.f_fname, ctty); | |
ad58e75e | 314 | (void) gethostname(LocalHostName, sizeof LocalHostName); |
ad787160 | 315 | if (p = strchr(LocalHostName, '.')) { |
ad58e75e EA |
316 | *p++ = '\0'; |
317 | LocalDomain = p; | |
318 | } | |
319 | else | |
320 | LocalDomain = ""; | |
64b300b4 | 321 | (void) signal(SIGTERM, die); |
ad787160 C |
322 | if (Debug) { |
323 | (void) signal(SIGINT, die); | |
324 | (void) signal(SIGQUIT, die); | |
325 | } | |
326 | else { | |
327 | (void) signal(SIGINT, SIG_IGN); | |
328 | (void) signal(SIGQUIT, SIG_IGN); | |
329 | } | |
64b300b4 | 330 | (void) signal(SIGCHLD, reapchild); |
ad58e75e | 331 | (void) signal(SIGALRM, domark); |
92e73e63 | 332 | (void) alarm(TIMERINTVL); |
64b300b4 EA |
333 | (void) unlink(LogName); |
334 | ||
0f607d14 | 335 | bzero((char *)&sunx, sizeof(sunx)); |
0d20624e KM |
336 | sunx.sun_family = AF_UNIX; |
337 | (void) strncpy(sunx.sun_path, LogName, sizeof sunx.sun_path); | |
e677da31 | 338 | funix = socket(AF_UNIX, SOCK_DGRAM, 0); |
0d20624e | 339 | if (funix < 0 || bind(funix, (struct sockaddr *) &sunx, |
ad787160 | 340 | sizeof(sunx)) < 0 || |
64b300b4 EA |
341 | chmod(LogName, 0666) < 0) { |
342 | (void) sprintf(line, "cannot create %s", LogName); | |
343 | logerror(line); | |
344 | dprintf("cannot create %s (%d)\n", LogName, errno); | |
345 | die(0); | |
e677da31 | 346 | } |
ad787160 | 347 | #ifdef DO_INET_SOCKET |
e677da31 RC |
348 | finet = socket(AF_INET, SOCK_DGRAM, 0); |
349 | if (finet >= 0) { | |
350 | struct servent *sp; | |
351 | ||
352 | sp = getservbyname("syslog", "udp"); | |
353 | if (sp == NULL) { | |
354 | errno = 0; | |
355 | logerror("syslog/udp: unknown service"); | |
64b300b4 | 356 | die(0); |
e677da31 | 357 | } |
ad787160 | 358 | bzero((char *)&sin, sizeof(sin)); /* added uunet!rbj */ |
e677da31 | 359 | sin.sin_family = AF_INET; |
ad787160 C |
360 | sin.sin_addr.s_addr = INADDR_ANY; |
361 | sin.sin_port = LogPort = htons(sp->s_port); | |
e53dbb38 | 362 | if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
e677da31 | 363 | logerror("bind"); |
64b300b4 EA |
364 | if (!Debug) |
365 | die(0); | |
366 | } else { | |
367 | inetm = FDMASK(finet); | |
368 | InetInuse = 1; | |
e677da31 | 369 | } |
e677da31 | 370 | } |
ad787160 C |
371 | #else |
372 | finet = -1; | |
373 | inetm = 0; | |
374 | #endif /* DO_INET_SOCKET */ | |
375 | #ifdef _PATH_KLOG | |
61b108ae | 376 | if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0) |
64b300b4 | 377 | klogm = FDMASK(fklog); |
84555b38 | 378 | else { |
61b108ae | 379 | dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); |
a49a6aba RC |
380 | klogm = 0; |
381 | } | |
ad787160 C |
382 | #else |
383 | fklog = -1; | |
384 | klogm = 0; | |
385 | #endif /* _PATH_KLOG */ | |
e677da31 RC |
386 | |
387 | /* tuck my process id away */ | |
64b300b4 | 388 | fp = fopen(PidFile, "w"); |
e677da31 RC |
389 | if (fp != NULL) { |
390 | fprintf(fp, "%d\n", getpid()); | |
64b300b4 | 391 | (void) fclose(fp); |
e677da31 RC |
392 | } |
393 | ||
394 | dprintf("off & running....\n"); | |
395 | ||
e677da31 | 396 | init(); |
64b300b4 | 397 | (void) signal(SIGHUP, init); |
454c883a | 398 | |
e677da31 | 399 | for (;;) { |
64b300b4 | 400 | int nfds, readfds = FDMASK(funix) | inetm | klogm; |
e677da31 | 401 | |
64b300b4 | 402 | errno = 0; |
ff8002b1 | 403 | dprintf("readfds = %#x\n", readfds); |
64b300b4 | 404 | nfds = select(20, (fd_set *) &readfds, (fd_set *) NULL, |
e53dbb38 | 405 | (fd_set *) NULL, (struct timeval *) NULL); |
e677da31 RC |
406 | if (nfds == 0) |
407 | continue; | |
408 | if (nfds < 0) { | |
64b300b4 EA |
409 | if (errno != EINTR) |
410 | logerror("select"); | |
e677da31 RC |
411 | continue; |
412 | } | |
92e73e63 | 413 | dprintf("got a message (%d, %#x)\n", nfds, readfds); |
a49a6aba | 414 | if (readfds & klogm) { |
84555b38 | 415 | i = read(fklog, line, sizeof(line) - 1); |
8a7154b1 RC |
416 | if (i > 0) { |
417 | line[i] = '\0'; | |
418 | printsys(line); | |
a49a6aba | 419 | } else if (i < 0 && errno != EINTR) { |
84555b38 RC |
420 | logerror("klog"); |
421 | fklog = -1; | |
a49a6aba RC |
422 | klogm = 0; |
423 | } | |
8a7154b1 | 424 | } |
64b300b4 | 425 | if (readfds & FDMASK(funix)) { |
e677da31 | 426 | len = sizeof fromunix; |
64b300b4 | 427 | i = recvfrom(funix, line, MAXLINE, 0, |
e53dbb38 | 428 | (struct sockaddr *) &fromunix, &len); |
a24c481a RC |
429 | if (i > 0) { |
430 | line[i] = '\0'; | |
64b300b4 | 431 | printline(LocalHostName, line); |
a24c481a | 432 | } else if (i < 0 && errno != EINTR) |
64b300b4 | 433 | logerror("recvfrom unix"); |
a24c481a | 434 | } |
84555b38 | 435 | if (readfds & inetm) { |
e677da31 | 436 | len = sizeof frominet; |
e53dbb38 KB |
437 | i = recvfrom(finet, line, MAXLINE, 0, |
438 | (struct sockaddr *) &frominet, &len); | |
64b300b4 EA |
439 | if (i > 0) { |
440 | extern char *cvthname(); | |
441 | ||
a24c481a | 442 | line[i] = '\0'; |
64b300b4 | 443 | printline(cvthname(&frominet), line); |
a24c481a | 444 | } else if (i < 0 && errno != EINTR) |
64b300b4 | 445 | logerror("recvfrom inet"); |
ad787160 | 446 | } |
e677da31 RC |
447 | } |
448 | } | |
449 | ||
a49a6aba RC |
450 | usage() |
451 | { | |
e185ee1c | 452 | (void) fprintf(stderr, |
1c15e888 | 453 | "usage: syslogd [-d] [-f conffile] [-m markinterval] [-p path]\n"); |
a49a6aba RC |
454 | exit(1); |
455 | } | |
456 | ||
e677da31 RC |
457 | /* |
458 | * Take a raw input line, decode the message, and print the message | |
459 | * on the appropriate log files. | |
460 | */ | |
461 | ||
64b300b4 EA |
462 | printline(hname, msg) |
463 | char *hname; | |
e677da31 RC |
464 | char *msg; |
465 | { | |
466 | register char *p, *q; | |
467 | register int c; | |
63cb489e | 468 | char line[MAXLINE + 1]; |
e677da31 RC |
469 | int pri; |
470 | ||
471 | /* test for special codes */ | |
a49a6aba | 472 | pri = DEFUPRI; |
e677da31 | 473 | p = msg; |
a49a6aba RC |
474 | if (*p == '<') { |
475 | pri = 0; | |
476 | while (isdigit(*++p)) | |
477 | pri = 10 * pri + (*p - '0'); | |
478 | if (*p == '>') | |
479 | ++p; | |
e677da31 | 480 | } |
35c3f83c MK |
481 | if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) |
482 | pri = DEFUPRI; | |
e677da31 | 483 | |
64b300b4 | 484 | /* don't allow users to log kernel messages */ |
35c3f83c MK |
485 | if (LOG_FAC(pri) == LOG_KERN) |
486 | pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); | |
64b300b4 | 487 | |
e677da31 | 488 | q = line; |
64b300b4 | 489 | |
953d8fe3 KB |
490 | while ((c = *p++ & 0177) != '\0' && |
491 | q < &line[sizeof(line) - 1]) | |
0d52e368 KB |
492 | if (iscntrl(c)) |
493 | if (c == '\n') | |
494 | *q++ = ' '; | |
495 | else if (c == '\t') | |
496 | *q++ = '\t'; | |
497 | else { | |
498 | *q++ = '^'; | |
499 | *q++ = c ^ 0100; | |
500 | } | |
501 | else | |
e677da31 | 502 | *q++ = c; |
e677da31 RC |
503 | *q = '\0'; |
504 | ||
64b300b4 | 505 | logmsg(pri, line, hname, 0); |
e677da31 RC |
506 | } |
507 | ||
63cb489e RC |
508 | /* |
509 | * Take a raw input line from /dev/klog, split and format similar to syslog(). | |
510 | */ | |
511 | ||
512 | printsys(msg) | |
513 | char *msg; | |
514 | { | |
515 | register char *p, *q; | |
516 | register int c; | |
517 | char line[MAXLINE + 1]; | |
8a7154b1 | 518 | int pri, flags; |
a49a6aba | 519 | char *lp; |
63cb489e | 520 | |
e185ee1c | 521 | (void) strcpy(line, "vmunix: "); |
a49a6aba | 522 | lp = line + strlen(line); |
63cb489e | 523 | for (p = msg; *p != '\0'; ) { |
92e73e63 | 524 | flags = SYNC_FILE | ADDDATE; /* fsync file after write */ |
a49a6aba RC |
525 | pri = DEFSPRI; |
526 | if (*p == '<') { | |
527 | pri = 0; | |
528 | while (isdigit(*++p)) | |
529 | pri = 10 * pri + (*p - '0'); | |
530 | if (*p == '>') | |
531 | ++p; | |
8a7154b1 RC |
532 | } else { |
533 | /* kernel printf's come out on console */ | |
534 | flags |= IGN_CONS; | |
535 | } | |
35c3f83c MK |
536 | if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) |
537 | pri = DEFSPRI; | |
a49a6aba RC |
538 | q = lp; |
539 | while (*p != '\0' && (c = *p++) != '\n' && | |
540 | q < &line[MAXLINE]) | |
63cb489e RC |
541 | *q++ = c; |
542 | *q = '\0'; | |
64b300b4 | 543 | logmsg(pri, line, LocalHostName, flags); |
63cb489e RC |
544 | } |
545 | } | |
546 | ||
ad787160 C |
547 | |
548 | #ifdef VERBOSE_DEBUG | |
549 | /* | |
550 | * Decode a numeric value to a symbolic name | |
551 | */ | |
552 | char * | |
553 | edoced(val, codetab) | |
554 | int val; | |
555 | CODE *codetab; | |
556 | { | |
557 | register CODE *c; | |
558 | ||
559 | if (val >= 0) | |
560 | for (c = codetab; c->c_val != -1; c++) | |
561 | if (c->c_val == val) | |
562 | return (c->c_name); | |
563 | return ("???"); | |
564 | } | |
565 | #endif | |
566 | ||
92e73e63 MK |
567 | time_t now; |
568 | ||
e677da31 RC |
569 | /* |
570 | * Log a message to the appropriate log files, users, etc. based on | |
571 | * the priority. | |
572 | */ | |
573 | ||
8a7154b1 | 574 | logmsg(pri, msg, from, flags) |
64b300b4 EA |
575 | int pri; |
576 | char *msg, *from; | |
577 | int flags; | |
e677da31 | 578 | { |
e677da31 | 579 | register struct filed *f; |
64b300b4 | 580 | int fac, prilev; |
92e73e63 MK |
581 | int omask, msglen; |
582 | char *timestamp; | |
e53dbb38 | 583 | time_t time(); |
84555b38 | 584 | |
ad787160 C |
585 | #ifdef VERBOSE_DEBUG |
586 | if (Debug) { | |
587 | int pfac = (flags & MARK) ? INTERNAL_MARK : (pri & LOG_FACMASK); | |
588 | printf("logmsg: {%s.%s} pri %o, flags %x, from %s, msg %s\n", | |
589 | edoced(pfac, facilitynames), | |
590 | edoced(LOG_PRI(pri), prioritynames), | |
591 | pri, flags, from, msg); | |
592 | } | |
593 | #else | |
e185ee1c KB |
594 | dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", |
595 | pri, flags, from, msg); | |
ad787160 | 596 | #endif |
64b300b4 | 597 | |
ad58e75e | 598 | omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); |
ada83039 | 599 | |
64b300b4 EA |
600 | /* |
601 | * Check to see if msg looks non-standard. | |
602 | */ | |
92e73e63 MK |
603 | msglen = strlen(msg); |
604 | if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || | |
ad58e75e | 605 | msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') |
64b300b4 | 606 | flags |= ADDDATE; |
a49a6aba | 607 | |
ad58e75e EA |
608 | (void) time(&now); |
609 | if (flags & ADDDATE) | |
92e73e63 MK |
610 | timestamp = ctime(&now) + 4; |
611 | else { | |
612 | timestamp = msg; | |
613 | msg += 16; | |
614 | msglen -= 16; | |
615 | } | |
64b300b4 EA |
616 | |
617 | /* extract facility and priority level */ | |
c16a39e2 MK |
618 | if (flags & MARK) |
619 | fac = LOG_NFACILITIES; | |
35c3f83c MK |
620 | else |
621 | fac = LOG_FAC(pri); | |
622 | prilev = LOG_PRI(pri); | |
64b300b4 | 623 | |
e677da31 | 624 | /* log the message to the particular outputs */ |
64b300b4 | 625 | if (!Initialized) { |
92e73e63 | 626 | f = &consfile; |
e53dbb38 | 627 | f->f_file = open(ctty, O_WRONLY, 0); |
64b300b4 | 628 | |
92e73e63 | 629 | if (f->f_file >= 0) { |
c49273cf | 630 | fprintlog(f, flags, msg); |
92e73e63 | 631 | (void) close(f->f_file); |
64b300b4 | 632 | } |
7eefe9c1 | 633 | (void) sigsetmask(omask); |
64b300b4 EA |
634 | return; |
635 | } | |
ad787160 | 636 | for (f = Files; f; f = f->f_nextone) { |
64b300b4 | 637 | /* skip messages that are incorrect priority */ |
ad787160 | 638 | if ((int)f->f_pmask[fac] < prilev || |
233e81a0 | 639 | f->f_pmask[fac] == INTERNAL_NOPRI) |
a49a6aba | 640 | continue; |
64b300b4 | 641 | |
35c3f83c MK |
642 | if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) |
643 | continue; | |
644 | ||
ad58e75e | 645 | /* don't output marks to recently written files */ |
92e73e63 | 646 | if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) |
ad58e75e EA |
647 | continue; |
648 | ||
92e73e63 MK |
649 | /* |
650 | * suppress duplicate lines to this file | |
651 | */ | |
652 | if ((flags & MARK) == 0 && msglen == f->f_prevlen && | |
653 | !strcmp(msg, f->f_prevline) && | |
654 | !strcmp(from, f->f_prevhost)) { | |
655 | (void) strncpy(f->f_lasttime, timestamp, 15); | |
656 | f->f_prevcount++; | |
953d8fe3 | 657 | dprintf("msg repeated %d times, %ld sec of %d\n", |
92e73e63 MK |
658 | f->f_prevcount, now - f->f_time, |
659 | repeatinterval[f->f_repeatcount]); | |
660 | /* | |
661 | * If domark would have logged this by now, | |
662 | * flush it now (so we don't hold isolated messages), | |
663 | * but back off so we'll flush less often | |
664 | * in the future. | |
665 | */ | |
666 | if (now > REPEATTIME(f)) { | |
35c3f83c | 667 | fprintlog(f, flags, (char *)NULL); |
92e73e63 | 668 | BACKOFF(f); |
8a7154b1 | 669 | } |
92e73e63 MK |
670 | } else { |
671 | /* new line, save it */ | |
35c3f83c MK |
672 | if (f->f_prevcount) |
673 | fprintlog(f, 0, (char *)NULL); | |
674 | f->f_repeatcount = 0; | |
92e73e63 | 675 | (void) strncpy(f->f_lasttime, timestamp, 15); |
35c3f83c MK |
676 | (void) strncpy(f->f_prevhost, from, |
677 | sizeof(f->f_prevhost)); | |
678 | if (msglen < MAXSVLINE) { | |
92e73e63 MK |
679 | f->f_prevlen = msglen; |
680 | f->f_prevpri = pri; | |
681 | (void) strcpy(f->f_prevline, msg); | |
35c3f83c MK |
682 | fprintlog(f, flags, (char *)NULL); |
683 | } else { | |
92e73e63 | 684 | f->f_prevline[0] = 0; |
35c3f83c MK |
685 | f->f_prevlen = 0; |
686 | fprintlog(f, flags, msg); | |
687 | } | |
92e73e63 MK |
688 | } |
689 | } | |
690 | (void) sigsetmask(omask); | |
691 | } | |
64b300b4 | 692 | |
35c3f83c | 693 | fprintlog(f, flags, msg) |
92e73e63 MK |
694 | register struct filed *f; |
695 | int flags; | |
35c3f83c | 696 | char *msg; |
92e73e63 MK |
697 | { |
698 | struct iovec iov[6]; | |
e53dbb38 | 699 | register struct iovec *v; |
92e73e63 | 700 | register int l; |
e53dbb38 | 701 | char line[MAXLINE + 1], repbuf[80], greetings[200]; |
92e73e63 | 702 | |
e53dbb38 KB |
703 | v = iov; |
704 | if (f->f_type == F_WALL) { | |
705 | v->iov_base = greetings; | |
ad787160 | 706 | sprintf(greetings, |
e53dbb38 KB |
707 | "\r\n\7Message from syslogd@%s at %.24s ...\r\n", |
708 | f->f_prevhost, ctime(&now)); | |
ad787160 | 709 | v->iov_len = strlen(greetings); |
e53dbb38 KB |
710 | v++; |
711 | v->iov_base = ""; | |
712 | v->iov_len = 0; | |
713 | v++; | |
714 | } else { | |
715 | v->iov_base = f->f_lasttime; | |
716 | v->iov_len = 15; | |
717 | v++; | |
718 | v->iov_base = " "; | |
719 | v->iov_len = 1; | |
720 | v++; | |
721 | } | |
92e73e63 MK |
722 | v->iov_base = f->f_prevhost; |
723 | v->iov_len = strlen(v->iov_base); | |
724 | v++; | |
725 | v->iov_base = " "; | |
726 | v->iov_len = 1; | |
727 | v++; | |
e53dbb38 | 728 | |
35c3f83c MK |
729 | if (msg) { |
730 | v->iov_base = msg; | |
731 | v->iov_len = strlen(msg); | |
732 | } else if (f->f_prevcount > 1) { | |
92e73e63 | 733 | v->iov_base = repbuf; |
ad787160 | 734 | sprintf(repbuf, "last message repeated %d times", |
e53dbb38 | 735 | f->f_prevcount); |
ad787160 | 736 | v->iov_len = strlen(repbuf); |
92e73e63 MK |
737 | } else { |
738 | v->iov_base = f->f_prevline; | |
739 | v->iov_len = f->f_prevlen; | |
740 | } | |
741 | v++; | |
742 | ||
743 | dprintf("Logging to %s", TypeNames[f->f_type]); | |
744 | f->f_time = now; | |
745 | ||
746 | switch (f->f_type) { | |
747 | case F_UNUSED: | |
748 | dprintf("\n"); | |
749 | break; | |
750 | ||
751 | case F_FORW: | |
752 | dprintf(" %s\n", f->f_un.f_forw.f_hname); | |
ad787160 | 753 | sprintf(line, "<%d>%.15s %s", f->f_prevpri, |
e53dbb38 | 754 | iov[0].iov_base, iov[4].iov_base); |
ad787160 | 755 | l = strlen(line); |
92e73e63 MK |
756 | if (l > MAXLINE) |
757 | l = MAXLINE; | |
758 | if (sendto(finet, line, l, 0, &f->f_un.f_forw.f_addr, | |
759 | sizeof f->f_un.f_forw.f_addr) != l) { | |
760 | int e = errno; | |
761 | (void) close(f->f_file); | |
762 | f->f_type = F_UNUSED; | |
763 | errno = e; | |
764 | logerror("sendto"); | |
765 | } | |
766 | break; | |
767 | ||
768 | case F_CONSOLE: | |
769 | if (flags & IGN_CONS) { | |
770 | dprintf(" (ignored)\n"); | |
64b300b4 | 771 | break; |
92e73e63 MK |
772 | } |
773 | /* FALLTHROUGH */ | |
e677da31 | 774 | |
92e73e63 MK |
775 | case F_TTY: |
776 | case F_FILE: | |
777 | dprintf(" %s\n", f->f_un.f_fname); | |
778 | if (f->f_type != F_FILE) { | |
64b300b4 EA |
779 | v->iov_base = "\r\n"; |
780 | v->iov_len = 2; | |
92e73e63 MK |
781 | } else { |
782 | v->iov_base = "\n"; | |
783 | v->iov_len = 1; | |
64b300b4 | 784 | } |
92e73e63 MK |
785 | again: |
786 | if (writev(f->f_file, iov, 6) < 0) { | |
787 | int e = errno; | |
788 | (void) close(f->f_file); | |
789 | /* | |
604d6f83 | 790 | * Check for errors on TTY's due to loss of tty |
92e73e63 | 791 | */ |
604d6f83 | 792 | if ((e == EIO || e == EBADF) && f->f_type != F_FILE) { |
e53dbb38 KB |
793 | f->f_file = open(f->f_un.f_fname, |
794 | O_WRONLY|O_APPEND, 0); | |
92e73e63 MK |
795 | if (f->f_file < 0) { |
796 | f->f_type = F_UNUSED; | |
797 | logerror(f->f_un.f_fname); | |
43d42ac6 | 798 | } else |
92e73e63 | 799 | goto again; |
92e73e63 MK |
800 | } else { |
801 | f->f_type = F_UNUSED; | |
802 | errno = e; | |
803 | logerror(f->f_un.f_fname); | |
804 | } | |
805 | } else if (flags & SYNC_FILE) | |
806 | (void) fsync(f->f_file); | |
807 | break; | |
e677da31 | 808 | |
92e73e63 MK |
809 | case F_USERS: |
810 | case F_WALL: | |
811 | dprintf("\n"); | |
812 | v->iov_base = "\r\n"; | |
813 | v->iov_len = 2; | |
814 | wallmsg(f, iov); | |
815 | break; | |
816 | } | |
817 | f->f_prevcount = 0; | |
e677da31 RC |
818 | } |
819 | ||
820 | /* | |
821 | * WALLMSG -- Write a message to the world at large | |
822 | * | |
823 | * Write the specified message to either the entire | |
824 | * world, or a list of approved users. | |
825 | */ | |
826 | ||
64b300b4 EA |
827 | wallmsg(f, iov) |
828 | register struct filed *f; | |
829 | struct iovec *iov; | |
e677da31 | 830 | { |
e53dbb38 KB |
831 | static int reenter; /* avoid calling ourselves */ |
832 | register FILE *uf; | |
e677da31 | 833 | register int i; |
e677da31 | 834 | struct utmp ut; |
e53dbb38 | 835 | char *p, *ttymsg(); |
64b300b4 EA |
836 | |
837 | if (reenter++) | |
838 | return; | |
61b108ae | 839 | if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { |
3cdeaa19 | 840 | logerror(_PATH_UTMP); |
64b300b4 | 841 | reenter = 0; |
e677da31 | 842 | return; |
ada83039 | 843 | } |
e53dbb38 KB |
844 | /* NOSTRICT */ |
845 | while (fread((char *) &ut, sizeof ut, 1, uf) == 1) { | |
846 | if (ut.ut_name[0] == '\0') | |
847 | continue; | |
848 | if (f->f_type == F_WALL) { | |
233e81a0 KB |
849 | if (p = ttymsg(iov, 6, ut.ut_line, 1)) { |
850 | errno = 0; /* already in msg */ | |
e53dbb38 | 851 | logerror(p); |
233e81a0 | 852 | } |
e53dbb38 KB |
853 | continue; |
854 | } | |
855 | /* should we send the message to this user? */ | |
856 | for (i = 0; i < MAXUNAMES; i++) { | |
857 | if (!f->f_un.f_uname[i][0]) | |
858 | break; | |
859 | if (!strncmp(f->f_un.f_uname[i], ut.ut_name, | |
860 | UT_NAMESIZE)) { | |
233e81a0 KB |
861 | if (p = ttymsg(iov, 6, ut.ut_line, 1)) { |
862 | errno = 0; /* already in msg */ | |
e53dbb38 | 863 | logerror(p); |
233e81a0 | 864 | } |
e53dbb38 | 865 | break; |
fcd484c8 | 866 | } |
e677da31 | 867 | } |
e677da31 | 868 | } |
84555b38 | 869 | (void) fclose(uf); |
64b300b4 | 870 | reenter = 0; |
84555b38 RC |
871 | } |
872 | ||
ad787160 | 873 | SIGHANDLER |
84555b38 RC |
874 | reapchild() |
875 | { | |
ad787160 | 876 | WAITVALUE status; |
84555b38 | 877 | |
64b300b4 | 878 | while (wait3(&status, WNOHANG, (struct rusage *) NULL) > 0) |
ad787160 | 879 | continue; |
e677da31 RC |
880 | } |
881 | ||
882 | /* | |
64b300b4 | 883 | * Return a printable representation of a host address. |
e677da31 | 884 | */ |
64b300b4 EA |
885 | char * |
886 | cvthname(f) | |
e677da31 RC |
887 | struct sockaddr_in *f; |
888 | { | |
889 | struct hostent *hp; | |
ad58e75e | 890 | register char *p; |
e677da31 RC |
891 | extern char *inet_ntoa(); |
892 | ||
64b300b4 | 893 | dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); |
e677da31 RC |
894 | |
895 | if (f->sin_family != AF_INET) { | |
896 | dprintf("Malformed from address\n"); | |
64b300b4 | 897 | return ("???"); |
e677da31 RC |
898 | } |
899 | hp = gethostbyaddr(&f->sin_addr, sizeof(struct in_addr), f->sin_family); | |
900 | if (hp == 0) { | |
901 | dprintf("Host name for your address (%s) unknown\n", | |
902 | inet_ntoa(f->sin_addr)); | |
64b300b4 | 903 | return (inet_ntoa(f->sin_addr)); |
e677da31 | 904 | } |
ad787160 | 905 | if ((p = strchr(hp->h_name, '.')) && strcmp(p + 1, LocalDomain) == 0) |
ad58e75e | 906 | *p = '\0'; |
64b300b4 | 907 | return (hp->h_name); |
e677da31 RC |
908 | } |
909 | ||
ad787160 | 910 | SIGHANDLER |
ad58e75e EA |
911 | domark() |
912 | { | |
92e73e63 | 913 | register struct filed *f; |
e53dbb38 | 914 | time_t time(); |
ad58e75e | 915 | |
e53dbb38 | 916 | now = time((time_t *)NULL); |
92e73e63 MK |
917 | MarkSeq += TIMERINTVL; |
918 | if (MarkSeq >= MarkInterval) { | |
c16a39e2 | 919 | logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); |
92e73e63 MK |
920 | MarkSeq = 0; |
921 | } | |
ad58e75e | 922 | |
ad787160 | 923 | for (f = Files; f; f = f->f_nextone) { |
92e73e63 MK |
924 | if (f->f_prevcount && now >= REPEATTIME(f)) { |
925 | dprintf("flush %s: repeated %d times, %d sec.\n", | |
926 | TypeNames[f->f_type], f->f_prevcount, | |
927 | repeatinterval[f->f_repeatcount]); | |
35c3f83c | 928 | fprintlog(f, 0, (char *)NULL); |
92e73e63 MK |
929 | BACKOFF(f); |
930 | } | |
931 | } | |
932 | (void) alarm(TIMERINTVL); | |
a49a6aba RC |
933 | } |
934 | ||
ad787160 C |
935 | static char * |
936 | xstrerror() | |
937 | { | |
938 | extern int sys_nerr; | |
939 | extern char *sys_errlist[]; | |
940 | extern int errno; | |
941 | static char buff[30]; | |
942 | ||
943 | if (errno >= 0 && errno < sys_nerr) | |
944 | return sys_errlist[errno]; | |
945 | (void)sprintf(buff, "Error code %d\n", errno); | |
946 | return buff; | |
947 | } | |
948 | ||
e677da31 RC |
949 | /* |
950 | * Print syslogd errors some place. | |
951 | */ | |
952 | logerror(type) | |
953 | char *type; | |
954 | { | |
ad787160 | 955 | char buf[100]; |
e677da31 | 956 | |
e185ee1c | 957 | if (errno) |
ad787160 | 958 | (void) sprintf(buf, "syslogd: %s: %s", type, xstrerror(errno)); |
e677da31 | 959 | else |
e185ee1c | 960 | (void) sprintf(buf, "syslogd: %s", type); |
e677da31 | 961 | errno = 0; |
ada83039 | 962 | dprintf("%s\n", buf); |
ad58e75e | 963 | logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); |
e677da31 RC |
964 | } |
965 | ||
ad787160 | 966 | SIGHANDLER |
64b300b4 | 967 | die(sig) |
e677da31 | 968 | { |
92e73e63 | 969 | register struct filed *f; |
64b300b4 | 970 | char buf[100]; |
ada83039 | 971 | |
ad787160 | 972 | for (f = Files; f != NULL; f = f->f_nextone) { |
92e73e63 MK |
973 | /* flush any pending output */ |
974 | if (f->f_prevcount) | |
35c3f83c | 975 | fprintlog(f, 0, (char *)NULL); |
92e73e63 | 976 | } |
a075f884 | 977 | if (sig) { |
92e73e63 MK |
978 | dprintf("syslogd: exiting on signal %d\n", sig); |
979 | (void) sprintf(buf, "exiting on signal %d", sig); | |
d34bf11a | 980 | errno = 0; |
a075f884 MK |
981 | logerror(buf); |
982 | } | |
64b300b4 | 983 | (void) unlink(LogName); |
e677da31 RC |
984 | exit(0); |
985 | } | |
a49a6aba RC |
986 | |
987 | /* | |
64b300b4 | 988 | * INIT -- Initialize syslogd from configuration table |
a49a6aba | 989 | */ |
64b300b4 | 990 | |
ad787160 | 991 | SIGHANDLER |
64b300b4 | 992 | init() |
a49a6aba | 993 | { |
a49a6aba | 994 | register int i; |
64b300b4 | 995 | register FILE *cf; |
92e73e63 | 996 | register struct filed *f, *next, **nextp; |
64b300b4 EA |
997 | register char *p; |
998 | char cline[BUFSIZ]; | |
a49a6aba | 999 | |
64b300b4 EA |
1000 | dprintf("init\n"); |
1001 | ||
64b300b4 EA |
1002 | /* |
1003 | * Close all open log files. | |
1004 | */ | |
d34bf11a | 1005 | Initialized = 0; |
92e73e63 MK |
1006 | for (f = Files; f != NULL; f = next) { |
1007 | /* flush any pending output */ | |
1008 | if (f->f_prevcount) | |
35c3f83c | 1009 | fprintlog(f, 0, (char *)NULL); |
92e73e63 | 1010 | |
bb112360 EA |
1011 | switch (f->f_type) { |
1012 | case F_FILE: | |
1013 | case F_TTY: | |
bb112360 | 1014 | case F_CONSOLE: |
2efc48b0 | 1015 | case F_FORW: |
64b300b4 | 1016 | (void) close(f->f_file); |
bb112360 EA |
1017 | break; |
1018 | } | |
ad787160 | 1019 | next = f->f_nextone; |
92e73e63 | 1020 | free((char *) f); |
64b300b4 | 1021 | } |
92e73e63 MK |
1022 | Files = NULL; |
1023 | nextp = &Files; | |
64b300b4 EA |
1024 | |
1025 | /* open the configuration file */ | |
1026 | if ((cf = fopen(ConfFile, "r")) == NULL) { | |
1027 | dprintf("cannot open %s\n", ConfFile); | |
ad787160 | 1028 | *nextp = (struct filed *)malloc(sizeof(*f)); |
92e73e63 | 1029 | cfline("*.ERR\t/dev/console", *nextp); |
ad787160 C |
1030 | (*nextp)->f_nextone = (struct filed *)malloc(sizeof(*f)); |
1031 | cfline("*.PANIC\t*", (*nextp)->f_nextone); | |
92e73e63 | 1032 | Initialized = 1; |
64b300b4 EA |
1033 | return; |
1034 | } | |
1035 | ||
1036 | /* | |
1037 | * Foreach line in the conf table, open that file. | |
1038 | */ | |
92e73e63 MK |
1039 | f = NULL; |
1040 | while (fgets(cline, sizeof cline, cf) != NULL) { | |
e15840af KB |
1041 | /* |
1042 | * check for end-of-section, comments, strip off trailing | |
1043 | * spaces and newline character. | |
1044 | */ | |
1045 | for (p = cline; isspace(*p); ++p); | |
1046 | if (*p == NULL || *p == '#') | |
a49a6aba | 1047 | continue; |
ad787160 | 1048 | for (p = strchr(cline, '\0'); isspace(*--p);); |
e15840af | 1049 | *++p = '\0'; |
ad787160 | 1050 | f = (struct filed *)malloc(sizeof(*f)); |
92e73e63 | 1051 | *nextp = f; |
ad787160 | 1052 | nextp = &f->f_nextone; |
92e73e63 | 1053 | cfline(cline, f); |
64b300b4 EA |
1054 | } |
1055 | ||
1056 | /* close the configuration file */ | |
1057 | (void) fclose(cf); | |
1058 | ||
1059 | Initialized = 1; | |
1060 | ||
1061 | if (Debug) { | |
ad787160 | 1062 | for (f = Files; f; f = f->f_nextone) { |
c16a39e2 | 1063 | for (i = 0; i <= LOG_NFACILITIES; i++) |
233e81a0 | 1064 | if (f->f_pmask[i] == INTERNAL_NOPRI) |
64b300b4 EA |
1065 | printf("X "); |
1066 | else | |
1067 | printf("%d ", f->f_pmask[i]); | |
1068 | printf("%s: ", TypeNames[f->f_type]); | |
1069 | switch (f->f_type) { | |
1070 | case F_FILE: | |
1071 | case F_TTY: | |
1072 | case F_CONSOLE: | |
1073 | printf("%s", f->f_un.f_fname); | |
1074 | break; | |
1075 | ||
1076 | case F_FORW: | |
1077 | printf("%s", f->f_un.f_forw.f_hname); | |
1078 | break; | |
1079 | ||
1080 | case F_USERS: | |
1081 | for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) | |
1082 | printf("%s, ", f->f_un.f_uname[i]); | |
1083 | break; | |
1084 | } | |
1085 | printf("\n"); | |
1086 | } | |
1087 | } | |
1088 | ||
ad58e75e | 1089 | logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); |
64b300b4 EA |
1090 | dprintf("syslogd: restarted\n"); |
1091 | } | |
1092 | ||
1093 | /* | |
1094 | * Crack a configuration file line | |
1095 | */ | |
1096 | ||
64b300b4 EA |
1097 | cfline(line, f) |
1098 | char *line; | |
1099 | register struct filed *f; | |
1100 | { | |
1101 | register char *p; | |
1102 | register char *q; | |
1103 | register int i; | |
1104 | char *bp; | |
1105 | int pri; | |
1106 | struct hostent *hp; | |
1107 | char buf[MAXLINE]; | |
1108 | ||
1109 | dprintf("cfline(%s)\n", line); | |
1110 | ||
e185ee1c | 1111 | errno = 0; /* keep strerror() stuff out of logerror messages */ |
d34bf11a | 1112 | |
64b300b4 EA |
1113 | /* clear out file entry */ |
1114 | bzero((char *) f, sizeof *f); | |
c16a39e2 | 1115 | for (i = 0; i <= LOG_NFACILITIES; i++) |
233e81a0 | 1116 | f->f_pmask[i] = INTERNAL_NOPRI; |
64b300b4 EA |
1117 | |
1118 | /* scan through the list of selectors */ | |
1119 | for (p = line; *p && *p != '\t';) { | |
1120 | ||
1121 | /* find the end of this facility name list */ | |
1122 | for (q = p; *q && *q != '\t' && *q++ != '.'; ) | |
a49a6aba | 1123 | continue; |
64b300b4 EA |
1124 | |
1125 | /* collect priority name */ | |
ad787160 | 1126 | for (bp = buf; *q && !strchr("\t,;", *q); ) |
64b300b4 EA |
1127 | *bp++ = *q++; |
1128 | *bp = '\0'; | |
1129 | ||
1130 | /* skip cruft */ | |
ad787160 | 1131 | while (strchr(", ;", *q)) |
64b300b4 EA |
1132 | q++; |
1133 | ||
1134 | /* decode priority name */ | |
1c15e888 | 1135 | pri = decode(buf, prioritynames); |
64b300b4 EA |
1136 | if (pri < 0) { |
1137 | char xbuf[200]; | |
1138 | ||
1c15e888 C |
1139 | (void) sprintf(xbuf, "unknown priority name \"%s\"", |
1140 | buf); | |
64b300b4 EA |
1141 | logerror(xbuf); |
1142 | return; | |
1143 | } | |
1144 | ||
1145 | /* scan facilities */ | |
ad787160 C |
1146 | while (*p && !strchr("\t.;", *p)) { |
1147 | for (bp = buf; *p && !strchr("\t,;.", *p); ) | |
64b300b4 EA |
1148 | *bp++ = *p++; |
1149 | *bp = '\0'; | |
1150 | if (*buf == '*') | |
1151 | for (i = 0; i < LOG_NFACILITIES; i++) | |
1152 | f->f_pmask[i] = pri; | |
1153 | else { | |
233e81a0 | 1154 | i = decode(buf, facilitynames); |
64b300b4 EA |
1155 | if (i < 0) { |
1156 | char xbuf[200]; | |
1157 | ||
1c15e888 | 1158 | (void) sprintf(xbuf, |
e53dbb38 KB |
1159 | "unknown facility name \"%s\"", |
1160 | buf); | |
64b300b4 EA |
1161 | logerror(xbuf); |
1162 | return; | |
1163 | } | |
1164 | f->f_pmask[i >> 3] = pri; | |
1165 | } | |
1166 | while (*p == ',' || *p == ' ') | |
1167 | p++; | |
1168 | } | |
1169 | ||
1170 | p = q; | |
1171 | } | |
1172 | ||
1173 | /* skip to action part */ | |
1174 | while (*p == '\t') | |
1175 | p++; | |
1176 | ||
1177 | switch (*p) | |
1178 | { | |
1179 | case '@': | |
1180 | if (!InetInuse) | |
1181 | break; | |
1182 | (void) strcpy(f->f_un.f_forw.f_hname, ++p); | |
1183 | hp = gethostbyname(p); | |
1184 | if (hp == NULL) { | |
ad787160 | 1185 | logerror("hostname lookup error"); |
64b300b4 EA |
1186 | break; |
1187 | } | |
1188 | bzero((char *) &f->f_un.f_forw.f_addr, | |
1189 | sizeof f->f_un.f_forw.f_addr); | |
1190 | f->f_un.f_forw.f_addr.sin_family = AF_INET; | |
1191 | f->f_un.f_forw.f_addr.sin_port = LogPort; | |
1192 | bcopy(hp->h_addr, (char *) &f->f_un.f_forw.f_addr.sin_addr, hp->h_length); | |
64b300b4 EA |
1193 | f->f_type = F_FORW; |
1194 | break; | |
1195 | ||
1196 | case '/': | |
1197 | (void) strcpy(f->f_un.f_fname, p); | |
e53dbb38 | 1198 | if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { |
e15840af | 1199 | f->f_file = F_UNUSED; |
64b300b4 EA |
1200 | logerror(p); |
1201 | break; | |
1202 | } | |
43d42ac6 | 1203 | if (isatty(f->f_file)) |
64b300b4 | 1204 | f->f_type = F_TTY; |
64b300b4 EA |
1205 | else |
1206 | f->f_type = F_FILE; | |
1207 | if (strcmp(p, ctty) == 0) | |
1208 | f->f_type = F_CONSOLE; | |
1209 | break; | |
1210 | ||
1211 | case '*': | |
1212 | f->f_type = F_WALL; | |
1213 | break; | |
1214 | ||
1215 | default: | |
1216 | for (i = 0; i < MAXUNAMES && *p; i++) { | |
1217 | for (q = p; *q && *q != ','; ) | |
1218 | q++; | |
e185ee1c KB |
1219 | (void) strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); |
1220 | if ((q - p) > UT_NAMESIZE) | |
1221 | f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; | |
64b300b4 EA |
1222 | else |
1223 | f->f_un.f_uname[i][q - p] = '\0'; | |
1224 | while (*q == ',' || *q == ' ') | |
1225 | q++; | |
1226 | p = q; | |
1227 | } | |
1228 | f->f_type = F_USERS; | |
1229 | break; | |
a49a6aba | 1230 | } |
64b300b4 EA |
1231 | } |
1232 | ||
1233 | ||
1234 | /* | |
1235 | * Decode a symbolic name to a numeric value | |
1236 | */ | |
1237 | ||
1238 | decode(name, codetab) | |
1239 | char *name; | |
233e81a0 | 1240 | CODE *codetab; |
64b300b4 | 1241 | { |
233e81a0 | 1242 | register CODE *c; |
64b300b4 EA |
1243 | register char *p; |
1244 | char buf[40]; | |
1245 | ||
1246 | if (isdigit(*name)) | |
1247 | return (atoi(name)); | |
1248 | ||
1249 | (void) strcpy(buf, name); | |
1250 | for (p = buf; *p; p++) | |
1251 | if (isupper(*p)) | |
1252 | *p = tolower(*p); | |
1253 | for (c = codetab; c->c_name; c++) | |
1254 | if (!strcmp(buf, c->c_name)) | |
1255 | return (c->c_val); | |
a49a6aba | 1256 | |
64b300b4 | 1257 | return (-1); |
a49a6aba | 1258 | } |
ad787160 C |
1259 | |
1260 | daemon(nochdir, noclose) | |
1261 | int nochdir, noclose; | |
1262 | { | |
1263 | int cpid; | |
1264 | ||
1265 | if ((cpid = fork()) == -1) | |
1266 | return (-1); | |
1267 | if (cpid) | |
1268 | exit(0); | |
1269 | (void) setsid(); | |
1270 | if (!nochdir) | |
1271 | (void) chdir("/"); | |
1272 | if (!noclose) { | |
1273 | int devnull = open("/dev/null", O_RDWR, 0); | |
1274 | ||
1275 | if (devnull != -1) { | |
1276 | (void) dup2(devnull, 0); | |
1277 | (void) dup2(devnull, 1); | |
1278 | (void) dup2(devnull, 2); | |
1279 | if (devnull > 2) | |
1280 | (void) close(devnull); | |
1281 | } | |
1282 | } | |
1283 | } | |
1284 | ||
1285 | ||
1286 | /* | |
1287 | * Display the contents of a uio structure on a terminal. Used by wall(1) | |
1288 | * and syslogd(8). Forks and finishes in child if write would block, waiting | |
1289 | * at most five minutes. Returns pointer to error string on unexpected error; | |
1290 | * string is not newline-terminated. Various "normal" errors are ignored | |
1291 | * (exclusive-use, lack of permission, etc.). | |
1292 | */ | |
1293 | char * | |
1294 | ttymsg(iov, iovcnt, line) | |
1295 | struct iovec *iov; | |
1296 | int iovcnt; | |
1297 | char *line; | |
1298 | { | |
1299 | static char device[64] = _PATH_DEV; | |
1300 | static char errbuf[1024]; | |
1301 | register int cnt, fd, left, wret; | |
1302 | struct iovec localiov[6]; | |
1303 | int forked = 0; | |
1304 | ||
1305 | if (iovcnt > 6) | |
1306 | return ("too many iov's"); | |
1307 | /* | |
1308 | * open will fail on slip lines or exclusive-use lines | |
1309 | * if not running as root; not an error. | |
1310 | */ | |
1311 | (void) strcpy(device + sizeof(_PATH_DEV) - 1, line); | |
1312 | if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) { | |
1313 | if (errno == EBUSY || errno == EACCES) | |
1314 | return (NULL); | |
1315 | (void) sprintf(errbuf, "%s: error %d", device, errno); | |
1316 | return (errbuf); | |
1317 | } | |
1318 | ||
1319 | for (cnt = left = 0; cnt < iovcnt; ++cnt) | |
1320 | left += iov[cnt].iov_len; | |
1321 | ||
1322 | for (;;) { | |
1323 | wret = writev(fd, iov, iovcnt); | |
1324 | if (wret >= left) | |
1325 | break; | |
1326 | if (wret >= 0) { | |
1327 | left -= wret; | |
1328 | if (iov != localiov) { | |
1329 | bcopy(iov, localiov, | |
1330 | iovcnt * sizeof(struct iovec)); | |
1331 | iov = localiov; | |
1332 | } | |
1333 | for (cnt = 0; wret >= iov->iov_len; ++cnt) { | |
1334 | wret -= iov->iov_len; | |
1335 | ++iov; | |
1336 | --iovcnt; | |
1337 | } | |
1338 | if (wret) { | |
1339 | iov->iov_base += wret; | |
1340 | iov->iov_len -= wret; | |
1341 | } | |
1342 | continue; | |
1343 | } | |
1344 | if (errno == EWOULDBLOCK) { | |
1345 | int cpid, off = 0; | |
1346 | ||
1347 | if (forked) { | |
1348 | (void) close(fd); | |
1349 | _exit(1); | |
1350 | } | |
1351 | cpid = fork(); | |
1352 | if (cpid < 0) { | |
1353 | (void) sprintf(errbuf, | |
1354 | "fork: error %d", errno); | |
1355 | (void) close(fd); | |
1356 | return (errbuf); | |
1357 | } | |
1358 | if (cpid) { /* parent */ | |
1359 | (void) close(fd); | |
1360 | return (NULL); | |
1361 | } | |
1362 | forked++; | |
1363 | /* wait at most 5 minutes */ | |
1364 | (void) signal(SIGALRM, SIG_DFL); | |
1365 | (void) signal(SIGTERM, SIG_DFL); /* XXX */ | |
1366 | (void) sigsetmask(0); | |
1367 | (void) alarm((u_int)(60 * 5)); | |
1368 | (void) fcntl(fd, FNDELAY, &off); | |
1369 | continue; | |
1370 | } | |
1371 | /* | |
1372 | * We get ENODEV on a slip line if we're running as root, | |
1373 | * and EIO if the line just went away. | |
1374 | */ | |
1375 | if (errno == ENODEV || errno == EIO) | |
1376 | break; | |
1377 | (void) close(fd); | |
1378 | if (forked) | |
1379 | _exit(1); | |
1380 | (void) sprintf(errbuf, "%s: error %d", errno); | |
1381 | return (errbuf); | |
1382 | } | |
1383 | ||
1384 | (void) close(fd); | |
1385 | if (forked) | |
1386 | _exit(0); | |
1387 | return (NULL); | |
1388 | } |