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