Mercurial > hg > toybox
annotate toys/pending/syslogd.c @ 995:893c86bbe452
Add daemonize function to lib for klogd and syslogd
author | Felix Janda <felix.janda@posteo.de> |
---|---|
date | Sat, 10 Aug 2013 20:18:18 +0200 |
parents | c0627c163893 |
children | 8b1814e4c987 |
rev | line source |
---|---|
960 | 1 /* syslogd.c - a system logging utility. |
2 * | |
3 * Copyright 2013 Madhur Verma <mad.flexi@gmail.com> | |
4 * | |
5 * No Standard | |
6 | |
7 USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT)) | |
8 | |
9 config SYSLOGD | |
10 bool "syslogd" | |
11 default n | |
12 help | |
13 Usage: syslogd [-a socket] [-p socket] [-O logfile] [-f config file] [-m interval] | |
14 [-p socket] [-s SIZE] [-b N] [-R HOST] [-l N] [-nSLKD] | |
15 | |
16 System logging utility | |
17 | |
18 -a Extra unix socket for listen | |
19 -O FILE Default log file <DEFAULT: /var/log/messages> | |
20 -f FILE Config file <DEFAULT: /etc/syslog.conf> | |
21 -p Alternative unix domain socket <DEFAULT : /dev/log> | |
22 -n Avoid auto-backgrounding. | |
23 -S Smaller output | |
24 -m MARK interval <DEFAULT: 20 minutes> (RANGE: 0 to 71582787) | |
25 -R HOST Log to IP or hostname on PORT (default PORT=514/UDP)" | |
26 -L Log locally and via network (default is network only if -R)" | |
27 -s SIZE Max size (KB) before rotation (default:200KB, 0=off) | |
28 -b N rotated logs to keep (default:1, max=99, 0=purge) | |
29 -K Log to kernel printk buffer (use dmesg to read it) | |
30 -l N Log only messages more urgent than prio(default:8 max:8 min:1) | |
31 -D Drop duplicates | |
32 */ | |
33 | |
34 #define FOR_syslogd | |
35 #include "toys.h" | |
36 #include "toynet.h" | |
37 | |
38 GLOBALS( | |
39 char *socket; | |
40 char *config_file; | |
41 char *unix_socket; | |
42 char *logfile; | |
43 long interval; | |
44 long rot_size; | |
45 long rot_count; | |
46 char *remote_log; | |
47 long log_prio; | |
48 | |
49 struct arg_list *lsocks; // list of listen sockets | |
50 struct arg_list *lfiles; // list of write logfiles | |
51 fd_set rfds; // fds for reading | |
52 int sd; // socket for logging remote messeges. | |
53 ) | |
54 | |
55 #define flag_get(f,v,d) ((toys.optflags & f) ? v : d) | |
56 #define flag_chk(f) ((toys.optflags & f) ? 1 : 0) | |
57 | |
58 #ifndef SYSLOG_NAMES | |
59 #define INTERNAL_NOPRI 0x10 | |
60 #define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES, 0) | |
61 | |
62 typedef struct _code { | |
63 char *c_name; | |
64 int c_val; | |
65 } CODE; | |
66 | |
67 static CODE prioritynames[] = | |
68 { | |
69 { "alert", LOG_ALERT }, | |
70 { "crit", LOG_CRIT }, | |
71 { "debug", LOG_DEBUG }, | |
72 { "emerg", LOG_EMERG }, | |
73 { "err", LOG_ERR }, | |
74 { "error", LOG_ERR }, /* DEPRECATED */ | |
75 { "info", LOG_INFO }, | |
76 { "none", INTERNAL_NOPRI }, /* INTERNAL */ | |
77 { "notice", LOG_NOTICE }, | |
78 { "panic", LOG_EMERG }, /* DEPRECATED */ | |
79 { "warn", LOG_WARNING }, /* DEPRECATED */ | |
80 { "warning", LOG_WARNING }, | |
81 { NULL, -1 } | |
82 }; | |
83 | |
84 static CODE facilitynames[] = | |
85 { | |
86 { "auth", LOG_AUTH }, | |
87 { "authpriv", LOG_AUTHPRIV }, | |
88 { "cron", LOG_CRON }, | |
89 { "daemon", LOG_DAEMON }, | |
90 { "ftp", LOG_FTP }, | |
91 { "kern", LOG_KERN }, | |
92 { "lpr", LOG_LPR }, | |
93 { "mail", LOG_MAIL }, | |
94 { "mark", INTERNAL_MARK }, /* INTERNAL */ | |
95 { "news", LOG_NEWS }, | |
96 { "security", LOG_AUTH }, /* DEPRECATED */ | |
97 { "syslog", LOG_SYSLOG }, | |
98 { "user", LOG_USER }, | |
99 { "uucp", LOG_UUCP }, | |
100 { "local0", LOG_LOCAL0 }, | |
101 { "local1", LOG_LOCAL1 }, | |
102 { "local2", LOG_LOCAL2 }, | |
103 { "local3", LOG_LOCAL3 }, | |
104 { "local4", LOG_LOCAL4 }, | |
105 { "local5", LOG_LOCAL5 }, | |
106 { "local6", LOG_LOCAL6 }, | |
107 { "local7", LOG_LOCAL7 }, | |
108 { NULL, -1 } | |
109 }; | |
110 #endif | |
111 | |
112 | |
113 // Signal handling | |
114 struct fd_pair { int rd; int wr; }; | |
115 static struct fd_pair sigfd; | |
116 | |
117 // UNIX Sockets for listening | |
118 typedef struct unsocks_s { | |
119 char *path; | |
120 struct sockaddr_un sdu; | |
121 int sd; | |
122 } unsocks_t; | |
123 | |
124 // Log file entry to log into. | |
125 typedef struct logfile_s { | |
126 char *filename; | |
127 char *config; | |
128 uint8_t isNetwork; | |
129 uint32_t facility[8]; | |
130 uint8_t level[LOG_NFACILITIES]; | |
131 int logfd; | |
132 struct sockaddr_in saddr; | |
133 } logfile_t; | |
134 | |
135 // Adds opened socks to rfds for select() | |
136 static int addrfds(void) | |
137 { | |
138 unsocks_t *sock; | |
139 int ret = 0; | |
140 struct arg_list *node = TT.lsocks; | |
141 FD_ZERO(&TT.rfds); | |
142 | |
143 while (node) { | |
144 sock = (unsocks_t*) node->arg; | |
145 if (sock->sd > 2) { | |
146 FD_SET(sock->sd, &TT.rfds); | |
147 ret = sock->sd; | |
148 } | |
149 node = node->next; | |
150 } | |
151 FD_SET(sigfd.rd, &TT.rfds); | |
152 return (sigfd.rd > ret)?sigfd.rd:ret; | |
153 } | |
154 | |
155 /* | |
156 * initializes unsock_t structure | |
157 * and opens socket for reading | |
158 * and adds to global lsock list. | |
159 */ | |
160 static int open_unix_socks(void) | |
161 { | |
162 struct arg_list *node; | |
163 unsocks_t *sock; | |
164 int ret = 0; | |
165 | |
166 for(node = TT.lsocks; node; node = node->next) { | |
167 sock = (unsocks_t*) node->arg; | |
168 sock->sdu.sun_family = AF_UNIX; | |
169 strcpy(sock->sdu.sun_path, sock->path); | |
170 sock->sd = socket(AF_UNIX, SOCK_DGRAM, 0); | |
171 if (sock->sd < 0) { | |
172 perror_msg("OPEN SOCKS : failed"); | |
173 continue; | |
174 } | |
175 unlink(sock->sdu.sun_path); | |
176 if (bind(sock->sd, (struct sockaddr *) &sock->sdu, sizeof(sock->sdu))) { | |
177 perror_msg("BIND SOCKS : failed sock : %s", sock->sdu.sun_path); | |
178 close(sock->sd); | |
179 continue; | |
180 } | |
181 chmod(sock->path, 0777); | |
182 ret++; | |
183 } | |
184 return ret; | |
185 } | |
186 | |
187 /* | |
188 * creates a socket of family INET and protocol UDP | |
189 * if successful then returns SOCK othrwise error | |
190 */ | |
191 static int open_udp_socks(char *host, int port, struct sockaddr_in *sadd) | |
192 { | |
193 struct addrinfo *info, rp; | |
194 | |
195 memset(&rp, 0, sizeof(rp)); | |
196 rp.ai_family = AF_INET; | |
197 rp.ai_socktype = SOCK_DGRAM; | |
198 rp.ai_protocol = IPPROTO_UDP; | |
199 | |
200 if (getaddrinfo(host, NULL, &rp, &info) || !info) | |
201 perror_exit("BAD ADDRESS: can't find : %s ", host); | |
202 ((struct sockaddr_in*)info->ai_addr)->sin_port = htons(port); | |
203 memcpy(sadd, info->ai_addr, info->ai_addrlen); | |
204 freeaddrinfo(info); | |
205 | |
206 return xsocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | |
207 } | |
208 | |
209 // Returns node having filename | |
210 static struct arg_list *get_file_node(char *filename, struct arg_list *list) | |
211 { | |
212 while (list) { | |
213 if (!strcmp(((logfile_t*) list->arg)->filename, filename)) return list; | |
214 list = list->next; | |
215 } | |
216 return list; | |
217 } | |
218 | |
219 /* | |
220 * recurses the logfile list and resolves config | |
221 * for evry file and updates facilty and log level bits. | |
222 */ | |
223 static int resolve_config(logfile_t *file) | |
224 { | |
225 char *tk, *fac, *lvl, *tmp, *nfac; | |
226 int count = 0; | |
227 unsigned facval = 0; | |
228 uint8_t set, levval, neg; | |
229 CODE *val = NULL; | |
230 | |
231 tmp = xstrdup(file->config); | |
232 for (tk = strtok(tmp, "; \0"); tk; tk = strtok(NULL, "; \0")) { | |
233 fac = tk; | |
234 tk = strchr(fac, '.'); | |
235 if (!tk) return -1; | |
236 *tk = '\0'; | |
237 lvl = tk + 1; | |
238 | |
239 while(1) { | |
240 count = 0; | |
241 if (*fac == '*') { | |
242 facval = 0xFFFFFFFF; | |
243 fac++; | |
244 } | |
245 nfac = strchr(fac, ','); | |
246 if (nfac) *nfac = '\0'; | |
247 while (*fac && ((CODE*) &facilitynames[count])->c_name) { | |
248 val = (CODE*) &facilitynames[count]; | |
249 if (!strcmp(fac, val->c_name)) { | |
250 facval |= (1<<LOG_FAC(val->c_val)); | |
251 break; | |
252 } | |
253 count++; | |
254 } | |
255 if (((CODE*) &facilitynames[count])->c_val == -1) | |
256 return -1; | |
257 | |
258 if (nfac) fac = nfac+1; | |
259 else break; | |
260 } | |
261 | |
262 count = 0; | |
263 set = 0; | |
264 levval = 0; | |
265 neg = 0; | |
266 if (*lvl == '!') { | |
267 neg = 1; | |
268 lvl++; | |
269 } | |
270 if (*lvl == '=') { | |
271 set = 1; | |
272 lvl++; | |
273 } | |
274 if (*lvl == '*') { | |
275 levval = 0xFF; | |
276 lvl++; | |
277 } | |
278 while (*lvl && ((CODE*) &prioritynames[count])->c_name) { | |
279 val = (CODE*) &prioritynames[count]; | |
280 if (!strcmp(lvl, val->c_name)) { | |
281 levval |= set ? LOG_MASK(val->c_val):LOG_UPTO(val->c_val); | |
282 if (neg) levval = ~levval; | |
283 break; | |
284 } | |
285 count++; | |
286 } | |
287 if (((CODE*) &prioritynames[count])->c_val == -1) return -1; | |
288 | |
289 count = 0; | |
290 set = levval; | |
291 while(set) { | |
292 if (set & 0x1) file->facility[count] |= facval; | |
293 set >>= 1; | |
294 count++; | |
295 } | |
296 for (count = 0; count < LOG_NFACILITIES; count++) { | |
297 if (facval & 0x1) file->level[count] |= levval; | |
298 facval >>= 1; | |
299 } | |
300 } | |
301 free(tmp); | |
302 | |
303 return 0; | |
304 } | |
305 | |
306 // Parse config file and update the log file list. | |
307 static int parse_config_file(void) | |
308 { | |
309 logfile_t *file; | |
310 FILE *fp = NULL; | |
311 char *confline = NULL, *tk = NULL, *tokens[2] = {NULL, NULL}; | |
312 int len, linelen, tcount, lineno = 0; | |
313 struct arg_list *node; | |
314 /* | |
315 * if -K then open only /dev/kmsg | |
316 * all other log files are neglected | |
317 * thus no need to open config either. | |
318 */ | |
319 if (flag_chk(FLAG_K)) { | |
320 node = xzalloc(sizeof(struct arg_list)); | |
321 file = xzalloc(sizeof(logfile_t)); | |
322 file->filename = "/dev/kmsg"; | |
323 file->config = "*.*"; | |
324 memset(file->level, 0xFF, sizeof(file->level)); | |
325 memset(file->facility, 0xFFFFFFFF, sizeof(file->facility)); | |
326 node->arg = (char*) file; | |
327 TT.lfiles = node; | |
328 return 0; | |
329 } | |
330 /* | |
331 * if -R then add remote host to log list | |
332 * if -L is not provided all other log | |
333 * files are neglected thus no need to | |
334 * open config either so just return. | |
335 */ | |
336 if (flag_chk(FLAG_R)) { | |
337 node = xzalloc(sizeof(struct arg_list)); | |
338 file = xzalloc(sizeof(logfile_t)); | |
339 file->filename = xmsprintf("@%s",TT.remote_log); | |
340 file->isNetwork = 1; | |
341 file->config = "*.*"; | |
342 memset(file->level, 0xFF, sizeof(file->level)); | |
343 memset(file->facility, 0xFFFFFFFF, sizeof(file->facility)); | |
344 node->arg = (char*) file; | |
345 TT.lfiles = node; | |
346 if (!flag_chk(FLAG_L))return 0; | |
347 } | |
348 /* | |
349 * Read config file and add logfiles to the list | |
350 * with their configuration. | |
351 */ | |
352 fp = fopen(TT.config_file, "r"); | |
353 if (!fp && flag_chk(FLAG_f)) | |
354 perror_exit("can't open '%s'", TT.config_file); | |
355 | |
356 for (len = 0, linelen = 0; fp;) { | |
357 len = getline(&confline, (size_t*) &linelen, fp); | |
358 if (len <= 0) break; | |
359 lineno++; | |
360 for (; *confline == ' '; confline++, len--) ; | |
361 if ((confline[0] == '#') || (confline[0] == '\n')) continue; | |
362 for (tcount = 0, tk = strtok(confline, " \t"); tk && (tcount < 2); tk = | |
363 strtok(NULL, " \t"), tcount++) { | |
364 if (tcount == 2) { | |
365 error_msg("error in '%s' at line %d", TT.config_file, lineno); | |
366 return -1; | |
367 } | |
368 tokens[tcount] = xstrdup(tk); | |
369 } | |
370 if (tcount <= 1 || tcount > 2) { | |
371 if (tokens[0]) free(tokens[0]); | |
372 error_msg("bad line %d: 1 tokens found, 2 needed", lineno); | |
373 return -1; | |
374 } | |
375 tk = (tokens[1] + (strlen(tokens[1]) - 1)); | |
376 if (*tk == '\n') *tk = '\0'; | |
377 if (*tokens[1] == '\0') { | |
378 error_msg("bad line %d: 1 tokens found, 2 needed", lineno); | |
379 return -1; | |
380 } | |
381 if (*tokens[1] == '*') goto loop_again; | |
382 | |
383 node = get_file_node(tokens[1], TT.lfiles); | |
384 if (!node) { | |
385 node = xzalloc(sizeof(struct arg_list)); | |
386 file = xzalloc(sizeof(logfile_t)); | |
387 file->config = xstrdup(tokens[0]); | |
388 if (resolve_config(file)==-1) { | |
389 error_msg("error in '%s' at line %d", TT.config_file, lineno); | |
390 return -1; | |
391 } | |
392 file->filename = xstrdup(tokens[1]); | |
393 if (*file->filename == '@') file->isNetwork = 1; | |
394 node->arg = (char*) file; | |
395 node->next = TT.lfiles; | |
396 TT.lfiles = node; | |
397 } else { | |
398 file = (logfile_t*) node->arg; | |
399 int rel = strlen(file->config) + strlen(tokens[0]) + 2; | |
400 file->config = xrealloc(file->config, rel); | |
401 sprintf(file->config, "%s;%s", file->config, tokens[0]); | |
402 } | |
403 loop_again: | |
404 if (tokens[0]) free(tokens[0]); | |
405 if (tokens[1]) free(tokens[1]); | |
406 free(confline); | |
407 confline = NULL; | |
408 } | |
409 /* | |
410 * Can't open config file or support is not enabled | |
411 * adding default logfile to the head of list. | |
412 */ | |
413 if (!fp){ | |
414 node = xzalloc(sizeof(struct arg_list)); | |
415 file = xzalloc(sizeof(logfile_t)); | |
416 file->filename = flag_get(FLAG_O, TT.logfile, "/var/log/messages"); //DEFLOGFILE | |
417 file->isNetwork = 0; | |
418 file->config = "*.*"; | |
419 memset(file->level, 0xFF, sizeof(file->level)); | |
420 memset(file->facility, 0xFFFFFFFF, sizeof(file->facility)); | |
421 node->arg = (char*) file; | |
422 node->next = TT.lfiles; | |
423 TT.lfiles = node; | |
424 } | |
425 if (fp) { | |
426 fclose(fp); | |
427 fp = NULL; | |
428 } | |
429 return 0; | |
430 } | |
431 | |
432 static int getport(char *str, char *filename) | |
433 { | |
434 char *endptr = NULL; | |
435 int base = 10; | |
436 errno = 0; | |
437 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) { | |
438 base = 16; | |
439 str += 2; | |
440 } | |
441 long port = strtol(str, &endptr, base); | |
442 if (errno || *endptr!='\0'|| endptr == str | |
443 || port < 0 || port > 65535) error_exit("wrong port no in %s", filename); | |
444 return (int)port; | |
445 } | |
446 | |
447 // open every log file in list. | |
448 static void open_logfiles(void) | |
449 { | |
450 logfile_t *tfd; | |
451 char *p, *tmpfile; | |
452 int port = -1; | |
453 struct arg_list *node = TT.lfiles; | |
454 | |
455 while (node) { | |
456 tfd = (logfile_t*) node->arg; | |
457 if (tfd->isNetwork) { | |
458 tmpfile = xstrdup(tfd->filename +1); | |
459 if ((p = strchr(tmpfile, ':'))) { | |
460 *p = '\0'; | |
461 port = getport(p + 1, tfd->filename); | |
462 } | |
463 tfd->logfd = open_udp_socks(tmpfile, (port>=0)?port:514, &tfd->saddr); | |
464 free(tmpfile); | |
465 } else tfd->logfd = open(tfd->filename, O_CREAT | O_WRONLY | O_APPEND, 0666); | |
466 if (tfd->logfd < 0) { | |
467 tfd->filename = "/dev/console"; | |
468 tfd->logfd = open(tfd->filename, O_APPEND); | |
469 } | |
470 node = node->next; | |
471 } | |
472 } | |
473 | |
474 //write to file with rotation | |
475 static int write_rotate( logfile_t *tf, int len) | |
476 { | |
477 int size, isreg; | |
478 struct stat statf; | |
479 isreg = (!fstat(tf->logfd, &statf) && S_ISREG(statf.st_mode)); | |
480 size = statf.st_size; | |
481 | |
482 if (flag_chk(FLAG_s) || flag_chk(FLAG_b)) { | |
483 if (TT.rot_size && isreg && (size + len) > (TT.rot_size*1024)) { | |
484 if (TT.rot_count) { /* always 0..99 */ | |
485 int i = strlen(tf->filename) + 3 + 1; | |
486 char old_file[i]; | |
487 char new_file[i]; | |
488 i = TT.rot_count - 1; | |
489 while (1) { | |
490 sprintf(new_file, "%s.%d", tf->filename, i); | |
491 if (!i) break; | |
492 sprintf(old_file, "%s.%d", tf->filename, --i); | |
493 rename(old_file, new_file); | |
494 } | |
495 rename(tf->filename, new_file); | |
496 unlink(tf->filename); | |
497 close(tf->logfd); | |
498 tf->logfd = open(tf->filename, O_CREAT | O_WRONLY | O_APPEND, 0666); | |
499 } | |
500 ftruncate(tf->logfd, 0); | |
501 } | |
502 } | |
503 return write(tf->logfd, toybuf, len); | |
504 } | |
505 | |
506 //search the given name and return its value | |
507 static char *dec(int val, CODE *clist) | |
508 { | |
509 const CODE *c; | |
510 | |
511 for (c = clist; c->c_name; c++) | |
512 if (val == c->c_val) return c->c_name; | |
513 return itoa(val); | |
514 } | |
515 | |
516 // Compute priority from "facility.level" pair | |
517 static void priority_to_string(int pri, char **facstr, char **lvlstr) | |
518 { | |
519 int fac,lev; | |
520 | |
521 fac = LOG_FAC(pri); | |
522 lev = LOG_PRI(pri); | |
523 *facstr = dec(fac<<3, facilitynames); | |
524 *lvlstr = dec(lev, prioritynames); | |
525 } | |
526 | |
527 //Parse messege and write to file. | |
528 static void logmsg(char *msg, int len) | |
529 { | |
530 time_t now; | |
531 char *p, *ts, *lvlstr, *facstr; | |
532 struct utsname uts; | |
533 int pri = 0; | |
534 struct arg_list *lnode = TT.lfiles; | |
535 | |
536 char *omsg = msg; | |
537 int olen = len, fac, lvl; | |
538 | |
539 if (*msg == '<') { // Extract the priority no. | |
540 pri = (int) strtoul(msg + 1, &p, 10); | |
541 if (*p == '>') msg = p + 1; | |
542 } | |
543 /* Jan 18 00:11:22 msg... | |
544 * 01234567890123456 | |
545 */ | |
546 if (len < 16 || msg[3] != ' ' || msg[6] != ' ' || msg[9] != ':' | |
547 || msg[12] != ':' || msg[15] != ' ') { | |
548 time(&now); | |
549 ts = ctime(&now) + 4; /* skip day of week */ | |
550 } else { | |
551 now = 0; | |
552 ts = msg; | |
553 msg += 16; | |
554 } | |
555 ts[15] = '\0'; | |
556 fac = LOG_FAC(pri); | |
557 lvl = LOG_PRI(pri); | |
558 | |
559 if (flag_chk(FLAG_K)) { | |
560 len = sprintf(toybuf, "<%d> %s\n", pri, msg); | |
561 goto do_log; | |
562 } | |
563 priority_to_string(pri, &facstr, &lvlstr); | |
564 | |
565 p = "local"; | |
566 if (!uname(&uts)) p = uts.nodename; | |
567 if (flag_chk(FLAG_S)) len = sprintf(toybuf, "%s %s\n", ts, msg); | |
568 else len = sprintf(toybuf, "%s %s %s.%s %s\n", ts, p, facstr, lvlstr, msg); | |
569 | |
570 do_log: | |
571 if (lvl >= TT.log_prio) return; | |
572 | |
573 while (lnode) { | |
574 logfile_t *tf = (logfile_t*) lnode->arg; | |
575 if (tf->logfd > 0) { | |
576 if ((tf->facility[lvl] & (1 << fac)) && (tf->level[fac] & (1<<lvl))) { | |
577 int wlen; | |
578 if (tf->isNetwork) | |
579 wlen = sendto(tf->logfd, omsg, olen, 0, (struct sockaddr*)&tf->saddr, sizeof(tf->saddr)); | |
580 else wlen = write_rotate(tf, len); | |
581 if (wlen < 0) perror_msg("write failed file : %s ", (tf->isNetwork)?(tf->filename+1):tf->filename); | |
582 } | |
583 } | |
584 lnode = lnode->next; | |
585 } | |
586 } | |
587 | |
588 /* | |
589 * closes all read and write fds | |
590 * and frees all nodes and lists | |
591 */ | |
592 static void cleanup(void) | |
593 { | |
594 struct arg_list *fnode; | |
595 while (TT.lsocks) { | |
596 fnode = TT.lsocks; | |
597 if (((unsocks_t*) fnode->arg)->sd >= 0) | |
598 close(((unsocks_t*) fnode->arg)->sd); | |
599 free(fnode->arg); | |
600 TT.lsocks = fnode->next; | |
601 free(fnode); | |
602 } | |
603 unlink("/dev/log"); | |
604 | |
605 while (TT.lfiles) { | |
606 fnode = TT.lfiles; | |
607 if (((logfile_t*) fnode->arg)->logfd >= 0) | |
608 close(((logfile_t*) fnode->arg)->logfd); | |
609 free(fnode->arg); | |
610 TT.lfiles = fnode->next; | |
611 free(fnode); | |
612 } | |
613 } | |
614 | |
615 static void signal_handler(int sig) | |
616 { | |
617 unsigned char ch = sig; | |
618 if (write(sigfd.wr, &ch, 1) != 1) error_msg("can't send signal"); | |
619 } | |
620 | |
621 static void setup_signal() | |
622 { | |
623 if (pipe((int *)&sigfd) < 0) error_exit("pipe failed\n"); | |
624 | |
625 fcntl(sigfd.wr , F_SETFD, FD_CLOEXEC); | |
626 fcntl(sigfd.rd , F_SETFD, FD_CLOEXEC); | |
627 int flags = fcntl(sigfd.wr, F_GETFL); | |
628 fcntl(sigfd.wr, F_SETFL, flags | O_NONBLOCK); | |
629 signal(SIGHUP, signal_handler); | |
630 signal(SIGTERM, signal_handler); | |
631 signal(SIGINT, signal_handler); | |
632 signal(SIGQUIT, signal_handler); | |
633 } | |
634 | |
635 void syslogd_main(void) | |
636 { | |
637 unsocks_t *tsd; | |
638 int maxfd, retval, last_len=0; | |
639 struct timeval tv; | |
640 struct arg_list *node; | |
641 char *temp, *buffer = (toybuf +2048), *last_buf = (toybuf + 3072); //these two buffs are of 1K each | |
642 | |
643 if (flag_chk(FLAG_p) && strlen(TT.unix_socket) > 108) | |
644 error_exit("Socket path should not be more than 108"); | |
645 | |
646 TT.config_file = flag_get(FLAG_f, TT.config_file, "/etc/syslog.conf"); //DEFCONFFILE | |
647 init_jumpin: | |
648 TT.lsocks = xzalloc(sizeof(struct arg_list)); | |
649 tsd = xzalloc(sizeof(unsocks_t)); | |
650 | |
651 tsd->path = flag_get(FLAG_p, TT.unix_socket , "/dev/log"); // DEFLOGSOCK | |
652 TT.lsocks->arg = (char*) tsd; | |
653 | |
654 if (flag_chk(FLAG_a)) { | |
655 for (temp = strtok(TT.socket, ":"); temp; temp = strtok(NULL, ":")) { | |
656 struct arg_list *ltemp = xzalloc(sizeof(struct arg_list)); | |
657 if (strlen(temp) > 107) temp[108] = '\0'; | |
658 tsd = xzalloc(sizeof(unsocks_t)); | |
659 tsd->path = temp; | |
660 ltemp->arg = (char*) tsd; | |
661 ltemp->next = TT.lsocks; | |
662 TT.lsocks = ltemp; | |
663 } | |
664 } | |
665 if (!open_unix_socks()) { | |
666 error_msg("Can't open single socket for listenning."); | |
667 goto clean_and_exit; | |
668 } | |
669 setup_signal(); | |
670 if (parse_config_file() == -1) goto clean_and_exit; | |
671 open_logfiles(); | |
995
893c86bbe452
Add daemonize function to lib for klogd and syslogd
Felix Janda <felix.janda@posteo.de>
parents:
960
diff
changeset
|
672 if (!flag_chk(FLAG_n)) { |
893c86bbe452
Add daemonize function to lib for klogd and syslogd
Felix Janda <felix.janda@posteo.de>
parents:
960
diff
changeset
|
673 //don't daemonize again if SIGHUP received. |
893c86bbe452
Add daemonize function to lib for klogd and syslogd
Felix Janda <felix.janda@posteo.de>
parents:
960
diff
changeset
|
674 toys.optflags |= FLAG_n; |
893c86bbe452
Add daemonize function to lib for klogd and syslogd
Felix Janda <felix.janda@posteo.de>
parents:
960
diff
changeset
|
675 } |
960 | 676 { |
677 int pid_fd = open("/var/run/syslogd.pid", O_CREAT | O_WRONLY | O_TRUNC, 0666); | |
678 if (pid_fd > 0) { | |
679 unsigned pid = getpid(); | |
680 int len = sprintf(toybuf, "%u\n", pid); | |
681 write(pid_fd, toybuf, len); | |
682 close(pid_fd); | |
683 } | |
684 } | |
685 | |
686 logmsg("<46>Toybox: syslogd started", 27); //27 : the length of message | |
687 for (;;) { | |
688 maxfd = addrfds(); | |
689 tv.tv_usec = 0; | |
690 tv.tv_sec = TT.interval*60; | |
691 | |
692 retval = select(maxfd + 1, &TT.rfds, NULL, NULL, (TT.interval)?&tv:NULL); | |
693 if (retval < 0) { /* Some error. */ | |
694 if (errno == EINTR) continue; | |
695 perror_msg("Error in select "); | |
696 continue; | |
697 } | |
698 if (!retval) { /* Timed out */ | |
699 logmsg("<46>-- MARK --", 14); | |
700 continue; | |
701 } | |
702 if (FD_ISSET(sigfd.rd, &TT.rfds)) { /* May be a signal */ | |
703 unsigned char sig; | |
704 | |
705 if (read(sigfd.rd, &sig, 1) != 1) { | |
706 error_msg("signal read failed.\n"); | |
707 continue; | |
708 } | |
709 switch(sig) { | |
710 case SIGTERM: /* FALLTHROUGH */ | |
711 case SIGINT: /* FALLTHROUGH */ | |
712 case SIGQUIT: | |
713 logmsg("<46>syslogd exiting", 19); | |
714 if (CFG_TOYBOX_FREE ) cleanup(); | |
715 signal(sig, SIG_DFL); | |
716 sigset_t ss; | |
717 sigemptyset(&ss); | |
718 sigaddset(&ss, sig); | |
719 sigprocmask(SIG_UNBLOCK, &ss, NULL); | |
720 raise(sig); | |
721 _exit(1); /* Should not reach it */ | |
722 break; | |
723 case SIGHUP: | |
724 logmsg("<46>syslogd exiting", 19); | |
725 cleanup(); //cleanup is done, as we restart syslog. | |
726 goto init_jumpin; | |
727 default: break; | |
728 } | |
729 } | |
730 if (retval > 0) { /* Some activity on listen sockets. */ | |
731 node = TT.lsocks; | |
732 while (node) { | |
733 int sd = ((unsocks_t*) node->arg)->sd; | |
734 if (FD_ISSET(sd, &TT.rfds)) { | |
735 int len = read(sd, buffer, 1023); //buffer is of 1K, hence readingonly 1023 bytes, 1 for NUL | |
736 if (len > 0) { | |
737 buffer[len] = '\0'; | |
738 if(flag_chk(FLAG_D) && (len == last_len)) | |
739 if (!memcmp(last_buf, buffer, len)) break; | |
740 | |
741 memcpy(last_buf, buffer, len); | |
742 last_len = len; | |
743 logmsg(buffer, len); | |
744 } | |
745 break; | |
746 } | |
747 node = node->next; | |
748 } | |
749 } | |
750 } | |
751 clean_and_exit: | |
752 logmsg("<46>syslogd exiting", 19); | |
753 if (CFG_TOYBOX_FREE ) cleanup(); | |
754 } |