diff options
author | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-01-04 17:57:54 +0000 |
---|---|---|
committer | vda <vda@69ca8d6d-28ef-0310-b511-8ec308f3f277> | 2007-01-04 17:57:54 +0000 |
commit | 80ca649fe760637073cb024f3cd2350f61d37b39 (patch) | |
tree | a5ca6a3ec0baf8a9c0417453b489aa79f9c8c95a | |
parent | 56cdfc5fdad7ed966cd926657773f20a8a6781e4 (diff) | |
download | busybox-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.c | 590 |
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 */ |
27 | static char lfile[MAXPATHLEN]; | 26 | static 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 */ |
30 | static const char *logFilePath = "/var/log/messages"; | 29 | static 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 */ |
34 | static int logFileSize = 200 * 1024; | 33 | static int logFileSize = 200 * 1024; |
35 | |||
36 | /* number of rotated message files */ | 34 | /* number of rotated message files */ |
37 | static int logFileRotate = 1; | 35 | static int logFileRotate = 1; |
38 | #endif | 36 | #endif |
39 | 37 | ||
40 | /* interval between marks in seconds */ | 38 | /* interval between marks in seconds */ |
41 | static int MarkInterval = 20 * 60; | 39 | static int markInterval = 20 * 60; |
42 | 40 | ||
43 | /* level of messages to be locally logged */ | 41 | /* level of messages to be locally logged */ |
44 | static int logLevel = 8; | 42 | static int logLevel = 8; |
45 | 43 | ||
46 | /* localhost's name */ | 44 | /* localhost's name */ |
47 | static char LocalHostName[64]; | 45 | static 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 */ |
52 | static int remotefd = -1; | 50 | static int remoteFD = -1; |
53 | static struct sockaddr_in remoteaddr; | 51 | static struct sockaddr_in remoteAddr; |
54 | |||
55 | #endif | 52 | #endif |
56 | 53 | ||
54 | |||
55 | /* NB: we may need 2x this amount on stack... */ | ||
56 | enum { 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 */ |
59 | enum { | 61 | enum { |
@@ -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 |
117 | static struct shbuf_ds { | 119 | static 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 | |||
124 | static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup | ||
125 | static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn | ||
126 | 125 | ||
127 | static int shmid = -1; // ipc shared memory id | 126 | static int shmid = -1; // ipc shared memory id |
128 | static int s_semid = -1; // ipc semaphore id | 127 | static 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 | ||
131 | static void ipcsyslog_cleanup(void) | 130 | static 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 | ||
146 | static void ipcsyslog_init(void) | 143 | static 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 */ |
180 | static void circ_message(const char *msg) | 171 | static 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 |
281 | void ipcsyslog_cleanup(void); | 241 | void ipcsyslog_cleanup(void); |
282 | void ipcsyslog_init(void); | 242 | void ipcsyslog_init(void); |
283 | void circ_message(const char *msg); | 243 | void 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. */ | ||
288 | static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2))); | ||
289 | static 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); | 250 | static 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 | ||
371 | static void logMessage(int pri, char *msg) | 318 | static 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 */ | ||
348 | static 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) | 380 | static 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 | ||
434 | static void quit_signal(int sig) | 415 | static 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 | ||
444 | static void domark(int sig) | 425 | static 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 | 433 | static void do_syslogd(void) ATTRIBUTE_NORETURN; |
453 | * enabled, we otherwise get a "storage size isn't constant error. */ | 434 | static void do_syslogd(void) |
454 | static 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 | |||
495 | static void doSyslogd(void) ATTRIBUTE_NORETURN; | ||
496 | static 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 | |||
571 | int syslogd_main(int argc, char **argv) | 517 | int 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 | } |