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