1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35#define FOR_syslogd
36#include "toys.h"
37
38
39struct unsocks {
40 struct unsocks *next;
41 char *path;
42 struct sockaddr_un sdu;
43 int sd;
44};
45
46
47struct logfile {
48 struct logfile *next;
49 char *filename;
50 uint32_t facility[8];
51 uint8_t level[LOG_NFACILITIES];
52 int logfd;
53 struct sockaddr_in saddr;
54};
55
56GLOBALS(
57 char *socket;
58 char *config_file;
59 char *unix_socket;
60 char *logfile;
61 long interval;
62 long rot_size;
63 long rot_count;
64 char *remote_log;
65 long log_prio;
66
67 struct unsocks *lsocks;
68 struct logfile *lfiles;
69 int sigfd[2];
70)
71
72
73
74int logger_lookup(int where, char *key)
75{
76 CODE *w = ((CODE *[]){facilitynames, prioritynames})[where];
77
78 for (; w->c_name; w++)
79 if (!strcasecmp(key, w->c_name)) return w->c_val;
80
81 return -1;
82}
83
84
85static char *dec(int val, CODE *clist, char *buf)
86{
87 for (; clist->c_name; clist++)
88 if (val == clist->c_val) return clist->c_name;
89 sprintf(buf, "%u", val);
90
91 return buf;
92}
93
94
95
96
97
98static int resolve_config(struct logfile *file, char *config)
99{
100 char *tk;
101
102 for (tk = strtok(config, "; \0"); tk; tk = strtok(NULL, "; \0")) {
103 char *fac = tk, *lvl;
104 int i = 0;
105 unsigned facval = 0;
106 uint8_t set, levval, bits = 0;
107
108 tk = strchr(fac, '.');
109 if (!tk) return -1;
110 *tk = '\0';
111 lvl = tk + 1;
112
113 for (;;) {
114 char *nfac = strchr(fac, ',');
115
116 if (nfac) *nfac = '\0';
117 if (*fac == '*') {
118 facval = 0xFFFFFFFF;
119 if (fac[1]) return -1;
120 } else {
121 if ((i = logger_lookup(0, fac)) == -1) return -1;
122 facval |= (1 << LOG_FAC(i));
123 }
124 if (nfac) fac = nfac + 1;
125 else break;
126 }
127
128 levval = 0;
129 for (tk = "!=*"; *tk; tk++, bits <<= 1) {
130 if (*lvl == *tk) {
131 bits++;
132 lvl++;
133 }
134 }
135 if (bits & 2) levval = 0xff;
136 if (*lvl) {
137 if ((i = logger_lookup(1, lvl)) == -1) return -1;
138 levval |= (bits & 4) ? LOG_MASK(i) : LOG_UPTO(i);
139 if (bits & 8) levval = ~levval;
140 }
141
142 for (i = 0, set = levval; set; set >>= 1, i++)
143 if (set & 0x1) file->facility[i] |= ~facval;
144 for (i = 0; i < LOG_NFACILITIES; facval >>= 1, i++)
145 if (facval & 0x1) file->level[i] |= ~levval;
146 }
147
148 return 0;
149}
150
151
152static int parse_config_file(void)
153{
154 struct logfile *file;
155 FILE *fp;
156 char *confline, *tk[2];
157 int len, lineno = 0;
158 size_t linelen;
159
160
161
162
163
164 if (toys.optflags & FLAG_K) {
165 file = xzalloc(sizeof(struct logfile));
166 file->filename = xstrdup("/dev/kmsg");
167 TT.lfiles = file;
168 return 0;
169 }
170
171
172
173
174
175
176 if (toys.optflags & FLAG_R) {
177 file = xzalloc(sizeof(struct logfile));
178 file->filename = xmprintf("@%s",TT.remote_log);
179 TT.lfiles = file;
180 if (!(toys.optflags & FLAG_L)) return 0;
181 }
182
183
184
185
186 if (!(fp = fopen(TT.config_file, "r")) && (toys.optflags & FLAG_f))
187 perror_exit("can't open '%s'", TT.config_file);
188
189 for (linelen = 0; fp;) {
190 confline = NULL;
191 len = getline(&confline, &linelen, fp);
192 if (len <= 0) break;
193 lineno++;
194 for (; *confline == ' '; confline++, len--) ;
195 if ((confline[0] == '#') || (confline[0] == '\n')) continue;
196 tk[0] = confline;
197 for (; len && !(*tk[0]==' ' || *tk[0]=='\t'); tk[0]++, len--);
198 for (tk[1] = tk[0]; len && (*tk[1]==' ' || *tk[1]=='\t'); tk[1]++, len--);
199 if (!len || (len == 1 && *tk[1] == '\n')) {
200 error_msg("error in '%s' at line %d", TT.config_file, lineno);
201 return -1;
202 }
203 else if (*(tk[1] + len - 1) == '\n') *(tk[1] + len - 1) = '\0';
204 *tk[0] = '\0';
205 if (*tk[1] != '*') {
206 file = TT.lfiles;
207 while (file && strcmp(file->filename, tk[1])) file = file->next;
208 if (!file) {
209 file = xzalloc(sizeof(struct logfile));
210 file->filename = xstrdup(tk[1]);
211 file->next = TT.lfiles;
212 TT.lfiles = file;
213 }
214 if (resolve_config(file, confline) == -1) {
215 error_msg("error in '%s' at line %d", TT.config_file, lineno);
216 return -1;
217 }
218 }
219 free(confline);
220 }
221
222
223
224
225 if (!fp){
226 file = xzalloc(sizeof(struct logfile));
227 file->filename = xstrdup((toys.optflags & FLAG_O) ?
228 TT.logfile : "/var/log/messages");
229 file->next = TT.lfiles;
230 TT.lfiles = file;
231 } else fclose(fp);
232 return 0;
233}
234
235
236static void open_logfiles(void)
237{
238 struct logfile *tfd;
239
240 for (tfd = TT.lfiles; tfd; tfd = tfd->next) {
241 char *p, *tmpfile;
242 long port = 514;
243
244 if (*tfd->filename == '@') {
245 struct addrinfo *info, rp;
246
247 tmpfile = xstrdup(tfd->filename + 1);
248 if ((p = strchr(tmpfile, ':'))) {
249 char *endptr;
250
251 *p = '\0';
252 port = strtol(++p, &endptr, 10);
253 if (*endptr || endptr == p || port < 0 || port > 65535)
254 error_exit("bad port in %s", tfd->filename);
255 }
256 memset(&rp, 0, sizeof(rp));
257 rp.ai_family = AF_INET;
258 rp.ai_socktype = SOCK_DGRAM;
259 rp.ai_protocol = IPPROTO_UDP;
260
261 if (getaddrinfo(tmpfile, NULL, &rp, &info) || !info)
262 perror_exit("BAD ADDRESS: can't find : %s ", tmpfile);
263 ((struct sockaddr_in*)info->ai_addr)->sin_port = htons(port);
264 memcpy(&tfd->saddr, info->ai_addr, info->ai_addrlen);
265 freeaddrinfo(info);
266
267 tfd->logfd = xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
268 free(tmpfile);
269 } else tfd->logfd = open(tfd->filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
270 if (tfd->logfd < 0) {
271 tfd->filename = "/dev/console";
272 tfd->logfd = open(tfd->filename, O_APPEND);
273 }
274 }
275}
276
277
278static int write_rotate(struct logfile *tf, int len)
279{
280 int size, isreg;
281 struct stat statf;
282 isreg = (!fstat(tf->logfd, &statf) && S_ISREG(statf.st_mode));
283 size = statf.st_size;
284
285 if ((toys.optflags & FLAG_s) || (toys.optflags & FLAG_b)) {
286 if (TT.rot_size && isreg && (size + len) > (TT.rot_size*1024)) {
287 if (TT.rot_count) {
288 int i = strlen(tf->filename) + 3 + 1;
289 char old_file[i];
290 char new_file[i];
291 i = TT.rot_count - 1;
292 while (1) {
293 sprintf(new_file, "%s.%d", tf->filename, i);
294 if (!i) break;
295 sprintf(old_file, "%s.%d", tf->filename, --i);
296 rename(old_file, new_file);
297 }
298 rename(tf->filename, new_file);
299 unlink(tf->filename);
300 close(tf->logfd);
301 tf->logfd = open(tf->filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
302 if (tf->logfd < 0) {
303 perror_msg("can't open %s", tf->filename);
304 return -1;
305 }
306 }
307 ftruncate(tf->logfd, 0);
308 }
309 }
310 return write(tf->logfd, toybuf, len);
311}
312
313
314static void logmsg(char *msg, int len)
315{
316 time_t now;
317 char *p, *ts, *lvlstr, *facstr;
318 struct utsname uts;
319 int pri = 0;
320 struct logfile *tf = TT.lfiles;
321
322 char *omsg = msg;
323 int olen = len, fac, lvl;
324
325 if (*msg == '<') {
326 pri = (int) strtoul(msg + 1, &p, 10);
327 if (*p == '>') msg = p + 1;
328 }
329
330
331
332 if (len < 16 || msg[3] != ' ' || msg[6] != ' ' || msg[9] != ':'
333 || msg[12] != ':' || msg[15] != ' ') {
334 time(&now);
335 ts = ctime(&now) + 4;
336 } else {
337 now = 0;
338 ts = msg;
339 msg += 16;
340 }
341 ts[15] = '\0';
342 fac = LOG_FAC(pri);
343 lvl = LOG_PRI(pri);
344
345 if (toys.optflags & FLAG_K) len = sprintf(toybuf, "<%d> %s", pri, msg);
346 else {
347 char facbuf[12], pribuf[12];
348
349 facstr = dec(pri & LOG_FACMASK, facilitynames, facbuf);
350 lvlstr = dec(LOG_PRI(pri), prioritynames, pribuf);
351
352 p = "local";
353 if (!uname(&uts)) p = uts.nodename;
354 if (toys.optflags & FLAG_S) len = sprintf(toybuf, "%s %s", ts, msg);
355 else len = sprintf(toybuf, "%s %s %s.%s %s", ts, p, facstr, lvlstr, msg);
356 }
357 if (lvl >= TT.log_prio) return;
358
359 for (; tf; tf = tf->next) {
360 if (tf->logfd > 0) {
361 if (!((tf->facility[lvl] & (1 << fac)) || (tf->level[fac] & (1<<lvl)))) {
362 int wlen, isNetwork = *tf->filename == '@';
363 if (isNetwork)
364 wlen = sendto(tf->logfd, omsg, olen, 0, (struct sockaddr*)&tf->saddr, sizeof(tf->saddr));
365 else wlen = write_rotate(tf, len);
366 if (wlen < 0) perror_msg("write failed file : %s ", tf->filename + isNetwork);
367 }
368 }
369 }
370}
371
372
373
374
375
376static void cleanup(void)
377{
378 while (TT.lsocks) {
379 struct unsocks *fnode = TT.lsocks;
380
381 if (fnode->sd >= 0) {
382 close(fnode->sd);
383 unlink(fnode->path);
384 }
385 TT.lsocks = fnode->next;
386 free(fnode);
387 }
388
389 while (TT.lfiles) {
390 struct logfile *fnode = TT.lfiles;
391
392 free(fnode->filename);
393 if (fnode->logfd >= 0) close(fnode->logfd);
394 TT.lfiles = fnode->next;
395 free(fnode);
396 }
397}
398
399static void signal_handler(int sig)
400{
401 unsigned char ch = sig;
402 if (write(TT.sigfd[1], &ch, 1) != 1) error_msg("can't send signal");
403}
404
405void syslogd_main(void)
406{
407 struct unsocks *tsd;
408 int nfds, retval, last_len=0;
409 struct timeval tv;
410 fd_set rfds;
411 char *temp, *buffer = (toybuf +2048), *last_buf = (toybuf + 3072);
412
413 if ((toys.optflags & FLAG_p) && (strlen(TT.unix_socket) > 108))
414 error_exit("Socket path should not be more than 108");
415
416 TT.config_file = (toys.optflags & FLAG_f) ?
417 TT.config_file : "/etc/syslog.conf";
418init_jumpin:
419 tsd = xzalloc(sizeof(struct unsocks));
420
421 tsd->path = (toys.optflags & FLAG_p) ? TT.unix_socket : "/dev/log";
422 TT.lsocks = tsd;
423
424 if (toys.optflags & FLAG_a) {
425 for (temp = strtok(TT.socket, ":"); temp; temp = strtok(NULL, ":")) {
426 if (strlen(temp) > 107) temp[108] = '\0';
427 tsd = xzalloc(sizeof(struct unsocks));
428 tsd->path = temp;
429 tsd->next = TT.lsocks;
430 TT.lsocks = tsd;
431 }
432 }
433
434
435
436
437
438 nfds = 0;
439 for (tsd = TT.lsocks; tsd; tsd = tsd->next) {
440 tsd->sdu.sun_family = AF_UNIX;
441 strcpy(tsd->sdu.sun_path, tsd->path);
442 tsd->sd = socket(AF_UNIX, SOCK_DGRAM, 0);
443 if (tsd->sd < 0) {
444 perror_msg("OPEN SOCKS : failed");
445 continue;
446 }
447 unlink(tsd->sdu.sun_path);
448 if (bind(tsd->sd, (struct sockaddr *) &tsd->sdu, sizeof(tsd->sdu))) {
449 perror_msg("BIND SOCKS : failed sock : %s", tsd->sdu.sun_path);
450 close(tsd->sd);
451 continue;
452 }
453 chmod(tsd->path, 0777);
454 nfds++;
455 }
456 if (!nfds) {
457 error_msg("Can't open single socket for listening.");
458 goto clean_and_exit;
459 }
460
461
462 xpipe(TT.sigfd);
463
464 fcntl(TT.sigfd[1] , F_SETFD, FD_CLOEXEC);
465 fcntl(TT.sigfd[0] , F_SETFD, FD_CLOEXEC);
466 int flags = fcntl(TT.sigfd[1], F_GETFL);
467 fcntl(TT.sigfd[1], F_SETFL, flags | O_NONBLOCK);
468 signal(SIGHUP, signal_handler);
469 signal(SIGTERM, signal_handler);
470 signal(SIGINT, signal_handler);
471 signal(SIGQUIT, signal_handler);
472
473 if (parse_config_file() == -1) goto clean_and_exit;
474 open_logfiles();
475 if (!(toys.optflags & FLAG_n)) {
476 daemon(0, 0);
477
478 toys.optflags |= FLAG_n;
479 }
480 xpidfile("syslogd");
481
482 logmsg("<46>Toybox: syslogd started", 27);
483 for (;;) {
484
485 FD_ZERO(&rfds);
486 for (tsd = TT.lsocks; tsd; tsd = tsd->next) FD_SET(tsd->sd, &rfds);
487 FD_SET(TT.sigfd[0], &rfds);
488 tv.tv_usec = 0;
489 tv.tv_sec = TT.interval*60;
490
491 retval = select(TT.sigfd[0] + 1, &rfds, NULL, NULL, (TT.interval)?&tv:NULL);
492 if (retval < 0) {
493 if (errno != EINTR) perror_msg("Error in select ");
494 }
495 else if (!retval) logmsg("<46>-- MARK --", 14);
496 else if (FD_ISSET(TT.sigfd[0], &rfds)) {
497 unsigned char sig;
498
499 if (read(TT.sigfd[0], &sig, 1) != 1) {
500 error_msg("signal read failed.\n");
501 continue;
502 }
503 switch(sig) {
504 case SIGTERM:
505 case SIGINT:
506 case SIGQUIT:
507 logmsg("<46>syslogd exiting", 19);
508 if (CFG_TOYBOX_FREE ) cleanup();
509 signal(sig, SIG_DFL);
510 sigset_t ss;
511 sigemptyset(&ss);
512 sigaddset(&ss, sig);
513 sigprocmask(SIG_UNBLOCK, &ss, NULL);
514 raise(sig);
515 _exit(1);
516 break;
517 case SIGHUP:
518 logmsg("<46>syslogd exiting", 19);
519 cleanup();
520 goto init_jumpin;
521 default: break;
522 }
523 } else {
524 for (tsd = TT.lsocks; tsd; tsd = tsd->next) {
525 int sd = tsd->sd;
526 if (FD_ISSET(sd, &rfds)) {
527
528
529 int len = read(sd, buffer, 1022);
530
531
532
533 while (len > 0 &&
534 (buffer[len - 1] == '\n' || buffer[len - 1] == '\0')) {
535 --len;
536 }
537
538 if (len > 0) {
539 buffer[len++] = '\n';
540 buffer[len] = '\0';
541 if((toys.optflags & FLAG_D) && (len == last_len))
542 if (!memcmp(last_buf, buffer, len)) break;
543
544 memcpy(last_buf, buffer, len);
545 last_len = len;
546 logmsg(buffer, len);
547 }
548 break;
549 }
550 }
551 }
552 }
553clean_and_exit:
554 logmsg("<46>syslogd exiting", 19);
555 if (CFG_TOYBOX_FREE ) cleanup();
556}
557