diff options
Diffstat (limited to 'busybox/sysklogd/syslogd.c')
-rw-r--r-- | busybox/sysklogd/syslogd.c | 712 |
1 files changed, 712 insertions, 0 deletions
diff --git a/busybox/sysklogd/syslogd.c b/busybox/sysklogd/syslogd.c new file mode 100644 index 000000000..8c6c44ee0 --- /dev/null +++ b/busybox/sysklogd/syslogd.c | |||
@@ -0,0 +1,712 @@ | |||
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 | 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 | 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 | 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)+3)], newFile[(strlen(logFilePath)+3)]; | ||
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 | |||
604 | RESERVE_CONFIG_BUFFER(tmpbuf, MAXLINE + 1); | ||
605 | |||
606 | memset(tmpbuf, '\0', MAXLINE + 1); | ||
607 | if ((i = recv(sock_fd, tmpbuf, MAXLINE, 0)) > 0) { | ||
608 | serveConnection(tmpbuf, i); | ||
609 | } else { | ||
610 | bb_perror_msg_and_die("UNIX socket error"); | ||
611 | } | ||
612 | RELEASE_CONFIG_BUFFER(tmpbuf); | ||
613 | } /* FD_ISSET() */ | ||
614 | } /* for main loop */ | ||
615 | } | ||
616 | |||
617 | extern int syslogd_main(int argc, char **argv) | ||
618 | { | ||
619 | int opt; | ||
620 | |||
621 | int doFork = TRUE; | ||
622 | |||
623 | char *p; | ||
624 | |||
625 | /* do normal option parsing */ | ||
626 | while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) { | ||
627 | switch (opt) { | ||
628 | case 'm': | ||
629 | MarkInterval = atoi(optarg) * 60; | ||
630 | break; | ||
631 | case 'n': | ||
632 | doFork = FALSE; | ||
633 | break; | ||
634 | case 'O': | ||
635 | logFilePath = optarg; | ||
636 | break; | ||
637 | #ifdef CONFIG_FEATURE_ROTATE_LOGFILE | ||
638 | case 's': | ||
639 | logFileSize = atoi(optarg) * 1024; | ||
640 | break; | ||
641 | case 'b': | ||
642 | logFileRotate = atoi(optarg); | ||
643 | if( logFileRotate > 99 ) logFileRotate = 99; | ||
644 | break; | ||
645 | #endif | ||
646 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
647 | case 'R': | ||
648 | RemoteHost = bb_xstrdup(optarg); | ||
649 | if ((p = strchr(RemoteHost, ':'))) { | ||
650 | RemotePort = atoi(p + 1); | ||
651 | *p = '\0'; | ||
652 | } | ||
653 | doRemoteLog = TRUE; | ||
654 | break; | ||
655 | case 'L': | ||
656 | local_logging = TRUE; | ||
657 | break; | ||
658 | #endif | ||
659 | #ifdef CONFIG_FEATURE_IPC_SYSLOG | ||
660 | case 'C': | ||
661 | if (optarg) { | ||
662 | int buf_size = atoi(optarg); | ||
663 | if (buf_size >= 4) { | ||
664 | shm_size = buf_size * 1024; | ||
665 | } | ||
666 | } | ||
667 | circular_logging = TRUE; | ||
668 | break; | ||
669 | #endif | ||
670 | case 'S': | ||
671 | small = true; | ||
672 | break; | ||
673 | default: | ||
674 | bb_show_usage(); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | #ifdef CONFIG_FEATURE_REMOTE_LOG | ||
679 | /* If they have not specified remote logging, then log locally */ | ||
680 | if (doRemoteLog == FALSE) | ||
681 | local_logging = TRUE; | ||
682 | #endif | ||
683 | |||
684 | |||
685 | /* Store away localhost's name before the fork */ | ||
686 | gethostname(LocalHostName, sizeof(LocalHostName)); | ||
687 | if ((p = strchr(LocalHostName, '.'))) { | ||
688 | *p = '\0'; | ||
689 | } | ||
690 | |||
691 | umask(0); | ||
692 | |||
693 | if (doFork == TRUE) { | ||
694 | #if defined(__uClinux__) | ||
695 | vfork_daemon_rexec(0, 1, argc, argv, "-n"); | ||
696 | #else /* __uClinux__ */ | ||
697 | if(daemon(0, 1) < 0) | ||
698 | bb_perror_msg_and_die("daemon"); | ||
699 | #endif /* __uClinux__ */ | ||
700 | } | ||
701 | doSyslogd(); | ||
702 | |||
703 | return EXIT_SUCCESS; | ||
704 | } | ||
705 | |||
706 | /* | ||
707 | Local Variables | ||
708 | c-file-style: "linux" | ||
709 | c-basic-offset: 4 | ||
710 | tab-width: 4 | ||
711 | End: | ||
712 | */ | ||