diff --git a/usr.sbin/bhyve/snapshot.c b/usr.sbin/bhyve/snapshot.c --- a/usr.sbin/bhyve/snapshot.c +++ b/usr.sbin/bhyve/snapshot.c @@ -1308,9 +1308,10 @@ } static int -vm_checkpoint(struct vmctx *ctx, const char *checkpoint_file, bool stop_vm) +vm_checkpoint(struct vmctx *ctx, int fddir, const char *checkpoint_file, + bool stop_vm) { - int fd_checkpoint = 0, kdata_fd = 0; + int fd_checkpoint = 0, kdata_fd = 0, fd_meta; int ret = 0; int error = 0; size_t memsz; @@ -1325,14 +1326,14 @@ return (-1); } - kdata_fd = open(kdata_filename, O_WRONLY | O_CREAT | O_TRUNC, 0700); + kdata_fd = openat(fddir, kdata_filename, O_WRONLY | O_CREAT | O_TRUNC, 0700); if (kdata_fd < 0) { perror("Failed to open kernel data snapshot file."); error = -1; goto done; } - fd_checkpoint = open(checkpoint_file, O_RDWR | O_CREAT | O_TRUNC, 0700); + fd_checkpoint = openat(fddir, checkpoint_file, O_RDWR | O_CREAT | O_TRUNC, 0700); if (fd_checkpoint < 0) { perror("Failed to create checkpoint file"); @@ -1346,9 +1347,12 @@ goto done; } - meta_file = fopen(meta_filename, "w"); + fd_meta = openat(fddir, meta_filename, O_WRONLY | O_CREAT | O_TRUNC, 0700); + if (fd_meta != -1) + meta_file = fdopen(fd_meta, "w"); if (meta_file == NULL) { perror("Failed to open vm metadata snapshot file."); + close(fd_meta); goto done; } @@ -1474,10 +1478,13 @@ int error; if (!nvlist_exists_string(nvl, "filename") || - !nvlist_exists_bool(nvl, "suspend")) + !nvlist_exists_bool(nvl, "suspend") || + !nvlist_exists_descriptor(nvl, "fddir")) error = EINVAL; else - error = vm_checkpoint(ctx, nvlist_get_string(nvl, "filename"), + error = vm_checkpoint(ctx, + nvlist_get_descriptor(nvl, "fddir"), + nvlist_get_string(nvl, "filename"), nvlist_get_bool(nvl, "suspend")); return (error); diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c --- a/usr.sbin/bhyvectl/bhyvectl.c +++ b/usr.sbin/bhyvectl/bhyvectl.c @@ -1711,14 +1711,35 @@ } static int -snapshot_request(const char *vmname, const char *file, bool suspend) +open_directory(const char *file) +{ + char *path; + int fd; + + if ((path = strdup(file)) == NULL) + return (-1); + + dirname(path); + fd = open(path, O_DIRECTORY); + free(path); + + return (fd); +} + +static int +snapshot_request(const char *vmname, char *file, bool suspend) { nvlist_t *nvl; + int fd; + + if ((fd = open_directory(file)) < 0) + return (errno); nvl = nvlist_create(0); nvlist_add_string(nvl, "cmd", "checkpoint"); - nvlist_add_string(nvl, "filename", file); + nvlist_add_string(nvl, "filename", basename(file)); nvlist_add_bool(nvl, "suspend", suspend); + nvlist_move_descriptor(nvl, "fddir", fd); return (send_message(vmname, nvl)); }