ce30798e5478877ae82ea0a4b225e31c2ef40134
[project/procd.git] / sysupgrade.c
1 /*
2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
4 * Copyright (C) 2017 Matthias Schiffer <mschiffer@universe-factory.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version 2.1
8 * as published by the Free Software Foundation
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16
17 #define _GNU_SOURCE
18 #include "watchdog.h"
19 #include "sysupgrade.h"
20
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25
26 #include <libubox/blobmsg.h>
27
28 void sysupgrade_exec_upgraded(const char *prefix, char *path, char *command,
29 struct blob_attr *options)
30 {
31 char *wdt_fd = watchdog_fd();
32 char *argv[] = { "/sbin/upgraded", NULL, NULL, NULL};
33 struct blob_attr *option;
34 int rem;
35 int ret;
36
37 ret = chroot(prefix);
38 if (ret < 0) {
39 fprintf(stderr, "Failed to chroot for upgraded exec.\n");
40 return;
41 }
42
43 argv[1] = path;
44 argv[2] = command;
45
46 if (wdt_fd) {
47 watchdog_set_cloexec(false);
48 setenv("WDTFD", wdt_fd, 1);
49 }
50
51 blobmsg_for_each_attr(option, options, rem) {
52 const char *prefix = "UPGRADE_OPT_";
53 char value[11];
54 char *name;
55 char *c;
56 int tmp;
57
58 if (asprintf(&name, "%s%s", prefix, blobmsg_name(option)) <= 0)
59 continue;
60 for (c = name + strlen(prefix); *c; c++) {
61 if (isalnum(*c) || *c == '_') {
62 *c = toupper(*c);
63 } else {
64 c = NULL;
65 break;
66 }
67 }
68
69 if (!c) {
70 fprintf(stderr, "Option \"%s\" contains invalid characters\n",
71 blobmsg_name(option));
72 free(name);
73 continue;
74 }
75
76 switch (blobmsg_type(option)) {
77 case BLOBMSG_TYPE_INT32:
78 tmp = blobmsg_get_u32(option);
79 break;
80 case BLOBMSG_TYPE_INT16:
81 tmp = blobmsg_get_u16(option);
82 break;
83 case BLOBMSG_TYPE_INT8:
84 tmp = blobmsg_get_u8(option);
85 break;
86 default:
87 fprintf(stderr, "Option \"%s\" has unsupported type: %d\n",
88 blobmsg_name(option), blobmsg_type(option));
89 free(name);
90 continue;
91 }
92 snprintf(value, sizeof(value), "%u", tmp);
93
94 setenv(name, value, 1);
95
96 free(name);
97 }
98
99 execvp(argv[0], argv);
100
101 /* Cleanup on failure */
102 fprintf(stderr, "Failed to exec upgraded.\n");
103 unsetenv("WDTFD");
104 watchdog_set_cloexec(true);
105 ret = chroot(".");
106 if (ret < 0) {
107 fprintf(stderr, "Failed to reset chroot, exiting.\n");
108 exit(EXIT_FAILURE);
109 }
110 }