summaryrefslogtreecommitdiff
path: root/qga/commands-posix.c
diff options
context:
space:
mode:
Diffstat (limited to 'qga/commands-posix.c')
-rw-r--r--qga/commands-posix.c128
1 files changed, 54 insertions, 74 deletions
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index adb9b3db8d..76c8235272 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -512,117 +512,88 @@ static void guest_fsfreeze_cleanup(void)
#define SUSPEND_SUPPORTED 0
#define SUSPEND_NOT_SUPPORTED 1
-/**
- * This function forks twice and the information about the mode support
- * status is passed to the qemu-ga process via a pipe.
- *
- * This approach allows us to keep the way we reap terminated children
- * in qemu-ga quite simple.
- */
static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
const char *sysfile_str, Error **err)
{
- pid_t pid;
- ssize_t ret;
char *pmutils_path;
- int status, pipefds[2];
-
- if (pipe(pipefds) < 0) {
- error_set(err, QERR_UNDEFINED_ERROR);
- return;
- }
+ pid_t pid, rpid;
+ int status;
pmutils_path = g_find_program_in_path(pmutils_bin);
pid = fork();
if (!pid) {
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = SIG_DFL;
- sigaction(SIGCHLD, &act, NULL);
+ char buf[32]; /* hopefully big enough */
+ ssize_t ret;
+ int fd;
setsid();
- close(pipefds[0]);
reopen_fd_to_null(0);
reopen_fd_to_null(1);
reopen_fd_to_null(2);
- pid = fork();
- if (!pid) {
- int fd;
- char buf[32]; /* hopefully big enough */
-
- if (pmutils_path) {
- execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
- }
-
- /*
- * If we get here either pm-utils is not installed or execle() has
- * failed. Let's try the manual method if the caller wants it.
- */
-
- if (!sysfile_str) {
- _exit(SUSPEND_NOT_SUPPORTED);
- }
-
- fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
- if (fd < 0) {
- _exit(SUSPEND_NOT_SUPPORTED);
- }
+ if (pmutils_path) {
+ execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
+ }
- ret = read(fd, buf, sizeof(buf)-1);
- if (ret <= 0) {
- _exit(SUSPEND_NOT_SUPPORTED);
- }
- buf[ret] = '\0';
+ /*
+ * If we get here either pm-utils is not installed or execle() has
+ * failed. Let's try the manual method if the caller wants it.
+ */
- if (strstr(buf, sysfile_str)) {
- _exit(SUSPEND_SUPPORTED);
- }
+ if (!sysfile_str) {
+ _exit(SUSPEND_NOT_SUPPORTED);
+ }
+ fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
+ if (fd < 0) {
_exit(SUSPEND_NOT_SUPPORTED);
}
- if (pid > 0) {
- wait(&status);
- } else {
- status = SUSPEND_NOT_SUPPORTED;
+ ret = read(fd, buf, sizeof(buf)-1);
+ if (ret <= 0) {
+ _exit(SUSPEND_NOT_SUPPORTED);
}
+ buf[ret] = '\0';
- ret = write(pipefds[1], &status, sizeof(status));
- if (ret != sizeof(status)) {
- _exit(EXIT_FAILURE);
+ if (strstr(buf, sysfile_str)) {
+ _exit(SUSPEND_SUPPORTED);
}
- _exit(EXIT_SUCCESS);
+ _exit(SUSPEND_NOT_SUPPORTED);
}
- close(pipefds[1]);
g_free(pmutils_path);
if (pid < 0) {
- error_set(err, QERR_UNDEFINED_ERROR);
- goto out;
- }
-
- ret = read(pipefds[0], &status, sizeof(status));
- if (ret == sizeof(status) && WIFEXITED(status) &&
- WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
- goto out;
+ goto undef_err;
+ }
+
+ do {
+ rpid = waitpid(pid, &status, 0);
+ } while (rpid == -1 && errno == EINTR);
+ if (rpid == pid && WIFEXITED(status)) {
+ switch (WEXITSTATUS(status)) {
+ case SUSPEND_SUPPORTED:
+ return;
+ case SUSPEND_NOT_SUPPORTED:
+ error_set(err, QERR_UNSUPPORTED);
+ return;
+ default:
+ goto undef_err;
+ }
}
- error_set(err, QERR_UNSUPPORTED);
-
-out:
- close(pipefds[0]);
+undef_err:
+ error_set(err, QERR_UNDEFINED_ERROR);
}
static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
Error **err)
{
- pid_t pid;
char *pmutils_path;
+ pid_t rpid, pid;
+ int status;
pmutils_path = g_find_program_in_path(pmutils_bin);
@@ -664,9 +635,18 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
g_free(pmutils_path);
if (pid < 0) {
- error_set(err, QERR_UNDEFINED_ERROR);
+ goto exit_err;
+ }
+
+ do {
+ rpid = waitpid(pid, &status, 0);
+ } while (rpid == -1 && errno == EINTR);
+ if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
return;
}
+
+exit_err:
+ error_set(err, QERR_UNDEFINED_ERROR);
}
void qmp_guest_suspend_disk(Error **err)