gluon/patches/openwrt/0106-procd-add-universal-staged-sysupgrade-patches.patch

1117 lines
34 KiB
Diff
Raw Permalink Normal View History

From: Matthias Schiffer <mschiffer@universe-factory.net>
Date: Thu, 1 Jun 2017 22:42:04 +0200
Subject: procd: add universal staged sysupgrade patches
diff --git a/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch b/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch
deleted file mode 100644
index bc2434200364b46f1db4c2eec22c4e8b973844d5..0000000000000000000000000000000000000000
--- a/package/system/procd/patches/0001-Add-support-for-alternative-rc.d-directories.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From 03a2bc70e4260ec9f669391c47b9a7a9ecd0b75d Mon Sep 17 00:00:00 2001
-Message-Id: <03a2bc70e4260ec9f669391c47b9a7a9ecd0b75d.1407329621.git.mschiffer@universe-factory.net>
-From: Matthias Schiffer <mschiffer@universe-factory.net>
-Date: Wed, 6 Aug 2014 14:51:49 +0200
-Subject: [PATCH] Add support for alternative rc.d directories
-
----
- initd/preinit.c | 38 ++++++++++++++++++++++++++++++++++++++
- rcS.c | 2 +-
- 2 files changed, 39 insertions(+), 1 deletion(-)
-
-diff --git a/initd/preinit.c b/initd/preinit.c
-index fb94527..8b832a7 100644
---- a/initd/preinit.c
-+++ b/initd/preinit.c
-@@ -12,6 +12,8 @@
- * GNU General Public License for more details.
- */
-
-+#define _GNU_SOURCE
-+
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <sys/mount.h>
-@@ -46,6 +48,35 @@ check_dbglvl(void)
- debug = lvl;
- }
-
-+static char*
-+get_rc_d(void)
-+{
-+ size_t n = 0;
-+ ssize_t len;
-+ char *ret = NULL;
-+
-+ FILE *fp = fopen("/tmp/rc_d_path", "r");
-+
-+ if (!fp)
-+ return NULL;
-+
-+ len = getline(&ret, &n, fp);
-+
-+ fclose(fp);
-+
-+ unlink("/tmp/rc_d_path");
-+
-+ if (len <= 0) {
-+ free(ret);
-+ return NULL;
-+ }
-+
-+ if (ret[len-1] == '\n')
-+ ret[len-1] = 0;
-+
-+ return ret;
-+}
-+
- static void
- spawn_procd(struct uloop_process *proc, int ret)
- {
-@@ -53,6 +84,7 @@ spawn_procd(struct uloop_process *proc, int ret)
- char *argv[] = { "/sbin/procd", NULL};
- struct stat s;
- char dbg[2];
-+ char *rc_d_path;
-
- if (plugd_proc.pid > 0)
- kill(plugd_proc.pid, SIGKILL);
-@@ -72,6 +104,12 @@ spawn_procd(struct uloop_process *proc, int ret)
- setenv("DBGLVL", dbg, 1);
- }
-
-+ rc_d_path = get_rc_d();
-+ if (rc_d_path) {
-+ setenv("RC_D_PATH", rc_d_path, 1);
-+ free(rc_d_path);
-+ }
-+
- execvp(argv[0], argv);
- }
-
-diff --git a/rcS.c b/rcS.c
-index 0e1b0ba..1b00831 100644
---- a/rcS.c
-+++ b/rcS.c
-@@ -150,7 +150,7 @@ int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *))
- q.empty_cb = q_empty;
- q.max_running_tasks = 1;
-
-- return _rc(&q, "/etc/rc.d", pattern, "*", param);
-+ return _rc(&q, getenv("RC_D_PATH") ?: "/etc/rc.d", pattern, "*", param);
- }
-
- int rc(const char *file, char *param)
---
-2.0.4
-
diff --git a/package/system/procd/patches/1001-Add-support-for-alternative-rc.d-directories.patch b/package/system/procd/patches/1001-Add-support-for-alternative-rc.d-directories.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2d3c24181cef32ae9e15401ff2e4772805ea9551
--- /dev/null
+++ b/package/system/procd/patches/1001-Add-support-for-alternative-rc.d-directories.patch
@@ -0,0 +1,97 @@
+From 36673c2a0e409d9c8ea9e1c15363e73bb21ae65b Mon Sep 17 00:00:00 2001
+Message-Id: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Wed, 6 Aug 2014 14:51:49 +0200
+Subject: [PATCH 1001/1007] Add support for alternative rc.d directories
+
+---
+ initd/preinit.c | 38 ++++++++++++++++++++++++++++++++++++++
+ rcS.c | 2 +-
+ 2 files changed, 39 insertions(+), 1 deletion(-)
+
+diff --git a/initd/preinit.c b/initd/preinit.c
+index f38d8ef..acc64e7 100644
+--- a/initd/preinit.c
++++ b/initd/preinit.c
+@@ -12,6 +12,8 @@
+ * GNU General Public License for more details.
+ */
+
++#define _GNU_SOURCE
++
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <sys/mount.h>
+@@ -47,6 +49,35 @@ check_dbglvl(void)
+ debug = lvl;
+ }
+
++static char*
++get_rc_d(void)
++{
++ size_t n = 0;
++ ssize_t len;
++ char *ret = NULL;
++
++ FILE *fp = fopen("/tmp/rc_d_path", "r");
++
++ if (!fp)
++ return NULL;
++
++ len = getline(&ret, &n, fp);
++
++ fclose(fp);
++
++ unlink("/tmp/rc_d_path");
++
++ if (len <= 0) {
++ free(ret);
++ return NULL;
++ }
++
++ if (ret[len-1] == '\n')
++ ret[len-1] = 0;
++
++ return ret;
++}
++
+ static void
+ spawn_procd(struct uloop_process *proc, int ret)
+ {
+@@ -54,6 +85,7 @@ spawn_procd(struct uloop_process *proc, int ret)
+ char *argv[] = { "/sbin/procd", NULL};
+ struct stat s;
+ char dbg[2];
++ char *rc_d_path;
+
+ if (plugd_proc.pid > 0)
+ kill(plugd_proc.pid, SIGKILL);
+@@ -73,6 +105,12 @@ spawn_procd(struct uloop_process *proc, int ret)
+ setenv("DBGLVL", dbg, 1);
+ }
+
++ rc_d_path = get_rc_d();
++ if (rc_d_path) {
++ setenv("RC_D_PATH", rc_d_path, 1);
++ free(rc_d_path);
++ }
++
+ execvp(argv[0], argv);
+ }
+
+diff --git a/rcS.c b/rcS.c
+index b3e3c22..e231d71 100644
+--- a/rcS.c
++++ b/rcS.c
+@@ -162,7 +162,7 @@ int rcS(char *pattern, char *param, void (*q_empty)(struct runqueue *))
+ q.empty_cb = q_empty;
+ q.max_running_tasks = 1;
+
+- return _rc(&q, "/etc/rc.d", pattern, "*", param);
++ return _rc(&q, getenv("RC_D_PATH") ?: "/etc/rc.d", pattern, "*", param);
+ }
+
+ int rc(const char *file, char *param)
+--
+2.13.0
+
diff --git a/package/system/procd/patches/1002-system-always-support-staged-sysupgrade.patch b/package/system/procd/patches/1002-system-always-support-staged-sysupgrade.patch
new file mode 100644
index 0000000000000000000000000000000000000000..f19a21aed1a5931d609684ff70784fe40b0d1406
--- /dev/null
+++ b/package/system/procd/patches/1002-system-always-support-staged-sysupgrade.patch
@@ -0,0 +1,114 @@
+From 7d2c86de79b6bd976f0e37f7c3cbc61a3b3c3bb7 Mon Sep 17 00:00:00 2001
+Message-Id: <7d2c86de79b6bd976f0e37f7c3cbc61a3b3c3bb7.1496349467.git.mschiffer@universe-factory.net>
+In-Reply-To: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+References: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Fri, 21 Apr 2017 20:06:59 +0200
+Subject: [PATCH 1002/1007] system: always support staged sysupgrade
+
+In preparation for switching all targets to the staged sysupgrade
+mechanism, upgraded is always built, and the "nandupgrade" ubus method is
+renamed to "sysupgrade".
+
+To make the migration easier, support for the old name "nandupgrade" and
+the "upgrade" method that will become unused with the staged sysupgrade is
+retained for now.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ CMakeLists.txt | 4 +---
+ system.c | 31 +++++++++++++------------------
+ 2 files changed, 14 insertions(+), 21 deletions(-)
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index cc1e4a5..9e378ae 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -32,9 +32,7 @@ IF(ZRAM_TMPFS)
+ SET(SOURCES_ZRAM initd/zram.c)
+ ENDIF()
+
+-IF(BUILD_UPGRADED)
+- add_subdirectory(upgraded)
+-ENDIF()
++add_subdirectory(upgraded)
+
+ ADD_EXECUTABLE(procd ${SOURCES})
+ TARGET_LINK_LIBRARIES(procd ${LIBS})
+diff --git a/system.c b/system.c
+index fb7fbe4..701ff35 100644
+--- a/system.c
++++ b/system.c
+@@ -328,12 +328,12 @@ static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj,
+ }
+
+ enum {
+- NAND_PATH,
+- __NAND_MAX
++ SYSUPGRADE_PATH,
++ __SYSUPGRADE_MAX
+ };
+
+-static const struct blobmsg_policy nand_policy[__NAND_MAX] = {
+- [NAND_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
++static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = {
++ [SYSUPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+ };
+
+ static void
+@@ -352,20 +352,20 @@ procd_spawn_upgraded(char *path)
+ execvp(argv[0], argv);
+ }
+
+-static int nand_set(struct ubus_context *ctx, struct ubus_object *obj,
+- struct ubus_request_data *req, const char *method,
+- struct blob_attr *msg)
++static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
++ struct ubus_request_data *req, const char *method,
++ struct blob_attr *msg)
+ {
+- struct blob_attr *tb[__NAND_MAX];
++ struct blob_attr *tb[__SYSUPGRADE_MAX];
+
+ if (!msg)
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+- blobmsg_parse(nand_policy, __NAND_MAX, tb, blob_data(msg), blob_len(msg));
+- if (!tb[NAND_PATH])
++ blobmsg_parse(sysupgrade_policy, __SYSUPGRADE_MAX, tb, blob_data(msg), blob_len(msg));
++ if (!tb[SYSUPGRADE_PATH])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+- procd_spawn_upgraded(blobmsg_get_string(tb[NAND_PATH]));
++ procd_spawn_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PATH]));
+ fprintf(stderr, "Yikees, something went wrong. no /sbin/upgraded ?\n");
+ return 0;
+ }
+@@ -383,9 +383,8 @@ static const struct ubus_method system_methods[] = {
+ UBUS_METHOD_NOARG("upgrade", system_upgrade),
+ UBUS_METHOD("watchdog", watchdog_set, watchdog_policy),
+ UBUS_METHOD("signal", proc_signal, signal_policy),
+-
+- /* must remain at the end as it ia not always loaded */
+- UBUS_METHOD("nandupgrade", nand_set, nand_policy),
++ UBUS_METHOD("nandupgrade", sysupgrade, sysupgrade_policy),
++ UBUS_METHOD("sysupgrade", sysupgrade, sysupgrade_policy),
+ };
+
+ static struct ubus_object_type system_object_type =
+@@ -414,12 +413,8 @@ procd_bcast_event(char *event, struct blob_attr *msg)
+
+ void ubus_init_system(struct ubus_context *ctx)
+ {
+- struct stat s;
+ int ret;
+
+- if (stat("/sbin/upgraded", &s))
+- system_object.n_methods -= 1;
+-
+ _ctx = ctx;
+ ret = ubus_add_object(ctx, &system_object);
+ if (ret)
+--
+2.13.0
+
diff --git a/package/system/procd/patches/1003-upgraded-link-dynamically-chroot-during-exec.patch b/package/system/procd/patches/1003-upgraded-link-dynamically-chroot-during-exec.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d57cb02fba42894e5d279d4aa4ab00e0619f66f4
--- /dev/null
+++ b/package/system/procd/patches/1003-upgraded-link-dynamically-chroot-during-exec.patch
@@ -0,0 +1,222 @@
+From a6f07873f2189dd7b6742c04064c7bbee2c9d28b Mon Sep 17 00:00:00 2001
+Message-Id: <a6f07873f2189dd7b6742c04064c7bbee2c9d28b.1496349467.git.mschiffer@universe-factory.net>
+In-Reply-To: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+References: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 23 Apr 2017 02:28:13 +0200
+Subject: [PATCH 1003/1007] upgraded: link dynamically, chroot during exec
+
+The chroot ensures we don't reference anything on the rootfs and is
+reverted after the upgraded exec. While we're at it, also improve error
+handling a bit.
+
+This change also required changes to sysupgrade, as the dynamically linked
+version is expected at a different location, and libraries need to be made
+available.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ system.c | 25 +++++++++++++++++++------
+ upgraded/CMakeLists.txt | 10 +---------
+ upgraded/upgraded.c | 26 +++++++++++++++++++++-----
+ watchdog.c | 9 +++++++--
+ watchdog.h | 2 +-
+ 5 files changed, 49 insertions(+), 23 deletions(-)
+
+diff --git a/system.c b/system.c
+index 701ff35..ad71956 100644
+--- a/system.c
++++ b/system.c
+@@ -329,27 +329,40 @@ static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj,
+
+ enum {
+ SYSUPGRADE_PATH,
++ SYSUPGRADE_PREFIX,
+ __SYSUPGRADE_MAX
+ };
+
+ static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = {
+ [SYSUPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
++ [SYSUPGRADE_PREFIX] = { .name = "prefix", .type = BLOBMSG_TYPE_STRING },
+ };
+
+ static void
+-procd_spawn_upgraded(char *path)
++procd_exec_upgraded(const char *prefix, char *path)
+ {
+ char *wdt_fd = watchdog_fd();
+- char *argv[] = { "/tmp/upgraded", NULL, NULL};
++ char *argv[] = { "/sbin/upgraded", NULL, NULL};
++
++ if (chroot(prefix)) {
++ fprintf(stderr, "Failed to chroot for upgraded exec.\n");
++ return;
++ }
+
+ argv[1] = path;
+
+ DEBUG(2, "Exec to upgraded now\n");
+ if (wdt_fd) {
+- watchdog_no_cloexec();
++ watchdog_set_cloexec(false);
+ setenv("WDTFD", wdt_fd, 1);
+ }
+ execvp(argv[0], argv);
++
++ /* Cleanup on failure */
++ fprintf(stderr, "Failed to exec upgraded.\n");
++ unsetenv("WDTFD");
++ watchdog_set_cloexec(true);
++ chroot(".");
+ }
+
+ static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
+@@ -362,11 +375,11 @@ static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ blobmsg_parse(sysupgrade_policy, __SYSUPGRADE_MAX, tb, blob_data(msg), blob_len(msg));
+- if (!tb[SYSUPGRADE_PATH])
++ if (!tb[SYSUPGRADE_PATH] || !tb[SYSUPGRADE_PREFIX])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+- procd_spawn_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PATH]));
+- fprintf(stderr, "Yikees, something went wrong. no /sbin/upgraded ?\n");
++ procd_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]),
++ blobmsg_get_string(tb[SYSUPGRADE_PATH]));
+ return 0;
+ }
+
+diff --git a/upgraded/CMakeLists.txt b/upgraded/CMakeLists.txt
+index 093dba2..00d8ce5 100644
+--- a/upgraded/CMakeLists.txt
++++ b/upgraded/CMakeLists.txt
+@@ -2,16 +2,8 @@ cmake_minimum_required(VERSION 2.6)
+
+ PROJECT(upgraded C)
+ ADD_DEFINITIONS(-Os -ggdb -Wall -Werror --std=gnu99 -Wmissing-declarations)
+-set(CMAKE_EXE_LINKER_FLAGS "-static -fPIC")
+-set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+-set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS)
+-set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS)
+-set(CMAKE_SHARED_LIBRARY_C_FLAGS)
+-set(CMAKE_SHARED_LIBRARY_CXX_FLAGS)
+-set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS)
+-set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS)
+ ADD_EXECUTABLE(upgraded upgraded.c ../watchdog.c)
+-TARGET_LINK_LIBRARIES(upgraded ubox rt -lc -lgcc_pic)
++TARGET_LINK_LIBRARIES(upgraded ubox)
+ INSTALL(TARGETS upgraded
+ RUNTIME DESTINATION sbin
+ )
+diff --git a/upgraded/upgraded.c b/upgraded/upgraded.c
+index d7433e7..aa0b4ff 100644
+--- a/upgraded/upgraded.c
++++ b/upgraded/upgraded.c
+@@ -14,6 +14,7 @@
+
+ #include <sys/reboot.h>
+
++#include <fcntl.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+@@ -24,6 +25,10 @@
+
+ #include "../watchdog.h"
+
++#ifndef O_PATH
++#define O_PATH 010000000
++#endif
++
+ static struct uloop_process upgrade_proc;
+ unsigned int debug = 2;
+
+@@ -34,7 +39,7 @@ static void upgrade_proc_cb(struct uloop_process *proc, int ret)
+ uloop_end();
+ }
+
+-static void sysupgarde(char *folder)
++static void sysupgrade(char *folder)
+ {
+ char *args[] = { "/sbin/sysupgrade", "nand", NULL, NULL };
+
+@@ -47,7 +52,7 @@ static void sysupgarde(char *folder)
+ exit(-1);
+ }
+ if (upgrade_proc.pid <= 0) {
+- fprintf(stderr, "Failed to start sysupgarde\n");
++ fprintf(stderr, "Failed to start sysupgrade\n");
+ uloop_end();
+ }
+ }
+@@ -60,10 +65,21 @@ int main(int argc, char **argv)
+ fprintf(stderr, "this tool needs to run as pid 1\n");
+ return -1;
+ }
+- if (chdir("/tmp") == -1) {
+- fprintf(stderr, "failed to chdir to /tmp: %s\n", strerror(errno));
++
++ int fd = open("/", O_DIRECTORY|O_PATH);
++ if (fd < 0) {
++ fprintf(stderr, "unable to open prefix directory: %s\n", strerror(errno));
+ return -1;
+ }
++
++ chroot(".");
++
++ if (fchdir(fd) == -1) {
++ fprintf(stderr, "failed to chdir to prefix directory: %s\n", strerror(errno));
++ return -1;
++ }
++ close(fd);
++
+ if (argc != 2) {
+ fprintf(stderr, "sysupgrade stage 2 failed, no folder specified\n");
+ return -1;
+@@ -71,7 +87,7 @@ int main(int argc, char **argv)
+
+ uloop_init();
+ watchdog_init(0);
+- sysupgarde(argv[1]);
++ sysupgrade(argv[1]);
+ uloop_run();
+
+ reboot(RB_AUTOBOOT);
+diff --git a/watchdog.c b/watchdog.c
+index 592ae7e..780b321 100644
+--- a/watchdog.c
++++ b/watchdog.c
+@@ -126,10 +126,15 @@ void watchdog_init(int preinit)
+ }
+
+
+-void watchdog_no_cloexec(void)
++void watchdog_set_cloexec(bool val)
+ {
+ if (wdt_fd < 0)
+ return;
+
+- fcntl(wdt_fd, F_SETFD, fcntl(wdt_fd, F_GETFD) & ~FD_CLOEXEC);
++ int flags = fcntl(wdt_fd, F_GETFD);
++ if (val)
++ flags |= FD_CLOEXEC;
++ else
++ flags &= ~FD_CLOEXEC;
++ fcntl(wdt_fd, F_SETFD, flags);
+ }
+diff --git a/watchdog.h b/watchdog.h
+index 015fa93..e857010 100644
+--- a/watchdog.h
++++ b/watchdog.h
+@@ -21,7 +21,7 @@ int watchdog_timeout(int timeout);
+ int watchdog_frequency(int frequency);
+ void watchdog_set_stopped(bool val);
+ bool watchdog_get_stopped(void);
+-void watchdog_no_cloexec(void);
++void watchdog_set_cloexec(bool val);
+ void watchdog_ping(void);
+
+ #endif
+--
+2.13.0
+
diff --git a/package/system/procd/patches/1004-upgraded-add-support-for-passing-a-command-argument-.patch b/package/system/procd/patches/1004-upgraded-add-support-for-passing-a-command-argument-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ac8c3fe6ee15e773c973c9d340fbe52ce428d6ee
--- /dev/null
+++ b/package/system/procd/patches/1004-upgraded-add-support-for-passing-a-command-argument-.patch
@@ -0,0 +1,104 @@
+From af1e6d9839a9a8f2c579202597630df9b8f842e6 Mon Sep 17 00:00:00 2001
+Message-Id: <af1e6d9839a9a8f2c579202597630df9b8f842e6.1496349467.git.mschiffer@universe-factory.net>
+In-Reply-To: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+References: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 23 Apr 2017 19:04:25 +0200
+Subject: [PATCH 1004/1007] upgraded: add support for passing a "command"
+ argument to stage2
+
+This allows us to make use of upgraded in "snapshot convert" as well.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ system.c | 10 +++++++---
+ upgraded/upgraded.c | 13 +++++++------
+ 2 files changed, 14 insertions(+), 9 deletions(-)
+
+diff --git a/system.c b/system.c
+index ad71956..1e8a06d 100644
+--- a/system.c
++++ b/system.c
+@@ -330,19 +330,21 @@ static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj,
+ enum {
+ SYSUPGRADE_PATH,
+ SYSUPGRADE_PREFIX,
++ SYSUPGRADE_COMMAND,
+ __SYSUPGRADE_MAX
+ };
+
+ static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = {
+ [SYSUPGRADE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+ [SYSUPGRADE_PREFIX] = { .name = "prefix", .type = BLOBMSG_TYPE_STRING },
++ [SYSUPGRADE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING },
+ };
+
+ static void
+-procd_exec_upgraded(const char *prefix, char *path)
++procd_exec_upgraded(const char *prefix, char *path, char *command)
+ {
+ char *wdt_fd = watchdog_fd();
+- char *argv[] = { "/sbin/upgraded", NULL, NULL};
++ char *argv[] = { "/sbin/upgraded", NULL, NULL, NULL};
+
+ if (chroot(prefix)) {
+ fprintf(stderr, "Failed to chroot for upgraded exec.\n");
+@@ -350,6 +352,7 @@ procd_exec_upgraded(const char *prefix, char *path)
+ }
+
+ argv[1] = path;
++ argv[2] = command;
+
+ DEBUG(2, "Exec to upgraded now\n");
+ if (wdt_fd) {
+@@ -379,7 +382,8 @@ static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+ procd_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]),
+- blobmsg_get_string(tb[SYSUPGRADE_PATH]));
++ blobmsg_get_string(tb[SYSUPGRADE_PATH]),
++ tb[SYSUPGRADE_COMMAND] ? blobmsg_get_string(tb[SYSUPGRADE_COMMAND]) : NULL);
+ return 0;
+ }
+
+diff --git a/upgraded/upgraded.c b/upgraded/upgraded.c
+index aa0b4ff..303edb7 100644
+--- a/upgraded/upgraded.c
++++ b/upgraded/upgraded.c
+@@ -39,11 +39,12 @@ static void upgrade_proc_cb(struct uloop_process *proc, int ret)
+ uloop_end();
+ }
+
+-static void sysupgrade(char *folder)
++static void sysupgrade(char *path, char *command)
+ {
+- char *args[] = { "/sbin/sysupgrade", "nand", NULL, NULL };
++ char *args[] = { "/sbin/sysupgrade", "nand", NULL, NULL, NULL };
+
+- args[2] = folder;
++ args[2] = path;
++ args[3] = command;
+ upgrade_proc.cb = upgrade_proc_cb;
+ upgrade_proc.pid = fork();
+ if (!upgrade_proc.pid) {
+@@ -80,14 +81,14 @@ int main(int argc, char **argv)
+ }
+ close(fd);
+
+- if (argc != 2) {
+- fprintf(stderr, "sysupgrade stage 2 failed, no folder specified\n");
++ if (argc != 2 && argc != 3) {
++ fprintf(stderr, "sysupgrade stage 2 failed, invalid command line\n");
+ return -1;
+ }
+
+ uloop_init();
+ watchdog_init(0);
+- sysupgrade(argv[1]);
++ sysupgrade(argv[1], (argc == 3) ? argv[2] : NULL);
+ uloop_run();
+
+ reboot(RB_AUTOBOOT);
+--
+2.13.0
+
diff --git a/package/system/procd/patches/1005-Remove-code-that-has-become-unnecessary-after-sysupg.patch b/package/system/procd/patches/1005-Remove-code-that-has-become-unnecessary-after-sysupg.patch
new file mode 100644
index 0000000000000000000000000000000000000000..0be544bce113b920556bc6a9889041227fc42e07
--- /dev/null
+++ b/package/system/procd/patches/1005-Remove-code-that-has-become-unnecessary-after-sysupg.patch
@@ -0,0 +1,119 @@
+From 45bd440ec30f777b3619dcd0e7db330cc29a7850 Mon Sep 17 00:00:00 2001
+Message-Id: <45bd440ec30f777b3619dcd0e7db330cc29a7850.1496349467.git.mschiffer@universe-factory.net>
+In-Reply-To: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+References: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Sun, 23 Apr 2017 19:06:12 +0200
+Subject: [PATCH 1005/1007] Remove code that has become unnecessary after
+ sysupgrade changes
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ procd.h | 1 -
+ service/instance.c | 2 --
+ system.c | 12 ------------
+ upgraded/upgraded.c | 10 +++++-----
+ 4 files changed, 5 insertions(+), 20 deletions(-)
+
+diff --git a/procd.h b/procd.h
+index 66d183c..796e524 100644
+--- a/procd.h
++++ b/procd.h
+@@ -27,7 +27,6 @@
+ #define __init __attribute__((constructor))
+
+ extern char *ubus_socket;
+-extern int upgrade_running;
+
+ void procd_connect_ubus(void);
+ void procd_reconnect_ubus(int reconnect);
+diff --git a/service/instance.c b/service/instance.c
+index 40ff021..f33eae9 100644
+--- a/service/instance.c
++++ b/service/instance.c
+@@ -453,8 +453,6 @@ instance_exit(struct uloop_process *p, int ret)
+ runtime = tp.tv_sec - in->start.tv_sec;
+
+ DEBUG(2, "Instance %s::%s exit with error code %d after %ld seconds\n", in->srv->name, in->name, ret, runtime);
+- if (upgrade_running)
+- return;
+
+ uloop_timeout_cancel(&in->timeout);
+ if (in->halt) {
+diff --git a/system.c b/system.c
+index 1e8a06d..80205da 100644
+--- a/system.c
++++ b/system.c
+@@ -31,8 +31,6 @@ static struct blob_buf b;
+ static int notify;
+ static struct ubus_context *_ctx;
+
+-int upgrade_running = 0;
+-
+ static int system_board(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+@@ -227,14 +225,6 @@ static int system_info(struct ubus_context *ctx, struct ubus_object *obj,
+ return UBUS_STATUS_OK;
+ }
+
+-static int system_upgrade(struct ubus_context *ctx, struct ubus_object *obj,
+- struct ubus_request_data *req, const char *method,
+- struct blob_attr *msg)
+-{
+- upgrade_running = 1;
+- return 0;
+-}
+-
+ enum {
+ WDT_FREQUENCY,
+ WDT_TIMEOUT,
+@@ -397,10 +387,8 @@ procd_subscribe_cb(struct ubus_context *ctx, struct ubus_object *obj)
+ static const struct ubus_method system_methods[] = {
+ UBUS_METHOD_NOARG("board", system_board),
+ UBUS_METHOD_NOARG("info", system_info),
+- UBUS_METHOD_NOARG("upgrade", system_upgrade),
+ UBUS_METHOD("watchdog", watchdog_set, watchdog_policy),
+ UBUS_METHOD("signal", proc_signal, signal_policy),
+- UBUS_METHOD("nandupgrade", sysupgrade, sysupgrade_policy),
+ UBUS_METHOD("sysupgrade", sysupgrade, sysupgrade_policy),
+ };
+
+diff --git a/upgraded/upgraded.c b/upgraded/upgraded.c
+index 303edb7..79ebd37 100644
+--- a/upgraded/upgraded.c
++++ b/upgraded/upgraded.c
+@@ -41,10 +41,10 @@ static void upgrade_proc_cb(struct uloop_process *proc, int ret)
+
+ static void sysupgrade(char *path, char *command)
+ {
+- char *args[] = { "/sbin/sysupgrade", "nand", NULL, NULL, NULL };
++ char *args[] = { "/lib/upgrade/stage2", NULL, NULL, NULL };
+
+- args[2] = path;
+- args[3] = command;
++ args[1] = path;
++ args[2] = command;
+ upgrade_proc.cb = upgrade_proc_cb;
+ upgrade_proc.pid = fork();
+ if (!upgrade_proc.pid) {
+@@ -81,14 +81,14 @@ int main(int argc, char **argv)
+ }
+ close(fd);
+
+- if (argc != 2 && argc != 3) {
++ if (argc != 3) {
+ fprintf(stderr, "sysupgrade stage 2 failed, invalid command line\n");
+ return -1;
+ }
+
+ uloop_init();
+ watchdog_init(0);
+- sysupgrade(argv[1], (argc == 3) ? argv[2] : NULL);
++ sysupgrade(argv[1], argv[2]);
+ uloop_run();
+
+ reboot(RB_AUTOBOOT);
+--
+2.13.0
+
diff --git a/package/system/procd/patches/1006-init-add-support-for-sysupgrades-triggered-from-prei.patch b/package/system/procd/patches/1006-init-add-support-for-sysupgrades-triggered-from-prei.patch
new file mode 100644
index 0000000000000000000000000000000000000000..872846be3e3984f6177512a7adbf0886b78d2677
--- /dev/null
+++ b/package/system/procd/patches/1006-init-add-support-for-sysupgrades-triggered-from-prei.patch
@@ -0,0 +1,280 @@
+From f4e6df8848e54d83bac0ab7451312a9db5b59143 Mon Sep 17 00:00:00 2001
+Message-Id: <f4e6df8848e54d83bac0ab7451312a9db5b59143.1496349467.git.mschiffer@universe-factory.net>
+In-Reply-To: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+References: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Mon, 24 Apr 2017 00:40:27 +0200
+Subject: [PATCH 1006/1007] init: add support for sysupgrades triggered from
+ preinit
+
+This will allow to add support for sysupgrades via upgraded from failsafe
+mode.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ CMakeLists.txt | 4 ++--
+ initd/preinit.c | 46 +++++++++++++++++++++++++++++++++++++++++-----
+ system.c | 35 ++++-------------------------------
+ sysupgrade.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
+ sysupgrade.h | 21 +++++++++++++++++++++
+ watchdog.h | 2 ++
+ 6 files changed, 119 insertions(+), 38 deletions(-)
+ create mode 100644 sysupgrade.c
+ create mode 100644 sysupgrade.h
+
+diff --git a/CMakeLists.txt b/CMakeLists.txt
+index 9e378ae..441216b 100644
+--- a/CMakeLists.txt
++++ b/CMakeLists.txt
+@@ -17,7 +17,7 @@ INSTALL(TARGETS setlbf
+ )
+
+
+-SET(SOURCES procd.c signal.c watchdog.c state.c inittab.c rcS.c ubus.c system.c
++SET(SOURCES procd.c signal.c watchdog.c state.c inittab.c rcS.c ubus.c system.c sysupgrade.c
+ service/service.c service/instance.c service/validate.c service/trigger.c service/watch.c
+ plug/coldplug.c plug/hotplug.c utils/utils.c)
+
+@@ -41,7 +41,7 @@ INSTALL(TARGETS procd
+ )
+
+
+-ADD_EXECUTABLE(init initd/init.c initd/early.c initd/preinit.c initd/mkdev.c watchdog.c
++ADD_EXECUTABLE(init initd/init.c initd/early.c initd/preinit.c initd/mkdev.c sysupgrade.c watchdog.c
+ utils/utils.c ${SOURCES_ZRAM})
+ TARGET_LINK_LIBRARIES(init ${LIBS})
+ INSTALL(TARGETS init
+diff --git a/initd/preinit.c b/initd/preinit.c
+index acc64e7..3a606e4 100644
+--- a/initd/preinit.c
++++ b/initd/preinit.c
+@@ -28,6 +28,7 @@
+
+ #include "init.h"
+ #include "../watchdog.h"
++#include "../sysupgrade.h"
+
+ static struct uloop_process preinit_proc;
+ static struct uloop_process plugd_proc;
+@@ -79,23 +80,58 @@ get_rc_d(void)
+ }
+
+ static void
++check_sysupgrade(void)
++{
++ char *prefix = NULL, *path = NULL, *command = NULL;
++ size_t n;
++
++ if (chdir("/"))
++ return;
++
++ FILE *sysupgrade = fopen("/tmp/sysupgrade", "r");
++ if (!sysupgrade)
++ return;
++
++ n = 0;
++ if (getdelim(&prefix, &n, 0, sysupgrade) < 0)
++ goto fail;
++ n = 0;
++ if (getdelim(&path, &n, 0, sysupgrade) < 0)
++ goto fail;
++ n = 0;
++ if (getdelim(&command, &n, 0, sysupgrade) < 0)
++ goto fail;
++
++ fclose(sysupgrade);
++
++ sysupgrade_exec_upgraded(prefix, path, command);
++
++ while (true)
++ sleep(1);
++
++fail:
++ fclose(sysupgrade);
++ free(prefix);
++ free(path);
++ free(command);
++}
++
++static void
+ spawn_procd(struct uloop_process *proc, int ret)
+ {
+ char *wdt_fd = watchdog_fd();
+ char *argv[] = { "/sbin/procd", NULL};
+- struct stat s;
+ char dbg[2];
+ char *rc_d_path;
+
+ if (plugd_proc.pid > 0)
+ kill(plugd_proc.pid, SIGKILL);
+
+- if (!stat("/tmp/sysupgrade", &s))
+- while (true)
+- sleep(1);
+-
+ unsetenv("INITRAMFS");
+ unsetenv("PREINIT");
++
++ check_sysupgrade();
++
+ DEBUG(2, "Exec to real procd now\n");
+ if (wdt_fd)
+ setenv("WDTFD", wdt_fd, 1);
+diff --git a/system.c b/system.c
+index 80205da..700530d 100644
+--- a/system.c
++++ b/system.c
+@@ -25,6 +25,7 @@
+ #include <libubox/uloop.h>
+
+ #include "procd.h"
++#include "sysupgrade.h"
+ #include "watchdog.h"
+
+ static struct blob_buf b;
+@@ -330,34 +331,6 @@ static const struct blobmsg_policy sysupgrade_policy[__SYSUPGRADE_MAX] = {
+ [SYSUPGRADE_COMMAND] = { .name = "command", .type = BLOBMSG_TYPE_STRING },
+ };
+
+-static void
+-procd_exec_upgraded(const char *prefix, char *path, char *command)
+-{
+- char *wdt_fd = watchdog_fd();
+- char *argv[] = { "/sbin/upgraded", NULL, NULL, NULL};
+-
+- if (chroot(prefix)) {
+- fprintf(stderr, "Failed to chroot for upgraded exec.\n");
+- return;
+- }
+-
+- argv[1] = path;
+- argv[2] = command;
+-
+- DEBUG(2, "Exec to upgraded now\n");
+- if (wdt_fd) {
+- watchdog_set_cloexec(false);
+- setenv("WDTFD", wdt_fd, 1);
+- }
+- execvp(argv[0], argv);
+-
+- /* Cleanup on failure */
+- fprintf(stderr, "Failed to exec upgraded.\n");
+- unsetenv("WDTFD");
+- watchdog_set_cloexec(true);
+- chroot(".");
+-}
+-
+ static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+@@ -371,9 +344,9 @@ static int sysupgrade(struct ubus_context *ctx, struct ubus_object *obj,
+ if (!tb[SYSUPGRADE_PATH] || !tb[SYSUPGRADE_PREFIX])
+ return UBUS_STATUS_INVALID_ARGUMENT;
+
+- procd_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]),
+- blobmsg_get_string(tb[SYSUPGRADE_PATH]),
+- tb[SYSUPGRADE_COMMAND] ? blobmsg_get_string(tb[SYSUPGRADE_COMMAND]) : NULL);
++ sysupgrade_exec_upgraded(blobmsg_get_string(tb[SYSUPGRADE_PREFIX]),
++ blobmsg_get_string(tb[SYSUPGRADE_PATH]),
++ tb[SYSUPGRADE_COMMAND] ? blobmsg_get_string(tb[SYSUPGRADE_COMMAND]) : NULL);
+ return 0;
+ }
+
+diff --git a/sysupgrade.c b/sysupgrade.c
+new file mode 100644
+index 0000000..30f1836
+--- /dev/null
++++ b/sysupgrade.c
+@@ -0,0 +1,49 @@
++/*
++ * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
++ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2017 Matthias Schiffer <mschiffer@universe-factory.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1
++ * as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++
++#include "watchdog.h"
++#include "sysupgrade.h"
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++
++
++void sysupgrade_exec_upgraded(const char *prefix, char *path, char *command)
++{
++ char *wdt_fd = watchdog_fd();
++ char *argv[] = { "/sbin/upgraded", NULL, NULL, NULL};
++
++ if (chroot(prefix)) {
++ fprintf(stderr, "Failed to chroot for upgraded exec.\n");
++ return;
++ }
++
++ argv[1] = path;
++ argv[2] = command;
++
++ if (wdt_fd) {
++ watchdog_set_cloexec(false);
++ setenv("WDTFD", wdt_fd, 1);
++ }
++ execvp(argv[0], argv);
++
++ /* Cleanup on failure */
++ fprintf(stderr, "Failed to exec upgraded.\n");
++ unsetenv("WDTFD");
++ watchdog_set_cloexec(true);
++ chroot(".");
++}
+diff --git a/sysupgrade.h b/sysupgrade.h
+new file mode 100644
+index 0000000..8c09fc9
+--- /dev/null
++++ b/sysupgrade.h
+@@ -0,0 +1,21 @@
++/*
++ * Copyright (C) 2017 Matthias Schiffer <mschiffer@universe-factory.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU Lesser General Public License version 2.1
++ * as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __PROCD_SYSUPGRADE_H
++#define __PROCD_SYSUPGRADE_H
++
++
++void sysupgrade_exec_upgraded(const char *prefix, char *path, char *command);
++
++
++#endif
+diff --git a/watchdog.h b/watchdog.h
+index e857010..06ce5e5 100644
+--- a/watchdog.h
++++ b/watchdog.h
+@@ -15,6 +15,8 @@
+ #ifndef __PROCD_WATCHDOG_H
+ #define __PROCD_WATCHDOG_H
+
++#include <stdbool.h>
++
+ void watchdog_init(int preinit);
+ char* watchdog_fd(void);
+ int watchdog_timeout(int timeout);
+--
+2.13.0
+
diff --git a/package/system/procd/patches/1007-upgraded-define-__GNU_SOURCE.patch b/package/system/procd/patches/1007-upgraded-define-__GNU_SOURCE.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c98cb9baa4371b64d6b1297fc0a9921d580947be
--- /dev/null
+++ b/package/system/procd/patches/1007-upgraded-define-__GNU_SOURCE.patch
@@ -0,0 +1,31 @@
+From 8137d283c7f858ca658fa556b95eb62e35ae980d Mon Sep 17 00:00:00 2001
+Message-Id: <8137d283c7f858ca658fa556b95eb62e35ae980d.1496349467.git.mschiffer@universe-factory.net>
+In-Reply-To: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+References: <36673c2a0e409d9c8ea9e1c15363e73bb21ae65b.1496349467.git.mschiffer@universe-factory.net>
+From: Matthias Schiffer <mschiffer@universe-factory.net>
+Date: Tue, 30 May 2017 07:23:57 +0200
+Subject: [PATCH 1007/1007] upgraded: define __GNU_SOURCE
+
+It is required on non-musl libcs for O_DIRECTORY.
+
+Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
+---
+ upgraded/upgraded.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/upgraded/upgraded.c b/upgraded/upgraded.c
+index 79ebd37..e70f92d 100644
+--- a/upgraded/upgraded.c
++++ b/upgraded/upgraded.c
+@@ -12,6 +12,8 @@
+ * GNU General Public License for more details.
+ */
+
++#define _GNU_SOURCE
++
+ #include <sys/reboot.h>
+
+ #include <fcntl.h>
+--
+2.13.0
+