system.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  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/reboot.h>
  21. #include <sys/stat.h>
  22. #include <fcntl.h>
  23. #include <signal.h>
  24. #include <unistd.h>
  25. #include <stdlib.h>
  26. #include <json-c/json_tokener.h>
  27. #include <libubox/blobmsg_json.h>
  28. #include <libubox/uloop.h>
  29. #include "procd.h"
  30. #include "sysupgrade.h"
  31. #include "watchdog.h"
  32. static struct blob_buf b;
  33. static int notify;
  34. static struct ubus_context *_ctx;
  35. enum vjson_state {
  36. VJSON_ERROR,
  37. VJSON_CONTINUE,
  38. VJSON_SUCCESS,
  39. };
  40. static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
  41. struct ubus_request_data *req, const char *method,
  42. struct blob_attr *msg)
  43. {
  44. void *c;
  45. char line[256];
  46. char *key, *val, *next;
  47. struct utsname utsname;
  48. FILE *f;
  49. blob_buf_init(&b, 0);
  50. if (uname(&utsname) >= 0)
  51. {
  52. blobmsg_add_string(&b, "kernel", utsname.release);
  53. blobmsg_add_string(&b, "hostname", utsname.nodename);
  54. }
  55. if ((f = fopen("/proc/cpuinfo", "r")) != NULL)
  56. {
  57. while(fgets(line, sizeof(line), f))
  58. {
  59. key = strtok(line, "\t:");
  60. val = strtok(NULL, "\t\n");
  61. if (!key || !val)
  62. continue;
  63. if (!strcasecmp(key, "system type") ||
  64. !strcasecmp(key, "processor") ||
  65. !strcasecmp(key, "cpu") ||
  66. !strcasecmp(key, "model name"))
  67. {
  68. strtoul(val + 2, &key, 0);
  69. if (key == (val + 2) || *key != 0)
  70. {
  71. blobmsg_add_string(&b, "system", val + 2);
  72. break;
  73. }
  74. }
  75. }
  76. fclose(f);
  77. }
  78. if ((f = fopen("/tmp/sysinfo/model", "r")) != NULL ||
  79. (f = fopen("/proc/device-tree/model", "r")) != NULL)
  80. {
  81. if (fgets(line, sizeof(line), f))
  82. {
  83. val = strtok(line, "\t\n");
  84. if (val)
  85. blobmsg_add_string(&b, "model", val);
  86. }
  87. fclose(f);
  88. }
  89. else if ((f = fopen("/proc/cpuinfo", "r")) != NULL)
  90. {
  91. while(fgets(line, sizeof(line), f))
  92. {
  93. key = strtok(line, "\t:");
  94. val = strtok(NULL, "\t\n");
  95. if (!key || !val)
  96. continue;
  97. if (!strcasecmp(key, "machine") ||
  98. !strcasecmp(key, "hardware"))
  99. {
  100. blobmsg_add_string(&b, "model", val + 2);
  101. break;
  102. }
  103. }
  104. fclose(f);
  105. }
  106. if ((f = fopen("/tmp/sysinfo/board_name", "r")) != NULL)
  107. {
  108. if (fgets(line, sizeof(line), f))
  109. {
  110. val = strtok(line, "\t\n");
  111. if (val)
  112. blobmsg_add_string(&b, "board_name", val);
  113. }
  114. fclose(f);
  115. }
  116. else if ((f = fopen("/proc/device-tree/compatible", "r")) != NULL)
  117. {
  118. if (fgets(line, sizeof(line), f))
  119. {
  120. val = strtok(line, "\t\n");
  121. if (val)
  122. {
  123. next = val;
  124. while ((next = strchr(next, ',')) != NULL)
  125. {
  126. *next = '-';
  127. next++;
  128. }
  129. blobmsg_add_string(&b, "board_name", val);
  130. }
  131. }
  132. fclose(f);
  133. }
  134. if ((f = fopen("/etc/openwrt_release", "r")) != NULL)
  135. {
  136. c = blobmsg_open_table(&b, "release");
  137. while (fgets(line, sizeof(line), f))
  138. {
  139. char *dest;
  140. char ch;
  141. key = line;
  142. val = strchr(line, '=');
  143. if (!val)
  144. continue;
  145. *(val++) = 0;
  146. if (!strcasecmp(key, "DISTRIB_ID"))
  147. key = "distribution";
  148. else if (!strcasecmp(key, "DISTRIB_RELEASE"))
  149. key = "version";
  150. else if (!strcasecmp(key, "DISTRIB_REVISION"))
  151. key = "revision";
  152. else if (!strcasecmp(key, "DISTRIB_CODENAME"))
  153. key = "codename";
  154. else if (!strcasecmp(key, "DISTRIB_TARGET"))
  155. key = "target";
  156. else if (!strcasecmp(key, "DISTRIB_DESCRIPTION"))
  157. key = "description";
  158. else
  159. continue;
  160. dest = blobmsg_alloc_string_buffer(&b, key, strlen(val));
  161. if (!dest) {
  162. ERROR("Failed to allocate blob.\n");
  163. continue;
  164. }
  165. while (val && (ch = *(val++)) != 0) {
  166. switch (ch) {
  167. case '\'':
  168. case '"':
  169. next = strchr(val, ch);
  170. if (next)
  171. *next = 0;
  172. strcpy(dest, val);
  173. if (next)
  174. val = next + 1;
  175. dest += strlen(dest);
  176. break;
  177. case '\\':
  178. *(dest++) = *(val++);
  179. break;
  180. }
  181. }
  182. blobmsg_add_string_buffer(&b);
  183. }
  184. blobmsg_close_array(&b, c);
  185. fclose(f);
  186. }
  187. ubus_send_reply(ctx, req, b.head);
  188. return UBUS_STATUS_OK;
  189. }
  190. static int system_info(struct ubus_context *ctx, struct ubus_object *obj,
  191. struct ubus_request_data *req, const char *method,
  192. struct blob_attr *msg)
  193. {
  194. time_t now;
  195. struct tm *tm;
  196. #ifdef linux
  197. struct sysinfo info;
  198. void *c;
  199. char line[256];
  200. char *key, *val;
  201. unsigned long long available, cached;
  202. FILE *f;
  203. if (sysinfo(&info))
  204. return UBUS_STATUS_UNKNOWN_ERROR;
  205. if ((f = fopen("/proc/meminfo", "r")) == NULL)
  206. return UBUS_STATUS_UNKNOWN_ERROR;
  207. /* if linux < 3.14 MemAvailable is not in meminfo */
  208. available = 0;
  209. cached = 0;
  210. while (fgets(line, sizeof(line), f))
  211. {
  212. key = strtok(line, " :");
  213. val = strtok(NULL, " ");
  214. if (!key || !val)
  215. continue;
  216. if (!strcasecmp(key, "MemAvailable"))
  217. available = 1024 * atoll(val);
  218. else if (!strcasecmp(key, "Cached"))
  219. cached = 1024 * atoll(val);
  220. }
  221. fclose(f);
  222. #endif
  223. now = time(NULL);
  224. if (!(tm = localtime(&now)))
  225. return UBUS_STATUS_UNKNOWN_ERROR;
  226. blob_buf_init(&b, 0);
  227. blobmsg_add_u32(&b, "localtime", now + tm->tm_gmtoff);
  228. #ifdef linux
  229. blobmsg_add_u32(&b, "uptime", info.uptime);
  230. c = blobmsg_open_array(&b, "load");
  231. blobmsg_add_u32(&b, NULL, info.loads[0]);
  232. blobmsg_add_u32(&b, NULL, info.loads[1]);
  233. blobmsg_add_u32(&b, NULL, info.loads[2]);
  234. blobmsg_close_array(&b, c);
  235. c = blobmsg_open_table(&b, "memory");
  236. blobmsg_add_u64(&b, "total",
  237. (uint64_t)info.mem_unit * (uint64_t)info.totalram);
  238. blobmsg_add_u64(&b, "free",
  239. (uint64_t)info.mem_unit * (uint64_t)info.freeram);
  240. blobmsg_add_u64(&b, "shared",
  241. (uint64_t)info.mem_unit * (uint64_t)info.sharedram);
  242. blobmsg_add_u64(&b, "buffered",
  243. (uint64_t)info.mem_unit * (uint64_t)info.bufferram);
  244. blobmsg_add_u64(&b, "available", available);
  245. blobmsg_add_u64(&b, "cached", cached);
  246. blobmsg_close_table(&b, c);
  247. c = blobmsg_open_table(&b, "swap");
  248. blobmsg_add_u64(&b, "total",
  249. (uint64_t)info.mem_unit * (uint64_t)info.totalswap);
  250. blobmsg_add_u64(&b, "free",
  251. (uint64_t)info.mem_unit * (uint64_t)info.freeswap);
  252. blobmsg_close_table(&b, c);
  253. #endif
  254. ubus_send_reply(ctx, req, b.head);
  255. return UBUS_STATUS_OK;
  256. }
  257. static int system_reboot(struct ubus_context *ctx, struct ubus_object *obj,
  258. struct ubus_request_data *req, const char *method,
  259. struct blob_attr *msg)
  260. {
  261. procd_shutdown(RB_AUTOBOOT);
  262. return 0;
  263. }
  264. enum {
  265. WDT_FREQUENCY,
  266. WDT_TIMEOUT,
  267. WDT_MAGICCLOSE,
  268. WDT_STOP,
  269. __WDT_MAX
  270. };
  271. static const struct blobmsg_policy watchdog_policy[__WDT_MAX] = {
  272. [WDT_FREQUENCY] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 },
  273. [WDT_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
  274. [WDT_MAGICCLOSE] = { .name = "magicclose", .type = BLOBMSG_TYPE_BOOL },
  275. [WDT_STOP] = { .name = "stop", .type = BLOBMSG_TYPE_BOOL },
  276. };
  277. static int watchdog_set(struct ubus_context *ctx, struct ubus_object *obj,
  278. struct ubus_request_data *req, const char *method,
  279. struct blob_attr *msg)
  280. {
  281. struct blob_attr *tb[__WDT_MAX];
  282. const char *status;
  283. if (!msg)
  284. return UBUS_STATUS_INVALID_ARGUMENT;
  285. blobmsg_parse(watchdog_policy, __WDT_MAX, tb, blob_data(msg), blob_len(msg));
  286. if (tb[WDT_FREQUENCY]) {
  287. unsigned int timeout = tb[WDT_TIMEOUT] ? blobmsg_get_u32(tb[WDT_TIMEOUT]) :
  288. watchdog_timeout(0);
  289. unsigned int freq = blobmsg_get_u32(tb[WDT_FREQUENCY]);
  290. if (freq) {
  291. if (freq > timeout / 2)
  292. freq = timeout / 2;
  293. watchdog_frequency(freq);
  294. }
  295. }
  296. if (tb[WDT_TIMEOUT]) {
  297. unsigned int timeout = blobmsg_get_u32(tb[WDT_TIMEOUT]);
  298. unsigned int frequency = watchdog_frequency(0);
  299. if (timeout <= frequency)
  300. timeout = frequency * 2;
  301. watchdog_timeout(timeout);
  302. }
  303. if (tb[WDT_MAGICCLOSE])
  304. watchdog_set_magicclose(blobmsg_get_bool(tb[WDT_MAGICCLOSE]));
  305. if (tb[WDT_STOP])
  306. watchdog_set_stopped(blobmsg_get_bool(tb[WDT_STOP]));
  307. if (watchdog_fd() == NULL)
  308. status = "offline";
  309. else if (watchdog_get_stopped())
  310. status = "stopped";
  311. else
  312. status = "running";
  313. blob_buf_init(&b, 0);
  314. blobmsg_add_string(&b, "status", status);
  315. blobmsg_add_u32(&b, "timeout", watchdog_timeout(0));
  316. blobmsg_add_u32(&b, "frequency", watchdog_frequency(0));
  317. blobmsg_add_u8(&b, "magicclose", watchdog_get_magicclose());
  318. ubus_send_reply(ctx, req, b.head);
  319. return 0;
  320. }
  321. enum {
  322. SIGNAL_PID,
  323. SIGNAL_NUM,
  324. __SIGNAL_MAX
  325. };
  326. static const struct blobmsg_policy signal_policy[__SIGNAL_MAX] = {
  327. [SIGNAL_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 },
  328. [SIGNAL_NUM] = { .name = "signum", .type = BLOBMSG_TYPE_INT32 },
  329. };
  330. static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj,
  331. struct ubus_request_data *req, const char *method,
  332. struct blob_attr *msg)
  333. {
  334. struct blob_attr *tb[__SIGNAL_MAX];
  335. if (!msg)
  336. return UBUS_STATUS_INVALID_ARGUMENT;
  337. blobmsg_parse(signal_policy, __SIGNAL_MAX, tb, blob_data(msg), blob_len(msg));
  338. if (!tb[SIGNAL_PID || !tb[SIGNAL_NUM]])
  339. return UBUS_STATUS_INVALID_ARGUMENT;
  340. kill(blobmsg_get_u32(tb[SIGNAL_PID]), blobmsg_get_u32(tb[SIGNAL_NUM]));
  341. return 0;
  342. }
  343. __attribute__((format (printf, 2, 3)))
  344. static enum vjson_state vjson_error(char **b, const char *fmt, ...)
  345. {
  346. static char buf[256] = { 0 };
  347. const char *pfx = "Firmware image couldn't be validated: ";
  348. va_list va;
  349. int r;
  350. r = snprintf(buf, sizeof(buf), "%s", pfx);
  351. if (r < 0) {
  352. *b = "vjson_error() snprintf failed";
  353. return VJSON_ERROR;
  354. }
  355. va_start(va, fmt);
  356. r = vsnprintf(buf+r, sizeof(buf)-r, fmt, va);
  357. if (r < 0) {
  358. *b = "vjson_error() vsnprintf failed";
  359. return VJSON_ERROR;
  360. }
  361. va_end(va);
  362. *b = buf;
  363. return VJSON_ERROR;
  364. }
  365. static enum vjson_state vjson_parse_token(json_tokener *tok, char *buf, ssize_t len, char **err)
  366. {
  367. json_object *jsobj = NULL;
  368. jsobj = json_tokener_parse_ex(tok, buf, len);
  369. if (json_tokener_get_error(tok) == json_tokener_continue)
  370. return VJSON_CONTINUE;
  371. if (json_tokener_get_error(tok) == json_tokener_success) {
  372. if (json_object_get_type(jsobj) != json_type_object) {
  373. json_object_put(jsobj);
  374. return vjson_error(err, "result is not an JSON object");
  375. }
  376. blobmsg_add_object(&b, jsobj);
  377. json_object_put(jsobj);
  378. return VJSON_SUCCESS;
  379. }
  380. return vjson_error(err, "failed to parse JSON: %s (%d)",
  381. json_tokener_error_desc(json_tokener_get_error(tok)),
  382. json_tokener_get_error(tok));
  383. }
  384. static enum vjson_state vjson_parse(int fd, char **err)
  385. {
  386. enum vjson_state r = VJSON_ERROR;
  387. size_t read_count = 0;
  388. char buf[64] = { 0 };
  389. json_tokener *tok;
  390. ssize_t len;
  391. int _errno;
  392. tok = json_tokener_new();
  393. if (!tok)
  394. return vjson_error(err, "json_tokener_new() failed");
  395. vjson_error(err, "incomplete JSON input");
  396. while ((len = read(fd, buf, sizeof(buf)))) {
  397. if (len < 0 && errno == EINTR)
  398. continue;
  399. if (len < 0) {
  400. _errno = errno;
  401. json_tokener_free(tok);
  402. return vjson_error(err, "read() failed: %s (%d)",
  403. strerror(_errno), _errno);
  404. }
  405. read_count += len;
  406. r = vjson_parse_token(tok, buf, len, err);
  407. if (r != VJSON_CONTINUE)
  408. break;
  409. memset(buf, 0, sizeof(buf));
  410. }
  411. if (read_count == 0)
  412. vjson_error(err, "no JSON input");
  413. json_tokener_free(tok);
  414. return r;
  415. }
  416. /**
  417. * validate_firmware_image_call - perform validation & store result in global b
  418. *
  419. * @file: firmware image path
  420. */
  421. static enum vjson_state validate_firmware_image_call(const char *file, char **err)
  422. {
  423. const char *path = "/usr/libexec/validate_firmware_image";
  424. enum vjson_state ret = VJSON_ERROR;
  425. int _errno;
  426. int fds[2];
  427. int fd;
  428. blob_buf_init(&b, 0);
  429. vjson_error(err, "unhandled error");
  430. if (pipe(fds)) {
  431. _errno = errno;
  432. return vjson_error(err, "pipe() failed: %s (%d)",
  433. strerror(_errno), _errno);
  434. }
  435. switch (fork()) {
  436. case -1:
  437. _errno = errno;
  438. close(fds[0]);
  439. close(fds[1]);
  440. return vjson_error(err, "fork() failed: %s (%d)",
  441. strerror(_errno), _errno);
  442. case 0:
  443. /* Set stdin & stderr to /dev/null */
  444. fd = open("/dev/null", O_RDWR);
  445. if (fd >= 0) {
  446. dup2(fd, 0);
  447. dup2(fd, 2);
  448. close(fd);
  449. }
  450. /* Set stdout to the shared pipe */
  451. dup2(fds[1], 1);
  452. close(fds[0]);
  453. close(fds[1]);
  454. execl(path, path, file, NULL);
  455. exit(errno);
  456. }
  457. /* Parent process */
  458. close(fds[1]);
  459. ret = vjson_parse(fds[0], err);
  460. close(fds[0]);
  461. return ret;
  462. }
  463. enum {
  464. VALIDATE_FIRMWARE_IMAGE_PATH,
  465. __VALIDATE_FIRMWARE_IMAGE_MAX,
  466. };
  467. static const struct blobmsg_policy validate_firmware_image_policy[__VALIDATE_FIRMWARE_IMAGE_MAX] = {
  468. [VALIDATE_FIRMWARE_IMAGE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
  469. };
  470. static int validate_firmware_image(struct ubus_context *ctx,
  471. struct ubus_object *obj,
  472. struct ubus_request_data *req,
  473. const char *method, struct blob_attr *msg)
  474. {
  475. struct blob_attr *tb[__VALIDATE_FIRMWARE_IMAGE_MAX];
  476. enum vjson_state ret = VJSON_ERROR;
  477. char *err;
  478. if (!msg)
  479. return UBUS_STATUS_INVALID_ARGUMENT;
  480. blobmsg_parse(validate_firmware_image_policy, __VALIDATE_FIRMWARE_IMAGE_MAX, tb, blob_data(msg), blob_len(msg));
  481. if (!tb[VALIDATE_FIRMWARE_IMAGE_PATH])
  482. return UBUS_STATUS_INVALID_ARGUMENT;
  483. ret = validate_firmware_image_call(blobmsg_get_string(tb[VALIDATE_FIRMWARE_IMAGE_PATH]), &err);
  484. if (ret != VJSON_SUCCESS)
  485. return UBUS_STATUS_UNKNOWN_ERROR;
  486. ubus_send_reply(ctx, req, b.head);
  487. return UBUS_STATUS_OK;
  488. }
  489. enum {
  490. SYSUPGRADE_PATH,
  491. SYSUPGRADE_FORCE,
  492. SYSUPGRADE_BACKUP,
  493. SYSUPGRADE_PREFIX,
  494. SYSUPGRADE_COMMAND,
  495. SYSUPGRADE_OPTIONS,
  496. __SYSUPGRADE_MAX
  497. };
  498. static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = {
  499. [SYSUPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
  500. [SYSUPGRADE_FORCE] = { .name = "force", .type = BLOBMSG_TYPE_BOOL },
  501. [SYSUPGRADE_BACKUP] = { .name = "backup", .type = BLOBMSG_TYPE_STRING },
  502. [SYSUPGRADE_PREFIX] = { .name = "prefix", .type = BLOBMSG_TYPE_STRING },
  503. [SYSUPGRADE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING },
  504. [SYSUPGRADE_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_TABLE },
  505. };
  506. static void sysupgrade_error(struct ubus_context *ctx,
  507. struct ubus_request_data *req,
  508. const char *message)
  509. {
  510. void *c;
  511. blob_buf_init(&b, 0);
  512. c = blobmsg_open_table(&b, "error");
  513. blobmsg_add_string(&b, "message", message);
  514. blobmsg_close_table(&b, c);
  515. ubus_send_reply(ctx, req, b.head);
  516. }
  517. static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
  518. struct ubus_request_data *req, const char *method,
  519. struct blob_attr *msg)
  520. {
  521. enum {
  522. VALIDATION_VALID,
  523. VALIDATION_FORCEABLE,
  524. VALIDATION_ALLOW_BACKUP,
  525. __VALIDATION_MAX
  526. };
  527. static const struct blobmsg_policy validation_policy[__VALIDATION_MAX] = {
  528. [VALIDATION_VALID] = { .name = "valid", .type = BLOBMSG_TYPE_BOOL },
  529. [VALIDATION_FORCEABLE] = { .name = "forceable", .type = BLOBMSG_TYPE_BOOL },
  530. [VALIDATION_ALLOW_BACKUP] = { .name = "allow_backup", .type = BLOBMSG_TYPE_BOOL },
  531. };
  532. struct blob_attr *validation[__VALIDATION_MAX];
  533. struct blob_attr *tb[__SYSUPGRADE_MAX];
  534. bool valid, forceable, allow_backup;
  535. enum vjson_state ret = VJSON_ERROR;
  536. char *err;
  537. if (!msg)
  538. return UBUS_STATUS_INVALID_ARGUMENT;
  539. blobmsg_parse(sysupgrade_policy, __SYSUPGRADE_MAX, tb, blob_data(msg), blob_len(msg));
  540. if (!tb[SYSUPGRADE_PATH] || !tb[SYSUPGRADE_PREFIX])
  541. return UBUS_STATUS_INVALID_ARGUMENT;
  542. ret = validate_firmware_image_call(blobmsg_get_string(tb[SYSUPGRADE_PATH]), &err);
  543. if (ret != VJSON_SUCCESS) {
  544. sysupgrade_error(ctx, req, err);
  545. return UBUS_STATUS_UNKNOWN_ERROR;
  546. }
  547. blobmsg_parse(validation_policy, __VALIDATION_MAX, validation, blob_data(b.head), blob_len(b.head));
  548. if (!validation[VALIDATION_VALID] || !validation[VALIDATION_FORCEABLE] ||
  549. !validation[VALIDATION_ALLOW_BACKUP]) {
  550. sysupgrade_error(ctx, req, "Validation script provided invalid input");
  551. return UBUS_STATUS_INVALID_ARGUMENT;
  552. }
  553. valid = validation[VALIDATION_VALID] && blobmsg_get_bool(validation[VALIDATION_VALID]);
  554. forceable = validation[VALIDATION_FORCEABLE] && blobmsg_get_bool(validation[VALIDATION_FORCEABLE]);
  555. allow_backup = validation[VALIDATION_ALLOW_BACKUP] && blobmsg_get_bool(validation[VALIDATION_ALLOW_BACKUP]);
  556. if (!valid) {
  557. if (!forceable) {
  558. sysupgrade_error(ctx, req, "Firmware image is broken and cannot be installed");
  559. return UBUS_STATUS_NOT_SUPPORTED;
  560. } else if (!tb[SYSUPGRADE_FORCE] || !blobmsg_get_bool(tb[SYSUPGRADE_FORCE])) {
  561. sysupgrade_error(ctx, req, "Firmware image is invalid");
  562. return UBUS_STATUS_NOT_SUPPORTED;
  563. }
  564. } else if (!allow_backup && tb[SYSUPGRADE_BACKUP]) {
  565. sysupgrade_error(ctx, req, "Firmware image doesn't allow preserving a backup");
  566. return UBUS_STATUS_NOT_SUPPORTED;
  567. }
  568. sysupgrade_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]),
  569. blobmsg_get_string(tb[SYSUPGRADE_PATH]),
  570. tb[SYSUPGRADE_BACKUP] ? blobmsg_get_string(tb[SYSUPGRADE_BACKUP]) : NULL,
  571. tb[SYSUPGRADE_COMMAND] ? blobmsg_get_string(tb[SYSUPGRADE_COMMAND]) : NULL,
  572. tb[SYSUPGRADE_OPTIONS]);
  573. /* sysupgrade_exec_upgraded() will never return unless something has gone wrong */
  574. return UBUS_STATUS_UNKNOWN_ERROR;
  575. }
  576. static void
  577. procd_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
  578. {
  579. notify = obj->has_subscribers;
  580. }
  581. static const struct ubus_method system_methods[] = {
  582. UBUS_METHOD_NOARG("board", system_board),
  583. UBUS_METHOD_NOARG("info", system_info),
  584. UBUS_METHOD_NOARG("reboot", system_reboot),
  585. UBUS_METHOD("watchdog", watchdog_set, watchdog_policy),
  586. UBUS_METHOD("signal", proc_signal, signal_policy),
  587. UBUS_METHOD("validate_firmware_image", validate_firmware_image, validate_firmware_image_policy),
  588. UBUS_METHOD("sysupgrade", sysupgrade, sysupgrade_policy),
  589. };
  590. static struct ubus_object_type system_object_type =
  591. UBUS_OBJECT_TYPE("system", system_methods);
  592. static struct ubus_object system_object = {
  593. .name = "system",
  594. .type = &system_object_type,
  595. .methods = system_methods,
  596. .n_methods = ARRAY_SIZE(system_methods),
  597. .subscribe_cb = procd_subscribe_cb,
  598. };
  599. void
  600. procd_bcast_event(char *event, struct blob_attr *msg)
  601. {
  602. int ret;
  603. if (!notify)
  604. return;
  605. ret = ubus_notify(_ctx, &system_object, event, msg, -1);
  606. if (ret)
  607. fprintf(stderr, "Failed to notify log: %s\n", ubus_strerror(ret));
  608. }
  609. void ubus_init_system(struct ubus_context *ctx)
  610. {
  611. int ret;
  612. _ctx = ctx;
  613. ret = ubus_add_object(ctx, &system_object);
  614. if (ret)
  615. ERROR("Failed to add object: %s\n", ubus_strerror(ret));
  616. }