Scan the devices listed in /proc/partitions

During the commands:
	- btrfs filesystem show
	- btrfs device scan
the devices "scanned" are extracted from /proc/partitions. This
should avoid to scan devices not suitable for a btrfs filesystem like cdrom
and floppy or to scan not existant devices.
The old behavior (scan all the block devices under /dev) may be
forced passing the "--all-devices" switch.
diff --git a/btrfs.c b/btrfs.c
index a48f07b..c16dc60 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -109,7 +109,7 @@
 	  NULL
 	},
 	{ do_show_filesystem, 999,
-	  "filesystem show", "[<device>|<uuid>|<label>]\n"
+	  "filesystem show", "[--all-devices][<uuid>|<label>]\n"
 		"Show the info of a btrfs filesystem. If no argument\n"
 		"is passed, info of all the btrfs filesystem are shown.",
 	  NULL
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index d099847..ecdae16 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -607,11 +607,29 @@
 int do_scan(int argc, char **argv)
 {
 	int	i, fd, e;
-	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);
+		if(checklist)
+			ret = btrfs_scan_block_devices(1);
+		else
+			ret = btrfs_scan_one_dir("/dev", 1);
 		if (ret){
 			fprintf(stderr, "ERROR: error %d while scanning\n", ret);
 			return 18;
@@ -625,7 +643,7 @@
 		return 10;
 	}
 
-	for( i = 1 ; i < argc ; i++ ){
+	for( i = devstart ; i < argc ; i++ ){
 		struct btrfs_ioctl_vol_args args;
 		int ret;
 
@@ -748,14 +766,33 @@
 	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;
+	}	
+
+	if(checklist)
+		ret = btrfs_scan_block_devices(0);
+	else
+		ret = btrfs_scan_one_dir("/dev", 0);
+
 	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) {
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index e830abd..ab9f44f 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -31,9 +31,9 @@
 .PP
 \fBbtrfs\fP \fBfilesystem defragment\fP\fI <file>|<dir> [<file>|<dir>...]\fP
 .PP
-\fBbtrfs\fP \fBdevice scan\fP\fI [<device>...]\fP
+\fBbtrfs\fP \fBdevice scan\fP\fI [--all-devices|<device> [<device>...]]\fP
 .PP
-\fBbtrfs\fP \fBdevice show\fP\fI [<device>|<uuid>|<label>]\fP
+\fBbtrfs\fP \fBdevice show\fP\fI [--all-devices|<uuid>|<label>]\fP
 .PP
 \fBbtrfs\fP \fBdevice add\fP\fI <device> [<device>...] <path> \fP
 .PP
@@ -153,11 +153,6 @@
 List the recently modified files in a subvolume, after \fI<last_gen>\fR ID.
 .TP
 
-\fBdevice scan\fR \fI[<device>...]\fR
-Scan devices for a btrfs filesystem. If no devices are passed, \fBbtrfs\fR scans
-all the block devices.
-.TP
-
 \fBfilesystem sync\fR\fI <path> \fR
 Force a sync for the filesystem identified by \fI<path>\fR.
 .TP
@@ -202,9 +197,11 @@
 - the filesystem should not have more than one device.
 .TP
 
-\fBfilesystem show\fR [<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.
+\fBfilesystem show\fR [--all-devices|<uuid>|<label>]\fR
+Show the btrfs filesystem with some additional info. If no \fIUUID\fP or 
+\fIlabel\fP is passed, \fBbtrfs\fR show info of all the btrfs filesystem.
+If \fB--all-devices\fP is passed, all the devices under /dev are scanned;
+otherwise the devices list is extracted from the /proc/partitions file.
 .TP
 
 \fBdevice balance\fR \fI<path>\fR
@@ -218,7 +215,15 @@
 
 \fBdevice delete\fR\fI <dev> [<dev>..] <path>\fR
 Remove device(s) from a filesystem identified by \fI<path>\fR.
-.PP
+.TP
+
+\fBdevice scan\fR \fI[--all-devices|<device> [<device>...]\fR
+If one or more devices are passed, these are scanned for a btrfs filesystem. 
+If no devices are passed, \fBbtrfs\fR scans all the block devices listed
+in the /proc/partitions file.
+Finally, if \fB--all-devices\fP is passed, all the devices under /dev are 
+scanned.
+.TP
 
 \fBscrub start\fP [-Bdqru] {\fI<path>\fP|\fI<device>\fP}
 Start a scrub on all devices of the filesystem identified by \fI<path>\fR or on
diff --git a/utils.c b/utils.c
index 8c80cfb..86c643c 100644
--- a/utils.c
+++ b/utils.c
@@ -1114,3 +1114,61 @@
 
        return 0;
 }
+
+int btrfs_scan_block_devices(int run_ioctl)
+{
+
+	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 fullpath[110];
+
+	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;
+		}
+
+		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;
+}
+
diff --git a/utils.h b/utils.h
index 02b3fe9..c5f55e1 100644
--- a/utils.h
+++ b/utils.h
@@ -44,4 +44,6 @@
 char *pretty_sizes(u64 size);
 int check_label(char *input);
 int get_mountpt(char *dev, char *mntpt, size_t size);
+
+int btrfs_scan_block_devices(int run_ioctl);
 #endif