Fix FreeBSD portability problem caused by it using character mode disk devices

We were using S_ISBLK() to test if a device could be used as a disk
device.  This doesn't work for FreeBSD.  We need to test for S_ISBLK()
|| S_ISCHR().

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
diff --git a/lib/blkid/blkidP.h b/lib/blkid/blkidP.h
index b90bfed..b3fe4a6 100644
--- a/lib/blkid/blkidP.h
+++ b/lib/blkid/blkidP.h
@@ -15,6 +15,12 @@
 
 #include <sys/types.h>
 #include <stdio.h>
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 
 #include <blkid/blkid.h>
 
@@ -152,6 +158,15 @@
 extern void blkid_debug_dump_tag(blkid_tag tag);
 #endif
 
+static inline int blkidP_is_disk_device(mode_t mode)
+{
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	return S_ISBLK(mode) || S_ISCHR(mode);
+#else
+	return S_ISBLK(mode);
+#endif
+}
+
 /* devno.c */
 struct dir_list {
 	char	*name;
diff --git a/lib/blkid/devname.c b/lib/blkid/devname.c
index 671e781..f3956da 100644
--- a/lib/blkid/devname.c
+++ b/lib/blkid/devname.c
@@ -231,7 +231,8 @@
 		    dev->bid_devno == devno)
 			goto set_pri;
 
