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 static void syslog_daemon(void)
|
|
636 {
|
|
637 int fd = open("/dev/null", O_RDWR);
|
|
638 if (fd < 0) fd = xcreate("/", O_RDONLY, 0666);
|
|
639
|
|
640 pid_t pid = fork();
|
|
641 if (pid < 0) perror_exit("DAEMON: failed to fork");
|
|
642 if (pid) exit(EXIT_SUCCESS);
|
|
643
|
|
644 setsid();
|
|
645 dup2(fd, 0);
|
|
646 dup2(fd, 1);
|
|
647 dup2(fd, 2);
|
|
648 if (fd > 2) close(fd);
|
|
649
|
|
650 //don't daemonize again if SIGHUP received.
|
|
651 toys.optflags |= FLAG_n;
|
|
652 }
|
|
653
|
|
654 void syslogd_main(void)
|
|
655 {
|
|
656 unsocks_t *tsd;
|
|
657 int maxfd, retval, last_len=0;
|
|
658 struct timeval tv;
|
|
659 struct arg_list *node;
|
|
660 char *temp, *buffer = (toybuf +2048), *last_buf = (toybuf + 3072); //these two buffs are of 1K each
|
|
661
|
|
662 if (flag_chk(FLAG_p) && strlen(TT.unix_socket) > 108)
|
|
663 error_exit("Socket path should not be more than 108");
|
|
664
|
|
665 TT.config_file = flag_get(FLAG_f, TT.config_file, "/etc/syslog.conf"); //DEFCONFFILE
|
|
666 init_jumpin:
|
|
667 TT.lsocks = xzalloc(sizeof(struct arg_list));
|
|
668 tsd = xzalloc(sizeof(unsocks_t));
|
|
669
|
|
670 tsd->path = flag_get(FLAG_p, TT.unix_socket , "/dev/log"); // DEFLOGSOCK
|
|
671 TT.lsocks->arg = (char*) tsd;
|
|
672
|
|
673 if (flag_chk(FLAG_a)) {
|
|
674 for (temp = strtok(TT.socket, ":"); temp; temp = strtok(NULL, ":")) {
|
|
675 struct arg_list *ltemp = xzalloc(sizeof(struct arg_list));
|
|
676 if (strlen(temp) > 107) temp[108] = '\0';
|
|
677 tsd = xzalloc(sizeof(unsocks_t));
|
|
678 tsd->path = temp;
|
|
679 ltemp->arg = (char*) tsd;
|
|
680 ltemp->next = TT.lsocks;
|
|
681 TT.lsocks = ltemp;
|
|
682 }
|
|
683 }
|
|
684 if (!open_unix_socks()) {
|
|
685 error_msg("Can't open single socket for listenning.");
|
|
686 goto clean_and_exit;
|
|
687 }
|
|
688 setup_signal();
|
|
689 if (parse_config_file() == -1) goto clean_and_exit;
|
|
690 open_logfiles();
|
|
691 if (!flag_chk(FLAG_n)) syslog_daemon();
|
|
692 {
|
|
693 int pid_fd = open("/var/run/syslogd.pid", O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
|
694 if (pid_fd > 0) {
|
|
695 unsigned pid = getpid();
|
|
696 int len = sprintf(toybuf, "%u\n", pid);
|
|
697 write(pid_fd, toybuf, len);
|
|
698 close(pid_fd);
|
|
699 }
|
|
700 }
|
|
701
|
|
702 logmsg("<46>Toybox: syslogd started", 27); //27 : the length of message
|
|
703 for (;;) {
|
|
704 maxfd = addrfds();
|
|
705 tv.tv_usec = 0;
|
|
706 tv.tv_sec = TT.interval*60;
|
|
707
|
|
708 retval = select(maxfd + 1, &TT.rfds, NULL, NULL, (TT.interval)?&tv:NULL);
|
|
709 if (retval < 0) { /* Some error. */
|
|
710 if (errno == EINTR) continue;
|
|
711 perror_msg("Error in select ");
|
|
712 continue;
|
|
713 }
|
|
714 if (!retval) { /* Timed out */
|
|
715 logmsg("<46>-- MARK --", 14);
|
|
716 continue;
|
|
717 }
|
|
718 if (FD_ISSET(sigfd.rd, &TT.rfds)) { /* May be a signal */
|
|
719 unsigned char sig;
|
|
720
|
|
721 if (read(sigfd.rd, &sig, 1) != 1) {
|
|
722 error_msg("signal read failed.\n");
|
|
723 continue;
|
|
724 }
|
|
725 switch(sig) {
|
|
726 case SIGTERM: /* FALLTHROUGH */
|
|
727 case SIGINT: /* FALLTHROUGH */
|
|
728 case SIGQUIT:
|
|
729 logmsg("<46>syslogd exiting", 19);
|
|
730 if (CFG_TOYBOX_FREE ) cleanup();
|
|
731 signal(sig, SIG_DFL);
|
|
732 sigset_t ss;
|
|
733 sigemptyset(&ss);
|
|
734 sigaddset(&ss, sig);
|
|
735 sigprocmask(SIG_UNBLOCK, &ss, NULL);
|
|
736 raise(sig);
|
|
737 _exit(1); /* Should not reach it */
|
|
738 break;
|
|
739 case SIGHUP:
|
|
740 logmsg("<46>syslogd exiting", 19);
|
|
741 cleanup(); //cleanup is done, as we restart syslog.
|
|
742 goto init_jumpin;
|
|
743 default: break;
|
|
744 }
|
|
745 }
|
|
746 if (retval > 0) { /* Some activity on listen sockets. */
|
|
747 node = TT.lsocks;
|
|
748 while (node) {
|
|
749 int sd = ((unsocks_t*) node->arg)->sd;
|
|
750 if (FD_ISSET(sd, &TT.rfds)) {
|
|
751 int len = read(sd, buffer, 1023); //buffer is of 1K, hence readingonly 1023 bytes, 1 for NUL
|
|
752 if (len > 0) {
|
|
753 buffer[len] = '\0';
|
|
754 if(flag_chk(FLAG_D) && (len == last_len))
|
|
755 if (!memcmp(last_buf, buffer, len)) break;
|
|
756
|
|
757 memcpy(last_buf, buffer, len);
|
|
758 last_len = len;
|
|
759 logmsg(buffer, len);
|
|
760 }
|
|
761 break;
|
|
762 }
|
|
763 node = node->next;
|
|
764 }
|
|
765 }
|
|
766 }
|
|
767 clean_and_exit:
|
|
768 logmsg("<46>syslogd exiting", 19);
|
|
769 if (CFG_TOYBOX_FREE ) cleanup();
|
|
770 }
|