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