Btrfs-progs: fix closing of opendir()
[platform/upstream/btrfs-progs.git] / cmds-subvolume.c
index a9999ac..6c6a698 100644 (file)
@@ -61,20 +61,25 @@ static int test_isdir(char *path)
 }
 
 static const char * const cmd_subvol_create_usage[] = {
-       "btrfs subvolume create [<dest>/]<name>",
+       "btrfs subvolume create [-i <qgroupid>] [<dest>/]<name>",
        "Create a subvolume",
        "Create a subvolume <name> in <dest>.  If <dest> is not given",
        "subvolume <name> will be created in the current directory.",
+       "",
+       "-i <qgroupid>  add the newly created subvolume to a qgroup. This",
+       "               option can be given multiple times.",
        NULL
 };
 
 static int cmd_subvol_create(int argc, char **argv)
 {
-       int     res, fddst, len, e;
+       int     retval, res, len;
+       int     fddst = -1;
        char    *newname;
        char    *dstdir;
        char    *dst;
        struct btrfs_qgroup_inherit *inherit = NULL;
+       DIR     *dirstream = NULL;
 
        optind = 1;
        while (1) {
@@ -85,13 +90,17 @@ static int cmd_subvol_create(int argc, char **argv)
                switch (c) {
                case 'c':
                        res = qgroup_inherit_add_copy(&inherit, optarg, 0);
-                       if (res)
-                               return res;
+                       if (res) {
+                               retval = res;
+                               goto out;
+                       }
                        break;
                case 'i':
                        res = qgroup_inherit_add_group(&inherit, optarg);
-                       if (res)
-                               return res;
+                       if (res) {
+                               retval = res;
+                               goto out;
+                       }
                        break;
                default:
                        usage(cmd_subvol_create_usage);
@@ -103,10 +112,11 @@ static int cmd_subvol_create(int argc, char **argv)
 
        dst = argv[optind];
 
+       retval = 1;     /* failure */
        res = test_isdir(dst);
        if (res >= 0) {
                fprintf(stderr, "ERROR: '%s' exists\n", dst);
-               return 1;
+               goto out;
        }
 
        newname = strdup(dst);
@@ -118,20 +128,20 @@ static int cmd_subvol_create(int argc, char **argv)
             strchr(newname, '/') ){
                fprintf(stderr, "ERROR: uncorrect subvolume name ('%s')\n",
                        newname);
-               return 1;
+               goto out;
        }
 
        len = strlen(newname);
        if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
                fprintf(stderr, "ERROR: subvolume name too long ('%s)\n",
                        newname);
-               return 1;
+               goto out;
        }
 
-       fddst = open_file_or_dir(dstdir);
+       fddst = open_file_or_dir(dstdir, &dirstream);
        if (fddst < 0) {
                fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
-               return 1;
+               goto out;
        }
 
        printf("Create subvolume '%s/%s'\n", dstdir, newname);
@@ -154,18 +164,18 @@ static int cmd_subvol_create(int argc, char **argv)
                res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
        }
 
-       e = errno;
-
-       close(fddst);
-       free(inherit);
-
        if (res < 0) {
                fprintf(stderr, "ERROR: cannot create subvolume - %s\n",
-                       strerror(e));
-               return 1;
+                       strerror(errno));
+               goto out;
        }
 
