1 /* 2 * Copyright (C) 2013 John Crispin <blogic@openwrt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License version 2.1 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <linux/un.h> 15 16 #include <sys/types.h> 17 #include <sys/socket.h> 18 #include <sys/stat.h> 19 20 #include <fcntl.h> 21 #include <regex.h> 22 #include <time.h> 23 #include <unistd.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <stdio.h> 27 #include <syslog.h> 28 #include <errno.h> 29 #include <ctype.h> 30 31 #include <libubox/uloop.h> 32 #include <libubox/usock.h> 33 #include <libubox/ustream.h> 34 35 #include "syslog.h" 36 37 #define LOG_DEFAULT_SIZE (16 * 1024) 38 #define LOG_DEFAULT_SOCKET "/dev/log" 39 #define SYSLOG_PADDING 16 40 41 #define KLOG_DEFAULT_PROC "/proc/kmsg" 42 43 #define PAD(x) (x % 4) ? (((x) - (x % 4)) + 4) : (x) 44 45 static char *log_dev = LOG_DEFAULT_SOCKET; 46 static int log_size = LOG_DEFAULT_SIZE; 47 static struct log_head *log, *log_end, *oldest, *newest; 48 static int current_id = 0; 49 static regex_t pat_prio; 50 static regex_t pat_tstamp; 51 52 static struct log_head* 53 log_next(struct log_head *h, int size) 54 { 55 struct log_head *n = (struct log_head *) &h->data[PAD(size)]; 56 57 return (n >= log_end) ? (log) : (n); 58 } 59 60 void 61 log_add(char *buf, int size, int source) 62 { 63 regmatch_t matches[4]; 64 struct log_head *next; 65 int priority = 0; 66 int ret; 67 char *c; 68 69 /* bounce out if we don't have init'ed yet (regmatch etc will blow) */ 70 if (!log) { 71 fprintf(stderr, "%s", buf); 72 return; 73 } 74 75 for (c = buf; *c; c++) { 76 if (*c == '\n') 77 *c = ' '; 78 } 79 80 c = buf + size - 2; 81 while (isspace(*c)) { 82 size--; 83 c--; 84 } 85 86 buf[size - 1] = 0; 87 88 /* strip the priority */ 89 ret = regexec(&pat_prio, buf, 3, matches, 0); 90 if (!ret) { 91 priority = atoi(&buf[matches[1].rm_so]); 92 size -= matches[2].rm_so; 93 buf += matches[2].rm_so; 94 } 95 96 #if 0 97 /* strip kernel timestamp */ 98 ret = regexec(&pat_tstamp,buf, 4, matches, 0); 99 if ((source == SOURCE_KLOG) && !ret) { 100 size -= matches[3].rm_so; 101 buf += matches[3].rm_so; 102 } 103 #endif 104 105 /* strip syslog timestamp */ 106 if ((source == SOURCE_SYSLOG) && (size > SYSLOG_PADDING) && (buf[SYSLOG_PADDING - 1] == ' ')) { 107 size -= SYSLOG_PADDING; 108 buf += SYSLOG_PADDING; 109 } 110 111 //fprintf(stderr, "-> %d - %s\n", priority, buf); 112 113 /* find new oldest entry */ 114 next = log_next(newest, size); 115 if (next > newest) { 116 while ((oldest > newest) && (oldest <= next) && (oldest != log)) 117 oldest = log_next(oldest, oldest->size); 118 } else { 119 //fprintf(stderr, "Log wrap\n"); 120 newest->size = 0; 121 next = log_next(log, size); 122 for (oldest = log; oldest <= next; oldest = log_next(oldest, oldest->size)) 123 ; 124 newest = log; 125 } 126 127 /* add the log message */ 128 newest->size = size; 129 newest->id = current_id++; 130 newest->priority = priority; 131 newest->source = source; 132 clock_gettime(CLOCK_REALTIME, &newest->ts); 133 strcpy(newest->data, buf); 134 135 ubus_notify_log(newest); 136 137 newest = next; 138 } 139 140 static void 141 syslog_handle_fd(struct uloop_fd *fd, unsigned int events) 142 { 143 static char buf[LOG_LINE_SIZE]; 144 int len; 145 146 while (1) { 147 len = recv(fd->fd, buf, LOG_LINE_SIZE - 1, 0); 148 if (len < 0) { 149 if (errno == EINTR) 150 continue; 151 152 break; 153 } 154 if (!len) 155 break; 156 157 buf[len] = 0; 158 159 log_add(buf, strlen(buf) + 1, SOURCE_SYSLOG); 160 } 161 } 162 163 static void 164 klog_cb(struct ustream *s, int bytes) 165 { 166 struct ustream_buf *buf = s->r.head; 167 char *newline, *str; 168 int len; 169 170 do { 171 str = ustream_get_read_buf(s, NULL); 172 if (!str) 173 break; 174 newline = strchr(buf->data, '\n'); 175 if (!newline) 176 break; 177 *newline = 0; 178 len = newline + 1 - str; 179 log_add(buf->data, len, SOURCE_KLOG); 180 ustream_consume(s, len); 181 } while (1); 182 } 183 184 static struct uloop_fd syslog_fd = { 185 .cb = syslog_handle_fd 186 }; 187 188 static struct ustream_fd klog = { 189 .stream.string_data = true, 190 .stream.notify_read = klog_cb, 191 }; 192 193 static int 194 klog_open(void) 195 { 196 int fd; 197 198 fd = open(KLOG_DEFAULT_PROC, O_RDONLY | O_NONBLOCK); 199 if (fd < 0) { 200 fprintf(stderr, "Failed to open %s\n", KLOG_DEFAULT_PROC); 201 return -1; 202 } 203 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); 204 ustream_fd_init(&klog, fd); 205 return 0; 206 } 207 208 static int 209 syslog_open(void) 210 { 211 unlink(log_dev); 212 syslog_fd.fd = usock(USOCK_UNIX | USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK, log_dev, NULL); 213 if (syslog_fd.fd < 0) { 214 fprintf(stderr,"Failed to open %s\n", log_dev); 215 return -1; 216 } 217 chmod(log_dev, 0666); 218 uloop_fd_add(&syslog_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER); 219 220 return 0; 221 } 222 223 struct log_head* 224 log_list(int count, struct log_head *h) 225 { 226 unsigned int min = count; 227 228 if (count) 229 min = (count < current_id) ? (current_id - count) : (0); 230 if (!h && oldest->id >= min) 231 return oldest; 232 if (!h) 233 h = oldest; 234 235 while (h != newest) { 236 h = log_next(h, h->size); 237 if (!h->size && (h > newest)) 238 h = log; 239 if (h->id >= min && (h != newest)) 240 return h; 241 } 242 243 return NULL; 244 } 245 246 int 247 log_buffer_init(int size) 248 { 249 struct log_head *_log = calloc(1, size); 250 251 if (!_log) { 252 fprintf(stderr, "Failed to initialize log buffer with size %d\n", log_size); 253 return -1; 254 } 255 256 if (log && ((log_size + sizeof(struct log_head)) < size)) { 257 struct log_head *start = _log; 258 struct log_head *end = ((void*) _log) + size; 259 struct log_head *l; 260 261 l = log_list(0, NULL); 262 while ((start < end) && l && l->size) { 263 memcpy(start, l, PAD(sizeof(struct log_head) + l->size)); 264 start = (struct log_head *) &l->data[PAD(l->size)]; 265 l = log_list(0, l); 266 } 267 free(log); 268 newest = start; 269 newest->size = 0; 270 oldest = log = _log; 271 log_end = ((void*) log) + size; 272 } else { 273 oldest = newest = log = _log; 274 log_end = ((void*) log) + size; 275 } 276 log_size = size; 277 278 return 0; 279 } 280 281 void 282 log_init(int _log_size) 283 { 284 if (_log_size > 0) 285 log_size = _log_size; 286 287 regcomp(&pat_prio, "^<([0-9]*)>(.*)", REG_EXTENDED); 288 regcomp(&pat_tstamp, "^\[[ 0]*([0-9]*).([0-9]*)] (.*)", REG_EXTENDED); 289 290 if (log_buffer_init(log_size)) { 291 fprintf(stderr, "Failed to allocate log memory\n"); 292 exit(-1); 293 } 294 295 syslog_open(); 296 klog_open(); 297 openlog("sysinit", LOG_CONS, LOG_DAEMON); 298 } 299 300 void 301 log_shutdown(void) 302 { 303 if (syslog_fd.registered) { 304 uloop_fd_delete(&syslog_fd); 305 close(syslog_fd.fd); 306 } 307 308 ustream_free(&klog.stream); 309 close(klog.fd.fd); 310 free(log); 311 regfree(&pat_prio); 312 regfree(&pat_tstamp); 313 } 314
This page was automatically generated by LXR 0.3.1. • OpenWrt