Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/sysklogd/syslogd.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/sysklogd/syslogd.c
r821 r1770 14 14 */ 15 15 16 #include "busybox.h" 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <ctype.h> 20 #include <errno.h> 21 #include <fcntl.h> 22 #include <getopt.h> 23 #include <netdb.h> 16 #include "libbb.h" 24 17 #include <paths.h> 25 #include <signal.h>26 #include <stdarg.h>27 #include <stdbool.h>28 #include <time.h>29 #include <string.h>30 #include <unistd.h>31 #include <sys/socket.h>32 #include <sys/types.h>33 18 #include <sys/un.h> 34 #include <sys/param.h> 35 36 /* SYSLOG_NAMES defined to pull some extra junk from syslog.h*/19 20 /* SYSLOG_NAMES defined to pull prioritynames[] and facilitynames[] 21 * from syslog.h. Grrrr - glibc puts those in _rwdata_! :( */ 37 22 #define SYSLOG_NAMES 23 #define SYSLOG_NAMES_CONST /* uclibc is saner :) */ 38 24 #include <sys/syslog.h> 39 25 #include <sys/uio.h> 40 26 41 /* Path for the file where all log messages are written */ 42 #define __LOG_FILE "/var/log/messages" 43 44 /* Path to the unix socket */ 45 static char lfile[MAXPATHLEN]; 46 47 static const char *logFilePath = __LOG_FILE; 48 49 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE 50 /* max size of message file before being rotated */ 51 static int logFileSize = 200 * 1024; 52 53 /* number of rotated message files */ 54 static int logFileRotate = 1; 55 #endif 56 57 /* interval between marks in seconds */ 58 static int MarkInterval = 20 * 60; 59 60 /* localhost's name */ 61 static char LocalHostName[64]; 62 63 #ifdef CONFIG_FEATURE_REMOTE_LOG 27 #if ENABLE_FEATURE_REMOTE_LOG 64 28 #include <netinet/in.h> 65 /* udp socket for logging to remote host */ 66 static int remotefd = -1; 67 static struct sockaddr_in remoteaddr; 68 69 /* where do we log? */ 70 static char *RemoteHost; 71 72 /* what port to log to? */ 73 static int RemotePort = 514; 74 75 /* To remote log or not to remote log, that is the question. */ 76 static int doRemoteLog = FALSE; 77 static int local_logging = FALSE; 78 #endif 79 80 /* Make loging output smaller. */ 81 static bool small = false; 82 83 84 #define MAXLINE 1024 /* maximum line length */ 29 #endif 30 31 #if ENABLE_FEATURE_IPC_SYSLOG 32 #include <sys/ipc.h> 33 #include <sys/sem.h> 34 #include <sys/shm.h> 35 #endif 36 37 38 #define DEBUG 0 39 40 /* MARK code is not very useful, is bloat, and broken: 41 * can deadlock if alarmed to make MARK while writing to IPC buffer 42 * (semaphores are down but do_mark routine tries to down them again) */ 43 #undef SYSLOGD_MARK 44 45 enum { MAX_READ = 256 }; 46 47 /* Semaphore operation structures */ 48 struct shbuf_ds { 49 int32_t size; /* size of data - 1 */ 50 int32_t tail; /* end of message list */ 51 char data[1]; /* data/messages */ 52 }; 53 54 /* Allows us to have smaller initializer. Ugly. */ 55 #define GLOBALS \ 56 const char *logFilePath; \ 57 int logFD; \ 58 /* interval between marks in seconds */ \ 59 /*int markInterval;*/ \ 60 /* level of messages to be logged */ \ 61 int logLevel; \ 62 USE_FEATURE_ROTATE_LOGFILE( \ 63 /* max size of file before rotation */ \ 64 unsigned logFileSize; \ 65 /* number of rotated message files */ \ 66 unsigned logFileRotate; \ 67 unsigned curFileSize; \ 68 smallint isRegular; \ 69 ) \ 70 USE_FEATURE_REMOTE_LOG( \ 71 /* udp socket for remote logging */ \ 72 int remoteFD; \ 73 len_and_sockaddr* remoteAddr; \ 74 ) \ 75 USE_FEATURE_IPC_SYSLOG( \ 76 int shmid; /* ipc shared memory id */ \ 77 int s_semid; /* ipc semaphore id */ \ 78 int shm_size; \ 79 struct sembuf SMwup[1]; \ 80 struct sembuf SMwdn[3]; \ 81 ) 82 83 struct init_globals { 84 GLOBALS 85 }; 86 87 struct globals { 88 GLOBALS 89 #if ENABLE_FEATURE_IPC_SYSLOG 90 struct shbuf_ds *shbuf; 91 #endif 92 time_t last_log_time; 93 /* localhost's name */ 94 char localHostName[64]; 95 96 /* We recv into recvbuf... */ 97 char recvbuf[MAX_READ]; 98 /* ...then copy to parsebuf, escaping control chars */ 99 /* (can grow x2 max) */ 100 char parsebuf[MAX_READ*2]; 101 /* ...then sprintf into printbuf, adding timestamp (15 chars), 102 * host (64), fac.prio (20) to the message */ 103 /* (growth by: 15 + 64 + 20 + delims = ~110) */ 104 char printbuf[MAX_READ*2 + 128]; 105 }; 106 107 static const struct init_globals init_data = { 108 .logFilePath = "/var/log/messages", 109 .logFD = -1, 110 #ifdef SYSLOGD_MARK 111 .markInterval = 20 * 60, 112 #endif 113 .logLevel = 8, 114 #if ENABLE_FEATURE_ROTATE_LOGFILE 115 .logFileSize = 200 * 1024, 116 .logFileRotate = 1, 117 #endif 118 #if ENABLE_FEATURE_REMOTE_LOG 119 .remoteFD = -1, 120 #endif 121 #if ENABLE_FEATURE_IPC_SYSLOG 122 .shmid = -1, 123 .s_semid = -1, 124 .shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024), // default shm size 125 .SMwup = { {1, -1, IPC_NOWAIT} }, 126 .SMwdn = { {0, 0}, {1, 0}, {1, +1} }, 127 #endif 128 }; 129 130 #define G (*ptr_to_globals) 131 132 133 /* Options */ 134 enum { 135 OPTBIT_mark = 0, // -m 136 OPTBIT_nofork, // -n 137 OPTBIT_outfile, // -O 138 OPTBIT_loglevel, // -l 139 OPTBIT_small, // -S 140 USE_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize ,) // -s 141 USE_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt ,) // -b 142 USE_FEATURE_REMOTE_LOG( OPTBIT_remote ,) // -R 143 USE_FEATURE_REMOTE_LOG( OPTBIT_localtoo ,) // -L 144 USE_FEATURE_IPC_SYSLOG( OPTBIT_circularlog,) // -C 145 146 OPT_mark = 1 << OPTBIT_mark , 147 OPT_nofork = 1 << OPTBIT_nofork , 148 OPT_outfile = 1 << OPTBIT_outfile , 149 OPT_loglevel = 1 << OPTBIT_loglevel, 150 OPT_small = 1 << OPTBIT_small , 151 OPT_filesize = USE_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize )) + 0, 152 OPT_rotatecnt = USE_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt )) + 0, 153 OPT_remotelog = USE_FEATURE_REMOTE_LOG( (1 << OPTBIT_remote )) + 0, 154 OPT_locallog = USE_FEATURE_REMOTE_LOG( (1 << OPTBIT_localtoo )) + 0, 155 OPT_circularlog = USE_FEATURE_IPC_SYSLOG( (1 << OPTBIT_circularlog)) + 0, 156 }; 157 #define OPTION_STR "m:nO:l:S" \ 158 USE_FEATURE_ROTATE_LOGFILE("s:" ) \ 159 USE_FEATURE_ROTATE_LOGFILE("b:" ) \ 160 USE_FEATURE_REMOTE_LOG( "R:" ) \ 161 USE_FEATURE_REMOTE_LOG( "L" ) \ 162 USE_FEATURE_IPC_SYSLOG( "C::") 163 #define OPTION_DECL *opt_m, *opt_l \ 164 USE_FEATURE_ROTATE_LOGFILE(,*opt_s) \ 165 USE_FEATURE_ROTATE_LOGFILE(,*opt_b) \ 166 USE_FEATURE_REMOTE_LOG( ,*opt_R) \ 167 USE_FEATURE_IPC_SYSLOG( ,*opt_C = NULL) 168 #define OPTION_PARAM &opt_m, &G.logFilePath, &opt_l \ 169 USE_FEATURE_ROTATE_LOGFILE(,&opt_s) \ 170 USE_FEATURE_ROTATE_LOGFILE(,&opt_b) \ 171 USE_FEATURE_REMOTE_LOG( ,&opt_R) \ 172 USE_FEATURE_IPC_SYSLOG( ,&opt_C) 85 173 86 174 87 175 /* circular buffer variables/structures */ 88 #if def CONFIG_FEATURE_IPC_SYSLOG176 #if ENABLE_FEATURE_IPC_SYSLOG 89 177 90 178 #if CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE < 4 … … 93 181 #endif 94 182 95 #include <sys/ipc.h>96 #include <sys/sem.h>97 #include <sys/shm.h>98 99 183 /* our shared key */ 100 static const long KEY_ID = 0x414e4547; /*"GENA" */ 101 102 // Semaphore operation structures 103 static struct shbuf_ds { 104 int size; // size of data written 105 int head; // start of message list 106 int tail; // end of message list 107 char data[1]; // data/messages 108 } *buf = NULL; // shared memory pointer 109 110 static struct sembuf SMwup[1] = { {1, -1, IPC_NOWAIT} }; // set SMwup 111 static struct sembuf SMwdn[3] = { {0, 0}, {1, 0}, {1, +1} }; // set SMwdn 112 113 static int shmid = -1; // ipc shared memory id 114 static int s_semid = -1; // ipc semaphore id 115 static int shm_size = ((CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE)*1024); // default shm size 116 static int circular_logging = FALSE; 117 118 /* 119 * sem_up - up()'s a semaphore. 120 */ 121 static inline void sem_up(int semid) 122 { 123 if (semop(semid, SMwup, 1) == -1) { 124 bb_perror_msg_and_die("semop[SMwup]"); 125 } 126 } 127 128 /* 129 * sem_down - down()'s a semaphore 130 */ 131 static inline void sem_down(int semid) 132 { 133 if (semop(semid, SMwdn, 3) == -1) { 134 bb_perror_msg_and_die("semop[SMwdn]"); 135 } 136 } 137 184 #define KEY_ID ((long)0x414e4547) /* "GENA" */ 138 185 139 186 static void ipcsyslog_cleanup(void) 140 187 { 141 printf("Exiting Syslogd!\n"); 142 if (shmid != -1) { 143 shmdt(buf); 144 } 145 146 if (shmid != -1) { 147 shmctl(shmid, IPC_RMID, NULL); 148 } 149 if (s_semid != -1) { 150 semctl(s_semid, 0, IPC_RMID, 0); 188 if (G.shmid != -1) { 189 shmdt(G.shbuf); 190 } 191 if (G.shmid != -1) { 192 shmctl(G.shmid, IPC_RMID, NULL); 193 } 194 if (G.s_semid != -1) { 195 semctl(G.s_semid, 0, IPC_RMID, 0); 151 196 } 152 197 } … … 154 199 static void ipcsyslog_init(void) 155 200 { 156 if (buf == NULL) { 157 if ((shmid = shmget(KEY_ID, shm_size, IPC_CREAT | 1023)) == -1) { 158 bb_perror_msg_and_die("shmget"); 159 } 160 161 if ((buf = shmat(shmid, NULL, 0)) == NULL) { 162 bb_perror_msg_and_die("shmat"); 163 } 164 165 buf->size = shm_size - sizeof(*buf); 166 buf->head = buf->tail = 0; 167 168 // we'll trust the OS to set initial semval to 0 (let's hope) 169 if ((s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023)) == -1) { 170 if (errno == EEXIST) { 171 if ((s_semid = semget(KEY_ID, 2, 0)) == -1) { 172 bb_perror_msg_and_die("semget"); 173 } 174 } else { 175 bb_perror_msg_and_die("semget"); 176 } 177 } 201 if (DEBUG) 202 printf("shmget(%lx, %d,...)\n", KEY_ID, G.shm_size); 203 204 G.shmid = shmget(KEY_ID, G.shm_size, IPC_CREAT | 0644); 205 if (G.shmid == -1) { 206 bb_perror_msg_and_die("shmget"); 207 } 208 209 G.shbuf = shmat(G.shmid, NULL, 0); 210 if (!G.shbuf) { 211 bb_perror_msg_and_die("shmat"); 212 } 213 214 memset(G.shbuf, 0, G.shm_size); 215 G.shbuf->size = G.shm_size - offsetof(struct shbuf_ds, data) - 1; 216 /*G.shbuf->tail = 0;*/ 217 218 // we'll trust the OS to set initial semval to 0 (let's hope) 219 G.s_semid = semget(KEY_ID, 2, IPC_CREAT | IPC_EXCL | 1023); 220 if (G.s_semid == -1) { 221 if (errno == EEXIST) { 222 G.s_semid = semget(KEY_ID, 2, 0); 223 if (G.s_semid != -1) 224 return; 225 } 226 bb_perror_msg_and_die("semget"); 227 } 228 } 229 230 /* Write message to shared mem buffer */ 231 static void log_to_shmem(const char *msg, int len) 232 { 233 int old_tail, new_tail; 234 235 if (semop(G.s_semid, G.SMwdn, 3) == -1) { 236 bb_perror_msg_and_die("SMwdn"); 237 } 238 239 /* Circular Buffer Algorithm: 240 * -------------------------- 241 * tail == position where to store next syslog message. 242 * tail's max value is (shbuf->size - 1) 243 * Last byte of buffer is never used and remains NUL. 244 */ 245 len++; /* length with NUL included */ 246 again: 247 old_tail = G.shbuf->tail; 248 new_tail = old_tail + len; 249 if (new_tail < G.shbuf->size) { 250 /* store message, set new tail */ 251 memcpy(G.shbuf->data + old_tail, msg, len); 252 G.shbuf->tail = new_tail; 178 253 } else { 179 printf("Buffer already allocated just grab the semaphore?"); 180 } 181 } 182 183 /* write message to buffer */ 184 static void circ_message(const char *msg) 185 { 186 int l = strlen(msg) + 1; /* count the whole message w/ '\0' included */ 187 188 sem_down(s_semid); 189 190 /* 191 * Circular Buffer Algorithm: 192 * -------------------------- 193 * 194 * Start-off w/ empty buffer of specific size SHM_SIZ 195 * Start filling it up w/ messages. I use '\0' as separator to break up messages. 196 * This is also very handy since we can do printf on message. 197 * 198 * Once the buffer is full we need to get rid of the first message in buffer and 199 * insert the new message. (Note: if the message being added is >1 message then 200 * we will need to "remove" >1 old message from the buffer). The way this is done 201 * is the following: 202 * When we reach the end of the buffer we set a mark and start from the beginning. 203 * Now what about the beginning and end of the buffer? Well we have the "head" 204 * index/pointer which is the starting point for the messages and we have "tail" 205 * index/pointer which is the ending point for the messages. When we "display" the 206 * messages we start from the beginning and continue until we reach "tail". If we 207 * reach end of buffer, then we just start from the beginning (offset 0). "head" and 208 * "tail" are actually offsets from the beginning of the buffer. 209 * 210 * Note: This algorithm uses Linux IPC mechanism w/ shared memory and semaphores to provide 211 * a threadsafe way of handling shared memory operations. 212 */ 213 if ((buf->tail + l) < buf->size) { 214 /* before we append the message we need to check the HEAD so that we won't 215 overwrite any of the message that we still need and adjust HEAD to point 216 to the next message! */ 217 if (buf->tail < buf->head) { 218 if ((buf->tail + l) >= buf->head) { 219 /* we need to move the HEAD to point to the next message 220 * Theoretically we have enough room to add the whole message to the 221 * buffer, because of the first outer IF statement, so we don't have 222 * to worry about overflows here! 223 */ 224 int k = buf->tail + l - buf->head; /* we need to know how many bytes 225 we are overwriting to make 226 enough room */ 227 char *c = 228 memchr(buf->data + buf->head + k, '\0', 229 buf->size - (buf->head + k)); 230 if (c != NULL) { /* do a sanity check just in case! */ 231 buf->head = c - buf->data + 1; /* we need to convert pointer to 232 offset + skip the '\0' since 233 we need to point to the beginning 234 of the next message */ 235 /* Note: HEAD is only used to "retrieve" messages, it's not used 236 when writing messages into our buffer */ 237 } else { /* show an error message to know we messed up? */ 238 printf("Weird! Can't find the terminator token?\n"); 239 buf->head = 0; 240 } 241 } 242 } 243 244 /* in other cases no overflows have been done yet, so we don't care! */ 245 /* we should be ok to append the message now */ 246 strncpy(buf->data + buf->tail, msg, l); /* append our message */ 247 buf->tail += l; /* count full message w/ '\0' terminating char */ 254 /* k == available buffer space ahead of old tail */ 255 int k = G.shbuf->size - old_tail; 256 /* copy what fits to the end of buffer, and repeat */ 257 memcpy(G.shbuf->data + old_tail, msg, k); 258 msg += k; 259 len -= k; 260 G.shbuf->tail = 0; 261 goto again; 262 } 263 if (semop(G.s_semid, G.SMwup, 1) == -1) { 264 bb_perror_msg_and_die("SMwup"); 265 } 266 if (DEBUG) 267 printf("tail:%d\n", G.shbuf->tail); 268 } 269 #else 270 void ipcsyslog_cleanup(void); 271 void ipcsyslog_init(void); 272 void log_to_shmem(const char *msg); 273 #endif /* FEATURE_IPC_SYSLOG */ 274 275 276 /* Print a message to the log file. */ 277 static void log_locally(char *msg) 278 { 279 struct flock fl; 280 int len = strlen(msg); 281 282 #if ENABLE_FEATURE_IPC_SYSLOG 283 if ((option_mask32 & OPT_circularlog) && G.shbuf) { 284 log_to_shmem(msg, len); 285 return; 286 } 287 #endif 288 if (G.logFD >= 0) { 289 time_t cur; 290 time(&cur); 291 if (G.last_log_time != cur) { 292 G.last_log_time = cur; /* reopen log file every second */ 293 close(G.logFD); 294 goto reopen; 295 } 248 296 } else { 249 /* we need to break up the message and "circle" it around */ 250 char *c; 251 int k = buf->tail + l - buf->size; /* count # of bytes we don't fit */ 252 253 /* We need to move HEAD! This is always the case since we are going 254 * to "circle" the message. 255 */ 256 c = memchr(buf->data + k, '\0', buf->size - k); 257 258 if (c != NULL) { /* if we don't have '\0'??? weird!!! */ 259 /* move head pointer */ 260 buf->head = c - buf->data + 1; 261 262 /* now write the first part of the message */ 263 strncpy(buf->data + buf->tail, msg, l - k - 1); 264 265 /* ALWAYS terminate end of buffer w/ '\0' */ 266 buf->data[buf->size - 1] = '\0'; 267 268 /* now write out the rest of the string to the beginning of the buffer */ 269 strcpy(buf->data, &msg[l - k - 1]); 270 271 /* we need to place the TAIL at the end of the message */ 272 buf->tail = k + 1; 273 } else { 274 printf 275 ("Weird! Can't find the terminator token from the beginning?\n"); 276 buf->head = buf->tail = 0; /* reset buffer, since it's probably corrupted */ 277 } 278 279 } 280 sem_up(s_semid); 281 } 282 #endif /* CONFIG_FEATURE_IPC_SYSLOG */ 283 284 /* Note: There is also a function called "message()" in init.c */ 285 /* Print a message to the log file. */ 286 static void message(char *fmt, ...) __attribute__ ((format(printf, 1, 2))); 287 static void message(char *fmt, ...) 288 { 289 int fd; 290 struct flock fl; 291 va_list arguments; 297 reopen: 298 G.logFD = device_open(G.logFilePath, O_WRONLY | O_CREAT 299 | O_NOCTTY | O_APPEND | O_NONBLOCK); 300 if (G.logFD < 0) { 301 /* cannot open logfile? - print to /dev/console then */ 302 int fd = device_open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY | O_NONBLOCK); 303 if (fd < 0) 304 fd = 2; /* then stderr, dammit */ 305 full_write(fd, msg, len); 306 if (fd != 2) 307 close(fd); 308 return; 309 } 310 #if ENABLE_FEATURE_ROTATE_LOGFILE 311 { 312 struct stat statf; 313 G.isRegular = (fstat(G.logFD, &statf) == 0 && S_ISREG(statf.st_mode)); 314 /* bug (mostly harmless): can wrap around if file > 4gb */ 315 G.curFileSize = statf.st_size; 316 } 317 #endif 318 } 292 319 293 320 fl.l_whence = SEEK_SET; 294 321 fl.l_start = 0; 295 322 fl.l_len = 1; 296 297 #ifdef CONFIG_FEATURE_IPC_SYSLOG 298 if ((circular_logging == TRUE) && (buf != NULL)) { 299 char b[1024]; 300 301 va_start(arguments, fmt); 302 vsnprintf(b, sizeof(b) - 1, fmt, arguments); 303 va_end(arguments); 304 circ_message(b); 305 306 } else 307 #endif 308 if ((fd = device_open(logFilePath, 309 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | 310 O_NONBLOCK)) >= 0) { 311 fl.l_type = F_WRLCK; 312 fcntl(fd, F_SETLKW, &fl); 313 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE 314 if ( logFileSize > 0 ) { 315 struct stat statf; 316 int r = fstat(fd, &statf); 317 if( !r && (statf.st_mode & S_IFREG) 318 && (lseek(fd,0,SEEK_END) > logFileSize) ) { 319 if(logFileRotate > 0) { 320 int i; 321 char oldFile[(strlen(logFilePath)+4)], newFile[(strlen(logFilePath)+4)]; 322 for(i=logFileRotate-1;i>0;i--) { 323 sprintf(oldFile, "%s.%d", logFilePath, i-1); 324 sprintf(newFile, "%s.%d", logFilePath, i); 325 rename(oldFile, newFile); 326 } 327 sprintf(newFile, "%s.%d", logFilePath, 0); 328 fl.l_type = F_UNLCK; 329 fcntl (fd, F_SETLKW, &fl); 330 close(fd); 331 rename(logFilePath, newFile); 332 fd = device_open (logFilePath, 333 O_WRONLY | O_CREAT | O_NOCTTY | O_APPEND | 334 O_NONBLOCK); 335 fl.l_type = F_WRLCK; 336 fcntl (fd, F_SETLKW, &fl); 337 } else { 338 ftruncate( fd, 0 ); 323 fl.l_type = F_WRLCK; 324 fcntl(G.logFD, F_SETLKW, &fl); 325 326 #if ENABLE_FEATURE_ROTATE_LOGFILE 327 if (G.logFileSize && G.isRegular && G.curFileSize > G.logFileSize) { 328 if (G.logFileRotate) { /* always 0..99 */ 329 int i = strlen(G.logFilePath) + 3 + 1; 330 char oldFile[i]; 331 char newFile[i]; 332 i = G.logFileRotate - 1; 333 /* rename: f.8 -> f.9; f.7 -> f.8; ... */ 334 while (1) { 335 sprintf(newFile, "%s.%d", G.logFilePath, i); 336 if (i == 0) break; 337 sprintf(oldFile, "%s.%d", G.logFilePath, --i); 338 rename(oldFile, newFile); 339 } 340 /* newFile == "f.0" now */ 341 rename(G.logFilePath, newFile); 342 fl.l_type = F_UNLCK; 343 fcntl(G.logFD, F_SETLKW, &fl); 344 close(G.logFD); 345 goto reopen; 346 } 347 ftruncate(G.logFD, 0); 348 } 349 G.curFileSize += 350 #endif 351 full_write(G.logFD, msg, len); 352 fl.l_type = F_UNLCK; 353 fcntl(G.logFD, F_SETLKW, &fl); 354 } 355 356 static void parse_fac_prio_20(int pri, char *res20) 357 { 358 const CODE *c_pri, *c_fac; 359 360 if (pri != 0) { 361 c_fac = facilitynames; 362 while (c_fac->c_name) { 363 if (c_fac->c_val != (LOG_FAC(pri) << 3)) { 364 c_fac++; continue; 365 } 366 /* facility is found, look for prio */ 367 c_pri = prioritynames; 368 while (c_pri->c_name) { 369 if (c_pri->c_val != LOG_PRI(pri)) { 370 c_pri++; continue; 339 371 } 340 } 341 } 342 #endif 343 va_start(arguments, fmt); 344 vdprintf(fd, fmt, arguments); 345 va_end(arguments); 346 fl.l_type = F_UNLCK; 347 fcntl(fd, F_SETLKW, &fl); 348 close(fd); 349 } else { 350 /* Always send console messages to /dev/console so people will see them. */ 351 if ((fd = device_open(_PATH_CONSOLE, 352 O_WRONLY | O_NOCTTY | O_NONBLOCK)) >= 0) { 353 va_start(arguments, fmt); 354 vdprintf(fd, fmt, arguments); 355 va_end(arguments); 356 close(fd); 357 } else { 358 fprintf(stderr, "Bummer, can't print: "); 359 va_start(arguments, fmt); 360 vfprintf(stderr, fmt, arguments); 361 fflush(stderr); 362 va_end(arguments); 363 } 364 } 365 } 366 367 #ifdef CONFIG_FEATURE_REMOTE_LOG 368 static void init_RemoteLog(void) 369 { 370 memset(&remoteaddr, 0, sizeof(remoteaddr)); 371 remotefd = bb_xsocket(AF_INET, SOCK_DGRAM, 0); 372 remoteaddr.sin_family = AF_INET; 373 remoteaddr.sin_addr = *(struct in_addr *) *(xgethostbyname(RemoteHost))->h_addr_list; 374 remoteaddr.sin_port = htons(RemotePort); 375 } 376 #endif 377 378 static void logMessage(int pri, char *msg) 379 { 380 time_t now; 372 snprintf(res20, 20, "%s.%s", 373 c_fac->c_name, c_pri->c_name); 374 return; 375 } 376 /* prio not found, bail out */ 377 break; 378 } 379 snprintf(res20, 20, "<%d>", pri); 380 } 381 } 382 383 /* len parameter is used only for "is there a timestamp?" check. 384 * NB: some callers cheat and supply 0 when they know 385 * that there is no timestamp, short-cutting the test. */ 386 static void timestamp_and_log(int pri, char *msg, int len) 387 { 381 388 char *timestamp; 382 static char res[20]; 383 #ifdef CONFIG_FEATURE_REMOTE_LOG 384 static char line[MAXLINE + 1]; 385 #endif 386 CODE *c_pri, *c_fac; 387 388 if (pri != 0) { 389 for (c_fac = facilitynames; 390 c_fac->c_name && !(c_fac->c_val == LOG_FAC(pri) << 3); c_fac++); 391 for (c_pri = prioritynames; 392 c_pri->c_name && !(c_pri->c_val == LOG_PRI(pri)); c_pri++); 393 if (c_fac->c_name == NULL || c_pri->c_name == NULL) { 394 snprintf(res, sizeof(res), "<%d>", pri); 395 } else { 396 snprintf(res, sizeof(res), "%s.%s", c_fac->c_name, c_pri->c_name); 397 } 398 } 399 400 if (strlen(msg) < 16 || msg[3] != ' ' || msg[6] != ' ' || 401 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') { 389 390 if (len < 16 || msg[3] != ' ' || msg[6] != ' ' 391 || msg[9] != ':' || msg[12] != ':' || msg[15] != ' ' 392 ) { 393 time_t now; 402 394 time(&now); 403 395 timestamp = ctime(&now) + 4; 404 timestamp[15] = '\0';405 396 } else { 406 397 timestamp = msg; 407 timestamp[15] = '\0';408 398 msg += 16; 409 399 } 410 411 /* todo: supress duplicates */ 412 413 #ifdef CONFIG_FEATURE_REMOTE_LOG 414 if (doRemoteLog == TRUE) { 415 /* trying connect the socket */ 416 if (-1 == remotefd) { 417 init_RemoteLog(); 418 } 419 420 /* if we have a valid socket, send the message */ 421 if (-1 != remotefd) { 422 now = 1; 423 snprintf(line, sizeof(line), "<%d>%s", pri, msg); 424 425 retry: 426 /* send message to remote logger */ 427 if(( -1 == sendto(remotefd, line, strlen(line), 0, 428 (struct sockaddr *) &remoteaddr, 429 sizeof(remoteaddr))) && (errno == EINTR)) { 430 /* sleep now seconds and retry (with now * 2) */ 431 sleep(now); 432 now *= 2; 433 goto retry; 434 } 435 } 436 } 437 438 if (local_logging == TRUE) 439 #endif 440 { 441 /* now spew out the message to wherever it is supposed to go */ 442 if (small) 443 message("%s %s\n", timestamp, msg); 444 else 445 message("%s %s %s %s\n", timestamp, LocalHostName, res, msg); 400 timestamp[15] = '\0'; 401 402 /* Log message locally (to file or shared mem) */ 403 if (!ENABLE_FEATURE_REMOTE_LOG || (option_mask32 & OPT_locallog)) { 404 if (LOG_PRI(pri) < G.logLevel) { 405 if (option_mask32 & OPT_small) 406 sprintf(G.printbuf, "%s %s\n", timestamp, msg); 407 else { 408 char res[20]; 409 parse_fac_prio_20(pri, res); 410 sprintf(G.printbuf, "%s %s %s %s\n", timestamp, G.localHostName, res, msg); 411 } 412 log_locally(G.printbuf); 413 } 414 } 415 } 416 417 static void split_escape_and_log(char *tmpbuf, int len) 418 { 419 char *p = tmpbuf; 420 421 tmpbuf += len; 422 while (p < tmpbuf) { 423 char c; 424 char *q = G.parsebuf; 425 int pri = (LOG_USER | LOG_NOTICE); 426 427 if (*p == '<') { 428 /* Parse the magic priority number */ 429 pri = bb_strtou(p + 1, &p, 10); 430 if (*p == '>') p++; 431 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) { 432 pri = (LOG_USER | LOG_NOTICE); 433 } 434 } 435 436 while ((c = *p++)) { 437 if (c == '\n') 438 c = ' '; 439 if (!(c & ~0x1f) && c != '\t') { 440 *q++ = '^'; 441 c += '@'; /* ^@, ^A, ^B... */ 442 } 443 *q++ = c; 444 } 445 *q = '\0'; 446 /* Now log it */ 447 timestamp_and_log(pri, G.parsebuf, q - G.parsebuf); 446 448 } 447 449 } … … 449 451 static void quit_signal(int sig) 450 452 { 451 logMessage(LOG_SYSLOG | LOG_INFO, "System log daemon exiting."); 452 unlink(lfile); 453 #ifdef CONFIG_FEATURE_IPC_SYSLOG 454 ipcsyslog_cleanup(); 455 #endif 456 457 exit(TRUE); 458 } 459 460 static void domark(int sig) 461 { 462 if (MarkInterval > 0) { 463 logMessage(LOG_SYSLOG | LOG_INFO, "-- MARK --"); 464 alarm(MarkInterval); 465 } 466 } 467 468 /* This must be a #define, since when CONFIG_DEBUG and BUFFERS_GO_IN_BSS are 469 * enabled, we otherwise get a "storage size isn't constant error. */ 470 static int serveConnection(char *tmpbuf, int n_read) 471 { 472 char *p = tmpbuf; 473 474 while (p < tmpbuf + n_read) { 475 476 int pri = (LOG_USER | LOG_NOTICE); 477 int num_lt = 0; 478 char line[MAXLINE + 1]; 479 unsigned char c; 480 char *q = line; 481 482 while ((c = *p) && q < &line[sizeof(line) - 1]) { 483 if (c == '<' && num_lt == 0) { 484 /* Parse the magic priority number. */ 485 num_lt++; 486 pri = 0; 487 while (isdigit(*(++p))) { 488 pri = 10 * pri + (*p - '0'); 489 } 490 if (pri & ~(LOG_FACMASK | LOG_PRIMASK)) { 491 pri = (LOG_USER | LOG_NOTICE); 492 } 493 } else if (c == '\n') { 494 *q++ = ' '; 495 } else if (iscntrl(c) && (c < 0177)) { 496 *q++ = '^'; 497 *q++ = c ^ 0100; 498 } else { 499 *q++ = c; 500 } 501 p++; 502 } 503 *q = '\0'; 504 p++; 505 /* Now log it */ 506 logMessage(pri, line); 507 } 508 return n_read; 509 } 510 511 static void doSyslogd(void) ATTRIBUTE_NORETURN; 512 static void doSyslogd(void) 453 timestamp_and_log(LOG_SYSLOG | LOG_INFO, (char*)"syslogd exiting", 0); 454 puts("syslogd exiting"); 455 if (ENABLE_FEATURE_IPC_SYSLOG) 456 ipcsyslog_cleanup(); 457 exit(1); 458 } 459 460 #ifdef SYSLOGD_MARK 461 static void do_mark(int sig) 462 { 463 if (G.markInterval) { 464 timestamp_and_log(LOG_SYSLOG | LOG_INFO, (char*)"-- MARK --", 0); 465 alarm(G.markInterval); 466 } 467 } 468 #endif 469 470 static void do_syslogd(void) ATTRIBUTE_NORETURN; 471 static void do_syslogd(void) 513 472 { 514 473 struct sockaddr_un sunx; 515 socklen_t addrLength;516 517 474 int sock_fd; 518 475 fd_set fds; 519 520 /* Set up signal handlers. */ 476 char *dev_log_name; 477 478 /* Set up signal handlers */ 521 479 signal(SIGINT, quit_signal); 522 480 signal(SIGTERM, quit_signal); … … 527 485 signal(SIGCLD, SIG_IGN); 528 486 #endif 529 signal(SIGALRM, domark); 530 alarm(MarkInterval); 531 532 /* Create the syslog file so realpath() can work. */ 533 if (realpath(_PATH_LOG, lfile) != NULL) { 534 unlink(lfile); 535 } 487 #ifdef SYSLOGD_MARK 488 signal(SIGALRM, do_mark); 489 alarm(G.markInterval); 490 #endif 491 remove_pidfile("/var/run/syslogd.pid"); 536 492 537 493 memset(&sunx, 0, sizeof(sunx)); 538 494 sunx.sun_family = AF_UNIX; 539 strncpy(sunx.sun_path, lfile, sizeof(sunx.sun_path)); 540 sock_fd = bb_xsocket(AF_UNIX, SOCK_DGRAM, 0); 541 addrLength = sizeof(sunx.sun_family) + strlen(sunx.sun_path); 542 if (bind(sock_fd, (struct sockaddr *) &sunx, addrLength) < 0) { 543 bb_perror_msg_and_die("Could not connect to socket " _PATH_LOG); 544 } 545 546 if (chmod(lfile, 0666) < 0) { 547 bb_perror_msg_and_die("Could not set permission on " _PATH_LOG); 548 } 549 #ifdef CONFIG_FEATURE_IPC_SYSLOG 550 if (circular_logging == TRUE) { 495 strcpy(sunx.sun_path, "/dev/log"); 496 497 /* Unlink old /dev/log or object it points to. */ 498 /* (if it exists, bind will fail) */ 499 logmode = LOGMODE_NONE; 500 dev_log_name = xmalloc_readlink_or_warn("/dev/log"); 501 logmode = LOGMODE_STDIO; 502 if (dev_log_name) { 503 int fd = xopen(".", O_NONBLOCK); 504 xchdir("/dev"); 505 /* we do not check whether this is a link also */ 506 unlink(dev_log_name); 507 fchdir(fd); 508 close(fd); 509 safe_strncpy(sunx.sun_path, dev_log_name, sizeof(sunx.sun_path)); 510 free(dev_log_name); 511 } else { 512 unlink("/dev/log"); 513 } 514 515 sock_fd = xsocket(AF_UNIX, SOCK_DGRAM, 0); 516 xbind(sock_fd, (struct sockaddr *) &sunx, sizeof(sunx)); 517 518 if (chmod("/dev/log", 0666) < 0) { 519 bb_perror_msg_and_die("cannot set permission on /dev/log"); 520 } 521 if (ENABLE_FEATURE_IPC_SYSLOG && (option_mask32 & OPT_circularlog)) { 551 522 ipcsyslog_init(); 552 523 } 553 #endif 554 555 #ifdef CONFIG_FEATURE_REMOTE_LOG 556 if (doRemoteLog == TRUE) { 557 init_RemoteLog(); 558 } 559 #endif 560 561 logMessage(LOG_SYSLOG | LOG_INFO, "syslogd started: " "BusyBox v" BB_VER ); 524 525 timestamp_and_log(LOG_SYSLOG | LOG_INFO, 526 (char*)"syslogd started: BusyBox v" BB_VER, 0); 562 527 563 528 for (;;) { 564 565 529 FD_ZERO(&fds); 566 530 FD_SET(sock_fd, &fds); … … 568 532 if (select(sock_fd + 1, &fds, NULL, NULL, NULL) < 0) { 569 533 if (errno == EINTR) { 570 /* alarm may have happened .*/534 /* alarm may have happened */ 571 535 continue; 572 536 } 573 bb_perror_msg_and_die("select error");537 bb_perror_msg_and_die("select"); 574 538 } 575 539 576 540 if (FD_ISSET(sock_fd, &fds)) { 577 541 int i; 578 #if MAXLINE > BUFSIZ 579 # define TMP_BUF_SZ BUFSIZ 580 #else 581 # define TMP_BUF_SZ MAXLINE 582 #endif 583 #define tmpbuf bb_common_bufsiz1 584 585 if ((i = recv(sock_fd, tmpbuf, TMP_BUF_SZ, 0)) > 0) { 586 tmpbuf[i] = '\0'; 587 serveConnection(tmpbuf, i); 588 } else { 542 i = recv(sock_fd, G.recvbuf, MAX_READ - 1, 0); 543 if (i <= 0) 589 544 bb_perror_msg_and_die("UNIX socket error"); 590 } 591 } /* FD_ISSET() */ 592 } /* for main loop */ 593 } 594 545 /* TODO: maybe suppress duplicates? */ 546 #if ENABLE_FEATURE_REMOTE_LOG 547 /* We are not modifying log messages in any way before send */ 548 /* Remote site cannot trust _us_ anyway and need to do validation again */ 549 if (G.remoteAddr) { 550 if (-1 == G.remoteFD) { 551 G.remoteFD = socket(G.remoteAddr->sa.sa_family, SOCK_DGRAM, 0); 552 } 553 if (-1 != G.remoteFD) { 554 /* send message to remote logger, ignore possible error */ 555 sendto(G.remoteFD, G.recvbuf, i, MSG_DONTWAIT, 556 &G.remoteAddr->sa, G.remoteAddr->len); 557 } 558 } 559 #endif 560 G.recvbuf[i] = '\0'; 561 split_escape_and_log(G.recvbuf, i); 562 } /* FD_ISSET() */ 563 } /* for */ 564 } 565 566 int syslogd_main(int argc, char **argv); 595 567 int syslogd_main(int argc, char **argv) 596 568 { 597 int opt; 598 599 int doFork = TRUE; 600 569 char OPTION_DECL; 601 570 char *p; 602 571 572 PTR_TO_GLOBALS = memcpy(xzalloc(sizeof(G)), &init_data, sizeof(init_data)); 573 603 574 /* do normal option parsing */ 604 while ((opt = getopt(argc, argv, "m:nO:s:Sb:R:LC::")) > 0) { 605 switch (opt) { 606 case 'm': 607 MarkInterval = atoi(optarg) * 60; 608 break; 609 case 'n': 610 doFork = FALSE; 611 break; 612 case 'O': 613 logFilePath = optarg; 614 break; 615 #ifdef CONFIG_FEATURE_ROTATE_LOGFILE 616 case 's': 617 logFileSize = atoi(optarg) * 1024; 618 break; 619 case 'b': 620 logFileRotate = atoi(optarg); 621 if( logFileRotate > 99 ) logFileRotate = 99; 622 break; 623 #endif 624 #ifdef CONFIG_FEATURE_REMOTE_LOG 625 case 'R': 626 RemoteHost = bb_xstrdup(optarg); 627 if ((p = strchr(RemoteHost, ':'))) { 628 RemotePort = atoi(p + 1); 629 *p = '\0'; 630 } 631 doRemoteLog = TRUE; 632 break; 633 case 'L': 634 local_logging = TRUE; 635 break; 636 #endif 637 #ifdef CONFIG_FEATURE_IPC_SYSLOG 638 case 'C': 639 if (optarg) { 640 int buf_size = atoi(optarg); 641 if (buf_size >= 4) { 642 shm_size = buf_size * 1024; 643 } 644 } 645 circular_logging = TRUE; 646 break; 647 #endif 648 case 'S': 649 small = true; 650 break; 651 default: 652 bb_show_usage(); 653 } 654 } 655 656 #ifdef CONFIG_FEATURE_REMOTE_LOG 575 opt_complementary = "=0"; /* no non-option params */ 576 getopt32(argv, OPTION_STR, OPTION_PARAM); 577 #ifdef SYSLOGD_MARK 578 if (option_mask32 & OPT_mark) // -m 579 G.markInterval = xatou_range(opt_m, 0, INT_MAX/60) * 60; 580 #endif 581 //if (option_mask32 & OPT_nofork) // -n 582 //if (option_mask32 & OPT_outfile) // -O 583 if (option_mask32 & OPT_loglevel) // -l 584 G.logLevel = xatou_range(opt_l, 1, 8); 585 //if (option_mask32 & OPT_small) // -S 586 #if ENABLE_FEATURE_ROTATE_LOGFILE 587 if (option_mask32 & OPT_filesize) // -s 588 G.logFileSize = xatou_range(opt_s, 0, INT_MAX/1024) * 1024; 589 if (option_mask32 & OPT_rotatecnt) // -b 590 G.logFileRotate = xatou_range(opt_b, 0, 99); 591 #endif 592 #if ENABLE_FEATURE_REMOTE_LOG 593 if (option_mask32 & OPT_remotelog) { // -R 594 G.remoteAddr = xhost2sockaddr(opt_R, 514); 595 } 596 //if (option_mask32 & OPT_locallog) // -L 597 #endif 598 #if ENABLE_FEATURE_IPC_SYSLOG 599 if (opt_C) // -Cn 600 G.shm_size = xatoul_range(opt_C, 4, INT_MAX/1024) * 1024; 601 #endif 602 657 603 /* If they have not specified remote logging, then log locally */ 658 if (doRemoteLog == FALSE) 659 local_logging = TRUE; 660 #endif 661 604 if (ENABLE_FEATURE_REMOTE_LOG && !(option_mask32 & OPT_remotelog)) 605 option_mask32 |= OPT_locallog; 662 606 663 607 /* Store away localhost's name before the fork */ 664 gethostname(LocalHostName, sizeof(LocalHostName)); 665 if ((p = strchr(LocalHostName, '.'))) { 608 gethostname(G.localHostName, sizeof(G.localHostName)); 609 p = strchr(G.localHostName, '.'); 610 if (p) { 666 611 *p = '\0'; 667 612 } 668 613 614 if (!(option_mask32 & OPT_nofork)) { 615 bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); 616 } 669 617 umask(0); 670 671 if (doFork == TRUE) { 672 #ifdef BB_NOMMU 673 vfork_daemon_rexec(0, 1, argc, argv, "-n"); 674 #else 675 bb_xdaemon(0, 1); 676 #endif 677 } 678 doSyslogd(); 679 680 return EXIT_SUCCESS; 681 } 618 write_pidfile("/var/run/syslogd.pid"); 619 do_syslogd(); 620 /* return EXIT_SUCCESS; */ 621 }
Note:
See TracChangeset
for help on using the changeset viewer.