blob: a8b52b36ee78a4e9502531b078664f0289416472 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen3843e961999-11-25 07:30:46 +00002/*
3 * Mini syslogd implementation for busybox
4 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Eric Andersen3843e961999-11-25 07:30:46 +00006 *
Erik Andersenf13df372000-04-18 23:51:51 +00007 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
8 *
Glenn L McGrath6ed77592002-12-12 10:54:48 +00009 * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>
Mark Whitley6317c4b2001-03-12 22:51:50 +000010 *
Glenn L McGrath6ed77592002-12-12 10:54:48 +000011 * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001
Mark Whitley6bff9cc2001-03-12 23:41:34 +000012 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000013 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersen3843e961999-11-25 07:30:46 +000014 */
Eric Andersenb99df0f1999-11-24 09:04:33 +000015
Bernhard Reutner-Fischere15d7572006-06-02 20:56:16 +000016#include "busybox.h"
Eric Andersenb186d981999-12-03 09:19:54 +000017#include <paths.h>
Eric Andersen7f94a5c2004-06-22 10:12:59 +000018#include <stdbool.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000019#include <sys/un.h>
Eric Andersenb186d981999-12-03 09:19:54 +000020
Eric Andersen3843e961999-11-25 07:30:46 +000021/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
22#define SYSLOG_NAMES
23#include <sys/syslog.h>
Eric Andersenced2cef2000-07-20 23:41:24 +000024#include <sys/uio.h>
Eric Andersen3843e961999-11-25 07:30:46 +000025
26/* Path for the file where all log messages are written */
Erik Andersen983b51b2000-04-04 18:14:25 +000027#define __LOG_FILE "/var/log/messages"
Eric Andersen3843e961999-11-25 07:30:46 +000028
Erik Andersen983b51b2000-04-04 18:14:25 +000029/* Path to the unix socket */
Eric Andersen871d93c2002-09-17 20:06:29 +000030static char lfile[MAXPATHLEN];
Eric Andersen3843e961999-11-25 07:30:46 +000031
Glenn L McGrathfe538ba2003-09-10 23:35:45 +000032static const char *logFilePath = __LOG_FILE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000033
Eric Andersen29c77f72003-10-09 09:43:18 +000034#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
Eric Andersenaff114c2004-04-14 17:51:38 +000035/* max size of message file before being rotated */
Eric Andersen29c77f72003-10-09 09:43:18 +000036static int logFileSize = 200 * 1024;
37
38/* number of rotated message files */
39static int logFileRotate = 1;
40#endif
41
Eric Andersen3843e961999-11-25 07:30:46 +000042/* interval between marks in seconds */
Erik Andersene49d5ec2000-02-08 19:58:47 +000043static int MarkInterval = 20 * 60;
44
Eric Andersen3843e961999-11-25 07:30:46 +000045/* localhost's name */
Eric Andersen871d93c2002-09-17 20:06:29 +000046static char LocalHostName[64];
Eric Andersen3843e961999-11-25 07:30:46 +000047
Eric Andersenbdfd0d72001-10-24 05:00:29 +000048#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +000049#include <netinet/in.h>
50/* udp socket for logging to remote host */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000051static int remotefd = -1;
Eric Andersen75813ee2004-08-26 23:15:29 +000052static struct sockaddr_in remoteaddr;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000053
Eric Andersenced2cef2000-07-20 23:41:24 +000054/* where do we log? */
55static char *RemoteHost;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000056
Eric Andersenced2cef2000-07-20 23:41:24 +000057/* what port to log to? */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000058static int RemotePort = 514;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000059
Eric Andersenced2cef2000-07-20 23:41:24 +000060#endif
61
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +000062/* options */
63static unsigned opts;
64#define SYSLOG_OPT_small (1)
65#define SYSLOG_OPT_remotelog (2)
66#define SYSLOG_OPT_locallog (4)
67#define SYSLOG_OPT_circularlog (8)
Eric Andersen871d93c2002-09-17 20:06:29 +000068
Glenn L McGrath912d8f42002-11-10 22:46:45 +000069#define MAXLINE 1024 /* maximum line length */
Eric Andersen871d93c2002-09-17 20:06:29 +000070
71
Mark Whitley6317c4b2001-03-12 22:51:50 +000072/* circular buffer variables/structures */
Eric Andersenbdfd0d72001-10-24 05:00:29 +000073#ifdef CONFIG_FEATURE_IPC_SYSLOG
Eric Andersend4a5e252003-12-19 11:32:14 +000074
75#if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4
76#error Sorry, you must set the syslogd buffer size to at least 4KB.
77#error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE
78#endif
79
Mark Whitley6317c4b2001-03-12 22:51:50 +000080#include <sys/ipc.h>
81#include <sys/sem.h>
82#include <sys/shm.h>
83
84/* our shared key */
Glenn L McGrath912d8f42002-11-10 22:46:45 +000085static const long KEY_ID = 0x414e4547; /*"GENA" */
Mark Whitley6317c4b2001-03-12 22:51:50 +000086
87// Semaphore operation structures
88static struct shbuf_ds {
Glenn L McGrath912d8f42002-11-10 22:46:45 +000089 int size; // size of data written
90 int head; // start of message list
91 int tail; // end of message list
92 char data[1]; // data/messages
93} *buf = NULL; // shared memory pointer
Mark Whitley6317c4b2001-03-12 22:51:50 +000094
Glenn L McGrath912d8f42002-11-10 22:46:45 +000095static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup
96static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn
Mark Whitley6317c4b2001-03-12 22:51:50 +000097
Glenn L McGrath912d8f42002-11-10 22:46:45 +000098static int shmid = -1; // ipc shared memory id
99static int s_semid = -1; // ipc semaphore id
Eric Andersend4a5e252003-12-19 11:32:14 +0000100static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024); // default shm size
Eric Andersen871d93c2002-09-17 20:06:29 +0000101
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000102static void ipcsyslog_cleanup(void)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000103{
Mark Whitley6317c4b2001-03-12 22:51:50 +0000104 printf("Exiting Syslogd!\n");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000105 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000106 shmdt(buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000107 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000108
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000109 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000110 shmctl(shmid, IPC_RMID, NULL);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000111 }
112 if (s_semid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000113 semctl(s_semid, 0, IPC_RMID, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000114 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000115}
116
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000117static void ipcsyslog_init(void)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000118{
119 if (buf == NULL) {
Eric Andersend4a5e252003-12-19 11:32:14 +0000120 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000121 bb_perror_msg_and_die("shmget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000122 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000123
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000124 if ((buf = shmat(shmid, NULL, 0)) == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000125 bb_perror_msg_and_die("shmat");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000126 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000127
Eric Andersend4a5e252003-12-19 11:32:14 +0000128 buf->size = shm_size - sizeof(*buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000129 buf->head = buf->tail = 0;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000130
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000131 // we'll trust the OS to set initial semval to 0 (let's hope)
132 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) {
133 if (errno == EEXIST) {
134 if ((s_semid = semget(KEY_ID, 2, 0)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000135 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000136 }
137 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000138 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000139 }
140 }
141 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000142 printf("Buffer already allocated just grab the semaphore?");
143 }
144}
145
146/* write message to buffer */
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000147static void circ_message(const char *msg)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000148{
149 int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000150 const char * const fail_msg = "Can't find the terminator token%s?\n";
Mark Whitley6317c4b2001-03-12 22:51:50 +0000151
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000152 if (semop(s_semid, SMwdn, 3) == -1) {
153 bb_perror_msg_and_die("SMwdn");
154 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000155
156 /*
157 * Circular Buffer Algorithm:
158 * --------------------------
159 *
160 * Start-off w/ empty buffer of specific size SHM_SIZ
161 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
162 * This is also very handy since we can do printf on message.
163 *
164 * Once the buffer is full we need to get rid of the first message in buffer and
165 * insert the new message. (Note: if the message being added is >1 message then
166 * we will need to "remove" >1 old message from the buffer). The way this is done
167 * is the following:
Eric Andersen871d93c2002-09-17 20:06:29 +0000168 * When we reach the end of the buffer we set a mark and start from the beginning.
169 * Now what about the beginning and end of the buffer? Well we have the "head"
170 * index/pointer which is the starting point for the messages and we have "tail"
171 * index/pointer which is the ending point for the messages. When we "display" the
172 * messages we start from the beginning and continue until we reach "tail". If we
173 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
174 * "tail" are actually offsets from the beginning of the buffer.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000175 *
176 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
Bernhard Reutner-Fischer0c013f52006-04-18 12:46:56 +0000177 * a threadsafe way of handling shared memory operations.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000178 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000179 if ((buf->tail + l) < buf->size) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000180 /* before we append the message we need to check the HEAD so that we won't
181 overwrite any of the message that we still need and adjust HEAD to point
182 to the next message! */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000183 if (buf->tail < buf->head) {
184 if ((buf->tail + l) >= buf->head) {
185 /* we need to move the HEAD to point to the next message
186 * Theoretically we have enough room to add the whole message to the
187 * buffer, because of the first outer IF statement, so we don't have
188 * to worry about overflows here!
189 */
190 int k = buf->tail + l - buf->head; /* we need to know how many bytes
191 we are overwriting to make
192 enough room */
193 char *c =
194 memchr(buf->data + buf->head + k, '\0',
195 buf->size - (buf->head + k));
196 if (c != NULL) { /* do a sanity check just in case! */
197 buf->head = c - buf->data + 1; /* we need to convert pointer to
198 offset + skip the '\0' since
199 we need to point to the beginning
200 of the next message */
201 /* Note: HEAD is only used to "retrieve" messages, it's not used
202 when writing messages into our buffer */
203 } else { /* show an error message to know we messed up? */
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000204 printf(fail_msg,"");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000205 buf->head = 0;
206 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000207 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000208 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000209
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000210 /* in other cases no overflows have been done yet, so we don't care! */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000211 /* we should be ok to append the message now */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000212 strncpy(buf->data + buf->tail, msg, l); /* append our message */
213 buf->tail += l; /* count full message w/ '\0' terminating char */
214 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000215 /* we need to break up the message and "circle" it around */
216 char *c;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000217 int k = buf->tail + l - buf->size; /* count # of bytes we don't fit */
Eric Andersen871d93c2002-09-17 20:06:29 +0000218
Mark Whitley6317c4b2001-03-12 22:51:50 +0000219 /* We need to move HEAD! This is always the case since we are going
220 * to "circle" the message.
221 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000222 c = memchr(buf->data + k, '\0', buf->size - k);
Eric Andersen871d93c2002-09-17 20:06:29 +0000223
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000224 if (c != NULL) { /* if we don't have '\0'??? weird!!! */
225 /* move head pointer */
226 buf->head = c - buf->data + 1;
Eric Andersen871d93c2002-09-17 20:06:29 +0000227
228 /* now write the first part of the message */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000229 strncpy(buf->data + buf->tail, msg, l - k - 1);
Eric Andersen871d93c2002-09-17 20:06:29 +0000230
Mark Whitley6317c4b2001-03-12 22:51:50 +0000231 /* ALWAYS terminate end of buffer w/ '\0' */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000232 buf->data[buf->size - 1] = '\0';
Eric Andersen871d93c2002-09-17 20:06:29 +0000233
Mark Whitley6317c4b2001-03-12 22:51:50 +0000234 /* now write out the rest of the string to the beginning of the buffer */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000235 strcpy(buf->data, &msg[l - k - 1]);
Mark Whitley6317c4b2001-03-12 22:51:50 +0000236
237 /* we need to place the TAIL at the end of the message */
238 buf->tail = k + 1;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000239 } else {
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000240 printf(fail_msg, " from the beginning");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000241 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000242 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000243
Mark Whitley6317c4b2001-03-12 22:51:50 +0000244 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000245 if (semop(s_semid, SMwup, 1) == -1) {
246 bb_perror_msg_and_die("SMwup");
247 }
248
Mark Whitley6317c4b2001-03-12 22:51:50 +0000249}
Rob Landley028ba282006-08-28 20:16:42 +0000250#else
251void ipcsyslog_cleanup(void);
252void ipcsyslog_init(void);
253void circ_message(const char *msg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000254#endif /* CONFIG_FEATURE_IPC_SYSLOG */
Eric Andersen871d93c2002-09-17 20:06:29 +0000255
Erik Andersenc053e412000-03-21 01:31:24 +0000256/* Note: There is also a function called "message()" in init.c */
Erik Andersen983b51b2000-04-04 18:14:25 +0000257/* Print a message to the log file. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000258static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
259static void message(char *fmt, ...)
Eric Andersen3843e961999-11-25 07:30:46 +0000260{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000261 int fd;
Erik Andersene3ed1562000-04-19 18:52:56 +0000262 struct flock fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000263 va_list arguments;
Eric Andersen3843e961999-11-25 07:30:46 +0000264
Erik Andersene3ed1562000-04-19 18:52:56 +0000265 fl.l_whence = SEEK_SET;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000266 fl.l_start = 0;
267 fl.l_len = 1;
Erik Andersene3ed1562000-04-19 18:52:56 +0000268
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000269#ifdef CONFIG_FEATURE_IPC_SYSLOG
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000270 if ((opts & SYSLOG_OPT_circularlog) && (buf != NULL)) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000271 char b[1024];
Mark Whitley6317c4b2001-03-12 22:51:50 +0000272
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000273 va_start(arguments, fmt);
274 vsnprintf(b, sizeof(b) - 1, fmt, arguments);
275 va_end(arguments);
276 circ_message(b);
277
278 } else
Mark Whitley6317c4b2001-03-12 22:51:50 +0000279#endif
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000280 if ((fd = device_open(logFilePath,
281 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000282 O_NONBLOCK)) >= 0) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000283 fl.l_type = F_WRLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000284 fcntl(fd, F_SETLKW, &fl);
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000285
Rob Landley028ba282006-08-28 20:16:42 +0000286#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000287 if (ENABLE_FEATURE_ROTATE_LOGFILE && logFileSize > 0 ) {
Eric Andersen29c77f72003-10-09 09:43:18 +0000288 struct stat statf;
289 int r = fstat(fd, &statf);
290 if( !r && (statf.st_mode & S_IFREG)
291 && (lseek(fd,0,SEEK_END) > logFileSize) ) {
292 if(logFileRotate > 0) {
293 int i;
Eric Andersen2c6b4182005-09-12 19:16:11 +0000294 char oldFile[(strlen(logFilePath)+4)], newFile[(strlen(logFilePath)+4)];
Eric Andersen29c77f72003-10-09 09:43:18 +0000295 for(i=logFileRotate-1;i>0;i--) {
296 sprintf(oldFile, "%s.%d", logFilePath, i-1);
297 sprintf(newFile, "%s.%d", logFilePath, i);
298 rename(oldFile, newFile);
299 }
300 sprintf(newFile, "%s.%d", logFilePath, 0);
301 fl.l_type = F_UNLCK;
302 fcntl (fd, F_SETLKW, &fl);
303 close(fd);
304 rename(logFilePath, newFile);
305 fd = device_open (logFilePath,
306 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
307 O_NONBLOCK);
308 fl.l_type = F_WRLCK;
309 fcntl (fd, F_SETLKW, &fl);
310 } else {
311 ftruncate( fd, 0 );
312 }
313 }
314 }
Rob Landley028ba282006-08-28 20:16:42 +0000315#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000316 va_start(arguments, fmt);
317 vdprintf(fd, fmt, arguments);
318 va_end(arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000319 fl.l_type = F_UNLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000320 fcntl(fd, F_SETLKW, &fl);
321 close(fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000322 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000323 /* Always send console messages to /dev/console so people will see them. */
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000324 if ((fd = device_open(_PATH_CONSOLE,
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000325 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
326 va_start(arguments, fmt);
327 vdprintf(fd, fmt, arguments);
328 va_end(arguments);
329 close(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000330 } else {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000331 fprintf(stderr, "Bummer, can't print: ");
332 va_start(arguments, fmt);
333 vfprintf(stderr, fmt, arguments);
334 fflush(stderr);
335 va_end(arguments);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000336 }
Eric Andersen3843e961999-11-25 07:30:46 +0000337 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000338}
339
Eric Andersenf91b9282004-09-08 10:56:06 +0000340#ifdef CONFIG_FEATURE_REMOTE_LOG
341static void init_RemoteLog(void)
342{
343 memset(&remoteaddr, 0, sizeof(remoteaddr));
Rob Landleyd921b2e2006-08-03 15:41:12 +0000344 remotefd = xsocket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenf91b9282004-09-08 10:56:06 +0000345 remoteaddr.sin_family = AF_INET;
346 remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list;
347 remoteaddr.sin_port = htons(RemotePort);
348}
Rob Landley028ba282006-08-28 20:16:42 +0000349#else
350void init_RemoteLog(void);
Eric Andersenf91b9282004-09-08 10:56:06 +0000351#endif
352
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000353static void logMessage(int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000354{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000355 time_t now;
356 char *timestamp;
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000357 char res[20];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000358 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000359
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000360 if (pri != 0) {
361 for (c_fac = facilitynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000362 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000363 for (c_pri = prioritynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000364 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
365 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000366 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000367 } else {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000368 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000369 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000370 }
Eric Andersen3843e961999-11-25 07:30:46 +0000371
Erik Andersene49d5ec2000-02-08 19:58:47 +0000372 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000373 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000374 time(&now);
375 timestamp = ctime(&now) + 4;
376 timestamp[15] = '\0';
377 } else {
378 timestamp = msg;
379 timestamp[15] = '\0';
380 msg += 16;
381 }
Eric Andersen3843e961999-11-25 07:30:46 +0000382
Erik Andersene49d5ec2000-02-08 19:58:47 +0000383 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000384
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000385#ifdef CONFIG_FEATURE_REMOTE_LOG
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000386 if (opts & SYSLOG_OPT_remotelog) {
387 char line[MAXLINE + 1];
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000388 /* trying connect the socket */
389 if (-1 == remotefd) {
390 init_RemoteLog();
391 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000392
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000393 /* if we have a valid socket, send the message */
394 if (-1 != remotefd) {
395 now = 1;
Paul Fox27cbffd2005-07-20 18:02:11 +0000396 snprintf(line, sizeof(line), "<%d>%s", pri, msg);
Eric Andersenced2cef2000-07-20 23:41:24 +0000397
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000398retry:
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000399 /* send message to remote logger */
400 if(( -1 == sendto(remotefd, line, strlen(line), 0,
401 (struct sockaddr *) &remoteaddr,
402 sizeof(remoteaddr))) && (errno == EINTR)) {
403 /* sleep now seconds and retry (with now * 2) */
404 sleep(now);
405 now *= 2;
406 goto retry;
407 }
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000408 }
409 }
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000410
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000411 if (opts & SYSLOG_OPT_locallog)
Eric Andersenced2cef2000-07-20 23:41:24 +0000412#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000413 {
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000414 /* now spew out the message to wherever it is supposed to go */
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000415 if (opts & SYSLOG_OPT_small)
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000416 message("%s %s\n", timestamp, msg);
417 else
418 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
419 }
Eric Andersen3843e961999-11-25 07:30:46 +0000420}
421
422static void quit_signal(int sig)
423{
Eric Andersen238bc402001-05-07 17:55:05 +0000424 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000425 unlink(lfile);
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000426 if (ENABLE_FEATURE_IPC_SYSLOG)
427 ipcsyslog_cleanup();
Mark Whitley6317c4b2001-03-12 22:51:50 +0000428
Erik Andersene49d5ec2000-02-08 19:58:47 +0000429 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000430}
431
Eric Andersen3843e961999-11-25 07:30:46 +0000432static void domark(int sig)
433{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000434 if (MarkInterval > 0) {
435 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
436 alarm(MarkInterval);
437 }
Eric Andersen3843e961999-11-25 07:30:46 +0000438}
439
Eric Andersene5272072003-07-22 22:15:21 +0000440/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
Eric Andersen22ecf042001-07-02 17:32:40 +0000441 * enabled, we otherwise get a "storage size isn't constant error. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000442static int serveConnection(char *tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000443{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000444 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000445
Matt Kraaib6ec7812001-08-14 17:32:23 +0000446 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000447
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000448 int pri = (LOG_USER | LOG_NOTICE);
Eric Andersend4f90ed2003-05-23 09:28:01 +0000449 int num_lt = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000450 char line[MAXLINE + 1];
Pavel Roskinda10ec02000-06-07 21:08:25 +0000451 unsigned char c;
Matt Kraaib6ec7812001-08-14 17:32:23 +0000452 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000453
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000454 while ((c = *p) && q < &line[sizeof(line) - 1]) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000455 if (c == '<' && num_lt == 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000456 /* Parse the magic priority number. */
Eric Andersend4f90ed2003-05-23 09:28:01 +0000457 num_lt++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000458 pri = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000459 while (isdigit(*(++p))) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000460 pri = 10 * pri + (*p - '0');
461 }
Eric Andersen46ba5682003-05-23 09:29:57 +0000462 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000463 pri = (LOG_USER | LOG_NOTICE);
Eric Andersen46ba5682003-05-23 09:29:57 +0000464 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000465 } else if (c == '\n') {
466 *q++ = ' ';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000467 } else if (iscntrl(c) && (c < 0177)) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000468 *q++ = '^';
469 *q++ = c ^ 0100;
470 } else {
471 *q++ = c;
472 }
473 p++;
474 }
475 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000476 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000477 /* Now log it */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000478 logMessage(pri, line);
Pavel Roskinda10ec02000-06-07 21:08:25 +0000479 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000480 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000481}
482
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000483static void doSyslogd(void) ATTRIBUTE_NORETURN;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000484static void doSyslogd(void)
Eric Andersen3843e961999-11-25 07:30:46 +0000485{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000486 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000487 socklen_t addrLength;
488
Erik Andersen983b51b2000-04-04 18:14:25 +0000489 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000490 fd_set fds;
491
Erik Andersenf13df372000-04-18 23:51:51 +0000492 /* Set up signal handlers. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000493 signal(SIGINT, quit_signal);
494 signal(SIGTERM, quit_signal);
495 signal(SIGQUIT, quit_signal);
496 signal(SIGHUP, SIG_IGN);
497 signal(SIGCHLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000498#ifdef SIGCLD
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000499 signal(SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000500#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000501 signal(SIGALRM, domark);
502 alarm(MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000503
Erik Andersenf13df372000-04-18 23:51:51 +0000504 /* Create the syslog file so realpath() can work. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000505 if (realpath(_PATH_LOG, lfile) != NULL) {
506 unlink(lfile);
507 }
Erik Andersen983b51b2000-04-04 18:14:25 +0000508
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000509 memset(&sunx, 0, sizeof(sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000510 sunx.sun_family = AF_UNIX;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000511 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
Rob Landleyd921b2e2006-08-03 15:41:12 +0000512 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000513 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
514 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000515 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000516 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000517
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000518 if (chmod(lfile, 0666) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000519 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000520 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000521 if (ENABLE_FEATURE_IPC_SYSLOG && opts & SYSLOG_OPT_circularlog) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000522 ipcsyslog_init();
Eric Andersenea906502001-04-05 20:55:17 +0000523 }
Eric Andersenea906502001-04-05 20:55:17 +0000524
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000525 if (ENABLE_FEATURE_REMOTE_LOG && opts & SYSLOG_OPT_remotelog) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000526 init_RemoteLog();
Eric Andersen871d93c2002-09-17 20:06:29 +0000527 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000528
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000529 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " "BusyBox v" BB_VER );
Erik Andersene49d5ec2000-02-08 19:58:47 +0000530
Erik Andersen983b51b2000-04-04 18:14:25 +0000531 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000532
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000533 FD_ZERO(&fds);
534 FD_SET(sock_fd, &fds);
Erik Andersenf13df372000-04-18 23:51:51 +0000535
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000536 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
Eric Andersen871d93c2002-09-17 20:06:29 +0000537 if (errno == EINTR) {
538 /* alarm may have happened. */
539 continue;
540 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000541 bb_perror_msg_and_die("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000542 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000543
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000544 if (FD_ISSET(sock_fd, &fds)) {
545 int i;
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000546#if MAXLINE > BUFSIZ
547# define TMP_BUF_SZ BUFSIZ
548#else
549# define TMP_BUF_SZ MAXLINE
550#endif
551#define tmpbuf bb_common_bufsiz1
Erik Andersene3ed1562000-04-19 18:52:56 +0000552
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000553 if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) {
554 tmpbuf[i] = '\0';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000555 serveConnection(tmpbuf, i);
556 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000557 bb_perror_msg_and_die("UNIX socket error");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000558 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000559 } /* FD_ISSET() */
560 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000561}
562
Rob Landleydfba7412006-03-06 20:47:33 +0000563int syslogd_main(int argc, char **argv)
Eric Andersen3843e961999-11-25 07:30:46 +0000564{
Eric Andersene5c24df2001-03-29 21:58:33 +0000565 int opt;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000566
Erik Andersene49d5ec2000-02-08 19:58:47 +0000567 int doFork = TRUE;
568
Erik Andersene49d5ec2000-02-08 19:58:47 +0000569 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000570
Eric Andersen394cf222000-12-11 16:48:50 +0000571 /* do normal option parsing */
Glenn L McGrath5529b7b2004-07-22 04:23:18 +0000572 while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000573 switch (opt) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000574 case 'm':
575 MarkInterval = atoi(optarg) * 60;
576 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000577 case 'n':
578 doFork = FALSE;
579 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000580 case 'O':
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000581 logFilePath = optarg;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000582 break;
Eric Andersen29c77f72003-10-09 09:43:18 +0000583#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
584 case 's':
585 logFileSize = atoi(optarg) * 1024;
586 break;
587 case 'b':
588 logFileRotate = atoi(optarg);
589 if( logFileRotate > 99 ) logFileRotate = 99;
590 break;
591#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000592#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000593 case 'R':
Rob Landleyd921b2e2006-08-03 15:41:12 +0000594 RemoteHost = xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000595 if ((p = strchr(RemoteHost, ':'))) {
596 RemotePort = atoi(p + 1);
597 *p = '\0';
598 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000599 opts |= SYSLOG_OPT_remotelog;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000600 break;
601 case 'L':
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000602 opts |= SYSLOG_OPT_locallog;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000603 break;
Eric Andersenced2cef2000-07-20 23:41:24 +0000604#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000605#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000606 case 'C':
Glenn L McGratha79220d2003-09-26 00:49:05 +0000607 if (optarg) {
608 int buf_size = atoi(optarg);
609 if (buf_size >= 4) {
Glenn L McGrathdf2c5652004-02-22 12:17:33 +0000610 shm_size = buf_size * 1024;
Glenn L McGratha79220d2003-09-26 00:49:05 +0000611 }
612 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000613 opts |= SYSLOG_OPT_circularlog;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000614 break;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000615#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000616 case 'S':
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000617 opts |= SYSLOG_OPT_small;
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000618 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000619 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000620 bb_show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000621 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000622 }
623
Eric Andersen4ed17822000-12-11 19:28:29 +0000624 /* If they have not specified remote logging, then log locally */
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000625 if (ENABLE_FEATURE_REMOTE_LOG && !(opts & SYSLOG_OPT_remotelog))
626 opts |= SYSLOG_OPT_locallog;
Eric Andersen4ed17822000-12-11 19:28:29 +0000627
Mark Whitley6317c4b2001-03-12 22:51:50 +0000628
Erik Andersene49d5ec2000-02-08 19:58:47 +0000629 /* Store away localhost's name before the fork */
630 gethostname(LocalHostName, sizeof(LocalHostName));
631 if ((p = strchr(LocalHostName, '.'))) {
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000632 *p = '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000633 }
634
Erik Andersen983b51b2000-04-04 18:14:25 +0000635 umask(0);
636
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000637 if (doFork == TRUE) {
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000638#ifdef BB_NOMMU
Russ Dilla1fece22003-12-15 21:57:44 +0000639 vfork_daemon_rexec(0, 1, argc, argv, "-n");
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000640#else
Rob Landleyd921b2e2006-08-03 15:41:12 +0000641 xdaemon(0, 1);
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000642#endif
Eric Andersen35e643b2003-07-28 07:40:39 +0000643 }
Eric Andersene5c24df2001-03-29 21:58:33 +0000644 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000645
Matt Kraai3e856ce2000-12-01 02:55:13 +0000646 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000647}