From 2f48e4cef4b8dae45b291afbe6c4146b97c61415 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Fri, 30 May 2008 21:48:45 -0400 Subject: [PATCH] use a mount monitor based on /proc/mounts instead of gio's mount monitor Also add a hack to work around the fact that device-mapper create it's own device nodes. --- src/Makefile.am | 1 + src/devkit-disks-daemon.c | 43 +++--- src/devkit-disks-mount-monitor.c | 276 +++++++++++++++++++++++++++++++++++++++ src/devkit-disks-mount-monitor.h | 70 ++++++++++ 4 files changed, 366 insertions(+), 24 deletions(-) create mode 100644 src/devkit-disks-mount-monitor.c create mode 100644 src/devkit-disks-mount-monitor.h diff --git a/src/Makefile.am b/src/Makefile.am index 91c5e85..417ddd7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,6 +44,7 @@ devkit_disks_daemon_SOURCES = \ devkit-disks-device.h devkit-disks-device.c \ devkit-disks-device-private.h \ mounts-file.h mounts-file.c \ + devkit-disks-mount-monitor.h devkit-disks-mount-monitor.c \ main.c \ $(BUILT_SOURCES) diff --git a/src/devkit-disks-daemon.c b/src/devkit-disks-daemon.c index 6042c72..c553b83 100644 --- a/src/devkit-disks-daemon.c +++ b/src/devkit-disks-daemon.c @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -54,6 +53,7 @@ #include "devkit-disks-device.h" #include "devkit-disks-device-private.h" #include "mounts-file.h" +#include "devkit-disks-mount-monitor.h" #include "devkit-disks-daemon-glue.h" #include "devkit-disks-marshal.h" @@ -74,23 +74,23 @@ static guint signals[LAST_SIGNAL] = { 0 }; struct DevkitDisksDaemonPrivate { - DBusGConnection *system_bus_connection; - DBusGProxy *system_bus_proxy; - PolKitContext *pk_context; - PolKitTracker *pk_tracker; + DBusGConnection *system_bus_connection; + DBusGProxy *system_bus_proxy; + PolKitContext *pk_context; + PolKitTracker *pk_tracker; - DevkitClient *devkit_client; + DevkitClient *devkit_client; - GIOChannel *mdstat_channel; + GIOChannel *mdstat_channel; - GHashTable *map_native_path_to_device; - GHashTable *map_object_path_to_device; + GHashTable *map_native_path_to_device; + GHashTable *map_object_path_to_device; - GUnixMountMonitor *mount_monitor; + DevkitDisksMountMonitor *mount_monitor; - guint smart_refresh_timer_id; + guint smart_refresh_timer_id; - DevkitDisksLogger *logger; + DevkitDisksLogger *logger; }; static void devkit_disks_daemon_class_init (DevkitDisksDaemonClass *klass); @@ -114,17 +114,15 @@ devkit_disks_daemon_local_update_mount_state (DevkitDisksDaemon *daemon, GList * devices_copy = g_list_copy (devices); - /* TODO: cache the mounts list to avoid rereading every time */ - mounts = g_unix_mounts_get (NULL); + mounts = devkit_disks_mount_monitor_get_mounts (daemon->priv->mount_monitor); for (l = mounts; l != NULL; l = l->next) { - GUnixMountEntry *mount_entry = l->data; + DevkitDisksMount *mount_entry = l->data; const char *device_file; const char *mount_path; - /* TODO: maybe use realpath() on the device_path */ - device_file = g_unix_mount_get_device_path (mount_entry); - mount_path = g_unix_mount_get_mount_path (mount_entry); + device_file = devkit_disks_mount_get_device_path (mount_entry); + mount_path = devkit_disks_mount_get_mount_path (mount_entry); for (j = devices_copy; j != NULL; j = jj) { DevkitDisksDevice *device = j->data; @@ -159,7 +157,7 @@ devkit_disks_daemon_local_update_mount_state (DevkitDisksDaemon *daemon, GList * } } } - g_list_foreach (mounts, (GFunc) g_unix_mount_free, NULL); + g_list_foreach (mounts, (GFunc) devkit_disks_mount_unref, NULL); g_list_free (mounts); /* Since we've removed mounted devices from the devices_copy @@ -580,7 +578,7 @@ devkit_disks_daemon_local_get_all_devices (DevkitDisksDaemon *daemon) } static void -mounts_changed (GUnixMountMonitor *monitor, gpointer user_data) +mounts_changed (DevkitDisksMountMonitor *monitor, gpointer user_data) { DevkitDisksDaemon *daemon = DEVKIT_DISKS_DAEMON (user_data); GList *devices; @@ -767,10 +765,7 @@ register_disks_daemon (DevkitDisksDaemon *daemon) g_signal_connect (daemon->priv->devkit_client, "device-event", G_CALLBACK (device_event_signal_handler), daemon); - /* monitor mounts */ - daemon->priv->mount_monitor = g_unix_mount_monitor_new (); - // See http://bugzilla.gnome.org/show_bug.cgi?id=521946 - //g_unix_mount_monitor_set_rate_limit (daemon->priv->mount_monitor, 50); + daemon->priv->mount_monitor = devkit_disks_mount_monitor_new (); g_signal_connect (daemon->priv->mount_monitor, "mounts-changed", (GCallback) mounts_changed, daemon); daemon->priv->logger = devkit_disks_logger_new (); diff --git a/src/devkit-disks-mount-monitor.c b/src/devkit-disks-mount-monitor.c new file mode 100644 index 0000000..90f82ad --- /dev/null +++ b/src/devkit-disks-mount-monitor.c @@ -0,0 +1,276 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "devkit-disks-mount-monitor.h" + +/*--------------------------------------------------------------------------------------------------------------*/ + +enum +{ + MOUNTS_CHANGED_SIGNAL, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +struct DevkitDisksMountMonitorPrivate +{ + GIOChannel *mounts_channel; +}; + +static GObjectClass *parent_class = NULL; + +G_DEFINE_TYPE (DevkitDisksMountMonitor, devkit_disks_mount_monitor, G_TYPE_OBJECT) + +#define DEVKIT_DISKS_MOUNT_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), DEVKIT_TYPE_DISKS_MOUNT_MONITOR, DevkitDisksMountMonitorPrivate)) + +static void +devkit_disks_mount_monitor_finalize (DevkitDisksMountMonitor *mount_monitor) +{ + if (mount_monitor->priv->mounts_channel != NULL) + g_io_channel_unref (mount_monitor->priv->mounts_channel); + if (G_OBJECT_CLASS (parent_class)->finalize) + (* G_OBJECT_CLASS (parent_class)->finalize) (G_OBJECT (mount_monitor)); +} + +static void +devkit_disks_mount_monitor_init (DevkitDisksMountMonitor *mount_monitor) +{ + mount_monitor->priv = DEVKIT_DISKS_MOUNT_MONITOR_GET_PRIVATE (mount_monitor); +} + +static void +devkit_disks_mount_monitor_class_init (DevkitDisksMountMonitorClass *klass) +{ + GObjectClass *obj_class = (GObjectClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + obj_class->finalize = (GObjectFinalizeFunc) devkit_disks_mount_monitor_finalize; + + g_type_class_add_private (klass, sizeof (DevkitDisksMountMonitorPrivate)); + + signals[MOUNTS_CHANGED_SIGNAL] = + g_signal_new ("mounts-changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static gboolean +mounts_changed_event (GIOChannel *channel, GIOCondition cond, gpointer user_data) +{ + DevkitDisksMountMonitor *mount_monitor = DEVKIT_DISKS_MOUNT_MONITOR (user_data); + + if (cond & ~G_IO_ERR) + goto out; + + g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED_SIGNAL], 0); + +out: + return TRUE; +} + +DevkitDisksMountMonitor * +devkit_disks_mount_monitor_new (void) +{ + DevkitDisksMountMonitor *mount_monitor; + GError *error; + + mount_monitor = DEVKIT_DISKS_MOUNT_MONITOR (g_object_new (DEVKIT_TYPE_DISKS_MOUNT_MONITOR, NULL)); + + error = NULL; + mount_monitor->priv->mounts_channel = g_io_channel_new_file ("/proc/mounts", "r", &error); + if (mount_monitor->priv->mounts_channel != NULL) { + g_io_add_watch (mount_monitor->priv->mounts_channel, G_IO_ERR, mounts_changed_event, mount_monitor); + } else { + g_warning ("No /proc/mounts file: %s", error->message); + g_error_free (error); + g_object_unref (mount_monitor); + mount_monitor = NULL; + goto out; + } + +out: + return mount_monitor; +} + +struct DevkitDisksMount { + char *mount_path; + char *device_path; +}; + +void +devkit_disks_mount_unref (DevkitDisksMount *mount) +{ + g_free (mount->mount_path); + g_free (mount->device_path); + g_free (mount); +} + +const char * +devkit_disks_mount_get_mount_path (DevkitDisksMount *mount) +{ + return mount->mount_path; +} + +const char * +devkit_disks_mount_get_device_path (DevkitDisksMount *mount) +{ + return mount->device_path; +} + +static const char * +_resolve_dev_root (void) +{ + static gboolean have_real_dev_root = FALSE; + static char real_dev_root[256]; + struct stat statbuf; + + /* see if it's cached already */ + if (have_real_dev_root) + goto found; + + /* otherwise we're going to find it right away.. */ + have_real_dev_root = TRUE; + + if (stat ("/dev/root", &statbuf) == 0) { + if (! S_ISLNK (statbuf.st_mode)) { + dev_t root_dev = statbuf.st_dev; + FILE *f; + char buf[1024]; + + /* see if device with similar major:minor as /dev/root is mentioned + * in /etc/mtab (it usually is) + */ + f = fopen ("/etc/mtab", "r"); + if (f != NULL) { + struct mntent *entp; + struct mntent ent; + while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL) { + if (stat (entp->mnt_fsname, &statbuf) == 0 && + statbuf.st_dev == root_dev) { + strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1); + real_dev_root[sizeof (real_dev_root) - 1] = '\0'; + fclose (f); + goto found; + } + } + endmntent (f); + } + /* no, that didn't work.. next we could scan /dev ... but I digress.. */ + } else { + char resolved[PATH_MAX]; + if (realpath ("/dev/root", resolved) != NULL) { + strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1); + real_dev_root[sizeof (real_dev_root) - 1] = '\0'; + goto found; + } + } + } + + /* bah sucks.. */ + strcpy (real_dev_root, "/dev/root"); +found: + return real_dev_root; +} + +/* device-mapper likes to create it's own device nodes a'la /dev/mapper/VolGroup00-LogVol00; + * this is pretty useless... So check the major/minor and map back to /dev/dm- + * if major==253. + */ +static char * +_check_lvm (const char *device_path) +{ + struct stat statbuf; + if (stat (device_path, &statbuf) == 0) { + g_warning ("major=%d minor=%d", major (statbuf.st_rdev), minor (statbuf.st_rdev)); + if (major (statbuf.st_rdev) == 253) { + return g_strdup_printf ("/dev/dm-%d", minor (statbuf.st_rdev)); + } + } + + return NULL; +} + +GList * +devkit_disks_mount_monitor_get_mounts (DevkitDisksMountMonitor *mount_monitor) +{ + GList *ret; + struct mntent *m; + FILE *f; + + /* TODO: cache this list */ + + ret = NULL; + + f = fopen ("/proc/mounts", "r"); + if (f == NULL) { + g_warning ("error opening /proc/mounts: %m"); + goto out; + } + while ((m = getmntent (f)) != NULL) { + DevkitDisksMount *mount; + mount = g_new0 (DevkitDisksMount, 1); + if (strcmp (m->mnt_fsname, "/dev/root") == 0) { + mount->device_path = g_strdup (_resolve_dev_root ()); + } else { + mount->device_path = g_strdup (m->mnt_fsname); + } + + if (g_str_has_prefix (mount->device_path, "/dev/mapper/")) { + char *s; + s = _check_lvm (m->mnt_fsname); + if (s != NULL) { + g_free (mount->device_path); + mount->device_path = s; + } + } + + mount->mount_path = g_strdup (m->mnt_dir); + ret = g_list_prepend (ret, mount); + } + fclose (f); + + ret = g_list_reverse (ret); + +out: + return ret; +} diff --git a/src/devkit-disks-mount-monitor.h b/src/devkit-disks-mount-monitor.h new file mode 100644 index 0000000..6f70dfc --- /dev/null +++ b/src/devkit-disks-mount-monitor.h @@ -0,0 +1,70 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2008 David Zeuthen + * + * 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 __DEVKIT_DISKS_MOUNT_MONITOR_H__ +#define __DEVKIT_DISKS_MOUNT_MONITOR_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define DEVKIT_TYPE_DISKS_MOUNT_MONITOR (devkit_disks_mount_monitor_get_type ()) +#define DEVKIT_DISKS_MOUNT_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DEVKIT_TYPE_DISKS_MOUNT_MONITOR, DevkitDisksMountMonitor)) +#define DEVKIT_DISKS_MOUNT_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), DEVKIT_TYPE_DISKS_MOUNT_MONITOR, DevkitDisksMountMonitorClass)) +#define DEVKIT_IS_DISKS_MOUNT_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DEVKIT_TYPE_DISKS_MOUNT_MONITOR)) +#define DEVKIT_IS_DISKS_MOUNT_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DEVKIT_TYPE_DISKS_MOUNT_MONITOR)) +#define DEVKIT_DISKS_MOUNT_MONITOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DEVKIT_TYPE_DISKS_MOUNT_MONITOR, DevkitDisksMountMonitorClass)) + +struct DevkitDisksMountMonitorPrivate; +typedef struct DevkitDisksMountMonitorPrivate DevkitDisksMountMonitorPrivate; + +typedef struct +{ + GObject parent; + DevkitDisksMountMonitorPrivate *priv; +} DevkitDisksMountMonitor; + +typedef struct +{ + GObjectClass parent_class; +} DevkitDisksMountMonitorClass; + +typedef gboolean (*DevkitDisksMountMonitorForeachFunc) (const char *device_path, + const char *mount_path, + const char *fstype, + const char *options, + gpointer user_data); + +GType devkit_disks_mount_monitor_get_type (void); +DevkitDisksMountMonitor *devkit_disks_mount_monitor_new (void); +GList *devkit_disks_mount_monitor_get_mounts (DevkitDisksMountMonitor *mount_monitor); + +struct DevkitDisksMount; +typedef struct DevkitDisksMount DevkitDisksMount; + +void devkit_disks_mount_unref (DevkitDisksMount *mount); +const char *devkit_disks_mount_get_mount_path (DevkitDisksMount *mount); +const char *devkit_disks_mount_get_device_path (DevkitDisksMount *mount); + +G_END_DECLS + +#endif /* __DEVKIT_DISKS_MOUNT_MONITOR_H__ */ -- 2.7.4