blob: f3de04653e0c72bbd98eff74c3e11206249c4b05 [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
Denis Vlasenkobd8f43d2006-09-08 17:31:55 +0000280 fd = device_open(logFilePath, O_WRONLY | O_CREAT
281 | O_NOCTTY | O_APPEND | O_NONBLOCK);
282 if (fd >= 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;
Denis Vlasenkobd8f43d2006-09-08 17:31:55 +0000294 char oldFile[(strlen(logFilePath)+4)];
295 char newFile[(strlen(logFilePath)+4)];
Eric Andersen29c77f72003-10-09 09:43:18 +0000296 for(i=logFileRotate-1;i>0;i--) {
297 sprintf(oldFile, "%s.%d", logFilePath, i-1);
298 sprintf(newFile, "%s.%d", logFilePath, i);
299 rename(oldFile, newFile);
300 }
301 sprintf(newFile, "%s.%d", logFilePath, 0);
302 fl.l_type = F_UNLCK;
303 fcntl (fd, F_SETLKW, &fl);
304 close(fd);
305 rename(logFilePath, newFile);
306 fd = device_open (logFilePath,
307 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
308 O_NONBLOCK);
309 fl.l_type = F_WRLCK;
310 fcntl (fd, F_SETLKW, &fl);
311 } else {
312 ftruncate( fd, 0 );
313 }
314 }
315 }
Rob Landley028ba282006-08-28 20:16:42 +0000316#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000317 va_start(arguments, fmt);
318 vdprintf(fd, fmt, arguments);
319 va_end(arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000320 fl.l_type = F_UNLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000321 fcntl(fd, F_SETLKW, &fl);
322 close(fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000323 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000324 /* Always send console messages to /dev/console so people will see them. */
Denis Vlasenkobd8f43d2006-09-08 17:31:55 +0000325 fd = device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK);
326 if (fd >= 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000327 va_start(arguments, fmt);
328 vdprintf(fd, fmt, arguments);
329 va_end(arguments);
330 close(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000331 } else {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000332 fprintf(stderr, "Bummer, can't print: ");
333 va_start(arguments, fmt);
334 vfprintf(stderr, fmt, arguments);
335 fflush(stderr);
336 va_end(arguments);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000337 }
Eric Andersen3843e961999-11-25 07:30:46 +0000338 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000339}
340
Eric Andersenf91b9282004-09-08 10:56:06 +0000341#ifdef CONFIG_FEATURE_REMOTE_LOG
342static void init_RemoteLog(void)
343{
344 memset(&remoteaddr, 0, sizeof(remoteaddr));
Rob Landleyd921b2e2006-08-03 15:41:12 +0000345 remotefd = xsocket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenf91b9282004-09-08 10:56:06 +0000346 remoteaddr.sin_family = AF_INET;
347 remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list;
348 remoteaddr.sin_port = htons(RemotePort);
349}
Rob Landley028ba282006-08-28 20:16:42 +0000350#else
351void init_RemoteLog(void);
Eric Andersenf91b9282004-09-08 10:56:06 +0000352#endif
353
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000354static void logMessage(int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000355{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000356 time_t now;
357 char *timestamp;
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000358 char res[20];
Erik Andersene49d5ec2000-02-08 19:58:47 +0000359 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000360
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000361 if (pri != 0) {
362 for (c_fac = facilitynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000363 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000364 for (c_pri = prioritynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000365 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
366 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000367 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000368 } else {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000369 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000370 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000371 }
Eric Andersen3843e961999-11-25 07:30:46 +0000372
Erik Andersene49d5ec2000-02-08 19:58:47 +0000373 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000374 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000375 time(&now);
376 timestamp = ctime(&now) + 4;
377 timestamp[15] = '\0';
378 } else {
379 timestamp = msg;
380 timestamp[15] = '\0';
381 msg += 16;
382 }
Eric Andersen3843e961999-11-25 07:30:46 +0000383
Erik Andersene49d5ec2000-02-08 19:58:47 +0000384 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000385
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000386#ifdef CONFIG_FEATURE_REMOTE_LOG
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000387 if (opts & SYSLOG_OPT_remotelog) {
388 char line[MAXLINE + 1];
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000389 /* trying connect the socket */
390 if (-1 == remotefd) {
391 init_RemoteLog();
392 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000393
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000394 /* if we have a valid socket, send the message */
395 if (-1 != remotefd) {
396 now = 1;
Paul Fox27cbffd2005-07-20 18:02:11 +0000397 snprintf(line, sizeof(line), "<%d>%s", pri, msg);
Eric Andersenced2cef2000-07-20 23:41:24 +0000398
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000399retry:
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000400 /* send message to remote logger */
401 if(( -1 == sendto(remotefd, line, strlen(line), 0,
402 (struct sockaddr *) &remoteaddr,
403 sizeof(remoteaddr))) && (errno == EINTR)) {
404 /* sleep now seconds and retry (with now * 2) */
405 sleep(now);
406 now *= 2;
407 goto retry;
408 }
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000409 }
410 }
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000411
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000412 if (opts & SYSLOG_OPT_locallog)
Eric Andersenced2cef2000-07-20 23:41:24 +0000413#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000414 {
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000415 /* now spew out the message to wherever it is supposed to go */
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000416 if (opts & SYSLOG_OPT_small)
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000417 message("%s %s\n", timestamp, msg);
418 else
419 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
420 }
Eric Andersen3843e961999-11-25 07:30:46 +0000421}
422
423static void quit_signal(int sig)
424{
Eric Andersen238bc402001-05-07 17:55:05 +0000425 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000426 unlink(lfile);
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000427 if (ENABLE_FEATURE_IPC_SYSLOG)
428 ipcsyslog_cleanup();
Mark Whitley6317c4b2001-03-12 22:51:50 +0000429
Erik Andersene49d5ec2000-02-08 19:58:47 +0000430 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000431}
432
Eric Andersen3843e961999-11-25 07:30:46 +0000433static void domark(int sig)
434{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000435 if (MarkInterval > 0) {
436 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
437 alarm(MarkInterval);
438 }
Eric Andersen3843e961999-11-25 07:30:46 +0000439}
440
Eric Andersene5272072003-07-22 22:15:21 +0000441/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
Eric Andersen22ecf042001-07-02 17:32:40 +0000442 * enabled, we otherwise get a "storage size isn't constant error. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000443static int serveConnection(char *tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000444{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000445 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000446
Matt Kraaib6ec7812001-08-14 17:32:23 +0000447 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000448
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000449 int pri = (LOG_USER | LOG_NOTICE);
Eric Andersend4f90ed2003-05-23 09:28:01 +0000450 int num_lt = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000451 char line[MAXLINE + 1];
Pavel Roskinda10ec02000-06-07 21:08:25 +0000452 unsigned char c;
Matt Kraaib6ec7812001-08-14 17:32:23 +0000453 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000454
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000455 while ((c = *p) && q < &line[sizeof(line) - 1]) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000456 if (c == '<' && num_lt == 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000457 /* Parse the magic priority number. */
Eric Andersend4f90ed2003-05-23 09:28:01 +0000458 num_lt++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000459 pri = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000460 while (isdigit(*(++p))) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000461 pri = 10 * pri + (*p - '0');
462 }
Eric Andersen46ba5682003-05-23 09:29:57 +0000463 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000464 pri = (LOG_USER | LOG_NOTICE);
Eric Andersen46ba5682003-05-23 09:29:57 +0000465 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000466 } else if (c == '\n') {
467 *q++ = ' ';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000468 } else if (iscntrl(c) && (c < 0177)) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000469 *q++ = '^';
470 *q++ = c ^ 0100;
471 } else {
472 *q++ = c;
473 }
474 p++;
475 }
476 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000477 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000478 /* Now log it */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000479 logMessage(pri, line);
Pavel Roskinda10ec02000-06-07 21:08:25 +0000480 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000481 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000482}
483
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000484static void doSyslogd(void) ATTRIBUTE_NORETURN;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000485static void doSyslogd(void)
Eric Andersen3843e961999-11-25 07:30:46 +0000486{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000487 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000488 socklen_t addrLength;
489
Erik Andersen983b51b2000-04-04 18:14:25 +0000490 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000491 fd_set fds;
492
Erik Andersenf13df372000-04-18 23:51:51 +0000493 /* Set up signal handlers. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000494 signal(SIGINT, quit_signal);
495 signal(SIGTERM, quit_signal);
496 signal(SIGQUIT, quit_signal);
497 signal(SIGHUP, SIG_IGN);
498 signal(SIGCHLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000499#ifdef SIGCLD
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000500 signal(SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000501#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000502 signal(SIGALRM, domark);
503 alarm(MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000504
Erik Andersenf13df372000-04-18 23:51:51 +0000505 /* Create the syslog file so realpath() can work. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000506 if (realpath(_PATH_LOG, lfile) != NULL) {
507 unlink(lfile);
508 }
Erik Andersen983b51b2000-04-04 18:14:25 +0000509
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000510 memset(&sunx, 0, sizeof(sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000511 sunx.sun_family = AF_UNIX;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000512 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
Rob Landleyd921b2e2006-08-03 15:41:12 +0000513 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000514 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
515 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000516 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000517 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000518
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000519 if (chmod(lfile, 0666) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000520 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000521 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000522 if (ENABLE_FEATURE_IPC_SYSLOG && opts & SYSLOG_OPT_circularlog) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000523 ipcsyslog_init();
Eric Andersenea906502001-04-05 20:55:17 +0000524 }
Eric Andersenea906502001-04-05 20:55:17 +0000525
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000526 if (ENABLE_FEATURE_REMOTE_LOG && opts & SYSLOG_OPT_remotelog) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000527 init_RemoteLog();
Eric Andersen871d93c2002-09-17 20:06:29 +0000528 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000529
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000530 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " "BusyBox v" BB_VER );
Erik Andersene49d5ec2000-02-08 19:58:47 +0000531
Erik Andersen983b51b2000-04-04 18:14:25 +0000532 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000533
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000534 FD_ZERO(&fds);
535 FD_SET(sock_fd, &fds);
Erik Andersenf13df372000-04-18 23:51:51 +0000536
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000537 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
Eric Andersen871d93c2002-09-17 20:06:29 +0000538 if (errno == EINTR) {
539 /* alarm may have happened. */
540 continue;
541 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000542 bb_perror_msg_and_die("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000543 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000544
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000545 if (FD_ISSET(sock_fd, &fds)) {
546 int i;
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000547#if MAXLINE > BUFSIZ
548# define TMP_BUF_SZ BUFSIZ
549#else
550# define TMP_BUF_SZ MAXLINE
551#endif
552#define tmpbuf bb_common_bufsiz1
Erik Andersene3ed1562000-04-19 18:52:56 +0000553
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000554 if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) {
555 tmpbuf[i] = '\0';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000556 serveConnection(tmpbuf, i);
557 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000558 bb_perror_msg_and_die("UNIX socket error");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000559 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000560 } /* FD_ISSET() */
561 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000562}
563
Rob Landleydfba7412006-03-06 20:47:33 +0000564int syslogd_main(int argc, char **argv)
Eric Andersen3843e961999-11-25 07:30:46 +0000565{
Eric Andersene5c24df2001-03-29 21:58:33 +0000566 int opt;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000567
Erik Andersene49d5ec2000-02-08 19:58:47 +0000568 int doFork = TRUE;
569
Erik Andersene49d5ec2000-02-08 19:58:47 +0000570 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000571
Eric Andersen394cf222000-12-11 16:48:50 +0000572 /* do normal option parsing */
Glenn L McGrath5529b7b2004-07-22 04:23:18 +0000573 while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000574 switch (opt) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000575 case 'm':
576 MarkInterval = atoi(optarg) * 60;
577 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000578 case 'n':
579 doFork = FALSE;
580 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000581 case 'O':
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000582 logFilePath = optarg;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000583 break;
Eric Andersen29c77f72003-10-09 09:43:18 +0000584#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
585 case 's':
586 logFileSize = atoi(optarg) * 1024;
587 break;
588 case 'b':
589 logFileRotate = atoi(optarg);
590 if( logFileRotate > 99 ) logFileRotate = 99;
591 break;
592#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000593#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000594 case 'R':
Rob Landleyd921b2e2006-08-03 15:41:12 +0000595 RemoteHost = xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000596 if ((p = strchr(RemoteHost, ':'))) {
597 RemotePort = atoi(p + 1);
598 *p = '\0';
599 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000600 opts |= SYSLOG_OPT_remotelog;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000601 break;
602 case 'L':
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000603 opts |= SYSLOG_OPT_locallog;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000604 break;
Eric Andersenced2cef2000-07-20 23:41:24 +0000605#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000606#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000607 case 'C':
Glenn L McGratha79220d2003-09-26 00:49:05 +0000608 if (optarg) {
609 int buf_size = atoi(optarg);
610 if (buf_size >= 4) {
Glenn L McGrathdf2c5652004-02-22 12:17:33 +0000611 shm_size = buf_size * 1024;
Glenn L McGratha79220d2003-09-26 00:49:05 +0000612 }
613 }
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000614 opts |= SYSLOG_OPT_circularlog;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000615 break;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000616#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000617 case 'S':
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000618 opts |= SYSLOG_OPT_small;
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000619 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000620 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000621 bb_show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000622 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000623 }
624
Eric Andersen4ed17822000-12-11 19:28:29 +0000625 /* If they have not specified remote logging, then log locally */
Bernhard Reutner-Fischerd591a362006-08-20 17:35:13 +0000626 if (ENABLE_FEATURE_REMOTE_LOG && !(opts & SYSLOG_OPT_remotelog))
627 opts |= SYSLOG_OPT_locallog;
Eric Andersen4ed17822000-12-11 19:28:29 +0000628
Mark Whitley6317c4b2001-03-12 22:51:50 +0000629
Erik Andersene49d5ec2000-02-08 19:58:47 +0000630 /* Store away localhost's name before the fork */
631 gethostname(LocalHostName, sizeof(LocalHostName));
632 if ((p = strchr(LocalHostName, '.'))) {
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000633 *p = '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000634 }
635
Erik Andersen983b51b2000-04-04 18:14:25 +0000636 umask(0);
637
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000638 if (doFork == TRUE) {
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000639#ifdef BB_NOMMU
Russ Dilla1fece22003-12-15 21:57:44 +0000640 vfork_daemon_rexec(0, 1, argc, argv, "-n");
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000641#else
Rob Landleyd921b2e2006-08-03 15:41:12 +0000642 xdaemon(0, 1);
Bernhard Reutner-Fischerc418d482006-05-31 10:19:51 +0000643#endif
Eric Andersen35e643b2003-07-28 07:40:39 +0000644 }
Eric Andersene5c24df2001-03-29 21:58:33 +0000645 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000646
Matt Kraai3e856ce2000-12-01 02:55:13 +0000647 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000648}