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