blob: a7712d445618bd45b0e74eec97ba55ad299b7494 [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 Andersencb81e642003-07-14 21:21:08 +00005 * Copyright (C) 1999-2003 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 *
Eric Andersen3843e961999-11-25 07:30:46 +000013 * 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 */
Eric Andersenb99df0f1999-11-24 09:04:33 +000028
Eric Andersen67e32302000-06-19 17:48:02 +000029#include <stdio.h>
30#include <stdlib.h>
Eric Andersen3843e961999-11-25 07:30:46 +000031#include <ctype.h>
Eric Andersenb186d981999-12-03 09:19:54 +000032#include <errno.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000033#include <fcntl.h>
34#include <netdb.h>
Eric Andersenb186d981999-12-03 09:19:54 +000035#include <paths.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000036#include <signal.h>
37#include <stdarg.h>
Eric Andersen67e32302000-06-19 17:48:02 +000038#include <time.h>
Eric Andersened3ef502001-01-27 08:24:39 +000039#include <string.h>
Eric Andersen67e32302000-06-19 17:48:02 +000040#include <unistd.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000041#include <sys/socket.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000042#include <sys/types.h>
43#include <sys/un.h>
Erik Andersen7d6ba572000-04-19 20:02:50 +000044#include <sys/param.h>
Eric Andersenb186d981999-12-03 09:19:54 +000045
Eric Andersencbe31da2001-02-20 06:14:08 +000046#include "busybox.h"
Eric Andersen67e32302000-06-19 17:48:02 +000047
Eric Andersen3843e961999-11-25 07:30:46 +000048/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
49#define SYSLOG_NAMES
50#include <sys/syslog.h>
Eric Andersenced2cef2000-07-20 23:41:24 +000051#include <sys/uio.h>
Eric Andersen3843e961999-11-25 07:30:46 +000052
53/* Path for the file where all log messages are written */
Erik Andersen983b51b2000-04-04 18:14:25 +000054#define __LOG_FILE "/var/log/messages"
Eric Andersen3843e961999-11-25 07:30:46 +000055
Erik Andersen983b51b2000-04-04 18:14:25 +000056/* Path to the unix socket */
Eric Andersen871d93c2002-09-17 20:06:29 +000057static char lfile[MAXPATHLEN];
Eric Andersen3843e961999-11-25 07:30:46 +000058
Glenn L McGrathfe538ba2003-09-10 23:35:45 +000059static const char *logFilePath = __LOG_FILE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000060
Eric Andersen3843e961999-11-25 07:30:46 +000061/* interval between marks in seconds */
Erik Andersene49d5ec2000-02-08 19:58:47 +000062static int MarkInterval = 20 * 60;
63
Eric Andersen3843e961999-11-25 07:30:46 +000064/* localhost's name */
Eric Andersen871d93c2002-09-17 20:06:29 +000065static char LocalHostName[64];
Eric Andersen3843e961999-11-25 07:30:46 +000066
Eric Andersenbdfd0d72001-10-24 05:00:29 +000067#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +000068#include <netinet/in.h>
69/* udp socket for logging to remote host */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000070static int remotefd = -1;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000071
Eric Andersenced2cef2000-07-20 23:41:24 +000072/* where do we log? */
73static char *RemoteHost;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000074
Eric Andersenced2cef2000-07-20 23:41:24 +000075/* what port to log to? */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000076static int RemotePort = 514;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000077
Eric Andersenced2cef2000-07-20 23:41:24 +000078/* To remote log or not to remote log, that is the question. */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000079static int doRemoteLog = FALSE;
Eric Andersen70d09ed2000-12-11 16:24:16 +000080static int local_logging = FALSE;
Eric Andersenced2cef2000-07-20 23:41:24 +000081#endif
82
Eric Andersen871d93c2002-09-17 20:06:29 +000083
Glenn L McGrath912d8f42002-11-10 22:46:45 +000084#define MAXLINE 1024 /* maximum line length */
Eric Andersen871d93c2002-09-17 20:06:29 +000085
86
Mark Whitley6317c4b2001-03-12 22:51:50 +000087/* circular buffer variables/structures */
Eric Andersenbdfd0d72001-10-24 05:00:29 +000088#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +000089#include <sys/ipc.h>
90#include <sys/sem.h>
91#include <sys/shm.h>
92
93/* our shared key */
Glenn L McGrath912d8f42002-11-10 22:46:45 +000094static const long KEY_ID = 0x414e4547; /*"GENA" */
Mark Whitley6317c4b2001-03-12 22:51:50 +000095
96// Semaphore operation structures
97static struct shbuf_ds {
Glenn L McGrath912d8f42002-11-10 22:46:45 +000098 int size; // size of data written
99 int head; // start of message list
100 int tail; // end of message list
101 char data[1]; // data/messages
102} *buf = NULL; // shared memory pointer
Mark Whitley6317c4b2001-03-12 22:51:50 +0000103
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000104static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup
105static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn
Mark Whitley6317c4b2001-03-12 22:51:50 +0000106
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000107static int shmid = -1; // ipc shared memory id
108static int s_semid = -1; // ipc semaphore id
109int data_size = 16000; // data size
110int shm_size = 16000 + sizeof(*buf); // our buffer size
Mark Whitley6317c4b2001-03-12 22:51:50 +0000111static int circular_logging = FALSE;
112
113/*
114 * sem_up - up()'s a semaphore.
115 */
116static inline void sem_up(int semid)
117{
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000118 if (semop(semid, SMwup, 1) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000119 bb_perror_msg_and_die("semop[SMwup]");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000120 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000121}
122
123/*
124 * sem_down - down()'s a semaphore
125 */
126static inline void sem_down(int semid)
127{
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000128 if (semop(semid, SMwdn, 3) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000129 bb_perror_msg_and_die("semop[SMwdn]");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000130 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000131}
132
Eric Andersen871d93c2002-09-17 20:06:29 +0000133
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000134void ipcsyslog_cleanup(void)
135{
Mark Whitley6317c4b2001-03-12 22:51:50 +0000136 printf("Exiting Syslogd!\n");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000137 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000138 shmdt(buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000139 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000140
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000141 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000142 shmctl(shmid, IPC_RMID, NULL);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000143 }
144 if (s_semid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000145 semctl(s_semid, 0, IPC_RMID, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000146 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000147}
148
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000149void ipcsyslog_init(void)
150{
151 if (buf == NULL) {
152 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000153 bb_perror_msg_and_die("shmget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000154 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000155
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000156 if ((buf = shmat(shmid, NULL, 0)) == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000157 bb_perror_msg_and_die("shmat");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000158 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000159
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000160 buf->size = data_size;
161 buf->head = buf->tail = 0;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000162
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000163 // we'll trust the OS to set initial semval to 0 (let's hope)
164 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) {
165 if (errno == EEXIST) {
166 if ((s_semid = semget(KEY_ID, 2, 0)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000167 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000168 }
169 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000170 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000171 }
172 }
173 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000174 printf("Buffer already allocated just grab the semaphore?");
175 }
176}
177
178/* write message to buffer */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000179void circ_message(const char *msg)
180{
181 int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000182
183 sem_down(s_semid);
184
185 /*
186 * Circular Buffer Algorithm:
187 * --------------------------
188 *
189 * Start-off w/ empty buffer of specific size SHM_SIZ
190 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
191 * This is also very handy since we can do printf on message.
192 *
193 * Once the buffer is full we need to get rid of the first message in buffer and
194 * insert the new message. (Note: if the message being added is >1 message then
195 * we will need to "remove" >1 old message from the buffer). The way this is done
196 * is the following:
Eric Andersen871d93c2002-09-17 20:06:29 +0000197 * When we reach the end of the buffer we set a mark and start from the beginning.
198 * Now what about the beginning and end of the buffer? Well we have the "head"
199 * index/pointer which is the starting point for the messages and we have "tail"
200 * index/pointer which is the ending point for the messages. When we "display" the
201 * messages we start from the beginning and continue until we reach "tail". If we
202 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
203 * "tail" are actually offsets from the beginning of the buffer.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000204 *
205 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
Eric Andersen871d93c2002-09-17 20:06:29 +0000206 * a threasafe way of handling shared memory operations.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000207 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000208 if ((buf->tail + l) < buf->size) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000209 /* before we append the message we need to check the HEAD so that we won't
210 overwrite any of the message that we still need and adjust HEAD to point
211 to the next message! */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000212 if (buf->tail < buf->head) {
213 if ((buf->tail + l) >= buf->head) {
214 /* we need to move the HEAD to point to the next message
215 * Theoretically we have enough room to add the whole message to the
216 * buffer, because of the first outer IF statement, so we don't have
217 * to worry about overflows here!
218 */
219 int k = buf->tail + l - buf->head; /* we need to know how many bytes
220 we are overwriting to make
221 enough room */
222 char *c =
223 memchr(buf->data + buf->head + k, '\0',
224 buf->size - (buf->head + k));
225 if (c != NULL) { /* do a sanity check just in case! */
226 buf->head = c - buf->data + 1; /* we need to convert pointer to
227 offset + skip the '\0' since
228 we need to point to the beginning
229 of the next message */
230 /* Note: HEAD is only used to "retrieve" messages, it's not used
231 when writing messages into our buffer */
232 } else { /* show an error message to know we messed up? */
233 printf("Weird! Can't find the terminator token??? \n");
234 buf->head = 0;
235 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000236 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000237 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000238
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000239 /* in other cases no overflows have been done yet, so we don't care! */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000240 /* we should be ok to append the message now */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000241 strncpy(buf->data + buf->tail, msg, l); /* append our message */
242 buf->tail += l; /* count full message w/ '\0' terminating char */
243 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000244 /* we need to break up the message and "circle" it around */
245 char *c;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000246 int k = buf->tail + l - buf->size; /* count # of bytes we don't fit */
Eric Andersen871d93c2002-09-17 20:06:29 +0000247
Mark Whitley6317c4b2001-03-12 22:51:50 +0000248 /* We need to move HEAD! This is always the case since we are going
249 * to "circle" the message.
250 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000251 c = memchr(buf->data + k, '\0', buf->size - k);
Eric Andersen871d93c2002-09-17 20:06:29 +0000252
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000253 if (c != NULL) { /* if we don't have '\0'??? weird!!! */
254 /* move head pointer */
255 buf->head = c - buf->data + 1;
Eric Andersen871d93c2002-09-17 20:06:29 +0000256
257 /* now write the first part of the message */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000258 strncpy(buf->data + buf->tail, msg, l - k - 1);
Eric Andersen871d93c2002-09-17 20:06:29 +0000259
Mark Whitley6317c4b2001-03-12 22:51:50 +0000260 /* ALWAYS terminate end of buffer w/ '\0' */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000261 buf->data[buf->size - 1] = '\0';
Eric Andersen871d93c2002-09-17 20:06:29 +0000262
Mark Whitley6317c4b2001-03-12 22:51:50 +0000263 /* now write out the rest of the string to the beginning of the buffer */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000264 strcpy(buf->data, &msg[l - k - 1]);
Mark Whitley6317c4b2001-03-12 22:51:50 +0000265
266 /* we need to place the TAIL at the end of the message */
267 buf->tail = k + 1;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000268 } else {
269 printf
270 ("Weird! Can't find the terminator token from the beginning??? \n");
271 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000272 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000273
Mark Whitley6317c4b2001-03-12 22:51:50 +0000274 }
275 sem_up(s_semid);
276}
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000277#endif /* CONFIG_FEATURE_IPC_SYSLOG */
Eric Andersen871d93c2002-09-17 20:06:29 +0000278
Erik Andersenc053e412000-03-21 01:31:24 +0000279/* Note: There is also a function called "message()" in init.c */
Erik Andersen983b51b2000-04-04 18:14:25 +0000280/* Print a message to the log file. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000281static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
282static void message(char *fmt, ...)
Eric Andersen3843e961999-11-25 07:30:46 +0000283{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000284 int fd;
Erik Andersene3ed1562000-04-19 18:52:56 +0000285 struct flock fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000286 va_list arguments;
Eric Andersen3843e961999-11-25 07:30:46 +0000287
Erik Andersene3ed1562000-04-19 18:52:56 +0000288 fl.l_whence = SEEK_SET;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000289 fl.l_start = 0;
290 fl.l_len = 1;
Erik Andersene3ed1562000-04-19 18:52:56 +0000291
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000292#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000293 if ((circular_logging == TRUE) && (buf != NULL)) {
294 char b[1024];
Mark Whitley6317c4b2001-03-12 22:51:50 +0000295
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000296 va_start(arguments, fmt);
297 vsnprintf(b, sizeof(b) - 1, fmt, arguments);
298 va_end(arguments);
299 circ_message(b);
300
301 } else
Mark Whitley6317c4b2001-03-12 22:51:50 +0000302#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000303 if ((fd =
304 device_open(logFilePath,
305 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
306 O_NONBLOCK)) >= 0) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000307 fl.l_type = F_WRLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000308 fcntl(fd, F_SETLKW, &fl);
309 va_start(arguments, fmt);
310 vdprintf(fd, fmt, arguments);
311 va_end(arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000312 fl.l_type = F_UNLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000313 fcntl(fd, F_SETLKW, &fl);
314 close(fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000315 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000316 /* Always send console messages to /dev/console so people will see them. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000317 if ((fd =
318 device_open(_PATH_CONSOLE,
319 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
320 va_start(arguments, fmt);
321 vdprintf(fd, fmt, arguments);
322 va_end(arguments);
323 close(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000324 } else {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000325 fprintf(stderr, "Bummer, can't print: ");
326 va_start(arguments, fmt);
327 vfprintf(stderr, fmt, arguments);
328 fflush(stderr);
329 va_end(arguments);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000330 }
Eric Andersen3843e961999-11-25 07:30:46 +0000331 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000332}
333
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000334static void logMessage(int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000335{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000336 time_t now;
337 char *timestamp;
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000338 static char res[20] = "";
Erik Andersene49d5ec2000-02-08 19:58:47 +0000339 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000340
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000341 if (pri != 0) {
342 for (c_fac = facilitynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000343 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000344 for (c_pri = prioritynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000345 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
346 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000347 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000348 } else {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000349 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000350 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000351 }
Eric Andersen3843e961999-11-25 07:30:46 +0000352
Erik Andersene49d5ec2000-02-08 19:58:47 +0000353 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000354 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000355 time(&now);
356 timestamp = ctime(&now) + 4;
357 timestamp[15] = '\0';
358 } else {
359 timestamp = msg;
360 timestamp[15] = '\0';
361 msg += 16;
362 }
Eric Andersen3843e961999-11-25 07:30:46 +0000363
Erik Andersene49d5ec2000-02-08 19:58:47 +0000364 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000365
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000366#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +0000367 /* send message to remote logger */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000368 if (-1 != remotefd) {
369 static const int IOV_COUNT = 2;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000370 struct iovec iov[IOV_COUNT];
371 struct iovec *v = iov;
Eric Andersenced2cef2000-07-20 23:41:24 +0000372
Eric Andersen044228d2001-07-17 01:12:36 +0000373 memset(&res, 0, sizeof(res));
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000374 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000375 v->iov_base = res;
Eric Andersen871d93c2002-09-17 20:06:29 +0000376 v->iov_len = strlen(res);
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000377 v++;
Eric Andersenced2cef2000-07-20 23:41:24 +0000378
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000379 v->iov_base = msg;
Eric Andersen871d93c2002-09-17 20:06:29 +0000380 v->iov_len = strlen(msg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000381 writev_retry:
Glenn L McGrath877d4182003-02-09 05:07:42 +0000382 if ((-1 == writev(remotefd, iov, IOV_COUNT)) && (errno == EINTR)) {
383 goto writev_retry;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000384 }
385 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000386 if (local_logging == TRUE)
Eric Andersenced2cef2000-07-20 23:41:24 +0000387#endif
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000388 /* now spew out the message to wherever it is supposed to go */
389 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
Eric Andersen3843e961999-11-25 07:30:46 +0000390}
391
392static void quit_signal(int sig)
393{
Eric Andersen238bc402001-05-07 17:55:05 +0000394 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000395 unlink(lfile);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000396#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +0000397 ipcsyslog_cleanup();
398#endif
399
Erik Andersene49d5ec2000-02-08 19:58:47 +0000400 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000401}
402
Eric Andersen3843e961999-11-25 07:30:46 +0000403static void domark(int sig)
404{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000405 if (MarkInterval > 0) {
406 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
407 alarm(MarkInterval);
408 }
Eric Andersen3843e961999-11-25 07:30:46 +0000409}
410
Eric Andersene5272072003-07-22 22:15:21 +0000411/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
Eric Andersen22ecf042001-07-02 17:32:40 +0000412 * enabled, we otherwise get a "storage size isn't constant error. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000413static int serveConnection(char *tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000414{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000415 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000416
Matt Kraaib6ec7812001-08-14 17:32:23 +0000417 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000418
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000419 int pri = (LOG_USER | LOG_NOTICE);
Eric Andersend4f90ed2003-05-23 09:28:01 +0000420 int num_lt = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000421 char line[MAXLINE + 1];
Pavel Roskinda10ec02000-06-07 21:08:25 +0000422 unsigned char c;
Matt Kraaib6ec7812001-08-14 17:32:23 +0000423 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000424
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000425 while ((c = *p) && q < &line[sizeof(line) - 1]) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000426 if (c == '<' && num_lt == 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000427 /* Parse the magic priority number. */
Eric Andersend4f90ed2003-05-23 09:28:01 +0000428 num_lt++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000429 pri = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000430 while (isdigit(*(++p))) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000431 pri = 10 * pri + (*p - '0');
432 }
Eric Andersen46ba5682003-05-23 09:29:57 +0000433 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000434 pri = (LOG_USER | LOG_NOTICE);
Eric Andersen46ba5682003-05-23 09:29:57 +0000435 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000436 } else if (c == '\n') {
437 *q++ = ' ';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000438 } else if (iscntrl(c) && (c < 0177)) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000439 *q++ = '^';
440 *q++ = c ^ 0100;
441 } else {
442 *q++ = c;
443 }
444 p++;
445 }
446 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000447 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000448 /* Now log it */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000449 logMessage(pri, line);
Pavel Roskinda10ec02000-06-07 21:08:25 +0000450 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000451 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000452}
453
Eric Andersenced2cef2000-07-20 23:41:24 +0000454
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000455#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000456static void init_RemoteLog(void)
Eric Andersen871d93c2002-09-17 20:06:29 +0000457{
Eric Andersenced2cef2000-07-20 23:41:24 +0000458
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000459 struct sockaddr_in remoteaddr;
460 struct hostent *hostinfo;
461 int len = sizeof(remoteaddr);
Eric Andersenced2cef2000-07-20 23:41:24 +0000462
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000463 memset(&remoteaddr, 0, len);
Mark Whitleybff6b182001-03-27 20:17:58 +0000464
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000465 remotefd = socket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenced2cef2000-07-20 23:41:24 +0000466
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000467 if (remotefd < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000468 bb_error_msg_and_die("cannot create socket");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000469 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000470
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000471 hostinfo = xgethostbyname(RemoteHost);
Eric Andersenced2cef2000-07-20 23:41:24 +0000472
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000473 remoteaddr.sin_family = AF_INET;
474 remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
475 remoteaddr.sin_port = htons(RemotePort);
Eric Andersenced2cef2000-07-20 23:41:24 +0000476
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000477 /* Since we are using UDP sockets, connect just sets the default host and port
478 * for future operations
479 */
480 if (0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000481 bb_error_msg_and_die("cannot connect to remote host %s:%d", RemoteHost,
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000482 RemotePort);
483 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000484
485}
486#endif
487
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000488static void doSyslogd(void) __attribute__ ((noreturn));
489static void doSyslogd(void)
Eric Andersen3843e961999-11-25 07:30:46 +0000490{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000491 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000492 socklen_t addrLength;
493
Erik Andersen983b51b2000-04-04 18:14:25 +0000494 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000495 fd_set fds;
496
Erik Andersenf13df372000-04-18 23:51:51 +0000497 /* Set up signal handlers. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000498 signal(SIGINT, quit_signal);
499 signal(SIGTERM, quit_signal);
500 signal(SIGQUIT, quit_signal);
501 signal(SIGHUP, SIG_IGN);
502 signal(SIGCHLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000503#ifdef SIGCLD
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000504 signal(SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000505#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000506 signal(SIGALRM, domark);
507 alarm(MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000508
Erik Andersenf13df372000-04-18 23:51:51 +0000509 /* Create the syslog file so realpath() can work. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000510 if (realpath(_PATH_LOG, lfile) != NULL) {
511 unlink(lfile);
512 }
Erik Andersen983b51b2000-04-04 18:14:25 +0000513
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000514 memset(&sunx, 0, sizeof(sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000515 sunx.sun_family = AF_UNIX;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000516 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
517 if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000518 bb_perror_msg_and_die("Couldn't get file descriptor for socket "
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000519 _PATH_LOG);
520 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000521
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000522 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
523 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000524 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000525 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000526
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000527 if (chmod(lfile, 0666) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000528 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000529 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000530#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000531 if (circular_logging == TRUE) {
532 ipcsyslog_init();
Eric Andersenea906502001-04-05 20:55:17 +0000533 }
534#endif
535
Eric Andersen871d93c2002-09-17 20:06:29 +0000536#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000537 if (doRemoteLog == TRUE) {
538 init_RemoteLog();
Eric Andersen871d93c2002-09-17 20:06:29 +0000539 }
540#endif
Eric Andersenced2cef2000-07-20 23:41:24 +0000541
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000542 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000543
Erik Andersen983b51b2000-04-04 18:14:25 +0000544 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000545
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000546 FD_ZERO(&fds);
547 FD_SET(sock_fd, &fds);
Erik Andersenf13df372000-04-18 23:51:51 +0000548
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000549 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
Eric Andersen871d93c2002-09-17 20:06:29 +0000550 if (errno == EINTR) {
551 /* alarm may have happened. */
552 continue;
553 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000554 bb_perror_msg_and_die("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000555 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000556
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000557 if (FD_ISSET(sock_fd, &fds)) {
558 int i;
Erik Andersene3ed1562000-04-19 18:52:56 +0000559
Eric Andersen900c8f32003-05-16 08:35:02 +0000560 RESERVE_CONFIG_BUFFER(tmpbuf, MAXLINE + 1);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000561
Eric Andersen900c8f32003-05-16 08:35:02 +0000562 memset(tmpbuf, '\0', MAXLINE + 1);
563 if ((i = recv(sock_fd, tmpbuf, MAXLINE, 0)) > 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000564 serveConnection(tmpbuf, i);
565 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000566 bb_perror_msg_and_die("UNIX socket error");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000567 }
568 RELEASE_CONFIG_BUFFER(tmpbuf);
569 } /* FD_ISSET() */
570 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000571}
572
Eric Andersen3843e961999-11-25 07:30:46 +0000573extern int syslogd_main(int argc, char **argv)
574{
Eric Andersene5c24df2001-03-29 21:58:33 +0000575 int opt;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000576
Erik Andersene49d5ec2000-02-08 19:58:47 +0000577 int doFork = TRUE;
578
Erik Andersene49d5ec2000-02-08 19:58:47 +0000579 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000580
Eric Andersen394cf222000-12-11 16:48:50 +0000581 /* do normal option parsing */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000582 while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000583 switch (opt) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000584 case 'm':
585 MarkInterval = atoi(optarg) * 60;
586 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000587 case 'n':
588 doFork = FALSE;
589 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000590 case 'O':
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000591 logFilePath = optarg;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000592 break;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000593#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000594 case 'R':
Manuel Novoa III cad53642003-03-19 09:13:01 +0000595 RemoteHost = bb_xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000596 if ((p = strchr(RemoteHost, ':'))) {
597 RemotePort = atoi(p + 1);
598 *p = '\0';
599 }
600 doRemoteLog = TRUE;
601 break;
602 case 'L':
603 local_logging = TRUE;
604 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':
608 circular_logging = TRUE;
609 break;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000610#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000611 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000612 bb_show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000613 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000614 }
615
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000616#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersen4ed17822000-12-11 19:28:29 +0000617 /* If they have not specified remote logging, then log locally */
Eric Andersen871d93c2002-09-17 20:06:29 +0000618 if (doRemoteLog == FALSE)
Eric Andersen4ed17822000-12-11 19:28:29 +0000619 local_logging = TRUE;
620#endif
621
Mark Whitley6317c4b2001-03-12 22:51:50 +0000622
Erik Andersene49d5ec2000-02-08 19:58:47 +0000623 /* Store away localhost's name before the fork */
624 gethostname(LocalHostName, sizeof(LocalHostName));
625 if ((p = strchr(LocalHostName, '.'))) {
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000626 *p = '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000627 }
628
Erik Andersen983b51b2000-04-04 18:14:25 +0000629 umask(0);
630
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000631 if (doFork == TRUE) {
632 if(daemon(0, 1) < 0)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000633 bb_perror_msg_and_die("daemon");
Glenn L McGrathdc72f3a2003-08-29 07:35:08 +0000634#if defined(__uClinux__)
Eric Andersen35e643b2003-07-28 07:40:39 +0000635 vfork_daemon_rexec(argc, argv, "-n");
Eric Andersen871d93c2002-09-17 20:06:29 +0000636#endif
Eric Andersen35e643b2003-07-28 07:40:39 +0000637 }
Eric Andersene5c24df2001-03-29 21:58:33 +0000638 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000639
Matt Kraai3e856ce2000-12-01 02:55:13 +0000640 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000641}
Erik Andersen983b51b2000-04-04 18:14:25 +0000642
643/*
Erik Andersene3ed1562000-04-19 18:52:56 +0000644Local Variables
645c-file-style: "linux"
646c-basic-offset: 4
647tab-width: 4
648End:
649*/