From 63789e51ed913394c6bd4ac34e40ed0c8fcccccf Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 24 Apr 2017 00:40:27 +0200 Subject: [PATCH] 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 --- 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 0729459..7d05e97 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,7 +18,7 @@ INSTALL(TARGETS setlbf ) -SET(SOURCES procd.c signal.c state.c inittab.c rcS.c ubus.c system.c +SET(SOURCES procd.c signal.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 utils/utils.c) IF(NOT DISABLE_INIT) @@ -54,7 +54,7 @@ INCLUDE_DIRECTORIES(${ubox_include_dir}) IF(DISABLE_INIT) ADD_DEFINITIONS(-DDISABLE_INIT) ELSE() -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 729978e..dda6576 100644 --- a/initd/preinit.c +++ b/initd/preinit.c @@ -27,6 +27,7 @@ #include "init.h" #include "../watchdog.h" +#include "../sysupgrade.h" static struct uloop_process preinit_proc; static struct uloop_process plugd_proc; @@ -49,23 +50,58 @@ check_dbglvl(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]; if (plugd_proc.pid > 0) kill(plugd_proc.pid, SIGKILL); - if (!stat("/tmp/sysupgrade", &s)) - while (true) - sleep(1); - unsetenv("INITRAMFS"); unsetenv("PREINIT"); unlink("/tmp/.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 dc509ff..8b8cdbc 100644 --- a/system.c +++ b/system.c @@ -28,6 +28,7 @@ #include #include "procd.h" +#include "sysupgrade.h" #include "watchdog.h" static struct blob_buf b; @@ -346,34 +347,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) @@ -387,9 +360,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 + * Copyright (C) 2013 John Crispin + * Copyright (C) 2017 Matthias Schiffer + * + * 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 +#include +#include + + +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 + * + * 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 641e7e1..3c4a487 100644 --- a/watchdog.h +++ b/watchdog.h @@ -15,6 +15,8 @@ #ifndef __PROCD_WATCHDOG_H #define __PROCD_WATCHDOG_H +#include + #ifndef DISABLE_INIT void watchdog_init(int preinit); char* watchdog_fd(void); -- 2.11.0