-		if (stat(device, &st) == 0 && S_ISBLK(st.st_mode) &&
+		if (stat(device, &st) == 0 &&
+		    blkidP_is_disk_device(st.st_mode) &&
 		    st.st_rdev == devno) {
 			devname = blkid_strdup(device);
 			goto get_dev;
diff --git a/lib/blkid/devno.c b/lib/blkid/devno.c
index 480030f..34ceb3c 100644
--- a/lib/blkid/devno.c
+++ b/lib/blkid/devno.c
@@ -119,7 +119,7 @@
 		if (stat(path, &st) < 0)
 			continue;
 
-		if (S_ISBLK(st.st_mode) && st.st_rdev == devno) {
+		if (blkidP_is_disk_device(st.st_mode) && st.st_rdev == devno) {
 			*devname = blkid_strdup(path);
 			DBG(DEBUG_DEVNO,
 			    printf("found 0x%llx at %s (%p)\n", (long long)devno,
diff --git a/lib/blkid/getsize.c b/lib/blkid/getsize.c
index 8e8eb4c..4e2835f 100644
--- a/lib/blkid/getsize.c
+++ b/lib/blkid/getsize.c
@@ -149,7 +149,7 @@
 		 * character) devices, so we need to check for S_ISCHR, too.
 		 */
 		if (fstat(fd, &st) >= 0 &&
-		    (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)))
+		    blkidP_is_disk_device(st.st_mode))
 			part = st.st_rdev & 7;
 
 		if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
diff --git a/lib/ext2fs/blkmap64_rb.c b/lib/ext2fs/blkmap64_rb.c
index 7e7e29d..448318c 100644
--- a/lib/ext2fs/blkmap64_rb.c
+++ b/lib/ext2fs/blkmap64_rb.c
@@ -9,6 +9,7 @@
  * %End-Header%
  */
 
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #if HAVE_UNISTD_H
diff --git a/lib/ext2fs/ext2fsP.h b/lib/ext2fs/ext2fsP.h
index 8de9d33..9d001d5 100644
--- a/lib/ext2fs/ext2fsP.h
+++ b/lib/ext2fs/ext2fsP.h
@@ -9,10 +9,23 @@
  * %End-Header%
  */
 
+#if HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
 #include "ext2fs.h"
 
 #define EXT2FS_MAX_NESTED_LINKS  8
 
+static inline int ext2fsP_is_disk_device(mode_t mode)
+{
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	return S_ISBLK(mode) || S_ISCHR(mode);
+#else
+	return S_ISBLK(mode);
+#endif
+}
+
 /*
  * Badblocks list
  */
diff --git a/lib/ext2fs/finddev.c b/lib/ext2fs/finddev.c
index 62fa0db..cd85ef5 100644
--- a/lib/ext2fs/finddev.c
+++ b/lib/ext2fs/finddev.c
@@ -104,7 +104,8 @@
 			goto skip_to_next;
 		if (S_ISDIR(st.st_mode))
 			add_to_dirlist(path, list);
-		if (S_ISBLK(st.st_mode) && st.st_rdev == device) {
+		if (ext2fsP_is_disk_device(st.st_mode) &&
+		    st.st_rdev == device) {
 			cp = malloc(strlen(path)+1);
 			if (!cp) {
 				closedir(dir);
diff --git a/lib/ext2fs/ismounted.c b/lib/ext2fs/ismounted.c
index 120299c..6cd497d 100644
--- a/lib/ext2fs/ismounted.c
+++ b/lib/ext2fs/ismounted.c
@@ -55,6 +55,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 #ifdef HAVE_SETMNTENT
 /*
@@ -115,7 +116,7 @@
 		return errno;
 	}
 	if (stat(file, &st_buf) == 0) {
-		if (S_ISBLK(st_buf.st_mode)) {
+		if (ext2fsP_is_disk_device(st_buf.st_mode)) {
 #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
 			file_rdev = st_buf.st_rdev;
 #endif	/* __GNU__ */
@@ -130,7 +131,7 @@
 		if (strcmp(file, mnt->mnt_fsname) == 0)
 			break;
 		if (stat(mnt->mnt_fsname, &st_buf) == 0) {
-			if (S_ISBLK(st_buf.st_mode)) {
+			if (ext2fsP_is_disk_device(st_buf.st_mode)) {
 #ifndef __GNU__
 				if (file_rdev && (file_rdev == st_buf.st_rdev))
 					break;
@@ -310,7 +311,7 @@
 	file_dev = 0;
 #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */
 	if ((stat(file, &st_buf) == 0) &&
-	    S_ISBLK(st_buf.st_mode))
+	    ext2fsP_is_disk_device(st_buf.st_mode))
 		file_dev = st_buf.st_rdev;
 #endif	/* __GNU__ */
 
@@ -337,7 +338,7 @@
 		}
 #ifndef __GNU__
 		if (file_dev && (stat(buf, &st_buf) == 0) &&
-		    S_ISBLK(st_buf.st_mode) &&
+		    ext2fsP_is_disk_device(st_buf.st_mode) &&
 		    file_dev == st_buf.st_rdev) {
 			ret++;
 			break;
@@ -404,7 +405,8 @@
 	{
 		struct stat st_buf;
 
-		if (stat(device, &st_buf) == 0 && S_ISBLK(st_buf.st_mode)) {
+		if (stat(device, &st_buf) == 0 &&
+		    ext2fsP_is_disk_device(st_buf.st_mode)) {
 			int fd = open(device, O_RDONLY | O_EXCL);
 
 			if (fd >= 0)
diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
index 6414195..c2ce9a1 100644
--- a/lib/ext2fs/unix_io.c
+++ b/lib/ext2fs/unix_io.c
@@ -76,6 +76,7 @@
 
 #include "ext2_fs.h"
 #include "ext2fs.h"
+#include "ext2fsP.h"
 
 /*
  * For checking structure magic numbers...
@@ -611,7 +612,7 @@
 	 * zero.
 	 */
 	if (ext2fs_fstat(data->dev, &st) == 0) {
-		if (S_ISBLK(st.st_mode))
+		if (ext2fsP_is_disk_device(st.st_mode))
 			io->flags |= CHANNEL_FLAGS_BLOCK_DEVICE;
 		else
 			io->flags |= CHANNEL_FLAGS_DISCARD_ZEROES;
@@ -682,7 +683,7 @@
 	     (ut.release[4] == '1') && (ut.release[5] >= '0') &&
 	     (ut.release[5] < '8')) &&
 	    (ext2fs_fstat(data->dev, &st) == 0) &&
-	    (S_ISBLK(st.st_mode))) {
+	    (ext2fsP_is_disk_device(st.st_mode))) {
 		struct rlimit	rlim;
 
 		rlim.rlim_cur = rlim.rlim_max = (unsigned long) RLIM_INFINITY;
diff --git a/misc/e2image.c b/misc/e2image.c
index e0c3188..030f9cb 100644
--- a/misc/e2image.c
+++ b/misc/e2image.c
@@ -43,6 +43,7 @@
 
 #include "ext2fs/ext2_fs.h"
 #include "ext2fs/ext2fs.h"
+#include "ext2fs/ext2fsP.h"
 #include "et/com_err.h"
 #include "uuid/uuid.h"
 #include "e2p/e2p.h"
@@ -1620,7 +1621,7 @@
 				_("Can not stat output\n"));
 			exit(1);
 		}
-		if (S_ISBLK(st.st_mode))
+		if (ext2fsP_is_disk_device(st.st_mode))
 			output_is_blk = 1;
 	}
 	if (flags & E2IMAGE_IS_QCOW2_FLAG) {