syslog.c 6.7 KB

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