Btrfs-progs: correcting misnamed parameter options for btrfs send
[platform/upstream/btrfs-progs.git] / cmds-send.c
index 8a0c110..d2f7691 100644 (file)
@@ -18,6 +18,8 @@
 
 #define _GNU_SOURCE
 
+#include "kerncompat.h"
+
 #include <unistd.h>
 #include <stdint.h>
 #include <dirent.h>
@@ -28,6 +30,7 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <libgen.h>
+#include <mntent.h>
 
 #include <uuid/uuid.h>
 
@@ -55,82 +58,35 @@ struct btrfs_send {
 
 int find_mount_root(const char *path, char **mount_root)
 {
-       int ret;
-       char *cur;
-       char fsid[BTRFS_FSID_SIZE];
+       FILE *mnttab;
        int fd;
-       struct stat st;
-       char *tmp;
-       char *dup = NULL;
-
-       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;
-
-       cur = strdup(path);
 
-       while (1) {
-               dup = strdup(cur);
-               tmp = dirname(dup);
-
-               if (!tmp)
-                       break;
-               fd = open(tmp, O_RDONLY | O_NOATIME);
-               if (fd < 0) {
-                       ret = -errno;
-                       goto out;
+       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 = ioctl(fd, BTRFS_IOC_FS_INFO, &args);
-               close(fd);
-               fd = -1;
-               if (ret < 0)
-                       break;
-               if (memcmp(fsid, args.fsid, BTRFS_FSID_SIZE) != 0)
-                       break;
-
-               free(cur);
-               cur = strdup(tmp);
-               free(dup);
-               dup = NULL;
-               if (strcmp(cur, "/") == 0)
-                       break;
-               if (strcmp(cur, ".") == 0)
-                       break;
        }
 
-       ret = 0;
-       *mount_root = realpath(cur, NULL);
+       *mount_root = realpath(longest_match, NULL);
+       free(longest_match);
 
-out:
-       if (dup)
-               free(dup);
-       if (fd != -1)
-               close(fd);
-       return ret;
+       return 0;
 }
 
 static int get_root_id(struct btrfs_send *s, const char *path, u64 *root_id)
@@ -280,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;
@@ -317,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];
 
@@ -332,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;
@@ -460,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;
@@ -469,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;
@@ -500,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;
@@ -513,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");
@@ -541,6 +513,7 @@ int cmd_send_start(int argc, char **argv)
 
        subvol = realpath(argv[optind], NULL);
        if (!subvol) {
+               ret = -errno;
                fprintf(stderr, "ERROR: unable to resolve %s\n", argv[optind]);
                goto out;
        }
@@ -565,6 +538,7 @@ int cmd_send_start(int argc, char **argv)
        for (i = optind; i < argc; i++) {
                subvol = realpath(argv[i], NULL);
                if (!subvol) {
+                       ret = -errno;
                        fprintf(stderr, "ERROR: unable to resolve %s\n", argv[i]);
                        goto out;
                }
@@ -617,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);
@@ -641,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);
        }
 
@@ -658,32 +636,28 @@ static const char * const send_cmd_group_usage[] = {
 };
 
 static const char * const cmd_send_usage[] = {
-       "btrfs send [-v] [-i <subvol>] [-p <parent>] <subvol>",
+       "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 occurrency 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
 };