2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
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
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.
17 #include <sys/types.h>
18 #include <sys/socket.h>
29 #include <libubox/uloop.h>
30 #include <libubox/usock.h>
31 #include <libubox/ustream.h>
36 #define LOG_DEFAULT_SIZE (16 * 1024)
37 #define LOG_DEFAULT_SOCKET "/dev/log"
38 #define LOG_LINE_LEN 256
39 #define SYSLOG_PADDING 16
41 #define KLOG_DEFAULT_PROC "/proc/kmsg"
43 #define PAD(x) (x % 4) ? (((x) - (x % 4)) + 4) : (x)
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
;
52 static struct log_head
*log_next(struct log_head
*h
, int size
)
54 struct log_head
*n
= (struct log_head
*) &h
->data
[PAD(sizeof(struct log_head
) + size
)];
56 return (n
>= log_end
) ? (log
) : (n
);
59 void log_add(char *buf
, int size
, int source
)
61 regmatch_t matches
[4];
62 struct log_head
*next
;
66 /* bounce out if we don't have init'ed yet (regmatch etc will blow) */
72 /* strip trailing newline */
73 if (buf
[size
- 2] == '\n') {
78 /* strip the priority */
79 ret
= regexec(&pat_prio
, buf
, 3, matches
, 0);
81 priority
= atoi(&buf
[matches
[1].rm_so
]);
82 size
-= matches
[2].rm_so
;
83 buf
+= matches
[2].rm_so
;
87 /* strip kernel timestamp */
88 ret
= regexec(&pat_tstamp
,buf
, 4, matches
, 0);
89 if ((source
== SOURCE_KLOG
) && !ret
) {
90 size
-= matches
[3].rm_so
;
91 buf
+= matches
[3].rm_so
;
95 /* strip syslog timestamp */
96 if ((source
== SOURCE_SYSLOG
) && (size
> SYSLOG_PADDING
) && (buf
[SYSLOG_PADDING
- 1] == ' ')) {
97 size
-= SYSLOG_PADDING
;
98 buf
+= SYSLOG_PADDING
;
101 DEBUG(2, "-> %d - %s\n", priority
, buf
);
103 /* find new oldest entry */
104 next
= log_next(newest
, size
);
106 while ((oldest
> newest
) && (oldest
<= next
) && (oldest
!= log
))
107 oldest
= log_next(oldest
, oldest
->size
);
109 DEBUG(2, "Log wrap\n");
111 next
= log_next(log
, size
);
112 for (oldest
= log
; oldest
<= next
; oldest
= log_next(oldest
, oldest
->size
))
117 /* add the log message */
119 newest
->id
= current_id
++;
120 newest
->priority
= priority
;
121 newest
->source
= source
;
122 clock_gettime(CLOCK_REALTIME
, &newest
->ts
);
123 strcpy(newest
->data
, buf
);
125 ubus_notify_log(newest
);
130 void log_printf(char *fmt
, ...)
132 static int buffer_len
= 128;
141 buffer
= malloc(buffer_len
);
145 n
= vsnprintf(buffer
, buffer_len
, fmt
, ap
);
149 if (n
>= buffer_len
) {
153 } while (n
>= buffer_len
);
155 log_add(buffer
, n
, SOURCE_INTERNAL
);
158 static void slog_cb(struct ustream
*s
, int bytes
)
160 struct ustream_buf
*buf
= s
->r
.head
;
165 str
= ustream_get_read_buf(s
, NULL
);
168 len
= strlen(buf
->data
);
171 ustream_consume(s
, 1);
174 log_add(buf
->data
, len
+ 1, SOURCE_SYSLOG
);
175 ustream_consume(s
, len
);
180 static void klog_cb(struct ustream
*s
, int bytes
)
182 struct ustream_buf
*buf
= s
->r
.head
;
187 str
= ustream_get_read_buf(s
, NULL
);
190 newline
= strchr(buf
->data
, '\n');
194 len
= newline
+ 1 - str
;
195 log_add(buf
->data
, len
, SOURCE_KLOG
);
196 ustream_consume(s
, len
);
200 struct ustream_fd slog
= {
201 .stream
.string_data
= true,
202 .stream
.notify_read
= slog_cb
,
205 struct ustream_fd klog
= {
206 .stream
.string_data
= true,
207 .stream
.notify_read
= klog_cb
,
210 static int klog_open(void)
214 DEBUG(1, "Opening %s\n", KLOG_DEFAULT_PROC
);
215 fd
= open(KLOG_DEFAULT_PROC
, O_RDONLY
| O_NONBLOCK
);
217 ERROR("Failed to open %s\n", KLOG_DEFAULT_PROC
);
220 fcntl(fd
, F_SETFD
, fcntl(fd
, F_GETFD
) | FD_CLOEXEC
);
221 ustream_fd_init(&klog
, fd
);
225 static int syslog_open(void)
229 DEBUG(1, "Opening %s\n", log_dev
);
231 fd
= usock(USOCK_UNIX
| USOCK_UDP
| USOCK_SERVER
| USOCK_NONBLOCK
, log_dev
, NULL
);
233 ERROR("Failed to open %s\n", log_dev
);
236 chmod(log_dev
, 0666);
237 ustream_fd_init(&slog
, fd
);
241 struct log_head
* log_list(int count
, struct log_head
*h
)
243 unsigned int min
= count
;
246 min
= (count
< current_id
) ? (current_id
- count
) : (0);
247 if (!h
&& oldest
->id
>= min
)
252 while (h
!= newest
) {
253 h
= log_next(h
, h
->size
);
254 if (!h
->size
&& (h
> newest
))
256 if (h
->id
>= min
&& (h
!= newest
))
263 int log_buffer_init(int size
)
265 struct log_head
*_log
= malloc(size
);
268 ERROR("Failed to initialize log buffer with size %d\n", log_size
);
272 memset(_log
, 0, size
);
274 if (log
&& ((log_size
+ sizeof(struct log_head
)) < size
)) {
275 struct log_head
*start
= _log
;
276 struct log_head
*end
= ((void*) _log
) + size
;
279 l
= log_list(0, NULL
);
280 while ((start
< end
) && l
&& l
->size
) {
281 memcpy(start
, l
, PAD(sizeof(struct log_head
) + l
->size
));
282 start
= (struct log_head
*) &l
->data
[PAD(l
->size
)];
289 log_end
= ((void*) log
) + size
;
291 oldest
= newest
= log
= _log
;
292 log_end
= ((void*) log
) + size
;
301 regcomp(&pat_prio
, "^<([0-9]*)>(.*)", REG_EXTENDED
);
302 regcomp(&pat_tstamp
, "^\[[ 0]*([0-9]*).([0-9]*)] (.*)", REG_EXTENDED
);
304 if (log_buffer_init(log_size
)) {
305 ERROR("Failed to allocate log memory\n");
311 openlog("sysinit", LOG_CONS
, LOG_DAEMON
);
314 void log_shutdown(void)
316 ustream_free(&slog
.stream
);
317 ustream_free(&klog
.stream
);