system.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
  3. * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
  4. *
  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
  8. *
  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.
  13. */
  14. #include <sys/utsname.h>
  15. #ifdef linux
  16. #include <sys/sysinfo.h>
  17. #endif
  18. #include <sys/ioctl.h>
  19. #include <sys/types.h>
  20. #include <sys/stat.h>
  21. #include <fcntl.h>
  22. #include <signal.h>
  23. #include <unistd.h>
  24. #include <stdlib.h>
  25. #include <libubox/uloop.h>
  26. #include "procd.h"
  27. #include "watchdog.h"
  28. static struct blob_buf b;
  29. static int notify;
  30. static struct ubus_context *_ctx;
  31. int upgrade_running = 0;
  32. static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
  33. struct ubus_request_data *req, const char *method,
  34. struct blob_attr *msg)
  35. {
  36. void *c;
  37. char line[256];
  38. char *key, *val, *next;
  39. struct utsname utsname;
  40. FILE *f;
  41. blob_buf_init(&b, 0);
  42. if (uname(&utsname) >= 0)
  43. {
  44. blobmsg_add_string(&b, "kernel", utsname.release);
  45. blobmsg_add_string(&b, "hostname", utsname.nodename);
  46. }
  47. if ((f = fopen("/proc/cpuinfo", "r")) != NULL)
  48. {
  49. while(fgets(line, sizeof(line), f))
  50. {
  51. key = strtok(line, "\t:");
  52. val = strtok(NULL, "\t\n");
  53. if (!key || !val)
  54. continue;
  55. if (!strcasecmp(key, "system type") ||
  56. !strcasecmp(key, "processor") ||
  57. !strcasecmp(key, "model name"))
  58. {
  59. strtoul(val + 2, &key, 0);
  60. if (key == (val + 2) || *key != 0)
  61. {
  62. blobmsg_add_string(&b, "system", val + 2);
  63. break;
  64. }
  65. }
  66. }
  67. fclose(f);
  68. }
  69. if ((f = fopen("/tmp/sysinfo/model", "r")) != NULL ||
  70. (f = fopen("/proc/device-tree/model", "r")) != NULL)
  71. {
  72. if (fgets(line, sizeof(line), f))
  73. {
  74. val = strtok(line, "\t\n");
  75. if (val)
  76. blobmsg_add_string(&b, "model", val);
  77. }
  78. fclose(f);
  79. }
  80. else if ((f = fopen("/proc/cpuinfo", "r")) != NULL)
  81. {
  82. while(fgets(line, sizeof(line), f))
  83. {
  84. key = strtok(line, "\t:");
  85. val = strtok(NULL, "\t\n");
  86. if (!key || !val)
  87. continue;
  88. if (!strcasecmp(key, "machine") ||
  89. !strcasecmp(key, "hardware"))
  90. {
  91. blobmsg_add_string(&b, "model", val + 2);
  92. break;
  93. }
  94. }
  95. fclose(f);
  96. }
  97. if ((f = fopen("/etc/openwrt_release", "r")) != NULL)
  98. {
  99. c = blobmsg_open_table(&b, "release");
  100. while (fgets(line, sizeof(line), f))
  101. {
  102. char *dest;
  103. char ch;
  104. key = line;
  105. val = strchr(line, '=');
  106. if (!val)
  107. continue;
  108. *(val++) = 0;
  109. if (!strcasecmp(key, "DISTRIB_ID"))
  110. key = "distribution";
  111. else if (!strcasecmp(key, "DISTRIB_RELEASE"))
  112. key = "version";
  113. else if (!strcasecmp(key, "DISTRIB_REVISION"))
  114. key = "revision";
  115. else if (!strcasecmp(key, "DISTRIB_CODENAME"))
  116. key = "codename";
  117. else if (!strcasecmp(key, "DISTRIB_TARGET"))
  118. key = "target";
  119. else if (!strcasecmp(key, "DISTRIB_DESCRIPTION"))
  120. key = "description";
  121. else
  122. continue;
  123. dest = blobmsg_alloc_string_buffer(&b, key, strlen(val));
  124. if (!dest) {
  125. ERROR("Failed to allocate blob.\n");
  126. continue;
  127. }
  128. while (val && (ch = *(val++)) != 0) {
  129. switch (ch) {
  130. case '\'':
  131. case '"':
  132. next = strchr(val, ch);
  133. if (next)
  134. *next = 0;
  135. strcpy(dest, val);
  136. if (next)
  137. val = next + 1;
  138. dest += strlen(dest);
  139. break;
  140. case '\\':
  141. *(dest++) = *(val++);
  142. break;
  143. }
  144. }
  145. blobmsg_add_string_buffer(&b);
  146. }
  147. blobmsg_close_array(&b, c);
  148. fclose(f);
  149. }
  150. ubus_send_reply(ctx, req, b.head);
  151. return UBUS_STATUS_OK;
  152. }
  153. static int system_info(struct ubus_context *ctx, struct ubus_object *obj,
  154. struct ubus_request_data *req, const char *method,
  155. struct blob_attr *msg)
  156. {
  157. time_t now;
  158. struct tm *tm;
  159. #ifdef linux
  160. struct sysinfo info;
  161. void *c;
  162. if (sysinfo(&info))
  163. return UBUS_STATUS_UNKNOWN_ERROR;
  164. #endif
  165. now = time(NULL);
  166. if (!(tm = localtime(&now)))
  167. return UBUS_STATUS_UNKNOWN_ERROR;
  168. blob_buf_init(&b, 0);
  169. blobmsg_add_u32(&b, "localtime", mktime(tm));
  170. #ifdef linux
  171. blobmsg_add_u32(&b, "uptime", info.uptime);
  172. c = blobmsg_open_array(&b, "load");
  173. blobmsg_add_u32(&b, NULL, info.loads[0]);
  174. blobmsg_add_u32(&b, NULL, info.loads[1]);
  175. blobmsg_add_u32(&b, NULL, info.loads[2]);
  176. blobmsg_close_array(&b, c);
  177. c = blobmsg_open_table(&b, "memory");
  178. blobmsg_add_u64(&b, "total", info.mem_unit * info.totalram);
  179. blobmsg_add_u64(&b, "free", info.mem_unit * info.freeram);
  180. blobmsg_add_u64(&b, "shared", info.mem_unit * info.sharedram);
  181. blobmsg_add_u64(&b, "buffered", info.mem_unit * info.bufferram);
  182. blobmsg_close_table(&b, c);
  183. c = blobmsg_open_table(&b, "swap");
  184. blobmsg_add_u64(&b, "total", info.mem_unit * info.totalswap);
  185. blobmsg_add_u64(&b, "free", info.mem_unit * info.freeswap);
  186. blobmsg_close_table(&b, c);
  187. #endif
  188. ubus_send_reply(ctx, req, b.head);
  189. return UBUS_STATUS_OK;
  190. }
  191. static int system_upgrade(struct ubus_context *ctx, struct ubus_object *obj,
  192. struct ubus_request_data *req, const char *method,
  193. struct blob_attr *msg)
  194. {
  195. upgrade_running = 1;
  196. return 0;
  197. }
  198. enum {
  199. WDT_FREQUENCY,
  200. WDT_TIMEOUT,
  201. WDT_STOP,
  202. __WDT_MAX
  203. };
  204. static const struct blobmsg_policy watchdog_policy[__WDT_MAX] = {
  205. [WDT_FREQUENCY] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 },
  206. [WDT_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
  207. [WDT_STOP] = { .name = "stop", .type = BLOBMSG_TYPE_BOOL },
  208. };
  209. static int watchdog_set(struct ubus_context *ctx, struct ubus_object *obj,
  210. struct ubus_request_data *req, const char *method,
  211. struct blob_attr *msg)
  212. {
  213. struct blob_attr *tb[__WDT_MAX];
  214. const char *status;
  215. if (!msg)
  216. return UBUS_STATUS_INVALID_ARGUMENT;
  217. blobmsg_parse(watchdog_policy, __WDT_MAX, tb, blob_data(msg), blob_len(msg));
  218. if (tb[WDT_FREQUENCY]) {
  219. unsigned int timeout = watchdog_timeout(0);
  220. unsigned int freq = blobmsg_get_u32(tb[WDT_FREQUENCY]);
  221. if (freq) {
  222. if (freq > timeout / 2)
  223. freq = timeout / 2;
  224. watchdog_frequency(freq);
  225. }
  226. }
  227. if (tb[WDT_TIMEOUT]) {
  228. unsigned int timeout = blobmsg_get_u32(tb[WDT_TIMEOUT]);
  229. unsigned int frequency = watchdog_frequency(0);
  230. if (timeout <= frequency)
  231. timeout = frequency * 2;
  232. watchdog_timeout(timeout);
  233. }
  234. if (tb[WDT_STOP])
  235. watchdog_set_stopped(blobmsg_get_bool(tb[WDT_STOP]));
  236. if (watchdog_fd() == NULL)
  237. status = "offline";
  238. else if (watchdog_get_stopped())
  239. status = "stopped";
  240. else
  241. status = "running";
  242. blob_buf_init(&b, 0);
  243. blobmsg_add_string(&b, "status", status);
  244. blobmsg_add_u32(&b, "timeout", watchdog_timeout(0));
  245. blobmsg_add_u32(&b, "frequency", watchdog_frequency(0));
  246. ubus_send_reply(ctx, req, b.head);
  247. return 0;
  248. }
  249. enum {
  250. SIGNAL_PID,
  251. SIGNAL_NUM,
  252. __SIGNAL_MAX
  253. };
  254. static const struct blobmsg_policy signal_policy[__SIGNAL_MAX] = {
  255. [SIGNAL_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
  256. [SIGNAL_NUM] = { .name = "signum", .type = BLOBMSG_TYPE_INT32 },
  257. };
  258. static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj,
  259. struct ubus_request_data *req, const char *method,
  260. struct blob_attr *msg)
  261. {
  262. struct blob_attr *tb[__SIGNAL_MAX];
  263. if (!msg)
  264. return UBUS_STATUS_INVALID_ARGUMENT;
  265. blobmsg_parse(signal_policy, __SIGNAL_MAX, tb, blob_data(msg), blob_len(msg));
  266. if (!tb[SIGNAL_PID || !tb[SIGNAL_NUM]])
  267. return UBUS_STATUS_INVALID_ARGUMENT;
  268. kill(blobmsg_get_u32(tb[SIGNAL_PID]), blobmsg_get_u32(tb[SIGNAL_NUM]));
  269. return 0;
  270. }
  271. enum {
  272. NAND_PATH,
  273. __NAND_MAX
  274. };
  275. static const struct blobmsg_policy nand_policy[__NAND_MAX] = {
  276. [NAND_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
  277. };
  278. static void
  279. procd_spawn_upgraded(char *path)
  280. {
  281. char *wdt_fd = watchdog_fd();
  282. char *argv[] = { "/tmp/upgraded", NULL, NULL};
  283. argv[1] = path;
  284. DEBUG(2, "Exec to upgraded now\n");
  285. if (wdt_fd) {
  286. watchdog_no_cloexec();
  287. setenv("WDTFD", wdt_fd, 1);
  288. }
  289. execvp(argv[0], argv);
  290. }
  291. static int nand_set(struct ubus_context *ctx, struct ubus_object *obj,
  292. struct ubus_request_data *req, const char *method,
  293. struct blob_attr *msg)
  294. {
  295. struct blob_attr *tb[__NAND_MAX];
  296. if (!msg)
  297. return UBUS_STATUS_INVALID_ARGUMENT;
  298. blobmsg_parse(nand_policy, __NAND_MAX, tb, blob_data(msg), blob_len(msg));
  299. if (!tb[NAND_PATH])
  300. return UBUS_STATUS_INVALID_ARGUMENT;
  301. procd_spawn_upgraded(blobmsg_get_string(tb[NAND_PATH]));
  302. fprintf(stderr, "Yikees, something went wrong. no /sbin/upgraded ?\n");
  303. return 0;
  304. }
  305. static void
  306. procd_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
  307. {
  308. notify = obj->has_subscribers;
  309. }
  310. static const struct ubus_method system_methods[] = {
  311. UBUS_METHOD_NOARG("board", system_board),
  312. UBUS_METHOD_NOARG("info", system_info),
  313. UBUS_METHOD_NOARG("upgrade", system_upgrade),
  314. UBUS_METHOD("watchdog", watchdog_set, watchdog_policy),
  315. UBUS_METHOD("signal", proc_signal, signal_policy),
  316. /* must remain at the end as it ia not always loaded */
  317. UBUS_METHOD("nandupgrade", nand_set, nand_policy),
  318. };
  319. static struct ubus_object_type system_object_type =
  320. UBUS_OBJECT_TYPE("system", system_methods);
  321. static struct ubus_object system_object = {
  322. .name = "system",
  323. .type = &system_object_type,
  324. .methods = system_methods,
  325. .n_methods = ARRAY_SIZE(system_methods),
  326. .subscribe_cb = procd_subscribe_cb,
  327. };
  328. void
  329. procd_bcast_event(char *event, struct blob_attr *msg)
  330. {
  331. int ret;
  332. if (!notify)
  333. return;
  334. ret = ubus_notify(_ctx, &system_object, event, msg, -1);
  335. if (ret)
  336. fprintf(stderr, "Failed to notify log: %s\n", ubus_strerror(ret));
  337. }
  338. void ubus_init_system(struct ubus_context *ctx)
  339. {
  340. struct stat s;
  341. int ret;
  342. if (stat("/sbin/upgraded", &s))
  343. system_object.n_methods -= 1;
  344. _ctx = ctx;
  345. ret = ubus_add_object(ctx, &system_object);
  346. if (ret)
  347. ERROR("Failed to add object: %s\n", ubus_strerror(ret));
  348. }