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