e754806daca67103488b3faba8a5386a110d8db7
[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  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21  * General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26  *
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <getopt.h>
35 #include <netdb.h>
36 #include <paths.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdbool.h>
40 #include <time.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/socket.h>
44 #include <sys/types.h>
45 #include <sys/un.h>
46 #include <sys/param.h>
47
48 #include "busybox.h"
49
50 /* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
51 #define SYSLOG_NAMES
52 #include <sys/syslog.h>
53 #include <sys/uio.h>
54
55 /* Path for the file where all log messages are written */
56 #define __LOG_FILE "/var/log/messages"
57
58 /* Path to the unix socket */
59 static char lfile[MAXPATHLEN];
60
61 static const char *logFilePath = __LOG_FILE;
62
63 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE
64 /* max size of message file before being rotated */
65 static int logFileSize = 200 * 1024;
66
67 /* number of rotated message files */
68 static int logFileRotate = 1;
69 #endif
70
71 /* interval between marks in seconds */
72 static int MarkInterval = 20 * 60;
73
74 /* localhost's name */
75 static char LocalHostName[64];
76
77 #ifdef CONFIG_FEATURE_REMOTE_LOG
78 #include <netinet/in.h>
79 /* udp socket for logging to remote host */
80 static int remotefd = -1;
81 static struct sockaddr_in remoteaddr;
82
83 /* where do we log? */
84 static char *RemoteHost;
85
86 /* what port to log to? */
87 static int RemotePort = 514;
88
89 /* To remote log or not to remote log, that is the question. */
90 static int doRemoteLog = FALSE;
91 static int local_logging = FALSE;
92 #endif
93
94 /* Make loging output smaller. */
95 static bool small = false;
96
97
98 #define MAXLINE         1024    /* maximum line length */
99
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 static const long KEY_ID = 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 } *buf = 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 static int circular_logging = FALSE;
131
132 /*
133  * sem_up - up()'s a semaphore.
134  */
135 static inline void sem_up(int semid)
136 {
137         if (semop(semid, SMwup, 1) == -1) {
138                 bb_perror_msg_and_die("semop[SMwup]");
139         }
140 }
141
142 /*
143  * sem_down - down()'s a semaphore
144  */
145 static inline void sem_down(int semid)
146 {
147         if (semop(semid, SMwdn, 3) == -1) {
148                 bb_perror_msg_and_die("semop[SMwdn]");
149         }
150 }
151
152
153 static void ipcsyslog_cleanup(void)
154 {
155         printf("Exiting Syslogd!\n");
156         if (shmid != -1) {
157                 shmdt(buf);
158         }
159
160         if (shmid != -1) {
161                 shmctl(shmid, IPC_RMID, NULL);
162         }
163         if (s_semid != -1) {
164                 semctl(s_semid, 0, IPC_RMID, 0);
165         }
166 }
167
168 static void ipcsyslog_init(void)
169 {
170         if (buf == NULL) {
171                 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) {
172                         bb_perror_msg_and_die("shmget");
173                 }
174
175                 if ((buf = shmat(shmid, NULL, 0)) == NULL) {
176                         bb_perror_msg_and_die("shmat");
177                 }
178
179                 buf->size = shm_size - sizeof(*buf);
180                 buf->head = buf->tail = 0;
181
182                 // we'll trust the OS to set initial semval to 0 (let's hope)
183                 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) {
184                         if (errno == EEXIST) {
185                                 if ((s_semid = semget(KEY_ID, 2, 0)) == -1) {
186                                         bb_perror_msg_and_die("semget");
187                                 }
188                         } else {
189                                 bb_perror_msg_and_die("semget");
190                         }
191                 }
192         } else {
193                 printf("Buffer already allocated just grab the semaphore?");
194         }
195 }
196
197 /* write message to buffer */
198 static void circ_message(const char *msg)
199 {
200         int l = strlen(msg) + 1;        /* count the whole message w/ '\0' included */
201
202         sem_down(s_semid);
203
204         /*
205          * Circular Buffer Algorithm:
206          * --------------------------
207          *
208          * Start-off w/ empty buffer of specific size SHM_SIZ
209          * Start filling it up w/ messages. I use '\0' as separator to break up messages.
210          * This is also very handy since we can do printf on message.
211          *
212          * Once the buffer is full we need to get rid of the first message in buffer and
213          * insert the new message. (Note: if the message being added is >1 message then
214          * we will need to "remove" >1 old message from the buffer). The way this is done
215          * is the following:
216          *      When we reach the end of the buffer we set a mark and start from the beginning.
217          *      Now what about the beginning and end of the buffer? Well we have the "head"
218          *      index/pointer which is the starting point for the messages and we have "tail"
219          *      index/pointer which is the ending point for the messages. When we "display" the
220          *      messages we start from the beginning and continue until we reach "tail". If we
221          *      reach end of buffer, then we just start from the beginning (offset 0). "head" and
222          *      "tail" are actually offsets from the beginning of the buffer.
223          *
224          * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
225          *       a threasafe way of handling shared memory operations.
226          */
227         if ((buf->tail + l) < buf->size) {
228                 /* before we append the message we need to check the HEAD so that we won't
229                    overwrite any of the message that we still need and adjust HEAD to point
230                    to the next message! */
231                 if (buf->tail < buf->head) {
232                         if ((buf->tail + l) >= buf->head) {
233                                 /* we need to move the HEAD to point to the next message
234                                  * Theoretically we have enough room to add the whole message to the
235                                  * buffer, because of the first outer IF statement, so we don't have
236                                  * to worry about overflows here!
237                                  */
238                                 int k = buf->tail + l - buf->head;      /* we need to know how many bytes
239                                                                                                            we are overwriting to make
240                                                                                                            enough room */
241                                 char *c =
242                                         memchr(buf->data + buf->head + k, '\0',
243                                                    buf->size - (buf->head + k));
244                                 if (c != NULL) {        /* do a sanity check just in case! */
245                                         buf->head = c - buf->data + 1;  /* we need to convert pointer to
246                                                                                                            offset + skip the '\0' since
247                                                                                                            we need to point to the beginning
248                                                                                                            of the next message */
249                                         /* Note: HEAD is only used to "retrieve" messages, it's not used
250                                            when writing messages into our buffer */
251                                 } else {        /* show an error message to know we messed up? */
252                                         printf("Weird! Can't find the terminator token??? \n");
253                                         buf->head = 0;
254                                 }
255                         }
256                 }
257
258                 /* in other cases no overflows have been done yet, so we don't care! */
259                 /* we should be ok to append the message now */
260                 strncpy(buf->data + buf->tail, msg, l); /* append our message */
261                 buf->tail += l; /* count full message w/ '\0' terminating char */
262         } else {
263                 /* we need to break up the message and "circle" it around */
264                 char *c;
265                 int k = buf->tail + l - buf->size;      /* count # of bytes we don't fit */
266
267                 /* We need to move HEAD! This is always the case since we are going
268                  * to "circle" the message.
269                  */
270                 c = memchr(buf->data + k, '\0', buf->size - k);
271
272                 if (c != NULL) {        /* if we don't have '\0'??? weird!!! */
273                         /* move head pointer */
274                         buf->head = c - buf->data + 1;
275
276                         /* now write the first part of the message */
277                         strncpy(buf->data + buf->tail, msg, l - k - 1);
278
279                         /* ALWAYS terminate end of buffer w/ '\0' */
280                         buf->data[buf->size - 1] = '\0';
281
282                         /* now write out the rest of the string to the beginning of the buffer */
283                         strcpy(buf->data, &msg[l - k - 1]);
284
285                         /* we need to place the TAIL at the end of the message */
286                         buf->tail = k + 1;
287                 } else {
288                         printf
289                                 ("Weird! Can't find the terminator token from the beginning??? \n");
290                         buf->head = buf->tail = 0;      /* reset buffer, since it's probably corrupted */
291                 }
292
293         }
294         sem_up(s_semid);
295 }
296 #endif                                                  /* CONFIG_FEATURE_IPC_SYSLOG */
297
298 /* Note: There is also a function called "message()" in init.c */
299 /* Print a message to the log file. */
300 static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
301 static void message(char *fmt, ...)
302 {
303         int fd;
304         struct flock fl;
305         va_list arguments;
306
307         fl.l_whence = SEEK_SET;
308         fl.l_start = 0;
309         fl.l_len = 1;
310
311 #ifdef CONFIG_FEATURE_IPC_SYSLOG
312         if ((circular_logging == TRUE) && (buf != NULL)) {
313                 char b[1024];
314
315                 va_start(arguments, fmt);
316                 vsnprintf(b, sizeof(b) - 1, fmt, arguments);
317                 va_end(arguments);
318                 circ_message(b);
319
320         } else
321 #endif
322         if ((fd =
323                          device_open(logFilePath,
324                                                          O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
325                                                          O_NONBLOCK)) >= 0) {
326                 fl.l_type = F_WRLCK;
327                 fcntl(fd, F_SETLKW, &fl);
328 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE
329                 if ( logFileSize > 0 ) {
330                         struct stat statf;
331                         int r = fstat(fd, &statf);
332                         if( !r && (statf.st_mode & S_IFREG)
333                                 && (lseek(fd,0,SEEK_END) > logFileSize) ) {
334                                 if(logFileRotate > 0) {
335                                         int i;
336                                         char oldFile[(strlen(logFilePath)+4)], newFile[(strlen(logFilePath)+4)];
337                                         for(i=logFileRotate-1;i>0;i--) {
338                                                 sprintf(oldFile, "%s.%d", logFilePath, i-1);
339                                                 sprintf(newFile, "%s.%d", logFilePath, i);
340                                                 rename(oldFile, newFile);
341                                         }
342                                         sprintf(newFile, "%s.%d", logFilePath, 0);
343                                         fl.l_type = F_UNLCK;
344                                         fcntl (fd, F_SETLKW, &fl);
345                                         close(fd);
346                                         rename(logFilePath, newFile);
347                                         fd = device_open (logFilePath,
348                                                    O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
349                                                    O_NONBLOCK);
350                                         fl.l_type = F_WRLCK;
351                                         fcntl (fd, F_SETLKW, &fl);
352                                 } else {
353                                         ftruncate( fd, 0 );
354                                 }
355                         }
356                 }
357 #endif
358                 va_start(arguments, fmt);
359                 vdprintf(fd, fmt, arguments);
360                 va_end(arguments);
361                 fl.l_type = F_UNLCK;
362                 fcntl(fd, F_SETLKW, &fl);
363                 close(fd);
364         } else {
365                 /* Always send console messages to /dev/console so people will see them. */
366                 if ((fd =
367                          device_open(_PATH_CONSOLE,
368                                                  O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
369                         va_start(arguments, fmt);
370                         vdprintf(fd, fmt, arguments);
371                         va_end(arguments);
372                         close(fd);
373                 } else {
374                         fprintf(stderr, "Bummer, can't print: ");
375                         va_start(arguments, fmt);
376                         vfprintf(stderr, fmt, arguments);
377                         fflush(stderr);
378                         va_end(arguments);
379                 }
380         }
381 }
382
383 #ifdef CONFIG_FEATURE_REMOTE_LOG
384 static void init_RemoteLog(void)
385 {
386         memset(&remoteaddr, 0, sizeof(remoteaddr));
387         remotefd = socket(AF_INET, SOCK_DGRAM, 0);
388
389         if (remotefd < 0) {
390                 bb_error_msg("cannot create socket");
391         }
392
393         remoteaddr.sin_family = AF_INET;
394         remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list;
395         remoteaddr.sin_port = htons(RemotePort);
396 }
397 #endif
398
399 static void logMessage(int pri, char *msg)
400 {
401         time_t now;
402         char *timestamp;
403         static char res[20] = "";
404 #ifdef CONFIG_FEATURE_REMOTE_LOG        
405         static char line[MAXLINE + 1];
406 #endif
407         CODE *c_pri, *c_fac;
408
409         if (pri != 0) {
410                 for (c_fac = facilitynames;
411                          c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
412                 for (c_pri = prioritynames;
413                          c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
414                 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
415                         snprintf(res, sizeof(res), "<%d>", pri);
416                 } else {
417                         snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
418                 }
419         }
420
421         if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
422                 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
423                 time(&now);
424                 timestamp = ctime(&now) + 4;
425                 timestamp[15] = '\0';
426         } else {
427                 timestamp = msg;
428                 timestamp[15] = '\0';
429                 msg += 16;
430         }
431
432         /* todo: supress duplicates */
433
434 #ifdef CONFIG_FEATURE_REMOTE_LOG
435         if (doRemoteLog == TRUE) {
436                 /* trying connect the socket */
437                 if (-1 == remotefd) {
438                         init_RemoteLog();
439                 }
440
441                 /* if we have a valid socket, send the message */
442                 if (-1 != remotefd) {
443                         now = 1;
444                         snprintf(line, sizeof(line), "<%d>%s", pri, msg);
445
446                 retry:
447                         /* send message to remote logger */
448                         if(( -1 == sendto(remotefd, line, strlen(line), 0,
449                                                         (struct sockaddr *) &remoteaddr,
450                                                         sizeof(remoteaddr))) && (errno == EINTR)) {
451                                 /* sleep now seconds and retry (with now * 2) */
452                                 sleep(now);
453                                 now *= 2;
454                                 goto retry;
455                         }
456                 }
457         }
458
459         if (local_logging == TRUE)
460 #endif
461         {
462                 /* now spew out the message to wherever it is supposed to go */
463                 if (small)
464                         message("%s %s\n", timestamp, msg);
465                 else
466                         message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
467         }
468 }
469
470 static void quit_signal(int sig)
471 {
472         logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
473         unlink(lfile);
474 #ifdef CONFIG_FEATURE_IPC_SYSLOG
475         ipcsyslog_cleanup();
476 #endif
477
478         exit(TRUE);
479 }
480
481 static void domark(int sig)
482 {
483         if (MarkInterval > 0) {
484                 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
485                 alarm(MarkInterval);
486         }
487 }
488
489 /* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
490  * enabled, we otherwise get a "storage size isn't constant error. */
491 static int serveConnection(char *tmpbuf, int n_read)
492 {
493         char *p = tmpbuf;
494
495         while (p < tmpbuf + n_read) {
496
497                 int pri = (LOG_USER | LOG_NOTICE);
498                 int num_lt = 0;
499                 char line[MAXLINE + 1];
500                 unsigned char c;
501                 char *q = line;
502
503                 while ((c = *p) && q < &line[sizeof(line) - 1]) {
504                         if (c == '<' && num_lt == 0) {
505                                 /* Parse the magic priority number. */
506                                 num_lt++;
507                                 pri = 0;
508                                 while (isdigit(*(++p))) {
509                                         pri = 10 * pri + (*p - '0');
510                                 }
511                                 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
512                                         pri = (LOG_USER | LOG_NOTICE);
513                                 }
514                         } else if (c == '\n') {
515                                 *q++ = ' ';
516                         } else if (iscntrl(c) && (c < 0177)) {
517                                 *q++ = '^';
518                                 *q++ = c ^ 0100;
519                         } else {
520                                 *q++ = c;
521                         }
522                         p++;
523                 }
524                 *q = '\0';
525                 p++;
526                 /* Now log it */
527                 logMessage(pri, line);
528         }
529         return n_read;
530 }
531
532 static void doSyslogd(void) __attribute__ ((noreturn));
533 static void doSyslogd(void)
534 {
535         struct sockaddr_un sunx;
536         socklen_t addrLength;
537
538         int sock_fd;
539         fd_set fds;
540
541         /* Set up signal handlers. */
542         signal(SIGINT, quit_signal);
543         signal(SIGTERM, quit_signal);
544         signal(SIGQUIT, quit_signal);
545         signal(SIGHUP, SIG_IGN);
546         signal(SIGCHLD, SIG_IGN);
547 #ifdef SIGCLD
548         signal(SIGCLD, SIG_IGN);
549 #endif
550         signal(SIGALRM, domark);
551         alarm(MarkInterval);
552
553         /* Create the syslog file so realpath() can work. */
554         if (realpath(_PATH_LOG, lfile) != NULL) {
555                 unlink(lfile);
556         }
557
558         memset(&sunx, 0, sizeof(sunx));
559         sunx.sun_family = AF_UNIX;
560         strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
561         if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
562                 bb_perror_msg_and_die("Couldn't get file descriptor for socket "
563                                                    _PATH_LOG);
564         }
565
566         addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
567         if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
568                 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
569         }
570
571         if (chmod(lfile, 0666) < 0) {
572                 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
573         }
574 #ifdef CONFIG_FEATURE_IPC_SYSLOG
575         if (circular_logging == TRUE) {
576                 ipcsyslog_init();
577         }
578 #endif
579
580 #ifdef CONFIG_FEATURE_REMOTE_LOG
581         if (doRemoteLog == TRUE) {
582                 init_RemoteLog();
583         }
584 #endif
585
586         logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
587
588         for (;;) {
589
590                 FD_ZERO(&fds);
591                 FD_SET(sock_fd, &fds);
592
593                 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
594                         if (errno == EINTR) {
595                                 /* alarm may have happened. */
596                                 continue;
597                         }
598                         bb_perror_msg_and_die("select error");
599                 }
600
601                 if (FD_ISSET(sock_fd, &fds)) {
602                         int i;
603 #if MAXLINE > BUFSIZ
604 # define TMP_BUF_SZ BUFSIZ
605 #else
606 # define TMP_BUF_SZ MAXLINE
607 #endif
608 #define tmpbuf bb_common_bufsiz1
609
610                         if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) {
611                                 tmpbuf[i] = '\0';
612                                 serveConnection(tmpbuf, i);
613                         } else {
614                                 bb_perror_msg_and_die("UNIX socket error");
615                         }
616                 }                               /* FD_ISSET() */
617         }                                       /* for main loop */
618 }
619
620 extern int syslogd_main(int argc, char **argv)
621 {
622         int opt;
623
624         int doFork = TRUE;
625
626         char *p;
627
628         /* do normal option parsing */
629         while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) {
630                 switch (opt) {
631                 case 'm':
632                         MarkInterval = atoi(optarg) * 60;
633                         break;
634                 case 'n':
635                         doFork = FALSE;
636                         break;
637                 case 'O':
638                         logFilePath = optarg;
639                         break;
640 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE
641                 case 's':
642                         logFileSize = atoi(optarg) * 1024;
643                         break;
644                 case 'b':
645                         logFileRotate = atoi(optarg);
646                         if( logFileRotate > 99 ) logFileRotate = 99;
647                         break;
648 #endif
649 #ifdef CONFIG_FEATURE_REMOTE_LOG
650                 case 'R':
651                         RemoteHost = bb_xstrdup(optarg);
652                         if ((p = strchr(RemoteHost, ':'))) {
653                                 RemotePort = atoi(p + 1);
654                                 *p = '\0';
655                         }
656                         doRemoteLog = TRUE;
657                         break;
658                 case 'L':
659                         local_logging = TRUE;
660                         break;
661 #endif
662 #ifdef CONFIG_FEATURE_IPC_SYSLOG
663                 case 'C':
664                         if (optarg) {
665                                 int buf_size = atoi(optarg);
666                                 if (buf_size >= 4) {
667                                         shm_size = buf_size * 1024;
668                                 }
669                         }
670                         circular_logging = TRUE;
671                         break;
672 #endif
673                 case 'S':
674                         small = true;
675                         break;
676                 default:
677                         bb_show_usage();
678                 }
679         }
680
681 #ifdef CONFIG_FEATURE_REMOTE_LOG
682         /* If they have not specified remote logging, then log locally */
683         if (doRemoteLog == FALSE)
684                 local_logging = TRUE;
685 #endif
686
687
688         /* Store away localhost's name before the fork */
689         gethostname(LocalHostName, sizeof(LocalHostName));
690         if ((p = strchr(LocalHostName, '.'))) {
691                 *p = '\0';
692         }
693
694         umask(0);
695
696         if (doFork == TRUE) {
697 #if defined(__uClinux__)
698                 vfork_daemon_rexec(0, 1, argc, argv, "-n");
699 #else /* __uClinux__ */
700                 if(daemon(0, 1) < 0)
701                         bb_perror_msg_and_die("daemon");
702 #endif /* __uClinux__ */
703         }
704         doSyslogd();
705
706         return EXIT_SUCCESS;
707 }
708
709 /*
710 Local Variables
711 c-file-style: "linux"
712 c-basic-offset: 4
713 tab-width: 4
714 End:
715 */