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