a28dde6b36a8368596e6e3eb547a5533d8bf6111
[oweals/busybox.git] / sysklogd / syslogd.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini syslogd implementation for busybox
4  *
5  * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6  *
7  * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
8  *
9  * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>
10  *
11  * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001
12  *
13  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
14  */
15
16 #include "busybox.h"
17 #include <paths.h>
18 #include <stdbool.h>
19 #include <sys/un.h>
20
21 /* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
22 #define SYSLOG_NAMES
23 #include <sys/syslog.h>
24 #include <sys/uio.h>
25
26 /* Path to the unix socket */
27 static char lfile[MAXPATHLEN];
28
29 /* Path for the file where all log messages are written */
30 static const char *logFilePath = "/var/log/messages";
31
32 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE
33 /* max size of message file before being rotated */
34 static int logFileSize = 200 * 1024;
35
36 /* number of rotated message files */
37 static int logFileRotate = 1;
38 #endif
39
40 /* interval between marks in seconds */
41 static int MarkInterval = 20 * 60;
42
43 /* level of messages to be locally logged */
44 static int logLevel = 8;
45
46 /* localhost's name */
47 static char LocalHostName[64];
48
49 #ifdef CONFIG_FEATURE_REMOTE_LOG
50 #include <netinet/in.h>
51 /* udp socket for logging to remote host */
52 static int remotefd = -1;
53 static struct sockaddr_in remoteaddr;
54
55 /* where do we log? */
56 static char *RemoteHost;
57
58 /* what port to log to? */
59 static int RemotePort = 514;
60
61 #endif
62
63 /* options */
64 static unsigned option_mask;
65 /* Correct regardless of combination of CONFIG_xxx */
66 enum {
67         OPTBIT_mark = 0, // -m
68         OPTBIT_nofork, // -n
69         OPTBIT_outfile, // -O
70         OPTBIT_loglevel, // -l
71         OPTBIT_small, // -S
72         USE_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize   ,) // -s
73         USE_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt  ,) // -b
74         USE_FEATURE_REMOTE_LOG(    OPTBIT_remote     ,) // -R
75         USE_FEATURE_REMOTE_LOG(    OPTBIT_localtoo   ,) // -L
76         USE_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,) // -C
77
78         OPT_mark        = 1 << OPTBIT_mark    ,
79         OPT_nofork      = 1 << OPTBIT_nofork  ,
80         OPT_outfile     = 1 << OPTBIT_outfile ,
81         OPT_loglevel    = 1 << OPTBIT_loglevel,
82         OPT_small       = 1 << OPTBIT_small   ,
83         OPT_filesize    = USE_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize   )) + 0,
84         OPT_rotatecnt   = USE_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt  )) + 0,
85         OPT_remotelog   = USE_FEATURE_REMOTE_LOG(    (1 << OPTBIT_remote     )) + 0,
86         OPT_locallog    = USE_FEATURE_REMOTE_LOG(    (1 << OPTBIT_localtoo   )) + 0,
87         OPT_circularlog = USE_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
88 };
89 #define OPTION_STR "m:nO:l:S" \
90         USE_FEATURE_ROTATE_LOGFILE("s:" ) \
91         USE_FEATURE_ROTATE_LOGFILE("b:" ) \
92         USE_FEATURE_REMOTE_LOG(    "R:" ) \
93         USE_FEATURE_REMOTE_LOG(    "L"  ) \
94         USE_FEATURE_IPC_SYSLOG(    "C::")
95 #define OPTION_DECL *opt_m, *opt_l \
96         USE_FEATURE_ROTATE_LOGFILE(,*opt_s) \
97         USE_FEATURE_ROTATE_LOGFILE(,*opt_b) \
98         USE_FEATURE_REMOTE_LOG(    ,*opt_R) \
99         USE_FEATURE_IPC_SYSLOG(    ,*opt_C = NULL)
100 #define OPTION_PARAM &opt_m, &logFilePath, &opt_l \
101         USE_FEATURE_ROTATE_LOGFILE(,&opt_s) \
102         USE_FEATURE_ROTATE_LOGFILE(,&opt_b) \
103         USE_FEATURE_REMOTE_LOG(    ,&opt_R) \
104         USE_FEATURE_IPC_SYSLOG(    ,&opt_C)
105
106 #define MAXLINE         1024    /* maximum line length */
107
108 /* circular buffer variables/structures */
109 #ifdef CONFIG_FEATURE_IPC_SYSLOG
110
111 #if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4
112 #error Sorry, you must set the syslogd buffer size to at least 4KB.
113 #error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE
114 #endif
115
116 #include <sys/ipc.h>
117 #include <sys/sem.h>
118 #include <sys/shm.h>
119
120 /* our shared key */
121 #define KEY_ID ((long)0x414e4547) /* "GENA" */
122
123 // Semaphore operation structures
124 static struct shbuf_ds {
125         int size;       // size of data written
126         int head;       // start of message list
127         int tail;       // end of message list
128         char data[1];   // data/messages
129 } *shbuf = NULL;        // shared memory pointer
130
131 static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} };        // set SMwup
132 static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} };    // set SMwdn
133
134 static int shmid = -1;   // ipc shared memory id
135 static int s_semid = -1; // ipc semaphore id
136 static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024);   // default shm size
137
138 static void ipcsyslog_cleanup(void)
139 {
140         puts("Exiting syslogd!");
141         if (shmid != -1) {
142                 shmdt(shbuf);
143         }
144
145         if (shmid != -1) {
146                 shmctl(shmid, IPC_RMID, NULL);
147         }
148         if (s_semid != -1) {
149                 semctl(s_semid, 0, IPC_RMID, 0);
150         }
151 }
152
153 static void ipcsyslog_init(void)
154 {
155         if (shbuf == NULL) {
156                 shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023);
157                 if (shmid == -1) {
158                         bb_perror_msg_and_die("shmget");
159                 }
160
161                 shbuf = shmat(shmid, NULL, 0);
162                 if (!shbuf) {
163                         bb_perror_msg_and_die("shmat");
164                 }
165
166                 shbuf->size = shm_size - sizeof(*shbuf);
167                 shbuf->head = shbuf->tail = 0;
168
169                 // we'll trust the OS to set initial semval to 0 (let's hope)
170                 s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023);
171                 if (s_semid == -1) {
172                         if (errno == EEXIST) {
173                                 s_semid = semget(KEY_ID, 2, 0);
174                                 if (s_semid == -1) {
175                                         bb_perror_msg_and_die("semget");
176                                 }
177                         } else {
178                                 bb_perror_msg_and_die("semget");
179                         }
180                 }
181         } else {
182                 printf("Buffer already allocated just grab the semaphore?");
183         }
184 }
185
186 /* write message to buffer */
187 static void circ_message(const char *msg)
188 {
189         int l = strlen(msg) + 1;        /* count the whole message w/ '\0' included */
190         const char * const fail_msg = "Can't find the terminator token%s?\n";
191
192         if (semop(s_semid, SMwdn, 3) == -1) {
193                 bb_perror_msg_and_die("SMwdn");
194         }
195
196         /*
197          * Circular Buffer Algorithm:
198          * --------------------------
199          *
200          * Start-off w/ empty buffer of specific size SHM_SIZ
201          * Start filling it up w/ messages. I use '\0' as separator to break up messages.
202          * This is also very handy since we can do printf on message.
203          *
204          * Once the buffer is full we need to get rid of the first message in buffer and
205          * insert the new message. (Note: if the message being added is >1 message then
206          * we will need to "remove" >1 old message from the buffer). The way this is done
207          * is the following:
208          *      When we reach the end of the buffer we set a mark and start from the beginning.
209          *      Now what about the beginning and end of the buffer? Well we have the "head"
210          *      index/pointer which is the starting point for the messages and we have "tail"
211          *      index/pointer which is the ending point for the messages. When we "display" the
212          *      messages we start from the beginning and continue until we reach "tail". If we
213          *      reach end of buffer, then we just start from the beginning (offset 0). "head" and
214          *      "tail" are actually offsets from the beginning of the buffer.
215          *
216          * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
217          *       a threadsafe way of handling shared memory operations.
218          */
219         if ((shbuf->tail + l) < shbuf->size) {
220                 /* before we append the message we need to check the HEAD so that we won't
221                    overwrite any of the message that we still need and adjust HEAD to point
222                    to the next message! */
223                 if (shbuf->tail < shbuf->head) {
224                         if ((shbuf->tail + l) >= shbuf->head) {
225                                 /* we need to move the HEAD to point to the next message
226                                  * Theoretically we have enough room to add the whole message to the
227                                  * buffer, because of the first outer IF statement, so we don't have
228                                  * to worry about overflows here!
229                                  */
230                                 /* we need to know how many bytes we are overwriting to make enough room */
231                                 int k = shbuf->tail + l - shbuf->head;
232                                 char *c =
233                                         memchr(shbuf->data + shbuf->head + k, '\0',
234                                                    shbuf->size - (shbuf->head + k));
235                                 if (c != NULL) { /* do a sanity check just in case! */
236                                         /* we need to convert pointer to offset + skip the '\0'
237                                            since we need to point to the beginning of the next message */
238                                         shbuf->head = c - shbuf->data + 1;
239                                         /* Note: HEAD is only used to "retrieve" messages, it's not used
240                                            when writing messages into our buffer */
241                                 } else { /* show an error message to know we messed up? */
242                                         printf(fail_msg,"");
243                                         shbuf->head = 0;
244                                 }
245                         }
246                 }
247
248                 /* in other cases no overflows have been done yet, so we don't care! */
249                 /* we should be ok to append the message now */
250                 strncpy(shbuf->data + shbuf->tail, msg, l);     /* append our message */
251                 shbuf->tail += l;       /* count full message w/ '\0' terminating char */
252         } else {
253                 /* we need to break up the message and "circle" it around */
254                 char *c;
255                 int k = shbuf->tail + l - shbuf->size;  /* count # of bytes we don't fit */
256
257                 /* We need to move HEAD! This is always the case since we are going
258                  * to "circle" the message. */
259                 c = memchr(shbuf->data + k, '\0', shbuf->size - k);
260
261                 if (c != NULL) {        /* if we don't have '\0'??? weird!!! */
262                         /* move head pointer */
263                         shbuf->head = c - shbuf->data + 1;
264
265                         /* now write the first part of the message */
266                         strncpy(shbuf->data + shbuf->tail, msg, l - k - 1);
267
268                         /* ALWAYS terminate end of buffer w/ '\0' */
269                         shbuf->data[shbuf->size - 1] = '\0';
270
271                         /* now write out the rest of the string to the beginning of the buffer */
272                         strcpy(shbuf->data, &msg[l - k - 1]);
273
274                         /* we need to place the TAIL at the end of the message */
275                         shbuf->tail = k + 1;
276                 } else {
277                         printf(fail_msg, " from the beginning");
278                         shbuf->head = shbuf->tail = 0;  /* reset buffer, since it's probably corrupted */
279                 }
280
281         }
282         if (semop(s_semid, SMwup, 1) == -1) {
283                 bb_perror_msg_and_die("SMwup");
284         }
285
286 }
287 #else
288 void ipcsyslog_cleanup(void);
289 void ipcsyslog_init(void);
290 void circ_message(const char *msg);
291 #endif                                                  /* CONFIG_FEATURE_IPC_SYSLOG */
292
293 /* Note: There is also a function called "message()" in init.c */
294 /* Print a message to the log file. */
295 static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
296 static void message(char *fmt, ...)
297 {
298         int fd = -1;
299         struct flock fl;
300         va_list arguments;
301
302         fl.l_whence = SEEK_SET;
303         fl.l_start = 0;
304         fl.l_len = 1;
305
306 #ifdef CONFIG_FEATURE_IPC_SYSLOG
307         if ((option_mask & OPT_circularlog) && shbuf) {
308                 char b[1024];
309
310                 va_start(arguments, fmt);
311                 vsnprintf(b, sizeof(b) - 1, fmt, arguments);
312                 va_end(arguments);
313                 circ_message(b);
314
315         } else
316 #endif
317         fd = device_open(logFilePath, O_WRONLY | O_CREAT
318                                         | O_NOCTTY | O_APPEND | O_NONBLOCK);
319         if (fd >= 0) {
320                 fl.l_type = F_WRLCK;
321                 fcntl(fd, F_SETLKW, &fl);
322
323 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE
324                 if (ENABLE_FEATURE_ROTATE_LOGFILE && logFileSize > 0 ) {
325                         struct stat statf;
326                         int r = fstat(fd, &statf);
327                         if (!r && (statf.st_mode & S_IFREG)
328                                         && (lseek(fd,0,SEEK_END) > logFileSize)) {
329                                 if (logFileRotate > 0) {
330                                         int i = strlen(logFilePath) + 4;
331                                         char oldFile[i];
332                                         char newFile[i];
333                                         for (i=logFileRotate-1; i>0; i--) {
334                                                 sprintf(oldFile, "%s.%d", logFilePath, i-1);
335                                                 sprintf(newFile, "%s.%d", logFilePath, i);
336                                                 rename(oldFile, newFile);
337                                         }
338                                         sprintf(newFile, "%s.%d", logFilePath, 0);
339                                         fl.l_type = F_UNLCK;
340                                         fcntl(fd, F_SETLKW, &fl);
341                                         close(fd);
342                                         rename(logFilePath, newFile);
343                                         fd = device_open(logFilePath,
344                                                    O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
345                                                    O_NONBLOCK);
346                                         fl.l_type = F_WRLCK;
347                                         fcntl(fd, F_SETLKW, &fl);
348                                 } else {
349                                         ftruncate(fd, 0);
350                                 }
351                         }
352                 }
353 #endif
354                 va_start(arguments, fmt);
355                 vdprintf(fd, fmt, arguments);
356                 va_end(arguments);
357                 fl.l_type = F_UNLCK;
358                 fcntl(fd, F_SETLKW, &fl);
359                 close(fd);
360         } else {
361                 /* Always send console messages to /dev/console so people will see them. */
362                 fd = device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK);
363                 if (fd >= 0) {
364                         va_start(arguments, fmt);
365                         vdprintf(fd, fmt, arguments);
366                         va_end(arguments);
367                         close(fd);
368                 } else {
369                         fprintf(stderr, "Bummer, can't print: ");
370                         va_start(arguments, fmt);
371                         vfprintf(stderr, fmt, arguments);
372                         fflush(stderr);
373                         va_end(arguments);
374                 }
375         }
376 }
377
378 #ifdef CONFIG_FEATURE_REMOTE_LOG
379 static void init_RemoteLog(void)
380 {
381         memset(&remoteaddr, 0, sizeof(remoteaddr));
382         remotefd = xsocket(AF_INET, SOCK_DGRAM, 0);
383         remoteaddr.sin_family = AF_INET;
384         remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list;
385         remoteaddr.sin_port = htons(RemotePort);
386 }
387 #else
388 void init_RemoteLog(void);
389 #endif
390
391 static void logMessage(int pri, char *msg)
392 {
393         time_t now;
394         char *timestamp;
395         char res[20];
396         CODE *c_pri, *c_fac;
397
398         if (pri != 0) {
399                 c_fac = facilitynames;
400                 while (c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3))
401                         c_fac++;
402                 c_pri = prioritynames;
403                 while (c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)))
404                         c_pri++;
405                 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
406                         snprintf(res, sizeof(res), "<%d>", pri);
407                 } else {
408                         snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
409                 }
410         }
411
412         if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
413                 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
414                 time(&now);
415                 timestamp = ctime(&now) + 4;
416                 timestamp[15] = '\0';
417         } else {
418                 timestamp = msg;
419                 timestamp[15] = '\0';
420                 msg += 16;
421         }
422
423         /* todo: supress duplicates */
424
425 #ifdef CONFIG_FEATURE_REMOTE_LOG
426         if (option_mask & OPT_remotelog) {
427                 char line[MAXLINE + 1];
428                 /* trying connect the socket */
429                 if (-1 == remotefd) {
430                         init_RemoteLog();
431                 }
432
433                 /* if we have a valid socket, send the message */
434                 if (-1 != remotefd) {
435                         now = 1;
436                         snprintf(line, sizeof(line), "<%d>%s", pri, msg);
437
438 retry:
439                         /* send message to remote logger */
440                         if ((-1 == sendto(remotefd, line, strlen(line), 0,
441                                                         (struct sockaddr *) &remoteaddr,
442                                                         sizeof(remoteaddr))) && (errno == EINTR)) {
443                                 /* sleep now seconds and retry (with now * 2) */
444                                 sleep(now);
445                                 now *= 2;
446                                 goto retry;
447                         }
448                 }
449         }
450
451         if (option_mask & OPT_locallog)
452 #endif
453         {
454                 /* now spew out the message to wherever it is supposed to go */
455                 if (pri == 0 || LOG_PRI(pri) < logLevel) {
456                         if (option_mask & OPT_small)
457                                 message("%s %s\n", timestamp, msg);
458                         else
459                                 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
460                 }
461         }
462 }
463
464 static void quit_signal(int sig)
465 {
466         logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
467         unlink(lfile);
468         if (ENABLE_FEATURE_IPC_SYSLOG)
469                 ipcsyslog_cleanup();
470
471         exit(TRUE);
472 }
473
474 static void domark(int sig)
475 {
476         if (MarkInterval > 0) {
477                 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
478                 alarm(MarkInterval);
479         }
480 }
481
482 /* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
483  * enabled, we otherwise get a "storage size isn't constant error. */
484 static int serveConnection(char *tmpbuf, int n_read)
485 {
486         char *p = tmpbuf;
487
488         while (p < tmpbuf + n_read) {
489
490                 int pri = (LOG_USER | LOG_NOTICE);
491                 int num_lt = 0;
492                 char line[MAXLINE + 1];
493                 unsigned char c;
494                 char *q = line;
495
496                 while ((c = *p) && q < &line[sizeof(line) - 1]) {
497                         if (c == '<' && num_lt == 0) {
498                                 /* Parse the magic priority number. */
499                                 num_lt++;
500                                 pri = 0;
501                                 while (isdigit(*(++p))) {
502                                         pri = 10 * pri + (*p - '0');
503                                 }
504                                 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
505                                         pri = (LOG_USER | LOG_NOTICE);
506                                 }
507                         } else if (c == '\n') {
508                                 *q++ = ' ';
509                         } else if (iscntrl(c) && (c < 0177)) {
510                                 *q++ = '^';
511                                 *q++ = c ^ 0100;
512                         } else {
513                                 *q++ = c;
514                         }
515                         p++;
516                 }
517                 *q = '\0';
518                 p++;
519                 /* Now log it */
520                 logMessage(pri, line);
521         }
522         return n_read;
523 }
524
525 static void doSyslogd(void) ATTRIBUTE_NORETURN;
526 static void doSyslogd(void)
527 {
528         struct sockaddr_un sunx;
529         socklen_t addrLength;
530
531         int sock_fd;
532         fd_set fds;
533
534         /* Set up signal handlers. */
535         signal(SIGINT, quit_signal);
536         signal(SIGTERM, quit_signal);
537         signal(SIGQUIT, quit_signal);
538         signal(SIGHUP, SIG_IGN);
539         signal(SIGCHLD, SIG_IGN);
540 #ifdef SIGCLD
541         signal(SIGCLD, SIG_IGN);
542 #endif
543         signal(SIGALRM, domark);
544         alarm(MarkInterval);
545
546         /* Create the syslog file so realpath() can work. */
547         if (realpath(_PATH_LOG, lfile) != NULL) {
548                 unlink(lfile);
549         }
550
551         memset(&sunx, 0, sizeof(sunx));
552         sunx.sun_family = AF_UNIX;
553         strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
554         sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
555         addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
556         if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
557                 bb_perror_msg_and_die("cannot connect to socket %s", lfile);
558         }
559
560         if (chmod(lfile, 0666) < 0) {
561                 bb_perror_msg_and_die("cannot set permission on %s", lfile);
562         }
563         if (ENABLE_FEATURE_IPC_SYSLOG && (option_mask & OPT_circularlog)) {
564                 ipcsyslog_init();
565         }
566
567         if (ENABLE_FEATURE_REMOTE_LOG && (option_mask & OPT_remotelog)) {
568                 init_RemoteLog();
569         }
570
571         logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " "BusyBox v" BB_VER );
572
573         for (;;) {
574                 FD_ZERO(&fds);
575                 FD_SET(sock_fd, &fds);
576
577                 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
578                         if (errno == EINTR) {
579                                 /* alarm may have happened. */
580                                 continue;
581                         }
582                         bb_perror_msg_and_die("select");
583                 }
584
585                 if (FD_ISSET(sock_fd, &fds)) {
586                         int i;
587 #if MAXLINE > BUFSIZ
588 # define TMP_BUF_SZ BUFSIZ
589 #else
590 # define TMP_BUF_SZ MAXLINE
591 #endif
592 #define tmpbuf bb_common_bufsiz1
593
594                         if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) {
595                                 tmpbuf[i] = '\0';
596                                 serveConnection(tmpbuf, i);
597                         } else {
598                                 bb_perror_msg_and_die("UNIX socket error");
599                         }
600                 }                               /* FD_ISSET() */
601         }                                       /* for main loop */
602 }
603
604
605 int syslogd_main(int argc, char **argv)
606 {
607         char OPTION_DECL;
608         char *p;
609
610         /* do normal option parsing */
611         option_mask = bb_getopt_ulflags(argc, argv, OPTION_STR, OPTION_PARAM);
612         if (option_mask & OPT_mark) MarkInterval = atoi(opt_m) * 60; // -m
613         //if (option_mask & OPT_nofork) // -n
614         //if (option_mask & OPT_outfile) // -O
615         if (option_mask & OPT_loglevel) { // -l
616                 logLevel = atoi(opt_l);
617                 /* Valid levels are between 1 and 8 */
618                 if (logLevel < 1 || logLevel > 8)
619                         bb_show_usage();
620         }
621         //if (option_mask & OPT_small) // -S
622 #if ENABLE_FEATURE_ROTATE_LOGFILE
623         if (option_mask & OPT_filesize) logFileSize = atoi(opt_s) * 1024; // -s
624         if (option_mask & OPT_rotatecnt) { // -b
625                 logFileRotate = atoi(opt_b);
626                 if (logFileRotate > 99) logFileRotate = 99; 
627         }
628 #endif
629 #if ENABLE_FEATURE_REMOTE_LOG
630         if (option_mask & OPT_remotelog) { // -R
631                 RemoteHost = xstrdup(opt_R);
632                 p = strchr(RemoteHost, ':');
633                 if (p) {
634                         RemotePort = atoi(p + 1);
635                         *p = '\0';
636                 }
637         }
638         //if (option_mask & OPT_locallog) // -L
639 #endif
640 #if ENABLE_FEATURE_IPC_SYSLOG
641         if (option_mask & OPT_circularlog) { // -C
642                 if (opt_C) {
643                         int buf_size = atoi(opt_C);
644                         if (buf_size >= 4)
645                                 shm_size = buf_size * 1024;
646                 }
647         }
648 #endif
649
650         /* If they have not specified remote logging, then log locally */
651         if (ENABLE_FEATURE_REMOTE_LOG && !(option_mask & OPT_remotelog))
652                 option_mask |= OPT_locallog;
653
654         /* Store away localhost's name before the fork */
655         gethostname(LocalHostName, sizeof(LocalHostName));
656         p = strchr(LocalHostName, '.');
657         if (p) {
658                 *p = '\0';
659         }
660
661         umask(0);
662
663         if (!(option_mask & OPT_nofork)) {
664 #ifdef BB_NOMMU
665                 vfork_daemon_rexec(0, 1, argc, argv, "-n");
666 #else
667                 xdaemon(0, 1);
668 #endif
669         }
670         doSyslogd();
671
672         return EXIT_SUCCESS;
673 }