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