2 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
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
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.
16 #include <sys/types.h>
17 #include <sys/socket.h>
31 #include <libubox/uloop.h>
32 #include <libubox/usock.h>
33 #include <libubox/ustream.h>
34 #include <libubox/utils.h>
38 #define LOG_DEFAULT_SIZE (16 * 1024)
39 #define LOG_DEFAULT_SOCKET "/dev/log"
40 #define SYSLOG_PADDING 16
42 #define KLOG_DEFAULT_PROC "/proc/kmsg"
44 #define PAD(x) (x % 4) ? (((x) - (x % 4)) + 4) : (x)
46 static char *log_dev
= LOG_DEFAULT_SOCKET
;
47 static int log_size
= LOG_DEFAULT_SIZE
;
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
= {
56 .format
= UDEBUG_FORMAT_STRING
,
58 static const struct udebug_buf_meta meta_user
= {
60 .format
= UDEBUG_FORMAT_STRING
,
62 static const struct udebug_buf_meta meta_debug
= {
64 .format
= UDEBUG_FORMAT_STRING
,
66 static struct udebug_ubus_ring rings
[] = {
70 .default_entries
= 1024,
71 .default_size
= 65536,
76 .default_entries
= 1024,
77 .default_size
= 65536,
82 .default_entries
= 1024,
83 .default_size
= 65536,
87 static struct log_head
*
88 log_next(struct log_head
*h
, int size
)
90 struct log_head
*n
= (struct log_head
*) &h
->data
[PAD(size
)];
92 return (n
>= log_end
) ? (log
) : (n
);
96 get_kernel_ts(const char *ts_sec
, const char *ts_nsec
)
98 uint64_t ts
= strtoull(ts_sec
, NULL
, 10) * UDEBUG_TS_SEC
+
99 strtoull(ts_nsec
, NULL
, 10) / 1000;
100 struct timespec wall
, mono
;
102 if (clock_gettime(CLOCK_REALTIME
, &wall
) ||
103 clock_gettime(CLOCK_MONOTONIC
, &mono
))
106 ts
+= (wall
.tv_sec
- mono
.tv_sec
) * UDEBUG_TS_SEC
;
107 ts
+= (wall
.tv_nsec
- mono
.tv_nsec
) / 1000;
113 log_add_udebug(int priority
, char *buf
, int size
, int source
)
115 regmatch_t matches
[4];
116 struct udebug_buf
*udb
;
119 if (source
== SOURCE_KLOG
)
121 else if ((priority
& LOG_FACMASK
) == LOG_LOCAL7
)
126 if (!udebug_buf_valid(udb
))
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
;
137 ts
= udebug_timestamp();
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
);
147 log_add(char *buf
, int size
, int source
)
149 regmatch_t matches
[3];
150 struct log_head
*next
;
155 /* bounce out if we don't have init'ed yet (regmatch etc will blow) */
157 fprintf(stderr
, "%s", buf
);
161 for (c
= buf
; *c
; c
++) {
167 while (isspace(*c
)) {
174 /* strip the priority */
175 ret
= regexec(&pat_prio
, buf
, 3, matches
, 0);
177 priority
= atoi(&buf
[matches
[1].rm_so
]);
178 size
-= matches
[2].rm_so
;
179 buf
+= matches
[2].rm_so
;
182 /* strip syslog timestamp */
183 if ((source
== SOURCE_SYSLOG
) && (size
> SYSLOG_PADDING
) && (buf
[SYSLOG_PADDING
- 1] == ' ')) {
184 size
-= SYSLOG_PADDING
;
185 buf
+= SYSLOG_PADDING
;
188 log_add_udebug(priority
, buf
, size
, source
);
191 if ((priority
& LOG_FACMASK
) == LOG_LOCAL7
)
194 /* find new oldest entry */
195 next
= log_next(newest
, size
);
197 while ((oldest
> newest
) && (oldest
<= next
) && (oldest
!= log
))
198 oldest
= log_next(oldest
, oldest
->size
);
200 //fprintf(stderr, "Log wrap\n");
202 next
= log_next(log
, size
);
203 for (oldest
= log
; oldest
<= next
; oldest
= log_next(oldest
, oldest
->size
))
208 /* add the log message */
210 newest
->id
= current_id
++;
211 newest
->priority
= priority
;
212 newest
->source
= source
;
213 clock_gettime(CLOCK_REALTIME
, &newest
->ts
);
214 strcpy(newest
->data
, buf
);
216 ubus_notify_log(newest
);
222 syslog_handle_fd(struct uloop_fd
*fd
, unsigned int events
)
224 static char buf
[LOG_LINE_SIZE
];
228 len
= recv(fd
->fd
, buf
, LOG_LINE_SIZE
- 1, 0);
240 log_add(buf
, strlen(buf
) + 1, SOURCE_SYSLOG
);
245 klog_cb(struct ustream
*s
, int bytes
)
247 struct ustream_buf
*buf
= s
->r
.head
;
252 str
= ustream_get_read_buf(s
, NULL
);
255 newline
= strchr(buf
->data
, '\n');
259 len
= newline
+ 1 - str
;
260 log_add(buf
->data
, len
, SOURCE_KLOG
);
261 ustream_consume(s
, len
);
265 static struct uloop_fd syslog_fd
= {
266 .cb
= syslog_handle_fd
269 static struct ustream_fd klog
= {
270 .stream
.string_data
= true,
271 .stream
.notify_read
= klog_cb
,
279 fd
= open(KLOG_DEFAULT_PROC
, O_RDONLY
| O_NONBLOCK
);
281 fprintf(stderr
, "Failed to open %s\n", KLOG_DEFAULT_PROC
);
284 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
285 ustream_fd_init(&klog
, fd
);
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
);
298 chmod(log_dev
, 0666);
299 uloop_fd_add(&syslog_fd
, ULOOP_READ
| ULOOP_EDGE_TRIGGER
);
305 log_list(int count
, struct log_head
*h
)
307 unsigned int min
= count
;
310 min
= (count
< current_id
) ? (current_id
- count
) : (0);
311 if (!h
&& oldest
->id
>= min
)
316 while (h
!= newest
) {
317 h
= log_next(h
, h
->size
);
318 if (!h
->size
&& (h
> newest
))
320 if (h
->id
>= min
&& (h
!= newest
))
328 log_buffer_init(int size
)
330 struct log_head
*_log
= calloc(1, size
);
333 fprintf(stderr
, "Failed to initialize log buffer with size %d\n", log_size
);
337 if (log
&& ((log_size
+ sizeof(struct log_head
)) < size
)) {
338 struct log_head
*start
= _log
;
339 struct log_head
*end
= ((void*) _log
) + size
;
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
)];
352 log_end
= ((void*) log
) + size
;
354 oldest
= newest
= log
= _log
;
355 log_end
= ((void*) log
) + size
;
362 void log_udebug_config(struct udebug_ubus
*ctx
, struct blob_attr
*data
,
365 udebug_ubus_apply_config(&ud
, rings
, ARRAY_SIZE(rings
), data
, enabled
);
369 log_init(int _log_size
)
372 log_size
= _log_size
;
374 regcomp(&pat_prio
, "^<([0-9]*)>(.*)", REG_EXTENDED
);
375 regcomp(&pat_tstamp
, "^\\[[ 0]*([0-9]*).([0-9]*)\\] (.*)", REG_EXTENDED
);
377 if (log_buffer_init(log_size
)) {
378 fprintf(stderr
, "Failed to allocate log memory\n");
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
]);
389 openlog("sysinit", LOG_CONS
, LOG_DAEMON
);
395 if (syslog_fd
.registered
) {
396 uloop_fd_delete(&syslog_fd
);
400 ustream_free(&klog
.stream
);
404 regfree(&pat_tstamp
);