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