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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170#ifndef _PATH_LOG
171#define _PATH_LOG "/dev/log"
172#endif
173
174#include <sys/un.h>
175#include <sys/uio.h>
176
177#if ENABLE_FEATURE_REMOTE_LOG
178#include <netinet/in.h>
179#endif
180
181#if ENABLE_FEATURE_IPC_SYSLOG
182#include <sys/ipc.h>
183#include <sys/sem.h>
184#include <sys/shm.h>
185#endif
186
187
188#define DEBUG 0
189
190
191
192
193#undef SYSLOGD_MARK
194
195
196#undef SYSLOGD_WRLOCK
197
198enum {
199 MAX_READ = CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE,
200 DNS_WAIT_SEC = 2 * 60,
201};
202
203
204struct shbuf_ds {
205 int32_t size;
206 int32_t tail;
207 char data[1];
208};
209
210#if ENABLE_FEATURE_REMOTE_LOG
211typedef struct {
212 int remoteFD;
213 unsigned last_dns_resolve;
214 len_and_sockaddr *remoteAddr;
215 const char *remoteHostname;
216} remoteHost_t;
217#endif
218
219typedef struct logFile_t {
220 const char *path;
221 int fd;
222 time_t last_log_time;
223#if ENABLE_FEATURE_ROTATE_LOGFILE
224 unsigned size;
225 uint8_t isRegular;
226#endif
227} logFile_t;
228
229#if ENABLE_FEATURE_SYSLOGD_CFG
230typedef struct logRule_t {
231 uint8_t enabled_facility_priomap[LOG_NFACILITIES];
232 struct logFile_t *file;
233 struct logRule_t *next;
234} logRule_t;
235#endif
236
237
238#define GLOBALS \
239 logFile_t logFile; \
240 \
241 \
242 \
243 int logLevel; \
244IF_FEATURE_ROTATE_LOGFILE( \
245 \
246 unsigned logFileSize; \
247 \
248 unsigned logFileRotate; \
249) \
250IF_FEATURE_IPC_SYSLOG( \
251 int shmid; \
252 int s_semid; \
253 int shm_size; \
254 struct sembuf SMwup[1]; \
255 struct sembuf SMwdn[3]; \
256) \
257IF_FEATURE_SYSLOGD_CFG( \
258 logRule_t *log_rules; \
259) \
260IF_FEATURE_KMSG_SYSLOG( \
261 int kmsgfd; \
262 int primask; \
263)
264
265struct init_globals {
266 GLOBALS
267};
268
269struct globals {
270 GLOBALS
271
272#if ENABLE_FEATURE_REMOTE_LOG
273 llist_t *remoteHosts;
274#endif
275#if ENABLE_FEATURE_IPC_SYSLOG
276 struct shbuf_ds *shbuf;
277#endif
278
279 char *hostname;
280
281
282 char recvbuf[MAX_READ * (1 + ENABLE_FEATURE_SYSLOGD_DUP)];
283
284
285 char parsebuf[MAX_READ*2];
286
287
288
289 char printbuf[MAX_READ*2 + 128];
290};
291
292static const struct init_globals init_data = {
293 .logFile = {
294 .path = "/var/log/messages",
295 .fd = -1,
296 },
297#ifdef SYSLOGD_MARK
298 .markInterval = 20 * 60,
299#endif
300 .logLevel = 8,
301#if ENABLE_FEATURE_ROTATE_LOGFILE
302 .logFileSize = 200 * 1024,
303 .logFileRotate = 1,
304#endif
305#if ENABLE_FEATURE_IPC_SYSLOG
306 .shmid = -1,
307 .s_semid = -1,
308 .shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024),
309 .SMwup = { {1, -1, IPC_NOWAIT} },
310 .SMwdn = { {0, 0}, {1, 0}, {1, +1} },
311#endif
312};
313
314#define G (*ptr_to_globals)
315#define INIT_G() do { \
316 SET_PTR_TO_GLOBALS(memcpy(xzalloc(sizeof(G)), &init_data, sizeof(init_data))); \
317} while (0)
318
319
320
321enum {
322 OPTBIT_mark = 0,
323 OPTBIT_nofork,
324 OPTBIT_outfile,
325 OPTBIT_loglevel,
326 OPTBIT_small,
327 OPTBIT_timestamp,
328 IF_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize ,)
329 IF_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt ,)
330 IF_FEATURE_REMOTE_LOG( OPTBIT_remotelog ,)
331 IF_FEATURE_REMOTE_LOG( OPTBIT_locallog ,)
332 IF_FEATURE_IPC_SYSLOG( OPTBIT_circularlog,)
333 IF_FEATURE_SYSLOGD_DUP( OPTBIT_dup ,)
334 IF_FEATURE_SYSLOGD_CFG( OPTBIT_cfg ,)
335 IF_FEATURE_KMSG_SYSLOG( OPTBIT_kmsg ,)
336
337 OPT_mark = 1 << OPTBIT_mark ,
338 OPT_nofork = 1 << OPTBIT_nofork ,
339 OPT_outfile = 1 << OPTBIT_outfile ,
340 OPT_loglevel = 1 << OPTBIT_loglevel,
341 OPT_small = 1 << OPTBIT_small ,
342 OPT_timestamp = 1 << OPTBIT_timestamp,
343 OPT_filesize = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize )) + 0,
344 OPT_rotatecnt = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt )) + 0,
345 OPT_remotelog = IF_FEATURE_REMOTE_LOG( (1 << OPTBIT_remotelog )) + 0,
346 OPT_locallog = IF_FEATURE_REMOTE_LOG( (1 << OPTBIT_locallog )) + 0,
347 OPT_circularlog = IF_FEATURE_IPC_SYSLOG( (1 << OPTBIT_circularlog)) + 0,
348 OPT_dup = IF_FEATURE_SYSLOGD_DUP( (1 << OPTBIT_dup )) + 0,
349 OPT_cfg = IF_FEATURE_SYSLOGD_CFG( (1 << OPTBIT_cfg )) + 0,
350 OPT_kmsg = IF_FEATURE_KMSG_SYSLOG( (1 << OPTBIT_kmsg )) + 0,
351};
352#define OPTION_STR "m:nO:l:St" \
353 IF_FEATURE_ROTATE_LOGFILE("s:" ) \
354 IF_FEATURE_ROTATE_LOGFILE("b:" ) \
355 IF_FEATURE_REMOTE_LOG( "R:*") \
356 IF_FEATURE_REMOTE_LOG( "L" ) \
357 IF_FEATURE_IPC_SYSLOG( "C::") \
358 IF_FEATURE_SYSLOGD_DUP( "D" ) \
359 IF_FEATURE_SYSLOGD_CFG( "f:" ) \
360 IF_FEATURE_KMSG_SYSLOG( "K" )
361#define OPTION_DECL *opt_m, *opt_l \
362 IF_FEATURE_ROTATE_LOGFILE(,*opt_s) \
363 IF_FEATURE_ROTATE_LOGFILE(,*opt_b) \
364 IF_FEATURE_IPC_SYSLOG( ,*opt_C = NULL) \
365 IF_FEATURE_SYSLOGD_CFG( ,*opt_f = NULL)
366#define OPTION_PARAM &opt_m, &(G.logFile.path), &opt_l \
367 IF_FEATURE_ROTATE_LOGFILE(,&opt_s) \
368 IF_FEATURE_ROTATE_LOGFILE(,&opt_b) \
369 IF_FEATURE_REMOTE_LOG( ,&remoteAddrList) \
370 IF_FEATURE_IPC_SYSLOG( ,&opt_C) \
371 IF_FEATURE_SYSLOGD_CFG( ,&opt_f)
372
373
374#if ENABLE_FEATURE_SYSLOGD_CFG
375static const CODE* find_by_name(char *name, const CODE* c_set)
376{
377 for (; c_set->c_name; c_set++) {
378 if (strcmp(name, c_set->c_name) == 0)
379 return c_set;
380 }
381 return NULL;
382}
383#endif
384static const CODE* find_by_val(int val, const CODE* c_set)
385{
386 for (; c_set->c_name; c_set++) {
387 if (c_set->c_val == val)
388 return c_set;
389 }
390 return NULL;
391}
392
393#if ENABLE_FEATURE_SYSLOGD_CFG
394static void parse_syslogdcfg(const char *file)
395{
396 char *t;
397 logRule_t **pp_rule;
398
399
400
401 char *tok[3];
402 parser_t *parser;
403
404 parser = config_open2(file ? file : "/etc/syslog.conf",
405 file ? xfopen_for_read : fopen_for_read);
406 if (!parser)
407
408
409 return;
410
411
412 pp_rule = &G.log_rules;
413
414 while (config_read(parser, tok, 3, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
415 char *cur_selector;
416 logRule_t *cur_rule;
417
418
419 if (tok[2])
420 goto cfgerr;
421
422 cur_rule = *pp_rule = xzalloc(sizeof(*cur_rule));
423
424 cur_selector = tok[0];
425
426 do {
427 const CODE *code;
428 char *next_selector;
429 uint8_t negated_prio;
430 uint8_t single_prio;
431 uint32_t facmap;
432 uint8_t primap;
433 unsigned i;
434
435 next_selector = strchr(cur_selector, ';');
436 if (next_selector)
437 *next_selector++ = '\0';
438
439 t = strchr(cur_selector, '.');
440 if (!t)
441 goto cfgerr;
442 *t++ = '\0';
443
444 negated_prio = 0;
445 single_prio = 0;
446 if (*t == '!') {
447 negated_prio = 1;
448 ++t;
449 }
450 if (*t == '=') {
451 single_prio = 1;
452 ++t;
453 }
454
455
456 if (*t == '*')
457 primap = 0xff;
458 else {
459 uint8_t priority;
460 code = find_by_name(t, bb_prioritynames);
461 if (!code)
462 goto cfgerr;
463 primap = 0;
464 priority = code->c_val;
465 if (priority == INTERNAL_NOPRI) {
466
467 negated_prio = 1;
468 } else {
469 priority = 1 << priority;
470 do {
471 primap |= priority;
472 if (single_prio)
473 break;
474 priority >>= 1;
475 } while (priority);
476 if (negated_prio)
477 primap = ~primap;
478 }
479 }
480
481
482 if (*cur_selector == '*')
483 facmap = (1<<LOG_NFACILITIES) - 1;
484 else {
485 char *next_facility;
486 facmap = 0;
487 t = cur_selector;
488
489 do {
490 next_facility = strchr(t, ',');
491 if (next_facility)
492 *next_facility++ = '\0';
493 code = find_by_name(t, bb_facilitynames);
494 if (!code)
495 goto cfgerr;
496
497 if (code->c_val != INTERNAL_MARK)
498 facmap |= 1<<(LOG_FAC(code->c_val));
499 t = next_facility;
500 } while (t);
501 }
502
503
504 for (i = 0; i < LOG_NFACILITIES; ++i) {
505 if (!(facmap & (1<<i)))
506 continue;
507 if (negated_prio)
508 cur_rule->enabled_facility_priomap[i] &= primap;
509 else
510 cur_rule->enabled_facility_priomap[i] |= primap;
511 }
512
513 cur_selector = next_selector;
514 } while (cur_selector);
515
516
517
518
519 if (strcmp(G.logFile.path, tok[1]) == 0) {
520 cur_rule->file = &G.logFile;
521 goto found;
522 }
523
524
525
526
527 for (cur_rule = G.log_rules; cur_rule != *pp_rule; cur_rule = cur_rule->next) {
528 if (strcmp(cur_rule->file->path, tok[1]) == 0) {
529
530 (*pp_rule)->file = cur_rule->file;
531 cur_rule = *pp_rule;
532 goto found;
533 }
534 }
535 cur_rule->file = xzalloc(sizeof(*cur_rule->file));
536 cur_rule->file->fd = -1;
537 cur_rule->file->path = xstrdup(tok[1]);
538 found:
539 pp_rule = &cur_rule->next;
540 }
541 config_close(parser);
542 return;
543
544 cfgerr:
545 bb_error_msg_and_die("error in '%s' at line %d",
546 file ? file : "/etc/syslog.conf",
547 parser->lineno);
548}
549#endif
550
551
552#if ENABLE_FEATURE_IPC_SYSLOG
553
554#if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4
555#error Sorry, you must set the syslogd buffer size to at least 4KB.
556#error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE
557#endif
558
559
560enum { KEY_ID = 0x414e4547 };
561
562static void ipcsyslog_cleanup(void)
563{
564 if (G.shmid != -1) {
565 shmdt(G.shbuf);
566 }
567 if (G.shmid != -1) {
568 shmctl(G.shmid, IPC_RMID, NULL);
569 }
570 if (G.s_semid != -1) {
571 semctl(G.s_semid, 0, IPC_RMID, 0);
572 }
573}
574
575static void ipcsyslog_init(void)
576{
577 if (DEBUG)
578 printf("shmget(%x, %d,...)\n", (int)KEY_ID, G.shm_size);
579
580 G.shmid = shmget(KEY_ID, G.shm_size, IPC_CREAT | 0644);
581 if (G.shmid == -1) {
582 bb_simple_perror_msg_and_die("shmget");
583 }
584
585 G.shbuf = shmat(G.shmid, NULL, 0);
586 if (G.shbuf == (void*) -1L) {
587 bb_simple_perror_msg_and_die("shmat");
588 }
589
590 memset(G.shbuf, 0, G.shm_size);
591 G.shbuf->size = G.shm_size - offsetof(struct shbuf_ds, data) - 1;
592
593
594
595 G.s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023);
596 if (G.s_semid == -1) {
597 if (errno == EEXIST) {
598 G.s_semid = semget(KEY_ID, 2, 0);
599 if (G.s_semid != -1)
600 return;
601 }
602 bb_simple_perror_msg_and_die("semget");
603 }
604}
605
606
607static void log_to_shmem(const char *msg)
608{
609 int old_tail, new_tail;
610 int len;
611
612 if (semop(G.s_semid, G.SMwdn, 3) == -1) {
613 bb_simple_perror_msg_and_die("SMwdn");
614 }
615
616
617
618
619
620
621
622 len = strlen(msg) + 1;
623 again:
624 old_tail = G.shbuf->tail;
625 new_tail = old_tail + len;
626 if (new_tail < G.shbuf->size) {
627
628 memcpy(G.shbuf->data + old_tail, msg, len);
629 G.shbuf->tail = new_tail;
630 } else {
631
632 int k = G.shbuf->size - old_tail;
633
634 memcpy(G.shbuf->data + old_tail, msg, k);
635 msg += k;
636 len -= k;
637 G.shbuf->tail = 0;
638 goto again;
639 }
640 if (semop(G.s_semid, G.SMwup, 1) == -1) {
641 bb_simple_perror_msg_and_die("SMwup");
642 }
643 if (DEBUG)
644 printf("tail:%d\n", G.shbuf->tail);
645}
646#else
647static void ipcsyslog_cleanup(void) {}
648static void ipcsyslog_init(void) {}
649void log_to_shmem(const char *msg);
650#endif
651
652#if ENABLE_FEATURE_KMSG_SYSLOG
653static void kmsg_init(void)
654{
655 G.kmsgfd = xopen("/dev/kmsg", O_WRONLY);
656
657
658
659
660
661 if (get_linux_version_code() < KERNEL_VERSION(3,5,0))
662 G.primask = LOG_PRIMASK;
663 else
664 G.primask = -1;
665}
666
667static void kmsg_cleanup(void)
668{
669 if (ENABLE_FEATURE_CLEAN_UP)
670 close(G.kmsgfd);
671}
672
673
674static void log_to_kmsg(int pri, const char *msg)
675{
676
677
678
679
680 pri &= G.primask;
681
682 full_write(G.kmsgfd, G.printbuf, sprintf(G.printbuf, "<%d>%s\n", pri, msg));
683}
684#else
685static void kmsg_init(void) {}
686static void kmsg_cleanup(void) {}
687static void log_to_kmsg(int pri UNUSED_PARAM, const char *msg UNUSED_PARAM) {}
688#endif
689
690
691static void log_locally(time_t now, char *msg, logFile_t *log_file)
692{
693#ifdef SYSLOGD_WRLOCK
694 struct flock fl;
695#endif
696 int len = strlen(msg);
697
698
699
700 if (log_file->fd > 1) {
701
702
703
704
705
706
707 if (!now)
708 now = time(NULL);
709 if (log_file->last_log_time != now) {
710 log_file->last_log_time = now;
711 close(log_file->fd);
712 goto reopen;
713 }
714 }
715 else if (log_file->fd == 1) {
716
717 }
718 else {
719 if (LONE_DASH(log_file->path)) {
720 log_file->fd = 1;
721
722 } else {
723 reopen:
724 log_file->fd = open(log_file->path, O_WRONLY | O_CREAT
725 | O_NOCTTY | O_APPEND | O_NONBLOCK,
726 0666);
727 if (log_file->fd < 0) {
728
729 int fd = device_open(DEV_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK);
730 if (fd < 0)
731 fd = 2;
732 full_write(fd, msg, len);
733 if (fd != 2)
734 close(fd);
735 return;
736 }
737#if ENABLE_FEATURE_ROTATE_LOGFILE
738 {
739 struct stat statf;
740 log_file->isRegular = (fstat(log_file->fd, &statf) == 0 && S_ISREG(statf.st_mode));
741
742 log_file->size = statf.st_size;
743 }
744#endif
745 }
746 }
747
748#ifdef SYSLOGD_WRLOCK
749 fl.l_whence = SEEK_SET;
750 fl.l_start = 0;
751 fl.l_len = 1;
752 fl.l_type = F_WRLCK;
753 fcntl(log_file->fd, F_SETLKW, &fl);
754#endif
755
756#if ENABLE_FEATURE_ROTATE_LOGFILE
757 if (G.logFileSize && log_file->isRegular && log_file->size > G.logFileSize) {
758 if (G.logFileRotate) {
759 int i = strlen(log_file->path) + 3 + 1;
760 char oldFile[i];
761 char newFile[i];
762 i = G.logFileRotate - 1;
763
764 while (1) {
765 sprintf(newFile, "%s.%d", log_file->path, i);
766 if (i == 0) break;
767 sprintf(oldFile, "%s.%d", log_file->path, --i);
768
769 rename(oldFile, newFile);
770 }
771
772 rename(log_file->path, newFile);
773 }
774
775
776
777
778
779
780
781
782
783
784 unlink(log_file->path);
785#ifdef SYSLOGD_WRLOCK
786 fl.l_type = F_UNLCK;
787 fcntl(log_file->fd, F_SETLKW, &fl);
788#endif
789 close(log_file->fd);
790 goto reopen;
791 }
792
793 len = full_write(log_file->fd, msg, len);
794 if (len > 0)
795 log_file->size += len;
796#else
797 full_write(log_file->fd, msg, len);
798#endif
799
800#ifdef SYSLOGD_WRLOCK
801 fl.l_type = F_UNLCK;
802 fcntl(log_file->fd, F_SETLKW, &fl);
803#endif
804}
805
806static void parse_fac_prio_20(int pri, char *res20)
807{
808 const CODE *c_pri, *c_fac;
809
810 c_fac = find_by_val(LOG_FAC(pri) << 3, bb_facilitynames);
811 if (c_fac) {
812 c_pri = find_by_val(LOG_PRI(pri), bb_prioritynames);
813 if (c_pri) {
814 snprintf(res20, 20, "%s.%s", c_fac->c_name, c_pri->c_name);
815 return;
816 }
817 }
818 snprintf(res20, 20, "<%d>", pri);
819}
820
821
822
823
824static void timestamp_and_log(int pri, char *msg, int len)
825{
826 char *timestamp = NULL;
827 time_t now;
828
829
830
831 if (len >= 16 && msg[3] == ' ' && msg[6] == ' '
832 && msg[9] == ':' && msg[12] == ':' && msg[15] == ' '
833 ) {
834 if (!(option_mask32 & OPT_timestamp)) {
835
836 timestamp = msg;
837 now = 0;
838 }
839 msg += 16;
840 }
841
842#if ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS
843 if (!timestamp) {
844 struct timeval tv;
845 xgettimeofday(&tv);
846 now = tv.tv_sec;
847 timestamp = ctime(&now) + 4;
848
849 sprintf(timestamp + 15, ".%03u", (unsigned)tv.tv_usec / 1000u);
850 } else {
851 timestamp[15] = '\0';
852 }
853#else
854 if (!timestamp) {
855 time(&now);
856 timestamp = ctime(&now) + 4;
857 }
858 timestamp[15] = '\0';
859#endif
860
861 if (option_mask32 & OPT_kmsg) {
862 log_to_kmsg(pri, msg);
863 return;
864 }
865
866 if (option_mask32 & OPT_small)
867 sprintf(G.printbuf, "%s %s\n", timestamp, msg);
868 else {
869 char res[20];
870 parse_fac_prio_20(pri, res);
871 sprintf(G.printbuf, "%s %.64s %s %s\n", timestamp, G.hostname, res, msg);
872 }
873
874
875#if ENABLE_FEATURE_SYSLOGD_CFG
876 {
877 bool match = 0;
878 logRule_t *rule;
879 uint8_t facility = LOG_FAC(pri);
880 uint8_t prio_bit = 1 << LOG_PRI(pri);
881
882 for (rule = G.log_rules; rule; rule = rule->next) {
883 if (rule->enabled_facility_priomap[facility] & prio_bit) {
884 log_locally(now, G.printbuf, rule->file);
885 match = 1;
886 }
887 }
888 if (match)
889 return;
890 }
891#endif
892 if (LOG_PRI(pri) < G.logLevel) {
893#if ENABLE_FEATURE_IPC_SYSLOG
894 if ((option_mask32 & OPT_circularlog) && G.shbuf) {
895 log_to_shmem(G.printbuf);
896 return;
897 }
898#endif
899 log_locally(now, G.printbuf, &G.logFile);
900 }
901}
902
903static void timestamp_and_log_internal(const char *msg)
904{
905
906 if (ENABLE_FEATURE_REMOTE_LOG && !(option_mask32 & OPT_locallog))
907 return;
908 timestamp_and_log(LOG_SYSLOG | LOG_INFO, (char*)msg, 0);
909}
910
911
912
913
914static void split_escape_and_log(char *tmpbuf, int len)
915{
916 char *p = tmpbuf;
917
918 tmpbuf += len;
919 while (p < tmpbuf) {
920 char c;
921 char *q = G.parsebuf;
922 int pri = (LOG_USER | LOG_NOTICE);
923
924 if (*p == '<') {
925
926 pri = bb_strtou(p + 1, &p, 10);
927 if (*p == '>')
928 p++;
929 if (pri & ~(LOG_FACMASK | LOG_PRIMASK))
930 pri = (LOG_USER | LOG_NOTICE);
931 }
932
933 while ((c = *p++)) {
934 if (c == '\n')
935 c = ' ';
936 if (!(c & ~0x1f) && c != '\t') {
937 *q++ = '^';
938 c += '@';
939 }
940 *q++ = c;
941 }
942 *q = '\0';
943
944
945 timestamp_and_log(pri, G.parsebuf, q - G.parsebuf);
946 }
947}
948
949#ifdef SYSLOGD_MARK
950static void do_mark(int sig)
951{
952 if (G.markInterval) {
953 timestamp_and_log_internal("-- MARK --");
954 alarm(G.markInterval);
955 }
956}
957#endif
958
959
960
961static NOINLINE int create_socket(void)
962{
963 struct sockaddr_un sunx;
964 int sock_fd;
965 char *dev_log_name;
966
967 memset(&sunx, 0, sizeof(sunx));
968 sunx.sun_family = AF_UNIX;
969
970
971
972 strcpy(sunx.sun_path, _PATH_LOG);
973 dev_log_name = xmalloc_follow_symlinks(_PATH_LOG);
974 if (dev_log_name) {
975 safe_strncpy(sunx.sun_path, dev_log_name, sizeof(sunx.sun_path));
976 free(dev_log_name);
977 }
978 unlink(sunx.sun_path);
979
980 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
981 xbind(sock_fd, (struct sockaddr *) &sunx, sizeof(sunx));
982 chmod(_PATH_LOG, 0666);
983
984 return sock_fd;
985}
986
987#if ENABLE_FEATURE_REMOTE_LOG
988static int try_to_resolve_remote(remoteHost_t *rh)
989{
990 if (!rh->remoteAddr) {
991 unsigned now = monotonic_sec();
992
993
994 if ((now - rh->last_dns_resolve) < DNS_WAIT_SEC)
995 return -1;
996 rh->last_dns_resolve = now;
997 rh->remoteAddr = host2sockaddr(rh->remoteHostname, 514);
998 if (!rh->remoteAddr)
999 return -1;
1000 }
1001 return xsocket(rh->remoteAddr->u.sa.sa_family, SOCK_DGRAM, 0);
1002}
1003#endif
1004
1005static void do_syslogd(void) NORETURN;
1006static void do_syslogd(void)
1007{
1008#if ENABLE_FEATURE_REMOTE_LOG
1009 llist_t *item;
1010#endif
1011#if ENABLE_FEATURE_SYSLOGD_DUP
1012 int last_sz = -1;
1013 char *last_buf;
1014 char *recvbuf = G.recvbuf;
1015#else
1016#define recvbuf (G.recvbuf)
1017#endif
1018
1019
1020 signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo);
1021 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
1022
1023 signal(SIGHUP, SIG_IGN);
1024#ifdef SYSLOGD_MARK
1025 signal(SIGALRM, do_mark);
1026 alarm(G.markInterval);
1027#endif
1028 xmove_fd(create_socket(), STDIN_FILENO);
1029
1030 if (option_mask32 & OPT_circularlog)
1031 ipcsyslog_init();
1032
1033 if (option_mask32 & OPT_kmsg)
1034 kmsg_init();
1035
1036 timestamp_and_log_internal("syslogd started: BusyBox v" BB_VER);
1037 write_pidfile_std_path_and_ext("syslogd");
1038
1039 while (!bb_got_signal) {
1040 ssize_t sz;
1041
1042#if ENABLE_FEATURE_SYSLOGD_DUP
1043 last_buf = recvbuf;
1044 if (recvbuf == G.recvbuf)
1045 recvbuf = G.recvbuf + MAX_READ;
1046 else
1047 recvbuf = G.recvbuf;
1048#endif
1049 read_again:
1050 sz = read(STDIN_FILENO, recvbuf, MAX_READ - 1);
1051 if (sz < 0) {
1052 if (!bb_got_signal)
1053 bb_perror_msg("read from %s", _PATH_LOG);
1054 break;
1055 }
1056
1057
1058 while (1) {
1059 if (sz == 0)
1060 goto read_again;
1061
1062
1063
1064
1065
1066
1067
1068 if (recvbuf[sz-1] != '\0' && recvbuf[sz-1] != '\n')
1069 break;
1070 sz--;
1071 }
1072#if ENABLE_FEATURE_SYSLOGD_DUP
1073 if ((option_mask32 & OPT_dup) && (sz == last_sz))
1074 if (memcmp(last_buf, recvbuf, sz) == 0)
1075 continue;
1076 last_sz = sz;
1077#endif
1078#if ENABLE_FEATURE_REMOTE_LOG
1079
1080
1081 recvbuf[sz] = '\n';
1082
1083
1084
1085 for (item = G.remoteHosts; item != NULL; item = item->link) {
1086 remoteHost_t *rh = (remoteHost_t *)item->data;
1087
1088 if (rh->remoteFD == -1) {
1089 rh->remoteFD = try_to_resolve_remote(rh);
1090 if (rh->remoteFD == -1)
1091 continue;
1092 }
1093
1094
1095
1096
1097
1098 if (sendto(rh->remoteFD, recvbuf, sz+1,
1099 MSG_DONTWAIT | MSG_NOSIGNAL,
1100 &(rh->remoteAddr->u.sa), rh->remoteAddr->len) == -1
1101 ) {
1102 switch (errno) {
1103 case ECONNRESET:
1104 case ENOTCONN:
1105 case EPIPE:
1106 close(rh->remoteFD);
1107 rh->remoteFD = -1;
1108 free(rh->remoteAddr);
1109 rh->remoteAddr = NULL;
1110 }
1111 }
1112 }
1113#endif
1114 if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) {
1115 recvbuf[sz] = '\0';
1116 split_escape_and_log(recvbuf, sz);
1117 }
1118 }
1119
1120 timestamp_and_log_internal("syslogd exiting");
1121 remove_pidfile_std_path_and_ext("syslogd");
1122 ipcsyslog_cleanup();
1123 if (option_mask32 & OPT_kmsg)
1124 kmsg_cleanup();
1125 kill_myself_with_sig(bb_got_signal);
1126#undef recvbuf
1127}
1128
1129int syslogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1130int syslogd_main(int argc UNUSED_PARAM, char **argv)
1131{
1132 int opts;
1133 char OPTION_DECL;
1134#if ENABLE_FEATURE_REMOTE_LOG
1135 llist_t *remoteAddrList = NULL;
1136#endif
1137
1138 INIT_G();
1139
1140
1141 opts = getopt32(argv, "^"OPTION_STR"\0""=0", OPTION_PARAM);
1142#if ENABLE_FEATURE_REMOTE_LOG
1143 while (remoteAddrList) {
1144 remoteHost_t *rh = xzalloc(sizeof(*rh));
1145 rh->remoteHostname = llist_pop(&remoteAddrList);
1146 rh->remoteFD = -1;
1147 rh->last_dns_resolve = monotonic_sec() - DNS_WAIT_SEC - 1;
1148 llist_add_to(&G.remoteHosts, rh);
1149 }
1150#endif
1151
1152#ifdef SYSLOGD_MARK
1153 if (opts & OPT_mark)
1154 G.markInterval = xatou_range(opt_m, 0, INT_MAX/60) * 60;
1155#endif
1156
1157
1158 if (opts & OPT_loglevel)
1159 G.logLevel = xatou_range(opt_l, 1, 8);
1160
1161#if ENABLE_FEATURE_ROTATE_LOGFILE
1162 if (opts & OPT_filesize)
1163 G.logFileSize = xatou_range(opt_s, 0, INT_MAX/1024) * 1024;
1164 if (opts & OPT_rotatecnt)
1165 G.logFileRotate = xatou_range(opt_b, 0, 99);
1166#endif
1167#if ENABLE_FEATURE_IPC_SYSLOG
1168 if (opt_C)
1169 G.shm_size = xatoul_range(opt_C, 4, INT_MAX/1024) * 1024;
1170#endif
1171
1172 if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog))
1173 option_mask32 |= OPT_locallog;
1174#if ENABLE_FEATURE_SYSLOGD_CFG
1175 parse_syslogdcfg(opt_f);
1176#endif
1177
1178
1179 G.hostname = safe_gethostname();
1180 *strchrnul(G.hostname, '.') = '\0';
1181
1182 if (!(opts & OPT_nofork)) {
1183 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
1184 }
1185
1186 do_syslogd();
1187
1188}
1189
1190
1191#undef DEBUG
1192#undef SYSLOGD_MARK
1193#undef SYSLOGD_WRLOCK
1194#undef G
1195#undef GLOBALS
1196#undef INIT_G
1197#undef OPTION_STR
1198#undef OPTION_DECL
1199#undef OPTION_PARAM
1200