• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/procd/system.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt