logd.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  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. #include <sys/types.h>
  14. #include <pwd.h>
  15. #include <stdio.h>
  16. #include <unistd.h>
  17. #include <syslog.h>
  18. #include <unistd.h>
  19. #include <linux/types.h>
  20. #include <libubox/uloop.h>
  21. #include <libubox/blobmsg.h>
  22. #include <libubox/list.h>
  23. #include <libubox/ustream.h>
  24. #include <libubox/utils.h>
  25. #include <libubus.h>
  26. #include "syslog.h"
  27. int debug = 0;
  28. static struct blob_buf b;
  29. static struct ubus_auto_conn conn;
  30. static struct udebug_ubus udebug;
  31. static LIST_HEAD(clients);
  32. enum {
  33. READ_LINES,
  34. READ_STREAM,
  35. READ_ONESHOT,
  36. __READ_MAX
  37. };
  38. static const struct blobmsg_policy read_policy[__READ_MAX] = {
  39. [READ_LINES] = { .name = "lines", .type = BLOBMSG_TYPE_INT32 },
  40. [READ_STREAM] = { .name = "stream", .type = BLOBMSG_TYPE_BOOL },
  41. [READ_ONESHOT] = { .name = "oneshot", .type = BLOBMSG_TYPE_BOOL },
  42. };
  43. static const struct blobmsg_policy write_policy =
  44. { .name = "event", .type = BLOBMSG_TYPE_STRING };
  45. struct client {
  46. struct list_head list;
  47. struct ustream_fd s;
  48. int fd;
  49. };
  50. static void
  51. client_close(struct ustream *s)
  52. {
  53. struct client *cl = container_of(s, struct client, s.stream);
  54. list_del(&cl->list);
  55. ustream_free(s);
  56. close(cl->fd);
  57. free(cl);
  58. }
  59. static void client_notify_state(struct ustream *s)
  60. {
  61. client_close(s);
  62. }
  63. static void client_notify_write(struct ustream *s, int bytes)
  64. {
  65. if (ustream_pending_data(s, true))
  66. return;
  67. client_close(s);
  68. }
  69. static void
  70. log_fill_msg(struct blob_buf *b, struct log_head *l)
  71. {
  72. blobmsg_add_string(b, "msg", l->data);
  73. blobmsg_add_u32(b, "id", l->id);
  74. blobmsg_add_u32(b, "priority", l->priority);
  75. blobmsg_add_u32(b, "source", l->source);
  76. blobmsg_add_u64(b, "time", (((__u64) l->ts.tv_sec) * 1000) + (l->ts.tv_nsec / 1000000));
  77. }
  78. static int
  79. read_log(struct ubus_context *ctx, struct ubus_object *obj,
  80. struct ubus_request_data *req, const char *method,
  81. struct blob_attr *msg)
  82. {
  83. struct client *cl;
  84. struct blob_attr *tb[__READ_MAX] = {};
  85. struct log_head *l;
  86. int count = 0;
  87. int fds[2];
  88. int ret;
  89. bool stream = true;
  90. bool oneshot = false;
  91. void *c, *e;
  92. if (!stream)
  93. count = 100;
  94. if (msg) {
  95. blobmsg_parse(read_policy, __READ_MAX, tb, blob_data(msg), blob_len(msg));
  96. if (tb[READ_LINES])
  97. count = blobmsg_get_u32(tb[READ_LINES]);
  98. if (tb[READ_STREAM])
  99. stream = blobmsg_get_bool(tb[READ_STREAM]);
  100. if (tb[READ_ONESHOT])
  101. oneshot = blobmsg_get_bool(tb[READ_ONESHOT]);
  102. }
  103. l = log_list(count, NULL);
  104. if (stream) {
  105. if (pipe(fds) == -1) {
  106. fprintf(stderr, "logd: failed to create pipe: %m\n");
  107. return -1;
  108. }
  109. ubus_request_set_fd(ctx, req, fds[0]);
  110. cl = calloc(1, sizeof(*cl));
  111. cl->s.stream.notify_state = client_notify_state;
  112. cl->fd = fds[1];
  113. ustream_fd_init(&cl->s, cl->fd);
  114. list_add(&cl->list, &clients);
  115. while ((!tb[READ_LINES] || count) && l) {
  116. blob_buf_init(&b, 0);
  117. log_fill_msg(&b, l);
  118. l = log_list(count, l);
  119. ret = ustream_write(&cl->s.stream, (void *) b.head, blob_len(b.head) + sizeof(struct blob_attr), false);
  120. if (ret < 0)
  121. break;
  122. }
  123. if (oneshot) {
  124. cl->s.stream.notify_write = client_notify_write;
  125. client_notify_write(&cl->s.stream, 0);
  126. }
  127. } else {
  128. blob_buf_init(&b, 0);
  129. c = blobmsg_open_array(&b, "log");
  130. while ((!tb[READ_LINES] || count) && l) {
  131. e = blobmsg_open_table(&b, NULL);
  132. log_fill_msg(&b, l);
  133. blobmsg_close_table(&b, e);
  134. l = log_list(count, l);
  135. }
  136. blobmsg_close_array(&b, c);
  137. ubus_send_reply(ctx, req, b.head);
  138. }
  139. blob_buf_free(&b);
  140. return 0;
  141. }
  142. static int
  143. write_log(struct ubus_context *ctx, struct ubus_object *obj,
  144. struct ubus_request_data *req, const char *method,
  145. struct blob_attr *msg)
  146. {
  147. struct blob_attr *tb;
  148. char *event;
  149. if (msg) {
  150. int len;
  151. blobmsg_parse(&write_policy, 1, &tb, blob_data(msg), blob_len(msg));
  152. if (tb) {
  153. event = blobmsg_get_string(tb);
  154. len = strlen(event) + 1;
  155. if (len > LOG_LINE_SIZE) {
  156. len = LOG_LINE_SIZE;
  157. event[len - 1] = 0;
  158. }
  159. log_add(event, len, SOURCE_SYSLOG);
  160. }
  161. }
  162. return 0;
  163. }
  164. static const struct ubus_method log_methods[] = {
  165. UBUS_METHOD("read", read_log, read_policy),
  166. { .name = "write", .handler = write_log, .policy = &write_policy, .n_policy = 1 },
  167. };
  168. static struct ubus_object_type log_object_type =
  169. UBUS_OBJECT_TYPE("log", log_methods);
  170. static struct ubus_object log_object = {
  171. .name = "log",
  172. .type = &log_object_type,
  173. .methods = log_methods,
  174. .n_methods = ARRAY_SIZE(log_methods),
  175. };
  176. void
  177. ubus_notify_log(struct log_head *l)
  178. {
  179. struct client *c;
  180. if (list_empty(&clients) && !log_object.has_subscribers)
  181. return;
  182. blob_buf_init(&b, 0);
  183. blobmsg_add_string(&b, "msg", l->data);
  184. blobmsg_add_u32(&b, "id", l->id);
  185. blobmsg_add_u32(&b, "priority", l->priority);
  186. blobmsg_add_u32(&b, "source", l->source);
  187. blobmsg_add_u64(&b, "time", (((__u64) l->ts.tv_sec) * 1000) + (l->ts.tv_nsec / 1000000));
  188. if (log_object.has_subscribers)
  189. ubus_notify(&conn.ctx, &log_object, "message", b.head, -1);
  190. list_for_each_entry(c, &clients, list)
  191. ustream_write(&c->s.stream, (void *) b.head, blob_len(b.head) + sizeof(struct blob_attr), false);
  192. blob_buf_free(&b);
  193. }
  194. static void
  195. ubus_connect_handler(struct ubus_context *ctx)
  196. {
  197. int ret;
  198. ret = ubus_add_object(ctx, &log_object);
  199. if (ret) {
  200. fprintf(stderr, "Failed to add object: %s\n", ubus_strerror(ret));
  201. exit(1);
  202. }
  203. fprintf(stderr, "log: connected to ubus\n");
  204. }
  205. int
  206. main(int argc, char **argv)
  207. {
  208. int ch, log_size = 16;
  209. struct passwd *p = NULL;
  210. signal(SIGPIPE, SIG_IGN);
  211. while ((ch = getopt(argc, argv, "S:")) != -1) {
  212. switch (ch) {
  213. case 'S':
  214. log_size = atoi(optarg);
  215. if (log_size < 1)
  216. log_size = 16;
  217. break;
  218. }
  219. }
  220. log_size *= 1024;
  221. uloop_init();
  222. log_init(log_size);
  223. conn.cb = ubus_connect_handler;
  224. ubus_auto_connect(&conn);
  225. udebug_ubus_init(&udebug, &conn.ctx, "log", log_udebug_config);
  226. p = getpwnam("logd");
  227. if (p) {
  228. if (setgid(p->pw_gid) < 0) {
  229. fprintf(stderr, "setgid() failed: %s\n", strerror(errno));
  230. exit(1);
  231. }
  232. if (setuid(p->pw_uid) < 0) {
  233. fprintf(stderr, "setuid() failed: %s\n", strerror(errno));
  234. exit(1);
  235. }
  236. }
  237. uloop_run();
  238. udebug_ubus_free(&udebug);
  239. log_shutdown();
  240. uloop_done();
  241. ubus_auto_shutdown(&conn);
  242. return 0;
  243. }