diff options
Diffstat (limited to 'cmds-send.c')
-rw-r--r-- | cmds-send.c | 110 |
1 files changed, 58 insertions, 52 deletions
diff --git a/cmds-send.c b/cmds-send.c index ac1d3cf6..69e9bcea 100644 --- a/cmds-send.c +++ b/cmds-send.c @@ -152,7 +152,7 @@ static int find_good_parent(struct btrfs_send *s, u64 root_id, u64 *found) if (tmp < 0) tmp *= -1; if (tmp < best_diff) { - best_parent = parent; + best_parent = parent2; best_diff = tmp; } } @@ -236,7 +236,7 @@ out: return ERR_PTR(ret); } -static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root) +static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root_id) { int ret; pthread_t t_read; @@ -273,6 +273,7 @@ static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root) goto out; } + memset(&io_send, 0, sizeof(io_send)); io_send.send_fd = pipefd[1]; send->send_fd = pipefd[0]; @@ -288,7 +289,7 @@ static int do_send(struct btrfs_send *send, u64 root_id, u64 parent_root) io_send.clone_sources = (__u64*)send->clone_sources; io_send.clone_sources_count = send->clone_sources_count; - io_send.parent_root = parent_root; + io_send.parent_root = parent_root_id; ret = ioctl(subvol_fd, BTRFS_IOC_SEND, &io_send); if (ret) { ret = -errno; @@ -333,12 +334,12 @@ out: return ret; } -static const char *get_subvol_name(struct btrfs_send *s, const char *full_path) +char *get_subvol_name(char *mnt, char *full_path) { - int len = strlen(s->root_path); + int len = strlen(mnt); if (!len) return full_path; - if (s->root_path[len - 1] != '/') + if (mnt[len - 1] != '/') len += 1; return full_path + len; @@ -425,21 +426,17 @@ int cmd_send_start(int argc, char **argv) char *snapshot_parent = NULL; u64 root_id; u64 parent_root_id = 0; + int full_send = 1; memset(&send, 0, sizeof(send)); send.dump_fd = fileno(stdout); - if (isatty(send.dump_fd)) { - fprintf(stderr, "ERROR: not dumping send stream into a terminal, redirect it into a file\n"); - return 1; - } - - while ((c = getopt(argc, argv, "vf:i:p:")) != -1) { + while ((c = getopt(argc, argv, "vc:f:i:p:")) != -1) { switch (c) { case 'v': g_verbose++; break; - case 'i': { + case 'c': subvol = realpath(optarg, NULL); if (!subvol) { ret = -errno; @@ -452,7 +449,7 @@ int cmd_send_start(int argc, char **argv) if (ret < 0) goto out; - ret = get_root_id(&send, get_subvol_name(&send, subvol), + ret = get_root_id(&send, get_subvol_name(send.root_path, subvol), &root_id); if (ret < 0) { fprintf(stderr, "ERROR: could not resolve " @@ -461,12 +458,16 @@ int cmd_send_start(int argc, char **argv) } add_clone_source(&send, root_id); free(subvol); + full_send = 0; break; - } case 'f': outname = optarg; break; case 'p': + if (snapshot_parent) { + fprintf(stderr, "ERROR: you cannot have more than one parent (-p)\n"); + return 1; + } snapshot_parent = realpath(optarg, NULL); if (!snapshot_parent) { ret = -errno; @@ -474,7 +475,12 @@ int cmd_send_start(int argc, char **argv) "%s\n", optarg, strerror(-ret)); goto out; } + full_send = 0; break; + case 'i': + fprintf(stderr, + "ERROR: -i was removed, use -c instead\n"); + return 1; case '?': default: fprintf(stderr, "ERROR: send args invalid.\n"); @@ -497,6 +503,13 @@ int cmd_send_start(int argc, char **argv) } } + if (isatty(send.dump_fd)) { + fprintf(stderr, + "ERROR: not dumping send stream into a terminal, " + "redirect it into a file\n"); + return 1; + } + /* use first send subvol to determine mount_root */ subvol = argv[optind]; @@ -513,7 +526,7 @@ int cmd_send_start(int argc, char **argv) if (snapshot_parent != NULL) { ret = get_root_id(&send, - get_subvol_name(&send, snapshot_parent), + get_subvol_name(send.root_path, snapshot_parent), &parent_root_id); if (ret < 0) { fprintf(stderr, "ERROR: could not resolve root_id " @@ -572,7 +585,7 @@ int cmd_send_start(int argc, char **argv) goto out; } - ret = get_root_id(&send, get_subvol_name(&send, subvol), + ret = get_root_id(&send, get_subvol_name(send.root_path, subvol), &root_id); if (ret < 0) { fprintf(stderr, "ERROR: could not resolve root_id " @@ -580,10 +593,13 @@ int cmd_send_start(int argc, char **argv) goto out; } - if (!parent_root_id) { + if (!full_send && !parent_root_id) { ret = find_good_parent(&send, root_id, &parent_root_id); - if (ret < 0) - parent_root_id = 0; + if (ret < 0) { + fprintf(stderr, "ERROR: parent determination failed for %lld\n", + root_id); + goto out; + } } ret = is_subvol_ro(&send, subvol); @@ -604,6 +620,7 @@ int cmd_send_start(int argc, char **argv) add_clone_source(&send, root_id); parent_root_id = 0; + full_send = 0; free(subvol); } @@ -620,43 +637,32 @@ static const char * const send_cmd_group_usage[] = { NULL }; -static const char * const cmd_send_usage[] = { - "btrfs send [-v] [-i <subvol>] [-p <parent>] <subvol>", +const char * const cmd_send_usage[] = { + "btrfs send [-v] [-p <parent>] [-c <clone-src>] <subvol>", "Send the subvolume to stdout.", "Sends the subvolume specified by <subvol> to stdout.", - "By default, this will send the whole subvolume. To do", - "an incremental send, one or multiple '-i <clone_source>'", - "arguments have to be specified. A 'clone source' is", - "a subvolume that is known to exist on the receiving", - "side in exactly the same state as on the sending side.\n", - "Normally, a good snapshot parent is searched automatically", - "in the list of 'clone sources'. To override this, use", - "'-p <parent>' to manually specify a snapshot parent.", - "A manually specified snapshot parent is also regarded", - "as 'clone source'.\n", - "-v Enable verbose debug output. Each", - " occurrency of this option increases the", - " verbose level more.", - "-i <subvol> Informs btrfs send that this subvolume,", - " can be taken as 'clone source'. This can", - " be used for incremental sends.", - "-p <subvol> Disable automatic snaphot parent", - " determination and use <subvol> as parent.", - " This subvolume is also added to the list", - " of 'clone sources' (see -i).", - "-f <outfile> Output is normally written to stdout.", - " To write to a file, use this option.", - " An alternative would be to use pipes.", + "By default, this will send the whole subvolume. To do an incremental", + "send, use '-p <parent>'. If you want to allow btrfs to clone from", + "any additional local snapshots, use -c <clone-src> (multiple times", + "where applicable). You must not specify clone sources unless you", + "guarantee that these snapshots are exactly in the same state on both", + "sides, the sender and the receiver. It is allowed to omit the", + "'-p <parent>' option when '-c <clone-src>' options are given, in", + "which case 'btrfs send' will determine a suitable parent among the", + "clone sources itself.", + "\n", + "-v Enable verbose debug output. Each occurrence of", + " this option increases the verbose level more.", + "-p <parent> Send an incremental stream from <parent> to", + " <subvol>.", + "-c <clone-src> Use this snapshot as a clone source for an ", + " incremental send (multiple allowed)", + "-f <outfile> Output is normally written to stdout. To write to", + " a file, use this option. An alternative would be to", + " use pipes.", NULL }; -const struct cmd_group send_cmd_group = { - send_cmd_group_usage, NULL, { - { "send", cmd_send_start, cmd_send_usage, NULL, 0 }, - { 0, 0, 0, 0, 0 }, - }, -}; - int cmd_send(int argc, char **argv) { return cmd_send_start(argc, argv); |