-       return 0;
+       retval = 0;     /* success */
+out:
+       close_file_or_dir(fddst, dirstream);
+       free(inherit);
+
+       return retval;
 }
 
 /*
@@ -199,6 +209,7 @@ static int cmd_subvol_delete(int argc, char **argv)
        struct btrfs_ioctl_vol_args     args;
        char    *dname, *vname, *cpath;
        char    *path;
+       DIR     *dirstream = NULL;
 
        if (argc < 2)
                usage(cmd_subvol_delete_usage);
@@ -241,7 +252,7 @@ again:
                goto out;
        }
 
-       fd = open_file_or_dir(dname);
+       fd = open_file_or_dir(dname, &dirstream);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access to '%s'\n", dname);
                ret = 12;
@@ -253,7 +264,7 @@ again:
        res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
        e = errno;
 
-       close(fd);
+       close_file_or_dir(fd, dirstream);
 
        if(res < 0 ){
                fprintf( stderr, "ERROR: cannot delete '%s/%s' - %s\n",
@@ -322,6 +333,7 @@ static int cmd_subvol_list(int argc, char **argv)
                {"sort", 1, NULL, 'S'},
                {0, 0, 0, 0}
        };
+       DIR *dirstream = NULL;
 
        filter_set = btrfs_list_alloc_filter_set();
        comparer_set = btrfs_list_alloc_comparer_set();
@@ -414,19 +426,7 @@ static int cmd_subvol_list(int argc, char **argv)
        }
 
        subvol = argv[optind];
-
-       ret = test_issubvolume(subvol);
-       if (ret < 0) {
-               fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
-               goto out;
-       }
-       if (!ret) {
-               fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
-               ret = -1;
-               goto out;
-       }
-
-       fd = open_file_or_dir(subvol);
+       fd = open_file_or_dir(subvol, &dirstream);
        if (fd < 0) {
                ret = -1;
                fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
@@ -464,8 +464,7 @@ static int cmd_subvol_list(int argc, char **argv)
                                !is_list_all && !is_only_in_path, NULL);
 
 out:
-       if (fd != -1)
-               close(fd);
+       close_file_or_dir(fd, dirstream);
        if (filter_set)
                btrfs_list_free_filter_set(filter_set);
        if (comparer_set)
@@ -478,11 +477,14 @@ out:
 
 static const char * const cmd_snapshot_usage[] = {
        "btrfs subvolume snapshot [-r] <source> [<dest>/]<name>",
+       "btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> [<dest>/]<name>",
        "Create a snapshot of the subvolume",
        "Create a writable/readonly snapshot of the subvolume <source> with",
        "the name <name> in the <dest> directory",
        "",
-       "-r     create a readonly snapshot",
+       "-r             create a readonly snapshot",
+       "-i <qgroupid>  add the newly created snapshot to a qgroup. This",
+       "               option can be given multiple times.",
        NULL
 };
 
@@ -496,6 +498,7 @@ static int cmd_snapshot(int argc, char **argv)
        char    *dstdir;
        struct btrfs_ioctl_vol_args_v2  args;
        struct btrfs_qgroup_inherit *inherit = NULL;
+       DIR *dirstream1 = NULL, *dirstream2 = NULL;
 
        optind = 1;
        memset(&args, 0, sizeof(args));
@@ -507,21 +510,27 @@ static int cmd_snapshot(int argc, char **argv)
                switch (c) {
                case 'c':
                        res = qgroup_inherit_add_copy(&inherit, optarg, 0);
-                       if (res)
-                               return res;
+                       if (res) {
+                               retval = res;
+                               goto out;
+                       }
                        break;
                case 'i':
                        res = qgroup_inherit_add_group(&inherit, optarg);
-                       if (res)
-                               return res;
+                       if (res) {
+                               retval = res;
+                               goto out;
+                       }
                        break;
                case 'r':
                        readonly = 1;
                        break;
                case 'x':
                        res = qgroup_inherit_add_copy(&inherit, optarg, 1);
-                       if (res)
-                               return res;
+                       if (res) {
+                               retval = res;
+                               goto out;
+                       }
                        break;
                default:
                        usage(cmd_snapshot_usage);
@@ -576,13 +585,13 @@ static int cmd_snapshot(int argc, char **argv)
                goto out;
        }
 
-       fddst = open_file_or_dir(dstdir);
+       fddst = open_file_or_dir(dstdir, &dirstream1);
        if (fddst < 0) {
                fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
                goto out;
        }
 
-       fd = open_file_or_dir(subvol);
+       fd = open_file_or_dir(subvol, &dirstream2);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access to '%s'\n", dstdir);
                goto out;
@@ -616,10 +625,8 @@ static int cmd_snapshot(int argc, char **argv)
        retval = 0;     /* success */
 
 out:
-       if (fd != -1)
-               close(fd);
-       if (fddst != -1)
-               close(fddst);
+       close_file_or_dir(fddst, dirstream1);
+       close_file_or_dir(fd, dirstream2);
        free(inherit);
 
        return retval;
@@ -638,23 +645,13 @@ static int cmd_subvol_get_default(int argc, char **argv)
        char *subvol;
        struct btrfs_list_filter_set *filter_set;
        u64 default_id;
+       DIR *dirstream = NULL;
 
        if (check_argc_exact(argc, 2))
                usage(cmd_subvol_get_default_usage);
 
        subvol = argv[1];
-
-       ret = test_issubvolume(subvol);
-       if (ret < 0) {
-               fprintf(stderr, "ERROR: error accessing '%s'\n", subvol);
-               return 1;
-       }
-       if (!ret) {
-               fprintf(stderr, "ERROR: '%s' is not a subvolume\n", subvol);
-               return 1;
-       }
-
-       fd = open_file_or_dir(subvol);
+       fd = open_file_or_dir(subvol, &dirstream);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
                return 1;
