[PATCH 4/4] softmmu: move parsing of -runas, -chroot and -daemonize code

Daniel P. Berrangé berrange at redhat.com
Fri Mar 4 11:56:57 UTC 2022


With the future intent to try to move to a fully QAPI driven
configuration system, we want to have any current command
parsing well isolated from logic that applies the resulting
configuration.

We also don't want os-posix.c to contain code that is specific
to the system emulators, as this file is linked to other binaries
too.

To satisfy these goals, we move parsing of the -runas, -chroot and
-daemonize code out of the os-posix.c helper code, and pass the
parsed data into APIs in os-posix.c.

As a side benefit the 'os_daemonize()' function now lives upto to
its name and will always daemonize, instead of using global state
to decide to be a no-op sometimes.

Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
---
 include/sysemu/os-posix.h |   4 +-
 include/sysemu/os-win32.h |   1 -
 os-posix.c                | 148 +++++++++++---------------------------
 os-win32.c                |   9 ---
 softmmu/vl.c              |  76 ++++++++++++++++++--
 5 files changed, 113 insertions(+), 125 deletions(-)

diff --git a/include/sysemu/os-posix.h b/include/sysemu/os-posix.h
index 2edf33658a..390f3f8396 100644
--- a/include/sysemu/os-posix.h
+++ b/include/sysemu/os-posix.h
@@ -46,7 +46,9 @@ void os_set_line_buffering(void);
 void os_set_proc_name(const char *s);
 void os_setup_signal_handling(void);
 void os_daemonize(void);
-void os_setup_post(void);
+void os_setup_post(const char *chroot_dir,
+                   uid_t uid, gid_t gid,
+                   const char *username);
 int os_mlock(void);
 
 #define closesocket(s) close(s)
diff --git a/include/sysemu/os-win32.h b/include/sysemu/os-win32.h
index 43f569b5c2..4879f8731d 100644
--- a/include/sysemu/os-win32.h
+++ b/include/sysemu/os-win32.h
@@ -61,7 +61,6 @@ struct tm *localtime_r(const time_t *timep, struct tm *result);
 
 static inline void os_setup_signal_handling(void) {}
 static inline void os_daemonize(void) {}
-static inline void os_setup_post(void) {}
 void os_set_line_buffering(void);
 static inline void os_set_proc_name(const char *dummy) {}
 
diff --git a/os-posix.c b/os-posix.c
index 30da1a1491..f598a52a4f 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -42,11 +42,6 @@
 #include <sys/prctl.h>
 #endif
 
-static char *user_name;
-static uid_t user_uid = (uid_t)-1;
-static gid_t user_gid = (gid_t)-1;
-
-static const char *chroot_dir;
 static int daemonize;
 static int daemon_pipe;
 
@@ -96,69 +91,6 @@ void os_set_proc_name(const char *s)
 }
 
 
