Ubox
OpenWrt core utilities
syslog.c
Go to the documentation of this file.
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 #include <libubox/utils.h>
35 
36 #include "syslog.h"
37 
38 #define LOG_DEFAULT_SIZE (16 * 1024)
39 #define LOG_DEFAULT_SOCKET "/dev/log"
40 #define SYSLOG_PADDING 16
41 
42 #define KLOG_DEFAULT_PROC "/proc/kmsg"
43 
44 #define PAD(x) (x % 4) ? (((x) - (x % 4)) + 4) : (x)
45 
46 static char *log_dev = LOG_DEFAULT_SOCKET;
48 static struct log_head *log, *log_end, *oldest, *newest;
49 static int current_id = 0;
50 static regex_t pat_prio;
51 static regex_t pat_tstamp;
52 static struct udebug ud;
53 static struct udebug_buf udb_kernel, udb_user, udb_debug;
54 static const struct udebug_buf_meta meta_kernel = {
55  .name = "kernel",
56  .format = UDEBUG_FORMAT_STRING,
57 };
58 static const struct udebug_buf_meta meta_user = {
59  .name = "syslog",
60  .format = UDEBUG_FORMAT_STRING,
61 };
62 static const struct udebug_buf_meta meta_debug = {
63  .name = "debug",
64  .format = UDEBUG_FORMAT_STRING,
65 };
66 static struct udebug_ubus_ring rings[] = {
67  {
68  .buf = &udb_kernel,
69  .meta = &meta_kernel,
70  .default_entries = 1024,
71  .default_size = 65536,
72  },
73  {
74  .buf = &udb_user,
75  .meta = &meta_user,
76  .default_entries = 1024,
77  .default_size = 65536,
78  },
79  {
80  .buf = &udb_debug,
81  .meta = &meta_debug,
82  .default_entries = 1024,
83  .default_size = 65536,
84  },
85 };
86 
87 static struct log_head*
88 log_next(struct log_head *h, int size)
89 {
90  struct log_head *n = (struct log_head *) &h->data[PAD(size)];
91 
92  return (n >= log_end) ? (log) : (n);
93 }
94 
95 static uint64_t
96 get_kernel_ts(const char *ts_sec, const char *ts_nsec)
97 {
98  uint64_t ts = strtoull(ts_sec, NULL, 10) * UDEBUG_TS_SEC +
99  strtoull(ts_nsec, NULL, 10) / 1000;
100  struct timespec wall, mono;
101 
102  if (clock_gettime(CLOCK_REALTIME, &wall) ||
103  clock_gettime(CLOCK_MONOTONIC, &mono))
104  return 0;
105 
106  ts += (wall.tv_sec - mono.tv_sec) * UDEBUG_TS_SEC;
107  ts += (wall.tv_nsec - mono.tv_nsec) / 1000;
108 
109  return ts;
110 }
111 
112 static void
113 log_add_udebug(int priority, char *buf, int size, int source)
114 {
115  regmatch_t matches[4];
116  struct udebug_buf *udb;
117  uint64_t ts = 0;
118 
119  if (source == SOURCE_KLOG)
120  udb = &udb_kernel;
121  else if ((priority & LOG_FACMASK) == LOG_LOCAL7)
122  udb = &udb_debug;
123  else
124  udb = &udb_user;
125 
126  if (!udebug_buf_valid(udb))
127  return;
128 
129  if (source == SOURCE_KLOG &&
130  !regexec(&pat_tstamp, buf, 4, matches, 0)) {
131  ts = get_kernel_ts(&buf[matches[1].rm_so], &buf[matches[2].rm_so]);
132  buf += matches[3].rm_so;
133  size -= matches[3].rm_so;
134  }
135 
136  if (!ts)
137  ts = udebug_timestamp();
138 
139  udebug_entry_init_ts(udb, ts);
140  udebug_entry_printf(udb, "<%d>", priority);
141  udebug_entry_append(udb, buf, size - 1);
142  udebug_entry_add(udb);
143 }
144 
145 
146 void
147 log_add(char *buf, int size, int source)
148 {
149  regmatch_t matches[3];
150  struct log_head *next;
151  int priority = 0;
152  int ret;
153  char *c;
154 
155  /* bounce out if we don't have init'ed yet (regmatch etc will blow) */
156  if (!log) {
157  fprintf(stderr, "%s", buf);
158  return;
159  }
160 
161  for (c = buf; *c; c++) {
162  if (*c == '\n')
163  *c = ' ';
164  }
165 
166  c = buf + size - 2;
167  while (isspace(*c)) {
168  size--;
169  c--;
170  }
171 
172  buf[size - 1] = 0;
173 
174  /* strip the priority */
175  ret = regexec(&pat_prio, buf, 3, matches, 0);
176  if (!ret) {
177  priority = atoi(&buf[matches[1].rm_so]);
178  size -= matches[2].rm_so;
179  buf += matches[2].rm_so;
180  }
181 
182  /* strip syslog timestamp */
183  if ((source == SOURCE_SYSLOG) && (size > SYSLOG_PADDING) && (buf[SYSLOG_PADDING - 1] == ' ')) {
184  size -= SYSLOG_PADDING;
185  buf += SYSLOG_PADDING;
186  }
187 
189 
190  /* debug message */
191  if ((priority & LOG_FACMASK) == LOG_LOCAL7)
192  return;
193 
194  /* find new oldest entry */
195  next = log_next(newest, size);
196  if (next > newest) {
197  while ((oldest > newest) && (oldest <= next) && (oldest != log))
199  } else {
200  //fprintf(stderr, "Log wrap\n");
201  newest->size = 0;
202  next = log_next(log, size);
203  for (oldest = log; oldest <= next; oldest = log_next(oldest, oldest->size))
204  ;
205  newest = log;
206  }
207 
208  /* add the log message */
209  newest->size = size;
210  newest->id = current_id++;
212  newest->source = source;
213  clock_gettime(CLOCK_REALTIME, &newest->ts);
214  strcpy(newest->data, buf);
215 
217 
218  newest = next;
219 }
220 
221 static void
222 syslog_handle_fd(struct uloop_fd *fd, unsigned int events)
223 {
224  static char buf[LOG_LINE_SIZE];
225  int len;
226 
227  while (1) {
228  len = recv(fd->fd, buf, LOG_LINE_SIZE - 1, 0);
229  if (len < 0) {
230  if (errno == EINTR)
231  continue;
232 
233  break;
234  }
235  if (!len)
236  break;
237 
238  buf[len] = 0;
239 
240  log_add(buf, strlen(buf) + 1, SOURCE_SYSLOG);
241  }
242 }
243 
244 static void
245 klog_cb(struct ustream *s, int bytes)
246 {
247  struct ustream_buf *buf = s->r.head;
248  char *newline, *str;
249  int len;
250 
251  do {
252  str = ustream_get_read_buf(s, NULL);
253  if (!str)
254  break;
255  newline = strchr(buf->data, '\n');
256  if (!newline)
257  break;
258  *newline = 0;
259  len = newline + 1 - str;
260  log_add(buf->data, len, SOURCE_KLOG);
261  ustream_consume(s, len);
262  } while (1);
263 }
264 
265 static struct uloop_fd syslog_fd = {
266  .cb = syslog_handle_fd
267 };
268 
269 static struct ustream_fd klog = {
270  .stream.string_data = true,
271  .stream.notify_read = klog_cb,
272 };
273 
274 static int
276 {
277  int fd;
278 
279  fd = open(KLOG_DEFAULT_PROC, O_RDONLY | O_NONBLOCK);
280  if (fd < 0) {
281  fprintf(stderr, "Failed to open %s\n", KLOG_DEFAULT_PROC);
282  return -1;
283  }
284  fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
285  ustream_fd_init(&klog, fd);
286  return 0;
287 }
288 
289 static int
291 {
292  unlink(log_dev);
293  syslog_fd.fd = usock(USOCK_UNIX | USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK, log_dev, NULL);
294  if (syslog_fd.fd < 0) {
295  fprintf(stderr,"Failed to open %s\n", log_dev);
296  return -1;
297  }
298  chmod(log_dev, 0666);
299  uloop_fd_add(&syslog_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER);
300 
301  return 0;
302 }
303 
304 struct log_head*
305 log_list(int count, struct log_head *h)
306 {
307  unsigned int min = count;
308 
309  if (count)
310  min = (count < current_id) ? (current_id - count) : (0);
311  if (!h && oldest->id >= min)
312  return oldest;
313  if (!h)
314  h = oldest;
315 
316  while (h != newest) {
317  h = log_next(h, h->size);
318  if (!h->size && (h > newest))
319  h = log;
320  if (h->id >= min && (h != newest))
321  return h;
322  }
323 
324  return NULL;
325 }
326 
327 int
329 {
330  struct log_head *_log = calloc(1, size);
331 
332  if (!_log) {
333  fprintf(stderr, "Failed to initialize log buffer with size %d\n", log_size);
334  return -1;
335  }
336 
337  if (log && ((log_size + sizeof(struct log_head)) < size)) {
338  struct log_head *start = _log;
339  struct log_head *end = ((void*) _log) + size;
340  struct log_head *l;
341 
342  l = log_list(0, NULL);
343  while ((start < end) && l && l->size) {
344  memcpy(start, l, PAD(sizeof(struct log_head) + l->size));
345  start = (struct log_head *) &l->data[PAD(l->size)];
346  l = log_list(0, l);
347  }
348  free(log);
349  newest = start;
350  newest->size = 0;
351  oldest = log = _log;
352  log_end = ((void*) log) + size;
353  } else {
354  oldest = newest = log = _log;
355  log_end = ((void*) log) + size;
356  }
357  log_size = size;
358 
359  return 0;
360 }
361 
362 void log_udebug_config(struct udebug_ubus *ctx, struct blob_attr *data,
363  bool enabled)
364 {
365  udebug_ubus_apply_config(&ud, rings, ARRAY_SIZE(rings), data, enabled);
366 }
367 
368 void
369 log_init(int _log_size)
370 {
371  if (_log_size > 0)
372  log_size = _log_size;
373 
374  regcomp(&pat_prio, "^<([0-9]*)>(.*)", REG_EXTENDED);
375  regcomp(&pat_tstamp, "^\\[[ 0]*([0-9]*).([0-9]*)\\] (.*)", REG_EXTENDED);
376 
377  if (log_buffer_init(log_size)) {
378  fprintf(stderr, "Failed to allocate log memory\n");
379  exit(-1);
380  }
381 
382  udebug_init(&ud);
383  udebug_auto_connect(&ud, NULL);
384  for (size_t i = 0; i < ARRAY_SIZE(rings); i++)
385  udebug_ubus_ring_init(&ud, &rings[i]);
386 
387  syslog_open();
388  klog_open();
389  openlog("sysinit", LOG_CONS, LOG_DAEMON);
390 }
391 
392 void
393 log_shutdown(void)
394 {
395  if (syslog_fd.registered) {
396  uloop_fd_delete(&syslog_fd);
397  close(syslog_fd.fd);
398  }
399 
400  ustream_free(&klog.stream);
401  close(klog.fd.fd);
402  free(log);
403  regfree(&pat_prio);
404  regfree(&pat_tstamp);
405 }
void ubus_notify_log(struct log_head *l)
Definition: logd.c:208
static struct udebug_ubus udebug
Definition: logd.c:35
static struct ubus_context * ctx
Definition: lsbloader.c:43
char data[]
Definition: syslog.h:34
unsigned int size
Definition: syslog.h:29
int source
Definition: syslog.h:32
unsigned int id
Definition: syslog.h:30
struct timespec ts
Definition: syslog.h:33
int priority
Definition: syslog.h:31
static struct ustream_fd klog
Definition: syslog.c:269
static regex_t pat_prio
Definition: syslog.c:50
static struct udebug_buf udb_kernel udb_user udb_debug
Definition: syslog.c:53
struct log_head * log_list(int count, struct log_head *h)
Definition: syslog.c:305
static int log_size
Definition: syslog.c:47
void log_add(char *buf, int size, int source)
Definition: syslog.c:147
#define LOG_DEFAULT_SIZE
Definition: syslog.c:38
static void syslog_handle_fd(struct uloop_fd *fd, unsigned int events)
Definition: syslog.c:222
static uint64_t get_kernel_ts(const char *ts_sec, const char *ts_nsec)
Definition: syslog.c:96
static struct uloop_fd syslog_fd
Definition: syslog.c:265
#define PAD(x)
Definition: syslog.c:44
static int klog_open(void)
Definition: syslog.c:275
static struct udebug ud
Definition: syslog.c:52
static int syslog_open(void)
Definition: syslog.c:290
static regex_t pat_tstamp
Definition: syslog.c:51
#define KLOG_DEFAULT_PROC
Definition: syslog.c:42
#define SYSLOG_PADDING
Definition: syslog.c:40
static int current_id
Definition: syslog.c:49
static struct log_head * oldest
Definition: syslog.c:48
static void klog_cb(struct ustream *s, int bytes)
Definition: syslog.c:245
static const struct udebug_buf_meta meta_debug
Definition: syslog.c:62
static struct log_head * log
Definition: syslog.c:48
static const struct udebug_buf_meta meta_kernel
Definition: syslog.c:54
static char * log_dev
Definition: syslog.c:46
static struct log_head * log_next(struct log_head *h, int size)
Definition: syslog.c:88
static void log_add_udebug(int priority, char *buf, int size, int source)
Definition: syslog.c:113
static struct udebug_ubus_ring rings[]
Definition: syslog.c:66
void log_init(int _log_size)
Definition: syslog.c:369
static struct log_head * log_end
Definition: syslog.c:48
int log_buffer_init(int size)
Definition: syslog.c:328
void log_udebug_config(struct udebug_ubus *ctx, struct blob_attr *data, bool enabled)
Definition: syslog.c:362
static struct log_head * newest
Definition: syslog.c:48
static const struct udebug_buf_meta meta_user
Definition: syslog.c:58
#define LOG_DEFAULT_SOCKET
Definition: syslog.c:39
void log_shutdown(void)
#define LOG_LINE_SIZE
Definition: syslog.h:17
@ SOURCE_KLOG
Definition: syslog.h:22
@ SOURCE_SYSLOG
Definition: syslog.h:23