@@ -695,8 +692,7 @@ static int cmd_subvol_get_default(int argc, char **argv)
        if (filter_set)
                btrfs_list_free_filter_set(filter_set);
 out:
-       if (fd != -1)
-               close(fd);
+       close_file_or_dir(fd, dirstream);
        if (ret)
                return 1;
        return 0;
@@ -714,6 +710,7 @@ static int cmd_subvol_set_default(int argc, char **argv)
        u64     objectid;
        char    *path;
        char    *subvolid;
+       DIR     *dirstream = NULL;
 
        if (check_argc_exact(argc, 3))
                usage(cmd_subvol_set_default_usage);
@@ -727,7 +724,7 @@ static int cmd_subvol_set_default(int argc, char **argv)
                return 1;
        }
 
-       fd = open_file_or_dir(path);
+       fd = open_file_or_dir(path, &dirstream);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access to '%s'\n", path);
                return 1;
@@ -735,7 +732,7 @@ static int cmd_subvol_set_default(int argc, char **argv)
 
        ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
        e = errno;
-       close(fd);
+       close_file_or_dir(fd, dirstream);
        if (ret < 0) {
                fprintf(stderr, "ERROR: unable to set a new default subvolume - %s\n",
                        strerror(e));
@@ -756,6 +753,7 @@ static int cmd_find_new(int argc, char **argv)
        int ret;
        char *subvol;
        u64 last_gen;
+       DIR *dirstream = NULL;
 
        if (check_argc_exact(argc, 3))
                usage(cmd_find_new_usage);
@@ -773,13 +771,13 @@ static int cmd_find_new(int argc, char **argv)
                return 13;
        }
 
-       fd = open_file_or_dir(subvol);
+       fd = open_file_or_dir(subvol, &dirstream);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access '%s'\n", subvol);
                return 12;
        }
        ret = btrfs_list_find_updated_files(fd, 0, last_gen);
-       close(fd);
+       close_file_or_dir(fd, dirstream);
        if (ret)
                return 19;
        return 0;
@@ -802,6 +800,7 @@ static int cmd_subvol_show(int argc, char **argv)
        u64 sv_id, mntid;
        int fd = -1, mntfd = -1;
        int ret = -1;
+       DIR *dirstream1 = NULL, *dirstream2 = NULL;
 
        if (check_argc_exact(argc, 2))
                usage(cmd_subvol_show_usage);
@@ -833,7 +832,7 @@ static int cmd_subvol_show(int argc, char **argv)
        ret = -1;
        svpath = get_subvol_name(mnt, fullpath);
 
-       fd = open_file_or_dir(fullpath);
+       fd = open_file_or_dir(fullpath, &dirstream1);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
                goto out;
@@ -846,7 +845,7 @@ static int cmd_subvol_show(int argc, char **argv)
                goto out;
        }
 
-       mntfd = open_file_or_dir(mnt);
+       mntfd = open_file_or_dir(mnt, &dirstream2);
        if (mntfd < 0) {
                fprintf(stderr, "ERROR: can't access '%s'\n", mnt);
                goto out;
@@ -889,10 +888,12 @@ static int cmd_subvol_show(int argc, char **argv)
                uuid_unparse(get_ri.puuid, uuidparse);
        printf("\tParent uuid: \t\t%s\n", uuidparse);
 
-       if (get_ri.otime)
-               strftime(tstr, 256, "%Y-%m-%d %X",
-                        localtime(&get_ri.otime));
-       else
+       if (get_ri.otime) {
+               struct tm tm;
+
+               localtime_r(&get_ri.otime, &tm);
+               strftime(tstr, 256, "%Y-%m-%d %X", &tm);
+       } else
                strcpy(tstr, "-");
        printf("\tCreation time: \t\t%s\n", tstr);
 
@@ -911,7 +912,7 @@ static int cmd_subvol_show(int argc, char **argv)
        printf("\tSnapshot(s):\n");
        filter_set = btrfs_list_alloc_filter_set();
        btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
-                               (u64)get_ri.uuid);
+                               (u64)(unsigned long)get_ri.uuid);
        btrfs_list_setup_print_column(BTRFS_LIST_PATH);
        btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
                        1, raw_prefix);
@@ -927,10 +928,8 @@ static int cmd_subvol_show(int argc, char **argv)
                btrfs_list_free_filter_set(filter_set);
 
 out:
-       if (mntfd >= 0)
-               close(mntfd);
-       if (fd >= 0)
-               close(fd);
+       close_file_or_dir(fd, dirstream1);
+       close_file_or_dir(mntfd, dirstream2);
        if (mnt)
                free(mnt);
        if (fullpath)