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