@@ -83,9 +83,10 @@ static struct Command commands[] = {
"will occupe all available space on the device."
},
{ do_show_filesystem, 999,
- "filesystem show", "[<uuid>|<label>]\n"
+ "filesystem show", "[--all-devices][<uuid>|<label>]\n"
"Show the info of a btrfs filesystem. If no <uuid> or <label>\n"
- "is passed, info of all the btrfs filesystem are shown."
+ "is passed, info of all the btrfs filesystem are shown.\n"
+ "If --all-devices is passed, all devices are scanned."
},
{ do_df_filesystem, 1,
"filesystem df", "<path>\n"
@@ -96,9 +97,10 @@ static struct Command commands[] = {
"Balance the chunks across the device."
},
{ do_scan,
- 999, "device scan", "[<device> [<device>..]\n"
+ 999, "device scan", "[--all-devices|<device> [<device>..]\n"
"Scan all device for or the passed device for a btrfs\n"
- "filesystem."
+ "filesystem.\n"
+ "If --all-devices is passed, all devices are scanned."
},
{ do_add_volume, -2,
"device add", "<dev> [<dev>..] <path>\n"
new file mode 100644
@@ -0,0 +1,24 @@
+#
+# This file lists the devices which have to be skipped or not
+# during the command 'btrfs filesystem show' and 'btrfs device scan'
+#
+# These lines may contain a shell wildcard pattern (*,?,[]).
+#
+# If a line starts with "!" and matches a device, the device is skipped
+# If a line matches a device, the device is evaluated
+# If a device is not matched by any line, the device is evaluated.
+#
+# The lines starting with "#" are comments. The lines empty are
+# ignored
+#
+
+
+
+# There are two default rules which are added automatically
+#
+# skip floppy
+# !/dev/fd*
+#
+# skip cdrom
+# !/dev/sr*
+#
@@ -529,11 +529,25 @@ int do_fssync(int argc, char **argv)
int do_scan(int argc, char **argv)
{
int i, fd;
- if(argc<=1){
+ int checklist = 1;
+ int devstart = 1;
+
+ if( argc >= 2 && !strcmp(argv[1],"--all-devices")){
+
+ if( argc >2 ){
+ fprintf(stderr, "ERROR: too may arguments\n");
+ return 22;
+ }
+
+ checklist = 0;
+ devstart += 1;
+ }
+
+ if(argc<=devstart){
int ret;
printf("Scanning for Btrfs filesystems\n");
- ret = btrfs_scan_one_dir("/dev", 1);
+ ret = btrfs_scan_block_devices(1, checklist);
if (ret){
fprintf(stderr, "ERROR: error %d while scanning\n", ret);
return 18;
@@ -547,7 +561,7 @@ int do_scan(int argc, char **argv)
return 10;
}
- for( i = 1 ; i < argc ; i++ ){
+ for( i = devstart ; i < argc ; i++ ){
struct btrfs_ioctl_vol_args args;
int ret;
@@ -666,15 +680,30 @@ int do_show_filesystem(int argc, char **argv)
struct list_head *all_uuids;
struct btrfs_fs_devices *fs_devices;
struct list_head *cur_uuid;
- char *search = argv[1];
+ char *search=0;
int ret;
+ int checklist = 1;
+ int searchstart = 1;
- ret = btrfs_scan_one_dir("/dev", 0);
+ if( argc >= 2 && !strcmp(argv[1],"--all-devices")){
+ checklist = 0;
+ searchstart += 1;
+ }
+
+ if( argc > searchstart+1 ){
+ fprintf(stderr, "ERROR: too many arguments\n");
+ return 22;
+ }
+
+ ret = btrfs_scan_block_devices(0, checklist);
if (ret){
fprintf(stderr, "ERROR: error %d while scanning\n", ret);
return 18;
}
+ if(searchstart < argc)
+ search = argv[searchstart];
+
all_uuids = btrfs_scanned_uuids();
list_for_each(cur_uuid, all_uuids) {
fs_devices = list_entry(cur_uuid, struct btrfs_fs_devices,
@@ -21,9 +21,9 @@ btrfs \- control a btrfs filesystem
.PP
\fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
.PP
-\fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
+\fBbtrfs\fP \fBfilesystem show\fP\fI [--all-devices] <uuid>|<label> [<uuid>|<label>...]\fP
.PP
-\fBbtrfs\fP \fBdevice show\fP\fI <dev>|<label> [<dev>|<label>...]\fP
+\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices][<device> [<device>..]]\fP
.PP
\fBbtrfs\fP \fBdevice balance\fP\fI <path> \fP
.PP
@@ -106,9 +106,10 @@ is returned by the \fBsubvolume list\fR command.
Defragment files and/or directories.
.TP
-\fBdevice scan\fR \fI[<device> [<device>..]]\fR
+\fBdevice scan\fR \fI[--all-devices][<device> [<device>..]]\fR
Scan devices for a btrfs filesystem. If no devices are passed, \fBbtrfs\fR scans
-all the block devices.
+all the block devices. If --all-devices is passed, the file /etc/btrfs.devices
+are ignored and all devices are scanned.
.TP
\fBfilesystem sync\fR\fI <path> \fR
@@ -138,9 +139,10 @@ can expand the partition before enlarging the filesystem and shrink the
partition after reducing the size of the filesystem.
.TP
-\fBfilesystem show\fR [<uuid>|<label>]\fR
+\fBfilesystem show\fR [--all-devices][<uuid>|<label>]\fR
Show the btrfs filesystem with some additional info. If no UUID or label is
-passed, \fBbtrfs\fR show info of all the btrfs filesystem.
+passed, \fBbtrfs\fR show info of all the btrfs filesystem. If --all-devices
+is passed, the file /etc/btrfs.devices are ignored and all devices are scanned.
.TP
\fBdevice balance\fR \fI<path>\fR
@@ -160,6 +162,14 @@ Remove device(s) from a filesystem identified by \fI<path>\fR.
\fBbtrfs\fR returns a zero exist status if it succeeds. Non zero is returned in
case of failure.
+.SH FILES
+The file \fB/etc/btrfs.devices\fR contains a list of devices which have to be
+skipped (or not) when the commands \fBbtrfs filesystem show\fR and
+\fBbtrfs device scan\fR are executed. If a line starts with '!', and matches
+a device, this device is skipped. If a line matches a device, this device is
+evaluated. If this file doesn't exists, the default rules are to skip floppy
+and cdrom.The shell wildcard may be used.
+
.SH AVAILABILITY
.B btrfs
is part of btrfs-progs. Btrfs filesystem is currently under heavy development,
@@ -35,6 +35,8 @@
#include <linux/major.h>
#include <linux/kdev_t.h>
#include <limits.h>
+#include <ctype.h>
+#include <fnmatch.h>
#include "kerncompat.h"
#include "radix-tree.h"
#include "ctree.h"
@@ -833,7 +835,185 @@ void btrfs_register_one_device(char *fname)
close(fd);
}
-int btrfs_scan_one_dir(char *dirname, int run_ioctl)
+
+static char **device_checklist = 0;
+static int device_checklist_count = 0;
+/*
+ * Default device black list:
+ * If the line starts with a "!" the device has to be skipped
+ * otherwise the device is OK
+ */
+static char *default_checklist[] = {
+ "!/dev/fd*",
+ "!/dev/sr*",
+ 0
+};
+/* add an entry in the checklist */
+static int device_checklist_add(char *entry)
+{
+ char *cpy;
+ char **res;
+
+ device_checklist_count += 1;
+ res = realloc(device_checklist,
+ sizeof(char*)*device_checklist_count);
+ if( !res ){
+ free(device_checklist);
+ device_checklist_count = 0;
+ return -1;
+ }
+ device_checklist = res;
+
+ cpy = strdup(entry);
+ if( !cpy ){
+ free(device_checklist);
+ device_checklist_count = 0;
+ return -1;
+ }
+
+ device_checklist[device_checklist_count-1] = cpy;
+ return 0;
+}
+
+/*
+ * init the check list on teh basis of the default check list
+ * and the check list stored in the file "fn"
+ */
+static int init_device_checklist(char *fn)
+{
+
+ char buf[1024];
+ int i;
+ FILE *fp;
+
+ if(device_checklist_count)
+ return 0;
+
+ if( fn == 0 )
+ return 0; /* no extra rules provided */
+
+ fp = fopen(fn, "r");
+ if(!fp)
+ return 0; /* the file doesn't exist */
+
+ while(fgets(buf,1023, fp)){
+ char *p = buf;
+ char *l;
+ while (isblank(*p)) p++;
+ l = p;
+ while( *l != '\n' && *l != '\r' && *l ) l++;
+ *l = 0;
+
+ if( *p == '#' || *p == 0 )
+ continue;
+
+ if(device_checklist_add(p)){
+ fclose(fp);
+ return -2;
+ }
+ }
+ fclose(fp);
+
+ for(i=0; default_checklist[i] ; i++ )
+ if(device_checklist_add(default_checklist[i]))
+ return -3;
+
+
+ return 0;
+}
+
+/*
+ * This function test if "dev" has to be skipped on the basis of the
+ * checklist; return values:
+ * 0 -> skip the deive
+ * 1 -> teh device is ok
+ */
+static int test_device(char *dev )
+{
+ int i;
+ for( i = 0 ; i < device_checklist_count ; i++ ){
+ int res;
+ char *rule;
+
+ rule = device_checklist[i];
+
+ if( rule[0] == '!' ){
+ res = 0; /* if match, skip the device */
+ rule++;
+ }else{
+ res = 1; /* if match, the device is ok */
+ }
+
+ if( !fnmatch(rule, dev, 0 ) )
+ return res;
+
+ }
+ return 1;
+}
+
+int btrfs_scan_block_devices(int run_ioctl, int checklist)
+{
+
+ struct stat st;
+ int ret;
+ int fd;
+ struct btrfs_fs_devices *tmp_devices;
+ u64 num_devices;
+ FILE *proc_partitions;
+ int i;
+ char buf[1024];
+ char name[100], fullpath[110];
+
+ if(checklist)
+ init_device_checklist(BTRFSDEVICELIST);
+
+ proc_partitions = fopen("/proc/partitions","r");
+ if (!proc_partitions) {
+ fprintf(stderr, "Unable to open '/proc/partitions' for scanning\n");
+ return -ENOENT;
+ }
+ /* skip the header */
+ for(i=0; i < 2 ; i++)
+ if(!fgets(buf, 1023, proc_partitions)){
+ fprintf(stderr, "Unable to read '/proc/partitions' for scanning\n");
+ fclose(proc_partitions);
+ return -ENOENT;
+ }
+
+ strcpy(fullpath,"/dev/");
+ while(fgets(buf, 1023, proc_partitions)) {
+
+ i = sscanf(buf," %*d %*d %*d %99s", fullpath+5);
+ ret = lstat(fullpath, &st);
+ if (ret < 0) {
+ fprintf(stderr, "failed to stat %s\n", fullpath);
+ continue;
+ }
+ if (!S_ISBLK(st.st_mode)) {
+ continue;
+ }
+ if (checklist && !test_device(fullpath)){
+ continue;
+ }
+ fd = open(fullpath, O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "failed to read %s\n", fullpath);
+ continue;
+ }
+ ret = btrfs_scan_one_device(fd, fullpath, &tmp_devices,
+ &num_devices,
+ BTRFS_SUPER_INFO_OFFSET);
+ if (ret == 0 && run_ioctl > 0) {
+ btrfs_register_one_device(fullpath);
+ }
+ close(fd);
+ }
+
+ fclose(proc_partitions);
+ return 0;
+}
+
+int btrfs_scan_one_dir_checklist(char *dirname, int run_ioctl, int checklist)
{
DIR *dirp = NULL;
struct dirent *dirent;
@@ -848,6 +1028,9 @@ int btrfs_scan_one_dir(char *dirname, int run_ioctl)
struct btrfs_fs_devices *tmp_devices;
u64 num_devices;
+ if(checklist)
+ init_device_checklist(BTRFSDEVICELIST);
+
INIT_LIST_HEAD(&pending_list);
pending = malloc(sizeof(*pending));
@@ -867,7 +1050,8 @@ again:
}
dirp = opendir(dirname);
if (!dirp) {
- fprintf(stderr, "Unable to open /sys/block for scanning\n");
+ fprintf(stderr, "Unable to open '%s' for scanning\n",
+ dirname);
return -ENOENT;
}
while(1) {
@@ -900,6 +1084,9 @@ again:
if (!S_ISBLK(st.st_mode)) {
continue;
}
+ if (checklist && !test_device(fullpath)){
+ continue;
+ }
fd = open(fullpath, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "failed to read %s\n", fullpath);
@@ -929,6 +1116,11 @@ fail:
return ret;
}
+int btrfs_scan_one_dir(char *dirname, int run_ioctl)
+{
+ return btrfs_scan_one_dir_checklist(dirname, run_ioctl, 0);
+}
+
int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64 total_devs,
int run_ioctls)
{
@@ -36,8 +36,13 @@ int btrfs_scan_for_fsid(struct btrfs_fs_devices *fs_devices, u64
total_devs,
int run_ioctls);
void btrfs_register_one_device(char *fname);
int btrfs_scan_one_dir(char *dirname, int run_ioctl);
+int btrfs_scan_one_dir_checklist(char *dirname, int run_ioctl, int checklist);
int check_mounted(const char *devicename);
int btrfs_device_already_in_root(struct btrfs_root *root, int fd,
int super_offset);
char *pretty_sizes(u64 size);
+int btrfs_scan_block_devices(int run_ioctl, int checklist);
+
+#define BTRFSDEVICELIST "/etc/btrfs.devices"
+