logd.c 6.2 KB

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