init: add support for sysupgrades triggered from preinit
authorMatthias Schiffer <mschiffer@universe-factory.net>
Sun, 23 Apr 2017 22:40:27 +0000 (00:40 +0200)
committerMatthias Schiffer <mschiffer@universe-factory.net>
Mon, 29 May 2017 21:06:36 +0000 (23:06 +0200)
This will allow to add support for sysupgrades via upgraded from failsafe
mode.

Signed-off-by: Matthias Schiffer <mschiffer@universe-factory.net>
CMakeLists.txt
initd/preinit.c
system.c
sysupgrade.c [new file with mode: 0644]
sysupgrade.h [new file with mode: 0644]
watchdog.h

index 0729459..7d05e97 100644 (file)
@@ -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
index 729978e..dda6576 100644 (file)
@@ -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);
index dc509ff..8b8cdbc 100644 (file)
--- a/system.c
+++ b/system.c
@@ -28,6 +28,7 @@
 #include <libubox/uloop.h>
 
 #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 (file)
index 0000000..30f1836
--- /dev/null
@@ -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 (file)
index 0000000..8c09fc9
--- /dev/null
@@ -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
index 641e7e1..3c4a487 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef __PROCD_WATCHDOG_H
 #define __PROCD_WATCHDOG_H
 
+#include <stdbool.h>
+
 #ifndef DISABLE_INIT
 void watchdog_init(int preinit);
 char* watchdog_fd(void);