blob: 3d94069e2ba11d7ef413291d1928b8544e67200f [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 *
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>
Glenn L McGrath5529b7b2004-07-22 04:23:18 +000034#include <getopt.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000035#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 Andersen7f94a5c2004-06-22 10:12:59 +000039#include <stdbool.h>
Eric Andersen67e32302000-06-19 17:48:02 +000040#include <time.h>
Eric Andersened3ef502001-01-27 08:24:39 +000041#include <string.h>
Eric Andersen67e32302000-06-19 17:48:02 +000042#include <unistd.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000043#include <sys/socket.h>
Erik Andersen983b51b2000-04-04 18:14:25 +000044#include <sys/types.h>
45#include <sys/un.h>
Erik Andersen7d6ba572000-04-19 20:02:50 +000046#include <sys/param.h>
Eric Andersenb186d981999-12-03 09:19:54 +000047
Eric Andersencbe31da2001-02-20 06:14:08 +000048#include "busybox.h"
Eric Andersen67e32302000-06-19 17:48:02 +000049
Eric Andersen3843e961999-11-25 07:30:46 +000050/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
51#define SYSLOG_NAMES
52#include <sys/syslog.h>
Eric Andersenced2cef2000-07-20 23:41:24 +000053#include <sys/uio.h>
Eric Andersen3843e961999-11-25 07:30:46 +000054
55/* Path for the file where all log messages are written */
Erik Andersen983b51b2000-04-04 18:14:25 +000056#define __LOG_FILE "/var/log/messages"
Eric Andersen3843e961999-11-25 07:30:46 +000057
Erik Andersen983b51b2000-04-04 18:14:25 +000058/* Path to the unix socket */
Eric Andersen871d93c2002-09-17 20:06:29 +000059static char lfile[MAXPATHLEN];
Eric Andersen3843e961999-11-25 07:30:46 +000060
Glenn L McGrathfe538ba2003-09-10 23:35:45 +000061static const char *logFilePath = __LOG_FILE;
Erik Andersene49d5ec2000-02-08 19:58:47 +000062
Eric Andersen29c77f72003-10-09 09:43:18 +000063#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
Eric Andersenaff114c2004-04-14 17:51:38 +000064/* max size of message file before being rotated */
Eric Andersen29c77f72003-10-09 09:43:18 +000065static int logFileSize = 200 * 1024;
66
67/* number of rotated message files */
68static int logFileRotate = 1;
69#endif
70
Eric Andersen3843e961999-11-25 07:30:46 +000071/* interval between marks in seconds */
Erik Andersene49d5ec2000-02-08 19:58:47 +000072static int MarkInterval = 20 * 60;
73
Eric Andersen3843e961999-11-25 07:30:46 +000074/* localhost's name */
Eric Andersen871d93c2002-09-17 20:06:29 +000075static char LocalHostName[64];
Eric Andersen3843e961999-11-25 07:30:46 +000076
Eric Andersenbdfd0d72001-10-24 05:00:29 +000077#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenced2cef2000-07-20 23:41:24 +000078#include <netinet/in.h>
79/* udp socket for logging to remote host */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000080static int remotefd = -1;
Eric Andersen75813ee2004-08-26 23:15:29 +000081static struct sockaddr_in remoteaddr;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000082
Eric Andersenced2cef2000-07-20 23:41:24 +000083/* where do we log? */
84static char *RemoteHost;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000085
Eric Andersenced2cef2000-07-20 23:41:24 +000086/* what port to log to? */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000087static int RemotePort = 514;
Glenn L McGrath912d8f42002-11-10 22:46:45 +000088
Eric Andersenced2cef2000-07-20 23:41:24 +000089/* To remote log or not to remote log, that is the question. */
Eric Andersenbf2b8ae2000-12-08 19:52:01 +000090static int doRemoteLog = FALSE;
Eric Andersen70d09ed2000-12-11 16:24:16 +000091static int local_logging = FALSE;
Eric Andersenced2cef2000-07-20 23:41:24 +000092#endif
93
Eric Andersen7f94a5c2004-06-22 10:12:59 +000094/* Make loging output smaller. */
95static bool small = false;
96
Eric Andersen871d93c2002-09-17 20:06:29 +000097
Glenn L McGrath912d8f42002-11-10 22:46:45 +000098#define MAXLINE 1024 /* maximum line length */
Eric Andersen871d93c2002-09-17 20:06:29 +000099
100
Mark Whitley6317c4b2001-03-12 22:51:50 +0000101/* circular buffer variables/structures */
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000102#ifdef CONFIG_FEATURE_IPC_SYSLOG
Eric Andersend4a5e252003-12-19 11:32:14 +0000103
104#if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4
105#error Sorry, you must set the syslogd buffer size to at least 4KB.
106#error Please check CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE
107#endif
108
Mark Whitley6317c4b2001-03-12 22:51:50 +0000109#include <sys/ipc.h>
110#include <sys/sem.h>
111#include <sys/shm.h>
112
113/* our shared key */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000114static const long KEY_ID = 0x414e4547; /*"GENA" */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000115
116// Semaphore operation structures
117static struct shbuf_ds {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000118 int size; // size of data written
119 int head; // start of message list
120 int tail; // end of message list
121 char data[1]; // data/messages
122} *buf = NULL; // shared memory pointer
Mark Whitley6317c4b2001-03-12 22:51:50 +0000123
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000124static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup
125static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn
Mark Whitley6317c4b2001-03-12 22:51:50 +0000126
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000127static int shmid = -1; // ipc shared memory id
128static int s_semid = -1; // ipc semaphore id
Eric Andersend4a5e252003-12-19 11:32:14 +0000129static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024); // default shm size
Mark Whitley6317c4b2001-03-12 22:51:50 +0000130static int circular_logging = FALSE;
131
132/*
133 * sem_up - up()'s a semaphore.
134 */
135static inline void sem_up(int semid)
136{
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000137 if (semop(semid, SMwup, 1) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000138 bb_perror_msg_and_die("semop[SMwup]");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000139 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000140}
141
142/*
143 * sem_down - down()'s a semaphore
144 */
145static inline void sem_down(int semid)
146{
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000147 if (semop(semid, SMwdn, 3) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000148 bb_perror_msg_and_die("semop[SMwdn]");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000149 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000150}
151
Eric Andersen871d93c2002-09-17 20:06:29 +0000152
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000153static void ipcsyslog_cleanup(void)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000154{
Mark Whitley6317c4b2001-03-12 22:51:50 +0000155 printf("Exiting Syslogd!\n");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000156 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000157 shmdt(buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000158 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000159
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000160 if (shmid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000161 shmctl(shmid, IPC_RMID, NULL);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000162 }
163 if (s_semid != -1) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000164 semctl(s_semid, 0, IPC_RMID, 0);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000165 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000166}
167
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000168static void ipcsyslog_init(void)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000169{
170 if (buf == NULL) {
Eric Andersend4a5e252003-12-19 11:32:14 +0000171 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000172 bb_perror_msg_and_die("shmget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000173 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000174
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000175 if ((buf = shmat(shmid, NULL, 0)) == NULL) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000176 bb_perror_msg_and_die("shmat");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000177 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000178
Eric Andersend4a5e252003-12-19 11:32:14 +0000179 buf->size = shm_size - sizeof(*buf);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000180 buf->head = buf->tail = 0;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000181
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000182 // we'll trust the OS to set initial semval to 0 (let's hope)
183 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) {
184 if (errno == EEXIST) {
185 if ((s_semid = semget(KEY_ID, 2, 0)) == -1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000186 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000187 }
188 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000189 bb_perror_msg_and_die("semget");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000190 }
191 }
192 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000193 printf("Buffer already allocated just grab the semaphore?");
194 }
195}
196
197/* write message to buffer */
"Vladimir N. Oleynik"e4baaa22005-09-22 12:59:26 +0000198static void circ_message(const char *msg)
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000199{
200 int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000201
202 sem_down(s_semid);
203
204 /*
205 * Circular Buffer Algorithm:
206 * --------------------------
207 *
208 * Start-off w/ empty buffer of specific size SHM_SIZ
209 * Start filling it up w/ messages. I use '\0' as separator to break up messages.
210 * This is also very handy since we can do printf on message.
211 *
212 * Once the buffer is full we need to get rid of the first message in buffer and
213 * insert the new message. (Note: if the message being added is >1 message then
214 * we will need to "remove" >1 old message from the buffer). The way this is done
215 * is the following:
Eric Andersen871d93c2002-09-17 20:06:29 +0000216 * When we reach the end of the buffer we set a mark and start from the beginning.
217 * Now what about the beginning and end of the buffer? Well we have the "head"
218 * index/pointer which is the starting point for the messages and we have "tail"
219 * index/pointer which is the ending point for the messages. When we "display" the
220 * messages we start from the beginning and continue until we reach "tail". If we
221 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
222 * "tail" are actually offsets from the beginning of the buffer.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000223 *
224 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
Eric Andersen871d93c2002-09-17 20:06:29 +0000225 * a threasafe way of handling shared memory operations.
Mark Whitley6317c4b2001-03-12 22:51:50 +0000226 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000227 if ((buf->tail + l) < buf->size) {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000228 /* before we append the message we need to check the HEAD so that we won't
229 overwrite any of the message that we still need and adjust HEAD to point
230 to the next message! */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000231 if (buf->tail < buf->head) {
232 if ((buf->tail + l) >= buf->head) {
233 /* we need to move the HEAD to point to the next message
234 * Theoretically we have enough room to add the whole message to the
235 * buffer, because of the first outer IF statement, so we don't have
236 * to worry about overflows here!
237 */
238 int k = buf->tail + l - buf->head; /* we need to know how many bytes
239 we are overwriting to make
240 enough room */
241 char *c =
242 memchr(buf->data + buf->head + k, '\0',
243 buf->size - (buf->head + k));
244 if (c != NULL) { /* do a sanity check just in case! */
245 buf->head = c - buf->data + 1; /* we need to convert pointer to
246 offset + skip the '\0' since
247 we need to point to the beginning
248 of the next message */
249 /* Note: HEAD is only used to "retrieve" messages, it's not used
250 when writing messages into our buffer */
251 } else { /* show an error message to know we messed up? */
252 printf("Weird! Can't find the terminator token??? \n");
253 buf->head = 0;
254 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000255 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000256 }
Mark Whitley6317c4b2001-03-12 22:51:50 +0000257
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000258 /* in other cases no overflows have been done yet, so we don't care! */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000259 /* we should be ok to append the message now */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000260 strncpy(buf->data + buf->tail, msg, l); /* append our message */
261 buf->tail += l; /* count full message w/ '\0' terminating char */
262 } else {
Mark Whitley6317c4b2001-03-12 22:51:50 +0000263 /* we need to break up the message and "circle" it around */
264 char *c;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000265 int k = buf->tail + l - buf->size; /* count # of bytes we don't fit */
Eric Andersen871d93c2002-09-17 20:06:29 +0000266
Mark Whitley6317c4b2001-03-12 22:51:50 +0000267 /* We need to move HEAD! This is always the case since we are going
268 * to "circle" the message.
269 */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000270 c = memchr(buf->data + k, '\0', buf->size - k);
Eric Andersen871d93c2002-09-17 20:06:29 +0000271
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000272 if (c != NULL) { /* if we don't have '\0'??? weird!!! */
273 /* move head pointer */
274 buf->head = c - buf->data + 1;
Eric Andersen871d93c2002-09-17 20:06:29 +0000275
276 /* now write the first part of the message */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000277 strncpy(buf->data + buf->tail, msg, l - k - 1);
Eric Andersen871d93c2002-09-17 20:06:29 +0000278
Mark Whitley6317c4b2001-03-12 22:51:50 +0000279 /* ALWAYS terminate end of buffer w/ '\0' */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000280 buf->data[buf->size - 1] = '\0';
Eric Andersen871d93c2002-09-17 20:06:29 +0000281
Mark Whitley6317c4b2001-03-12 22:51:50 +0000282 /* now write out the rest of the string to the beginning of the buffer */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000283 strcpy(buf->data, &msg[l - k - 1]);
Mark Whitley6317c4b2001-03-12 22:51:50 +0000284
285 /* we need to place the TAIL at the end of the message */
286 buf->tail = k + 1;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000287 } else {
288 printf
289 ("Weird! Can't find the terminator token from the beginning??? \n");
290 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */
Mark Whitley6317c4b2001-03-12 22:51:50 +0000291 }
Eric Andersen871d93c2002-09-17 20:06:29 +0000292
Mark Whitley6317c4b2001-03-12 22:51:50 +0000293 }
294 sem_up(s_semid);
295}
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000296#endif /* CONFIG_FEATURE_IPC_SYSLOG */
Eric Andersen871d93c2002-09-17 20:06:29 +0000297
Erik Andersenc053e412000-03-21 01:31:24 +0000298/* Note: There is also a function called "message()" in init.c */
Erik Andersen983b51b2000-04-04 18:14:25 +0000299/* Print a message to the log file. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000300static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
301static void message(char *fmt, ...)
Eric Andersen3843e961999-11-25 07:30:46 +0000302{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000303 int fd;
Erik Andersene3ed1562000-04-19 18:52:56 +0000304 struct flock fl;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000305 va_list arguments;
Eric Andersen3843e961999-11-25 07:30:46 +0000306
Erik Andersene3ed1562000-04-19 18:52:56 +0000307 fl.l_whence = SEEK_SET;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000308 fl.l_start = 0;
309 fl.l_len = 1;
Erik Andersene3ed1562000-04-19 18:52:56 +0000310
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000311#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000312 if ((circular_logging == TRUE) && (buf != NULL)) {
313 char b[1024];
Mark Whitley6317c4b2001-03-12 22:51:50 +0000314
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000315 va_start(arguments, fmt);
316 vsnprintf(b, sizeof(b) - 1, fmt, arguments);
317 va_end(arguments);
318 circ_message(b);
319
320 } else
Mark Whitley6317c4b2001-03-12 22:51:50 +0000321#endif
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000322 if ((fd = device_open(logFilePath,
323 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000324 O_NONBLOCK)) >= 0) {
Erik Andersene3ed1562000-04-19 18:52:56 +0000325 fl.l_type = F_WRLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000326 fcntl(fd, F_SETLKW, &fl);
Eric Andersen29c77f72003-10-09 09:43:18 +0000327#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
328 if ( logFileSize > 0 ) {
329 struct stat statf;
330 int r = fstat(fd, &statf);
331 if( !r && (statf.st_mode & S_IFREG)
332 && (lseek(fd,0,SEEK_END) > logFileSize) ) {
333 if(logFileRotate > 0) {
334 int i;
Eric Andersen2c6b4182005-09-12 19:16:11 +0000335 char oldFile[(strlen(logFilePath)+4)], newFile[(strlen(logFilePath)+4)];
Eric Andersen29c77f72003-10-09 09:43:18 +0000336 for(i=logFileRotate-1;i>0;i--) {
337 sprintf(oldFile, "%s.%d", logFilePath, i-1);
338 sprintf(newFile, "%s.%d", logFilePath, i);
339 rename(oldFile, newFile);
340 }
341 sprintf(newFile, "%s.%d", logFilePath, 0);
342 fl.l_type = F_UNLCK;
343 fcntl (fd, F_SETLKW, &fl);
344 close(fd);
345 rename(logFilePath, newFile);
346 fd = device_open (logFilePath,
347 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
348 O_NONBLOCK);
349 fl.l_type = F_WRLCK;
350 fcntl (fd, F_SETLKW, &fl);
351 } else {
352 ftruncate( fd, 0 );
353 }
354 }
355 }
356#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000357 va_start(arguments, fmt);
358 vdprintf(fd, fmt, arguments);
359 va_end(arguments);
Erik Andersene3ed1562000-04-19 18:52:56 +0000360 fl.l_type = F_UNLCK;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000361 fcntl(fd, F_SETLKW, &fl);
362 close(fd);
Eric Andersen3843e961999-11-25 07:30:46 +0000363 } else {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000364 /* Always send console messages to /dev/console so people will see them. */
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000365 if ((fd = device_open(_PATH_CONSOLE,
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000366 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) {
367 va_start(arguments, fmt);
368 vdprintf(fd, fmt, arguments);
369 va_end(arguments);
370 close(fd);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000371 } else {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000372 fprintf(stderr, "Bummer, can't print: ");
373 va_start(arguments, fmt);
374 vfprintf(stderr, fmt, arguments);
375 fflush(stderr);
376 va_end(arguments);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000377 }
Eric Andersen3843e961999-11-25 07:30:46 +0000378 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000379}
380
Eric Andersenf91b9282004-09-08 10:56:06 +0000381#ifdef CONFIG_FEATURE_REMOTE_LOG
382static void init_RemoteLog(void)
383{
384 memset(&remoteaddr, 0, sizeof(remoteaddr));
385 remotefd = socket(AF_INET, SOCK_DGRAM, 0);
386
387 if (remotefd < 0) {
388 bb_error_msg("cannot create socket");
389 }
390
391 remoteaddr.sin_family = AF_INET;
392 remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list;
393 remoteaddr.sin_port = htons(RemotePort);
394}
395#endif
396
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000397static void logMessage(int pri, char *msg)
Eric Andersen3843e961999-11-25 07:30:46 +0000398{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000399 time_t now;
400 char *timestamp;
"Vladimir N. Oleynik"d3d829a2005-10-15 14:24:01 +0000401 static char res[20];
Eric Andersen192c35f2004-09-02 22:22:17 +0000402#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersenf91b9282004-09-08 10:56:06 +0000403 static char line[MAXLINE + 1];
Eric Andersen192c35f2004-09-02 22:22:17 +0000404#endif
Erik Andersene49d5ec2000-02-08 19:58:47 +0000405 CODE *c_pri, *c_fac;
Eric Andersenb99df0f1999-11-24 09:04:33 +0000406
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000407 if (pri != 0) {
408 for (c_fac = facilitynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000409 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++);
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000410 for (c_pri = prioritynames;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000411 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++);
412 if (c_fac->c_name == NULL || c_pri->c_name == NULL) {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000413 snprintf(res, sizeof(res), "<%d>", pri);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000414 } else {
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000415 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000416 }
Erik Andersen9ffdaa62000-02-11 21:55:04 +0000417 }
Eric Andersen3843e961999-11-25 07:30:46 +0000418
Erik Andersene49d5ec2000-02-08 19:58:47 +0000419 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' ||
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000420 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') {
Erik Andersene49d5ec2000-02-08 19:58:47 +0000421 time(&now);
422 timestamp = ctime(&now) + 4;
423 timestamp[15] = '\0';
424 } else {
425 timestamp = msg;
426 timestamp[15] = '\0';
427 msg += 16;
428 }
Eric Andersen3843e961999-11-25 07:30:46 +0000429
Erik Andersene49d5ec2000-02-08 19:58:47 +0000430 /* todo: supress duplicates */
Eric Andersen3843e961999-11-25 07:30:46 +0000431
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000432#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000433 if (doRemoteLog == TRUE) {
434 /* trying connect the socket */
435 if (-1 == remotefd) {
436 init_RemoteLog();
437 }
Eric Andersenced2cef2000-07-20 23:41:24 +0000438
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000439 /* if we have a valid socket, send the message */
440 if (-1 != remotefd) {
441 now = 1;
Paul Fox27cbffd2005-07-20 18:02:11 +0000442 snprintf(line, sizeof(line), "<%d>%s", pri, msg);
Eric Andersenced2cef2000-07-20 23:41:24 +0000443
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000444 retry:
445 /* send message to remote logger */
446 if(( -1 == sendto(remotefd, line, strlen(line), 0,
447 (struct sockaddr *) &remoteaddr,
448 sizeof(remoteaddr))) && (errno == EINTR)) {
449 /* sleep now seconds and retry (with now * 2) */
450 sleep(now);
451 now *= 2;
452 goto retry;
453 }
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000454 }
455 }
Glenn L McGrath73ebb882004-09-14 18:12:13 +0000456
Eric Andersen871d93c2002-09-17 20:06:29 +0000457 if (local_logging == TRUE)
Eric Andersenced2cef2000-07-20 23:41:24 +0000458#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000459 {
Eric Andersenbf2b8ae2000-12-08 19:52:01 +0000460 /* now spew out the message to wherever it is supposed to go */
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000461 if (small)
462 message("%s %s\n", timestamp, msg);
463 else
464 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg);
465 }
Eric Andersen3843e961999-11-25 07:30:46 +0000466}
467
468static void quit_signal(int sig)
469{
Eric Andersen238bc402001-05-07 17:55:05 +0000470 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting.");
Erik Andersen983b51b2000-04-04 18:14:25 +0000471 unlink(lfile);
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000472#ifdef CONFIG_FEATURE_IPC_SYSLOG
Mark Whitley6317c4b2001-03-12 22:51:50 +0000473 ipcsyslog_cleanup();
474#endif
475
Erik Andersene49d5ec2000-02-08 19:58:47 +0000476 exit(TRUE);
Eric Andersen3843e961999-11-25 07:30:46 +0000477}
478
Eric Andersen3843e961999-11-25 07:30:46 +0000479static void domark(int sig)
480{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000481 if (MarkInterval > 0) {
482 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --");
483 alarm(MarkInterval);
484 }
Eric Andersen3843e961999-11-25 07:30:46 +0000485}
486
Eric Andersene5272072003-07-22 22:15:21 +0000487/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are
Eric Andersen22ecf042001-07-02 17:32:40 +0000488 * enabled, we otherwise get a "storage size isn't constant error. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000489static int serveConnection(char *tmpbuf, int n_read)
Pavel Roskinda10ec02000-06-07 21:08:25 +0000490{
Matt Kraaib6ec7812001-08-14 17:32:23 +0000491 char *p = tmpbuf;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000492
Matt Kraaib6ec7812001-08-14 17:32:23 +0000493 while (p < tmpbuf + n_read) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000494
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000495 int pri = (LOG_USER | LOG_NOTICE);
Eric Andersend4f90ed2003-05-23 09:28:01 +0000496 int num_lt = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000497 char line[MAXLINE + 1];
Pavel Roskinda10ec02000-06-07 21:08:25 +0000498 unsigned char c;
Matt Kraaib6ec7812001-08-14 17:32:23 +0000499 char *q = line;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000500
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000501 while ((c = *p) && q < &line[sizeof(line) - 1]) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000502 if (c == '<' && num_lt == 0) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000503 /* Parse the magic priority number. */
Eric Andersend4f90ed2003-05-23 09:28:01 +0000504 num_lt++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000505 pri = 0;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000506 while (isdigit(*(++p))) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000507 pri = 10 * pri + (*p - '0');
508 }
Eric Andersen46ba5682003-05-23 09:29:57 +0000509 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
Eric Andersend4f90ed2003-05-23 09:28:01 +0000510 pri = (LOG_USER | LOG_NOTICE);
Eric Andersen46ba5682003-05-23 09:29:57 +0000511 }
Pavel Roskinda10ec02000-06-07 21:08:25 +0000512 } else if (c == '\n') {
513 *q++ = ' ';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000514 } else if (iscntrl(c) && (c < 0177)) {
Pavel Roskinda10ec02000-06-07 21:08:25 +0000515 *q++ = '^';
516 *q++ = c ^ 0100;
517 } else {
518 *q++ = c;
519 }
520 p++;
521 }
522 *q = '\0';
Matt Kraaib6ec7812001-08-14 17:32:23 +0000523 p++;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000524 /* Now log it */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000525 logMessage(pri, line);
Pavel Roskinda10ec02000-06-07 21:08:25 +0000526 }
Mark Whitleybff6b182001-03-27 20:17:58 +0000527 return n_read;
Pavel Roskinda10ec02000-06-07 21:08:25 +0000528}
529
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000530static void doSyslogd(void) __attribute__ ((noreturn));
531static void doSyslogd(void)
Eric Andersen3843e961999-11-25 07:30:46 +0000532{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000533 struct sockaddr_un sunx;
Erik Andersen1d1d9502000-04-21 01:26:49 +0000534 socklen_t addrLength;
535
Erik Andersen983b51b2000-04-04 18:14:25 +0000536 int sock_fd;
Erik Andersenf13df372000-04-18 23:51:51 +0000537 fd_set fds;
538
Erik Andersenf13df372000-04-18 23:51:51 +0000539 /* Set up signal handlers. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000540 signal(SIGINT, quit_signal);
541 signal(SIGTERM, quit_signal);
542 signal(SIGQUIT, quit_signal);
543 signal(SIGHUP, SIG_IGN);
544 signal(SIGCHLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000545#ifdef SIGCLD
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000546 signal(SIGCLD, SIG_IGN);
Pavel Roskind39d1202000-09-13 14:14:29 +0000547#endif
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000548 signal(SIGALRM, domark);
549 alarm(MarkInterval);
Eric Andersenb99df0f1999-11-24 09:04:33 +0000550
Erik Andersenf13df372000-04-18 23:51:51 +0000551 /* Create the syslog file so realpath() can work. */
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000552 if (realpath(_PATH_LOG, lfile) != NULL) {
553 unlink(lfile);
554 }
Erik Andersen983b51b2000-04-04 18:14:25 +0000555
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000556 memset(&sunx, 0, sizeof(sunx));
Erik Andersen983b51b2000-04-04 18:14:25 +0000557 sunx.sun_family = AF_UNIX;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000558 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path));
559 if ((sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000560 bb_perror_msg_and_die("Couldn't get file descriptor for socket "
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000561 _PATH_LOG);
562 }
Eric Andersenb99df0f1999-11-24 09:04:33 +0000563
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000564 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
565 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000566 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000567 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000568
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000569 if (chmod(lfile, 0666) < 0) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000570 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000571 }
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000572#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000573 if (circular_logging == TRUE) {
574 ipcsyslog_init();
Eric Andersenea906502001-04-05 20:55:17 +0000575 }
576#endif
577
Eric Andersen871d93c2002-09-17 20:06:29 +0000578#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000579 if (doRemoteLog == TRUE) {
580 init_RemoteLog();
Eric Andersen871d93c2002-09-17 20:06:29 +0000581 }
582#endif
Eric Andersenced2cef2000-07-20 23:41:24 +0000583
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000584 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " BB_BANNER);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000585
Erik Andersen983b51b2000-04-04 18:14:25 +0000586 for (;;) {
Erik Andersenf13df372000-04-18 23:51:51 +0000587
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000588 FD_ZERO(&fds);
589 FD_SET(sock_fd, &fds);
Erik Andersenf13df372000-04-18 23:51:51 +0000590
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000591 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) {
Eric Andersen871d93c2002-09-17 20:06:29 +0000592 if (errno == EINTR) {
593 /* alarm may have happened. */
594 continue;
595 }
Manuel Novoa III cad53642003-03-19 09:13:01 +0000596 bb_perror_msg_and_die("select error");
Erik Andersene49d5ec2000-02-08 19:58:47 +0000597 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000598
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000599 if (FD_ISSET(sock_fd, &fds)) {
600 int i;
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000601#if MAXLINE > BUFSIZ
602# define TMP_BUF_SZ BUFSIZ
603#else
604# define TMP_BUF_SZ MAXLINE
605#endif
606#define tmpbuf bb_common_bufsiz1
Erik Andersene3ed1562000-04-19 18:52:56 +0000607
"Vladimir N. Oleynik"b32b1db2005-10-15 13:49:21 +0000608 if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) {
609 tmpbuf[i] = '\0';
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000610 serveConnection(tmpbuf, i);
611 } else {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000612 bb_perror_msg_and_die("UNIX socket error");
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000613 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000614 } /* FD_ISSET() */
615 } /* for main loop */
Eric Andersenb99df0f1999-11-24 09:04:33 +0000616}
617
Eric Andersen3843e961999-11-25 07:30:46 +0000618extern int syslogd_main(int argc, char **argv)
619{
Eric Andersene5c24df2001-03-29 21:58:33 +0000620 int opt;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000621
Erik Andersene49d5ec2000-02-08 19:58:47 +0000622 int doFork = TRUE;
623
Erik Andersene49d5ec2000-02-08 19:58:47 +0000624 char *p;
Erik Andersene49d5ec2000-02-08 19:58:47 +0000625
Eric Andersen394cf222000-12-11 16:48:50 +0000626 /* do normal option parsing */
Glenn L McGrath5529b7b2004-07-22 04:23:18 +0000627 while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) {
Eric Andersen394cf222000-12-11 16:48:50 +0000628 switch (opt) {
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000629 case 'm':
630 MarkInterval = atoi(optarg) * 60;
631 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000632 case 'n':
633 doFork = FALSE;
634 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000635 case 'O':
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000636 logFilePath = optarg;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000637 break;
Eric Andersen29c77f72003-10-09 09:43:18 +0000638#ifdef CONFIG_FEATURE_ROTATE_LOGFILE
639 case 's':
640 logFileSize = atoi(optarg) * 1024;
641 break;
642 case 'b':
643 logFileRotate = atoi(optarg);
644 if( logFileRotate > 99 ) logFileRotate = 99;
645 break;
646#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000647#ifdef CONFIG_FEATURE_REMOTE_LOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000648 case 'R':
Manuel Novoa III cad53642003-03-19 09:13:01 +0000649 RemoteHost = bb_xstrdup(optarg);
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000650 if ((p = strchr(RemoteHost, ':'))) {
651 RemotePort = atoi(p + 1);
652 *p = '\0';
653 }
654 doRemoteLog = TRUE;
655 break;
656 case 'L':
657 local_logging = TRUE;
658 break;
Eric Andersenced2cef2000-07-20 23:41:24 +0000659#endif
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000660#ifdef CONFIG_FEATURE_IPC_SYSLOG
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000661 case 'C':
Glenn L McGratha79220d2003-09-26 00:49:05 +0000662 if (optarg) {
663 int buf_size = atoi(optarg);
664 if (buf_size >= 4) {
Glenn L McGrathdf2c5652004-02-22 12:17:33 +0000665 shm_size = buf_size * 1024;
Glenn L McGratha79220d2003-09-26 00:49:05 +0000666 }
667 }
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000668 circular_logging = TRUE;
669 break;
Mark Whitley6317c4b2001-03-12 22:51:50 +0000670#endif
Eric Andersen7f94a5c2004-06-22 10:12:59 +0000671 case 'S':
672 small = true;
673 break;
Glenn L McGrath912d8f42002-11-10 22:46:45 +0000674 default:
Manuel Novoa III cad53642003-03-19 09:13:01 +0000675 bb_show_usage();
Eric Andersen3843e961999-11-25 07:30:46 +0000676 }
Erik Andersene49d5ec2000-02-08 19:58:47 +0000677 }
678
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000679#ifdef CONFIG_FEATURE_REMOTE_LOG
Eric Andersen4ed17822000-12-11 19:28:29 +0000680 /* If they have not specified remote logging, then log locally */
Eric Andersen871d93c2002-09-17 20:06:29 +0000681 if (doRemoteLog == FALSE)
Eric Andersen4ed17822000-12-11 19:28:29 +0000682 local_logging = TRUE;
683#endif
684
Mark Whitley6317c4b2001-03-12 22:51:50 +0000685
Erik Andersene49d5ec2000-02-08 19:58:47 +0000686 /* Store away localhost's name before the fork */
687 gethostname(LocalHostName, sizeof(LocalHostName));
688 if ((p = strchr(LocalHostName, '.'))) {
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000689 *p = '\0';
Erik Andersene49d5ec2000-02-08 19:58:47 +0000690 }
691
Erik Andersen983b51b2000-04-04 18:14:25 +0000692 umask(0);
693
Glenn L McGrathfe538ba2003-09-10 23:35:45 +0000694 if (doFork == TRUE) {
Glenn L McGrathdc72f3a2003-08-29 07:35:08 +0000695#if defined(__uClinux__)
Russ Dilla1fece22003-12-15 21:57:44 +0000696 vfork_daemon_rexec(0, 1, argc, argv, "-n");
697#else /* __uClinux__ */
698 if(daemon(0, 1) < 0)
699 bb_perror_msg_and_die("daemon");
700#endif /* __uClinux__ */
Eric Andersen35e643b2003-07-28 07:40:39 +0000701 }
Eric Andersene5c24df2001-03-29 21:58:33 +0000702 doSyslogd();
Eric Andersenb186d981999-12-03 09:19:54 +0000703
Matt Kraai3e856ce2000-12-01 02:55:13 +0000704 return EXIT_SUCCESS;
Eric Andersen3843e961999-11-25 07:30:46 +0000705}
Erik Andersen983b51b2000-04-04 18:14:25 +0000706
707/*
Erik Andersene3ed1562000-04-19 18:52:56 +0000708Local Variables
709c-file-style: "linux"
710c-basic-offset: 4
711tab-width: 4
712End:
713*/