diff --git a/src/Makefile.am b/src/Makefile.am index 63b2250c5..e74cd800a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -89,6 +89,7 @@ libudisks_daemon_la_SOURCES = udisksthreadedjob.h udisksthreadedjob.c \ udiskssimplejob.h udiskssimplejob.c \ udisksmount.h udisksmount.c \ + udisksmountutil.h \ udisksmountmonitor.h udisksmountmonitor.c \ udisksdaemonutil.h udisksdaemonutil.c \ udiskslogging.h udiskslogging.c \ diff --git a/src/udisksmountmonitor.c b/src/udisksmountmonitor.c index 1c0c9b5e8..33db389f6 100644 --- a/src/udisksmountmonitor.c +++ b/src/udisksmountmonitor.c @@ -37,6 +37,7 @@ #include "udiskslogging.h" #include "udisksmountmonitor.h" #include "udisksmount.h" +#include "udisksmountutil.h" #include "udisksprivate.h" #include "udisksdaemonutil.h" @@ -510,46 +511,8 @@ udisks_mount_monitor_parse_mountinfo (UDisksMountMonitor *monitor, */ if (major == 0) { - const gchar *sep; - sep = strstr (lines[n], " - "); - if (sep != NULL) - { - gchar fstype[PATH_MAX + 1]; - gchar mount_source[PATH_MAX + 1]; - struct stat statbuf; - - if (sscanf (sep + 3, PATH_MAX_FMT " " PATH_MAX_FMT, fstype, mount_source) != 2) - { - udisks_warning ("Error parsing things past - for '%s'", lines[n]); - continue; - } - fstype[sizeof fstype - 1] = '\0'; - mount_source[sizeof mount_source - 1] = '\0'; - - if (g_strcmp0 (fstype, "btrfs") != 0) - continue; - - if (!g_str_has_prefix (mount_source, "/dev/")) - continue; - - if (stat (mount_source, &statbuf) != 0) - { - udisks_warning ("Error statting %s: %m", mount_source); - continue; - } - - if (!S_ISBLK (statbuf.st_mode)) - { - udisks_warning ("%s is not a block device", mount_source); - continue; - } - - dev = statbuf.st_rdev; - } - else - { - continue; - } + if (!udisks_mount_util_get_btrfs_device_from_mountinfo (lines[n], &dev)) + continue; } else { diff --git a/src/udisksmountutil.h b/src/udisksmountutil.h new file mode 100644 index 000000000..b41d58691 --- /dev/null +++ b/src/udisksmountutil.h @@ -0,0 +1,72 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2026 Wang Yu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __UDISKS_MOUNT_UTIL_H__ +#define __UDISKS_MOUNT_UTIL_H__ + +#include +#include +#include +#include +#include + +#include + +#define UDISKS_MOUNT_UTIL_XSTR(s) UDISKS_MOUNT_UTIL_STR(s) +#define UDISKS_MOUNT_UTIL_STR(s) #s +#define UDISKS_MOUNT_UTIL_PATH_MAX_FMT "%" UDISKS_MOUNT_UTIL_XSTR(PATH_MAX) "s" + +static gboolean +udisks_mount_util_get_btrfs_device_from_mountinfo (const gchar *line, + dev_t *block_device) +{ + const gchar *sep; + gchar fstype[PATH_MAX + 1]; + gchar mount_source[PATH_MAX + 1]; + struct stat statbuf; + + sep = strstr (line, " - "); + if (sep == NULL) + return FALSE; + + if (sscanf (sep + 3, + UDISKS_MOUNT_UTIL_PATH_MAX_FMT " " UDISKS_MOUNT_UTIL_PATH_MAX_FMT, + fstype, + mount_source) != 2) + return FALSE; + + fstype[sizeof fstype - 1] = '\0'; + mount_source[sizeof mount_source - 1] = '\0'; + + if (g_strcmp0 (fstype, "btrfs") != 0 || + !g_str_has_prefix (mount_source, "/dev/") || + stat (mount_source, &statbuf) != 0 || + !S_ISBLK (statbuf.st_mode)) + return FALSE; + + *block_device = statbuf.st_rdev; + return TRUE; +} + +#undef UDISKS_MOUNT_UTIL_PATH_MAX_FMT +#undef UDISKS_MOUNT_UTIL_STR +#undef UDISKS_MOUNT_UTIL_XSTR + +#endif /* __UDISKS_MOUNT_UTIL_H__ */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 5f9a84acc..b76cbb603 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -43,6 +43,7 @@ sbin_PROGRAMS = umount.udisks2 umount_udisks2_SOURCES = \ umount-udisks.c \ + $(top_srcdir)/src/udisksmountutil.h \ $(NULL) umount_udisks2_CFLAGS = \ diff --git a/tools/umount-udisks.c b/tools/umount-udisks.c index 6ced7f119..14db523c2 100644 --- a/tools/umount-udisks.c +++ b/tools/umount-udisks.c @@ -28,9 +28,60 @@ #include #include #include +#include #include +#include "src/udisksmountutil.h" + +#define xstr(s) str(s) +#define str(s) #s +#define PATH_MAX_FMT "%" xstr(PATH_MAX) "s" +#define PATH_MAX_SKIP_FMT "%*" xstr(PATH_MAX) "s" + +static gboolean +lookup_block_device_for_mount_point (const gchar *mount_point, + dev_t *block_device) +{ + gchar *contents = NULL; + gchar **lines = NULL; + guint n; + gboolean ret = FALSE; + + if (!g_file_get_contents ("/proc/self/mountinfo", &contents, NULL, NULL)) + return FALSE; + + lines = g_strsplit (contents, "\n", 0); + for (n = 0; lines[n] != NULL; n++) + { + gchar encoded_mount_point[PATH_MAX + 1]; + gchar *decoded_mount_point; + + if (strlen (lines[n]) == 0) + continue; + + if (sscanf (lines[n], + "%*u %*u %*u:%*u " PATH_MAX_SKIP_FMT " " PATH_MAX_FMT, + encoded_mount_point) != 1) + continue; + + encoded_mount_point[sizeof encoded_mount_point - 1] = '\0'; + decoded_mount_point = g_strcompress (encoded_mount_point); + + if (g_strcmp0 (decoded_mount_point, mount_point) == 0) + ret = udisks_mount_util_get_btrfs_device_from_mountinfo (lines[n], block_device); + + g_free (decoded_mount_point); + + if (ret) + break; + } + + g_strfreev (lines); + g_free (contents); + return ret; +} + static UDisksObject * lookup_object_for_block (UDisksClient *client, dev_t block_device) @@ -94,7 +145,7 @@ main (int argc, char *argv[]) if (S_ISBLK (statbuf.st_mode)) block_device = statbuf.st_rdev; - else + else if (!lookup_block_device_for_mount_point (argv[1], &block_device)) block_device = statbuf.st_dev; error = NULL;