|
@@ -46,10 +46,29 @@ extern char **environ;
|
|
|
#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);
|
|
@@ -60,8 +79,8 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
|
|
} 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;
|
|
|
}
|
|
|
|
|
@@ -77,18 +96,27 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
|
|
"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 {
|
|
@@ -111,7 +139,7 @@ static void guest_file_handle_add(FILE *fh)
|
|
|
QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
|
|
|
}
|
|
|
|
|
|
-static GuestFileHandle *guest_file_handle_find(int64_t id)
|
|
|
+static GuestFileHandle *guest_file_handle_find(int64_t id, Error **err)
|
|
|
{
|
|
|
GuestFileHandle *gfh;
|
|
|
|
|
@@ -122,6 +150,7 @@ static GuestFileHandle *guest_file_handle_find(int64_t id)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ error_setg(err, "handle '%" PRId64 "' has not been found", id);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
@@ -137,7 +166,8 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
|
|
|
slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
|
|
|
fh = fopen(path, mode);
|
|
|
if (!fh) {
|
|
|
- error_set(err, QERR_OPEN_FILE_FAILED, path);
|
|
|
+ error_setg_errno(err, errno, "failed to open file '%s' (mode: '%s')",
|
|
|
+ path, mode);
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -148,7 +178,8 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
|
|
|
ret = fcntl(fd, F_GETFL);
|
|
|
ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
|
|
|
if (ret == -1) {
|
|
|
- error_set(err, QERR_QGA_COMMAND_FAILED, "fcntl() failed");
|
|
|
+ error_setg_errno(err, errno, "failed to make file '%s' non-blocking",
|
|
|
+ path);
|
|
|
fclose(fh);
|
|
|
return -1;
|
|
|
}
|
|
@@ -160,18 +191,17 @@ int64_t qmp_guest_file_open(const char *path, bool has_mode, const char *mode, E
|
|
|
|
|
|
void qmp_guest_file_close(int64_t handle, Error **err)
|
|
|
{
|
|
|
- GuestFileHandle *gfh = guest_file_handle_find(handle);
|
|
|
+ GuestFileHandle *gfh = guest_file_handle_find(handle, err);
|
|
|
int ret;
|
|
|
|
|
|
slog("guest-file-close called, handle: %ld", handle);
|
|
|
if (!gfh) {
|
|
|
- error_set(err, QERR_FD_NOT_FOUND, "handle");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
ret = fclose(gfh->fh);
|
|
|
- if (ret == -1) {
|
|
|
- error_set(err, QERR_QGA_COMMAND_FAILED, "fclose() failed");
|
|
|
+ if (ret == EOF) {
|
|
|
+ error_setg_errno(err, errno, "failed to close handle");
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -182,21 +212,21 @@ void qmp_guest_file_close(int64_t handle, Error **err)
|
|
|
struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
|
|
|
int64_t count, Error **err)
|
|
|
{
|
|
|
- GuestFileHandle *gfh = guest_file_handle_find(handle);
|
|
|
+ GuestFileHandle *gfh = guest_file_handle_find(handle, err);
|
|
|
GuestFileRead *read_data = NULL;
|
|
|
guchar *buf;
|
|
|
FILE *fh;
|
|
|
size_t read_count;
|
|
|
|
|
|
if (!gfh) {
|
|
|
- error_set(err, QERR_FD_NOT_FOUND, "handle");
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
if (!has_count) {
|
|
|
count = QGA_READ_COUNT_DEFAULT;
|
|
|
} else if (count < 0) {
|
|
|
- error_set(err, QERR_INVALID_PARAMETER, "count");
|
|
|
+ error_setg(err, "value '%" PRId64 "' is invalid for argument count",
|
|
|
+ count);
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
@@ -204,8 +234,8 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
|
|
|
buf = g_malloc0(count+1);
|
|
|
read_count = fread(buf, 1, count, fh);
|
|
|
if (ferror(fh)) {
|
|
|
+ error_setg_errno(err, errno, "failed to read file");
|
|
|
slog("guest-file-read failed, handle: %ld", handle);
|
|
|
- error_set(err, QERR_QGA_COMMAND_FAILED, "fread() failed");
|
|
|
} else {
|
|
|
buf[read_count] = 0;
|
|
|
read_data = g_malloc0(sizeof(GuestFileRead));
|
|
@@ -228,11 +258,10 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
|
|
|
guchar *buf;
|
|
|
gsize buf_len;
|
|
|
int write_count;
|
|
|
- GuestFileHandle *gfh = guest_file_handle_find(handle);
|
|
|
+ GuestFileHandle *gfh = guest_file_handle_find(handle, err);
|
|
|
FILE *fh;
|
|
|
|
|
|
if (!gfh) {
|
|
|
- error_set(err, QERR_FD_NOT_FOUND, "handle");
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
@@ -242,15 +271,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
|
|
|
if (!has_count) {
|
|
|
count = buf_len;
|
|
|
} else if (count < 0 || count > buf_len) {
|
|
|
+ error_setg(err, "value '%" PRId64 "' is invalid for argument count",
|
|
|
+ count);
|
|
|
g_free(buf);
|
|
|
- error_set(err, QERR_INVALID_PARAMETER, "count");
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
write_count = fwrite(buf, 1, count, fh);
|
|
|
if (ferror(fh)) {
|
|
|
+ error_setg_errno(err, errno, "failed to write to file");
|
|
|
slog("guest-file-write failed, handle: %ld", handle);
|
|
|
- error_set(err, QERR_QGA_COMMAND_FAILED, "fwrite() error");
|
|
|
} else {
|
|
|
write_data = g_malloc0(sizeof(GuestFileWrite));
|
|
|
write_data->count = write_count;
|
|
@@ -265,20 +295,19 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
|
|
|
struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
|
|
|
int64_t whence, Error **err)
|
|
|
{
|
|
|
- GuestFileHandle *gfh = guest_file_handle_find(handle);
|
|
|
+ GuestFileHandle *gfh = guest_file_handle_find(handle, err);
|
|
|
GuestFileSeek *seek_data = NULL;
|
|
|
FILE *fh;
|
|
|
int ret;
|
|
|
|
|
|
if (!gfh) {
|
|
|
- error_set(err, QERR_FD_NOT_FOUND, "handle");
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
fh = gfh->fh;
|
|
|
ret = fseek(fh, offset, whence);
|
|
|
if (ret == -1) {
|
|
|
- error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
|
|
|
+ error_setg_errno(err, errno, "failed to seek file");
|
|
|
} else {
|
|
|
seek_data = g_malloc0(sizeof(GuestFileRead));
|
|
|
seek_data->position = ftell(fh);
|
|
@@ -291,19 +320,18 @@ struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
|
|
|
|
|
|
void qmp_guest_file_flush(int64_t handle, Error **err)
|
|
|
{
|
|
|
- GuestFileHandle *gfh = guest_file_handle_find(handle);
|
|
|
+ GuestFileHandle *gfh = guest_file_handle_find(handle, err);
|
|
|
FILE *fh;
|
|
|
int ret;
|
|
|
|
|
|
if (!gfh) {
|
|
|
- error_set(err, QERR_FD_NOT_FOUND, "handle");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
fh = gfh->fh;
|
|
|
ret = fflush(fh);
|
|
|
if (ret == EOF) {
|
|
|
- error_set(err, QERR_QGA_COMMAND_FAILED, strerror(errno));
|
|
|
+ error_setg_errno(err, errno, "failed to flush file");
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -343,7 +371,7 @@ static void free_fs_mount_list(FsMountList *mounts)
|
|
|
/*
|
|
|
* 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;
|
|
@@ -352,8 +380,8 @@ static int build_fs_mount_list(FsMountList *mounts)
|
|
|
|
|
|
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))) {
|
|
@@ -377,13 +405,71 @@ static int build_fs_mount_list(FsMountList *mounts)
|
|
|
}
|
|
|
|
|
|
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
|
|
|
*/
|
|
@@ -405,15 +491,22 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err)
|
|
|
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 */
|
|
@@ -422,9 +515,7 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err)
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -440,9 +531,8 @@ int64_t qmp_guest_fsfreeze_freeze(Error **err)
|
|
|
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;
|
|
|
}
|
|
@@ -470,12 +560,12 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -513,6 +603,9 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)
|
|
|
|
|
|
ga_unset_frozen(ga_state);
|
|
|
free_fs_mount_list(&mounts);
|
|
|
+
|
|
|
+ execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, err);
|
|
|
+
|
|
|
return i;
|
|
|
}
|
|
|
|
|
@@ -540,7 +633,7 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
|
|
|
FsMountList mounts;
|
|
|
struct FsMount *mount;
|
|
|
int fd;
|
|
|
- char err_msg[512];
|
|
|
+ Error *local_err = NULL;
|
|
|
struct fstrim_range r = {
|
|
|
.start = 0,
|
|
|
.len = -1,
|
|
@@ -550,17 +643,16 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -573,9 +665,8 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **err)
|
|
|
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;
|
|
|
}
|
|
@@ -596,8 +687,9 @@ 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);
|
|
@@ -642,38 +734,46 @@ static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
|
|
|
}
|
|
|
|
|
|
_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);
|
|
@@ -711,23 +811,29 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
|
|
|
}
|
|
|
|
|
|
_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)
|
|
@@ -780,12 +886,9 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
|
{
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -821,20 +924,16 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
|
/* 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;
|
|
|
}
|
|
|
|
|
@@ -845,9 +944,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
|
(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;
|
|
|
}
|
|
|
|
|
@@ -862,9 +959,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
|
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;
|
|
|
}
|
|
|
|
|
@@ -884,9 +979,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
|
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;
|
|
|
}
|
|
|
|