From 58b839308a4b56845ba9906c7e8a36e2f729449e Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sun, 30 Jul 2017 20:57:33 +0200 Subject: [PATCH] Backport sysupgrade error handling fixes --- ...port-sysupgrade-error-handling-fixes.patch | 144 ++++++++++++++++++ ...rade-argument-passed-from-preupgrade.patch | 33 ++++ ...oop-forever-trying-to-kill-processes.patch | 42 +++++ 3 files changed, 219 insertions(+) create mode 100644 patches/openwrt/0117-procd-backport-sysupgrade-error-handling-fixes.patch create mode 100644 patches/openwrt/0118-base-files-upgrade-correctly-handle-nand_do_upgrade-argument-passed-from-preupgrade.patch create mode 100644 patches/openwrt/0119-base-files-upgrade-don-t-loop-forever-trying-to-kill-processes.patch diff --git a/patches/openwrt/0117-procd-backport-sysupgrade-error-handling-fixes.patch b/patches/openwrt/0117-procd-backport-sysupgrade-error-handling-fixes.patch new file mode 100644 index 00000000..3a72503c --- /dev/null +++ b/patches/openwrt/0117-procd-backport-sysupgrade-error-handling-fixes.patch @@ -0,0 +1,144 @@ +From: Matthias Schiffer +Date: Sun, 30 Jul 2017 20:53:22 +0200 +Subject: procd: backport sysupgrade error handling fixes + +diff --git a/package/system/procd/patches/1008-upgraded-register-stage2-process-in-uloop-as-intende.patch b/package/system/procd/patches/1008-upgraded-register-stage2-process-in-uloop-as-intende.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..9acbb7beb188fb06a538d1dbd2e9a5e166728340 +--- /dev/null ++++ b/package/system/procd/patches/1008-upgraded-register-stage2-process-in-uloop-as-intende.patch +@@ -0,0 +1,30 @@ ++From cc3332d28e50e6fbc4f717f1232fb076c44176be Mon Sep 17 00:00:00 2001 ++Message-Id: ++From: Matthias Schiffer ++Date: Thu, 13 Jul 2017 00:04:49 +0200 ++Subject: [PATCH 1/2] upgraded: register stage2 process in uloop as intended ++ ++Make the process callback effective, so an exit of state2 will trigger a ++reboot. ++ ++Signed-off-by: Matthias Schiffer ++--- ++ upgraded/upgraded.c | 2 ++ ++ 1 file changed, 2 insertions(+) ++ ++diff --git a/upgraded/upgraded.c b/upgraded/upgraded.c ++index e70f92d..6bc5ad8 100644 ++--- a/upgraded/upgraded.c +++++ b/upgraded/upgraded.c ++@@ -58,6 +58,8 @@ static void sysupgrade(char *path, char *command) ++ fprintf(stderr, "Failed to start sysupgrade\n"); ++ uloop_end(); ++ } +++ +++ uloop_process_add(&upgrade_proc); ++ } ++ ++ int main(int argc, char **argv) ++-- ++2.13.3 ++ +diff --git a/package/system/procd/patches/1009-upgraded-improve-error-handling.patch b/package/system/procd/patches/1009-upgraded-improve-error-handling.patch +new file mode 100644 +index 0000000000000000000000000000000000000000..c8cd893c7874746d3c14db83acfd451bbc416803 +--- /dev/null ++++ b/package/system/procd/patches/1009-upgraded-improve-error-handling.patch +@@ -0,0 +1,98 @@ ++From 04d8a9b7f0c3d68133ae26009c55dce34dc28364 Mon Sep 17 00:00:00 2001 ++Message-Id: <04d8a9b7f0c3d68133ae26009c55dce34dc28364.1501440704.git.mschiffer@universe-factory.net> ++In-Reply-To: ++References: ++From: Matthias Schiffer ++Date: Thu, 13 Jul 2017 13:18:00 +0200 ++Subject: [PATCH 2/2] upgraded: improve error handling ++ ++* exit with code 1 instead of unusual -1 in the parent process ++* exit using _exit() when child exec fails ++* fix fork/exec error messages ++* only uloop_run() after successful child fork (uloop_end() before ++ uloop_run() doesn't have any effect, so uloop_run() would hang forever) ++* minor code cleanup ++ ++Signed-off-by: Matthias Schiffer ++--- ++ upgraded/upgraded.c | 28 ++++++++++++++-------------- ++ 1 file changed, 14 insertions(+), 14 deletions(-) ++ ++diff --git a/upgraded/upgraded.c b/upgraded/upgraded.c ++index 6bc5ad8..09c623c 100644 ++--- a/upgraded/upgraded.c +++++ b/upgraded/upgraded.c ++@@ -43,23 +43,24 @@ static void upgrade_proc_cb(struct uloop_process *proc, int ret) ++ ++ static void sysupgrade(char *path, char *command) ++ { ++- char *args[] = { "/lib/upgrade/stage2", NULL, NULL, NULL }; +++ char *args[] = { "/lib/upgrade/stage2", path, command, NULL }; ++ ++- args[1] = path; ++- args[2] = command; ++ upgrade_proc.cb = upgrade_proc_cb; ++ upgrade_proc.pid = fork(); ++- if (!upgrade_proc.pid) { ++- execvp(args[0], args); +++ if (upgrade_proc.pid < 0) { ++ fprintf(stderr, "Failed to fork sysupgrade\n"); ++- exit(-1); +++ return; ++ } ++- if (upgrade_proc.pid <= 0) { ++- fprintf(stderr, "Failed to start sysupgrade\n"); ++- uloop_end(); +++ +++ if (!upgrade_proc.pid) { +++ /* Child */ +++ execvp(args[0], args); +++ fprintf(stderr, "Failed to exec sysupgrade\n"); +++ _exit(-1); ++ } ++ ++ uloop_process_add(&upgrade_proc); +++ uloop_run(); ++ } ++ ++ int main(int argc, char **argv) ++@@ -68,32 +69,31 @@ int main(int argc, char **argv) ++ ++ if (p != 1) { ++ fprintf(stderr, "this tool needs to run as pid 1\n"); ++- return -1; +++ return 1; ++ } ++ ++ int fd = open("/", O_DIRECTORY|O_PATH); ++ if (fd < 0) { ++ fprintf(stderr, "unable to open prefix directory: %s\n", strerror(errno)); ++- return -1; +++ return 1; ++ } ++ ++ chroot("."); ++ ++ if (fchdir(fd) == -1) { ++ fprintf(stderr, "failed to chdir to prefix directory: %s\n", strerror(errno)); ++- return -1; +++ return 1; ++ } ++ close(fd); ++ ++ if (argc != 3) { ++ fprintf(stderr, "sysupgrade stage 2 failed, invalid command line\n"); ++- return -1; +++ return 1; ++ } ++ ++ uloop_init(); ++ watchdog_init(0); ++ sysupgrade(argv[1], argv[2]); ++- uloop_run(); ++ ++ reboot(RB_AUTOBOOT); ++ ++-- ++2.13.3 ++ diff --git a/patches/openwrt/0118-base-files-upgrade-correctly-handle-nand_do_upgrade-argument-passed-from-preupgrade.patch b/patches/openwrt/0118-base-files-upgrade-correctly-handle-nand_do_upgrade-argument-passed-from-preupgrade.patch new file mode 100644 index 00000000..de93150d --- /dev/null +++ b/patches/openwrt/0118-base-files-upgrade-correctly-handle-nand_do_upgrade-argument-passed-from-preupgrade.patch @@ -0,0 +1,33 @@ +From: Matthias Schiffer +Date: Mon, 10 Jul 2017 10:35:19 +0200 +Subject: base-files: upgrade: correctly handle nand_do_upgrade argument passed from preupgrade + +Fixes: 30f61a34b4cf "base-files: always use staged sysupgrade" +Signed-off-by: Matthias Schiffer + +diff --git a/package/base-files/files/lib/upgrade/common.sh b/package/base-files/files/lib/upgrade/common.sh +index fc59bf2323498d332159b00eb7ab443bfe6b147e..c8b71015c2e44210696a4e28a5b7babbd0233184 100644 +--- a/package/base-files/files/lib/upgrade/common.sh ++++ b/package/base-files/files/lib/upgrade/common.sh +@@ -211,7 +211,7 @@ default_do_upgrade() { + do_upgrade_stage2() { + v "Performing system upgrade..." + if [ -n "$do_upgrade" ]; then +- $do_upgrade "$IMAGE" ++ eval "$do_upgrade" + elif type 'platform_do_upgrade' >/dev/null 2>/dev/null; then + platform_do_upgrade "$IMAGE" + else +diff --git a/package/base-files/files/lib/upgrade/nand.sh b/package/base-files/files/lib/upgrade/nand.sh +index 05940e2567e22fe1936fb5afdc7c1df4826570ee..5750c6d9a6a1f738c7a0fb251e712ab7bc548d4f 100644 +--- a/package/base-files/files/lib/upgrade/nand.sh ++++ b/package/base-files/files/lib/upgrade/nand.sh +@@ -278,7 +278,7 @@ nand_do_upgrade() { + # hook; this piece of code handles scripts that haven't been + # updated. All scripts should gradually move to call nand_do_upgrade + # from platform_do_upgrade instead. +- export do_upgrade=nand_do_upgrade ++ export do_upgrade="nand_do_upgrade '$1'" + return + fi + diff --git a/patches/openwrt/0119-base-files-upgrade-don-t-loop-forever-trying-to-kill-processes.patch b/patches/openwrt/0119-base-files-upgrade-don-t-loop-forever-trying-to-kill-processes.patch new file mode 100644 index 00000000..2dfe0ca6 --- /dev/null +++ b/patches/openwrt/0119-base-files-upgrade-don-t-loop-forever-trying-to-kill-processes.patch @@ -0,0 +1,42 @@ +From: Matthias Schiffer +Date: Thu, 13 Jul 2017 00:19:32 +0200 +Subject: base-files: upgrade: don't loop forever trying to kill processes + +When processes don't die on SIGKILL (usually because of kernel bugs), it's +better to give up instead of looping forever. + +upgraded will trigger a reboot in this case (and if this fails, a hardware +watchdog will eventually time out and reset the system, if present). + +Signed-off-by: Matthias Schiffer + +diff --git a/package/base-files/files/lib/upgrade/stage2 b/package/base-files/files/lib/upgrade/stage2 +index bdbb8926643287f48a4ae62c5d1d4b4a29130859..097ad63adfecdd70019acaa5b652d2056e774c3f 100755 +--- a/package/base-files/files/lib/upgrade/stage2 ++++ b/package/base-files/files/lib/upgrade/stage2 +@@ -87,6 +87,8 @@ switch_to_ramfs() { + } + + kill_remaining() { # [ [ ] ] ++ local loop_limit=10 ++ + local sig="${1:-TERM}" + local loop="${2:-0}" + local run=true +@@ -117,8 +119,15 @@ kill_remaining() { # [ [ ] ] + + [ $loop -eq 1 ] && run=true + done ++ ++ let loop_limit-- ++ [ $loop_limit -eq 0 ] && { ++ echo ++ echo "Failed to kill all processes." ++ exit 1 ++ } + done +- echo "" ++ echo + } + +