1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2006-2007 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
22 * Author: Alexander Larsson <alexl@redhat.com>
27 #include <sys/types.h>
30 #ifndef HAVE_SYSCTLBYNAME
31 #ifdef HAVE_SYS_PARAM_H
32 #include <sys/param.h>
34 #ifdef HAVE_SYS_POLL_H
51 #include <sys/statfs.h>
53 #if HAVE_SYS_STATVFS_H
54 #include <sys/statvfs.h>
58 #elif HAVE_SYS_MOUNT_H
60 #include <sys/param.h>
62 #include <sys/mount.h>
69 #include "gunixmounts.h"
71 #include "gfilemonitor.h"
73 #include "gthemedicon.h"
77 static const char *_resolve_dev_root (void);
82 * @include: gio/gunixmounts.h
83 * @short_description: UNIX mounts
85 * Routines for managing mounted UNIX mount points and paths.
87 * Note that <filename><gio/gunixmounts.h></filename> belongs to the
88 * UNIX-specific GIO interfaces, thus you have to use the
89 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
94 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
95 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
96 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
97 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
98 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
99 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
100 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
101 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
102 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
103 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
104 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
105 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
106 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
108 * Types of UNIX mounts.
111 G_UNIX_MOUNT_TYPE_UNKNOWN,
112 G_UNIX_MOUNT_TYPE_FLOPPY,
113 G_UNIX_MOUNT_TYPE_CDROM,
114 G_UNIX_MOUNT_TYPE_NFS,
115 G_UNIX_MOUNT_TYPE_ZIP,
116 G_UNIX_MOUNT_TYPE_JAZ,
117 G_UNIX_MOUNT_TYPE_MEMSTICK,
118 G_UNIX_MOUNT_TYPE_CF,
119 G_UNIX_MOUNT_TYPE_SM,
120 G_UNIX_MOUNT_TYPE_SDMMC,
121 G_UNIX_MOUNT_TYPE_IPOD,
122 G_UNIX_MOUNT_TYPE_CAMERA,
126 struct _GUnixMountEntry {
129 char *filesystem_type;
130 gboolean is_read_only;
131 gboolean is_system_internal;
134 struct _GUnixMountPoint {
137 char *filesystem_type;
139 gboolean is_read_only;
140 gboolean is_user_mountable;
141 gboolean is_loopback;
150 static guint signals[LAST_SIGNAL];
152 struct _GUnixMountMonitor {
155 GFileMonitor *fstab_monitor;
156 GFileMonitor *mtab_monitor;
158 GSource *proc_mounts_watch_source;
161 struct _GUnixMountMonitorClass {
162 GObjectClass parent_class;
165 static GUnixMountMonitor *the_mount_monitor = NULL;
167 static GList *_g_get_unix_mounts (void);
168 static GList *_g_get_unix_mount_points (void);
170 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT);
172 #define MOUNT_POLL_INTERVAL 4000
174 #ifdef HAVE_SYS_MNTTAB_H
175 #define MNTOPT_RO "ro"
180 #elif defined (HAVE_SYS_MNTTAB_H)
181 #include <sys/mnttab.h>
184 #ifdef HAVE_SYS_VFSTAB_H
185 #include <sys/vfstab.h>
188 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
189 #include <sys/mntctl.h>
191 #include <sys/vmount.h>
195 #if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
196 #include <sys/ucred.h>
197 #include <sys/mount.h>
199 #ifdef HAVE_SYS_SYSCTL_H
200 #include <sys/sysctl.h>
204 #ifndef HAVE_SETMNTENT
205 #define setmntent(f,m) fopen(f,m)
207 #ifndef HAVE_ENDMNTENT
208 #define endmntent(f) fclose(f)
212 is_in (const char *value, const char *set[])
215 for (i = 0; set[i] != NULL; i++)
217 if (strcmp (set[i], value) == 0)
224 * g_unix_is_mount_path_system_internal:
225 * @mount_path: a mount path, e.g. <filename>/media/disk</filename>
226 * or <filename>/usr</filename>
228 * Determines if @mount_path is considered an implementation of the
229 * OS. This is primarily used for hiding mountable and mounted volumes
230 * that only are used in the OS and has little to no relevance to the
233 * Returns: %TRUE if @mount_path is considered an implementation detail
237 g_unix_is_mount_path_system_internal (const char *mount_path)
239 const char *ignore_mountpoints[] = {
240 /* Includes all FHS 2.3 toplevel dirs and other specilized
241 * directories that we want to hide from the user.
243 "/", /* we already have "Filesystem root" in Nautilus */
266 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
269 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
277 if (is_in (mount_path, ignore_mountpoints))
280 if (g_str_has_prefix (mount_path, "/dev/") ||
281 g_str_has_prefix (mount_path, "/proc/") ||
282 g_str_has_prefix (mount_path, "/sys/"))
285 if (g_str_has_suffix (mount_path, "/.gvfs"))
292 guess_system_internal (const char *mountpoint,
296 const char *ignore_fs[] = {
317 const char *ignore_devices[] = {
327 if (is_in (fs, ignore_fs))
330 if (is_in (device, ignore_devices))
333 if (g_unix_is_mount_path_system_internal (mountpoint))
342 get_mtab_read_file (void)
346 return "/proc/mounts";
348 return _PATH_MOUNTED;
356 get_mtab_monitor_file (void)
360 return "/proc/mounts";
362 return _PATH_MOUNTED;
369 #ifndef HAVE_GETMNTENT_R
370 G_LOCK_DEFINE_STATIC(getmntent);
374 _g_get_unix_mounts (void)
376 #ifdef HAVE_GETMNTENT_R
380 struct mntent *mntent;
383 GUnixMountEntry *mount_entry;
384 GHashTable *mounts_hash;
387 read_file = get_mtab_read_file ();
389 file = setmntent (read_file, "r");
395 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
397 #ifdef HAVE_GETMNTENT_R
398 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
401 while ((mntent = getmntent (file)) != NULL)
404 /* ignore any mnt_fsname that is repeated and begins with a '/'
406 * We do this to avoid being fooled by --bind mounts, since
407 * these have the same device as the location they bind to.
408 * It's not an ideal solution to the problem, but it's likely that
409 * the most important mountpoint is first and the --bind ones after
410 * that aren't as important. So it should work.
412 * The '/' is to handle procfs, tmpfs and other no device mounts.
414 if (mntent->mnt_fsname != NULL &&
415 mntent->mnt_fsname[0] == '/' &&
416 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
419 mount_entry = g_new0 (GUnixMountEntry, 1);
420 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
421 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
422 mount_entry->device_path = g_strdup (_resolve_dev_root ());
424 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
425 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
427 #if defined (HAVE_HASMNTOPT)
428 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
429 mount_entry->is_read_only = TRUE;
432 mount_entry->is_system_internal =
433 guess_system_internal (mount_entry->mount_path,
434 mount_entry->filesystem_type,
435 mount_entry->device_path);
437 g_hash_table_insert (mounts_hash,
438 mount_entry->device_path,
439 mount_entry->device_path);
441 return_list = g_list_prepend (return_list, mount_entry);
443 g_hash_table_destroy (mounts_hash);
447 #ifndef HAVE_GETMNTENT_R
448 G_UNLOCK (getmntent);
451 return g_list_reverse (return_list);
454 #elif defined (HAVE_SYS_MNTTAB_H)
456 G_LOCK_DEFINE_STATIC(getmntent);
459 get_mtab_read_file (void)
462 return _PATH_MOUNTED;
464 return "/etc/mnttab";
469 get_mtab_monitor_file (void)
471 return get_mtab_read_file ();
475 _g_get_unix_mounts (void)
477 struct mnttab mntent;
480 GUnixMountEntry *mount_entry;
483 read_file = get_mtab_read_file ();
485 file = setmntent (read_file, "r");
492 while (! getmntent (file, &mntent))
494 mount_entry = g_new0 (GUnixMountEntry, 1);
496 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
497 mount_entry->device_path = g_strdup (mntent.mnt_special);
498 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
500 #if defined (HAVE_HASMNTOPT)
501 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
502 mount_entry->is_read_only = TRUE;
505 mount_entry->is_system_internal =
506 guess_system_internal (mount_entry->mount_path,
507 mount_entry->filesystem_type,
508 mount_entry->device_path);
510 return_list = g_list_prepend (return_list, mount_entry);
515 G_UNLOCK (getmntent);
517 return g_list_reverse (return_list);
520 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
523 get_mtab_monitor_file (void)
529 _g_get_unix_mounts (void)
531 struct vfs_ent *fs_info;
532 struct vmount *vmount_info;
534 unsigned int vmount_size;
538 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
540 g_warning ("Unable to know the number of mounted volumes\n");
545 vmount_info = (struct vmount*)g_malloc (vmount_size);
547 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
549 if (vmount_info->vmt_revision != VMT_REVISION)
550 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
552 if (vmount_number < 0)
554 g_warning ("Unable to recover mounted volumes information\n");
556 g_free (vmount_info);
561 while (vmount_number > 0)
563 mount_entry = g_new0 (GUnixMountEntry, 1);
565 mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT));
566 mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB));
567 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
568 mount_entry->is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
570 fs_info = getvfsbytype (vmount_info->vmt_gfstype);
573 mount_entry->filesystem_type = g_strdup ("unknown");
575 mount_entry->filesystem_type = g_strdup (fs_info->vfsent_name);
577 mount_entry->is_system_internal =
578 guess_system_internal (mount_entry->mount_path,
579 mount_entry->filesystem_type,
580 mount_entry->device_path);
582 return_list = g_list_prepend (return_list, mount_entry);
584 vmount_info = (struct vmount *)( (char*)vmount_info
585 + vmount_info->vmt_length);
589 g_free (vmount_info);
591 return g_list_reverse (return_list);
594 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
597 get_mtab_monitor_file (void)
603 _g_get_unix_mounts (void)
605 #if defined(HAVE_GETVFSSTAT)
606 struct statvfs *mntent = NULL;
607 #elif defined(HAVE_GETFSSTAT)
608 struct statfs *mntent = NULL;
610 #error statfs juggling failed
614 GUnixMountEntry *mount_entry;
617 /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
618 #if defined(HAVE_GETVFSSTAT)
619 num_mounts = getvfsstat (NULL, 0, ST_NOWAIT);
620 #elif defined(HAVE_GETFSSTAT)
621 num_mounts = getfsstat (NULL, 0, MNT_NOWAIT);
623 if (num_mounts == -1)
626 bufsize = num_mounts * sizeof (*mntent);
627 mntent = g_malloc (bufsize);
628 #if defined(HAVE_GETVFSSTAT)
629 num_mounts = getvfsstat (mntent, bufsize, ST_NOWAIT);
630 #elif defined(HAVE_GETFSSTAT)
631 num_mounts = getfsstat (mntent, bufsize, MNT_NOWAIT);
633 if (num_mounts == -1)
638 for (i = 0; i < num_mounts; i++)
640 mount_entry = g_new0 (GUnixMountEntry, 1);
642 mount_entry->mount_path = g_strdup (mntent[i].f_mntonname);
643 mount_entry->device_path = g_strdup (mntent[i].f_mntfromname);
644 mount_entry->filesystem_type = g_strdup (mntent[i].f_fstypename);
645 #if defined(HAVE_GETVFSSTAT)
646 if (mntent[i].f_flag & ST_RDONLY)
647 #elif defined(HAVE_GETFSSTAT)
648 if (mntent[i].f_flags & MNT_RDONLY)
650 mount_entry->is_read_only = TRUE;
652 mount_entry->is_system_internal =
653 guess_system_internal (mount_entry->mount_path,
654 mount_entry->filesystem_type,
655 mount_entry->device_path);
657 return_list = g_list_prepend (return_list, mount_entry);
662 return g_list_reverse (return_list);
664 #elif defined(__INTERIX)
667 get_mtab_monitor_file (void)
673 _g_get_unix_mounts (void)
676 GList* return_list = NULL;
677 char filename[9 + NAME_MAX];
679 dirp = opendir ("/dev/fs");
682 g_warning ("unable to read /dev/fs!");
688 struct statvfs statbuf;
690 struct dirent* result;
692 if (readdir_r (dirp, &entry, &result) || result == NULL)
695 strcpy (filename, "/dev/fs/");
696 strcat (filename, entry.d_name);
698 if (statvfs (filename, &statbuf) == 0)
700 GUnixMountEntry* mount_entry = g_new0(GUnixMountEntry, 1);
702 mount_entry->mount_path = g_strdup (statbuf.f_mntonname);
703 mount_entry->device_path = g_strdup (statbuf.f_mntfromname);
704 mount_entry->filesystem_type = g_strdup (statbuf.f_fstypename);
706 if (statbuf.f_flag & ST_RDONLY)
707 mount_entry->is_read_only = TRUE;
709 return_list = g_list_prepend(return_list, mount_entry);
713 return_list = g_list_reverse (return_list);
720 #error No _g_get_unix_mounts() implementation for system
723 /* _g_get_unix_mount_points():
725 * don't return swap and ignore mounts.
729 get_fstab_file (void)
731 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
733 return "/etc/filesystems";
734 #elif defined(_PATH_MNTTAB)
736 #elif defined(VFSTAB)
745 _g_get_unix_mount_points (void)
747 #ifdef HAVE_GETMNTENT_R
751 struct mntent *mntent;
754 GUnixMountPoint *mount_entry;
757 read_file = get_fstab_file ();
759 file = setmntent (read_file, "r");
765 #ifdef HAVE_GETMNTENT_R
766 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
769 while ((mntent = getmntent (file)) != NULL)
772 if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
773 (strcmp (mntent->mnt_dir, "swap") == 0) ||
774 (strcmp (mntent->mnt_dir, "none") == 0))
777 #ifdef HAVE_HASMNTOPT
778 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
779 if (hasmntopt (mntent, "bind"))
783 mount_entry = g_new0 (GUnixMountPoint, 1);
784 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
785 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
786 mount_entry->device_path = g_strdup (_resolve_dev_root ());
788 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
789 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
790 mount_entry->options = g_strdup (mntent->mnt_opts);
792 #ifdef HAVE_HASMNTOPT
793 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
794 mount_entry->is_read_only = TRUE;
796 if (hasmntopt (mntent, "loop") != NULL)
797 mount_entry->is_loopback = TRUE;
801 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
802 #ifdef HAVE_HASMNTOPT
803 || (hasmntopt (mntent, "user") != NULL
804 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
805 || hasmntopt (mntent, "pamconsole") != NULL
806 || hasmntopt (mntent, "users") != NULL
807 || hasmntopt (mntent, "owner") != NULL
810 mount_entry->is_user_mountable = TRUE;
812 return_list = g_list_prepend (return_list, mount_entry);
817 #ifndef HAVE_GETMNTENT_R
818 G_UNLOCK (getmntent);
821 return g_list_reverse (return_list);
824 #elif defined (HAVE_SYS_MNTTAB_H)
827 _g_get_unix_mount_points (void)
829 struct mnttab mntent;
832 GUnixMountPoint *mount_entry;
835 read_file = get_fstab_file ();
837 file = setmntent (read_file, "r");
844 while (! getmntent (file, &mntent))
846 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
847 (strcmp (mntent.mnt_mountp, "swap") == 0) ||
848 (strcmp (mntent.mnt_mountp, "none") == 0))
851 mount_entry = g_new0 (GUnixMountPoint, 1);
853 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
854 mount_entry->device_path = g_strdup (mntent.mnt_special);
855 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
856 mount_entry->options = g_strdup (mntent.mnt_mntopts);
858 #ifdef HAVE_HASMNTOPT
859 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
860 mount_entry->is_read_only = TRUE;
862 if (hasmntopt (&mntent, "lofs") != NULL)
863 mount_entry->is_loopback = TRUE;
866 if ((mntent.mnt_fstype != NULL)
867 #ifdef HAVE_HASMNTOPT
868 || (hasmntopt (&mntent, "user") != NULL
869 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
870 || hasmntopt (&mntent, "pamconsole") != NULL
871 || hasmntopt (&mntent, "users") != NULL
872 || hasmntopt (&mntent, "owner") != NULL
875 mount_entry->is_user_mountable = TRUE;
877 return_list = g_list_prepend (return_list, mount_entry);
881 G_UNLOCK (getmntent);
883 return g_list_reverse (return_list);
885 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
887 /* functions to parse /etc/filesystems on aix */
889 /* read character, ignoring comments (begin with '*', end with '\n' */
891 aix_fs_getc (FILE *fd)
895 while ((c = getc (fd)) == '*')
897 while (((c = getc (fd)) != '\n') && (c != EOF))
902 /* eat all continuous spaces in a file */
904 aix_fs_ignorespace (FILE *fd)
908 while ((c = aix_fs_getc (fd)) != EOF)
910 if (!g_ascii_isspace (c))
920 /* read one word from file */
922 aix_fs_getword (FILE *fd,
927 aix_fs_ignorespace (fd);
929 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
933 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
945 char mnt_mount[PATH_MAX];
946 char mnt_special[PATH_MAX];
948 char mnt_options[128];
949 } AixMountTableEntry;
951 /* read mount points properties */
953 aix_fs_get (FILE *fd,
954 AixMountTableEntry *prop)
956 static char word[PATH_MAX] = { 0 };
957 char value[PATH_MAX];
962 if (aix_fs_getword (fd, word) == EOF)
966 word[strlen(word) - 1] = 0;
967 strcpy (prop->mnt_mount, word);
969 /* read attributes and value */
971 while (aix_fs_getword (fd, word) != EOF)
973 /* test if is attribute or new stanza */
974 if (word[strlen(word) - 1] == ':')
978 aix_fs_getword (fd, value);
981 aix_fs_getword (fd, value);
983 if (strcmp (word, "dev") == 0)
984 strcpy (prop->mnt_special, value);
985 else if (strcmp (word, "vfs") == 0)
986 strcpy (prop->mnt_fstype, value);
987 else if (strcmp (word, "options") == 0)
988 strcpy(prop->mnt_options, value);
995 _g_get_unix_mount_points (void)
997 struct mntent *mntent;
1000 GUnixMountPoint *mount_entry;
1001 AixMountTableEntry mntent;
1004 read_file = get_fstab_file ();
1006 file = setmntent (read_file, "r");
1012 while (!aix_fs_get (file, &mntent))
1014 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
1016 mount_entry = g_new0 (GUnixMountPoint, 1);
1018 mount_entry->mount_path = g_strdup (mntent.mnt_mount);
1019 mount_entry->device_path = g_strdup (mntent.mnt_special);
1020 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
1021 mount_entry->options = g_strdup (mntent.mnt_options);
1022 mount_entry->is_read_only = TRUE;
1023 mount_entry->is_user_mountable = TRUE;
1025 return_list = g_list_prepend (return_list, mount_entry);
1031 return g_list_reverse (return_list);
1034 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
1037 _g_get_unix_mount_points (void)
1039 struct fstab *fstab = NULL;
1040 GUnixMountPoint *mount_entry;
1042 #ifdef HAVE_SYS_SYSCTL_H
1044 size_t len = sizeof(usermnt);
1053 #ifdef HAVE_SYS_SYSCTL_H
1054 #if defined(HAVE_SYSCTLBYNAME)
1055 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
1056 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
1061 mib[1] = VFS_USERMOUNT;
1062 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1064 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
1069 mib[1] = KERN_USERMOUNT;
1070 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1075 while ((fstab = getfsent ()) != NULL)
1077 if (strcmp (fstab->fs_vfstype, "swap") == 0)
1080 mount_entry = g_new0 (GUnixMountPoint, 1);
1082 mount_entry->mount_path = g_strdup (fstab->fs_file);
1083 mount_entry->device_path = g_strdup (fstab->fs_spec);
1084 mount_entry->filesystem_type = g_strdup (fstab->fs_vfstype);
1085 mount_entry->options = g_strdup (fstab->fs_mntops);
1087 if (strcmp (fstab->fs_type, "ro") == 0)
1088 mount_entry->is_read_only = TRUE;
1090 #ifdef HAVE_SYS_SYSCTL_H
1093 uid_t uid = getuid ();
1094 if (stat (fstab->fs_file, &sb) == 0)
1096 if (uid == 0 || sb.st_uid == uid)
1097 mount_entry->is_user_mountable = TRUE;
1102 return_list = g_list_prepend (return_list, mount_entry);
1107 return g_list_reverse (return_list);
1109 #elif defined(__INTERIX)
1111 _g_get_unix_mount_points (void)
1113 return _g_get_unix_mounts ();
1116 #error No g_get_mount_table() implementation for system
1120 get_mounts_timestamp (void)
1122 const char *monitor_file;
1125 monitor_file = get_mtab_monitor_file ();
1128 if (stat (monitor_file, &buf) == 0)
1129 return (guint64)buf.st_mtime;
1135 get_mount_points_timestamp (void)
1137 const char *monitor_file;
1140 monitor_file = get_fstab_file ();
1143 if (stat (monitor_file, &buf) == 0)
1144 return (guint64)buf.st_mtime;
1150 * g_unix_mounts_get: (skip)
1151 * @time_read: (out) (allow-none): guint64 to contain a timestamp, or %NULL
1153 * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1154 * If @time_read is set, it will be filled with the mount
1155 * timestamp, allowing for checking if the mounts have changed
1156 * with g_unix_mounts_changed_since().
1158 * Returns: (element-type GUnixMountEntry) (transfer full):
1159 * a #GList of the UNIX mounts.
1162 g_unix_mounts_get (guint64 *time_read)
1165 *time_read = get_mounts_timestamp ();
1167 return _g_get_unix_mounts ();
1171 * g_unix_mount_at: (skip)
1172 * @mount_path: path for a possible unix mount.
1173 * @time_read: (out) (allow-none): guint64 to contain a timestamp.
1175 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1176 * is set, it will be filled with a unix timestamp for checking
1177 * if the mounts have changed since with g_unix_mounts_changed_since().
1179 * Returns: (transfer full): a #GUnixMountEntry.
1182 g_unix_mount_at (const char *mount_path,
1186 GUnixMountEntry *mount_entry, *found;
1188 mounts = g_unix_mounts_get (time_read);
1191 for (l = mounts; l != NULL; l = l->next)
1193 mount_entry = l->data;
1195 if (!found && strcmp (mount_path, mount_entry->mount_path) == 0)
1196 found = mount_entry;
1198 g_unix_mount_free (mount_entry);
1200 g_list_free (mounts);
1206 * g_unix_mount_points_get: (skip)
1207 * @time_read: (out) (allow-none): guint64 to contain a timestamp.
1209 * Gets a #GList of #GUnixMountPoint containing the unix mount points.
1210 * If @time_read is set, it will be filled with the mount timestamp,
1211 * allowing for checking if the mounts have changed with
1212 * g_unix_mount_points_changed_since().
1214 * Returns: (element-type GUnixMountPoint) (transfer full):
1215 * a #GList of the UNIX mountpoints.
1218 g_unix_mount_points_get (guint64 *time_read)
1221 *time_read = get_mount_points_timestamp ();
1223 return _g_get_unix_mount_points ();
1227 * g_unix_mounts_changed_since:
1228 * @time: guint64 to contain a timestamp.
1230 * Checks if the unix mounts have changed since a given unix time.
1232 * Returns: %TRUE if the mounts have changed since @time.
1235 g_unix_mounts_changed_since (guint64 time)
1237 return get_mounts_timestamp () != time;
1241 * g_unix_mount_points_changed_since:
1242 * @time: guint64 to contain a timestamp.
1244 * Checks if the unix mount points have changed since a given unix time.
1246 * Returns: %TRUE if the mount points have changed since @time.
1249 g_unix_mount_points_changed_since (guint64 time)
1251 return get_mount_points_timestamp () != time;
1255 g_unix_mount_monitor_finalize (GObject *object)
1257 GUnixMountMonitor *monitor;
1259 monitor = G_UNIX_MOUNT_MONITOR (object);
1261 if (monitor->fstab_monitor)
1263 g_file_monitor_cancel (monitor->fstab_monitor);
1264 g_object_unref (monitor->fstab_monitor);
1267 if (monitor->proc_mounts_watch_source != NULL)
1268 g_source_destroy (monitor->proc_mounts_watch_source);
1270 if (monitor->mtab_monitor)
1272 g_file_monitor_cancel (monitor->mtab_monitor);
1273 g_object_unref (monitor->mtab_monitor);
1276 the_mount_monitor = NULL;
1278 G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
1283 g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
1285 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1287 gobject_class->finalize = g_unix_mount_monitor_finalize;
1290 * GUnixMountMonitor::mounts-changed:
1291 * @monitor: the object on which the signal is emitted
1293 * Emitted when the unix mounts have changed.
1295 signals[MOUNTS_CHANGED] =
1296 g_signal_new ("mounts-changed",
1297 G_TYPE_FROM_CLASS (klass),
1301 g_cclosure_marshal_VOID__VOID,
1305 * GUnixMountMonitor::mountpoints-changed:
1306 * @monitor: the object on which the signal is emitted
1308 * Emitted when the unix mount points have changed.
1310 signals[MOUNTPOINTS_CHANGED] =
1311 g_signal_new ("mountpoints-changed",
1312 G_TYPE_FROM_CLASS (klass),
1316 g_cclosure_marshal_VOID__VOID,
1321 fstab_file_changed (GFileMonitor *monitor,
1324 GFileMonitorEvent event_type,
1327 GUnixMountMonitor *mount_monitor;
1329 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1330 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1331 event_type != G_FILE_MONITOR_EVENT_DELETED)
1334 mount_monitor = user_data;
1335 g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0);
1339 mtab_file_changed (GFileMonitor *monitor,
1342 GFileMonitorEvent event_type,
1345 GUnixMountMonitor *mount_monitor;
1347 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1348 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1349 event_type != G_FILE_MONITOR_EVENT_DELETED)
1352 mount_monitor = user_data;
1353 g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
1357 proc_mounts_changed (GIOChannel *channel,
1361 GUnixMountMonitor *mount_monitor = G_UNIX_MOUNT_MONITOR (user_data);
1362 if (cond & G_IO_ERR)
1363 g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
1368 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1372 if (get_fstab_file () != NULL)
1374 file = g_file_new_for_path (get_fstab_file ());
1375 monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1376 g_object_unref (file);
1378 g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor);
1381 if (get_mtab_monitor_file () != NULL)
1383 const gchar *mtab_path;
1385 mtab_path = get_mtab_monitor_file ();
1386 /* /proc/mounts monitoring is special - can't just use GFileMonitor.
1387 * See 'man proc' for more details.
1389 if (g_strcmp0 (mtab_path, "/proc/mounts") == 0)
1391 GIOChannel *proc_mounts_channel;
1392 GError *error = NULL;
1393 proc_mounts_channel = g_io_channel_new_file ("/proc/mounts", "r", &error);
1394 if (proc_mounts_channel == NULL)
1396 g_warning ("Error creating IO channel for /proc/mounts: %s (%s, %d)",
1397 error->message, g_quark_to_string (error->domain), error->code);
1398 g_error_free (error);
1402 monitor->proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
1403 g_source_set_callback (monitor->proc_mounts_watch_source,
1404 (GSourceFunc) proc_mounts_changed,
1407 g_source_attach (monitor->proc_mounts_watch_source,
1408 g_main_context_get_thread_default ());
1409 g_source_unref (monitor->proc_mounts_watch_source);
1410 g_io_channel_unref (proc_mounts_channel);
1415 file = g_file_new_for_path (mtab_path);
1416 monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1417 g_object_unref (file);
1418 g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor);
1424 * g_unix_mount_monitor_set_rate_limit:
1425 * @mount_monitor: a #GUnixMountMonitor
1426 * @limit_msec: a integer with the limit in milliseconds to
1429 * Sets the rate limit to which the @mount_monitor will report
1430 * consecutive change events to the mount and mount point entry files.
1435 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
1438 g_return_if_fail (G_IS_UNIX_MOUNT_MONITOR (mount_monitor));
1440 if (mount_monitor->fstab_monitor != NULL)
1441 g_file_monitor_set_rate_limit (mount_monitor->fstab_monitor, limit_msec);
1443 if (mount_monitor->mtab_monitor != NULL)
1444 g_file_monitor_set_rate_limit (mount_monitor->mtab_monitor, limit_msec);
1448 * g_unix_mount_monitor_new:
1450 * Gets a new #GUnixMountMonitor. The default rate limit for which the
1451 * monitor will report consecutive changes for the mount and mount
1452 * point entry files is the default for a #GFileMonitor. Use
1453 * g_unix_mount_monitor_set_rate_limit() to change this.
1455 * Returns: a #GUnixMountMonitor.
1458 g_unix_mount_monitor_new (void)
1460 if (the_mount_monitor == NULL)
1462 the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL);
1463 return the_mount_monitor;
1466 return g_object_ref (the_mount_monitor);
1470 * g_unix_mount_free:
1471 * @mount_entry: a #GUnixMountEntry.
1473 * Frees a unix mount.
1476 g_unix_mount_free (GUnixMountEntry *mount_entry)
1478 g_return_if_fail (mount_entry != NULL);
1480 g_free (mount_entry->mount_path);
1481 g_free (mount_entry->device_path);
1482 g_free (mount_entry->filesystem_type);
1483 g_free (mount_entry);
1487 * g_unix_mount_point_free:
1488 * @mount_point: unix mount point to free.
1490 * Frees a unix mount point.
1493 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1495 g_return_if_fail (mount_point != NULL);
1497 g_free (mount_point->mount_path);
1498 g_free (mount_point->device_path);
1499 g_free (mount_point->filesystem_type);
1500 g_free (mount_point->options);
1501 g_free (mount_point);
1505 * g_unix_mount_compare:
1506 * @mount1: first #GUnixMountEntry to compare.
1507 * @mount2: second #GUnixMountEntry to compare.
1509 * Compares two unix mounts.
1511 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1512 * or less than @mount2, respectively.
1515 g_unix_mount_compare (GUnixMountEntry *mount1,
1516 GUnixMountEntry *mount2)
1520 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1522 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1526 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1530 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1534 res = mount1->is_read_only - mount2->is_read_only;
1542 * g_unix_mount_get_mount_path:
1543 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1545 * Gets the mount path for a unix mount.
1547 * Returns: the mount path for @mount_entry.
1550 g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
1552 g_return_val_if_fail (mount_entry != NULL, NULL);
1554 return mount_entry->mount_path;
1558 * g_unix_mount_get_device_path:
1559 * @mount_entry: a #GUnixMount.
1561 * Gets the device path for a unix mount.
1563 * Returns: a string containing the device path.
1566 g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
1568 g_return_val_if_fail (mount_entry != NULL, NULL);
1570 return mount_entry->device_path;
1574 * g_unix_mount_get_fs_type:
1575 * @mount_entry: a #GUnixMount.
1577 * Gets the filesystem type for the unix mount.
1579 * Returns: a string containing the file system type.
1582 g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
1584 g_return_val_if_fail (mount_entry != NULL, NULL);
1586 return mount_entry->filesystem_type;
1590 * g_unix_mount_is_readonly:
1591 * @mount_entry: a #GUnixMount.
1593 * Checks if a unix mount is mounted read only.
1595 * Returns: %TRUE if @mount_entry is read only.
1598 g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
1600 g_return_val_if_fail (mount_entry != NULL, FALSE);
1602 return mount_entry->is_read_only;
1606 * g_unix_mount_is_system_internal:
1607 * @mount_entry: a #GUnixMount.
1609 * Checks if a unix mount is a system path.
1611 * Returns: %TRUE if the unix mount is for a system path.
1614 g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
1616 g_return_val_if_fail (mount_entry != NULL, FALSE);
1618 return mount_entry->is_system_internal;
1622 * g_unix_mount_point_compare:
1623 * @mount1: a #GUnixMount.
1624 * @mount2: a #GUnixMount.
1626 * Compares two unix mount points.
1628 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1629 * or less than @mount2, respectively.
1632 g_unix_mount_point_compare (GUnixMountPoint *mount1,
1633 GUnixMountPoint *mount2)
1637 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1639 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1643 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1647 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1651 res = g_strcmp0 (mount1->options, mount2->options);
1655 res = mount1->is_read_only - mount2->is_read_only;
1659 res = mount1->is_user_mountable - mount2->is_user_mountable;
1663 res = mount1->is_loopback - mount2->is_loopback;
1671 * g_unix_mount_point_get_mount_path:
1672 * @mount_point: a #GUnixMountPoint.
1674 * Gets the mount path for a unix mount point.
1676 * Returns: a string containing the mount path.
1679 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
1681 g_return_val_if_fail (mount_point != NULL, NULL);
1683 return mount_point->mount_path;
1687 * g_unix_mount_point_get_device_path:
1688 * @mount_point: a #GUnixMountPoint.
1690 * Gets the device path for a unix mount point.
1692 * Returns: a string containing the device path.
1695 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
1697 g_return_val_if_fail (mount_point != NULL, NULL);
1699 return mount_point->device_path;
1703 * g_unix_mount_point_get_fs_type:
1704 * @mount_point: a #GUnixMountPoint.
1706 * Gets the file system type for the mount point.
1708 * Returns: a string containing the file system type.
1711 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
1713 g_return_val_if_fail (mount_point != NULL, NULL);
1715 return mount_point->filesystem_type;
1719 * g_unix_mount_point_get_options:
1720 * @mount_point: a #GUnixMountPoint.
1722 * Gets the options for the mount point.
1724 * Returns: a string containing the options.
1729 g_unix_mount_point_get_options (GUnixMountPoint *mount_point)
1731 g_return_val_if_fail (mount_point != NULL, NULL);
1733 return mount_point->options;
1737 * g_unix_mount_point_is_readonly:
1738 * @mount_point: a #GUnixMountPoint.
1740 * Checks if a unix mount point is read only.
1742 * Returns: %TRUE if a mount point is read only.
1745 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
1747 g_return_val_if_fail (mount_point != NULL, FALSE);
1749 return mount_point->is_read_only;
1753 * g_unix_mount_point_is_user_mountable:
1754 * @mount_point: a #GUnixMountPoint.
1756 * Checks if a unix mount point is mountable by the user.
1758 * Returns: %TRUE if the mount point is user mountable.
1761 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
1763 g_return_val_if_fail (mount_point != NULL, FALSE);
1765 return mount_point->is_user_mountable;
1769 * g_unix_mount_point_is_loopback:
1770 * @mount_point: a #GUnixMountPoint.
1772 * Checks if a unix mount point is a loopback device.
1774 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
1777 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
1779 g_return_val_if_fail (mount_point != NULL, FALSE);
1781 return mount_point->is_loopback;
1784 static GUnixMountType
1785 guess_mount_type (const char *mount_path,
1786 const char *device_path,
1787 const char *filesystem_type)
1789 GUnixMountType type;
1792 type = G_UNIX_MOUNT_TYPE_UNKNOWN;
1794 if ((strcmp (filesystem_type, "udf") == 0) ||
1795 (strcmp (filesystem_type, "iso9660") == 0) ||
1796 (strcmp (filesystem_type, "cd9660") == 0))
1797 type = G_UNIX_MOUNT_TYPE_CDROM;
1798 else if ((strcmp (filesystem_type, "nfs") == 0) ||
1799 (strcmp (filesystem_type, "nfs4") == 0))
1800 type = G_UNIX_MOUNT_TYPE_NFS;
1801 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
1802 g_str_has_prefix (device_path, "/dev/fd") ||
1803 g_str_has_prefix (device_path, "/dev/floppy"))
1804 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1805 else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
1806 g_str_has_prefix (device_path, "/dev/acd") ||
1807 g_str_has_prefix (device_path, "/dev/cd"))
1808 type = G_UNIX_MOUNT_TYPE_CDROM;
1809 else if (g_str_has_prefix (device_path, "/vol/"))
1811 const char *name = mount_path + strlen ("/");
1813 if (g_str_has_prefix (name, "cdrom"))
1814 type = G_UNIX_MOUNT_TYPE_CDROM;
1815 else if (g_str_has_prefix (name, "floppy") ||
1816 g_str_has_prefix (device_path, "/vol/dev/diskette/"))
1817 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1818 else if (g_str_has_prefix (name, "rmdisk"))
1819 type = G_UNIX_MOUNT_TYPE_ZIP;
1820 else if (g_str_has_prefix (name, "jaz"))
1821 type = G_UNIX_MOUNT_TYPE_JAZ;
1822 else if (g_str_has_prefix (name, "memstick"))
1823 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1827 basename = g_path_get_basename (mount_path);
1829 if (g_str_has_prefix (basename, "cdr") ||
1830 g_str_has_prefix (basename, "cdwriter") ||
1831 g_str_has_prefix (basename, "burn") ||
1832 g_str_has_prefix (basename, "dvdr"))
1833 type = G_UNIX_MOUNT_TYPE_CDROM;
1834 else if (g_str_has_prefix (basename, "floppy"))
1835 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1836 else if (g_str_has_prefix (basename, "zip"))
1837 type = G_UNIX_MOUNT_TYPE_ZIP;
1838 else if (g_str_has_prefix (basename, "jaz"))
1839 type = G_UNIX_MOUNT_TYPE_JAZ;
1840 else if (g_str_has_prefix (basename, "camera"))
1841 type = G_UNIX_MOUNT_TYPE_CAMERA;
1842 else if (g_str_has_prefix (basename, "memstick") ||
1843 g_str_has_prefix (basename, "memory_stick") ||
1844 g_str_has_prefix (basename, "ram"))
1845 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1846 else if (g_str_has_prefix (basename, "compact_flash"))
1847 type = G_UNIX_MOUNT_TYPE_CF;
1848 else if (g_str_has_prefix (basename, "smart_media"))
1849 type = G_UNIX_MOUNT_TYPE_SM;
1850 else if (g_str_has_prefix (basename, "sd_mmc"))
1851 type = G_UNIX_MOUNT_TYPE_SDMMC;
1852 else if (g_str_has_prefix (basename, "ipod"))
1853 type = G_UNIX_MOUNT_TYPE_IPOD;
1858 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
1859 type = G_UNIX_MOUNT_TYPE_HD;
1865 * g_unix_mount_guess_type:
1866 * @mount_entry: a #GUnixMount.
1868 * Guesses the type of a unix mount. If the mount type cannot be
1869 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1871 * Returns: a #GUnixMountType.
1873 static GUnixMountType
1874 g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
1876 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1877 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1878 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1879 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1881 return guess_mount_type (mount_entry->mount_path,
1882 mount_entry->device_path,
1883 mount_entry->filesystem_type);
1887 * g_unix_mount_point_guess_type:
1888 * @mount_point: a #GUnixMountPoint.
1890 * Guesses the type of a unix mount point.
1891 * If the mount type cannot be determined,
1892 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1894 * Returns: a #GUnixMountType.
1896 static GUnixMountType
1897 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
1899 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1900 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1901 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1902 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1904 return guess_mount_type (mount_point->mount_path,
1905 mount_point->device_path,
1906 mount_point->filesystem_type);
1910 type_to_icon (GUnixMountType type, gboolean is_mount_point, gboolean use_symbolic)
1912 const char *icon_name;
1916 case G_UNIX_MOUNT_TYPE_HD:
1918 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
1920 icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
1922 case G_UNIX_MOUNT_TYPE_FLOPPY:
1923 case G_UNIX_MOUNT_TYPE_ZIP:
1924 case G_UNIX_MOUNT_TYPE_JAZ:
1926 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
1928 icon_name = use_symbolic ? "media-removable-symbolic" : "media-floppy";
1930 case G_UNIX_MOUNT_TYPE_CDROM:
1932 icon_name = use_symbolic ? "drive-optical-symbolic" : "drive-optical";
1934 icon_name = use_symbolic ? "media-optical-symbolic" : "media-optical";
1936 case G_UNIX_MOUNT_TYPE_NFS:
1937 icon_name = use_symbolic ? "folder-remote-symbolic" : "folder-remote";
1939 case G_UNIX_MOUNT_TYPE_MEMSTICK:
1941 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
1943 icon_name = use_symbolic ? "media-removable-symbolic" : "media-flash";
1945 case G_UNIX_MOUNT_TYPE_CAMERA:
1947 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
1949 icon_name = use_symbolic ? "camera-photo-symbolic" : "camera-photo";
1951 case G_UNIX_MOUNT_TYPE_IPOD:
1953 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
1955 icon_name = use_symbolic ? "multimedia-player-symbolic" : "multimedia-player";
1957 case G_UNIX_MOUNT_TYPE_UNKNOWN:
1960 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
1962 icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
1970 * g_unix_mount_guess_name:
1971 * @mount_entry: a #GUnixMountEntry
1973 * Guesses the name of a Unix mount.
1974 * The result is a translated string.
1976 * Returns: A newly allocated string that must
1977 * be freed with g_free()
1980 g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
1984 if (strcmp (mount_entry->mount_path, "/") == 0)
1985 name = g_strdup (_("Filesystem root"));
1987 name = g_filename_display_basename (mount_entry->mount_path);
1993 * g_unix_mount_guess_icon:
1994 * @mount_entry: a #GUnixMountEntry
1996 * Guesses the icon of a Unix mount.
1998 * Returns: (transfer full): a #GIcon
2001 g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
2003 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, FALSE));
2007 * g_unix_mount_guess_symbolic_icon:
2008 * @mount_entry: a #GUnixMountEntry
2010 * Guesses the symbolic icon of a Unix mount.
2012 * Returns: (transfer full): a #GIcon
2017 g_unix_mount_guess_symbolic_icon (GUnixMountEntry *mount_entry)
2019 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, TRUE));
2023 * g_unix_mount_point_guess_name:
2024 * @mount_point: a #GUnixMountPoint
2026 * Guesses the name of a Unix mount point.
2027 * The result is a translated string.
2029 * Returns: A newly allocated string that must
2030 * be freed with g_free()
2033 g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
2037 if (strcmp (mount_point->mount_path, "/") == 0)
2038 name = g_strdup (_("Filesystem root"));
2040 name = g_filename_display_basename (mount_point->mount_path);
2046 * g_unix_mount_point_guess_icon:
2047 * @mount_point: a #GUnixMountPoint
2049 * Guesses the icon of a Unix mount point.
2051 * Returns: (transfer full): a #GIcon
2054 g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
2056 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, FALSE));
2060 * g_unix_mount_point_guess_symbolic_icon:
2061 * @mount_point: a #GUnixMountPoint
2063 * Guesses the symbolic icon of a Unix mount point.
2065 * Returns: (transfer full): a #GIcon
2070 g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount_point)
2072 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, TRUE));
2076 * g_unix_mount_guess_can_eject:
2077 * @mount_entry: a #GUnixMountEntry
2079 * Guesses whether a Unix mount can be ejected.
2081 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
2084 g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
2086 GUnixMountType guessed_type;
2088 guessed_type = g_unix_mount_guess_type (mount_entry);
2089 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2090 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2097 * g_unix_mount_guess_should_display:
2098 * @mount_entry: a #GUnixMountEntry
2100 * Guesses whether a Unix mount should be displayed in the UI.
2102 * Returns: %TRUE if @mount_entry is deemed to be displayable.
2105 g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
2107 const char *mount_path;
2108 const gchar *user_name;
2109 gsize user_name_len;
2111 /* Never display internal mountpoints */
2112 if (g_unix_mount_is_system_internal (mount_entry))
2115 /* Only display things in /media (which are generally user mountable)
2116 and home dir (fuse stuff) and /run/media/$USER */
2117 mount_path = mount_entry->mount_path;
2118 if (mount_path != NULL)
2120 gboolean is_in_runtime_dir = FALSE;
2121 /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
2122 if (g_strstr_len (mount_path, -1, "/.") != NULL)
2125 /* Check /run/media/$USER/ */
2126 user_name = g_get_user_name ();
2127 user_name_len = strlen (user_name);
2128 if (strncmp (mount_path, "/run/media/", sizeof ("/run/media/") - 1) == 0 &&
2129 strncmp (mount_path + sizeof ("/run/media/") - 1, user_name, user_name_len) == 0 &&
2130 mount_path[sizeof ("/run/media/") - 1 + user_name_len] == '/')
2131 is_in_runtime_dir = TRUE;
2133 if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/"))
2136 /* Avoid displaying mounts that are not accessible to the user.
2138 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
2139 * want to avoid g_access() for mount points which can potentially
2140 * block or fail stat()'ing, such as network mounts.
2142 path = g_path_get_dirname (mount_path);
2143 if (g_str_has_prefix (path, "/media/"))
2145 if (g_access (path, R_OK|X_OK) != 0)
2153 if (mount_entry->device_path && mount_entry->device_path[0] == '/')
2156 if (g_stat (mount_entry->device_path, &st) == 0 &&
2157 S_ISBLK(st.st_mode) &&
2158 g_access (mount_path, R_OK|X_OK) != 0)
2164 if (g_str_has_prefix (mount_path, g_get_home_dir ()) &&
2165 mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
2173 * g_unix_mount_point_guess_can_eject:
2174 * @mount_point: a #GUnixMountPoint
2176 * Guesses whether a Unix mount point can be ejected.
2178 * Returns: %TRUE if @mount_point is deemed to be ejectable.
2181 g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
2183 GUnixMountType guessed_type;
2185 guessed_type = g_unix_mount_point_guess_type (mount_point);
2186 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2187 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2193 #ifdef HAVE_MNTENT_H
2194 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
2196 _canonicalize_filename (gchar *filename)
2199 gboolean last_was_slash = FALSE;
2206 if (*p == G_DIR_SEPARATOR)
2208 if (!last_was_slash)
2209 *q++ = G_DIR_SEPARATOR;
2211 last_was_slash = TRUE;
2215 if (last_was_slash && *p == '.')
2217 if (*(p + 1) == G_DIR_SEPARATOR ||
2220 if (*(p + 1) == '\0')
2225 else if (*(p + 1) == '.' &&
2226 (*(p + 2) == G_DIR_SEPARATOR ||
2229 if (q > filename + 1)
2232 while (q > filename + 1 &&
2233 *(q - 1) != G_DIR_SEPARATOR)
2237 if (*(p + 2) == '\0')
2245 last_was_slash = FALSE;
2251 last_was_slash = FALSE;
2258 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
2265 _resolve_symlink (const char *file)
2273 f = g_strdup (file);
2275 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK))
2277 link = g_file_read_link (f, &error);
2280 g_error_free (error);
2286 dir = g_path_get_dirname (f);
2287 f1 = g_strdup_printf ("%s/%s", dir, link);
2296 _canonicalize_filename (f);
2301 _resolve_dev_root (void)
2303 static gboolean have_real_dev_root = FALSE;
2304 static char real_dev_root[256];
2305 struct stat statbuf;
2307 /* see if it's cached already */
2308 if (have_real_dev_root)
2311 /* otherwise we're going to find it right away.. */
2312 have_real_dev_root = TRUE;
2314 if (stat ("/dev/root", &statbuf) == 0)
2316 if (! S_ISLNK (statbuf.st_mode))
2318 dev_t root_dev = statbuf.st_dev;
2321 /* see if device with similar major:minor as /dev/root is mention
2322 * in /etc/mtab (it usually is)
2324 f = fopen ("/etc/mtab", "r");
2327 struct mntent *entp;
2328 #ifdef HAVE_GETMNTENT_R
2331 while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL)
2335 while ((entp = getmntent (f)) != NULL)
2338 if (stat (entp->mnt_fsname, &statbuf) == 0 &&
2339 statbuf.st_dev == root_dev)
2341 strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
2342 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2350 #ifndef HAVE_GETMNTENT_R
2351 G_UNLOCK (getmntent);
2355 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2361 resolved = _resolve_symlink ("/dev/root");
2362 if (resolved != NULL)
2364 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
2365 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2373 strcpy (real_dev_root, "/dev/root");
2376 return real_dev_root;