blob: 74c4071429083d2e736d8874eda7177bac42be7f [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersen3843e961999-11-25 07:30:46 +00002/*
3 * Mini syslogd implementation for busybox
4 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00005 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
Eric Andersen3843e961999-11-25 07:30:46 +00006 *
Erik Andersenf13df372000-04-18 23:51:51 +00007 * Copyright (C) 2000 by Karl M. Hegbloom <karlheg@debian.org>
8 *
Glenn L McGrath6ed77592002-12-12 10:54:48 +00009 * "circular buffer" Copyright (C) 2001 by Gennady Feldman <gfeldman@gena01.com>
Mark Whitley6317c4b2001-03-12 22:51:50 +000010 *
Glenn L McGrath6ed77592002-12-12 10:54:48 +000011 * Maintainer: Gennady Feldman <gfeldman@gena01.com> as of Mar 12, 2001
Mark Whitley6bff9cc2001-03-12 23:41:34 +000012 *
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +000013 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Eric Andersen3843e961999-11-25 07:30:46 +000014 */
Eric Andersenb99df0f1999-11-24 09:04:33 +000015
Eric Andersen67e32302000-06-19 17:48:02 +000016#include <stdio.h>
17#include <stdlib.h>
Eric Andersen3843e961999-11-25 07:30:46 +000018#include <ctype.h>
Eric Andersenb186d981999-12-03 09:19:54 +000019#include <errno.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000020#include <fcntl.h>
Glenn L McGrath5529b7b2004-07-22 04:23:18 +000021#include <getopt.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000022#include <netdb.h>
Eric Andersenb186d981999-12-03 09:19:54 +000023#include <paths.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000024#include <signal.h>
25#include <stdarg.h>
Eric Andersen7f94a5c2004-06-22 10:12:59 +000026#include <stdbool.h>
Eric Andersen67e32302000-06-19 17:48:02 +000027#include <time.h>
Eric Andersened3ef502001-01-27 08:24:39 +000028#include <string.h>
Eric Andersen67e32302000-06-19 17:48:02 +000029#include <unistd.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000030#include <sys/socket.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000031#include <sys/types.h>
32#include <sys/un.h>
Erik Andersen7d6ba572000-04-19 20:02:50 +000033#include <sys/param.h>
Eric Andersenb186d981999-12-03 09:19:54 +000034
Eric Andersencbe31da2001-02-20 06:14:08 +000035#include "busybox.h"
Eric Andersen67e32302000-06-19 17:48:02 +000036
Eric Andersen3843e961999-11-25 07:30:46 +000037/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
38#define SYSLOG_NAMES
39#include <sys/syslog.h>
Eric Andersenced2cef2000-07-20 23:41:24 +000040#include <sys/uio.h>
Eric Andersen3843e961999-11-25 07:30:46 +000041
42/* Path for the file where all log messages are written */
Erik Andersen983b51b2000-04-04 18:14:25 +000043#define __LOG_FILE "/var/log/messages"
Eric Andersen3843e961999-11-25 07:30:46 +000044
Erik Andersen983b51b2000-04-04 18:14:25 +000045/* Path to the unix socket */
Eric Andersen871d93c2002-09-17 20:06:29 +000046static char lfile[MAXPATHLEN];
Eric Andersen3843e961999-11-25 07:30:46 +000047
Glenn L McGrathfe538ba2003-09-10 23:35:45 +000048static const char *logFilePath = __LOG_FILE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000049
Eric Andersen29c77f72003-10-09 09:43:18 +000050#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
Eric Andersenaff114c2004-04-14 17:51:38 +000051/* max size of message file before being rotated */
Eric Andersen29c77f72003-10-09 09:43:18 +000052static int logFileSize = 200 * 1024;
53
54/* number of rotated message files */
55static int logFileRotate = 1;
56#endif
57
Eric Andersen3843e961999-11-25 07:30:46 +000058/* interval between marks in seconds */
Erik Andersene49d5ec2000-02-08 19:58:47 +000059static int MarkInterval = 20 * 60;
60
Eric Andersen3843e961999-11-25 07:30:46 +000061/* localhost's name */
Eric Andersen871d93c2002-09-17 20:06:29 +000062static char LocalHostName[64];
Eric Andersen3843e961999-11-25 07:30:46 +000063
Eric Andersenbdfd0d72001-10-24 05:00:29 +000064#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +000065#include <netinet/in.h>
66/* udp socket for logging to remote host */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000067static int remotefd = -1;
Eric Andersen75813ee2004-08-26 23:15:29 +000068static struct sockaddr_in remoteaddr;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000069
Eric Andersenced2cef2000-07-20 23:41:24 +000070/* where do we log? */
71static char *RemoteHost;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000072
Eric Andersenced2cef2000-07-20 23:41:24 +000073/* what port to log to? */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000074static int RemotePort = 514;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000075
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
Eric Andersen7f94a5c2004-06-22 10:12:59 +000081/* Make loging output smaller. */
82static bool small = false;
83
Eric Andersen871d93c2002-09-17 20:06:29 +000084
Glenn L McGrath912d8f42002-11-10 22:46:45 +000085#define MAXLINE 1024 /* maximum line length */
Eric Andersen871d93c2002-09-17 20:06:29 +000086
87
Mark Whitley6317c4b2001-03-12 22:51:50 +000088/* circular buffer variables/structures */
Eric Andersenbdfd0d72001-10-24 05:00:29 +000089#ifdef CONFIG_FEATURE_IPC_SYSLOG
Eric Andersend4a5e252003-12-19 11:32:14 +000090
91#if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4
92#error Sorry, you must set the syslogd buffer size to at least 4KB.
93#error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE
94#endif
95
Mark Whitley6317c4b2001-03-12 22:51:50 +000096#include <sys/ipc.h>
97#include <sys/sem.h>
98#include <sys/shm.h>
99
100/* our shared key */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000101static const long KEY_ID = 0x414e4547; /*"GENA" */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000102
103// Semaphore operation structures
104static struct shbuf_ds {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000105 int size; // size of data written
106 int head; // start of message list
107 int tail; // end of message list
108 char data[1]; // data/messages
109} *buf = NULL; // shared memory pointer
Mark Whitley6317c4b2001-03-12 22:51:50 +0000110
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000111static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup
112static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn
Mark Whitley6317c4b2001-03-12 22:51:50 +0000113
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000114static int shmid = -1; // ipc shared memory id
115static int s_semid = -1; // ipc semaphore id
Eric Andersend4a5e252003-12-19 11:32:14 +0000116static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024); // default shm 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
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000140static void ipcsyslog_cleanup(void)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000141{
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
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000155static void ipcsyslog_init(void)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000156{
157 if (buf == NULL) {
Eric Andersend4a5e252003-12-19 11:32:14 +0000158 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
Eric Andersend4a5e252003-12-19 11:32:14 +0000166 buf->size = shm_size - sizeof(*buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000167 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 */
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000185static void circ_message(const char *msg)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000186{
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
Bernhard Reutner-Fischer0c013f52006-04-18 12:46:56 +0000212 * a threadsafe 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? */
Bernhard Reutner-Fischer0c013f52006-04-18 12:46:56 +0000239 printf("Weird! Can't find the terminator token?\n");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000240 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
Bernhard Reutner-Fischer0c013f52006-04-18 12:46:56 +0000276 ("Weird! Can't find the terminator token from the beginning?\n");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000277 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
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000309 if ((fd = device_open(logFilePath,
310 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000311 O_NONBLOCK)) >= 0) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000312 fl.l_type = F_WRLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000313 fcntl(fd, F_SETLKW, &fl);
Eric Andersen29c77f72003-10-09 09:43:18 +0000314#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
315 if ( logFileSize > 0 ) {
316 struct stat statf;
317 int r = fstat(fd, &statf);
318 if( !r && (statf.st_mode & S_IFREG)
319 && (lseek(fd,0,SEEK_END) > logFileSize) ) {
320 if(logFileRotate > 0) {
321 int i;
Eric Andersen2c6b4182005-09-12 19:16:11 +0000322 char oldFile[(strlen(logFilePath)+4)], newFile[(strlen(logFilePath)+4)];
Eric Andersen29c77f72003-10-09 09:43:18 +0000323 for(i=logFileRotate-1;i>0;i--) {
324 sprintf(oldFile, "%s.%d", logFilePath, i-1);
325 sprintf(newFile, "%s.%d", logFilePath, i);
326 rename(oldFile, newFile);
327 }
328 sprintf(newFile, "%s.%d", logFilePath, 0);
329 fl.l_type = F_UNLCK;
330 fcntl (fd, F_SETLKW, &fl);
331 close(fd);
332 rename(logFilePath, newFile);
333 fd = device_open (logFilePath,
334 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
335 O_NONBLOCK);
336 fl.l_type = F_WRLCK;
337 fcntl (fd, F_SETLKW, &fl);
338 } else {
339 ftruncate( fd, 0 );
340 }
341 }
342 }
343#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000344 va_start(arguments, fmt);
345 vdprintf(fd, fmt, arguments);
346 va_end(arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000347 fl.l_type = F_UNLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000348 fcntl(fd, F_SETLKW, &fl);
349 close(fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000350 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000351 /* Always send console messages to /dev/console so people will see them. */
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000352 if ((fd = device_open(_PATH_CONSOLE,
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000353 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
354 va_start(arguments, fmt);
355 vdprintf(fd, fmt, arguments);
356 va_end(arguments);
357 close(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000358 } else {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000359 fprintf(stderr, "Bummer, can't print: ");
360 va_start(arguments, fmt);
361 vfprintf(stderr, fmt, arguments);
362 fflush(stderr);
363 va_end(arguments);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000364 }
Eric Andersen3843e961999-11-25 07:30:46 +0000365 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000366}
367
Eric Andersenf91b9282004-09-08 10:56:06 +0000368#ifdef CONFIG_FEATURE_REMOTE_LOG
369static void init_RemoteLog(void)
370{
371 memset(&remoteaddr, 0, sizeof(remoteaddr));
Bernhard Reutner-Fischerdac7ff12006-04-12 17:55:51 +0000372 remotefd = bb_xsocket(AF_INET, SOCK_DGRAM, 0);
Eric Andersenf91b9282004-09-08 10:56:06 +0000373 remoteaddr.sin_family = AF_INET;
374 remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list;
375 remoteaddr.sin_port = htons(RemotePort);
376}
377#endif
378
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000379static void logMessage(int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000380{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000381 time_t now;
382 char *timestamp;
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000383 static char res[20];
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000384#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenf91b9282004-09-08 10:56:06 +0000385 static char line[MAXLINE + 1];
Eric Andersen192c35f2004-09-02 22:22:17 +0000386#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000387 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000388
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000389 if (pri != 0) {
390 for (c_fac = facilitynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000391 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000392 for (c_pri = prioritynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000393 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
394 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000395 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000396 } else {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000397 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000398 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000399 }
Eric Andersen3843e961999-11-25 07:30:46 +0000400
Erik Andersene49d5ec2000-02-08 19:58:47 +0000401 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000402 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000403 time(&now);
404 timestamp = ctime(&now) + 4;
405 timestamp[15] = '\0';
406 } else {
407 timestamp = msg;
408 timestamp[15] = '\0';
409 msg += 16;
410 }
Eric Andersen3843e961999-11-25 07:30:46 +0000411
Erik Andersene49d5ec2000-02-08 19:58:47 +0000412 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000413
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000414#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000415 if (doRemoteLog == TRUE) {
416 /* trying connect the socket */
417 if (-1 == remotefd) {
418 init_RemoteLog();
419 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000420
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000421 /* if we have a valid socket, send the message */
422 if (-1 != remotefd) {
423 now = 1;
Paul Fox27cbffd2005-07-20 18:02:11 +0000424 snprintf(line, sizeof(line), "<%d>%s", pri, msg);
Eric Andersenced2cef2000-07-20 23:41:24 +0000425
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000426 retry:
427 /* send message to remote logger */
428 if(( -1 == sendto(remotefd, line, strlen(line), 0,
429 (struct sockaddr *) &remoteaddr,
430 sizeof(remoteaddr))) && (errno == EINTR)) {
431 /* sleep now seconds and retry (with now * 2) */
432 sleep(now);
433 now *= 2;
434 goto retry;
435 }
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000436 }
437 }
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000438
Eric Andersen871d93c2002-09-17 20:06:29 +0000439 if (local_logging == TRUE)
Eric Andersenced2cef2000-07-20 23:41:24 +0000440#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000441 {
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000442 /* now spew out the message to wherever it is supposed to go */
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000443 if (small)
444 message("%s %s\n", timestamp, msg);
445 else
446 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
447 }
Eric Andersen3843e961999-11-25 07:30:46 +0000448}
449
450static void quit_signal(int sig)
451{
Eric Andersen238bc402001-05-07 17:55:05 +0000452 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000453 unlink(lfile);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000454#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +0000455 ipcsyslog_cleanup();
456#endif
457
Erik Andersene49d5ec2000-02-08 19:58:47 +0000458 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000459}
460
Eric Andersen3843e961999-11-25 07:30:46 +0000461static void domark(int sig)
462{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000463 if (MarkInterval > 0) {
464 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
465 alarm(MarkInterval);
466 }
Eric Andersen3843e961999-11-25 07:30:46 +0000467}
468
Eric Andersene5272072003-07-22 22:15:21 +0000469/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
Eric Andersen22ecf042001-07-02 17:32:40 +0000470 * enabled, we otherwise get a "storage size isn't constant error. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000471static int serveConnection(char *tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000472{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000473 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000474
Matt Kraaib6ec7812001-08-14 17:32:23 +0000475 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000476
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000477 int pri = (LOG_USER | LOG_NOTICE);
Eric Andersend4f90ed2003-05-23 09:28:01 +0000478 int num_lt = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000479 char line[MAXLINE + 1];
Pavel Roskinda10ec02000-06-07 21:08:25 +0000480 unsigned char c;
Matt Kraaib6ec7812001-08-14 17:32:23 +0000481 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000482
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000483 while ((c = *p) && q < &line[sizeof(line) - 1]) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000484 if (c == '<' && num_lt == 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000485 /* Parse the magic priority number. */
Eric Andersend4f90ed2003-05-23 09:28:01 +0000486 num_lt++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000487 pri = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000488 while (isdigit(*(++p))) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000489 pri = 10 * pri + (*p - '0');
490 }
Eric Andersen46ba5682003-05-23 09:29:57 +0000491 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000492 pri = (LOG_USER | LOG_NOTICE);
Eric Andersen46ba5682003-05-23 09:29:57 +0000493 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000494 } else if (c == '\n') {
495 *q++ = ' ';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000496 } else if (iscntrl(c) && (c < 0177)) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000497 *q++ = '^';
498 *q++ = c ^ 0100;
499 } else {
500 *q++ = c;
501 }
502 p++;
503 }
504 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000505 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000506 /* Now log it */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000507 logMessage(pri, line);
Pavel Roskinda10ec02000-06-07 21:08:25 +0000508 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000509 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000510}
511
Bernhard Reutner-Fischer86f5c992006-01-22 22:55:11 +0000512static void doSyslogd(void) ATTRIBUTE_NORETURN;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000513static void doSyslogd(void)
Eric Andersen3843e961999-11-25 07:30:46 +0000514{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000515 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000516 socklen_t addrLength;
517
Erik Andersen983b51b2000-04-04 18:14:25 +0000518 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000519 fd_set fds;
520
Erik Andersenf13df372000-04-18 23:51:51 +0000521 /* Set up signal handlers. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000522 signal(SIGINT, quit_signal);
523 signal(SIGTERM, quit_signal);
524 signal(SIGQUIT, quit_signal);
525 signal(SIGHUP, SIG_IGN);
526 signal(SIGCHLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000527#ifdef SIGCLD
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000528 signal(SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000529#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000530 signal(SIGALRM, domark);
531 alarm(MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000532
Erik Andersenf13df372000-04-18 23:51:51 +0000533 /* Create the syslog file so realpath() can work. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000534 if (realpath(_PATH_LOG, lfile) != NULL) {
535 unlink(lfile);
536 }
Erik Andersen983b51b2000-04-04 18:14:25 +0000537
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000538 memset(&sunx, 0, sizeof(sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000539 sunx.sun_family = AF_UNIX;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000540 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
Bernhard Reutner-Fischerdac7ff12006-04-12 17:55:51 +0000541 sock_fd = bb_xsocket(AF_UNIX, SOCK_DGRAM, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000542 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
543 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000544 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000545 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000546
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000547 if (chmod(lfile, 0666) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000548 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000549 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000550#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000551 if (circular_logging == TRUE) {
552 ipcsyslog_init();
Eric Andersenea906502001-04-05 20:55:17 +0000553 }
554#endif
555
Eric Andersen871d93c2002-09-17 20:06:29 +0000556#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000557 if (doRemoteLog == TRUE) {
558 init_RemoteLog();
Eric Andersen871d93c2002-09-17 20:06:29 +0000559 }
560#endif
Eric Andersenced2cef2000-07-20 23:41:24 +0000561
"Vladimir N. Oleynik"dd1ccdd2006-02-16 15:40:24 +0000562 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " "BusyBox v" BB_VER );
Erik Andersene49d5ec2000-02-08 19:58:47 +0000563
Erik Andersen983b51b2000-04-04 18:14:25 +0000564 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000565
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000566 FD_ZERO(&fds);
567 FD_SET(sock_fd, &fds);
Erik Andersenf13df372000-04-18 23:51:51 +0000568
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000569 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
Eric Andersen871d93c2002-09-17 20:06:29 +0000570 if (errno == EINTR) {
571 /* alarm may have happened. */
572 continue;
573 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000574 bb_perror_msg_and_die("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000575 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000576
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000577 if (FD_ISSET(sock_fd, &fds)) {
578 int i;
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000579#if MAXLINE > BUFSIZ
580# define TMP_BUF_SZ BUFSIZ
581#else
582# define TMP_BUF_SZ MAXLINE
583#endif
584#define tmpbuf bb_common_bufsiz1
Erik Andersene3ed1562000-04-19 18:52:56 +0000585
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000586 if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) {
587 tmpbuf[i] = '\0';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000588 serveConnection(tmpbuf, i);
589 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000590 bb_perror_msg_and_die("UNIX socket error");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000591 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000592 } /* FD_ISSET() */
593 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000594}
595
Rob Landleydfba7412006-03-06 20:47:33 +0000596int syslogd_main(int argc, char **argv)
Eric Andersen3843e961999-11-25 07:30:46 +0000597{
Eric Andersene5c24df2001-03-29 21:58:33 +0000598 int opt;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000599
Erik Andersene49d5ec2000-02-08 19:58:47 +0000600 int doFork = TRUE;
601
Erik Andersene49d5ec2000-02-08 19:58:47 +0000602 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000603
Eric Andersen394cf222000-12-11 16:48:50 +0000604 /* do normal option parsing */
Glenn L McGrath5529b7b2004-07-22 04:23:18 +0000605 while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000606 switch (opt) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000607 case 'm':
608 MarkInterval = atoi(optarg) * 60;
609 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000610 case 'n':
611 doFork = FALSE;
612 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000613 case 'O':
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000614 logFilePath = optarg;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000615 break;
Eric Andersen29c77f72003-10-09 09:43:18 +0000616#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
617 case 's':
618 logFileSize = atoi(optarg) * 1024;
619 break;
620 case 'b':
621 logFileRotate = atoi(optarg);
622 if( logFileRotate > 99 ) logFileRotate = 99;
623 break;
624#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000625#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000626 case 'R':
Manuel Novoa III cad53642003-03-19 09:13:01 +0000627 RemoteHost = bb_xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000628 if ((p = strchr(RemoteHost, ':'))) {
629 RemotePort = atoi(p + 1);
630 *p = '\0';
631 }
632 doRemoteLog = TRUE;
633 break;
634 case 'L':
635 local_logging = TRUE;
636 break;
Eric Andersenced2cef2000-07-20 23:41:24 +0000637#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000638#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000639 case 'C':
Glenn L McGratha79220d2003-09-26 00:49:05 +0000640 if (optarg) {
641 int buf_size = atoi(optarg);
642 if (buf_size >= 4) {
Glenn L McGrathdf2c5652004-02-22 12:17:33 +0000643 shm_size = buf_size * 1024;
Glenn L McGratha79220d2003-09-26 00:49:05 +0000644 }
645 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000646 circular_logging = TRUE;
647 break;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000648#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000649 case 'S':
650 small = true;
651 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000652 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000653 bb_show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000654 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000655 }
656
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000657#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersen4ed17822000-12-11 19:28:29 +0000658 /* If they have not specified remote logging, then log locally */
Eric Andersen871d93c2002-09-17 20:06:29 +0000659 if (doRemoteLog == FALSE)
Eric Andersen4ed17822000-12-11 19:28:29 +0000660 local_logging = TRUE;
661#endif
662
Mark Whitley6317c4b2001-03-12 22:51:50 +0000663
Erik Andersene49d5ec2000-02-08 19:58:47 +0000664 /* Store away localhost's name before the fork */
665 gethostname(LocalHostName, sizeof(LocalHostName));
666 if ((p = strchr(LocalHostName, '.'))) {
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000667 *p = '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000668 }
669
Erik Andersen983b51b2000-04-04 18:14:25 +0000670 umask(0);
671
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000672 if (doFork == TRUE) {
Glenn L McGrathdc72f3a2003-08-29 07:35:08 +0000673#if defined(__uClinux__)
Russ Dilla1fece22003-12-15 21:57:44 +0000674 vfork_daemon_rexec(0, 1, argc, argv, "-n");
675#else /* __uClinux__ */
Bernhard Reutner-Fischer2c998512006-04-12 18:09:26 +0000676 bb_xdaemon(0, 1);
Russ Dilla1fece22003-12-15 21:57:44 +0000677#endif /* __uClinux__ */
Eric Andersen35e643b2003-07-28 07:40:39 +0000678 }
Eric Andersene5c24df2001-03-29 21:58:33 +0000679 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000680
Matt Kraai3e856ce2000-12-01 02:55:13 +0000681 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000682}
Erik Andersen983b51b2000-04-04 18:14:25 +0000683
684/*
Erik Andersene3ed1562000-04-19 18:52:56 +0000685Local Variables
686c-file-style: "linux"
687c-basic-offset: 4
688tab-width: 4
689End:
690*/