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