aboutsummaryrefslogtreecommitdiff
path: root/syslogd.c
diff options
context:
space:
mode:
Diffstat (limited to 'syslogd.c')
-rw-r--r--syslogd.c641
1 files changed, 0 insertions, 641 deletions
diff --git a/syslogd.c b/syslogd.c
deleted file mode 100644
index 25bc68f20..000000000
--- a/syslogd.c
+++ /dev/null
@@ -1,641 +0,0 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini syslogd implementation for busybox
4 *
5 * Copyright (C) 1999,2000,2001 by Lineo, inc.
6 * Written by Erik Andersen <andersen@lineo.com>, <andersee@debian.org>
7 *
8 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
9 *
10 * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>
11 *
12 * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <ctype.h>
33#include <errno.h>
34#include <fcntl.h>
35#include <netdb.h>
36#include <paths.h>
37#include <signal.h>
38#include <stdarg.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 */
58static char lfile[BUFSIZ];
59
60static char *logFilePath = __LOG_FILE;
61
62/* interval between marks in seconds */
63static int MarkInterval = 20 * 60;
64
65/* localhost's name */
66static char LocalHostName[32];
67
68#ifdef BB_FEATURE_REMOTE_LOG
69#include <netinet/in.h>
70/* udp socket for logging to remote host */
71static int remotefd = -1;
72/* where do we log? */
73static char *RemoteHost;
74/* what port to log to? */
75static int RemotePort = 514;
76/* To remote log or not to remote log, that is the question. */
77static int doRemoteLog = FALSE;
78static int local_logging = FALSE;
79#endif
80
81/* circular buffer variables/structures */
82#ifdef BB_FEATURE_IPC_SYSLOG
83
84#include <sys/ipc.h>
85#include <sys/sem.h>
86#include <sys/shm.h>
87
88/* our shared key */
89static const long KEY_ID = 0x414e4547; /*"GENA"*/
90
91// Semaphore operation structures
92static struct shbuf_ds {
93 int size; // size of data written
94 int head; // start of message list
95 int tail; // end of message list
96 char data[1]; // data/messages
97} *buf = NULL; // shared memory pointer
98
99static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup
100static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn
101
102static int shmid = -1; // ipc shared memory id
103static int s_semid = -1; // ipc semaphore id
104int data_size = 16000; // data size
105int shm_size = 16000 + sizeof(*buf); // our buffer size
106static int circular_logging = FALSE;
107
108/*
109 * sem_up - up()'s a semaphore.
110 */
111static inline void sem_up(int semid)
112{
113 if ( semop(semid, SMwup, 1) == -1 )
114 perror_msg_and_die("semop[SMwup]");
115}
116
117/*
118 * sem_down - down()'s a semaphore
119 */
120static inline void sem_down(int semid)
121{
122 if ( semop(semid, SMwdn, 3) == -1 )
123 perror_msg_and_die("semop[SMwdn]");
124}
125
126
127void ipcsyslog_cleanup(void){
128 printf("Exiting Syslogd!\n");
129 if (shmid != -1)
130 shmdt(buf);
131
132 if (shmid != -1)
133 shmctl(shmid, IPC_RMID, NULL);
134 if (s_semid != -1)
135 semctl(s_semid, 0, IPC_RMID, 0);
136}
137
138void ipcsyslog_init(void){
139 if (buf == NULL){
140 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1)
141 perror_msg_and_die("shmget");
142
143
144 if ((buf = shmat(shmid, NULL, 0)) == NULL)
145 perror_msg_and_die("shmat");
146
147
148 buf->size=data_size;
149 buf->head=buf->tail=0;
150
151 // we'll trust the OS to set initial semval to 0 (let's hope)
152 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){
153 if (errno == EEXIST){
154 if ((s_semid = semget(KEY_ID, 2, 0)) == -1)
155 perror_msg_and_die("semget");
156 }else
157 perror_msg_and_die("semget");
158 }
159 }else{
160 printf("Buffer already allocated just grab the semaphore?");
161 }
162}
163
164/* write message to buffer */
165void circ_message(const char *msg){
166 int l=strlen(msg)+1; /* count the whole message w/ '\0' included */
167
168 sem_down(s_semid);
169
170 /*
171 * Circular Buffer Algorithm:
172 * --------------------------
173 *
174 * Start-off w/ empty buffer of specific size SHM_SIZ
175 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
176 * This is also very handy since we can do printf on message.
177 *
178 * Once the buffer is full we need to get rid of the first message in buffer and
179 * insert the new message. (Note: if the message being added is >1 message then
180 * we will need to "remove" >1 old message from the buffer). The way this is done
181 * is the following:
182 * When we reach the end of the buffer we set a mark and start from the beginning.
183 * Now what about the beginning and end of the buffer? Well we have the "head"
184 * index/pointer which is the starting point for the messages and we have "tail"
185 * index/pointer which is the ending point for the messages. When we "display" the
186 * messages we start from the beginning and continue until we reach "tail". If we
187 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
188 * "tail" are actually offsets from the beginning of the buffer.
189 *
190 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
191 * a threasafe way of handling shared memory operations.
192 */
193 if ( (buf->tail + l) < buf->size ){
194 /* before we append the message we need to check the HEAD so that we won't
195 overwrite any of the message that we still need and adjust HEAD to point
196 to the next message! */
197 if ( buf->tail < buf->head){
198 if ( (buf->tail + l) >= buf->head ){
199 /* we need to move the HEAD to point to the next message
200 * Theoretically we have enough room to add the whole message to the
201 * buffer, because of the first outer IF statement, so we don't have
202 * to worry about overflows here!
203 */
204 int k= buf->tail + l - buf->head; /* we need to know how many bytes
205 we are overwriting to make
206 enough room */
207 char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k));
208 if (c != NULL) {/* do a sanity check just in case! */
209 buf->head = c - buf->data + 1; /* we need to convert pointer to
210 offset + skip the '\0' since
211 we need to point to the beginning
212 of the next message */
213 /* Note: HEAD is only used to "retrieve" messages, it's not used
214 when writing messages into our buffer */
215 }else{ /* show an error message to know we messed up? */
216 printf("Weird! Can't find the terminator token??? \n");
217 buf->head=0;
218 }
219 }
220 } /* in other cases no overflows have been done yet, so we don't care! */
221
222 /* we should be ok to append the message now */
223 strncpy(buf->data + buf->tail,msg,l); /* append our message */
224 buf->tail+=l; /* count full message w/ '\0' terminating char */
225 }else{
226 /* we need to break up the message and "circle" it around */
227 char *c;
228 int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */
229
230 /* We need to move HEAD! This is always the case since we are going
231 * to "circle" the message.
232 */
233 c=memchr(buf->data + k ,'\0', buf->size - k);
234
235 if (c != NULL) /* if we don't have '\0'??? weird!!! */{
236 /* move head pointer*/
237 buf->head=c-buf->data+1;
238
239 /* now write the first part of the message */
240 strncpy(buf->data + buf->tail, msg, l - k - 1);
241
242 /* ALWAYS terminate end of buffer w/ '\0' */
243 buf->data[buf->size-1]='\0';
244
245 /* now write out the rest of the string to the beginning of the buffer */
246 strcpy(buf->data, &msg[l-k-1]);
247
248 /* we need to place the TAIL at the end of the message */
249 buf->tail = k + 1;
250 }else{
251 printf("Weird! Can't find the terminator token from the beginning??? \n");
252 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
253 }
254
255 }
256 sem_up(s_semid);
257}
258#endif
259/* Note: There is also a function called "message()" in init.c */
260/* Print a message to the log file. */
261static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
262static void message (char *fmt, ...)
263{
264 int fd;
265 struct flock fl;
266 va_list arguments;
267
268 fl.l_whence = SEEK_SET;
269 fl.l_start = 0;
270 fl.l_len = 1;
271
272#ifdef BB_FEATURE_IPC_SYSLOG
273 if ((circular_logging == TRUE) && (buf != NULL)){
274 char b[1024];
275 va_start (arguments, fmt);
276 vsprintf (b, fmt, arguments);
277 va_end (arguments);
278 circ_message(b);
279
280 }else
281#endif
282 if ((fd = device_open (logFilePath,
283 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
284 O_NONBLOCK)) >= 0) {
285 fl.l_type = F_WRLCK;
286 fcntl (fd, F_SETLKW, &fl);
287 va_start (arguments, fmt);
288 vdprintf (fd, fmt, arguments);
289 va_end (arguments);
290 fl.l_type = F_UNLCK;
291 fcntl (fd, F_SETLKW, &fl);
292 close (fd);
293 } else {
294 /* Always send console messages to /dev/console so people will see them. */
295 if ((fd = device_open (_PATH_CONSOLE,
296 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
297 va_start (arguments, fmt);
298 vdprintf (fd, fmt, arguments);
299 va_end (arguments);
300 close (fd);
301 } else {
302 fprintf (stderr, "Bummer, can't print: ");
303 va_start (arguments, fmt);
304 vfprintf (stderr, fmt, arguments);
305 fflush (stderr);
306 va_end (arguments);
307 }
308 }
309}
310
311static void logMessage (int pri, char *msg)
312{
313 time_t now;
314 char *timestamp;
315 static char res[20] = "";
316 CODE *c_pri, *c_fac;
317
318 if (pri != 0) {
319 for (c_fac = facilitynames;
320 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
321 for (c_pri = prioritynames;
322 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
323 if (c_fac->c_name == NULL || c_pri->c_name == NULL)
324 snprintf(res, sizeof(res), "<%d>", pri);
325 else
326 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
327 }
328
329 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
330 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
331 time(&now);
332 timestamp = ctime(&now) + 4;
333 timestamp[15] = '\0';
334 } else {
335 timestamp = msg;
336 timestamp[15] = '\0';
337 msg += 16;
338 }
339
340 /* todo: supress duplicates */
341
342#ifdef BB_FEATURE_REMOTE_LOG
343 /* send message to remote logger */
344 if ( -1 != remotefd){
345static const int IOV_COUNT = 2;
346 struct iovec iov[IOV_COUNT];
347 struct iovec *v = iov;
348
349 memset(&res, 0, sizeof(res));
350 snprintf(res, sizeof(res), "<%d>", pri);
351 v->iov_base = res ;
352 v->iov_len = strlen(res);
353 v++;
354
355 v->iov_base = msg;
356 v->iov_len = strlen(msg);
357
358 if ( -1 == writev(remotefd,iov, IOV_COUNT)){
359 error_msg_and_die("syslogd: cannot write to remote file handle on"
360 "%s:%d",RemoteHost,RemotePort);
361 }
362 }
363 if (local_logging == TRUE)
364#endif
365 /* now spew out the message to wherever it is supposed to go */
366 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
367
368
369}
370
371static void quit_signal(int sig)
372{
373 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
374 unlink(lfile);
375#ifdef BB_FEATURE_IPC_SYSLOG
376 ipcsyslog_cleanup();
377#endif
378
379 exit(TRUE);
380}
381
382static void domark(int sig)
383{
384 if (MarkInterval > 0) {
385 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
386 alarm(MarkInterval);
387 }
388}
389
390/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
391 * enabled, we otherwise get a "storage size isn't constant error. */
392#define BUFSIZE 1023
393static int serveConnection (int conn)
394{
395 RESERVE_BB_BUFFER(tmpbuf, BUFSIZE + 1);
396 int n_read;
397 char *p = tmpbuf;
398
399 n_read = read (conn, tmpbuf, BUFSIZE );
400
401 while (p < tmpbuf + n_read) {
402
403 int pri = (LOG_USER | LOG_NOTICE);
404 char line[ BUFSIZE + 1 ];
405 unsigned char c;
406
407 char *q = line;
408
409 tmpbuf[ n_read - 1 ] = '\0';
410
411 while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) {
412 if (c == '<') {
413 /* Parse the magic priority number. */
414 pri = 0;
415 while (isdigit (*(++p))) {
416 pri = 10 * pri + (*p - '0');
417 }
418 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){
419 pri = (LOG_USER | LOG_NOTICE);
420 }
421 } else if (c == '\n') {
422 *q++ = ' ';
423 } else if (iscntrl (c) && (c < 0177)) {
424 *q++ = '^';
425 *q++ = c ^ 0100;
426 } else {
427 *q++ = c;
428 }
429 p++;
430 }
431 *q = '\0';
432 p++;
433 /* Now log it */
434 logMessage (pri, line);
435 }
436 RELEASE_BB_BUFFER (tmpbuf);
437 return n_read;
438}
439
440
441#ifdef BB_FEATURE_REMOTE_LOG
442static void init_RemoteLog (void){
443
444 struct sockaddr_in remoteaddr;
445 struct hostent *hostinfo;
446 int len = sizeof(remoteaddr);
447
448 memset(&remoteaddr, 0, len);
449
450 remotefd = socket(AF_INET, SOCK_DGRAM, 0);
451
452 if (remotefd < 0) {
453 error_msg_and_die("syslogd: cannot create socket");
454 }
455
456 hostinfo = xgethostbyname(RemoteHost);
457
458 remoteaddr.sin_family = AF_INET;
459 remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
460 remoteaddr.sin_port = htons(RemotePort);
461
462 /*
463 Since we are using UDP sockets, connect just sets the default host and port
464 for future operations
465 */
466 if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){
467 error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort);
468 }
469
470}
471#endif
472
473static void doSyslogd (void) __attribute__ ((noreturn));
474static void doSyslogd (void)
475{
476 struct sockaddr_un sunx;
477 socklen_t addrLength;
478
479
480 int sock_fd;
481 fd_set fds;
482
483 /* Set up signal handlers. */
484 signal (SIGINT, quit_signal);
485 signal (SIGTERM, quit_signal);
486 signal (SIGQUIT, quit_signal);
487 signal (SIGHUP, SIG_IGN);
488 signal (SIGCHLD, SIG_IGN);
489#ifdef SIGCLD
490 signal (SIGCLD, SIG_IGN);
491#endif
492 signal (SIGALRM, domark);
493 alarm (MarkInterval);
494
495 /* Create the syslog file so realpath() can work. */
496 if (realpath (_PATH_LOG, lfile) != NULL)
497 unlink (lfile);
498
499 memset (&sunx, 0, sizeof (sunx));
500 sunx.sun_family = AF_UNIX;
501 strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path));
502 if ((sock_fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
503 perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG);
504
505 addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path);
506 if ((bind (sock_fd, (struct sockaddr *) &sunx, addrLength)) || (listen (sock_fd, 5)))
507 perror_msg_and_die ("Could not connect to socket " _PATH_LOG);
508
509 if (chmod (lfile, 0666) < 0)
510 perror_msg_and_die ("Could not set permission on " _PATH_LOG);
511
512 FD_ZERO (&fds);
513 FD_SET (sock_fd, &fds);
514
515#ifdef BB_FEATURE_IPC_SYSLOG
516 if (circular_logging == TRUE ){
517 ipcsyslog_init();
518 }
519#endif
520
521 #ifdef BB_FEATURE_REMOTE_LOG
522 if (doRemoteLog == TRUE){
523 init_RemoteLog();
524 }
525 #endif
526
527 logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
528
529 for (;;) {
530
531 fd_set readfds;
532 int n_ready;
533 int fd;
534
535 memcpy (&readfds, &fds, sizeof (fds));
536
537 if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) {
538 if (errno == EINTR) continue; /* alarm may have happened. */
539 perror_msg_and_die ("select error");
540 }
541
542 for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) {
543 if (FD_ISSET (fd, &readfds)) {
544
545 --n_ready;
546
547 if (fd == sock_fd) {
548 int conn;
549
550 //printf("New Connection request.\n");
551 if ((conn = accept (sock_fd, (struct sockaddr *) &sunx, &addrLength)) < 0) {
552 perror_msg_and_die ("accept error");
553 }
554
555 FD_SET(conn, &fds);
556 //printf("conn: %i, set_size: %i\n",conn,FD_SETSIZE);
557 } else {
558 //printf("Serving connection: %i\n",fd);
559 if ( serveConnection(fd) <= 0 ) {
560 close (fd);
561 FD_CLR(fd, &fds);
562 }
563 } /* fd == sock_fd */
564 }/* FD_ISSET() */
565 }/* for */
566 } /* for main loop */
567}
568
569extern int syslogd_main(int argc, char **argv)
570{
571 int opt;
572 int doFork = TRUE;
573
574 char *p;
575
576 /* do normal option parsing */
577 while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
578 switch (opt) {
579 case 'm':
580 MarkInterval = atoi(optarg) * 60;
581 break;
582 case 'n':
583 doFork = FALSE;
584 break;
585 case 'O':
586 logFilePath = strdup(optarg);
587 break;
588#ifdef BB_FEATURE_REMOTE_LOG
589 case 'R':
590 RemoteHost = strdup(optarg);
591 if ( (p = strchr(RemoteHost, ':'))){
592 RemotePort = atoi(p+1);
593 *p = '\0';
594 }
595 doRemoteLog = TRUE;
596 break;
597 case 'L':
598 local_logging = TRUE;
599 break;
600#endif
601#ifdef BB_FEATURE_IPC_SYSLOG
602 case 'C':
603 circular_logging = TRUE;
604 break;
605#endif
606 default:
607 show_usage();
608 }
609 }
610
611#ifdef BB_FEATURE_REMOTE_LOG
612 /* If they have not specified remote logging, then log locally */
613 if (doRemoteLog == FALSE)
614 local_logging = TRUE;
615#endif
616
617
618 /* Store away localhost's name before the fork */
619 gethostname(LocalHostName, sizeof(LocalHostName));
620 if ((p = strchr(LocalHostName, '.'))) {
621 *p++ = '\0';
622 }
623
624 umask(0);
625
626 if (doFork == TRUE) {
627 if (daemon(0, 1) < 0)
628 perror_msg_and_die("daemon");
629 }
630 doSyslogd();
631
632 return EXIT_SUCCESS;
633}
634
635/*
636Local Variables
637c-file-style: "linux"
638c-basic-offset: 4
639tab-width: 4
640End:
641*/