*/
#include "kerncompat.h"
+#include "androidcompat.h"
#include <unistd.h>
#include <stdint.h>
#include <pthread.h>
#include <math.h>
#include <ftw.h>
-#include <wait.h>
+#include <sys/wait.h>
#include <assert.h>
#include <getopt.h>
+#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
int dest_dir_fd;
int write_fd;
- char *write_path;
+ char write_path[PATH_MAX];
char *root_path;
char *dest_dir_path; /* relative to root_path */
- char *full_subvol_path;
+ char full_subvol_path[PATH_MAX];
char *full_root_path;
int dest_dir_chroot;
struct subvol_info cur_subvol;
+ /*
+ * Substitute for cur_subvol::path which is a pointer and we cannot
+ * change it to an array as it's a public API.
+ */
+ char cur_subvol_path[PATH_MAX];
struct subvol_uuid_search sus;
char uuid_str[BTRFS_UUID_UNPARSED_SIZE];
u64 flags;
- if (r->cur_subvol.path == NULL)
+ if (r->cur_subvol_path[0] == 0)
return 0;
- subvol_fd = openat(r->mnt_fd, r->cur_subvol.path,
+ subvol_fd = openat(r->mnt_fd, r->cur_subvol_path,
O_RDONLY | O_NOATIME);
if (subvol_fd < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: open %s failed. %s\n",
- r->cur_subvol.path, strerror(-ret));
+ error("cannot open %s: %s\n",
+ r->cur_subvol_path, strerror(-ret));
goto out;
}
ret = ioctl(subvol_fd, BTRFS_IOC_SET_RECEIVED_SUBVOL, &rs_args);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: BTRFS_IOC_SET_RECEIVED_SUBVOL failed. %s\n",
+ error("ioctl BTRFS_IOC_SET_RECEIVED_SUBVOL failed: %s",
strerror(-ret));
goto out;
}
ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: BTRFS_IOC_SUBVOL_GETFLAGS failed. %s\n",
+ error("ioctl BTRFS_IOC_SUBVOL_GETFLAGS failed: %s",
strerror(-ret));
goto out;
}
ret = ioctl(subvol_fd, BTRFS_IOC_SUBVOL_SETFLAGS, &flags);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: failed to make subvolume read only. "
- "%s\n", strerror(-ret));
+ error("failed to make subvolume read only: %s",
+ strerror(-ret));
goto out;
}
ret = 0;
out:
- if (r->cur_subvol.path) {
- free(r->cur_subvol.path);
- r->cur_subvol.path = NULL;
+ if (r->cur_subvol_path[0]) {
+ r->cur_subvol_path[0] = 0;
}
if (subvol_fd != -1)
close(subvol_fd);
if (ret < 0)
goto out;
- BUG_ON(r->cur_subvol.path);
+ if (r->cur_subvol.path) {
+ error("subvol: another one already started, path ptr: %s",
+ r->cur_subvol.path);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (r->cur_subvol_path[0]) {
+ error("subvol: another one already started, path buf: %s",
+ r->cur_subvol.path);
+ ret = -EINVAL;
+ goto out;
+ }
- if (strlen(r->dest_dir_path) == 0)
- r->cur_subvol.path = strdup(path);
- else
- r->cur_subvol.path = path_cat(r->dest_dir_path, path);
- free(r->full_subvol_path);
- r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
+ if (*r->dest_dir_path == 0) {
+ strncpy_null(r->cur_subvol_path, path);
+ } else {
+ ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
+ if (ret < 0) {
+ error("subvol: path invalid: %s\n", path);
+ goto out;
+ }
+ }
+ ret = path_cat3_out(r->full_subvol_path, r->root_path,
+ r->dest_dir_path, path);
+ if (ret < 0) {
+ error("subvol: path invalid: %s", path);
+ goto out;
+ }
fprintf(stderr, "At subvol %s\n", path);
ret = ioctl(r->dest_dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args_v1);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: creating subvolume %s failed. "
- "%s\n", path, strerror(-ret));
+ error("creating subvolume %s failed: %s", path, strerror(-ret));
goto out;
}
if (ret < 0)
goto out;
- BUG_ON(r->cur_subvol.path);
+ if (r->cur_subvol.path) {
+ error("snapshot: another one already started, path ptr: %s",
+ r->cur_subvol.path);
+ ret = -EINVAL;
+ goto out;
+ }
+ if (r->cur_subvol_path[0]) {
+ error("snapshot: another one already started, path buf: %s",
+ r->cur_subvol.path);
+ ret = -EINVAL;
+ goto out;
+ }
- if (strlen(r->dest_dir_path) == 0)
- r->cur_subvol.path = strdup(path);
- else
- r->cur_subvol.path = path_cat(r->dest_dir_path, path);
- free(r->full_subvol_path);
- r->full_subvol_path = path_cat3(r->root_path, r->dest_dir_path, path);
+ if (*r->dest_dir_path == 0) {
+ strncpy_null(r->cur_subvol_path, path);
+ } else {
+ ret = path_cat_out(r->cur_subvol_path, r->dest_dir_path, path);
+ if (ret < 0) {
+ error("snapshot: path invalid: %s", path);
+ goto out;
+ }
+ }
+ ret = path_cat3_out(r->full_subvol_path, r->root_path,
+ r->dest_dir_path, path);
+ if (ret < 0) {
+ error("snapshot: path invalid: %s", path);
+ goto out;
+ }
fprintf(stdout, "At snapshot %s\n", path);
}
if (!parent_subvol) {
ret = -ENOENT;
- fprintf(stderr, "ERROR: could not find parent subvolume\n");
+ error("cannot find parent subvolume");
goto out;
}
/* First make sure the parent subvol is actually in our path */
if (sub_len < root_len ||
strstr(parent_subvol->path, r->full_root_path) == NULL) {
- fprintf(stderr, "ERROR: parent subvol is not reachable"
- " from inside the root subvol.\n");
+ error(
+ "parent subvol is not reachable from inside the root subvol");
ret = -ENOENT;
goto out;
}
}
}*/
- if (strlen(parent_subvol->path) == 0)
+ if (*parent_subvol->path == 0)
args_v2.fd = dup(r->mnt_fd);
else
args_v2.fd = openat(r->mnt_fd, parent_subvol->path,
if (args_v2.fd < 0) {
ret = -errno;
if (errno != ENOENT)
- fprintf(stderr, "ERROR: open %s failed. %s\n",
+ error("cannot open %s: %s",
parent_subvol->path, strerror(-ret));
else
fprintf(stderr,
close(args_v2.fd);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: creating snapshot %s -> %s "
- "failed. %s\n", parent_subvol->path,
- path, strerror(-ret));
+ error("creating snapshot %s -> %s failed: %s",
+ parent_subvol->path, path, strerror(-ret));
goto out;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("mkfile: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mkfile %s\n", path);
ret = creat(full_path, 0600);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: mkfile %s failed. %s\n", path,
- strerror(-ret));
+ error("mkfile %s failed: %s", path, strerror(-ret));
goto out;
}
close(ret);
ret = 0;
out:
- free(full_path);
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("mkdir: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mkdir %s\n", path);
ret = mkdir(full_path, 0700);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: mkdir %s failed. %s\n", path,
- strerror(-ret));
+ error("mkdir %s failed: %s", path, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("mknod: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mknod %s mode=%llu, dev=%llu\n",
ret = mknod(full_path, mode & S_IFMT, dev);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
- strerror(-ret));
+ error("mknod %s failed: %s", path, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("mkfifo: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mkfifo %s\n", path);
ret = mkfifo(full_path, 0600);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: mkfifo %s failed. %s\n", path,
- strerror(-ret));
+ error("mkfifo %s failed: %s", path, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("mksock: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "mksock %s\n", path);
ret = mknod(full_path, 0600 | S_IFSOCK, 0);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: mknod %s failed. %s\n", path,
- strerror(-ret));
+ error("mknod %s failed: %s", path, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("symlink: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "symlink %s -> %s\n", path, lnk);
ret = symlink(lnk, full_path);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: symlink %s -> %s failed. %s\n", path,
+ error("symlink %s -> %s failed: %s", path,
lnk, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_from = path_cat(r->full_subvol_path, from);
- char *full_to = path_cat(r->full_subvol_path, to);
+ char full_from[PATH_MAX];
+ char full_to[PATH_MAX];
+
+ ret = path_cat_out(full_from, r->full_subvol_path, from);
+ if (ret < 0) {
+ error("rename: source path invalid: %s", from);
+ goto out;
+ }
+
+ ret = path_cat_out(full_to, r->full_subvol_path, to);
+ if (ret < 0) {
+ error("rename: target path invalid: %s", to);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "rename %s -> %s\n", from, to);
ret = rename(full_from, full_to);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: rename %s -> %s failed. %s\n", from,
+ error("rename %s -> %s failed: %s", from,
to, strerror(-ret));
}
- free(full_from);
- free(full_to);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
- char *full_link_path = path_cat(r->full_subvol_path, lnk);
+ char full_path[PATH_MAX];
+ char full_link_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("link: source path invalid: %s", full_path);
+ goto out;
+ }
+
+ ret = path_cat_out(full_link_path, r->full_subvol_path, lnk);
+ if (ret < 0) {
+ error("link: target path invalid: %s", full_link_path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "link %s -> %s\n", path, lnk);
ret = link(full_link_path, full_path);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: link %s -> %s failed. %s\n", path,
- lnk, strerror(-ret));
+ error("link %s -> %s failed: %s", path, lnk, strerror(-ret));
}
- free(full_path);
- free(full_link_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("unlink: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "unlink %s\n", path);
ret = unlink(full_path);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: unlink %s failed. %s\n", path,
- strerror(-ret));
+ error("unlink %s failed. %s", path, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
{
int ret;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("rmdir: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "rmdir %s\n", path);
ret = rmdir(full_path);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: rmdir %s failed. %s\n", path,
- strerror(-ret));
+ error("rmdir %s failed: %s", path, strerror(-ret));
}
- free(full_path);
+out:
return ret;
}
-
static int open_inode_for_write(struct btrfs_receive *r, const char *path)
{
int ret = 0;
r->write_fd = open(path, O_RDWR);
if (r->write_fd < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: open %s failed. %s\n", path,
- strerror(-ret));
+ error("cannot open %s: %s", path, strerror(-ret));
goto out;
}
- free(r->write_path);
- r->write_path = strdup(path);
+ strncpy_null(r->write_path, path);
out:
return ret;
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
u64 pos = 0;
int w;
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("write: path invalid: %s", path);
+ goto out;
+ }
+
ret = open_inode_for_write(r, full_path);
if (ret < 0)
goto out;
offset + pos);
if (w < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: writing to %s failed. %s\n",
+ error("writing to %s failed: %s\n",
path, strerror(-ret));
goto out;
}
}
out:
- free(full_path);
return ret;
}
struct btrfs_receive *r = user;
struct btrfs_ioctl_clone_range_args clone_args;
struct subvol_info *si = NULL;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
char *subvol_path = NULL;
- char *full_clone_path = NULL;
+ char full_clone_path[PATH_MAX];
int clone_fd = -1;
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("clone: source path invalid: %s", path);
+ goto out;
+ }
+
ret = open_inode_for_write(r, full_path);
if (ret < 0)
goto out;
if (memcmp(clone_uuid, r->cur_subvol.received_uuid,
BTRFS_UUID_SIZE) == 0) {
/* TODO check generation of extent */
- subvol_path = strdup(r->cur_subvol.path);
+ subvol_path = strdup(r->cur_subvol_path);
} else {
ret = -ENOENT;
- fprintf(stderr, "ERROR: did not find source subvol.\n");
+ error("clone: did not find source subvol");
goto out;
}
} else {
subvol_path = strdup(si->path);
}
- full_clone_path = path_cat(subvol_path, clone_path);
+ ret = path_cat_out(full_clone_path, subvol_path, clone_path);
+ if (ret < 0) {
+ error("clone: target path invalid: %s", clone_path);
+ goto out;
+ }
clone_fd = openat(r->mnt_fd, full_clone_path, O_RDONLY | O_NOATIME);
if (clone_fd < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: failed to open %s. %s\n",
- full_clone_path, strerror(-ret));
+ error("cannot open %s: %s", full_clone_path, strerror(-ret));
goto out;
}
clone_args.src_length = len;
clone_args.dest_offset = offset;
ret = ioctl(r->write_fd, BTRFS_IOC_CLONE_RANGE, &clone_args);
- if (ret) {
+ if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: failed to clone extents to %s\n%s\n",
+ error("failed to clone extents to %s\n%s\n",
path, strerror(-ret));
goto out;
}
free(si->path);
free(si);
}
- free(full_path);
- free(full_clone_path);
free(subvol_path);
if (clone_fd != -1)
close(clone_fd);
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("set_xattr: path invalid: %s", path);
+ goto out;
+ }
if (strcmp("security.capability", name) == 0) {
if (g_verbose >= 3)
fprintf(stderr, "set_xattr: cache capabilities\n");
if (r->cached_capabilities_len)
- fprintf(stderr,
- "WARNING: capabilities set multiple times per file: %s\n",
+ warning("capabilities set multiple times per file: %s",
full_path);
if (len > sizeof(r->cached_capabilities)) {
- fprintf(stderr,
- "ERROR: capabilities encoded to %d bytes, buffer too small\n",
+ error("capabilities encoded to %d bytes, buffer too small",
len);
ret = -E2BIG;
goto out;
ret = lsetxattr(full_path, name, data, len, 0);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: lsetxattr %s %s=%.*s failed. %s\n",
+ error("lsetxattr %s %s=%.*s failed: %s",
path, name, len, (char*)data, strerror(-ret));
goto out;
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("remove_xattr: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2) {
fprintf(stderr, "remove_xattr %s - name=%s\n",
ret = lremovexattr(full_path, name);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: lremovexattr %s %s failed. %s\n",
+ error("lremovexattr %s %s failed: %s",
path, name, strerror(-ret));
goto out;
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("truncate: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "truncate %s size=%llu\n", path, size);
ret = truncate(full_path, size);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: truncate %s failed. %s\n",
- path, strerror(-ret));
+ error("truncate %s failed: %s", path, strerror(-ret));
goto out;
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("chmod: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "chmod %s - mode=0%o\n", path, (int)mode);
ret = chmod(full_path, mode);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: chmod %s failed. %s\n",
- path, strerror(-ret));
+ error("chmod %s failed: %s", path, strerror(-ret));
goto out;
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
+
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("chown: path invalid: %s", path);
+ goto out;
+ }
if (g_verbose >= 2)
fprintf(stderr, "chown %s - uid=%llu, gid=%llu\n", path,
ret = lchown(full_path, uid, gid);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: chown %s failed. %s\n",
- path, strerror(-ret));
+ error("chown %s failed: %s", path, strerror(-ret));
goto out;
}
r->cached_capabilities_len = 0;
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: restoring capabilities %s: %s\n",
+ error("restoring capabilities %s: %s",
path, strerror(-ret));
goto out;
}
}
out:
- free(full_path);
return ret;
}
{
int ret = 0;
struct btrfs_receive *r = user;
- char *full_path = path_cat(r->full_subvol_path, path);
+ char full_path[PATH_MAX];
struct timespec tv[2];
+ ret = path_cat_out(full_path, r->full_subvol_path, path);
+ if (ret < 0) {
+ error("utimes: path invalid: %s", path);
+ goto out;
+ }
+
if (g_verbose >= 2)
fprintf(stderr, "utimes %s\n", path);
ret = utimensat(AT_FDCWD, full_path, tv, AT_SYMLINK_NOFOLLOW);
if (ret < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: utimes %s failed. %s\n",
+ error("utimes %s failed: %s",
path, strerror(-ret));
goto out;
}
out:
- free(full_path);
return ret;
}
u64 subvol_id;
int ret;
char *dest_dir_full_path;
- char *root_subvol_path;
+ char root_subvol_path[PATH_MAX];
int end = 0;
dest_dir_full_path = realpath(tomnt, NULL);
if (!dest_dir_full_path) {
ret = -errno;
- fprintf(stderr, "ERROR: realpath(%s) failed. %s\n", tomnt,
- strerror(-ret));
+ error("realpath(%s) failed: %s", tomnt, strerror(-ret));
goto out;
}
r->dest_dir_fd = open(dest_dir_full_path, O_RDONLY | O_NOATIME);
if (r->dest_dir_fd < 0) {
ret = -errno;
- fprintf(stderr,
- "ERROR: failed to open destination directory %s. %s\n",
+ error("cannot open destination directory %s: %s",
dest_dir_full_path, strerror(-ret));
goto out;
}
- if (realmnt) {
+ if (realmnt[0]) {
r->root_path = realmnt;
} else {
ret = find_mount_root(dest_dir_full_path, &r->root_path);
if (ret < 0) {
- fprintf(stderr,
- "ERROR: failed to determine mount point for %s: %s\n",
+ error("failed to determine mount point for %s: %s",
dest_dir_full_path, strerror(-ret));
ret = -EINVAL;
goto out;
}
if (ret > 0) {
- fprintf(stderr,
- "ERROR: %s doesn't belong to btrfs mount point\n",
- dest_dir_full_path);
+ error("%s doesn't belong to btrfs mount point",
+ dest_dir_full_path);
ret = -EINVAL;
goto out;
}
r->mnt_fd = open(r->root_path, O_RDONLY | O_NOATIME);
if (r->mnt_fd < 0) {
ret = -errno;
- fprintf(stderr, "ERROR: failed to open %s. %s\n", r->root_path,
- strerror(-ret));
+ error("cannot open %s: %s", r->root_path, strerror(-ret));
goto out;
}
* subvols we want to receive in.
*/
ret = btrfs_list_get_path_rootid(r->mnt_fd, &subvol_id);
- if (ret) {
- fprintf(stderr, "ERROR: couldn't resolve our subvolid %d\n",
- ret);
- goto out;
- }
-
- root_subvol_path = malloc(PATH_MAX);
- if (!root_subvol_path) {
- ret = -ENOMEM;
- fprintf(stderr, "ERROR: couldn't allocate buffer for the root "
- "subvol path\n");
+ if (ret)
goto out;
- }
+ root_subvol_path[0] = 0;
ret = btrfs_subvolid_resolve(r->mnt_fd, root_subvol_path,
PATH_MAX, subvol_id);
if (ret) {
- fprintf(stderr, "ERROR: couldn't resolve our subvol path\n");
+ error("cannot resolve our subvol path");
goto out;
}
* Ok we're inside of a subvol off of the root subvol, we need to
* actually set full_root_path.
*/
- if (strlen(root_subvol_path))
+ if (*root_subvol_path)
r->full_root_path = root_subvol_path;
- else
- free(root_subvol_path);
if (r->dest_dir_chroot) {
if (chroot(dest_dir_full_path)) {
ret = -errno;
- fprintf(stderr,
- "ERROR: failed to chroot to %s, %s\n",
- dest_dir_full_path,
- strerror(-ret));
+ error("failed to chroot to %s: %s",
+ dest_dir_full_path, strerror(-ret));
goto out;
}
if (chdir("/")) {
ret = -errno;
- fprintf(stderr,
- "ERROR: failed to chdir to /, %s\n",
+ error("failed to chdir to / after chroot: %s",
strerror(-ret));
goto out;
}
close(r->write_fd);
r->write_fd = -1;
}
- free(r->root_path);
+
+ if (r->root_path != realmnt)
+ free(r->root_path);
r->root_path = NULL;
- free(r->write_path);
- r->write_path = NULL;
- free(r->full_subvol_path);
- r->full_subvol_path = NULL;
r->dest_dir_path = NULL;
free(dest_dir_full_path);
- if (r->cur_subvol.path) {
- free(r->cur_subvol.path);
- r->cur_subvol.path = NULL;
- }
subvol_uuid_search_finit(&r->sus);
if (r->mnt_fd != -1) {
close(r->mnt_fd);
close(r->dest_dir_fd);
r->dest_dir_fd = -1;
}
- if (r->full_root_path) {
- free(r->full_root_path);
- r->full_root_path = NULL;
- }
+
return ret;
}
int cmd_receive(int argc, char **argv)
{
char *tomnt = NULL;
- char *fromfile = NULL;
- char *realmnt = NULL;
+ char fromfile[PATH_MAX];
+ char realmnt[PATH_MAX];
struct btrfs_receive r;
int receive_fd = fileno(stdin);
u64 max_errors = 1;
r.write_fd = -1;
r.dest_dir_fd = -1;
r.dest_dir_chroot = 0;
+ realmnt[0] = 0;
+ fromfile[0] = 0;
while (1) {
int c;
g_verbose++;
break;
case 'f':
- fromfile = optarg;
+ if (arg_copy_path(fromfile, optarg, sizeof(fromfile))) {
+ error("input file path too long (%zu)",
+ strlen(optarg));
+ ret = 1;
+ goto out;
+ }
break;
case 'e':
r.honor_end_cmd = 1;
max_errors = arg_strtou64(optarg);
break;
case 'm':
- free(realmnt);
- realmnt = strdup(optarg);
- if (!realmnt) {
- fprintf(stderr, "ERROR: couldn't allocate realmnt.\n");
+ if (arg_copy_path(realmnt, optarg, sizeof(realmnt))) {
+ error("mount point path too long (%zu)",
+ strlen(optarg));
+ ret = 1;
goto out;
}
break;
case '?':
default:
- fprintf(stderr, "ERROR: receive args invalid.\n");
+ error("receive args invalid");
return 1;
}
}
tomnt = argv[optind];
- if (fromfile) {
+ if (fromfile[0]) {
receive_fd = open(fromfile, O_RDONLY | O_NOATIME);
if (receive_fd < 0) {
- fprintf(stderr, "ERROR: failed to open %s\n", fromfile);
+ error("cannot open %s: %s", fromfile, strerror(errno));
goto out;
}
}
ret = do_receive(&r, tomnt, realmnt, receive_fd, max_errors);
+ if (receive_fd != fileno(stdin))
+ close(receive_fd);
out:
- free(realmnt);
return !!ret;
}