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