#endif
#endif
+static void ga_wait_child(pid_t pid, int *status, Error **err)
+{
+ pid_t rpid;
+
+ *status = 0;
+
+ do {
+ rpid = waitpid(pid, status, 0);
+ } while (rpid == -1 && errno == EINTR);
+
+ if (rpid == -1) {
+ error_setg_errno(err, errno, "failed to wait for child (pid: %d)", pid);
+ return;
+ }
+
+ g_assert(rpid == pid);
+}
+
void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
{
const char *shutdown_flag;
- pid_t rpid, pid;
+ Error *local_err = NULL;
+ pid_t pid;
int status;
slog("guest-shutdown called, mode: %s", mode);
} else if (strcmp(mode, "reboot") == 0) {
shutdown_flag = "-r";
} else {
- error_set(err, QERR_INVALID_PARAMETER_VALUE, "mode",
- "halt|powerdown|reboot");
+ error_setg(err,
+ "mode is invalid (valid values are: halt|powerdown|reboot");
return;
}
"hypervisor initiated shutdown", (char*)NULL, environ);
_exit(EXIT_FAILURE);
} else if (pid < 0) {
- goto exit_err;
+ error_setg_errno(err, errno, "failed to create child process");
+ return;
}
- do {
- rpid = waitpid(pid, &status, 0);
- } while (rpid == -1 && errno == EINTR);
- if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
+ ga_wait_child(pid, &status, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
+ return;
+ }
+
+ if (!WIFEXITED(status)) {
+ error_setg(err, "child process has terminated abnormally");
+ return;
+ }
+
+ if (WEXITSTATUS(status)) {
+ error_setg(err, "child process has failed to shutdown");
return;
}
-exit_err:
- error_set(err, QERR_UNDEFINED_ERROR);
+ /* succeded */
}
typedef struct GuestFileHandle {
/*
* Walk the mount table and build a list of local file systems
*/
-static int build_fs_mount_list(FsMountList *mounts)
+static void build_fs_mount_list(FsMountList *mounts, Error **err)
{
struct mntent *ment;
FsMount *mount;
fp = setmntent(mtab, "r");
if (!fp) {
- g_warning("fsfreeze: unable to read mtab");
- return -1;
+ error_setg(err, "failed to open mtab file: '%s'", mtab);
+ return;
}
while ((ment = getmntent(fp))) {
}
endmntent(fp);
-
- return 0;
}
#endif
#if defined(CONFIG_FSFREEZE)
+typedef enum {
+ FSFREEZE_HOOK_THAW = 0,
+ FSFREEZE_HOOK_FREEZE,
+} FsfreezeHookArg;
+
+const char *fsfreeze_hook_arg_string[] = {
+ "thaw",
+ "freeze",
+};
+
+static void execute_fsfreeze_hook(FsfreezeHookArg arg, Error **err)
+{
+ int status;
+ pid_t pid;
+ const char *hook;
+ const char *arg_str = fsfreeze_hook_arg_string[arg];
+ Error *local_err = NULL;
+
+ hook = ga_fsfreeze_hook(ga_state);
+ if (!hook) {
+ return;
+ }
+ if (access(hook, X_OK) != 0) {
+ error_setg_errno(err, errno, "can't access fsfreeze hook '%s'", hook);
+ return;
+ }
+
+ slog("executing fsfreeze hook with arg '%s'", arg_str);
+ pid = fork();
+ if (pid == 0) {
+ setsid();
+ reopen_fd_to_null(0);
+ reopen_fd_to_null(1);
+ reopen_fd_to_null(2);
+
+ execle(hook, hook, arg_str, NULL, environ);
+ _exit(EXIT_FAILURE);
+ } else if (pid < 0) {
+ error_setg_errno(err, errno, "failed to create child process");
+ return;
+ }
+
+ ga_wait_child(pid, &status, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
+ return;
+ }
+
+ if (!WIFEXITED(status)) {
+ error_setg(err, "fsfreeze hook has terminated abnormally");
+ return;
+ }
+
+ status = WEXITSTATUS(status);
+ if (status) {
+ error_setg(err, "fsfreeze hook has failed with status %d", status);
+ return;
+ }
+}
+
/*
* Return status of freeze/thaw
*/
int ret = 0, i = 0;
FsMountList mounts;
struct FsMount *mount;
+ Error *local_err = NULL;
int fd;
- char err_msg[512];
slog("guest-fsfreeze called");
+ execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
+ return -1;
+ }
+
QTAILQ_INIT(&mounts);
- ret = build_fs_mount_list(&mounts);
- if (ret < 0) {
- return ret;
+ build_fs_mount_list(&mounts, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
+ return -1;
}
/* cannot risk guest agent blocking itself on a write in this state */
QTAILQ_FOREACH(mount, &mounts, next) {
fd = qemu_open(mount->dirname, O_RDONLY);
if (fd == -1) {
- sprintf(err_msg, "failed to open %s, %s", mount->dirname,
- strerror(errno));
- error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(err, errno, "failed to open %s", mount->dirname);
goto error;
}
ret = ioctl(fd, FIFREEZE);
if (ret == -1) {
if (errno != EOPNOTSUPP) {
- sprintf(err_msg, "failed to freeze %s, %s",
- mount->dirname, strerror(errno));
- error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(err, errno, "failed to freeze %s",
+ mount->dirname);
close(fd);
goto error;
}
FsMountList mounts;
FsMount *mount;
int fd, i = 0, logged;
+ Error *local_err = NULL;
QTAILQ_INIT(&mounts);
- ret = build_fs_mount_list(&mounts);
- if (ret) {
- error_set(err, QERR_QGA_COMMAND_FAILED,
- "failed to enumerate filesystems");
+ build_fs_mount_list(&mounts, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
return 0;
}
ga_unset_frozen(ga_state);
free_fs_mount_list(&mounts);
+
+ execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err);
+
return i;
}
FsMountList mounts;
struct FsMount *mount;
int fd;
- char err_msg[512];
+ Error *local_err = NULL;
struct fstrim_range r = {
.start = 0,
.len = -1,
slog("guest-fstrim called");
QTAILQ_INIT(&mounts);
- ret = build_fs_mount_list(&mounts);
- if (ret < 0) {
+ build_fs_mount_list(&mounts, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
return;
}
QTAILQ_FOREACH(mount, &mounts, next) {
fd = qemu_open(mount->dirname, O_RDONLY);
if (fd == -1) {
- sprintf(err_msg, "failed to open %s, %s", mount->dirname,
- strerror(errno));
- error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(err, errno, "failed to open %s", mount->dirname);
goto error;
}
ret = ioctl(fd, FITRIM, &r);
if (ret == -1) {
if (errno != ENOTTY && errno != EOPNOTSUPP) {
- sprintf(err_msg, "failed to trim %s, %s",
- mount->dirname, strerror(errno));
- error_set(err, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(err, errno, "failed to trim %s",
+ mount->dirname);
close(fd);
goto error;
}
static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
const char *sysfile_str, Error **err)
{
+ Error *local_err = NULL;
char *pmutils_path;
- pid_t pid, rpid;
+ pid_t pid;
int status;
pmutils_path = g_find_program_in_path(pmutils_bin);
}
_exit(SUSPEND_NOT_SUPPORTED);
+ } else if (pid < 0) {
+ error_setg_errno(err, errno, "failed to create child process");
+ goto out;
}
- g_free(pmutils_path);
+ ga_wait_child(pid, &status, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
+ goto out;
+ }
- if (pid < 0) {
- goto undef_err;
+ if (!WIFEXITED(status)) {
+ error_setg(err, "child process has terminated abnormally");
+ goto out;
}
- 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;
- }
+ switch (WEXITSTATUS(status)) {
+ case SUSPEND_SUPPORTED:
+ goto out;
+ case SUSPEND_NOT_SUPPORTED:
+ error_setg(err,
+ "the requested suspend mode is not supported by the guest");
+ goto out;
+ default:
+ error_setg(err,
+ "the helper program '%s' returned an unexpected exit status"
+ " code (%d)", pmutils_path, WEXITSTATUS(status));
+ goto out;
}
-undef_err:
- error_set(err, QERR_UNDEFINED_ERROR);
+out:
+ g_free(pmutils_path);
}
static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
Error **err)
{
+ Error *local_err = NULL;
char *pmutils_path;
- pid_t rpid, pid;
+ pid_t pid;
int status;
pmutils_path = g_find_program_in_path(pmutils_bin);
}
_exit(EXIT_SUCCESS);
+ } else if (pid < 0) {
+ error_setg_errno(err, errno, "failed to create child process");
+ goto out;
}
- g_free(pmutils_path);
+ ga_wait_child(pid, &status, &local_err);
+ if (error_is_set(&local_err)) {
+ error_propagate(err, local_err);
+ goto out;
+ }
- if (pid < 0) {
- goto exit_err;
+ if (!WIFEXITED(status)) {
+ error_setg(err, "child process has terminated abnormally");
+ goto out;
}
- do {
- rpid = waitpid(pid, &status, 0);
- } while (rpid == -1 && errno == EINTR);
- if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
- return;
+ if (WEXITSTATUS(status)) {
+ error_setg(err, "child process has failed to suspend");
+ goto out;
}
-exit_err:
- error_set(err, QERR_UNDEFINED_ERROR);
+out:
+ g_free(pmutils_path);
}
void qmp_guest_suspend_disk(Error **err)
{
GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
struct ifaddrs *ifap, *ifa;
- char err_msg[512];
if (getifaddrs(&ifap) < 0) {
- snprintf(err_msg, sizeof(err_msg),
- "getifaddrs failed: %s", strerror(errno));
- error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(errp, errno, "getifaddrs failed");
goto error;
}
/* we haven't obtained HW address yet */
sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
- snprintf(err_msg, sizeof(err_msg),
- "failed to create socket: %s", strerror(errno));
- error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(errp, errno, "failed to create socket");
goto error;
}
memset(&ifr, 0, sizeof(ifr));
pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->value->name);
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
- snprintf(err_msg, sizeof(err_msg),
- "failed to get MAC address of %s: %s",
- ifa->ifa_name,
- strerror(errno));
- error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(errp, errno,
+ "failed to get MAC address of %s",
+ ifa->ifa_name);
goto error;
}
(int) mac_addr[0], (int) mac_addr[1],
(int) mac_addr[2], (int) mac_addr[3],
(int) mac_addr[4], (int) mac_addr[5]) == -1) {
- snprintf(err_msg, sizeof(err_msg),
- "failed to format MAC: %s", strerror(errno));
- error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(errp, errno, "failed to format MAC");
goto error;
}
address_item->value = g_malloc0(sizeof(*address_item->value));
p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
- snprintf(err_msg, sizeof(err_msg),
- "inet_ntop failed : %s", strerror(errno));
- error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(errp, errno, "inet_ntop failed");
goto error;
}
address_item->value = g_malloc0(sizeof(*address_item->value));
p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
- snprintf(err_msg, sizeof(err_msg),
- "inet_ntop failed : %s", strerror(errno));
- error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
+ error_setg_errno(errp, errno, "inet_ntop failed");
goto error;
}