aboutsummaryrefslogtreecommitdiffstats
path: root/filesystems
diff options
context:
space:
mode:
authorMatthias Andree <mandree@FreeBSD.org>2025-09-30 00:30:47 +0200
committerMatthias Andree <mandree@FreeBSD.org>2025-09-30 01:09:52 +0200
commitfd46b8c7f0d78952a1a60e56aacccbdccdc76dc1 (patch)
tree5d6ec03a43dcfe95376c76a87ced188e99d9a334 /filesystems
parent4aea75ddb74a4dee0c57f43687151ff8a6892cb4 (diff)
filesystems/libblkid: fix odd reads and fdisk
TL;DR: This fixes "invalid argument" in util-linux's fdisk. libblkid assumes buffered block devices, skipping most character devices (unless their name starts with "ubi") and failing because it tries reads that aren't a multiple of the underlying I/O size. Detail: util-linux assumes a Linux-like behavior and naming of devices, and assumes it's looking at buffered block devices, which FreeBSD has not been provided for many major releases. It also requires specific layouts of procfs, sysfs, devfs, which FreeBSD or its Linuxulator does not provide. So we specifically need to patch the read_buffer function to make sure it rounds up its read size to the io_size (often 512) and not attempt to read 36, 256, 548 or other strange sizes and emulate a buffered disk character device; we also need to patch many of the S_ISCHR checks so they accept our character devices. This patching is apparently enough to fix the "invalid argument" (EINVAL, errno==22) errors from the util-linux fdisk tools. This patch set is not complete, but is sufficient to get the util-linux fdisk/cfdisk/sfdisk back up to their feet so we can nuke the dangerous linuxfdisk port now and for good. Note that many uses will require sysctl to allow foot-shooting by setting kern.geom.debugflags=16. blkid can not yet enumerate disk character devices if run without argument. Approved by: portmgr@ (blanket just-fix it) Could the port maintainer please check with the upstream what their stance on supporting non-GNU userspaces and non-Linux kernels is? Can we work with them to get such fixes upstreamed or will they turn us down because the tools are specifically called "util-linux"?
Diffstat (limited to 'filesystems')
-rw-r--r--filesystems/libblkid/Makefile2
-rw-r--r--filesystems/libblkid/files/patch-libblkid_src_devname.c30
-rw-r--r--filesystems/libblkid/files/patch-libblkid_src_probe.c49
-rw-r--r--filesystems/libblkid/files/patch-misc-utils_blkid.c18
4 files changed, 98 insertions, 1 deletions
diff --git a/filesystems/libblkid/Makefile b/filesystems/libblkid/Makefile
index 077bc2158912..3367ae62ac6b 100644
--- a/filesystems/libblkid/Makefile
+++ b/filesystems/libblkid/Makefile
@@ -1,7 +1,7 @@
PORTNAME= libblkid
DISTVERSIONPREFIX= v
DISTVERSION= 2.41.1
-PORTREVISION= 1
+PORTREVISION= 2
CATEGORIES= filesystems
MAINTAINER= arrowd@FreeBSD.org
diff --git a/filesystems/libblkid/files/patch-libblkid_src_devname.c b/filesystems/libblkid/files/patch-libblkid_src_devname.c
new file mode 100644
index 000000000000..cf1040ef3f52
--- /dev/null
+++ b/filesystems/libblkid/files/patch-libblkid_src_devname.c
@@ -0,0 +1,30 @@
+--- libblkid/src/devname.c.orig 2025-06-24 07:55:28 UTC
++++ libblkid/src/devname.c
+@@ -224,7 +224,11 @@ static void probe_one(blkid_cache cache, const char *p
+
+ if (stat(device, &st) == 0 &&
+ (S_ISBLK(st.st_mode) ||
+- (S_ISCHR(st.st_mode) && !strncmp(ptname, "ubi", 3))) &&
++ (S_ISCHR(st.st_mode)
++#ifdef __linux__
++ && !strncmp(ptname, "ubi", 3)
++#endif
++ )) &&
+ st.st_rdev == devno) {
+ devname = strdup(device);
+ goto get_dev;
+@@ -251,8 +255,12 @@ set_pri:
+ dev->bid_pri = BLKID_PRI_DM;
+ if (is_dm_leaf(ptname))
+ dev->bid_pri += 5;
+- } else if (!strncmp(ptname, "md", 2))
+- dev->bid_pri = BLKID_PRI_MD;
++ } else {
++#ifdef __linux__
++ if (!strncmp(ptname, "md", 2))
++ dev->bid_pri = BLKID_PRI_MD;
++#endif
++ }
+ if (removable)
+ dev->bid_flags |= BLKID_BID_FL_REMOVABLE;
+ }
diff --git a/filesystems/libblkid/files/patch-libblkid_src_probe.c b/filesystems/libblkid/files/patch-libblkid_src_probe.c
new file mode 100644
index 000000000000..aecc99b2b03b
--- /dev/null
+++ b/filesystems/libblkid/files/patch-libblkid_src_probe.c
@@ -0,0 +1,49 @@
+--- libblkid/src/probe.c.orig 2025-06-24 07:55:28 UTC
++++ libblkid/src/probe.c
+@@ -594,7 +594,18 @@ static struct blkid_bufinfo *read_buffer(blkid_probe p
+ DBG(LOWPROBE, ul_debug("\tread: off=%"PRIu64" len=%"PRIu64"",
+ real_off, len));
+
+- ret = read(pr->fd, bf->data, len);
++ /* on FreeBSD, devices are unbuffered so we need to align to full I/O blocks by ourselves */
++ if (len % pr->io_size) {
++ unsigned rawlen = len + (pr->io_size - len % pr->io_size);
++ char buf[rawlen];
++ ret = read(pr->fd, buf, rawlen);
++ if (ret < 0 || ret < len)
++ return NULL;
++ memcpy(bf->data, buf, len);
++ ret = len;
++ } else {
++ ret = read(pr->fd, bf->data, len);
++ }
+ if (ret != (ssize_t) len) {
+ DBG(LOWPROBE, ul_debug("\tread failed: %m"));
+ remove_buffer(bf);
+@@ -718,7 +729,7 @@ const unsigned char *blkid_probe_get_buffer(blkid_prob
+ struct blkid_bufinfo *bf = NULL;
+ uint64_t real_off, bias, len_align;
+
+- bias = off % pr->io_size;
++ bias = off % /* pr->io_size */ 4096;
+ off -= bias;
+ len += bias;
+
+@@ -1106,6 +1117,7 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
+ goto err;
+ }
+ } else if (S_ISCHR(sb.st_mode)) {
++#ifdef __linux__
+ char buf[PATH_MAX];
+
+ if (!sysfs_chrdev_devno_to_devname(sb.st_rdev, buf, sizeof(buf))
+@@ -1114,6 +1126,9 @@ int blkid_probe_set_device(blkid_probe pr, int fd,
+ errno = EINVAL;
+ goto err;
+ }
++#else
++ /* no-op, FreeBSD maps block devices as character */
++#endif
+ devsiz = 1; /* UBI devices are char... */
+ } else if (S_ISREG(sb.st_mode))
+ devsiz = sb.st_size; /* regular file */
diff --git a/filesystems/libblkid/files/patch-misc-utils_blkid.c b/filesystems/libblkid/files/patch-misc-utils_blkid.c
new file mode 100644
index 000000000000..6fe581bc1c13
--- /dev/null
+++ b/filesystems/libblkid/files/patch-misc-utils_blkid.c
@@ -0,0 +1,18 @@
+--- misc-utils/blkid.c.orig 2025-06-24 07:55:28 UTC
++++ misc-utils/blkid.c
+@@ -876,6 +876,7 @@ int main(int argc, char **argv)
+ else if (S_ISREG(sb.st_mode))
+ ;
+ else if (S_ISCHR(sb.st_mode)) {
++#ifdef __linux__
+ char buf[PATH_MAX];
+
+ if (!sysfs_chrdev_devno_to_devname(
+@@ -883,6 +884,7 @@ int main(int argc, char **argv)
+ continue;
+ if (strncmp(buf, "ubi", 3) != 0)
+ continue;
++#endif
+ } else
+ continue;
+