X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=cmds-send.c;h=d2f76914d95dbe7135fda8fd9d5894e093ab0fc5;hb=cc088694ff51c715793c974fffa110bb44451a5e;hp=aba25b114f2f84c05d1b9edb539714a6b34efc3a;hpb=f1c24cd80dfd037407cdee85181646adca6dd5bb;p=platform%2Fupstream%2Fbtrfs-progs.git diff --git a/cmds-send.c b/cmds-send.c index aba25b1..d2f7691 100644 --- a/cmds-send.c +++ b/cmds-send.c @@ -18,6 +18,8 @@ #define _GNU_SOURCE +#include "kerncompat.h" + #include #include #include @@ -27,6 +29,8 @@ #include #include #include +#include +#include #include @@ -54,77 +58,35 @@ struct btrfs_send { int find_mount_root(const char *path, char **mount_root) { - int ret; - char cur[BTRFS_PATH_NAME_MAX]; - char fsid[BTRFS_FSID_SIZE]; + FILE *mnttab; int fd; - struct stat st; - int pos; - char *tmp; - - struct btrfs_ioctl_fs_info_args args; + struct mntent *ent; + int len; + int longest_matchlen = 0; + char *longest_match = NULL; fd = open(path, O_RDONLY | O_NOATIME); - if (fd < 0) { - ret = -errno; - goto out; - } - - ret = fstat(fd, &st); - if (fd < 0) { - ret = -errno; - goto out; - } - if (!S_ISDIR(st.st_mode)) { - ret = -ENOTDIR; - goto out; - } - - ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args); - if (fd < 0) { - ret = -errno; - goto out; - } - memcpy(fsid, args.fsid, BTRFS_FSID_SIZE); + if (fd < 0) + return -errno; close(fd); - fd = -1; - - strcpy(cur, path); - while (1) { - tmp = strrchr(cur, '/'); - if (!tmp) - break; - if (tmp == cur) - break; - pos = tmp - cur; - cur[pos] = 0; - fd = open(cur, O_RDONLY | O_NOATIME); - if (fd < 0) { - ret = -errno; - goto out; - } - - ret = ioctl(fd, BTRFS_IOC_FS_INFO, &args); - close(fd); - fd = -1; - if (ret < 0) { - cur[pos] = '/'; - break; - } - if (memcmp(fsid, args.fsid, BTRFS_FSID_SIZE) != 0) { - cur[pos] = '/'; - break; + mnttab = fopen("/etc/mtab", "r"); + while ((ent = getmntent(mnttab))) { + len = strlen(ent->mnt_dir); + if (strncmp(ent->mnt_dir, path, len) == 0) { + /* match found */ + if (longest_matchlen < len) { + free(longest_match); + longest_matchlen = len; + longest_match = strdup(ent->mnt_dir); + } } } - ret = 0; - *mount_root = realpath(cur, NULL); + *mount_root = realpath(longest_match, NULL); + free(longest_match); -out: - if (fd != -1) - close(fd); - return ret; + return 0; } static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id) @@ -274,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; @@ -311,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]; @@ -326,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; @@ -373,7 +336,13 @@ out: static const char *get_subvol_name(struct btrfs_send *s, const char *full_path) { - return full_path + strlen(s->root_path) + 1; + int len = strlen(s->root_path); + if (!len) + return full_path; + if (s->root_path[len - 1] != '/') + len += 1; + + return full_path + len; } static int init_root_path(struct btrfs_send *s, const char *subvol) @@ -448,7 +417,7 @@ out: int cmd_send_start(int argc, char **argv) { char *subvol = NULL; - char c; + int c; int ret; char *outname = NULL; struct btrfs_send send; @@ -457,16 +426,22 @@ 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); - while ((c = getopt(argc, argv, "vf:i:p:")) != -1) { + 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, "vc:f:i:p:")) != -1) { switch (c) { case 'v': g_verbose++; break; - case 'i': { + case 'c': subvol = realpath(optarg, NULL); if (!subvol) { ret = -errno; @@ -488,12 +463,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; @@ -501,7 +480,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"); @@ -527,6 +511,13 @@ int cmd_send_start(int argc, char **argv) /* use first send subvol to determine mount_root */ subvol = argv[optind]; + subvol = realpath(argv[optind], NULL); + if (!subvol) { + ret = -errno; + fprintf(stderr, "ERROR: unable to resolve %s\n", argv[optind]); + goto out; + } + ret = init_root_path(&send, subvol); if (ret < 0) goto out; @@ -545,7 +536,12 @@ int cmd_send_start(int argc, char **argv) } for (i = optind; i < argc; i++) { - subvol = argv[i]; + subvol = realpath(argv[i], NULL); + if (!subvol) { + ret = -errno; + fprintf(stderr, "ERROR: unable to resolve %s\n", argv[i]); + goto out; + } ret = find_mount_root(subvol, &mount_root); if (ret < 0) { @@ -571,6 +567,7 @@ int cmd_send_start(int argc, char **argv) subvol); goto out; } + free(subvol); } for (i = optind; i < argc; i++) { @@ -594,10 +591,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); @@ -618,6 +618,7 @@ int cmd_send_start(int argc, char **argv) add_clone_source(&send, root_id); parent_root_id = 0; + full_send = 0; free(subvol); } @@ -635,32 +636,28 @@ static const char * const send_cmd_group_usage[] = { }; static const char * const cmd_send_usage[] = { - "btrfs send [-v] [-i ] [-p ] ", + "btrfs send [-v] [-p ] [-c ] ", "Send the subvolume to stdout.", "Sends the subvolume specified by to stdout.", - "By default, this will send the whole subvolume. To do", - "an incremental send, one or multiple '-i '", - "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 ' 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 Informs btrfs send that this subvolume,", - " can be taken as 'clone source'. This can", - " be used for incremental sends.", - "-p Disable automatic snaphot parent", - " determination and use as parent.", - " This subvolume is also added to the list", - " of 'clone sources' (see -i).", - "-f 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 '. If you want to allow btrfs to clone from", + "any additional local snapshots, use -c (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 ' option when '-c ' 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 occurrency of", + " this option increases the verbose level more.", + "-p Send an incremental stream from to", + " .", + "-c Use this snapshot as a clone source for an ", + " incremental send (multiple allowed)", + "-f Output is normally written to stdout. To write to", + " a file, use this option. An alternative would be to", + " use pipes.", NULL };