Goffredo Baroncelli
2010-Jan-21 19:29 UTC
[RFC] Move all btrfs command to only one command
Hi all this RFC is about unify all btrfs command (btrfsctl, btrfs-show, btrfs-tune.. ) in only one called "btrfs" (or whatever we want). Today "btrfsctl" needs a "bit" of care because * the help is basically wrong [1] * the return codes are incoherent [2] * the syntax of the command are very ugly (a lot of people complained about the subvolumes/snapshot creation, because they aren''t very clear) [3] * the code is a mess (in the main there is a useless for(); there a lot of ''if'' because sometime the last argument is the target of ioctl, sometime no..) [4] * The checks of the number of argument are incorrect [5] I think that is better to rewrite from scratch a new command instead of patching the old one. So we don''t care about the backward compatibility. Other filesystem (hammer, tux3, zfs) have only one command for management purpose. Instead we have btrfsctl (which has a lot of different function) and btrfs-show, btrfs-tune, btrfs-volume which have few functions. There are patches which address [6] some of the previous issues, but these are not integrated (because the developers are busy on other issues). To me rewriting from scratch seems a fast path for solving these issues. I made a prototype (see attached file) in bash of what "btrfs" should be. The major different from btrfsctl are: - I talk about clone and not snapshot - If a sub-volume is required (for example for the cloning), the program check that the argument is a root of the subvolume and not a subdirectory - Creating a sub-volume requires only one argument Below some examples: $ btrfs Usage: btrfs clone|-c <source> [<dest>/]<name> Clone the subvolume <source> with the name <name> in the <dest> directory. btrfs delete|-d <subvolume> Delete the subvolume <subvolume>. btrfs create|-C [<dest>/]<name> Create a subvolume in <dest> (or the current directory if not passed. btrfs defrag|-d <file>|<dir> [<file>|<dir>...] Defragment a file or a directory. btrfs fssync|-s <path> Force a fs sync on the filesystem <path> btrfs resize|-r [+/-]<newsize>[gkm]|max <filesystem> Resize the file system. If ''max'' is passed, the filesystem will occupe all available space on the device. btrfs scan|-S [<device> [<device>..] Scan all device for or the passed device for a btrfs filesystem. btrfs show|-l <dev>|<label> [<dev>|<label>.. ] Show the btrfs devices btrfs balance|-b <path> Balance teh chunk across the device btrfs add|-A <dev> <path> Add a device to a filesystem btrfs rem|-R <dev> <path> Remove a device to a filesystem btrfs help|--help|-h Show the help. Comment are welcome [1] In the help the -r, -c options seem that don''t need any further argument; The -D command seems that accpet only "." as 2nd parameter.... [2] If something goes wrong btrfsctl returns 1; if the ioctl return 0 the command still returns 1... [3] See the email in the mailing list [4] If I does btrfsctl -c -d -A -S a . what result do you aspect ? [5] If I pass more argument than the ones needed no error is showed. -D checks if there is only one argument, when it needs two argument... [6] - 10/26/09 - little fixme in btrfsctl.c [PATCH] - From: David Nicol <davidnicol@gmail.com> - 12/24/09 - [PATCH] btrfs-progs: check slash in deleting subvolumes. - From: TARUISI - 12/13/09 - [PATCH] Improve the btrfsctl help - From: Goffredo Baroncelli <kreijack@gmail.com> -- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512
TARUISI Hiroaki
2010-Jan-22 00:02 UTC
Re: [RFC] Move all btrfs command to only one command
Hi Goffredo, It sounds good for me though detailed points need more discussion. btrfs-progs seems unkind for operator as you mentioned, and many features will be implemented to btrfsctl from now, it''s good that we arrange and unify btrfs-progs now. As for me, plain keywords(delete,defrag...) as commands are welcome. Regards, taruisi (2010/01/22 4:29), Goffredo Baroncelli wrote:> Hi all > > this RFC is about unify all btrfs command (btrfsctl, btrfs-show, btrfs-tune.. > ) in only one called "btrfs" (or whatever we want). > > Today "btrfsctl" needs a "bit" of care because > * the help is basically wrong [1] > * the return codes are incoherent [2] > * the syntax of the command are very ugly (a lot of people complained > about the subvolumes/snapshot creation, because they aren''t very clear) > [3] > * the code is a mess (in the main there is a useless for(); there a lot > of ''if'' because sometime the last argument is the target of ioctl, > sometime no..) [4] > * The checks of the number of argument are incorrect [5] > > I think that is better to rewrite from scratch a new command instead of > patching the old one. So we don''t care about the backward compatibility. > > Other filesystem (hammer, tux3, zfs) have only one command for management > purpose. Instead we have btrfsctl (which has a lot of different > function) and btrfs-show, btrfs-tune, btrfs-volume which have few functions. > > There are patches which address [6] some of the previous issues, > but these are not integrated (because the developers are busy on other > issues). To me rewriting from scratch seems a fast path for solving these > issues. > > I made a prototype (see attached file) in bash of what "btrfs" should be. The > major different from btrfsctl are: > - I talk about clone and not snapshot > - If a sub-volume is required (for example for the cloning), the program check > that the argument is a root of the subvolume and not a subdirectory > - Creating a sub-volume requires only one argument > > Below some examples: > > $ btrfs > Usage: > btrfs clone|-c <source> [<dest>/]<name> > Clone the subvolume <source> with the name <name> in the > <dest> > directory. > btrfs delete|-d <subvolume> > Delete the subvolume <subvolume>. > btrfs create|-C [<dest>/]<name> > Create a subvolume in <dest> (or the current directory if not > passed. > btrfs defrag|-d <file>|<dir> [<file>|<dir>...] > Defragment a file or a directory. > btrfs fssync|-s <path> > Force a fs sync on the filesystem <path> > btrfs resize|-r [+/-]<newsize>[gkm]|max <filesystem> > Resize the file system. If ''max'' is passed, the filesystem > will occupe all available space on the device. > btrfs scan|-S [<device> [<device>..] > Scan all device for or the passed device for a btrfs > filesystem. > btrfs show|-l <dev>|<label> [<dev>|<label>.. ] > Show the btrfs devices > btrfs balance|-b <path> > Balance teh chunk across the device > btrfs add|-A <dev> <path> > Add a device to a filesystem > btrfs rem|-R <dev> <path> > Remove a device to a filesystem > > btrfs help|--help|-h > Show the help. > > > > Comment are welcome > > > > > [1] In the help the -r, -c options seem that don''t need any further argument; > The -D command seems that accpet only "." as 2nd parameter.... > > [2] If something goes wrong btrfsctl returns 1; if the ioctl return 0 the > command still returns 1... > > [3] See the email in the mailing list > > [4] If I does > btrfsctl -c -d -A -S a . > what result do you aspect ? > > [5] If I pass more argument than the ones needed no error is showed. -D checks > if there is only one argument, when it needs two argument... > > [6] > - 10/26/09 - little fixme in btrfsctl.c [PATCH] - From: > David Nicol <davidnicol@gmail.com> > - 12/24/09 - [PATCH] btrfs-progs: check slash in deleting subvolumes. - From: > TARUISI > - 12/13/09 - [PATCH] Improve the btrfsctl help - From: > Goffredo Baroncelli <kreijack@gmail.com> > >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
Michael Niederle
2010-Jan-22 00:11 UTC
Re: [RFC] Move all btrfs command to only one command
> $ btrfs > Usage: > btrfs clone|-c <source> [<dest>/]<name> > Clone the subvolume <source> with the name <name> in the > <dest> > directory. > btrfs delete|-d > <subvolume> Delete the subvolume <subvolume>. > btrfs create|-C [<dest>/]<name> > Create a subvolume in <dest> (or the current directory if not > passed. > btrfs defrag|-d <file>|<dir> [<file>|<dir>...] > Defragment a file or a directory. > btrfs fssync|-s <path> > Force a fs sync on the filesystem <path> > btrfs resize|-r [+/-]<newsize>[gkm]|max <filesystem> > Resize the file system. If ''max'' is passed, the filesystem > will occupe all available space on the device. > btrfs scan|-S [<device> [<device>..] > Scan all device for or the passed device for a btrfs > filesystem. > btrfs show|-l <dev>|<label> [<dev>|<label>.. ] > Show the btrfs devices > btrfs balance|-b <path> > Balance teh chunk across the device > btrfs add|-A <dev> <path> > Add a device to a filesystem > btrfs rem|-R <dev> <path> > Remove a device to a filesystem > > btrfs help|--help|-h > Show the help.I like this idea! Just a small suggestion: "btrfs remove" instead of "btrfs rem" ----- Another question: Is there a simple way to convert a directory into a subvolume? Currently I first create the new subvolume; copy or move the data of the directory into the new subvolume, then delete the directory and finally rename the subvolume. Greetings, Michael -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
Adrian von Bidder
2010-Jan-22 08:23 UTC
Re: [RFC] Move all btrfs command to only one command
Hi, I like this very much, I found myself wondering which program did what again and again when I started to use btrfs, too. On Thursday 21 January 2010 20.29:26 Goffredo Baroncelli wrote:> btrfs resize|-r [+/-]<newsize>[gkm]|max <filesystem> > Resize the file system. If ''max'' is passed, the filesystem > will occupe all available space on the device.Switch the arguments, and if the 2nd is missing do what you propose for "max".> btrfs scan|-S [<device> [<device>..] > Scan all device for or the passed device for a btrfs > filesystem.This is the only that *migt* be sensible to have as a separate tool, if "btrfs" ends up requiring additional runtime dependencies: the scan utility should be small since it will need to be included in the initrd. -- Protect your privacy - encrypt your email: fortytwo.ch/gpg/intro
Xavier Nicollet
2010-Jan-22 09:33 UTC
Re: [RFC] Move all btrfs command to only one command
Le 22 janvier 2010 à 01:11, Michael Niederle a écrit:> > btrfs clone|-c <source> [<dest>/]<name> > > Clone the subvolume <source> with the name <name> in the > > <dest> > > directory.Maybe you should add the "writable snapshot" in the description, since everyone is using the word "snapshot" on the mailing list. When I hear "clone", I understand "dump".> > btrfs delete|-d > > <subvolume> Delete the subvolume <subvolume>.> > btrfs rem|-R <dev> <path> > > Remove a device to a filesystem> Just a small suggestion: > "btrfs remove" instead of "btrfs rem"Why not "btrfs rm", which reminds "git rm" ? Actually, I would do something like: btrfs vol add btrfs vol rm btrfs dev add btrfs dev rm It would bet simpler, wouldn''t it ? -- Xavier Nicollet -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2010-Jan-24 17:35 UTC
[RFC] Move all btrfs command to only one command: btrfs.c
Hi all, this is a follow-up of the previous email. I rewrite the btrfs command in C. Now the following actions are implemented: snapshot (-s) -> create a snapshot delete (-D) -> delete a subvolume or a snapshot create (-S) -> create a subvolume defrag (-d) -> defrag a tree or a file fssync (-c) -> sync a filesystem scan (-a) -> scan devices searching a btrfs filesystem show (-l) -> list the btrfs fs and its volumes balance (-b) -> balance the chunk across the volumes add-dev (-A) -> add a volume to a filesystem rem-dev (-R) -> remove a volume to a filesystem I cared that btrfs returns appropriate error code. And I check that a correct parameters number is passed. Finally, where appropriate if a subvolume is required (for example in case of snapshot and or delete) is checked that the passed path is a subvolume. This should limits the complain like: - I snapshot a sub directory, but I got a snapshot of the entire tree. I renamed remove (a volume) in rem-dev in order to avoid confusion with delete (a subvolume). You can find a git repository in cassiopea.homelinux.net/git/?p=btrfs-command.git;a=summary select the branch "btrfs-command" TODO: * resizing implementation * btrfstune implementation * btrfslabel implementation (but it require patch to the kernel) * mkfs implementation * check of the label length * test suite finalisation * test, test, test Suggestions are welcome. BR G.Baroncelli diff --git a/Makefile b/Makefile index 02f881e..888ef8d 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ bindir = $(prefix)/bin LIBS=-luuid progs = btrfsctl mkfs.btrfs btrfs-debug-tree btrfs-show btrfs-vol btrfsck \ - btrfs-map-logical + btrfs-map-logical btrfs # make C=1 to enable sparse ifdef C @@ -36,6 +36,9 @@ all: version $(progs) manpages version: bash version.sh +btrfs: $(objects) btrfs.o + gcc $(CFLAGS) -o btrfs btrfs.o $(objects) $(LDFLAGS) $(LIBS) + btrfsctl: $(objects) btrfsctl.o gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS) diff --git a/btrfs.c b/btrfs.c new file mode 100644 index 0000000..369e556 --- /dev/null +++ b/btrfs.c @@ -0,0 +1,743 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License v2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + */ + + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <dirent.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <libgen.h> +#include <limits.h> +#include <uuid/uuid.h> + +#undef ULONG_MAX + +#include "kerncompat.h" +#include "ctree.h" +#include "transaction.h" +#include "utils.h" +#include "version.h" +#include "ioctl.h" +#include "volumes.h" + +#ifdef __CHECKER__ +#define BLKGETSIZE64 0 +#define BTRFS_IOC_SNAP_CREATE 0 +#define BTRFS_VOL_NAME_MAX 255 +struct btrfs_ioctl_vol_args { char name[BTRFS_VOL_NAME_MAX]; }; +static inline int ioctl(int fd, int define, void *arg) { return 0; } +#endif + +/* + * test if path is a subvolume: + * this function return + * 0-> path exists but it is not a subvolume + * 1-> path exists and it is a subvolume + * -1 -> path is unaccessible + */ +static int test_issubvolume(char *path) +{ + + struct stat st; + int res; + + res = stat(path, &st); + if(res < 0 ) + return -1; + + return (st.st_ino == 256) && S_ISDIR(st.st_mode); + +} + +/* + * test if path is a directory + * this function return + * 0-> path exists but it is not a directory + * 1-> path exists and it is a directory + * -1 -> path is unaccessible + */ +static int test_isdir(char *path) +{ + struct stat st; + int res; + + res = stat(path, &st); + if(res < 0 ) + return -1; + + return S_ISDIR(st.st_mode); + +} + +static int open_file_or_dir(const char *fname) +{ + int ret; + struct stat st; + DIR *dirstream; + int fd; + + ret = stat(fname, &st); + if (ret < 0) { + return -1; + } + if (S_ISDIR(st.st_mode)) { + dirstream = opendir(fname); + if (!dirstream) { + return -2; + } + fd = dirfd(dirstream); + } else { + fd = open(fname, O_RDWR); + } + if (fd < 0) { + return -3; + } + return fd; +} + +static int do_clone(char *subvol, char *dst) +{ + int res, fd, fddst; + char *newname; + char *dstdir; + struct btrfs_ioctl_vol_args args; + + res = test_issubvolume(subvol); + if(res<0){ + fprintf(stderr, "ERROR: error accessing ''%s''\n", subvol); + return 12; + } + if(!res){ + fprintf(stderr, "ERROR: ''%s'' is not a subvolume\n", subvol); + return 13; + } + + res = test_isdir(dst); + if(res == 0 ){ + fprintf(stderr, "ERROR: ''%s'' exists and it is not a directory\n", dst); + return 12; + } + + if(res>0){ + newname = strdup(subvol); + newname = basename(newname); + dstdir = dst; + }else{ + newname = strdup(dst); + newname = basename(newname); + dstdir = strdup(dst); + dstdir = dirname(dstdir); + } + + if( !strcmp(newname,".") || !strcmp(newname,"..") || + strchr(newname, ''/'') ){ + fprintf(stderr, "ERROR: uncorrect snapshot name (''%s'')\n", + newname); + return 14; + } + + fddst = open_file_or_dir(dstdir); + if (fddst < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); + return 12; + } + + fd = open_file_or_dir(subvol); + if (fd < 0) { + close(fddst); + fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); + return 12; + } + + printf("Create a snapshot of ''%s'' in ''%s/%s''\n", + subvol, dstdir, newname); + args.fd = fd; + strcpy(args.name, newname); + res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE, &args); + + close(fd); + close(fddst); + + if(res < 0 ){ + fprintf( stderr, "ERROR: cannot snapshot ''%s''\n",subvol); + return 11; + } + + return 0; + +} + +static int do_delete_subvolume(char *path) +{ + int res, fd; + struct btrfs_ioctl_vol_args args; + char *dname, *vname, *cpath; + + res = test_issubvolume(path); + if(res<0){ + fprintf(stderr, "ERROR: error accessing ''%s''\n", path); + return 12; + } + if(!res){ + fprintf(stderr, "ERROR: ''%s'' is not a subvolume\n", path); + return 13; + } + + cpath = realpath(path, 0); + dname = strdup(cpath); + dname = dirname(dname); + vname = strdup(cpath); + vname = basename(vname); + free(cpath); + + if( !strcmp(vname,".") || !strcmp(vname,"..") || + strchr(vname, ''/'') ){ + fprintf(stderr, "ERROR: uncorrect subvolume name (''%s'')\n", + vname); + return 14; + } + + fd = open_file_or_dir(dname); + if (fd < 0) { + close(fd); + fprintf(stderr, "ERROR: can''t access to ''%s''\n", dname); + return 12; + } + + printf("Delete subvolume ''%s/%s''\n", dname, vname); + strcpy(args.name, vname); + res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args); + + close(fd); + + if(res < 0 ){ + fprintf( stderr, "ERROR: cannot delete ''%s/%s''\n",dname, vname); + return 11; + } + + return 0; + +} + +static int do_create_subvol(char *dst) +{ + int res, fddst; + char *newname; + char *dstdir; + struct btrfs_ioctl_vol_args args; + + res = test_isdir(dst); + if(res >= 0 ){ + fprintf(stderr, "ERROR: ''%s'' exists\n", dst); + return 12; + } + + newname = strdup(dst); + newname = basename(newname); + dstdir = strdup(dst); + dstdir = dirname(dstdir); + + if( !strcmp(newname,".") || !strcmp(newname,"..") || + strchr(newname, ''/'') ){ + fprintf(stderr, "ERROR: uncorrect subvolume name (''%s'')\n", + newname); + return 14; + } + + fddst = open_file_or_dir(dstdir); + if (fddst < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", dstdir); + return 12; + } + + printf("Create subvolume ''%s/%s''\n", dstdir, newname); + strcpy(args.name, newname); + res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args); + + close(fddst); + + if(res < 0 ){ + fprintf( stderr, "ERROR: cannot create subvolume\n"); + return 11; + } + + return 0; + +} + +static int do_fssync(char *path) +{ + int fd, res; + + fd = open_file_or_dir(path); + if (fd < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", path); + return 12; + } + + printf("FSSync ''%s''\n", path); + res = ioctl(fd, BTRFS_IOC_SYNC); + close(fd); + if( res < 0 ){ + fprintf(stderr, "ERROR: unable to fs-syncing ''%s''\n", path); + return 16; + } + + return 0; +} + +static int do_scan(int nargs, char **argv) +{ + int i, fd; + if(!nargs){ + int ret; + + printf("Scanning for Btrfs filesystems\n"); + ret = btrfs_scan_one_dir("/dev", 1); + if (ret){ + fprintf(stderr, "ERROR: error %d while scanning\n", ret); + return 18; + } + return 0; + } + + fd = open("/dev/btrfs-control", O_RDWR); + if (fd < 0) { + perror("failed to open /dev/btrfs-control"); + return 10; + } + + for( i = 0 ; i < nargs ; i++ ){ + struct btrfs_ioctl_vol_args args; + int ret; + + printf("Scanning for Btrfs filesystems in ''%s''\n", argv[i]); + + strcpy(args.name, argv[i]); + /* + * FIXME: which are the error code returned by this ioctl ? + * it seems that is impossible to undetand if there no is + * a btrfs filesystem from an I/O error !!! + */ + ret = ioctl(fd, BTRFS_IOC_SCAN_DEV, &args); + + if( ret < 0 ){ + close(fd); + fprintf(stderr, "ERROR: unable to scan the device ''%s''\n", argv[i]); + return 11; + } + } + + close(fd); + return 0; + +} + +static int do_defrag(int argc, char **argv) +{ + + int i, ret=0; + + for(i=0 ; i <argc ; i++){ + int fd, res; + char *path = argv[i]; + fd = open_file_or_dir(path); + if (fd < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", path); + ret++; + continue; + } + + printf("Defrag ''%s''\n", path); + res = ioctl(fd, BTRFS_IOC_DEFRAG); + close(fd); + if( res < 0 ){ + fprintf(stderr, "ERROR: unable to defrag ''%s''\n", argv[i]); + ret++; + continue; + } + } + + /* + * the return code is 0 (success) or the number of the failure + 20 + */ + if(ret) + ret+=20; + return ret; +} + +static int uuid_search(struct btrfs_fs_devices *fs_devices, char *search) +{ + struct list_head *cur; + struct btrfs_device *device; + + list_for_each(cur, &fs_devices->devices) { + device = list_entry(cur, struct btrfs_device, dev_list); + if ((device->label && strcmp(device->label, search) == 0) || + strcmp(device->name, search) == 0) + return 1; + } + return 0; +} + +static void print_one_uuid(struct btrfs_fs_devices *fs_devices) +{ + char uuidbuf[37]; + struct list_head *cur; + struct btrfs_device *device; + char *super_bytes_used; + u64 devs_found = 0; + u64 total; + + uuid_unparse(fs_devices->fsid, uuidbuf); + device = list_entry(fs_devices->devices.next, struct btrfs_device, + dev_list); + if (device->label && device->label[0]) + printf("Label: ''%s'' ", device->label); + else + printf("Label: none "); + + super_bytes_used = pretty_sizes(device->super_bytes_used); + + total = device->total_devs; + printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf, + (unsigned long long)total, super_bytes_used); + + free(super_bytes_used); + + list_for_each(cur, &fs_devices->devices) { + char *total_bytes; + char *bytes_used; + device = list_entry(cur, struct btrfs_device, dev_list); + total_bytes = pretty_sizes(device->total_bytes); + bytes_used = pretty_sizes(device->bytes_used); + printf("\tdevid %4llu size %s used %s path %s\n", + (unsigned long long)device->devid, + total_bytes, bytes_used, device->name); + free(total_bytes); + free(bytes_used); + devs_found++; + } + if (devs_found < total) { + printf("\t*** Some devices missing\n"); + } + printf("\n"); +} + +static int do_show_volume(char *search) +{ + struct list_head *all_uuids; + struct btrfs_fs_devices *fs_devices; + struct list_head *cur_uuid; + int ret; + + ret = btrfs_scan_one_dir("/dev", 0); + if (ret){ + fprintf(stderr, "ERROR: error %d while scanning\n", ret); + return 18; + } + + all_uuids = btrfs_scanned_uuids(); + list_for_each(cur_uuid, all_uuids) { + fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices, + list); + if (search && uuid_search(fs_devices, search) == 0) + continue; + print_one_uuid(fs_devices); + } + printf("%s\n", BTRFS_BUILD_VERSION); + return 0; +} + +static int do_add_volume(int nargs, char **args) +{ + + char *mntpnt = args[nargs-1]; + int i, fdmnt, ret=0; + + + fdmnt = open_file_or_dir(mntpnt); + if (fdmnt < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", mntpnt); + return 12; + } + + for(i=0 ; i < (nargs-1) ; i++ ){ + struct btrfs_ioctl_vol_args ioctl_args; + int devfd, res; + u64 dev_block_count = 0; + struct stat st; + + devfd = open(args[i], O_RDWR); + if (!devfd) { + fprintf(stderr, "ERROR: Unable to open device ''%s''\n", args[i]); + close(devfd); + ret++; + continue; + } + ret = fstat(devfd, &st); + if (ret) { + fprintf(stderr, "ERROR: Unable to stat ''%s''\n", args[i]); + close(devfd); + ret++; + continue; + } + if (!S_ISBLK(st.st_mode)) { + fprintf(stderr, "ERROR: ''%s'' is not a block device\n", args[i]); + close(devfd); + ret++; + continue; + } + + res = btrfs_prepare_device(devfd, args[i], 1, &dev_block_count); + if (ret) { + fprintf(stderr, "ERROR: Unable to init ''%s''\n", args[i]); + close(devfd); + ret++; + continue; + } + close(devfd); + + strcpy(ioctl_args.name, args[i]); + res = ioctl(fdmnt, BTRFS_IOC_ADD_DEV, &ioctl_args); + if(res<0){ + fprintf(stderr, "ERROR: error adding the device ''%s''\n", args[i]); + ret++; + } + + } + + close(fdmnt); + if( ret) + return ret+20; + else + return 0; + +} + +static int do_balance(char *path) +{ + + int fdmnt, ret=0; + + fdmnt = open_file_or_dir(path); + if (fdmnt < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", path); + return 12; + } + + ret = ioctl(fdmnt, BTRFS_IOC_BALANCE); + close(fdmnt); + if(ret<0){ + fprintf(stderr, "ERROR: balancing ''%s''\n", path); + + return 19; + } + return 0; +} +static int do_remove_volume(int nargs, char **args) +{ + + char *mntpnt = args[nargs-1]; + int i, fdmnt, ret=0; + + fdmnt = open_file_or_dir(mntpnt); + if (fdmnt < 0) { + fprintf(stderr, "ERROR: can''t access to ''%s''\n", mntpnt); + return 12; + } + + for(i=0 ; i < (nargs-1) ; i++ ){ + struct btrfs_ioctl_vol_args arg; + int res; + + strcpy(arg.name, args[i]); + res = ioctl(fdmnt, BTRFS_IOC_RM_DEV, &arg); + if(res<0){ + fprintf(stderr, "ERROR: error removing the device ''%s''\n", args[i]); + ret++; + } + } + + close(fdmnt); + if( ret) + return ret+20; + else + return 0; +} + + +static void help(char *programname) +{ + char *np; + + np = strrchr(programname,''/''); + if(!np) + np = programname; + else + np++; + + printf("Usage:\n"); + printf(" %s snapshot|-s <source> [<dest>/]<name>\n", np); + printf(" Create a writeble snapshot of the subvolume\n"); + printf(" <source> with the name <name> in the <dest>\n"); + printf(" directory.\n"); + printf(" %s delete|-D <subvolume>\n", np); + printf(" Delete the subvolume <subvolume>.\n"); + printf(" %s create|-S [<dest>/]<name>\n", np); + printf(" Create a subvolume in <dest> (or the current directory if not\n"); + printf(" passed.\n"); + printf(" %s defrag|-d <file>|<dir> [<file>|<dir>...]\n", np); + printf(" Defragment a file or a directory.\n"); + printf(" %s fssync|-c <path>\n", np); + printf(" Force a fs sync on the filesystem <path>\n"); + printf(" %s resize|-r [+/-]<newsize>[gkm]|max <filesystem>\n", np); + printf(" Resize the file system. If ''max'' is passed, the filesystem\n"); + printf(" will occupe all available space on the device. \n"); + printf(" %s scan|-a [<device> [<device>..]\n", np); + printf(" Scan all device for or the passed device for a\n"); + printf(" btrfs filesystem.\n"); + printf(" %s show|-l <dev>|<label> [<dev>|<label>...]\n", np); + printf(" Show the btrfs devices\n"); + printf(" %s balance|-b <path>\n", np); + printf(" Balance the chunk across the device\n"); + printf(" %s add-dev|-A <dev> [<dev>..] <path>\n", np); + printf(" Add a device to a filesystem\n"); + printf(" %s rem-dev|-R <dev> [<dev>..] <path>\n", np); + printf(" Remove a device to a filesystem\n"); + printf("\n"); + printf(" %s help|--help|-h\n",np); + printf(" Show the help.\n"); + printf("%s\n", BTRFS_BUILD_VERSION); + +} + +int main(int argc, char **argv ) +{ + + int i; + + for( i = 1 ; i < argc ; i++ ){ + /* number of arguments after the verb*/ + int nargs = argc -i - 1; + + if( !strcmp(argv[i], "scan") || !strcmp(argv[i],"-a" )){ + + exit(do_scan(nargs, argv+i+1)); + + }else if( !strcmp(argv[i], "defrag") || !strcmp(argv[i],"-d" )){ + if( nargs < 1 ){ + fprintf(stderr, + "ERROR: ''%s'' requires minimum 1 arg\n", argv[i]); + exit(2); + } + exit(do_defrag(nargs, argv+i+1)); + + }else if( !strcmp(argv[i], "snapshot") || !strcmp(argv[i],"-s" )){ + + if( nargs > 2 || nargs < 2 ){ + fprintf(stderr, "ERROR: ''%s'' requires 2 args\n", argv[i]); + exit(2); + } + exit(do_clone(argv[i+1], argv[i+2])); + + }else if( !strcmp(argv[i], "create") || !strcmp(argv[i],"-S" )){ + + if( nargs > 1 || nargs < 1 ){ + fprintf(stderr, "ERROR: ''%s'' requires 1 arg\n", argv[i]); + exit(2); + } + exit(do_create_subvol(argv[i+1])); + + }else if( !strcmp(argv[i], "fssync") || !strcmp(argv[i],"-c" )){ + + if( nargs > 1 || nargs < 1 ){ + fprintf(stderr, "ERROR: ''%s'' requires 1 arg\n", argv[i]); + exit(2); + } + exit(do_fssync(argv[i+1])); + + }else if( !strcmp(argv[i], "delete") || !strcmp(argv[i],"-D" )){ + + if( nargs > 1 || nargs < 1 ){ + fprintf(stderr, + "ERROR: ''%s'' requires 1 arg\n", argv[i]); + exit(2); + } + exit(do_delete_subvolume(argv[i+1])); + + }else if( !strcmp(argv[i], "show") || !strcmp(argv[i],"-l" )){ + + if( nargs > 1 ){ + fprintf(stderr, + "ERROR: ''%s'' requires maximum 1 arg\n", argv[i]); + exit(2); + } + exit(do_show_volume(nargs ? argv[i+1]:0)); + + }else if( !strcmp(argv[i], "add-dev") || !strcmp(argv[i],"-A" )){ + + if( nargs < 2 ){ + fprintf(stderr, + "ERROR: ''%s'' requires minimum 2 arg\n", argv[i]); + exit(2); + } + exit(do_add_volume(nargs, argv+i+1)); + + }else if( !strcmp(argv[i], "rem-dev") || !strcmp(argv[i],"-R" )){ + + if( nargs < 2 ){ + fprintf(stderr, + "ERROR: ''%s'' requires minimum 2 arg\n", argv[i]); + exit(2); + } + exit(do_remove_volume(nargs, argv+i+1)); + + }else if( !strcmp(argv[i], "balance") || !strcmp(argv[i],"-b" )){ + + if( nargs > 1 ){ + fprintf(stderr, + "ERROR: ''%s'' requires 1 arg\n", argv[i]); + exit(2); + } + exit(do_balance(argv[i+1])); + + } else if( !strcmp(argv[i], "help") || !strcmp(argv[i], "-h") || + !strcmp(argv[i], "--help")){ + help(argv[0]); + exit(0); + } else { + fprintf( stderr, "ERROR: unknow command ''%s''\n",argv[i]); + help(argv[0]); + exit(1); + } + + } + + /* + * no command is passed + */ + fprintf(stderr, "ERROR: no command passed\n"); + help(argv[0]); + exit(1); + + +} \ No newline at end of file -- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512
Piavlo
2010-Jan-24 18:34 UTC
Re: [RFC] Move all btrfs command to only one command: btrfs.c
Goffredo Baroncelli wrote:> Hi all, > > this is a follow-up of the previous email. I rewrite the btrfs command in C. > Now the following actions are implemented: > > snapshot (-s) -> create a snapshot > delete (-D) -> delete a subvolume or a snapshot > create (-S) -> create a subvolume > defrag (-d) -> defrag a tree or a file > fssync (-c) -> sync a filesystem > scan (-a) -> scan devices searching a btrfs filesystem > show (-l) -> list the btrfs fs and its volumes > balance (-b) -> balance the chunk across the volumes > add-dev (-A) -> add a volume to a filesystem > rem-dev (-R) -> remove a volume to a filesystem > > I cared that btrfs returns appropriate error code. And I check that a correct > parameters number is passed. Finally, where appropriate if a subvolume is > required (for example in case of snapshot and or delete) is checked that the > passed path is a subvolume. This should limits the complain like: > - I snapshot a sub directory, but I got a snapshot of the entire tree. > > I renamed remove (a volume) in rem-dev in order to avoid confusion with delete > (a subvolume). >To avoid such confusion IMHO it''s logically better to have two commands instead one for handling actions at volume level and other command at file system level - something like btrfs & btrpool - like in other well known file system :) Alex> You can find a git repository in > > cassiopea.homelinux.net/git/?p=btrfs-command.git;a=summary > > select the branch "btrfs-command" > > TODO: > * resizing implementation > * btrfstune implementation > * btrfslabel implementation (but it require patch to the kernel) > * mkfs implementation > * check of the label length > * test suite finalisation > * test, test, test > > Suggestions are welcome. > > BR > G.Baroncelli >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
Chris Mason
2010-Feb-11 16:33 UTC
Re: [RFC] Move all btrfs command to only one command: btrfs.c
On Sun, Jan 24, 2010 at 06:35:33PM +0100, Goffredo Baroncelli wrote:> Hi all, > > this is a follow-up of the previous email. I rewrite the btrfs command in C. > Now the following actions are implemented: > > snapshot (-s) -> create a snapshot > delete (-D) -> delete a subvolume or a snapshot > create (-S) -> create a subvolume > defrag (-d) -> defrag a tree or a file > fssync (-c) -> sync a filesystem > scan (-a) -> scan devices searching a btrfs filesystem > show (-l) -> list the btrfs fs and its volumes > balance (-b) -> balance the chunk across the volumes > add-dev (-A) -> add a volume to a filesystem > rem-dev (-R) -> remove a volume to a filesystem > > I cared that btrfs returns appropriate error code. And I check that a correct > parameters number is passed. Finally, where appropriate if a subvolume is > required (for example in case of snapshot and or delete) is checked that the > passed path is a subvolume. This should limits the complain like: > - I snapshot a sub directory, but I got a snapshot of the entire tree. > > I renamed remove (a volume) in rem-dev in order to avoid confusion with delete > (a subvolume).Sorry for the late reply, but I really like this mode and will work on integrating it. rem-dev should be rm-dev or remove-dev -chris -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2010-Feb-11 18:15 UTC
Re: [RFC] Move all btrfs command to only one command: btrfs.c
On Thursday 11 February 2010, Chris Mason wrote:> On Sun, Jan 24, 2010 at 06:35:33PM +0100, Goffredo Baroncelli wrote: > > Hi all, > > > > this is a follow-up of the previous email. I rewrite the btrfs command inC.> > Now the following actions are implemented: > > > > snapshot (-s) -> create a snapshot > > delete (-D) -> delete a subvolume or a snapshot > > create (-S) -> create a subvolume > > defrag (-d) -> defrag a tree or a file > > fssync (-c) -> sync a filesystem > > scan (-a) -> scan devices searching a btrfs filesystem > > show (-l) -> list the btrfs fs and its volumes > > balance (-b) -> balance the chunk across the volumes > > add-dev (-A) -> add a volume to a filesystem > > rem-dev (-R) -> remove a volume to a filesystem > > > > I cared that btrfs returns appropriate error code. And I check that acorrect> > parameters number is passed. Finally, where appropriate if a subvolume is > > required (for example in case of snapshot and or delete) is checked thatthe> > passed path is a subvolume. This should limits the complain like: > > - I snapshot a sub directory, but I got a snapshot of the entire tree. > > > > I renamed remove (a volume) in rem-dev in order to avoid confusion withdelete> > (a subvolume). > > Sorry for the late reply, but I really like this mode and will work on > integrating it. rem-dev should be rm-dev or remove-devFor me is ok; I will update my patch this week end> -chris > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at vger.kernel.org/majordomo-info.html >-- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack@inwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
.. it would be good to have some "mechanism" that will "prevent" people mixing -d with -D Chris Mason wrote:> On Sun, Jan 24, 2010 at 06:35:33PM +0100, Goffredo Baroncelli wrote: > >> Hi all, >> >> this is a follow-up of the previous email. I rewrite the btrfs command in C. >> Now the following actions are implemented: >> >> snapshot (-s) -> create a snapshot >> delete (-D) -> delete a subvolume or a snapshot >> create (-S) -> create a subvolume >> defrag (-d) -> defrag a tree or a file >> fssync (-c) -> sync a filesystem >> scan (-a) -> scan devices searching a btrfs filesystem >> show (-l) -> list the btrfs fs and its volumes >> balance (-b) -> balance the chunk across the volumes >> add-dev (-A) -> add a volume to a filesystem >> rem-dev (-R) -> remove a volume to a filesystem >> >> I cared that btrfs returns appropriate error code. And I check that a correct >> parameters number is passed. Finally, where appropriate if a subvolume is >> required (for example in case of snapshot and or delete) is checked that the >> passed path is a subvolume. This should limits the complain like: >> - I snapshot a sub directory, but I got a snapshot of the entire tree. >> >> I renamed remove (a volume) in rem-dev in order to avoid confusion with delete >> (a subvolume). >> > > Sorry for the late reply, but I really like this mode and will work on > integrating it. rem-dev should be rm-dev or remove-dev > > -chris > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at vger.kernel.org/majordomo-info.html >-- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html
Goffredo Baroncelli
2010-Feb-11 21:29 UTC
Re: [RFC] Move all btrfs command to only one command: btrfs.c
On Thursday 11 February 2010, rk wrote:> . it would be good to have some "mechanism" that will "prevent" people > mixing -d with -Dbtrfs checks that the path passed to -D command is referred to a subvolume. If there is an agreement I am open to change the switch (-d) of the defrag command. BR Goffredo> Chris Mason wrote: > > On Sun, Jan 24, 2010 at 06:35:33PM +0100, Goffredo Baroncelli wrote: > > > >> Hi all, > >> > >> this is a follow-up of the previous email. I rewrite the btrfs command inC.> >> Now the following actions are implemented: > >> > >> snapshot (-s) -> create a snapshot > >> delete (-D) -> delete a subvolume or a snapshot > >> create (-S) -> create a subvolume > >> defrag (-d) -> defrag a tree or a file > >> fssync (-c) -> sync a filesystem > >> scan (-a) -> scan devices searching a btrfs filesystem > >> show (-l) -> list the btrfs fs and its volumes > >> balance (-b) -> balance the chunk across the volumes > >> add-dev (-A) -> add a volume to a filesystem > >> rem-dev (-R) -> remove a volume to a filesystem > >> > >> I cared that btrfs returns appropriate error code. And I check that acorrect> >> parameters number is passed. Finally, where appropriate if a subvolume is > >> required (for example in case of snapshot and or delete) is checked thatthe> >> passed path is a subvolume. This should limits the complain like: > >> - I snapshot a sub directory, but I got a snapshot of the entire tree. > >> > >> I renamed remove (a volume) in rem-dev in order to avoid confusion withdelete> >> (a subvolume). > >> > > > > Sorry for the late reply, but I really like this mode and will work on > > integrating it. rem-dev should be rm-dev or remove-dev > > > > -chris > > -- > > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > > the body of a message to majordomo@vger.kernel.org > > More majordomo info at vger.kernel.org/majordomo-info.html > > > > -- > To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at vger.kernel.org/majordomo-info.html >-- gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijackATinwind.it> Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at vger.kernel.org/majordomo-info.html