-static bool os_parse_runas_uid_gid(const char *optarg,
-                                   uid_t *runas_uid, gid_t *runas_gid)
-{
-    unsigned long lv;
-    const char *ep;
-    uid_t got_uid;
-    gid_t got_gid;
-    int rc;
-
-    rc = qemu_strtoul(optarg, &ep, 0, &lv);
-    got_uid = lv; /* overflow here is ID in C99 */
-    if (rc || *ep != ':' || got_uid != lv || got_uid == (uid_t)-1) {
-        return false;
-    }
-
-    rc = qemu_strtoul(ep + 1, 0, 0, &lv);
-    got_gid = lv; /* overflow here is ID in C99 */
-    if (rc || got_gid != lv || got_gid == (gid_t)-1) {
-        return false;
-    }
-
-    *runas_uid = got_uid;
-    *runas_gid = got_gid;
-    return true;
-}
-
-/*
- * Parse OS specific command line options.
- * return 0 if option handled, -1 otherwise
- */
-int os_parse_cmd_args(int index, const char *optarg)
-{
-    struct passwd *user_pwd;
-
-    switch (index) {
-    case QEMU_OPTION_runas:
-        user_pwd = getpwnam(optarg);
-        if (user_pwd) {
-            user_uid = user_pwd->pw_uid;
-            user_gid = user_pwd->pw_gid;
-            user_name = g_strdup(user_pwd->pw_name);
-        } else if (!os_parse_runas_uid_gid(optarg,
-                                           &user_uid,
-                                           &user_gid)) {
-            error_report("User \"%s\" doesn't exist"
-                         " (and is not <uid>:<gid>)",
-                         optarg);
-            exit(1);
-        }
-        break;
-    case QEMU_OPTION_chroot:
-        chroot_dir = optarg;
-        break;
-    case QEMU_OPTION_daemonize:
-        daemonize = 1;
-        break;
-    default:
-        return -1;
-    }
-
-    return 0;
-}
-
 static void change_process_uid(uid_t uid, gid_t gid, const char *name)
 {
     if (setgid(gid) < 0) {
@@ -202,54 +134,56 @@ static void change_root(const char *root)
 
 void os_daemonize(void)
 {
-    if (daemonize) {
-        pid_t pid;
-        int fds[2];
+    pid_t pid;
+    int fds[2];
 
-        if (pipe(fds) == -1) {
-            exit(1);
-        }
+    if (pipe(fds) == -1) {
+        exit(1);
+    }
 
-        pid = fork();
-        if (pid > 0) {
-            uint8_t status;
-            ssize_t len;
+    pid = fork();
+    if (pid > 0) {
+        uint8_t status;
+        ssize_t len;
 
-            close(fds[1]);
+        close(fds[1]);
 
-            do {
-                len = read(fds[0], &status, 1);
-            } while (len < 0 && errno == EINTR);
+        do {
+            len = read(fds[0], &status, 1);
+        } while (len < 0 && errno == EINTR);
 
-            /* only exit successfully if our child actually wrote
-             * a one-byte zero to our pipe, upon successful init */
-            exit(len == 1 && status == 0 ? 0 : 1);
+        /* only exit successfully if our child actually wrote
+         * a one-byte zero to our pipe, upon successful init */
+        exit(len == 1 && status == 0 ? 0 : 1);
 
-        } else if (pid < 0) {
-            exit(1);
-        }
+    } else if (pid < 0) {
+        exit(1);
+    }
 
-        close(fds[0]);
-        daemon_pipe = fds[1];
-        qemu_set_cloexec(daemon_pipe);
+    close(fds[0]);
+    daemon_pipe = fds[1];
+    qemu_set_cloexec(daemon_pipe);
 
-        setsid();
+    setsid();
 
-        pid = fork();
-        if (pid > 0) {
+    pid = fork();
+    if (pid > 0) {
             exit(0);
-        } else if (pid < 0) {
-            exit(1);
-        }
-        umask(027);
-
-        signal(SIGTSTP, SIG_IGN);
-        signal(SIGTTOU, SIG_IGN);
-        signal(SIGTTIN, SIG_IGN);
+    } else if (pid < 0) {
+        exit(1);
     }
+    umask(027);
+
+    signal(SIGTSTP, SIG_IGN);
+    signal(SIGTTOU, SIG_IGN);
+    signal(SIGTTIN, SIG_IGN);
+
+    daemonize = true;
 }
 
-void os_setup_post(void)
+void os_setup_post(const char *root_dir,
+                   uid_t runas_uid, gid_t runas_gid,
+                   const char *runas_name)
 {
     int fd = 0;
 
@@ -264,11 +198,11 @@ void os_setup_post(void)
         }
     }
 
-    if (chroot_dir) {
-        change_root(chroot_dir);
+    if (root_dir != NULL) {
+        change_root(root_dir);
     }
-    if (user_uid != -1 && user_gid != -1) {
-        change_process_uid(user_uid, user_gid, user_name);
+    if (runas_uid != -1 && runas_gid != -1) {
+        change_process_uid(runas_uid, runas_gid, runas_name);
     }
 
     if (daemonize) {
diff --git a/os-win32.c b/os-win32.c
index e31c921983..6f21b57841 100644
--- a/os-win32.c
+++ b/os-win32.c
@@ -61,12 +61,3 @@ void os_set_line_buffering(void)
     setbuf(stdout, NULL);
     setbuf(stderr, NULL);
 }
-
-/*
- * Parse OS specific command line options.
- * return 0 if option handled, -1 otherwise
- */
-int os_parse_cmd_args(int index, const char *optarg)
-{
-    return -1;
-}
diff --git a/softmmu/vl.c b/softmmu/vl.c
index 1fe028800f..cdf27b6027 100644
--- a/softmmu/vl.c
+++ b/softmmu/vl.c
@@ -2602,11 +2602,13 @@ static void qemu_process_help_options(void)
     }
 }
 
-static void qemu_maybe_daemonize(const char *pid_file)
+static void qemu_maybe_daemonize(bool daemonize, const char *pid_file)
 {
     Error *err = NULL;
 
-    os_daemonize();
+    if (daemonize) {
+        os_daemonize();
+    }
     rcu_disable_atfork();
 
     if (pid_file && !qemu_write_pidfile(pid_file, &err)) {
@@ -2768,6 +2770,35 @@ void qmp_x_exit_preconfig(Error **errp)
     }
 }
 
+#ifndef WIN32
+static bool os_parse_runas_uid_gid(const char *optarg,
+                                   uid_t *runas_uid,
+                                   gid_t *runas_gid)
+{
+    unsigned long lv;
+    const char *ep;
+    uid_t got_uid;
+    gid_t got_gid;
+    int rc;
+
+    rc = qemu_strtoul(optarg, &ep, 0, &lv);
+    got_uid = lv; /* overflow here is ID in C99 */
+    if (rc || *ep != ':' || got_uid != lv || got_uid == (uid_t)-1) {
+        return false;
+    }
+
+    rc = qemu_strtoul(ep + 1, 0, 0, &lv);
+    got_gid = lv; /* overflow here is ID in C99 */
+    if (rc || got_gid != lv || got_gid == (gid_t)-1) {
+        return false;
+    }
+
+    *runas_gid = got_gid;
+    *runas_uid = got_uid;
+    return true;
+}
+#endif /* !WIN32 */
+
 void qemu_init(int argc, char **argv, char **envp)
 {
     QemuOpts *opts;
@@ -2778,6 +2809,14 @@ void qemu_init(int argc, char **argv, char **envp)
     MachineClass *machine_class;
     bool userconfig = true;
     FILE *vmstate_dump_file = NULL;
+    bool daemonize = false;
+#ifndef WIN32
+    struct passwd *pwd;
+    uid_t runas_uid = -1;
+    gid_t runas_gid = -1;
+    g_autofree char *runas_name = NULL;
+    const char *chroot_dir = NULL;
+#endif /* !WIN32 */
 
     qemu_add_opts(&qemu_drive_opts);
     qemu_add_drive_opts(&qemu_legacy_drive_opts);
@@ -3659,11 +3698,32 @@ void qemu_init(int argc, char **argv, char **envp)
             case QEMU_OPTION_nouserconfig:
                 /* Nothing to be parsed here. Especially, do not error out below. */
                 break;
-            default:
-                if (os_parse_cmd_args(popt->index, optarg)) {
-                    error_report("Option not supported in this build");
+#ifndef WIN32
+            case QEMU_OPTION_runas:
+                pwd = getpwnam(optarg);
+                if (pwd) {
+                    runas_uid = pwd->pw_uid;
+                    runas_gid = pwd->pw_gid;
+                    runas_name = g_strdup(pwd->pw_name);
+                } else if (!os_parse_runas_uid_gid(optarg,
+                                                   &runas_uid,
+                                                   &runas_gid)) {
+                    error_report("User \"%s\" doesn't exist"
+                                 " (and is not <uid>:<gid>)",
+                                 optarg);
                     exit(1);
                 }
+                break;
+            case QEMU_OPTION_chroot:
+                chroot_dir = optarg;
+                break;
+            case QEMU_OPTION_daemonize:
+                daemonize = 1;
+                break;
+#endif /* !WIN32 */
+            default:
+                error_report("Option not supported in this build");
+                exit(1);
             }
         }
     }
@@ -3683,7 +3743,7 @@ void qemu_init(int argc, char **argv, char **envp)
     qemu_process_early_options();
 
     qemu_process_help_options();
-    qemu_maybe_daemonize(pid_file);
+    qemu_maybe_daemonize(daemonize, pid_file);
 
     /*
      * The trace backend must be initialized after daemonizing.
@@ -3778,6 +3838,8 @@ void qemu_init(int argc, char **argv, char **envp)
     }
     qemu_init_displays();
     accel_setup_post(current_machine);
-    os_setup_post();
+#ifndef WIN32
+    os_setup_post(chroot_dir, runas_uid, runas_gid, runas_name);
+#endif /* !WIN32 */
     resume_mux_open();
 }
-- 
2.34.1




More information about the libvir-list mailing list