blob: f0a7f1a843821e47be76148ee4f623edddb65c72 [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 Andersenbdfd0d72001-10-24 05:00:29 +00005 * Copyright (C) 1999,2000 by Lineo, inc. and Erik Andersen
6 * Copyright (C) 1999,2000,2001 by Erik Andersen <andersee@debian.org>
Eric Andersen3843e961999-11-25 07:30:46 +00007 *
Erik Andersenf13df372000-04-18 23:51:51 +00008 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
9 *
Mark Whitley6317c4b2001-03-12 22:51:50 +000010 * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@cachier.com>
11 *
Mark Whitley6bff9cc2001-03-12 23:41:34 +000012 * Maintainer: Gennady Feldman <gena01@cachier.com> as of Mar 12, 2001
13 *
Eric Andersen3843e961999-11-25 07:30:46 +000014 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28 */
Eric Andersenb99df0f1999-11-24 09:04:33 +000029
Eric Andersen67e32302000-06-19 17:48:02 +000030#include <stdio.h>
31#include <stdlib.h>
Eric Andersen3843e961999-11-25 07:30:46 +000032#include <ctype.h>
Eric Andersenb186d981999-12-03 09:19:54 +000033#include <errno.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000034#include <fcntl.h>
35#include <netdb.h>
Eric Andersenb186d981999-12-03 09:19:54 +000036#include <paths.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000037#include <signal.h>
38#include <stdarg.h>
Eric Andersen67e32302000-06-19 17:48:02 +000039#include <time.h>
Eric Andersened3ef502001-01-27 08:24:39 +000040#include <string.h>
Eric Andersen67e32302000-06-19 17:48:02 +000041#include <unistd.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000042#include <sys/socket.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000043#include <sys/types.h>
44#include <sys/un.h>
Erik Andersen7d6ba572000-04-19 20:02:50 +000045#include <sys/param.h>
Eric Andersenb186d981999-12-03 09:19:54 +000046
Eric Andersencbe31da2001-02-20 06:14:08 +000047#include "busybox.h"
Eric Andersen67e32302000-06-19 17:48:02 +000048
Eric Andersen3843e961999-11-25 07:30:46 +000049/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
50#define SYSLOG_NAMES
51#include <sys/syslog.h>
Eric Andersenced2cef2000-07-20 23:41:24 +000052#include <sys/uio.h>
Eric Andersen3843e961999-11-25 07:30:46 +000053
54/* Path for the file where all log messages are written */
Erik Andersen983b51b2000-04-04 18:14:25 +000055#define __LOG_FILE "/var/log/messages"
Eric Andersen3843e961999-11-25 07:30:46 +000056
Erik Andersen983b51b2000-04-04 18:14:25 +000057/* Path to the unix socket */
Matt Kraaic3088472001-07-06 19:28:07 +000058static char lfile[BUFSIZ];
Eric Andersen3843e961999-11-25 07:30:46 +000059
Erik Andersene49d5ec2000-02-08 19:58:47 +000060static char *logFilePath = __LOG_FILE;
61
Eric Andersen3843e961999-11-25 07:30:46 +000062/* interval between marks in seconds */
Erik Andersene49d5ec2000-02-08 19:58:47 +000063static int MarkInterval = 20 * 60;
64
Eric Andersen3843e961999-11-25 07:30:46 +000065/* localhost's name */
66static char LocalHostName[32];
67
Eric Andersenbdfd0d72001-10-24 05:00:29 +000068#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +000069#include <netinet/in.h>
70/* udp socket for logging to remote host */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000071static int remotefd = -1;
Eric Andersenced2cef2000-07-20 23:41:24 +000072/* where do we log? */
73static char *RemoteHost;
74/* what port to log to? */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000075static int RemotePort = 514;
Eric Andersenced2cef2000-07-20 23:41:24 +000076/* To remote log or not to remote log, that is the question. */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000077static int doRemoteLog = FALSE;
Eric Andersen70d09ed2000-12-11 16:24:16 +000078static int local_logging = FALSE;
Eric Andersenced2cef2000-07-20 23:41:24 +000079#endif
80
Mark Whitley6317c4b2001-03-12 22:51:50 +000081/* circular buffer variables/structures */
Eric Andersenbdfd0d72001-10-24 05:00:29 +000082#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +000083
Gennady Feldman087bc822001-10-26 16:09:09 +000084#if __GNU_LIBRARY__ < 5
85#error Sorry. Looks like you are using libc5.
86#error libc5 shm support isnt good enough.
87#error Please disable CONFIG_FEATURE_IPC_SYSLOG
88#endif
89
Mark Whitley6317c4b2001-03-12 22:51:50 +000090#include <sys/ipc.h>
91#include <sys/sem.h>
92#include <sys/shm.h>
93
94/* our shared key */
95static const long KEY_ID = 0x414e4547; /*"GENA"*/
96
97// Semaphore operation structures
98static struct shbuf_ds {
99 int size; // size of data written
100 int head; // start of message list
101 int tail; // end of message list
102 char data[1]; // data/messages
103} *buf = NULL; // shared memory pointer
104
105static struct sembuf SMwup[1] = {{1, -1, IPC_NOWAIT}}; // set SMwup
106static struct sembuf SMwdn[3] = {{0, 0}, {1, 0}, {1, +1}}; // set SMwdn
107
108static int shmid = -1; // ipc shared memory id
109static int s_semid = -1; // ipc semaphore id
110int data_size = 16000; // data size
111int shm_size = 16000 + sizeof(*buf); // our buffer size
112static int circular_logging = FALSE;
113
114/*
115 * sem_up - up()'s a semaphore.
116 */
117static inline void sem_up(int semid)
118{
119 if ( semop(semid, SMwup, 1) == -1 )
120 perror_msg_and_die("semop[SMwup]");
121}
122
123/*
124 * sem_down - down()'s a semaphore
125 */
126static inline void sem_down(int semid)
127{
Eric Andersenea906502001-04-05 20:55:17 +0000128 if ( semop(semid, SMwdn, 3) == -1 )
Mark Whitley6317c4b2001-03-12 22:51:50 +0000129 perror_msg_and_die("semop[SMwdn]");
130}
131
Mark Whitley6317c4b2001-03-12 22:51:50 +0000132void ipcsyslog_cleanup(void){
133 printf("Exiting Syslogd!\n");
134 if (shmid != -1)
135 shmdt(buf);
136
137 if (shmid != -1)
138 shmctl(shmid, IPC_RMID, NULL);
139 if (s_semid != -1)
140 semctl(s_semid, 0, IPC_RMID, 0);
141}
142
143void ipcsyslog_init(void){
144 if (buf == NULL){
145 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1)
146 perror_msg_and_die("shmget");
147
148
149 if ((buf = shmat(shmid, NULL, 0)) == NULL)
150 perror_msg_and_die("shmat");
151
152
153 buf->size=data_size;
154 buf->head=buf->tail=0;
155
156 // we'll trust the OS to set initial semval to 0 (let's hope)
157 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1){
158 if (errno == EEXIST){
159 if ((s_semid = semget(KEY_ID, 2, 0)) == -1)
160 perror_msg_and_die("semget");
161 }else
162 perror_msg_and_die("semget");
163 }
164 }else{
165 printf("Buffer already allocated just grab the semaphore?");
166 }
167}
168
169/* write message to buffer */
170void circ_message(const char *msg){
171 int l=strlen(msg)+1; /* count the whole message w/ '\0' included */
172
173 sem_down(s_semid);
174
175 /*
176 * Circular Buffer Algorithm:
177 * --------------------------
178 *
179 * Start-off w/ empty buffer of specific size SHM_SIZ
180 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
181 * This is also very handy since we can do printf on message.
182 *
183 * Once the buffer is full we need to get rid of the first message in buffer and
184 * insert the new message. (Note: if the message being added is >1 message then
185 * we will need to "remove" >1 old message from the buffer). The way this is done
186 * is the following:
187 * When we reach the end of the buffer we set a mark and start from the beginning.
188 * Now what about the beginning and end of the buffer? Well we have the "head"
189 * index/pointer which is the starting point for the messages and we have "tail"
190 * index/pointer which is the ending point for the messages. When we "display" the
191 * messages we start from the beginning and continue until we reach "tail". If we
192 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
193 * "tail" are actually offsets from the beginning of the buffer.
194 *
195 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
196 * a threasafe way of handling shared memory operations.
197 */
198 if ( (buf->tail + l) < buf->size ){
199 /* before we append the message we need to check the HEAD so that we won't
200 overwrite any of the message that we still need and adjust HEAD to point
201 to the next message! */
202 if ( buf->tail < buf->head){
203 if ( (buf->tail + l) >= buf->head ){
204 /* we need to move the HEAD to point to the next message
205 * Theoretically we have enough room to add the whole message to the
206 * buffer, because of the first outer IF statement, so we don't have
207 * to worry about overflows here!
208 */
209 int k= buf->tail + l - buf->head; /* we need to know how many bytes
210 we are overwriting to make
211 enough room */
212 char *c=memchr(buf->data+buf->head + k,'\0',buf->size - (buf->head + k));
213 if (c != NULL) {/* do a sanity check just in case! */
214 buf->head = c - buf->data + 1; /* we need to convert pointer to
215 offset + skip the '\0' since
216 we need to point to the beginning
217 of the next message */
218 /* Note: HEAD is only used to "retrieve" messages, it's not used
219 when writing messages into our buffer */
220 }else{ /* show an error message to know we messed up? */
221 printf("Weird! Can't find the terminator token??? \n");
222 buf->head=0;
223 }
224 }
225 } /* in other cases no overflows have been done yet, so we don't care! */
226
227 /* we should be ok to append the message now */
228 strncpy(buf->data + buf->tail,msg,l); /* append our message */
229 buf->tail+=l; /* count full message w/ '\0' terminating char */
230 }else{
231 /* we need to break up the message and "circle" it around */
232 char *c;
233 int k=buf->tail + l - buf->size; /* count # of bytes we don't fit */
234
235 /* We need to move HEAD! This is always the case since we are going
236 * to "circle" the message.
237 */
238 c=memchr(buf->data + k ,'\0', buf->size - k);
239
240 if (c != NULL) /* if we don't have '\0'??? weird!!! */{
241 /* move head pointer*/
242 buf->head=c-buf->data+1;
243
244 /* now write the first part of the message */
245 strncpy(buf->data + buf->tail, msg, l - k - 1);
246
247 /* ALWAYS terminate end of buffer w/ '\0' */
248 buf->data[buf->size-1]='\0';
249
250 /* now write out the rest of the string to the beginning of the buffer */
251 strcpy(buf->data, &msg[l-k-1]);
252
253 /* we need to place the TAIL at the end of the message */
254 buf->tail = k + 1;
255 }else{
256 printf("Weird! Can't find the terminator token from the beginning??? \n");
257 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
258 }
259
260 }
261 sem_up(s_semid);
262}
263#endif
Erik Andersenc053e412000-03-21 01:31:24 +0000264/* Note: There is also a function called "message()" in init.c */
Erik Andersen983b51b2000-04-04 18:14:25 +0000265/* Print a message to the log file. */
Erik Andersenf13df372000-04-18 23:51:51 +0000266static void message (char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
267static void message (char *fmt, ...)
Eric Andersen3843e961999-11-25 07:30:46 +0000268{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000269 int fd;
Erik Andersene3ed1562000-04-19 18:52:56 +0000270 struct flock fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000271 va_list arguments;
Eric Andersen3843e961999-11-25 07:30:46 +0000272
Erik Andersene3ed1562000-04-19 18:52:56 +0000273 fl.l_whence = SEEK_SET;
274 fl.l_start = 0;
275 fl.l_len = 1;
276
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000277#ifdef CONFIG_FEATURE_IPC_SYSLOG
Matt Kraai1f0c4362001-12-20 23:13:26 +0000278 if ((circular_logging) && (buf != NULL)){
Mark Whitley6317c4b2001-03-12 22:51:50 +0000279 char b[1024];
280 va_start (arguments, fmt);
281 vsprintf (b, fmt, arguments);
282 va_end (arguments);
283 circ_message(b);
284
285 }else
286#endif
Erik Andersenf13df372000-04-18 23:51:51 +0000287 if ((fd = device_open (logFilePath,
288 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
289 O_NONBLOCK)) >= 0) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000290 fl.l_type = F_WRLCK;
291 fcntl (fd, F_SETLKW, &fl);
Erik Andersenf13df372000-04-18 23:51:51 +0000292 va_start (arguments, fmt);
293 vdprintf (fd, fmt, arguments);
294 va_end (arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000295 fl.l_type = F_UNLCK;
296 fcntl (fd, F_SETLKW, &fl);
Erik Andersenf13df372000-04-18 23:51:51 +0000297 close (fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000298 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000299 /* Always send console messages to /dev/console so people will see them. */
Erik Andersenf13df372000-04-18 23:51:51 +0000300 if ((fd = device_open (_PATH_CONSOLE,
301 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
302 va_start (arguments, fmt);
303 vdprintf (fd, fmt, arguments);
304 va_end (arguments);
305 close (fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000306 } else {
Erik Andersenf13df372000-04-18 23:51:51 +0000307 fprintf (stderr, "Bummer, can't print: ");
308 va_start (arguments, fmt);
309 vfprintf (stderr, fmt, arguments);
310 fflush (stderr);
311 va_end (arguments);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000312 }
Eric Andersen3843e961999-11-25 07:30:46 +0000313 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000314}
315
Erik Andersenf13df372000-04-18 23:51:51 +0000316static void logMessage (int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000317{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000318 time_t now;
319 char *timestamp;
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000320 static char res[20] = "";
Erik Andersene49d5ec2000-02-08 19:58:47 +0000321 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000322
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000323 if (pri != 0) {
324 for (c_fac = facilitynames;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000325 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000326 for (c_pri = prioritynames;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000327 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
Matt Kraai5a964f92000-12-11 20:13:37 +0000328 if (c_fac->c_name == NULL || c_pri->c_name == NULL)
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000329 snprintf(res, sizeof(res), "<%d>", pri);
330 else
331 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
332 }
Eric Andersen3843e961999-11-25 07:30:46 +0000333
Erik Andersene49d5ec2000-02-08 19:58:47 +0000334 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000335 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000336 time(&now);
337 timestamp = ctime(&now) + 4;
338 timestamp[15] = '\0';
339 } else {
340 timestamp = msg;
341 timestamp[15] = '\0';
342 msg += 16;
343 }
Eric Andersen3843e961999-11-25 07:30:46 +0000344
Erik Andersene49d5ec2000-02-08 19:58:47 +0000345 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000346
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000347#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +0000348 /* send message to remote logger */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000349 if ( -1 != remotefd){
Mark Whitley59ab0252001-01-23 22:30:04 +0000350static const int IOV_COUNT = 2;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000351 struct iovec iov[IOV_COUNT];
352 struct iovec *v = iov;
Eric Andersenced2cef2000-07-20 23:41:24 +0000353
Eric Andersen044228d2001-07-17 01:12:36 +0000354 memset(&res, 0, sizeof(res));
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000355 snprintf(res, sizeof(res), "<%d>", pri);
356 v->iov_base = res ;
357 v->iov_len = strlen(res);
358 v++;
Eric Andersenced2cef2000-07-20 23:41:24 +0000359
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000360 v->iov_base = msg;
361 v->iov_len = strlen(msg);
362
Eric Andersen4e116822002-04-13 14:07:32 +0000363writev_retry:
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000364 if ( -1 == writev(remotefd,iov, IOV_COUNT)){
Eric Andersen4e116822002-04-13 14:07:32 +0000365 if (errno == EINTR) goto writev_retry;
366 error_msg_and_die("syslogd: cannot write to remote file handle on"
Matt Kraaidd19c692001-01-31 19:00:21 +0000367 "%s:%d",RemoteHost,RemotePort);
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000368 }
369 }
Matt Kraai1f0c4362001-12-20 23:13:26 +0000370 if (local_logging)
Eric Andersenced2cef2000-07-20 23:41:24 +0000371#endif
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000372 /* now spew out the message to wherever it is supposed to go */
373 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
Eric Andersen76fef0a2000-12-08 19:41:21 +0000374
Eric Andersenced2cef2000-07-20 23:41:24 +0000375
Eric Andersen3843e961999-11-25 07:30:46 +0000376}
377
378static void quit_signal(int sig)
379{
Eric Andersen238bc402001-05-07 17:55:05 +0000380 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000381 unlink(lfile);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000382#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +0000383 ipcsyslog_cleanup();
384#endif
385
Erik Andersene49d5ec2000-02-08 19:58:47 +0000386 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000387}
388
Eric Andersen3843e961999-11-25 07:30:46 +0000389static void domark(int sig)
390{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000391 if (MarkInterval > 0) {
392 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
393 alarm(MarkInterval);
394 }
Eric Andersen3843e961999-11-25 07:30:46 +0000395}
396
Eric Andersen22ecf042001-07-02 17:32:40 +0000397/* This must be a #define, since when DODEBUG and BUFFERS_GO_IN_BSS are
398 * enabled, we otherwise get a "storage size isn't constant error. */
399#define BUFSIZE 1023
Eric Andersen74b007f2002-08-05 11:56:25 +0000400static int serveConnection (char* tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000401{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000402 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000403
Matt Kraaib6ec7812001-08-14 17:32:23 +0000404 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000405
406 int pri = (LOG_USER | LOG_NOTICE);
407 char line[ BUFSIZE + 1 ];
408 unsigned char c;
Robert Grieblfc78b792002-07-19 20:52:21 +0000409 int gotpri = 0;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000410
Matt Kraaib6ec7812001-08-14 17:32:23 +0000411 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000412
Pavel Roskinda10ec02000-06-07 21:08:25 +0000413 while (p && (c = *p) && q < &line[ sizeof (line) - 1 ]) {
Robert Grieblfc78b792002-07-19 20:52:21 +0000414 if ((c == '<') && !gotpri && isdigit(p[1])) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000415 /* Parse the magic priority number. */
Robert Grieblfc78b792002-07-19 20:52:21 +0000416 gotpri = 1;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000417 pri = 0;
418 while (isdigit (*(++p))) {
419 pri = 10 * pri + (*p - '0');
420 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000421 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)){
Pavel Roskinda10ec02000-06-07 21:08:25 +0000422 pri = (LOG_USER | LOG_NOTICE);
Eric Andersenced2cef2000-07-20 23:41:24 +0000423 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000424 } else if (c == '\n') {
425 *q++ = ' ';
426 } else if (iscntrl (c) && (c < 0177)) {
427 *q++ = '^';
428 *q++ = c ^ 0100;
429 } else {
430 *q++ = c;
431 }
432 p++;
433 }
434 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000435 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000436 /* Now log it */
437 logMessage (pri, line);
438 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000439 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000440}
441
Eric Andersenced2cef2000-07-20 23:41:24 +0000442
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000443#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +0000444static void init_RemoteLog (void){
445
446 struct sockaddr_in remoteaddr;
447 struct hostent *hostinfo;
448 int len = sizeof(remoteaddr);
449
Eric Andersen044228d2001-07-17 01:12:36 +0000450 memset(&remoteaddr, 0, len);
Mark Whitleybff6b182001-03-27 20:17:58 +0000451
Eric Andersenced2cef2000-07-20 23:41:24 +0000452 remotefd = socket(AF_INET, SOCK_DGRAM, 0);
453
454 if (remotefd < 0) {
Matt Kraaidd19c692001-01-31 19:00:21 +0000455 error_msg_and_die("syslogd: cannot create socket");
Eric Andersenced2cef2000-07-20 23:41:24 +0000456 }
457
Matt Kraaic55b8d42001-05-16 15:40:51 +0000458 hostinfo = xgethostbyname(RemoteHost);
Eric Andersenced2cef2000-07-20 23:41:24 +0000459
460 remoteaddr.sin_family = AF_INET;
461 remoteaddr.sin_addr = *(struct in_addr *) *hostinfo->h_addr_list;
462 remoteaddr.sin_port = htons(RemotePort);
463
464 /*
465 Since we are using UDP sockets, connect just sets the default host and port
466 for future operations
467 */
468 if ( 0 != (connect(remotefd, (struct sockaddr *) &remoteaddr, len))){
Matt Kraaidd19c692001-01-31 19:00:21 +0000469 error_msg_and_die("syslogd: cannot connect to remote host %s:%d", RemoteHost, RemotePort);
Eric Andersenced2cef2000-07-20 23:41:24 +0000470 }
471
472}
473#endif
474
Manuel Novoa III f8277ca2002-08-06 20:12:56 +0000475#define MAXLINE 1024 /* maximum line length */
476
Erik Andersen983b51b2000-04-04 18:14:25 +0000477static void doSyslogd (void) __attribute__ ((noreturn));
478static void doSyslogd (void)
Eric Andersen3843e961999-11-25 07:30:46 +0000479{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000480 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000481 socklen_t addrLength;
482
Erik Andersenf13df372000-04-18 23:51:51 +0000483
Erik Andersen983b51b2000-04-04 18:14:25 +0000484 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000485 fd_set fds;
486
Erik Andersenf13df372000-04-18 23:51:51 +0000487 /* Set up signal handlers. */
Erik Andersen983b51b2000-04-04 18:14:25 +0000488 signal (SIGINT, quit_signal);
489 signal (SIGTERM, quit_signal);
490 signal (SIGQUIT, quit_signal);
491 signal (SIGHUP, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000492 signal (SIGCHLD, SIG_IGN);
493#ifdef SIGCLD
Erik Andersene3ed1562000-04-19 18:52:56 +0000494 signal (SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000495#endif
Erik Andersen983b51b2000-04-04 18:14:25 +0000496 signal (SIGALRM, domark);
497 alarm (MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000498
Erik Andersenf13df372000-04-18 23:51:51 +0000499 /* Create the syslog file so realpath() can work. */
Eric Andersen87d893c2001-05-03 07:01:41 +0000500 if (realpath (_PATH_LOG, lfile) != NULL)
501 unlink (lfile);
Erik Andersen983b51b2000-04-04 18:14:25 +0000502
Erik Andersenf13df372000-04-18 23:51:51 +0000503 memset (&sunx, 0, sizeof (sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000504 sunx.sun_family = AF_UNIX;
Erik Andersenf13df372000-04-18 23:51:51 +0000505 strncpy (sunx.sun_path, lfile, sizeof (sunx.sun_path));
Eric Andersenc59716f2002-08-05 11:14:30 +0000506 if ((sock_fd = socket (AF_UNIX, SOCK_DGRAM, 0)) < 0)
Eric Andersen87d893c2001-05-03 07:01:41 +0000507 perror_msg_and_die ("Couldn't get file descriptor for socket " _PATH_LOG);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000508
Erik Andersen983b51b2000-04-04 18:14:25 +0000509 addrLength = sizeof (sunx.sun_family) + strlen (sunx.sun_path);
Eric Andersenc59716f2002-08-05 11:14:30 +0000510 if (bind (sock_fd, (struct sockaddr *) &sunx, addrLength) < 0)
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000511 perror_msg_and_die ("Could not connect to socket " _PATH_LOG);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000512
Erik Andersenf13df372000-04-18 23:51:51 +0000513 if (chmod (lfile, 0666) < 0)
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000514 perror_msg_and_die ("Could not set permission on " _PATH_LOG);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000515
Erik Andersenf13df372000-04-18 23:51:51 +0000516 FD_ZERO (&fds);
517 FD_SET (sock_fd, &fds);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000518
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000519#ifdef CONFIG_FEATURE_IPC_SYSLOG
Matt Kraai1f0c4362001-12-20 23:13:26 +0000520 if (circular_logging ){
Eric Andersenea906502001-04-05 20:55:17 +0000521 ipcsyslog_init();
522 }
523#endif
524
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000525 #ifdef CONFIG_FEATURE_REMOTE_LOG
Matt Kraai1f0c4362001-12-20 23:13:26 +0000526 if (doRemoteLog){
Eric Andersenced2cef2000-07-20 23:41:24 +0000527 init_RemoteLog();
528 }
529 #endif
530
Eric Andersen238bc402001-05-07 17:55:05 +0000531 logMessage (LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000532
Erik Andersen983b51b2000-04-04 18:14:25 +0000533 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000534
535 fd_set readfds;
536 int n_ready;
537 int fd;
538
539 memcpy (&readfds, &fds, sizeof (fds));
Erik Andersene49d5ec2000-02-08 19:58:47 +0000540
Erik Andersen983b51b2000-04-04 18:14:25 +0000541 if ((n_ready = select (FD_SETSIZE, &readfds, NULL, NULL, NULL)) < 0) {
542 if (errno == EINTR) continue; /* alarm may have happened. */
Matt Kraai1fa1ade2000-12-18 03:57:16 +0000543 perror_msg_and_die ("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000544 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000545
Erik Andersenf13df372000-04-18 23:51:51 +0000546 for (fd = 0; (n_ready > 0) && (fd < FD_SETSIZE); fd++) {
Erik Andersen983b51b2000-04-04 18:14:25 +0000547 if (FD_ISSET (fd, &readfds)) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000548
Erik Andersenf13df372000-04-18 23:51:51 +0000549 --n_ready;
Erik Andersene3ed1562000-04-19 18:52:56 +0000550
Erik Andersen983b51b2000-04-04 18:14:25 +0000551 if (fd == sock_fd) {
Eric Andersen74b007f2002-08-05 11:56:25 +0000552 int i;
553 RESERVE_CONFIG_BUFFER(tmpbuf, BUFSIZE + 1);
Erik Andersene3ed1562000-04-19 18:52:56 +0000554
Eric Andersen74b007f2002-08-05 11:56:25 +0000555 memset(tmpbuf, '\0', BUFSIZE+1);
556 if ( (i = recv(fd, tmpbuf, MAXLINE - 2, 0)) > 0) {
557 if ( serveConnection(tmpbuf, i) <= 0 ) {
558 close (fd);
559 FD_CLR(fd, &fds);
560 }
561 } else {
562 perror_msg_and_die ("UNIX socket error");
Erik Andersen983b51b2000-04-04 18:14:25 +0000563 }
Eric Andersen74b007f2002-08-05 11:56:25 +0000564 RELEASE_CONFIG_BUFFER (tmpbuf);
Mark Whitley1a49fc52001-03-12 19:51:09 +0000565 } /* fd == sock_fd */
566 }/* FD_ISSET() */
567 }/* for */
568 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000569}
570
Eric Andersen3843e961999-11-25 07:30:46 +0000571extern int syslogd_main(int argc, char **argv)
572{
Eric Andersene5c24df2001-03-29 21:58:33 +0000573 int opt;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000574 int doFork = TRUE;
575
Erik Andersene49d5ec2000-02-08 19:58:47 +0000576 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000577
Eric Andersen394cf222000-12-11 16:48:50 +0000578 /* do normal option parsing */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000579 while ((opt = getopt(argc, argv, "m:nO:R:LC")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000580 switch (opt) {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000581 case 'm':
Eric Andersen394cf222000-12-11 16:48:50 +0000582 MarkInterval = atoi(optarg) * 60;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000583 break;
584 case 'n':
585 doFork = FALSE;
586 break;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000587 case 'O':
Matt Kraaic8227632001-11-12 16:57:27 +0000588 logFilePath = xstrdup(optarg);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000589 break;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000590#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +0000591 case 'R':
Matt Kraaic8227632001-11-12 16:57:27 +0000592 RemoteHost = xstrdup(optarg);
Eric Andersen394cf222000-12-11 16:48:50 +0000593 if ( (p = strchr(RemoteHost, ':'))){
594 RemotePort = atoi(p+1);
595 *p = '\0';
Mark Whitleybff6b182001-03-27 20:17:58 +0000596 }
Eric Andersen394cf222000-12-11 16:48:50 +0000597 doRemoteLog = TRUE;
598 break;
Eric Andersen70d09ed2000-12-11 16:24:16 +0000599 case 'L':
600 local_logging = TRUE;
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000601 break;
Eric Andersenced2cef2000-07-20 23:41:24 +0000602#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000603#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +0000604 case 'C':
605 circular_logging = TRUE;
606 break;
607#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000608 default:
Eric Andersen67991cf2001-02-14 21:23:06 +0000609 show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000610 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000611 }
612
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000613#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersen4ed17822000-12-11 19:28:29 +0000614 /* If they have not specified remote logging, then log locally */
Matt Kraai1f0c4362001-12-20 23:13:26 +0000615 if (! doRemoteLog)
Eric Andersen4ed17822000-12-11 19:28:29 +0000616 local_logging = TRUE;
617#endif
618
Mark Whitley6317c4b2001-03-12 22:51:50 +0000619
Erik Andersene49d5ec2000-02-08 19:58:47 +0000620 /* Store away localhost's name before the fork */
621 gethostname(LocalHostName, sizeof(LocalHostName));
622 if ((p = strchr(LocalHostName, '.'))) {
623 *p++ = '\0';
624 }
625
Erik Andersen983b51b2000-04-04 18:14:25 +0000626 umask(0);
627
Matt Kraai1f0c4362001-12-20 23:13:26 +0000628 if (doFork) {
Eric Andersen72f9a422001-10-28 05:12:20 +0000629#if !defined(__UCLIBC__) || defined(__UCLIBC_HAS_MMU__)
Eric Andersene5c24df2001-03-29 21:58:33 +0000630 if (daemon(0, 1) < 0)
631 perror_msg_and_die("daemon");
Eric Andersen72f9a422001-10-28 05:12:20 +0000632#else
633 error_msg_and_die("daemon not supported");
634#endif
Eric Andersen3843e961999-11-25 07:30:46 +0000635 }
Eric Andersene5c24df2001-03-29 21:58:33 +0000636 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000637
Matt Kraai3e856ce2000-12-01 02:55:13 +0000638 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000639}
Erik Andersen983b51b2000-04-04 18:14:25 +0000640
641/*
Erik Andersene3ed1562000-04-19 18:52:56 +0000642Local Variables
643c-file-style: "linux"
644c-basic-offset: 4
645tab-width: 4
646End:
647*/