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(a)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