commit:     05738bfce120114037d4f02c67ec740813f94b89
Author:     William Hubbs <w.d.hubbs <AT> gmail <DOT> com>
AuthorDate: Wed Apr 12 22:56:30 2017 +0000
Commit:     William Hubbs <williamh <AT> gentoo <DOT> org>
CommitDate: Wed Apr 12 22:56:36 2017 +0000
URL:        https://gitweb.gentoo.org/proj/openrc.git/commit/?id=05738bfc

init: add re-exec capability

This will allow the re-execution of the init process after upgrading
OpenRC.

 man/openrc-shutdown.8    |  7 ++++++-
 src/rc/openrc-init.c     | 22 +++++++++++++++++++---
 src/rc/openrc-shutdown.c | 14 ++++++++++++--
 3 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/man/openrc-shutdown.8 b/man/openrc-shutdown.8
index 98ec64a6..eae16ae8 100644
--- a/man/openrc-shutdown.8
+++ b/man/openrc-shutdown.8
@@ -19,11 +19,13 @@
 .Op Fl H , -halt
 .Op Fl k , -kexec
 .Op Fl p , -poweroff
+.Op Fl R , -reexec
 .Op Fl r , -reboot
 .Sh DESCRIPTION
 .Nm
 is the utility that communicates with openrc-init(8) to bring down the
-system.  The following options affect how the system is brought down:
+system or instruct openrc-init to re-execute itself. It supports the
+following options:
 .Bl -tag -width "poweroff"
 .It Fl H , -halt
 Stop all services, kill all remaining processes and halt the system.
@@ -32,6 +34,9 @@ Stop all services, kill all processes and boot directly into 
a new
 kernel loaded via kexec(8).
 .It Fl p , -poweroff
 Stop all services, kill all processes and power off the system.
+.It Fl R , -reexec
+instruct openrc-init to re-exec itself. This should be used after an
+upgrade of OpenRC if you are using openrc-init as your init process.
 .It Fl r , -reboot
 Stop all services, kill all processes and reboot the system.
 .El

diff --git a/src/rc/openrc-init.c b/src/rc/openrc-init.c
index fb3347a4..61052806 100644
--- a/src/rc/openrc-init.c
+++ b/src/rc/openrc-init.c
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <signal.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -79,6 +80,12 @@ static void init(const char *default_runlevel)
        waitpid(pid, NULL, 0);
 }
 
+static void handle_reexec(char *my_name)
+{
+       execl(my_name, my_name, "reexec", NULL);
+       return;
+}
+
 static void handle_shutdown(const char *runlevel, int cmd)
 {
        pid_t pid;
@@ -123,10 +130,11 @@ static void signal_handler(int sig)
 
 int main(int argc, char **argv)
 {
-       char *default_runlevel = NULL;
+       char *default_runlevel;
        char buf[2048];
        int count;
        FILE *fifo;
+       bool reexec = false;
        struct sigaction sa;
 
        if (getpid() != 1)
@@ -134,16 +142,22 @@ int main(int argc, char **argv)
 
        if (argc > 1)
                default_runlevel = argv[1];
+       else
+               default_runlevel = NULL;
+
+       if (default_runlevel && strcmp(default_runlevel, "reexec") == 0)
+               reexec = true;
 
        printf("OpenRC init version %s starting\n", VERSION);
-       init(default_runlevel);
+       if (! reexec)
+               init(default_runlevel);
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = signal_handler;
        sigaction(SIGCHLD, &sa, NULL);
        sigaction(SIGINT, &sa, NULL);
        reboot(RB_DISABLE_CAD);
 
-       if (mkfifo(RC_INIT_FIFO, 0600) == -1)
+       if (mkfifo(RC_INIT_FIFO, 0600) == -1 && errno != EEXIST)
                perror("mkfifo");
 
        for (;;) {
@@ -166,6 +180,8 @@ int main(int argc, char **argv)
                        handle_shutdown("shutdown", RB_POWER_OFF);
                else if (strcmp(buf, "reboot") == 0)
                        handle_shutdown("reboot", RB_AUTOBOOT);
+               else if (strcmp(buf, "reexec") == 0)
+                       handle_reexec(argv[0]);
        }
        return 0;
 }

diff --git a/src/rc/openrc-shutdown.c b/src/rc/openrc-shutdown.c
index 978e8a68..8905d354 100644
--- a/src/rc/openrc-shutdown.c
+++ b/src/rc/openrc-shutdown.c
@@ -35,11 +35,12 @@
 
 const char *applet = NULL;
 const char *extraopts = NULL;
-const char *getoptstring = "kpr" getoptstring_COMMON;
+const char *getoptstring = "HkpRr" getoptstring_COMMON;
 const struct option longopts[] = {
        { "halt",        no_argument, NULL, 'H'},
        { "kexec",        no_argument, NULL, 'k'},
        { "poweroff",        no_argument, NULL, 'p'},
+       { "reexec",        no_argument, NULL, 'R'},
        { "reboot",        no_argument, NULL, 'r'},
        longopts_COMMON
 };
@@ -47,11 +48,13 @@ const char * const longopts_help[] = {
        "halt the system",
        "reboot the system using kexec",
        "power off the system",
+       "re-execute init (use after upgrading)",
        "reboot the system",
        longopts_help_COMMON
 };
 const char *usagestring = NULL;
-const char *exclusive = "Select one of --halt, --kexec, --poweroff or 
--reboot";
+const char *exclusive = "Select one of "
+"--halt, --kexec, --poweroff, --reexec or --reboot";
 
 static void send_cmd(const char *cmd)
 {
@@ -79,6 +82,7 @@ int main(int argc, char **argv)
        bool do_kexec = false;
        bool do_poweroff = false;
        bool do_reboot = false;
+       bool do_reexec = false;
 
        applet = basename_c(argv[0]);
 if (geteuid() != 0)
@@ -99,6 +103,10 @@ if (geteuid() != 0)
                        do_poweroff = true;
                        cmd_count++;
                        break;
+               case 'R':
+                       do_reexec = true;
+                       cmd_count++;
+                       break;
                case 'r':
                        do_reboot = true;
                        cmd_count++;
@@ -118,5 +126,7 @@ if (geteuid() != 0)
                send_cmd("poweroff");
        else if (do_reboot)
                send_cmd("reboot");
+       else if (do_reexec)
+               send_cmd("reexec");
        return 0;
 }

Reply via email to