aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-01-04 17:57:54 +0000
committervda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277>2007-01-04 17:57:54 +0000
commit80ca649fe760637073cb024f3cd2350f61d37b39 (patch)
treea5ca6a3ec0baf8a9c0417453b489aa79f9c8c95a
parent56cdfc5fdad7ed966cd926657773f20a8a6781e4 (diff)
downloadbusybox-w32-80ca649fe760637073cb024f3cd2350f61d37b39.tar.gz
busybox-w32-80ca649fe760637073cb024f3cd2350f61d37b39.tar.bz2
busybox-w32-80ca649fe760637073cb024f3cd2350f61d37b39.zip
syslogd: almost rewritten. Had several obvious bugs...
git-svn-id: svn://busybox.net/trunk/busybox@17155 69ca8d6d-28ef-0310-b511-8ec308f3f277
-rw-r--r--sysklogd/syslogd.c590
1 files changed, 263 insertions, 327 deletions
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 453cbda35..9e4bc63c2 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -15,7 +15,6 @@
15 15
16#include "busybox.h" 16#include "busybox.h"
17#include <paths.h> 17#include <paths.h>
18#include <stdbool.h>
19#include <sys/un.h> 18#include <sys/un.h>
20 19
21/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */ 20/* SYSLOG_NAMES defined to pull some extra junk from syslog.h */
@@ -24,36 +23,39 @@
24#include <sys/uio.h> 23#include <sys/uio.h>
25 24
26/* Path to the unix socket */ 25/* Path to the unix socket */
27static char lfile[MAXPATHLEN]; 26static char dev_log_name[MAXPATHLEN];
28 27
29/* Path for the file where all log messages are written */ 28/* Path for the file where all log messages are written */
30static const char *logFilePath = "/var/log/messages"; 29static const char *logFilePath = "/var/log/messages";
31 30
32#ifdef CONFIG_FEATURE_ROTATE_LOGFILE 31#if ENABLE_FEATURE_ROTATE_LOGFILE
33/* max size of message file before being rotated */ 32/* max size of message file before being rotated */
34static int logFileSize = 200 * 1024; 33static int logFileSize = 200 * 1024;
35
36/* number of rotated message files */ 34/* number of rotated message files */
37static int logFileRotate = 1; 35static int logFileRotate = 1;
38#endif 36#endif
39 37
40/* interval between marks in seconds */ 38/* interval between marks in seconds */
41static int MarkInterval = 20 * 60; 39static int markInterval = 20 * 60;
42 40
43/* level of messages to be locally logged */ 41/* level of messages to be locally logged */
44static int logLevel = 8; 42static int logLevel = 8;
45 43
46/* localhost's name */ 44/* localhost's name */
47static char LocalHostName[64]; 45static char localHostName[64];
48 46
49#ifdef CONFIG_FEATURE_REMOTE_LOG 47#if ENABLE_FEATURE_REMOTE_LOG
50#include <netinet/in.h> 48#include <netinet/in.h>
51/* udp socket for logging to remote host */ 49/* udp socket for logging to remote host */
52static int remotefd = -1; 50static int remoteFD = -1;
53static struct sockaddr_in remoteaddr; 51static struct sockaddr_in remoteAddr;
54
55#endif 52#endif
56 53
54
55/* NB: we may need 2x this amount on stack... */
56enum { MAX_READ = 1024 };
57
58
57/* options */ 59/* options */
58/* Correct regardless of combination of CONFIG_xxx */ 60/* Correct regardless of combination of CONFIG_xxx */
59enum { 61enum {
@@ -96,10 +98,10 @@ enum {
96 USE_FEATURE_REMOTE_LOG( ,&opt_R) \ 98 USE_FEATURE_REMOTE_LOG( ,&opt_R) \
97 USE_FEATURE_IPC_SYSLOG( ,&opt_C) 99 USE_FEATURE_IPC_SYSLOG( ,&opt_C)
98 100
99#define MAXLINE 1024 /* maximum line length */
100 101
101/* circular buffer variables/structures */ 102/* circular buffer variables/structures */
102#ifdef CONFIG_FEATURE_IPC_SYSLOG 103#if ENABLE_FEATURE_IPC_SYSLOG
104
103 105
104#if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4 106#if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4
105#error Sorry, you must set the syslogd buffer size to at least 4KB. 107#error Sorry, you must set the syslogd buffer size to at least 4KB.
@@ -115,14 +117,11 @@ enum {
115 117
116// Semaphore operation structures 118// Semaphore operation structures
117static struct shbuf_ds { 119static struct shbuf_ds {
118 int size; // size of data written 120 int32_t size; // size of data written
119 int head; // start of message list 121 int32_t head; // start of message list
120 int tail; // end of message list 122 int32_t tail; // end of message list
121 char data[1]; // data/messages 123 char data[1]; // data/messages
122} *shbuf = NULL; // shared memory pointer 124} *shbuf; // shared memory pointer
123
124static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup
125static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn
126 125
127static int shmid = -1; // ipc shared memory id 126static int shmid = -1; // ipc shared memory id
128static int s_semid = -1; // ipc semaphore id 127static int s_semid = -1; // ipc semaphore id
@@ -130,11 +129,9 @@ static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024); // default
130 129
131static void ipcsyslog_cleanup(void) 130static void ipcsyslog_cleanup(void)
132{ 131{
133 puts("Exiting syslogd!");
134 if (shmid != -1) { 132 if (shmid != -1) {
135 shmdt(shbuf); 133 shmdt(shbuf);
136 } 134 }
137
138 if (shmid != -1) { 135 if (shmid != -1) {
139 shmctl(shmid, IPC_RMID, NULL); 136 shmctl(shmid, IPC_RMID, NULL);
140 } 137 }
@@ -145,359 +142,299 @@ static void ipcsyslog_cleanup(void)
145 142
146static void ipcsyslog_init(void) 143static void ipcsyslog_init(void)
147{ 144{
148 if (shbuf == NULL) { 145 shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023);
149 shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023); 146 if (shmid == -1) {
150 if (shmid == -1) { 147 bb_perror_msg_and_die("shmget");
151 bb_perror_msg_and_die("shmget"); 148 }
152 }
153 149
154 shbuf = shmat(shmid, NULL, 0); 150 shbuf = shmat(shmid, NULL, 0);
155 if (!shbuf) { 151 if (!shbuf) {
156 bb_perror_msg_and_die("shmat"); 152 bb_perror_msg_and_die("shmat");
157 } 153 }
158 154
159 shbuf->size = shm_size - sizeof(*shbuf); 155 shbuf->size = shm_size - offsetof(struct shbuf_ds, data);
160 shbuf->head = shbuf->tail = 0; 156 shbuf->head = shbuf->tail = 0;
161 157
162 // we'll trust the OS to set initial semval to 0 (let's hope) 158 // we'll trust the OS to set initial semval to 0 (let's hope)
163 s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023); 159 s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023);
164 if (s_semid == -1) { 160 if (s_semid == -1) {
165 if (errno == EEXIST) { 161 if (errno == EEXIST) {
166 s_semid = semget(KEY_ID, 2, 0); 162 s_semid = semget(KEY_ID, 2, 0);
167 if (s_semid == -1) { 163 if (s_semid != -1)
168 bb_perror_msg_and_die("semget"); 164 return;
169 }
170 } else {
171 bb_perror_msg_and_die("semget");
172 }
173 } 165 }
174 } else { 166 bb_perror_msg_and_die("semget");
175 printf("Buffer already allocated just grab the semaphore?");
176 } 167 }
177} 168}
178 169
179/* write message to buffer */ 170/* write message to buffer */
180static void circ_message(const char *msg) 171static void log_to_shmem(const char *msg, int len)
181{ 172{
182 int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */ 173 static /*const*/ struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} };
183 const char * const fail_msg = "Can't find the terminator token%s?\n"; 174 static /*const*/ struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} };
175
176 int old_tail, new_tail;
177 char *c;
184 178
185 if (semop(s_semid, SMwdn, 3) == -1) { 179 if (semop(s_semid, SMwdn, 3) == -1) {
186 bb_perror_msg_and_die("SMwdn"); 180 bb_perror_msg_and_die("SMwdn");
187 } 181 }
188 182
189 /* 183 /* Circular Buffer Algorithm:
190 * Circular Buffer Algorithm:
191 * -------------------------- 184 * --------------------------
192 * 185 * tail == position where to store next syslog message.
193 * Start-off w/ empty buffer of specific size SHM_SIZ 186 * head == position of next message to retrieve ("print").
194 * Start filling it up w/ messages. I use '\0' as separator to break up messages. 187 * if head == tail, there is no "unprinted" messages left.
195 * This is also very handy since we can do printf on message. 188 * head is typically advanced by separate "reader" program,
196 * 189 * but if there isn't one, we have to do it ourself.
197 * Once the buffer is full we need to get rid of the first message in buffer and 190 * messages are NUL-separated.
198 * insert the new message. (Note: if the message being added is >1 message then
199 * we will need to "remove" >1 old message from the buffer). The way this is done
200 * is the following:
201 * When we reach the end of the buffer we set a mark and start from the beginning.
202 * Now what about the beginning and end of the buffer? Well we have the "head"
203 * index/pointer which is the starting point for the messages and we have "tail"
204 * index/pointer which is the ending point for the messages. When we "display" the
205 * messages we start from the beginning and continue until we reach "tail". If we
206 * reach end of buffer, then we just start from the beginning (offset 0). "head" and
207 * "tail" are actually offsets from the beginning of the buffer.
208 *
209 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide
210 * a threadsafe way of handling shared memory operations.
211 */ 191 */
212 if ((shbuf->tail + l) < shbuf->size) { 192 len++; /* length with NUL included */
213 /* before we append the message we need to check the HEAD so that we won't 193 again:
214 overwrite any of the message that we still need and adjust HEAD to point 194 old_tail = shbuf->tail;
215 to the next message! */ 195 new_tail = old_tail + len;
216 if (shbuf->tail < shbuf->head) { 196 if (new_tail < shbuf->size) {
217 if ((shbuf->tail + l) >= shbuf->head) { 197 /* No need to move head if shbuf->head <= old_tail,
218 /* we need to move the HEAD to point to the next message 198 * else... */
219 * Theoretically we have enough room to add the whole message to the 199 if (old_tail < shbuf->head && shbuf->head <= new_tail) {
220 * buffer, because of the first outer IF statement, so we don't have 200 /* ...need to move head forward */
221 * to worry about overflows here! 201 c = memchr(shbuf->data + new_tail, '\0',
222 */ 202 shbuf->size - new_tail);
223 /* we need to know how many bytes we are overwriting to make enough room */ 203 if (!c) /* no NUL ahead of us, wrap around */
224 int k = shbuf->tail + l - shbuf->head; 204 c = memchr(shbuf->data, '\0', old_tail);
225 char *c = 205 if (!c) { /* still nothing? point to this msg... */
226 memchr(shbuf->data + shbuf->head + k, '\0', 206 shbuf->head = old_tail;
227 shbuf->size - (shbuf->head + k)); 207 } else {
228 if (c != NULL) { /* do a sanity check just in case! */ 208 /* convert pointer to offset + skip NUL */
229 /* we need to convert pointer to offset + skip the '\0' 209 shbuf->head = c - shbuf->data + 1;
230 since we need to point to the beginning of the next message */
231 shbuf->head = c - shbuf->data + 1;
232 /* Note: HEAD is only used to "retrieve" messages, it's not used
233 when writing messages into our buffer */
234 } else { /* show an error message to know we messed up? */
235 printf(fail_msg,"");
236 shbuf->head = 0;
237 }
238 } 210 }
239 } 211 }
240 212 /* store message, set new tail */
241 /* in other cases no overflows have been done yet, so we don't care! */ 213 memcpy(shbuf->data + old_tail, msg, len);
242 /* we should be ok to append the message now */ 214 shbuf->tail = new_tail;
243 strncpy(shbuf->data + shbuf->tail, msg, l); /* append our message */
244 shbuf->tail += l; /* count full message w/ '\0' terminating char */
245 } else { 215 } else {
246 /* we need to break up the message and "circle" it around */ 216 /* we need to break up the message and wrap it around */
247 char *c; 217 /* k == available buffer space ahead of old tail */
248 int k = shbuf->tail + l - shbuf->size; /* count # of bytes we don't fit */ 218 int k = shbuf->size - old_tail - 1;
249 219 if (shbuf->head > old_tail) {
250 /* We need to move HEAD! This is always the case since we are going 220 /* we are going to overwrite head, need to
251 * to "circle" the message. */ 221 * move it out of the way */
252 c = memchr(shbuf->data + k, '\0', shbuf->size - k); 222 c = memchr(shbuf->data, '\0', old_tail);
253 223 if (!c) { /* nothing? point to this msg... */
254 if (c != NULL) { /* if we don't have '\0'??? weird!!! */ 224 shbuf->head = old_tail;
255 /* move head pointer */ 225 } else { /* convert pointer to offset + skip NUL */
256 shbuf->head = c - shbuf->data + 1; 226 shbuf->head = c - shbuf->data + 1;
257 227 }
258 /* now write the first part of the message */
259 strncpy(shbuf->data + shbuf->tail, msg, l - k - 1);
260
261 /* ALWAYS terminate end of buffer w/ '\0' */
262 shbuf->data[shbuf->size - 1] = '\0';
263
264 /* now write out the rest of the string to the beginning of the buffer */
265 strcpy(shbuf->data, &msg[l - k - 1]);
266
267 /* we need to place the TAIL at the end of the message */
268 shbuf->tail = k + 1;
269 } else {
270 printf(fail_msg, " from the beginning");
271 shbuf->head = shbuf->tail = 0; /* reset buffer, since it's probably corrupted */
272 } 228 }
273 229 /* copy what fits to the end of buffer, and repeat */
230 memcpy(shbuf->data + old_tail, msg, k);
231 msg += k;
232 len -= k;
233 shbuf->tail = 0;
234 goto again;
274 } 235 }
275 if (semop(s_semid, SMwup, 1) == -1) { 236 if (semop(s_semid, SMwup, 1) == -1) {
276 bb_perror_msg_and_die("SMwup"); 237 bb_perror_msg_and_die("SMwup");
277 } 238 }
278
279} 239}
280#else 240#else
281void ipcsyslog_cleanup(void); 241void ipcsyslog_cleanup(void);
282void ipcsyslog_init(void); 242void ipcsyslog_init(void);
283void circ_message(const char *msg); 243void log_to_shmem(const char *msg);
284#endif /* CONFIG_FEATURE_IPC_SYSLOG */
285 244
286/* Note: There is also a function called "message()" in init.c */
287/* Print a message to the log file. */
288static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2)));
289static void message(char *fmt, ...)
290{
291 int fd = -1;
292 struct flock fl;
293 va_list arguments;
294 245
295 fl.l_whence = SEEK_SET; 246#endif /* FEATURE_IPC_SYSLOG */
296 fl.l_start = 0;
297 fl.l_len = 1;
298 247
299#ifdef CONFIG_FEATURE_IPC_SYSLOG
300 if ((option_mask32 & OPT_circularlog) && shbuf) {
301 char b[1024];
302 248
303 va_start(arguments, fmt); 249/* Print a message to the log file. */
304 vsnprintf(b, sizeof(b) - 1, fmt, arguments); 250static void log_locally(char *msg)
305 va_end(arguments); 251{
306 circ_message(b); 252 int fd, len = strlen(msg);
307 253
308 } else 254#if ENABLE_FEATURE_IPC_SYSLOG
255 if ((option_mask32 & OPT_circularlog) && shbuf) {
256 log_to_shmem(msg, len);
257 return;
258 }
309#endif 259#endif
260
261 again:
310 fd = device_open(logFilePath, O_WRONLY | O_CREAT 262 fd = device_open(logFilePath, O_WRONLY | O_CREAT
311 | O_NOCTTY | O_APPEND | O_NONBLOCK); 263 | O_NOCTTY | O_APPEND | O_NONBLOCK);
312 if (fd >= 0) { 264 if (fd >= 0) {
265 struct flock fl;
266
267 fl.l_whence = SEEK_SET;
268 fl.l_start = 0;
269 fl.l_len = 1;
313 fl.l_type = F_WRLCK; 270 fl.l_type = F_WRLCK;
314 fcntl(fd, F_SETLKW, &fl); 271 fcntl(fd, F_SETLKW, &fl);
315 272
316#ifdef CONFIG_FEATURE_ROTATE_LOGFILE 273#if ENABLE_FEATURE_ROTATE_LOGFILE
317 if (ENABLE_FEATURE_ROTATE_LOGFILE && logFileSize > 0 ) { 274 if (logFileSize) {
318 struct stat statf; 275 struct stat statf;
319 int r = fstat(fd, &statf); 276 int r = fstat(fd, &statf);
320 if (!r && (statf.st_mode & S_IFREG) 277 if (!r && (statf.st_mode & S_IFREG)
321 && (lseek(fd,0,SEEK_END) > logFileSize)) { 278 && (lseek(fd, 0, SEEK_END) > logFileSize)
322 if (logFileRotate > 0) { 279 ) {
323 int i = strlen(logFilePath) + 4; 280 if (logFileRotate) { /* always 0..99 */
281 int i = strlen(logFilePath) + 3 + 1;
324 char oldFile[i]; 282 char oldFile[i];
325 char newFile[i]; 283 char newFile[i];
326 for (i=logFileRotate-1; i>0; i--) { 284 i = logFileRotate - 1;
327 sprintf(oldFile, "%s.%d", logFilePath, i-1); 285 /* rename: f.8 -> f.9; f.7 -> f.8; ... */
286 while (1) {
328 sprintf(newFile, "%s.%d", logFilePath, i); 287 sprintf(newFile, "%s.%d", logFilePath, i);
288 if (i == 0) break;
289 sprintf(oldFile, "%s.%d", logFilePath, --i);
329 rename(oldFile, newFile); 290 rename(oldFile, newFile);
330 } 291 }
331 sprintf(newFile, "%s.%d", logFilePath, 0); 292 /* newFile == "f.0" now */
293 rename(logFilePath, newFile);
332 fl.l_type = F_UNLCK; 294 fl.l_type = F_UNLCK;
333 fcntl(fd, F_SETLKW, &fl); 295 fcntl(fd, F_SETLKW, &fl);
334 close(fd); 296 close(fd);
335 rename(logFilePath, newFile); 297 goto again;
336 fd = device_open(logFilePath,
337 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND |
338 O_NONBLOCK);
339 fl.l_type = F_WRLCK;
340 fcntl(fd, F_SETLKW, &fl);
341 } else {
342 ftruncate(fd, 0);
343 } 298 }
299 ftruncate(fd, 0);
344 } 300 }
345 } 301 }
346#endif 302#endif
347 va_start(arguments, fmt); 303 full_write(fd, msg, len);
348 vdprintf(fd, fmt, arguments);
349 va_end(arguments);
350 fl.l_type = F_UNLCK; 304 fl.l_type = F_UNLCK;
351 fcntl(fd, F_SETLKW, &fl); 305 fcntl(fd, F_SETLKW, &fl);
352 close(fd); 306 close(fd);
353 } else { 307 } else {
354 /* Always send console messages to /dev/console so people will see them. */ 308 /* cannot open logfile? - print to /dev/console then */
355 fd = device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK); 309 fd = device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK);
356 if (fd >= 0) { 310 if (fd < 0)
357 va_start(arguments, fmt); 311 fd = 2; /* then stderr, dammit */
358 vdprintf(fd, fmt, arguments); 312 full_write(fd, msg, len);
359 va_end(arguments); 313 if (fd != 2)
360 close(fd); 314 close(fd);
361 } else {
362 fprintf(stderr, "Bummer, can't print: ");
363 va_start(arguments, fmt);
364 vfprintf(stderr, fmt, arguments);
365 fflush(stderr);
366 va_end(arguments);
367 }
368 } 315 }
369} 316}
370 317
371static void logMessage(int pri, char *msg) 318static void parse_fac_prio_20(int pri, char *res20)
372{ 319{
373 time_t now;
374 char *timestamp;
375 char res[20];
376 CODE *c_pri, *c_fac; 320 CODE *c_pri, *c_fac;
377 321
378 if (pri != 0) { 322 if (pri != 0) {
379 c_fac = facilitynames; 323 c_fac = facilitynames;
380 while (c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3)) 324 while (c_fac->c_name) {
381 c_fac++; 325 if (c_fac->c_val != (LOG_FAC(pri) << 3)) {
382 c_pri = prioritynames; 326 c_fac++; continue;
383 while (c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri))) 327 }
384 c_pri++; 328 /* facility is found, look for prio */
385 if (c_fac->c_name == NULL || c_pri->c_name == NULL) { 329 c_pri = prioritynames;
386 snprintf(res, sizeof(res), "<%d>", pri); 330 while (c_pri->c_name) {
387 } else { 331 if (c_pri->c_val != LOG_PRI(pri)) {
388 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); 332 c_pri++; continue;
333 }
334 snprintf(res20, 20, "%s.%s",
335 c_fac->c_name, c_pri->c_name);
336 return;
337 }
338 /* prio not found, bail out */
339 break;
389 } 340 }
341 snprintf(res20, 20, "<%d>", pri);
390 } 342 }
343}
391 344
392 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || 345/* len parameter is used only for "is there a timestamp?" check
393 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') { 346 * NB: some callers cheat and supply 0 when they know
347 * that there is no timestamp, short-cutting the test */
348static void timestamp_and_log(int pri, char *msg, int len)
349{
350 time_t now;
351 char *timestamp;
352
353 if (len < 16 || msg[3] != ' ' || msg[6] != ' '
354 || msg[9] != ':' || msg[12] != ':' || msg[15] != ' '
355 ) {
394 time(&now); 356 time(&now);
395 timestamp = ctime(&now) + 4; 357 timestamp = ctime(&now) + 4;
396 timestamp[15] = '\0';
397 } else { 358 } else {
398 timestamp = msg; 359 timestamp = msg;
399 timestamp[15] = '\0';
400 msg += 16; 360 msg += 16;
401 } 361 }
362 timestamp[15] = '\0';
402 363
403 /* todo: supress duplicates */ 364 /* Log message locally (to file or shared mem) */
404 365 if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) {
405#ifdef CONFIG_FEATURE_REMOTE_LOG 366 if (LOG_PRI(pri) < logLevel) {
406 if (option_mask32 & OPT_remotelog) { 367 if (option_mask32 & OPT_small)
407 char line[MAXLINE + 1]; 368 msg = xasprintf("%s %s\n", timestamp, msg);
408 /* trying connect the socket */ 369 else {
409 if (-1 == remotefd) { 370 char res[20];
410 remotefd = socket(AF_INET, SOCK_DGRAM, 0); 371 parse_fac_prio_20(pri, res);
411 } 372 msg = xasprintf("%s %s %s %s\n", timestamp, localHostName, res, msg);
412 /* if we have a valid socket, send the message */ 373 }
413 if (-1 != remotefd) { 374 log_locally(msg);
414 snprintf(line, sizeof(line), "<%d>%s", pri, msg); 375 free(msg);
415 /* send message to remote logger, ignore possible error */
416 sendto(remotefd, line, strlen(line), 0,
417 (struct sockaddr *) &remoteaddr, sizeof(remoteaddr));
418 } 376 }
419 } 377 }
378}
420 379
421 if (option_mask32 & OPT_locallog) 380static void split_escape_and_log(char *tmpbuf, int len)
422#endif 381{
423 { 382 char line[len * 2 + 1]; /* gcc' cheap alloca */
424 /* now spew out the message to wherever it is supposed to go */ 383 char *p = tmpbuf;
425 if (pri == 0 || LOG_PRI(pri) < logLevel) { 384
426 if (option_mask32 & OPT_small) 385 tmpbuf += len;
427 message("%s %s\n", timestamp, msg); 386 while (p < tmpbuf) {
428 else 387 char c;
429 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg); 388 char *q = line;
389 int pri = (LOG_USER | LOG_NOTICE);
390
391 if (*p == '<') {
392 /* Parse the magic priority number. */
393 pri = bb_strtou(p + 1, &p, 10);
394 if (*p == '>') p++;
395 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
396 pri = (LOG_USER | LOG_NOTICE);
397 }
430 } 398 }
399
400 while ((c = *p++)) {
401 if (c == '\n')
402 c = ' ';
403 if (!(c & ~0x1f)) {
404 *q++ = '^';
405 c += '@'; /* ^@, ^A, ^B... */
406 }
407 *q++ = c;
408 }
409 *q = '\0';
410 /* now log it */
411 timestamp_and_log(pri, line, q - line);
431 } 412 }
432} 413}
433 414
434static void quit_signal(int sig) 415static void quit_signal(int sig)
435{ 416{
436 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); 417 timestamp_and_log(LOG_SYSLOG | LOG_INFO, "System log daemon exiting", 0);
437 unlink(lfile); 418 puts("System log daemon exiting");
419 unlink(dev_log_name);
438 if (ENABLE_FEATURE_IPC_SYSLOG) 420 if (ENABLE_FEATURE_IPC_SYSLOG)
439 ipcsyslog_cleanup(); 421 ipcsyslog_cleanup();
440
441 exit(1); 422 exit(1);
442} 423}
443 424
444static void domark(int sig) 425static void do_mark(int sig)
445{ 426{
446 if (MarkInterval > 0) { 427 if (markInterval) {
447 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --"); 428 timestamp_and_log(LOG_SYSLOG | LOG_INFO, "-- MARK --", 0);
448 alarm(MarkInterval); 429 alarm(markInterval);
449 } 430 }
450} 431}
451 432
452/* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are 433static void do_syslogd(void) ATTRIBUTE_NORETURN;
453 * enabled, we otherwise get a "storage size isn't constant error. */ 434static void do_syslogd(void)
454static int serveConnection(char *tmpbuf, int n_read)
455{
456 char *p = tmpbuf;
457
458 while (p < tmpbuf + n_read) {
459
460 int pri = (LOG_USER | LOG_NOTICE);
461 int num_lt = 0;
462 char line[MAXLINE + 1];
463 unsigned char c;
464 char *q = line;
465
466 while ((c = *p) && q < &line[sizeof(line) - 1]) {
467 if (c == '<' && num_lt == 0) {
468 /* Parse the magic priority number. */
469 num_lt++;
470 pri = 0;
471 while (isdigit(*++p)) {
472 pri = 10 * pri + (*p - '0');
473 }
474 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) {
475 pri = (LOG_USER | LOG_NOTICE);
476 }
477 } else if (c == '\n') {
478 *q++ = ' ';
479 } else if (iscntrl(c) && (c < 0177)) {
480 *q++ = '^';
481 *q++ = c ^ 0100;
482 } else {
483 *q++ = c;
484 }
485 p++;
486 }
487 *q = '\0';
488 p++;
489 /* Now log it */
490 logMessage(pri, line);
491 }
492 return n_read;
493}
494
495static void doSyslogd(void) ATTRIBUTE_NORETURN;
496static void doSyslogd(void)
497{ 435{
498 struct sockaddr_un sunx; 436 struct sockaddr_un sunx;
499 socklen_t addrLength; 437 socklen_t addrLength;
500
501 int sock_fd; 438 int sock_fd;
502 fd_set fds; 439 fd_set fds;
503 440
@@ -510,31 +447,31 @@ static void doSyslogd(void)
510#ifdef SIGCLD 447#ifdef SIGCLD
511 signal(SIGCLD, SIG_IGN); 448 signal(SIGCLD, SIG_IGN);
512#endif 449#endif
513 signal(SIGALRM, domark); 450 signal(SIGALRM, do_mark);
514 alarm(MarkInterval); 451 alarm(markInterval);
515 452
516 /* Create the syslog file so realpath() can work. */ 453 /* Unlink old /dev/log (or object it points to) */
517 if (realpath(_PATH_LOG, lfile) != NULL) { 454 if (realpath(_PATH_LOG, dev_log_name) != NULL) {
518 unlink(lfile); 455 unlink(dev_log_name);
519 } 456 }
520 457
521 memset(&sunx, 0, sizeof(sunx)); 458 memset(&sunx, 0, sizeof(sunx));
522 sunx.sun_family = AF_UNIX; 459 sunx.sun_family = AF_UNIX;
523 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path)); 460 strncpy(sunx.sun_path, dev_log_name, sizeof(sunx.sun_path));
524 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0); 461 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0);
525 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path); 462 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path);
526 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) { 463 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) {
527 bb_perror_msg_and_die("cannot connect to socket %s", lfile); 464 bb_perror_msg_and_die("cannot connect to socket %s", dev_log_name);
528 } 465 }
529 466
530 if (chmod(lfile, 0666) < 0) { 467 if (chmod(dev_log_name, 0666) < 0) {
531 bb_perror_msg_and_die("cannot set permission on %s", lfile); 468 bb_perror_msg_and_die("cannot set permission on %s", dev_log_name);
532 } 469 }
533 if (ENABLE_FEATURE_IPC_SYSLOG && (option_mask32 & OPT_circularlog)) { 470 if (ENABLE_FEATURE_IPC_SYSLOG && (option_mask32 & OPT_circularlog)) {
534 ipcsyslog_init(); 471 ipcsyslog_init();
535 } 472 }
536 473
537 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " "BusyBox v" BB_VER ); 474 timestamp_and_log(LOG_SYSLOG | LOG_INFO, "syslogd started: BusyBox v" BB_VER, 0);
538 475
539 for (;;) { 476 for (;;) {
540 FD_ZERO(&fds); 477 FD_ZERO(&fds);
@@ -550,24 +487,33 @@ static void doSyslogd(void)
550 487
551 if (FD_ISSET(sock_fd, &fds)) { 488 if (FD_ISSET(sock_fd, &fds)) {
552 int i; 489 int i;
553#if MAXLINE > BUFSIZ
554# define TMP_BUF_SZ BUFSIZ
555#else
556# define TMP_BUF_SZ MAXLINE
557#endif
558#define tmpbuf bb_common_bufsiz1 490#define tmpbuf bb_common_bufsiz1
559 491 i = recv(sock_fd, tmpbuf, MAX_READ, 0);
560 if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) { 492 if (i <= 0)
561 tmpbuf[i] = '\0';
562 serveConnection(tmpbuf, i);
563 } else {
564 bb_perror_msg_and_die("UNIX socket error"); 493 bb_perror_msg_and_die("UNIX socket error");
494 /* TODO: maybe supress duplicates? */
495#if ENABLE_FEATURE_REMOTE_LOG
496 /* We are not modifying log messages in any way before send */
497 /* Remote site cannot trust _us_ anyway and need to do validation again */
498 if (option_mask32 & OPT_remotelog) {
499 if (-1 == remoteFD) {
500 remoteFD = socket(AF_INET, SOCK_DGRAM, 0);
501 }
502 if (-1 != remoteFD) {
503 /* send message to remote logger, ignore possible error */
504 sendto(remoteFD, tmpbuf, i, MSG_DONTWAIT,
505 (struct sockaddr *) &remoteAddr,
506 sizeof(remoteAddr));
507 }
565 } 508 }
566 } /* FD_ISSET() */ 509#endif
567 } /* for main loop */ 510 tmpbuf[i] = '\0';
511 split_escape_and_log(tmpbuf, i);
512#undef tmpbuf
513 } /* FD_ISSET() */
514 } /* for */
568} 515}
569 516
570
571int syslogd_main(int argc, char **argv) 517int syslogd_main(int argc, char **argv)
572{ 518{
573 char OPTION_DECL; 519 char OPTION_DECL;
@@ -575,46 +521,37 @@ int syslogd_main(int argc, char **argv)
575 521
576 /* do normal option parsing */ 522 /* do normal option parsing */
577 getopt32(argc, argv, OPTION_STR, OPTION_PARAM); 523 getopt32(argc, argv, OPTION_STR, OPTION_PARAM);
578 if (option_mask32 & OPT_mark) MarkInterval = xatoul_range(opt_m, 0, INT_MAX/60) * 60; // -m 524 if (option_mask32 & OPT_mark) // -m
525 markInterval = xatou_range(opt_m, 0, INT_MAX/60) * 60;
579 //if (option_mask32 & OPT_nofork) // -n 526 //if (option_mask32 & OPT_nofork) // -n
580 //if (option_mask32 & OPT_outfile) // -O 527 //if (option_mask32 & OPT_outfile) // -O
581 if (option_mask32 & OPT_loglevel) { // -l 528 if (option_mask32 & OPT_loglevel) // -l
582 logLevel = xatoi_u(opt_l); 529 logLevel = xatou_range(opt_l, 1, 8);
583 /* Valid levels are between 1 and 8 */
584 if (logLevel < 1 || logLevel > 8)
585 bb_show_usage();
586 }
587 //if (option_mask32 & OPT_small) // -S 530 //if (option_mask32 & OPT_small) // -S
588#if ENABLE_FEATURE_ROTATE_LOGFILE 531#if ENABLE_FEATURE_ROTATE_LOGFILE
589 if (option_mask32 & OPT_filesize) logFileSize = xatoul_range(opt_s, 0, INT_MAX/1024) * 1024; // -s 532 if (option_mask32 & OPT_filesize) // -s
590 if (option_mask32 & OPT_rotatecnt) { // -b 533 logFileSize = xatou_range(opt_s, 0, INT_MAX/1024) * 1024;
591 logFileRotate = xatoi_u(opt_b); 534 if (option_mask32 & OPT_rotatecnt) // -b
592 if (logFileRotate > 99) logFileRotate = 99; 535 logFileRotate = xatou_range(opt_b, 0, 99);
593 }
594#endif 536#endif
595#if ENABLE_FEATURE_REMOTE_LOG 537#if ENABLE_FEATURE_REMOTE_LOG
596 if (option_mask32 & OPT_remotelog) { // -R 538 if (option_mask32 & OPT_remotelog) { // -R
597 int port = 514; 539 int port = 514;
598 char *host = xstrdup(opt_R); 540 p = strchr(opt_R, ':');
599 p = strchr(host, ':');
600 if (p) { 541 if (p) {
601 port = xatou16(p + 1); 542 *p++ = '\0';
602 *p = '\0'; 543 port = xatou16(p);
603 } 544 }
604 remoteaddr.sin_family = AF_INET; 545 remoteAddr.sin_family = AF_INET;
605 /* FIXME: looks ip4-specific. need to do better */ 546 /* FIXME: looks ip4-specific. need to do better */
606 remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(host)->h_addr_list); 547 remoteAddr.sin_addr = *(struct in_addr *) *(xgethostbyname(opt_R)->h_addr_list);
607 remoteaddr.sin_port = htons(port); 548 remoteAddr.sin_port = htons(port);
608 free(host);
609 } 549 }
610 //if (option_mask32 & OPT_locallog) // -L 550 //if (option_mask32 & OPT_locallog) // -L
611#endif 551#endif
612#if ENABLE_FEATURE_IPC_SYSLOG 552#if ENABLE_FEATURE_IPC_SYSLOG
613 if (option_mask32 & OPT_circularlog) { // -C 553 if ((option_mask32 & OPT_circularlog) && opt_C) // -C
614 if (opt_C) { 554 shm_size = xatoul_range(opt_C, 4, INT_MAX/1024) * 1024;
615 shm_size = xatoul_range(opt_C, 4, INT_MAX/1024) * 1024;
616 }
617 }
618#endif 555#endif
619 556
620 /* If they have not specified remote logging, then log locally */ 557 /* If they have not specified remote logging, then log locally */
@@ -622,14 +559,12 @@ int syslogd_main(int argc, char **argv)
622 option_mask32 |= OPT_locallog; 559 option_mask32 |= OPT_locallog;
623 560
624 /* Store away localhost's name before the fork */ 561 /* Store away localhost's name before the fork */
625 gethostname(LocalHostName, sizeof(LocalHostName)); 562 gethostname(localHostName, sizeof(localHostName));
626 p = strchr(LocalHostName, '.'); 563 p = strchr(localHostName, '.');
627 if (p) { 564 if (p) {
628 *p = '\0'; 565 *p = '\0';
629 } 566 }
630 567
631 umask(0);
632
633 if (!(option_mask32 & OPT_nofork)) { 568 if (!(option_mask32 & OPT_nofork)) {
634#ifdef BB_NOMMU 569#ifdef BB_NOMMU
635 vfork_daemon_rexec(0, 1, argc, argv, "-n"); 570 vfork_daemon_rexec(0, 1, argc, argv, "-n");
@@ -637,7 +572,8 @@ int syslogd_main(int argc, char **argv)
637 xdaemon(0, 1); 572 xdaemon(0, 1);
638#endif 573#endif
639 } 574 }
640 doSyslogd(); 575 umask(0);
576 do_syslogd();
641 577
642 return EXIT_SUCCESS; 578 return EXIT_SUCCESS;
643} 579}