blob: 06dfca6d84c2d918b74a33bf0635cb7c9bd9758e [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
Erik Andersene49d5ec2000-02-08 19:58:47 +000059static char *logFilePath = __LOG_FILE;
60
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
Gennady Feldman087bc822001-10-26 16:09:09 +000089#if __GNU_LIBRARY__ < 5
90#error Sorry. Looks like you are using libc5.
91#error libc5 shm support isnt good enough.
92#error Please disable CONFIG_FEATURE_IPC_SYSLOG
93#endif
94
Mark Whitley6317c4b2001-03-12 22:51:50 +000095#include <sys/ipc.h>
96#include <sys/sem.h>
97#include <sys/shm.h>
98
99/* our shared key */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000100static const long KEY_ID = 0x414e4547; /*"GENA" */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000101
102// Semaphore operation structures
103static struct shbuf_ds {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000104 int size; // size of data written
105 int head; // start of message list
106 int tail; // end of message list
107 char data[1]; // data/messages
108} *buf = NULL; // shared memory pointer
Mark Whitley6317c4b2001-03-12 22:51:50 +0000109
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000110static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup
111static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn
Mark Whitley6317c4b2001-03-12 22:51:50 +0000112
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000113static int shmid = -1; // ipc shared memory id
114static int s_semid = -1; // ipc semaphore id
115int data_size = 16000; // data size
116int shm_size = 16000 + sizeof(*buf); // our buffer size
Mark Whitley6317c4b2001-03-12 22:51:50 +0000117static int circular_logging = FALSE;
118
119/*
120 * sem_up - up()'s a semaphore.
121 */
122static inline void sem_up(int semid)
123{
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000124 if (semop(semid, SMwup, 1) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000125 bb_perror_msg_and_die("semop[SMwup]");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000126 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000127}
128
129/*
130 * sem_down - down()'s a semaphore
131 */
132static inline void sem_down(int semid)
133{
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000134 if (semop(semid, SMwdn, 3) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000135 bb_perror_msg_and_die("semop[SMwdn]");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000136 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000137}
138
Eric Andersen871d93c2002-09-17 20:06:29 +0000139
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000140void ipcsyslog_cleanup(void)
141{
Mark Whitley6317c4b2001-03-12 22:51:50 +0000142 printf("Exiting Syslogd!\n");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000143 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000144 shmdt(buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000145 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000146
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000147 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000148 shmctl(shmid, IPC_RMID, NULL);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000149 }
150 if (s_semid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000151 semctl(s_semid, 0, IPC_RMID, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000152 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000153}
154
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000155void ipcsyslog_init(void)
156{
157 if (buf == NULL) {
158 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000159 bb_perror_msg_and_die("shmget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000160 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000161
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000162 if ((buf = shmat(shmid, NULL, 0)) == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000163 bb_perror_msg_and_die("shmat");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000164 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000165
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000166 buf->size = data_size;
167 buf->head = buf->tail = 0;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000168
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000169 // we'll trust the OS to set initial semval to 0 (let's hope)
170 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) {
171 if (errno == EEXIST) {
172 if ((s_semid = semget(KEY_ID, 2, 0)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000173 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000174 }
175 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000176 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000177 }
178 }
179 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000180 printf("Buffer already allocated just grab the semaphore?");
181 }
182}
183
184/* write message to buffer */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000185void circ_message(const char *msg)
186{
187 int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000188
189 sem_down(s_semid);
190
191 /*
192 * Circular Buffer Algorithm:
193 * --------------------------
194 *
195 * Start-off w/ empty buffer of specific size SHM_SIZ
196 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
197 * This is also very handy since we can do printf on message.
198 *
199 * Once the buffer is full we need to get rid of the first message in buffer and
200 * insert the new message. (Note: if the message being added is >1 message then
201 * we will need to "remove" >1 old message from the buffer). The way this is done
202 * is the following:
Eric Andersen871d93c2002-09-17 20:06:29 +0000203 * When we reach the end of the buffer we set a mark and start from the beginning.
204 * Now what about the beginning and end of the buffer? Well we have the "head"
205 * index/pointer which is the starting point for the messages and we have "tail"
206 * index/pointer which is the ending point for the messages. When we "display" the
207 * messages we start from the beginning and continue until we reach "tail". If we
208 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
209 * "tail" are actually offsets from the beginning of the buffer.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000210 *
211 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
Eric Andersen871d93c2002-09-17 20:06:29 +0000212 * a threasafe way of handling shared memory operations.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000213 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000214 if ((buf->tail + l) < buf->size) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000215 /* before we append the message we need to check the HEAD so that we won't
216 overwrite any of the message that we still need and adjust HEAD to point
217 to the next message! */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000218 if (buf->tail < buf->head) {
219 if ((buf->tail + l) >= buf->head) {
220 /* we need to move the HEAD to point to the next message
221 * Theoretically we have enough room to add the whole message to the
222 * buffer, because of the first outer IF statement, so we don't have
223 * to worry about overflows here!
224 */
225 int k = buf->tail + l - buf->head; /* we need to know how many bytes
226 we are overwriting to make
227 enough room */
228 char *c =
229 memchr(buf->data + buf->head + k, '\0',
230 buf->size - (buf->head + k));
231 if (c != NULL) { /* do a sanity check just in case! */
232 buf->head = c - buf->data + 1; /* we need to convert pointer to
233 offset + skip the '\0' since
234 we need to point to the beginning
235 of the next message */
236 /* Note: HEAD is only used to "retrieve" messages, it's not used
237 when writing messages into our buffer */
238 } else { /* show an error message to know we messed up? */
239 printf("Weird! Can't find the terminator token??? \n");
240 buf->head = 0;
241 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000242 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000243 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000244
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000245 /* in other cases no overflows have been done yet, so we don't care! */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000246 /* we should be ok to append the message now */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000247 strncpy(buf->data + buf->tail, msg, l); /* append our message */
248 buf->tail += l; /* count full message w/ '\0' terminating char */
249 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000250 /* we need to break up the message and "circle" it around */
251 char *c;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000252 int k = buf->tail + l - buf->size; /* count # of bytes we don't fit */
Eric Andersen871d93c2002-09-17 20:06:29 +0000253
Mark Whitley6317c4b2001-03-12 22:51:50 +0000254 /* We need to move HEAD! This is always the case since we are going
255 * to "circle" the message.
256 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000257 c = memchr(buf->data + k, '\0', buf->size - k);
Eric Andersen871d93c2002-09-17 20:06:29 +0000258
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000259 if (c != NULL) { /* if we don't have '\0'??? weird!!! */
260 /* move head pointer */
261 buf->head = c - buf->data + 1;
Eric Andersen871d93c2002-09-17 20:06:29 +0000262
263 /* now write the first part of the message */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000264 strncpy(buf->data + buf->tail, msg, l - k - 1);
Eric Andersen871d93c2002-09-17 20:06:29 +0000265
Mark Whitley6317c4b2001-03-12 22:51:50 +0000266 /* ALWAYS terminate end of buffer w/ '\0' */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000267 buf->data[buf->size - 1] = '\0';
Eric Andersen871d93c2002-09-17 20:06:29 +0000268
Mark Whitley6317c4b2001-03-12 22:51:50 +0000269 /* now write out the rest of the string to the beginning of the buffer */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000270 strcpy(buf->data, &msg[l - k - 1]);
Mark Whitley6317c4b2001-03-12 22:51:50 +0000271
272 /* we need to place the TAIL at the end of the message */
273 buf->tail = k + 1;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000274 } else {
275 printf
276 ("Weird! Can't find the terminator token from the beginning??? \n");
277 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000278 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000279
Mark Whitley6317c4b2001-03-12 22:51:50 +0000280 }
281 sem_up(s_semid);
282}
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000283#endif /* CONFIG_FEATURE_IPC_SYSLOG */
Eric Andersen871d93c2002-09-17 20:06:29 +0000284
Erik Andersenc053e412000-03-21 01:31:24 +0000285/* Note: There is also a function called "message()" in init.c */
Erik Andersen983b51b2000-04-04 18:14:25 +0000286/* Print a message to the log file. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000287static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
288static void message(char *fmt, ...)
Eric Andersen3843e961999-11-25 07:30:46 +0000289{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000290 int fd;
Erik Andersene3ed1562000-04-19 18:52:56 +0000291 struct flock fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000292 va_list arguments;
Eric Andersen3843e961999-11-25 07:30:46 +0000293
Erik Andersene3ed1562000-04-19 18:52:56 +0000294 fl.l_whence = SEEK_SET;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000295 fl.l_start = 0;
296 fl.l_len = 1;
Erik Andersene3ed1562000-04-19 18:52:56 +0000297
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000298#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000299 if ((circular_logging == TRUE) && (buf != NULL)) {
300 char b[1024];
Mark Whitley6317c4b2001-03-12 22:51:50 +0000301
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000302 va_start(arguments, fmt);
303 vsnprintf(b, sizeof(b) - 1, fmt, arguments);
304 va_end(arguments);
305 circ_message(b);
306
307 } else
Mark Whitley6317c4b2001-03-12 22:51:50 +0000308#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000309 if ((fd =
310 device_open(logFilePath,
311 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
312 O_NONBLOCK)) >= 0) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000313 fl.l_type = F_WRLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000314 fcntl(fd, F_SETLKW, &fl);
315 va_start(arguments, fmt);
316 vdprintf(fd, fmt, arguments);
317 va_end(arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000318 fl.l_type = F_UNLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000319 fcntl(fd, F_SETLKW, &fl);
320 close(fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000321 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000322 /* Always send console messages to /dev/console so people will see them. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000323 if ((fd =
324 device_open(_PATH_CONSOLE,
325 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
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000340static void logMessage(int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000341{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000342 time_t now;
343 char *timestamp;
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000344 static char res[20] = "";
Erik Andersene49d5ec2000-02-08 19:58:47 +0000345 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000346
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000347 if (pri != 0) {
348 for (c_fac = facilitynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000349 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000350 for (c_pri = prioritynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000351 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
352 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000353 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000354 } else {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000355 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000356 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000357 }
Eric Andersen3843e961999-11-25 07:30:46 +0000358
Erik Andersene49d5ec2000-02-08 19:58:47 +0000359 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000360 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000361 time(&now);
362 timestamp = ctime(&now) + 4;
363 timestamp[15] = '\0';
364 } else {
365 timestamp = msg;
366 timestamp[15] = '\0';
367 msg += 16;
368 }
Eric Andersen3843e961999-11-25 07:30:46 +0000369
Erik Andersene49d5ec2000-02-08 19:58:47 +0000370 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000371
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000372#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +0000373 /* send message to remote logger */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000374 if (-1 != remotefd) {
375 static const int IOV_COUNT = 2;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000376 struct iovec iov[IOV_COUNT];
377 struct iovec *v = iov;
Eric Andersenced2cef2000-07-20 23:41:24 +0000378
Eric Andersen044228d2001-07-17 01:12:36 +0000379 memset(&res, 0, sizeof(res));
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000380 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000381 v->iov_base = res;
Eric Andersen871d93c2002-09-17 20:06:29 +0000382 v->iov_len = strlen(res);
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000383 v++;
Eric Andersenced2cef2000-07-20 23:41:24 +0000384
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000385 v->iov_base = msg;
Eric Andersen871d93c2002-09-17 20:06:29 +0000386 v->iov_len = strlen(msg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000387 writev_retry:
Glenn L McGrath877d4182003-02-09 05:07:42 +0000388 if ((-1 == writev(remotefd, iov, IOV_COUNT)) && (errno == EINTR)) {
389 goto writev_retry;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000390 }
391 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000392 if (local_logging == TRUE)
Eric Andersenced2cef2000-07-20 23:41:24 +0000393#endif
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000394 /* now spew out the message to wherever it is supposed to go */
395 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
Eric Andersen3843e961999-11-25 07:30:46 +0000396}
397
398static void quit_signal(int sig)
399{
Eric Andersen238bc402001-05-07 17:55:05 +0000400 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000401 unlink(lfile);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000402#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +0000403 ipcsyslog_cleanup();
404#endif
405
Erik Andersene49d5ec2000-02-08 19:58:47 +0000406 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000407}
408
Eric Andersen3843e961999-11-25 07:30:46 +0000409static void domark(int sig)
410{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000411 if (MarkInterval > 0) {
412 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
413 alarm(MarkInterval);
414 }
Eric Andersen3843e961999-11-25 07:30:46 +0000415}
416
Eric Andersen22ecf042001-07-02 17:32:40 +0000417/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
418 * enabled, we otherwise get a "storage size isn't constant error. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000419static int serveConnection(char *tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000420{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000421 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000422
Matt Kraaib6ec7812001-08-14 17:32:23 +0000423 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000424
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000425 int pri = (LOG_USER | LOG_NOTICE);
Eric Andersend4f90ed2003-05-23 09:28:01 +0000426 int num_lt = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000427 char line[MAXLINE + 1];
Pavel Roskinda10ec02000-06-07 21:08:25 +0000428 unsigned char c;
Matt Kraaib6ec7812001-08-14 17:32:23 +0000429 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000430
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000431 while ((c = *p) && q < &line[sizeof(line) - 1]) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000432 if (c == '<' && num_lt == 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000433 /* Parse the magic priority number. */
Eric Andersend4f90ed2003-05-23 09:28:01 +0000434 num_lt++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000435 pri = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000436 while (isdigit(*(++p))) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000437 pri = 10 * pri + (*p - '0');
438 }
Eric Andersen46ba5682003-05-23 09:29:57 +0000439 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000440 pri = (LOG_USER | LOG_NOTICE);
Eric Andersen46ba5682003-05-23 09:29:57 +0000441 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000442 } else if (c == '\n') {
443 *q++ = ' ';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000444 } else if (iscntrl(c) && (c < 0177)) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000445 *q++ = '^';
446 *q++ = c ^ 0100;
447 } else {
448 *q++ = c;
449 }
450 p++;
451 }
452 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000453 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000454 /* Now log it */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000455 logMessage(pri, line);
Pavel Roskinda10ec02000-06-07 21:08:25 +0000456 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000457 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000458}
459
Eric Andersenced2cef2000-07-20 23:41:24 +0000460
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000461#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000462static void init_RemoteLog(void)
Eric Andersen871d93c2002-09-17 20:06:29 +0000463{
Eric Andersenced2cef2000-07-20 23:41:24 +0000464
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000465 struct sockaddr_in remoteaddr;
466 struct hostent *hostinfo;
467 int len = sizeof(remoteaddr);
Eric Andersenced2cef2000-07-20 23:41:24 +0000468
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000469 memset(&remoteaddr, 0, len);
Mark Whitleybff6b182001-03-27 20:17:58 +0000470
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000471 remotefd = socket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenced2cef2000-07-20 23:41:24 +0000472
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000473 if (remotefd < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000474 bb_error_msg_and_die("cannot create socket");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000475 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000476
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000477 hostinfo = xgethostbyname(RemoteHost);
Eric Andersenced2cef2000-07-20 23:41:24 +0000478
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000479 remoteaddr.sin_family = AF_INET;
480 remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
481 remoteaddr.sin_port = htons(RemotePort);
Eric Andersenced2cef2000-07-20 23:41:24 +0000482
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000483 /* Since we are using UDP sockets, connect just sets the default host and port
484 * for future operations
485 */
486 if (0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000487 bb_error_msg_and_die("cannot connect to remote host %s:%d", RemoteHost,
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000488 RemotePort);
489 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000490
491}
492#endif
493
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000494static void doSyslogd(void) __attribute__ ((noreturn));
495static void doSyslogd(void)
Eric Andersen3843e961999-11-25 07:30:46 +0000496{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000497 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000498 socklen_t addrLength;
499
Erik Andersen983b51b2000-04-04 18:14:25 +0000500 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000501 fd_set fds;
502
Erik Andersenf13df372000-04-18 23:51:51 +0000503 /* Set up signal handlers. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000504 signal(SIGINT, quit_signal);
505 signal(SIGTERM, quit_signal);
506 signal(SIGQUIT, quit_signal);
507 signal(SIGHUP, SIG_IGN);
508 signal(SIGCHLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000509#ifdef SIGCLD
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000510 signal(SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000511#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000512 signal(SIGALRM, domark);
513 alarm(MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000514
Erik Andersenf13df372000-04-18 23:51:51 +0000515 /* Create the syslog file so realpath() can work. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000516 if (realpath(_PATH_LOG, lfile) != NULL) {
517 unlink(lfile);
518 }
Erik Andersen983b51b2000-04-04 18:14:25 +0000519
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000520 memset(&sunx, 0, sizeof(sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000521 sunx.sun_family = AF_UNIX;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000522 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
523 if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000524 bb_perror_msg_and_die("Couldn't get file descriptor for socket "
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000525 _PATH_LOG);
526 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000527
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000528 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
529 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000530 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000531 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000532
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000533 if (chmod(lfile, 0666) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000534 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000535 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000536#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000537 if (circular_logging == TRUE) {
538 ipcsyslog_init();
Eric Andersenea906502001-04-05 20:55:17 +0000539 }
540#endif
541
Eric Andersen871d93c2002-09-17 20:06:29 +0000542#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000543 if (doRemoteLog == TRUE) {
544 init_RemoteLog();
Eric Andersen871d93c2002-09-17 20:06:29 +0000545 }
546#endif
Eric Andersenced2cef2000-07-20 23:41:24 +0000547
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000548 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000549
Erik Andersen983b51b2000-04-04 18:14:25 +0000550 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000551
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000552 FD_ZERO(&fds);
553 FD_SET(sock_fd, &fds);
Erik Andersenf13df372000-04-18 23:51:51 +0000554
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000555 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
Eric Andersen871d93c2002-09-17 20:06:29 +0000556 if (errno == EINTR) {
557 /* alarm may have happened. */
558 continue;
559 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000560 bb_perror_msg_and_die("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000561 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000562
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000563 if (FD_ISSET(sock_fd, &fds)) {
564 int i;
Erik Andersene3ed1562000-04-19 18:52:56 +0000565
Eric Andersen900c8f32003-05-16 08:35:02 +0000566 RESERVE_CONFIG_BUFFER(tmpbuf, MAXLINE + 1);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000567
Eric Andersen900c8f32003-05-16 08:35:02 +0000568 memset(tmpbuf, '\0', MAXLINE + 1);
569 if ((i = recv(sock_fd, tmpbuf, MAXLINE, 0)) > 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000570 serveConnection(tmpbuf, i);
571 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000572 bb_perror_msg_and_die("UNIX socket error");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000573 }
574 RELEASE_CONFIG_BUFFER(tmpbuf);
575 } /* FD_ISSET() */
576 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000577}
578
Eric Andersen3843e961999-11-25 07:30:46 +0000579extern int syslogd_main(int argc, char **argv)
580{
Eric Andersene5c24df2001-03-29 21:58:33 +0000581 int opt;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000582
Eric Andersen871d93c2002-09-17 20:06:29 +0000583#if ! defined(__uClinux__)
Erik Andersene49d5ec2000-02-08 19:58:47 +0000584 int doFork = TRUE;
Eric Andersen871d93c2002-09-17 20:06:29 +0000585#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000586
Erik Andersene49d5ec2000-02-08 19:58:47 +0000587 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000588
Eric Andersen394cf222000-12-11 16:48:50 +0000589 /* do normal option parsing */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000590 while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000591 switch (opt) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000592 case 'm':
593 MarkInterval = atoi(optarg) * 60;
594 break;
Eric Andersen871d93c2002-09-17 20:06:29 +0000595#if ! defined(__uClinux__)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000596 case 'n':
597 doFork = FALSE;
598 break;
Eric Andersen871d93c2002-09-17 20:06:29 +0000599#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000600 case 'O':
Manuel Novoa III cad53642003-03-19 09:13:01 +0000601 logFilePath = bb_xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000602 break;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000603#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000604 case 'R':
Manuel Novoa III cad53642003-03-19 09:13:01 +0000605 RemoteHost = bb_xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000606 if ((p = strchr(RemoteHost, ':'))) {
607 RemotePort = atoi(p + 1);
608 *p = '\0';
609 }
610 doRemoteLog = TRUE;
611 break;
612 case 'L':
613 local_logging = TRUE;
614 break;
Eric Andersenced2cef2000-07-20 23:41:24 +0000615#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000616#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000617 case 'C':
618 circular_logging = TRUE;
619 break;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000620#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000621 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000622 bb_show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000623 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000624 }
625
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000626#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersen4ed17822000-12-11 19:28:29 +0000627 /* If they have not specified remote logging, then log locally */
Eric Andersen871d93c2002-09-17 20:06:29 +0000628 if (doRemoteLog == FALSE)
Eric Andersen4ed17822000-12-11 19:28:29 +0000629 local_logging = TRUE;
630#endif
631
Mark Whitley6317c4b2001-03-12 22:51:50 +0000632
Erik Andersene49d5ec2000-02-08 19:58:47 +0000633 /* Store away localhost's name before the fork */
634 gethostname(LocalHostName, sizeof(LocalHostName));
635 if ((p = strchr(LocalHostName, '.'))) {
636 *p++ = '\0';
637 }
638
Erik Andersen983b51b2000-04-04 18:14:25 +0000639 umask(0);
640
Eric Andersen871d93c2002-09-17 20:06:29 +0000641#if ! defined(__uClinux__)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000642 if ((doFork == TRUE) && (daemon(0, 1) < 0)) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000643 bb_perror_msg_and_die("daemon");
Eric Andersen3843e961999-11-25 07:30:46 +0000644 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000645#endif
Eric Andersene5c24df2001-03-29 21:58:33 +0000646 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000647
Matt Kraai3e856ce2000-12-01 02:55:13 +0000648 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000649}
Erik Andersen983b51b2000-04-04 18:14:25 +0000650
651/*
Erik Andersene3ed1562000-04-19 18:52:56 +0000652Local Variables
653c-file-style: "linux"
654c-basic-offset: 4
655tab-width: 4
656End:
657*/