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 285 continue; 286 287 dest = blobmsg_alloc_string_buffer(&b, key, strlen(val)); 288 if (!dest) { 289 ERROR("Failed to allocate blob.\n"); 290 continue; 291 } 292 293 while (val && (ch = *(val++)) != 0) { 294 switch (ch) { 295 case '\'': 296 case '"': 297 next = strchr(val, ch); 298 if (next) 299 *next = 0; 300 301 strcpy(dest, val); 302 303 if (next) 304 val = next + 1; 305 306 dest += strlen(dest); 307 break; 308 case '\\': 309 *(dest++) = *(val++); 310 break; 311 } 312 } 313 blobmsg_add_string_buffer(&b); 314 } 315 316 blobmsg_close_array(&b, c); 317 318 fclose(f); 319 } 320 321 ubus_send_reply(ctx, req, b.head); 322 323 return UBUS_STATUS_OK; 324 } 325 326 static unsigned long 327 kscale(unsigned long b, unsigned long bs) 328 { 329 return (b * (unsigned long long) bs + 1024/2) / 1024; 330 } 331 332 static int system_info(struct ubus_context *ctx, struct ubus_object *obj, 333 struct ubus_request_data *req, const char *method, 334 struct blob_attr *msg) 335 { 336 time_t now; 337 struct tm *tm; 338 #ifdef linux 339 struct sysinfo info; 340 void *c; 341 char line[256]; 342 char *key, *val; 343 unsigned long long available, cached; 344 FILE *f; 345 int i; 346 struct statvfs s; 347 const char *fslist[] = { 348 "/", "root", 349 "/tmp", "tmp", 350 }; 351 352 if (sysinfo(&info)) 353 return UBUS_STATUS_UNKNOWN_ERROR; 354 355 if ((f = fopen("/proc/meminfo", "r")) == NULL) 356 return UBUS_STATUS_UNKNOWN_ERROR; 357 358 /* if linux < 3.14 MemAvailable is not in meminfo */ 359 available = 0; 360 cached = 0; 361 362 while (fgets(line, sizeof(line), f)) 363 { 364 key = strtok(line, " :"); 365 val = strtok(NULL, " "); 366 367 if (!key || !val) 368 continue; 369 370 if (!strcasecmp(key, "MemAvailable")) 371 available = 1024 * atoll(val); 372 else if (!strcasecmp(key, "Cached")) 373 cached = 1024 * atoll(val); 374 } 375 376 fclose(f); 377 #endif 378 379 now = time(NULL); 380 381 if (!(tm = localtime(&now))) 382 return UBUS_STATUS_UNKNOWN_ERROR; 383 384 blob_buf_init(&b, 0); 385 386 blobmsg_add_u32(&b, "localtime", now + tm->tm_gmtoff); 387 388 #ifdef linux 389 blobmsg_add_u32(&b, "uptime", info.uptime); 390 391 c = blobmsg_open_array(&b, "load"); 392 blobmsg_add_u32(&b, NULL, info.loads[0]); 393 blobmsg_add_u32(&b, NULL, info.loads[1]); 394 blobmsg_add_u32(&b, NULL, info.loads[2]); 395 blobmsg_close_array(&b, c); 396 397 c = blobmsg_open_table(&b, "memory"); 398 blobmsg_add_u64(&b, "total", 399 (uint64_t)info.mem_unit * (uint64_t)info.totalram); 400 blobmsg_add_u64(&b, "free", 401 (uint64_t)info.mem_unit * (uint64_t)info.freeram); 402 blobmsg_add_u64(&b, "shared", 403 (uint64_t)info.mem_unit * (uint64_t)info.sharedram); 404 blobmsg_add_u64(&b, "buffered", 405 (uint64_t)info.mem_unit * (uint64_t)info.bufferram); 406 blobmsg_add_u64(&b, "available", available); 407 blobmsg_add_u64(&b, "cached", cached); 408 blobmsg_close_table(&b, c); 409 410 for (i = 0; i < sizeof(fslist) / sizeof(fslist[0]); i += 2) { 411 if (statvfs(fslist[i], &s)) 412 continue; 413 414 c = blobmsg_open_table(&b, fslist[i+1]); 415 416 if (!s.f_frsize) 417 s.f_frsize = s.f_bsize; 418 419 blobmsg_add_u64(&b, "total", kscale(s.f_blocks, s.f_frsize)); 420 blobmsg_add_u64(&b, "free", kscale(s.f_bfree, s.f_frsize)); 421 blobmsg_add_u64(&b, "used", kscale(s.f_blocks - s.f_bfree, s.f_frsize)); 422 blobmsg_add_u64(&b, "avail", kscale(s.f_bavail, s.f_frsize)); 423 424 blobmsg_close_table(&b, c); 425 } 426 427 c = blobmsg_open_table(&b, "swap"); 428 blobmsg_add_u64(&b, "total", 429 (uint64_t)info.mem_unit * (uint64_t)info.totalswap); 430 blobmsg_add_u64(&b, "free", 431 (uint64_t)info.mem_unit * (uint64_t)info.freeswap); 432 blobmsg_close_table(&b, c); 433 #endif 434 435 ubus_send_reply(ctx, req, b.head); 436 437 return UBUS_STATUS_OK; 438 } 439 440 static int system_reboot(struct ubus_context *ctx, struct ubus_object *obj, 441 struct ubus_request_data *req, const char *method, 442 struct blob_attr *msg) 443 { 444 procd_shutdown(RB_AUTOBOOT); 445 return 0; 446 } 447 448 enum { 449 WDT_FREQUENCY, 450 WDT_TIMEOUT, 451 WDT_MAGICCLOSE, 452 WDT_STOP, 453 __WDT_MAX 454 }; 455 456 static const struct blobmsg_policy watchdog_policy[__WDT_MAX] = { 457 [WDT_FREQUENCY] = { .name = "frequency", .type = BLOBMSG_TYPE_INT32 }, 458 [WDT_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 }, 459 [WDT_MAGICCLOSE] = { .name = "magicclose", .type = BLOBMSG_TYPE_BOOL }, 460 [WDT_STOP] = { .name = "stop", .type = BLOBMSG_TYPE_BOOL }, 461 }; 462 463 static int watchdog_set(struct ubus_context *ctx, struct ubus_object *obj, 464 struct ubus_request_data *req, const char *method, 465 struct blob_attr *msg) 466 { 467 struct blob_attr *tb[__WDT_MAX]; 468 const char *status; 469 470 if (!msg) 471 return UBUS_STATUS_INVALID_ARGUMENT; 472 473 blobmsg_parse(watchdog_policy, __WDT_MAX, tb, blob_data(msg), blob_len(msg)); 474 if (tb[WDT_FREQUENCY]) { 475 unsigned int timeout = tb[WDT_TIMEOUT] ? blobmsg_get_u32(tb[WDT_TIMEOUT]) : 476 watchdog_timeout(0); 477 unsigned int freq = blobmsg_get_u32(tb[WDT_FREQUENCY]); 478 479 if (freq) { 480 if (freq > timeout / 2) 481 freq = timeout / 2; 482 watchdog_frequency(freq); 483 } 484 } 485 486 if (tb[WDT_TIMEOUT]) { 487 unsigned int timeout = blobmsg_get_u32(tb[WDT_TIMEOUT]); 488 unsigned int frequency = watchdog_frequency(0); 489 490 if (timeout <= frequency) 491 timeout = frequency * 2; 492 watchdog_timeout(timeout); 493 } 494 495 if (tb[WDT_MAGICCLOSE]) 496 watchdog_set_magicclose(blobmsg_get_bool(tb[WDT_MAGICCLOSE])); 497 498 if (tb[WDT_STOP]) 499 watchdog_set_stopped(blobmsg_get_bool(tb[WDT_STOP])); 500 501 if (watchdog_fd() == NULL) 502 status = "offline"; 503 else if (watchdog_get_stopped()) 504 status = "stopped"; 505 else 506 status = "running"; 507 508 blob_buf_init(&b, 0); 509 blobmsg_add_string(&b, "status", status); 510 blobmsg_add_u32(&b, "timeout", watchdog_timeout(0)); 511 blobmsg_add_u32(&b, "frequency", watchdog_frequency(0)); 512 blobmsg_add_u8(&b, "magicclose", watchdog_get_magicclose()); 513 ubus_send_reply(ctx, req, b.head); 514 515 return 0; 516 } 517 518 enum { 519 SIGNAL_PID, 520 SIGNAL_NUM, 521 __SIGNAL_MAX 522 }; 523 524 static const struct blobmsg_policy signal_policy[__SIGNAL_MAX] = { 525 [SIGNAL_PID] = { .name = "pid", .type = BLOBMSG_TYPE_INT32 }, 526 [SIGNAL_NUM] = { .name = "signum", .type = BLOBMSG_TYPE_INT32 }, 527 }; 528 529 static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj, 530 struct ubus_request_data *req, const char *method, 531 struct blob_attr *msg) 532 { 533 struct blob_attr *tb[__SIGNAL_MAX]; 534 535 if (!msg) 536 return UBUS_STATUS_INVALID_ARGUMENT; 537 538 blobmsg_parse(signal_policy, __SIGNAL_MAX, tb, blob_data(msg), blob_len(msg)); 539 if (!tb[SIGNAL_PID || !tb[SIGNAL_NUM]]) 540 return UBUS_STATUS_INVALID_ARGUMENT; 541 542 kill(blobmsg_get_u32(tb[SIGNAL_PID]), blobmsg_get_u32(tb[SIGNAL_NUM])); 543 544 return 0; 545 } 546 547 __attribute__((format (printf, 2, 3))) 548 static enum vjson_state vjson_error(char **b, const char *fmt, ...) 549 { 550 static char buf[256] = { 0 }; 551 const char *pfx = "Firmware image couldn't be validated: "; 552 va_list va; 553 int r; 554 555 r = snprintf(buf, sizeof(buf), "%s", pfx); 556 if (r < 0) { 557 *b = "vjson_error() snprintf failed"; 558 return VJSON_ERROR; 559 } 560 561 va_start(va, fmt); 562 r = vsnprintf(buf+r, sizeof(buf)-r, fmt, va); 563 if (r < 0) { 564 *b = "vjson_error() vsnprintf failed"; 565 return VJSON_ERROR; 566 } 567 va_end(va); 568 569 *b = buf; 570 return VJSON_ERROR; 571 } 572 573 static enum vjson_state vjson_parse_token(json_tokener *tok, char *buf, ssize_t len, char **err) 574 { 575 json_object *jsobj = NULL; 576 577 jsobj = json_tokener_parse_ex(tok, buf, len); 578 if (json_tokener_get_error(tok) == json_tokener_continue) 579 return VJSON_CONTINUE; 580 581 if (json_tokener_get_error(tok) == json_tokener_success) { 582 if (json_object_get_type(jsobj) != json_type_object) { 583 json_object_put(jsobj); 584 return vjson_error(err, "result is not an JSON object"); 585 } 586 587 blobmsg_add_object(&b, jsobj); 588 json_object_put(jsobj); 589 return VJSON_SUCCESS; 590 } 591 592 return vjson_error(err, "failed to parse JSON: %s (%d)", 593 json_tokener_error_desc(json_tokener_get_error(tok)), 594 json_tokener_get_error(tok)); 595 } 596 597 static enum vjson_state vjson_parse(int fd, char **err) 598 { 599 enum vjson_state r = VJSON_ERROR; 600 size_t read_count = 0; 601 char buf[64] = { 0 }; 602 json_tokener *tok; 603 ssize_t len; 604 int _errno; 605 606 tok = json_tokener_new(); 607 if (!tok) 608 return vjson_error(err, "json_tokener_new() failed"); 609 610 vjson_error(err, "incomplete JSON input"); 611 612 while ((len = read(fd, buf, sizeof(buf)))) { 613 if (len < 0 && errno == EINTR) 614 continue; 615 616 if (len < 0) { 617 _errno = errno; 618 json_tokener_free(tok); 619 return vjson_error(err, "read() failed: %s (%d)", 620 strerror(_errno), _errno); 621 } 622 623 read_count += len; 624 r = vjson_parse_token(tok, buf, len, err); 625 if (r != VJSON_CONTINUE) 626 break; 627 628 memset(buf, 0, sizeof(buf)); 629 } 630 631 if (read_count == 0) 632 vjson_error(err, "no JSON input"); 633 634 json_tokener_free(tok); 635 return r; 636 } 637 638 /** 639 * validate_firmware_image_call - perform validation & store result in global b 640 * 641 * @file: firmware image path 642 */ 643 static enum vjson_state validate_firmware_image_call(const char *file, char **err) 644 { 645 const char *path = "/usr/libexec/validate_firmware_image"; 646 enum vjson_state ret = VJSON_ERROR; 647 int _errno; 648 int fds[2]; 649 int fd; 650 651 blob_buf_init(&b, 0); 652 vjson_error(err, "unhandled error"); 653 654 if (pipe(fds)) { 655 _errno = errno; 656 return vjson_error(err, "pipe() failed: %s (%d)", 657 strerror(_errno), _errno); 658 } 659 660 switch (fork()) { 661 case -1: 662 _errno = errno; 663 664 close(fds[0]); 665 close(fds[1]); 666 667 return vjson_error(err, "fork() failed: %s (%d)", 668 strerror(_errno), _errno); 669 case 0: 670 /* Set stdin & stderr to /dev/null */ 671 fd = open("/dev/null", O_RDWR); 672 if (fd >= 0) { 673 dup2(fd, 0); 674 dup2(fd, 2); 675 close(fd); 676 } 677 678 /* Set stdout to the shared pipe */ 679 dup2(fds[1], 1); 680 close(fds[0]); 681 close(fds[1]); 682 683 execl(path, path, file, NULL); 684 exit(errno); 685 } 686 687 /* Parent process */ 688 close(fds[1]); 689 690 ret = vjson_parse(fds[0], err); 691 close(fds[0]); 692 693 return ret; 694 } 695 696 enum { 697 VALIDATE_FIRMWARE_IMAGE_PATH, 698 __VALIDATE_FIRMWARE_IMAGE_MAX, 699 }; 700 701 static const struct blobmsg_policy validate_firmware_image_policy[__VALIDATE_FIRMWARE_IMAGE_MAX] = { 702 [VALIDATE_FIRMWARE_IMAGE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, 703 }; 704 705 static int validate_firmware_image(struct ubus_context *ctx, 706 struct ubus_object *obj, 707 struct ubus_request_data *req, 708 const char *method, struct blob_attr *msg) 709 { 710 struct blob_attr *tb[__VALIDATE_FIRMWARE_IMAGE_MAX]; 711 enum vjson_state ret = VJSON_ERROR; 712 char *err; 713 714 if (!msg) 715 return UBUS_STATUS_INVALID_ARGUMENT; 716 717 blobmsg_parse(validate_firmware_image_policy, __VALIDATE_FIRMWARE_IMAGE_MAX, tb, blob_data(msg), blob_len(msg)); 718 if (!tb[VALIDATE_FIRMWARE_IMAGE_PATH]) 719 return UBUS_STATUS_INVALID_ARGUMENT; 720 721 ret = validate_firmware_image_call(blobmsg_get_string(tb[VALIDATE_FIRMWARE_IMAGE_PATH]), &err); 722 if (ret != VJSON_SUCCESS) 723 return UBUS_STATUS_UNKNOWN_ERROR; 724 725 ubus_send_reply(ctx, req, b.head); 726 727 return UBUS_STATUS_OK; 728 } 729 730 enum { 731 SYSUPGRADE_PATH, 732 SYSUPGRADE_FORCE, 733 SYSUPGRADE_BACKUP, 734 SYSUPGRADE_PREFIX, 735 SYSUPGRADE_COMMAND, 736 SYSUPGRADE_OPTIONS, 737 __SYSUPGRADE_MAX 738 }; 739 740 static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = { 741 [SYSUPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING }, 742 [SYSUPGRADE_FORCE] = { .name = "force", .type = BLOBMSG_TYPE_BOOL }, 743 [SYSUPGRADE_BACKUP] = { .name = "backup", .type = BLOBMSG_TYPE_STRING }, 744 [SYSUPGRADE_PREFIX] = { .name = "prefix", .type = BLOBMSG_TYPE_STRING }, 745 [SYSUPGRADE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING }, 746 [SYSUPGRADE_OPTIONS] = { .name = "options", .type = BLOBMSG_TYPE_TABLE }, 747 }; 748 749 static void sysupgrade_error(struct ubus_context *ctx, 750 struct ubus_request_data *req, 751 const char *message) 752 { 753 void *c; 754 755 blob_buf_init(&b, 0); 756 757 c = blobmsg_open_table(&b, "error"); 758 blobmsg_add_string(&b, "message", message); 759 blobmsg_close_table(&b, c); 760 761 ubus_send_reply(ctx, req, b.head); 762 } 763 764 static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj, 765 struct ubus_request_data *req, const char *method, 766 struct blob_attr *msg) 767 { 768 enum { 769 VALIDATION_VALID, 770 VALIDATION_FORCEABLE, 771 VALIDATION_ALLOW_BACKUP, 772 __VALIDATION_MAX 773 }; 774 static const struct blobmsg_policy validation_policy[__VALIDATION_MAX] = { 775 [VALIDATION_VALID] = { .name = "valid", .type = BLOBMSG_TYPE_BOOL }, 776 [VALIDATION_FORCEABLE] = { .name = "forceable", .type = BLOBMSG_TYPE_BOOL }, 777 [VALIDATION_ALLOW_BACKUP] = { .name = "allow_backup", .type = BLOBMSG_TYPE_BOOL }, 778 }; 779 struct blob_attr *validation[__VALIDATION_MAX]; 780 struct blob_attr *tb[__SYSUPGRADE_MAX]; 781 bool valid, forceable, allow_backup; 782 enum vjson_state ret = VJSON_ERROR; 783 char *err; 784 785 if (!msg) 786 return UBUS_STATUS_INVALID_ARGUMENT; 787 788 blobmsg_parse(sysupgrade_policy, __SYSUPGRADE_MAX, tb, blob_data(msg), blob_len(msg)); 789 if (!tb[SYSUPGRADE_PATH] || !tb[SYSUPGRADE_PREFIX]) 790 return UBUS_STATUS_INVALID_ARGUMENT; 791 792 ret = validate_firmware_image_call(blobmsg_get_string(tb[SYSUPGRADE_PATH]), &err); 793 if (ret != VJSON_SUCCESS) { 794 sysupgrade_error(ctx, req, err); 795 return UBUS_STATUS_UNKNOWN_ERROR; 796 } 797 798 blobmsg_parse(validation_policy, __VALIDATION_MAX, validation, blob_data(b.head), blob_len(b.head)); 799 800 if (!validation[VALIDATION_VALID] || !validation[VALIDATION_FORCEABLE] || 801 !validation[VALIDATION_ALLOW_BACKUP]) { 802 sysupgrade_error(ctx, req, "Validation script provided invalid input"); 803 return UBUS_STATUS_INVALID_ARGUMENT; 804 } 805 806 valid = validation[VALIDATION_VALID] && blobmsg_get_bool(validation[VALIDATION_VALID]); 807 forceable = validation[VALIDATION_FORCEABLE] && blobmsg_get_bool(validation[VALIDATION_FORCEABLE]); 808 allow_backup = validation[VALIDATION_ALLOW_BACKUP] && blobmsg_get_bool(validation[VALIDATION_ALLOW_BACKUP]); 809 810 if (!valid) { 811 if (!forceable) { 812 sysupgrade_error(ctx, req, "Firmware image is broken and cannot be installed"); 813 return UBUS_STATUS_NOT_SUPPORTED; 814 } else if (!tb[SYSUPGRADE_FORCE] || !blobmsg_get_bool(tb[SYSUPGRADE_FORCE])) { 815 sysupgrade_error(ctx, req, "Firmware image is invalid"); 816 return UBUS_STATUS_NOT_SUPPORTED; 817 } 818 } else if (!allow_backup && tb[SYSUPGRADE_BACKUP]) { 819 sysupgrade_error(ctx, req, "Firmware image doesn't allow preserving a backup"); 820 return UBUS_STATUS_NOT_SUPPORTED; 821 } 822 823 service_stop_all(); 824 825 sysupgrade_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]), 826 blobmsg_get_string(tb[SYSUPGRADE_PATH]), 827 tb[SYSUPGRADE_BACKUP] ? blobmsg_get_string(tb[SYSUPGRADE_BACKUP]) : NULL, 828 tb[SYSUPGRADE_COMMAND] ? blobmsg_get_string(tb[SYSUPGRADE_COMMAND]) : NULL, 829 tb[SYSUPGRADE_OPTIONS]); 830 831 /* sysupgrade_exec_upgraded() will never return unless something has gone wrong */ 832 return UBUS_STATUS_UNKNOWN_ERROR; 833 } 834 835 static void 836 procd_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj) 837 { 838 notify = obj->has_subscribers; 839 } 840 841 842 static const struct ubus_method system_methods[] = { 843 UBUS_METHOD_NOARG("board", system_board), 844 UBUS_METHOD_NOARG("info", system_info), 845 UBUS_METHOD_NOARG("reboot", system_reboot), 846 UBUS_METHOD("watchdog", watchdog_set, watchdog_policy), 847 UBUS_METHOD("signal", proc_signal, signal_policy), 848 UBUS_METHOD("validate_firmware_image", validate_firmware_image, validate_firmware_image_policy), 849 UBUS_METHOD("sysupgrade", sysupgrade, sysupgrade_policy), 850 }; 851 852 static struct ubus_object_type system_object_type = 853 UBUS_OBJECT_TYPE("system", system_methods); 854 855 static struct ubus_object system_object = { 856 .name = "system", 857 .type = &system_object_type, 858 .methods = system_methods, 859 .n_methods = ARRAY_SIZE(system_methods), 860 .subscribe_cb = procd_subscribe_cb, 861 }; 862 863 void 864 procd_bcast_event(char *event, struct blob_attr *msg) 865 { 866 int ret; 867 868 if (!notify) 869 return; 870 871 ret = ubus_notify(_ctx, &system_object, event, msg, -1); 872 if (ret) 873 fprintf(stderr, "Failed to notify log: %s\n", ubus_strerror(ret)); 874 } 875 876 void ubus_init_system(struct ubus_context *ctx) 877 { 878 int ret; 879 880 _ctx = ctx; 881 882 initramfs = !!getenv("INITRAMFS"); 883 if (initramfs) 884 unsetenv("INITRAMFS"); 885 886 ret = ubus_add_object(ctx, &system_object); 887 if (ret) 888 ERROR("Failed to add object: %s\n", ubus_strerror(ret)); 889 } 890
This page was automatically generated by LXR 0.3.1. • OpenWrt