logd: prevent the buffer from being bigger than the maximum ubus size
[project/ubox.git] / log / logd.c
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 <stdio.h>
15 #include <syslog.h>
16 #include <unistd.h>
17
18 #include <linux/types.h>
19
20 #include <libubox/uloop.h>
21 #include <libubox/blobmsg.h>
22 #include <libubus.h>
23
24 #include "syslog.h"
25
26 int debug = 0;
27 static int notify;
28 static struct blob_buf b;
29 static struct ubus_context *_ctx;
30 static struct uloop_timeout ubus_timer;
31
32 static const struct blobmsg_policy read_policy =
33         { .name = "lines", .type = BLOBMSG_TYPE_INT32 };
34
35 static const struct blobmsg_policy write_policy =
36         { .name = "event", .type = BLOBMSG_TYPE_STRING };
37
38 static int
39 read_log(struct ubus_context *ctx, struct ubus_object *obj,
40                 struct ubus_request_data *req, const char *method,
41                 struct blob_attr *msg)
42 {
43         struct blob_attr *tb;
44         struct log_head *l;
45         void *lines, *entry;
46         int count = 0;
47
48         if (msg) {
49                 blobmsg_parse(&read_policy, 1, &tb, blob_data(msg), blob_len(msg));
50                 if (tb)
51                         count = blobmsg_get_u32(tb);
52         }
53
54         blob_buf_init(&b, 0);
55         lines = blobmsg_open_array(&b, "lines");
56
57         l = log_list(count, NULL);
58
59         while (l) {
60                 entry = blobmsg_open_table(&b, NULL);
61                 blobmsg_add_string(&b, "msg", l->data);
62                 blobmsg_add_u32(&b, "id", l->id);
63                 blobmsg_add_u32(&b, "priority", l->priority);
64                 blobmsg_add_u32(&b, "source", l->source);
65                 blobmsg_add_u64(&b, "time", l->ts.tv_sec);
66                 blobmsg_close_table(&b, entry);
67                 l = log_list(count, l);
68         }
69         blobmsg_close_table(&b, lines);
70         ubus_send_reply(ctx, req, b.head);
71
72         return 0;
73 }
74
75 static int
76 write_log(struct ubus_context *ctx, struct ubus_object *obj,
77                 struct ubus_request_data *req, const char *method,
78                 struct blob_attr *msg)
79 {
80         struct blob_attr *tb;
81         char *event;
82
83         if (msg) {
84                 blobmsg_parse(&write_policy, 1, &tb, blob_data(msg), blob_len(msg));
85                 if (tb) {
86                         event = blobmsg_get_string(tb);
87                         log_add(event, strlen(event) + 1, SOURCE_SYSLOG);
88                 }
89         }
90
91         return 0;
92 }
93
94 static void
95 log_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
96 {
97         notify = obj->has_subscribers;
98 }
99
100 static const struct ubus_method log_methods[] = {
101         { .name = "read", .handler = read_log, .policy = &read_policy, .n_policy = 1 },
102         { .name = "write", .handler = write_log, .policy = &write_policy, .n_policy = 1 },
103 };
104
105 static struct ubus_object_type log_object_type =
106         UBUS_OBJECT_TYPE("log", log_methods);
107
108 static struct ubus_object log_object = {
109         .name = "log",
110         .type = &log_object_type,
111         .methods = log_methods,
112         .n_methods = ARRAY_SIZE(log_methods),
113         .subscribe_cb = log_subscribe_cb,
114 };
115
116 void
117 ubus_notify_log(struct log_head *l)
118 {
119         int ret;
120
121         if (!notify)
122                 return;
123
124         blob_buf_init(&b, 0);
125         blobmsg_add_u32(&b, "id", l->id);
126         blobmsg_add_u32(&b, "priority", l->priority);
127         blobmsg_add_u32(&b, "source", l->source);
128         blobmsg_add_u64(&b, "time", (((__u64) l->ts.tv_sec) * 1000) + (l->ts.tv_nsec / 1000000));
129
130         ret = ubus_notify(_ctx, &log_object, l->data, b.head, -1);
131         if (ret)
132                 fprintf(stderr, "Failed to notify log: %s\n", ubus_strerror(ret));
133 }
134
135 static void
136 ubus_reconnect_cb(struct uloop_timeout *timeout)
137 {
138         if (!ubus_reconnect(_ctx, NULL))
139                 ubus_add_uloop(_ctx);
140         else
141                 uloop_timeout_set(timeout, 1000);
142 }
143
144 static void
145 ubus_disconnect_cb(struct ubus_context *ctx)
146 {
147         ubus_timer.cb = ubus_reconnect_cb;
148         uloop_timeout_set(&ubus_timer, 1000);
149 }
150
151 static void
152 ubus_connect_cb(struct uloop_timeout *timeout)
153 {
154         int ret;
155
156         _ctx = ubus_connect(NULL);
157         if (!_ctx) {
158                 uloop_timeout_set(timeout, 1000);
159                 fprintf(stderr, "failed to connect to ubus\n");
160                 return;
161         }
162         _ctx->connection_lost = ubus_disconnect_cb;
163         ret = ubus_add_object(_ctx, &log_object);
164         if (ret)
165                 fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
166         fprintf(stderr, "log: connected to ubus\n");
167         ubus_add_uloop(_ctx);
168 }
169
170 int
171 main(int argc, char **argv)
172 {
173         int ch, log_size = 0;
174
175         signal(SIGPIPE, SIG_IGN);
176
177         while ((ch = getopt(argc, argv, "S:")) != -1) {
178                 switch (ch) {
179                 case 'S':
180                         log_size = atoi(optarg);
181                         if (log_size < 1)
182                                 log_size = 1;
183                         log_size *= 1024;
184                         break;
185                 }
186         }
187         uloop_init();
188         ubus_timer.cb = ubus_connect_cb;
189         uloop_timeout_set(&ubus_timer, 1000);
190         log_init(log_size);
191         uloop_run();
192         if (_ctx)
193                 ubus_free(_ctx);
194         log_shutdown();
195         uloop_done();
196
197         return 0;
198 }