Browse Source

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>
Matthias Schiffer 7 years ago
parent
commit
63789e51ed
6 changed files with 119 additions and 38 deletions
  1. 2 2
      CMakeLists.txt
  2. 41 5
      initd/preinit.c
  3. 4 31
      system.c
  4. 49 0
      sysupgrade.c
  5. 21 0
      sysupgrade.h
  6. 2 0
      watchdog.h

+ 2 - 2
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

+ 41 - 5
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;
@@ -48,24 +49,59 @@ check_dbglvl(void)
 		debug = lvl;
 }
 
+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);

+ 4 - 31
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;
 }
 

+ 49 - 0
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(".");
+}

+ 21 - 0
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

+ 2 - 0
watchdog.h

@@ -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);