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