system.c 21 KB

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