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, see <http://www.gnu.org/licenses/>.
20 * 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>
48 #include <sys/statfs.h>
50 #if HAVE_SYS_STATVFS_H
51 #include <sys/statvfs.h>
55 #elif HAVE_SYS_MOUNT_H
57 #include <sys/param.h>
59 #include <sys/mount.h>
66 #include "gunixmounts.h"
68 #include "gfilemonitor.h"
70 #include "gthemedicon.h"
71 #include "gcontextspecificgroup.h"
75 static const char *_resolve_dev_root (void);
80 * @include: gio/gunixmounts.h
81 * @short_description: UNIX mounts
83 * Routines for managing mounted UNIX mount points and paths.
85 * Note that `<gio/gunixmounts.h>` belongs to the UNIX-specific GIO
86 * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config
92 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
93 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
94 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
95 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
96 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
97 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
98 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
99 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
100 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
101 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
102 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
103 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
104 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
106 * Types of UNIX mounts.
109 G_UNIX_MOUNT_TYPE_UNKNOWN,
110 G_UNIX_MOUNT_TYPE_FLOPPY,
111 G_UNIX_MOUNT_TYPE_CDROM,
112 G_UNIX_MOUNT_TYPE_NFS,
113 G_UNIX_MOUNT_TYPE_ZIP,
114 G_UNIX_MOUNT_TYPE_JAZ,
115 G_UNIX_MOUNT_TYPE_MEMSTICK,
116 G_UNIX_MOUNT_TYPE_CF,
117 G_UNIX_MOUNT_TYPE_SM,
118 G_UNIX_MOUNT_TYPE_SDMMC,
119 G_UNIX_MOUNT_TYPE_IPOD,
120 G_UNIX_MOUNT_TYPE_CAMERA,
124 struct _GUnixMountEntry {
127 char *filesystem_type;
128 gboolean is_read_only;
129 gboolean is_system_internal;
132 struct _GUnixMountPoint {
135 char *filesystem_type;
137 gboolean is_read_only;
138 gboolean is_user_mountable;
139 gboolean is_loopback;
142 static GList *_g_get_unix_mounts (void);
143 static GList *_g_get_unix_mount_points (void);
145 static guint64 mount_poller_time = 0;
147 #ifdef HAVE_SYS_MNTTAB_H
148 #define MNTOPT_RO "ro"
154 #include <libmount/libmount.h>
156 #elif defined (HAVE_SYS_MNTTAB_H)
157 #include <sys/mnttab.h>
160 #ifdef HAVE_SYS_VFSTAB_H
161 #include <sys/vfstab.h>
164 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
165 #include <sys/mntctl.h>
167 #include <sys/vmount.h>
171 #if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
172 #include <sys/param.h>
173 #include <sys/ucred.h>
174 #include <sys/mount.h>
176 #ifdef HAVE_SYS_SYSCTL_H
177 #include <sys/sysctl.h>
181 #ifndef HAVE_SETMNTENT
182 #define setmntent(f,m) fopen(f,m)
184 #ifndef HAVE_ENDMNTENT
185 #define endmntent(f) fclose(f)
189 is_in (const char *value, const char *set[])
192 for (i = 0; set[i] != NULL; i++)
194 if (strcmp (set[i], value) == 0)
201 * g_unix_is_mount_path_system_internal:
202 * @mount_path: (type filename): a mount path, e.g. `/media/disk` or `/usr`
204 * Determines if @mount_path is considered an implementation of the
205 * OS. This is primarily used for hiding mountable and mounted volumes
206 * that only are used in the OS and has little to no relevance to the
209 * Returns: %TRUE if @mount_path is considered an implementation detail
213 g_unix_is_mount_path_system_internal (const char *mount_path)
215 const char *ignore_mountpoints[] = {
216 /* Includes all FHS 2.3 toplevel dirs and other specialized
217 * directories that we want to hide from the user.
219 "/", /* we already have "Filesystem root" in Nautilus */
222 "/compat/linux/proc",
251 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
254 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
262 if (is_in (mount_path, ignore_mountpoints))
265 if (g_str_has_prefix (mount_path, "/dev/") ||
266 g_str_has_prefix (mount_path, "/proc/") ||
267 g_str_has_prefix (mount_path, "/sys/"))
270 if (g_str_has_suffix (mount_path, "/.gvfs"))
277 guess_system_internal (const char *mountpoint,
281 const char *ignore_fs[] = {
305 const char *ignore_devices[] = {
315 if (is_in (fs, ignore_fs))
318 if (is_in (device, ignore_devices))
321 if (g_unix_is_mount_path_system_internal (mountpoint))
327 /* GUnixMounts (ie: mtab) implementations {{{1 */
329 static GUnixMountEntry *
330 create_unix_mount_entry (const char *device_path,
331 const char *mount_path,
332 const char *filesystem_type,
333 gboolean is_read_only)
335 GUnixMountEntry *mount_entry = NULL;
337 mount_entry = g_new0 (GUnixMountEntry, 1);
338 mount_entry->device_path = g_strdup (device_path);
339 mount_entry->mount_path = g_strdup (mount_path);
340 mount_entry->filesystem_type = g_strdup (filesystem_type);
341 mount_entry->is_read_only = is_read_only;
343 mount_entry->is_system_internal =
344 guess_system_internal (mount_entry->mount_path,
345 mount_entry->filesystem_type,
346 mount_entry->device_path);
350 static GUnixMountPoint *
351 create_unix_mount_point (const char *device_path,
352 const char *mount_path,
353 const char *filesystem_type,
355 gboolean is_read_only,
356 gboolean is_user_mountable,
357 gboolean is_loopback)
359 GUnixMountPoint *mount_point = NULL;
361 mount_point = g_new0 (GUnixMountPoint, 1);
362 mount_point->device_path = g_strdup (device_path);
363 mount_point->mount_path = g_strdup (mount_path);
364 mount_point->filesystem_type = g_strdup (filesystem_type);
365 mount_point->options = g_strdup (options);
366 mount_point->is_read_only = is_read_only;
367 mount_point->is_user_mountable = is_user_mountable;
368 mount_point->is_loopback = is_loopback;
373 /* mntent.h (Linux, GNU, NSS) {{{2 */
378 /* For documentation on /proc/self/mountinfo see
379 * http://www.kernel.org/doc/Documentation/filesystems/proc.txt
381 #define PROC_MOUNTINFO_PATH "/proc/self/mountinfo"
384 _g_get_unix_mounts (void)
386 struct libmnt_table *table = NULL;
387 struct libmnt_context *ctxt = NULL;
388 struct libmnt_iter* iter = NULL;
389 struct libmnt_fs *fs = NULL;
390 GUnixMountEntry *mount_entry = NULL;
391 GList *return_list = NULL;
393 ctxt = mnt_new_context ();
394 mnt_context_get_mtab (ctxt, &table);
398 iter = mnt_new_iter (MNT_ITER_FORWARD);
399 while (mnt_table_next_fs (table, iter, &fs) == 0)
401 const char *device_path = NULL;
402 char *mount_options = NULL;
403 unsigned long mount_flags = 0;
404 gboolean is_read_only = FALSE;
406 if (!mnt_table_is_fs_mounted (table, fs))
409 device_path = mnt_fs_get_source (fs);
410 if (g_strcmp0 (device_path, "/dev/root") == 0)
411 device_path = _resolve_dev_root ();
413 mount_options = mnt_fs_strdup_options (fs);
416 mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
417 g_free (mount_options);
419 is_read_only = (mount_flags & MS_RDONLY) ? TRUE : FALSE;
421 mount_entry = create_unix_mount_entry (device_path,
422 mnt_fs_get_target (fs),
423 mnt_fs_get_fstype (fs),
426 return_list = g_list_prepend (return_list, mount_entry);
428 mnt_free_iter (iter);
431 mnt_free_context (ctxt);
433 return g_list_reverse (return_list);
439 get_mtab_read_file (void)
443 return "/proc/mounts";
445 return _PATH_MOUNTED;
452 #ifndef HAVE_GETMNTENT_R
453 G_LOCK_DEFINE_STATIC(getmntent);
457 _g_get_unix_mounts (void)
459 #ifdef HAVE_GETMNTENT_R
463 struct mntent *mntent;
466 GUnixMountEntry *mount_entry;
467 GHashTable *mounts_hash;
470 read_file = get_mtab_read_file ();
472 file = setmntent (read_file, "r");
478 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
480 #ifdef HAVE_GETMNTENT_R
481 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
484 while ((mntent = getmntent (file)) != NULL)
487 const char *device_path = NULL;
488 gboolean is_read_only = FALSE;
490 /* ignore any mnt_fsname that is repeated and begins with a '/'
492 * We do this to avoid being fooled by --bind mounts, since
493 * these have the same device as the location they bind to.
494 * It's not an ideal solution to the problem, but it's likely that
495 * the most important mountpoint is first and the --bind ones after
496 * that aren't as important. So it should work.
498 * The '/' is to handle procfs, tmpfs and other no device mounts.
500 if (mntent->mnt_fsname != NULL &&
501 mntent->mnt_fsname[0] == '/' &&
502 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
505 if (g_strcmp0 (mntent->mnt_fsname, "/dev/root") == 0)
506 device_path = _resolve_dev_root ();
508 device_path = mntent->mnt_fsname;
510 #if defined (HAVE_HASMNTOPT)
511 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
515 mount_entry = create_unix_mount_entry (device_path,
520 g_hash_table_insert (mounts_hash,
521 mount_entry->device_path,
522 mount_entry->device_path);
524 return_list = g_list_prepend (return_list, mount_entry);
526 g_hash_table_destroy (mounts_hash);
530 #ifndef HAVE_GETMNTENT_R
531 G_UNLOCK (getmntent);
534 return g_list_reverse (return_list);
537 #endif /* HAVE_LIBMOUNT */
540 get_mtab_monitor_file (void)
542 static char *mountinfo_path = NULL;
547 if (mountinfo_path != NULL)
548 return mountinfo_path;
551 /* If using libmount we'll have the logic in place to read mountinfo */
552 if (stat (PROC_MOUNTINFO_PATH, &buf) == 0)
554 mountinfo_path = PROC_MOUNTINFO_PATH;
555 return mountinfo_path;
561 mountinfo_path = "/proc/mounts";
563 mountinfo_path = _PATH_MOUNTED;
566 mountinfo_path = "/etc/mtab";
569 return mountinfo_path;
573 #elif defined (HAVE_SYS_MNTTAB_H)
575 G_LOCK_DEFINE_STATIC(getmntent);
578 get_mtab_read_file (void)
581 return _PATH_MOUNTED;
583 return "/etc/mnttab";
588 get_mtab_monitor_file (void)
590 return get_mtab_read_file ();
594 _g_get_unix_mounts (void)
596 struct mnttab mntent;
599 GUnixMountEntry *mount_entry;
602 read_file = get_mtab_read_file ();
604 file = setmntent (read_file, "r");
611 while (! getmntent (file, &mntent))
613 gboolean is_read_only = FALSE;
615 #if defined (HAVE_HASMNTOPT)
616 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
620 mount_entry = create_unix_mount_entry (mntent.mnt_special,
625 return_list = g_list_prepend (return_list, mount_entry);
630 G_UNLOCK (getmntent);
632 return g_list_reverse (return_list);
635 /* mntctl.h (AIX) {{{2 */
636 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
639 get_mtab_monitor_file (void)
645 _g_get_unix_mounts (void)
647 struct vfs_ent *fs_info;
648 struct vmount *vmount_info;
650 unsigned int vmount_size;
654 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
656 g_warning ("Unable to know the number of mounted volumes\n");
661 vmount_info = (struct vmount*)g_malloc (vmount_size);
663 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
665 if (vmount_info->vmt_revision != VMT_REVISION)
666 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
668 if (vmount_number < 0)
670 g_warning ("Unable to recover mounted volumes information\n");
672 g_free (vmount_info);
677 while (vmount_number > 0)
679 gboolean is_read_only = FALSE;
681 fs_info = getvfsbytype (vmount_info->vmt_gfstype);
683 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
684 is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
686 mount_entry = create_unix_mount_entry (vmt2dataptr (vmount_info, VMT_OBJECT),
687 vmt2dataptr (vmount_info, VMT_STUB),
688 fs_info == NULL ? "unknown" : fs_info->vfsent_name,
691 return_list = g_list_prepend (return_list, mount_entry);
693 vmount_info = (struct vmount *)( (char*)vmount_info
694 + vmount_info->vmt_length);
698 g_free (vmount_info);
700 return g_list_reverse (return_list);
703 /* sys/mount.h {{{2 */
704 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
707 get_mtab_monitor_file (void)
713 _g_get_unix_mounts (void)
715 #if defined(USE_STATVFS)
716 struct statvfs *mntent = NULL;
717 #elif defined(USE_STATFS)
718 struct statfs *mntent = NULL;
720 #error statfs juggling failed
724 GUnixMountEntry *mount_entry;
727 /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
728 #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
729 num_mounts = getvfsstat (NULL, 0, ST_NOWAIT);
730 #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
731 num_mounts = getfsstat (NULL, 0, MNT_NOWAIT);
733 if (num_mounts == -1)
736 bufsize = num_mounts * sizeof (*mntent);
737 mntent = g_malloc (bufsize);
738 #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
739 num_mounts = getvfsstat (mntent, bufsize, ST_NOWAIT);
740 #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
741 num_mounts = getfsstat (mntent, bufsize, MNT_NOWAIT);
743 if (num_mounts == -1)
748 for (i = 0; i < num_mounts; i++)
750 gboolean is_read_only = FALSE;
752 #if defined(USE_STATVFS)
753 if (mntent[i].f_flag & ST_RDONLY)
754 #elif defined(USE_STATFS)
755 if (mntent[i].f_flags & MNT_RDONLY)
757 #error statfs juggling failed
761 mount_entry = create_unix_mount_entry (mntent[i].f_mntfromname,
762 mntent[i].f_mntonname,
763 mntent[i].f_fstypename,
766 return_list = g_list_prepend (return_list, mount_entry);
771 return g_list_reverse (return_list);
775 #elif defined(__INTERIX)
778 get_mtab_monitor_file (void)
784 _g_get_unix_mounts (void)
787 GList* return_list = NULL;
788 char filename[9 + NAME_MAX];
790 dirp = opendir ("/dev/fs");
793 g_warning ("unable to read /dev/fs!");
799 struct statvfs statbuf;
801 struct dirent* result;
803 if (readdir_r (dirp, &entry, &result) || result == NULL)
806 strcpy (filename, "/dev/fs/");
807 strcat (filename, entry.d_name);
809 if (statvfs (filename, &statbuf) == 0)
811 GUnixMountEntry* mount_entry = g_new0(GUnixMountEntry, 1);
813 mount_entry->mount_path = g_strdup (statbuf.f_mntonname);
814 mount_entry->device_path = g_strdup (statbuf.f_mntfromname);
815 mount_entry->filesystem_type = g_strdup (statbuf.f_fstypename);
817 if (statbuf.f_flag & ST_RDONLY)
818 mount_entry->is_read_only = TRUE;
820 return_list = g_list_prepend(return_list, mount_entry);
824 return_list = g_list_reverse (return_list);
831 /* Common code {{{2 */
833 #error No _g_get_unix_mounts() implementation for system
836 /* GUnixMountPoints (ie: fstab) implementations {{{1 */
838 /* _g_get_unix_mount_points():
840 * don't return swap and ignore mounts.
844 get_fstab_file (void)
847 return (char *) mnt_get_fstab_path ();
849 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
851 return "/etc/filesystems";
852 #elif defined(_PATH_MNTTAB)
854 #elif defined(VFSTAB)
862 /* mntent.h (Linux, GNU, NSS) {{{2 */
868 _g_get_unix_mount_points (void)
870 struct libmnt_table *table = NULL;
871 struct libmnt_context *ctxt = NULL;
872 struct libmnt_iter* iter = NULL;
873 struct libmnt_fs *fs = NULL;
874 GUnixMountPoint *mount_point = NULL;
875 GList *return_list = NULL;
877 ctxt = mnt_new_context ();
878 mnt_context_get_fstab (ctxt, &table);
882 iter = mnt_new_iter (MNT_ITER_FORWARD);
883 while (mnt_table_next_fs (table, iter, &fs) == 0)
885 const char *device_path = NULL;
886 const char *mount_path = NULL;
887 const char *mount_fstype = NULL;
888 char *mount_options = NULL;
889 gboolean is_read_only = FALSE;
890 gboolean is_user_mountable = FALSE;
891 gboolean is_loopback = FALSE;
893 mount_path = mnt_fs_get_target (fs);
894 if ((strcmp (mount_path, "ignore") == 0) ||
895 (strcmp (mount_path, "swap") == 0) ||
896 (strcmp (mount_path, "none") == 0))
899 mount_fstype = mnt_fs_get_fstype (fs);
900 mount_options = mnt_fs_strdup_options (fs);
903 unsigned long mount_flags = 0;
904 unsigned long userspace_flags = 0;
906 mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
907 mnt_optstr_get_flags (mount_options, &userspace_flags, mnt_get_builtin_optmap (MNT_USERSPACE_MAP));
909 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
910 if (mount_flags & MS_BIND)
912 g_free (mount_options);
916 is_read_only = (mount_flags & MS_RDONLY) != 0;
917 is_loopback = (userspace_flags & MNT_MS_LOOP) != 0;
919 if ((mount_fstype != NULL && g_strcmp0 ("supermount", mount_fstype) == 0) ||
920 ((userspace_flags & MNT_MS_USER) &&
921 (g_strstr_len (mount_options, -1, "user_xattr") == NULL)) ||
922 (g_strstr_len (mount_options, -1, "pamconsole") == NULL) ||
923 (userspace_flags & MNT_MS_USERS) ||
924 (userspace_flags & MNT_MS_OWNER))
926 is_user_mountable = TRUE;
930 device_path = mnt_fs_get_source (fs);
931 if (g_strcmp0 (device_path, "/dev/root") == 0)
932 device_path = _resolve_dev_root ();
934 mount_point = create_unix_mount_point (device_path,
942 g_free (mount_options);
944 return_list = g_list_prepend (return_list, mount_point);
946 mnt_free_iter (iter);
949 mnt_free_context (ctxt);
951 return g_list_reverse (return_list);
957 _g_get_unix_mount_points (void)
959 #ifdef HAVE_GETMNTENT_R
963 struct mntent *mntent;
966 GUnixMountPoint *mount_point;
969 read_file = get_fstab_file ();
971 file = setmntent (read_file, "r");
977 #ifdef HAVE_GETMNTENT_R
978 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
981 while ((mntent = getmntent (file)) != NULL)
984 const char *device_path = NULL;
985 gboolean is_read_only = FALSE;
986 gboolean is_user_mountable = FALSE;
987 gboolean is_loopback = FALSE;
989 if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
990 (strcmp (mntent->mnt_dir, "swap") == 0) ||
991 (strcmp (mntent->mnt_dir, "none") == 0))
994 #ifdef HAVE_HASMNTOPT
995 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
996 if (hasmntopt (mntent, "bind"))
1000 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
1001 device_path = _resolve_dev_root ();
1003 device_path = mntent->mnt_fsname;
1005 #ifdef HAVE_HASMNTOPT
1006 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
1007 is_read_only = TRUE;
1009 if (hasmntopt (mntent, "loop") != NULL)
1014 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
1015 #ifdef HAVE_HASMNTOPT
1016 || (hasmntopt (mntent, "user") != NULL
1017 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
1018 || hasmntopt (mntent, "pamconsole") != NULL
1019 || hasmntopt (mntent, "users") != NULL
1020 || hasmntopt (mntent, "owner") != NULL
1023 is_user_mountable = TRUE;
1025 mount_point = create_unix_mount_point (device_path,
1033 return_list = g_list_prepend (return_list, mount_point);
1038 #ifndef HAVE_GETMNTENT_R
1039 G_UNLOCK (getmntent);
1042 return g_list_reverse (return_list);
1045 #endif /* HAVE_LIBMOUNT */
1048 #elif defined (HAVE_SYS_MNTTAB_H)
1051 _g_get_unix_mount_points (void)
1053 struct mnttab mntent;
1056 GUnixMountPoint *mount_point;
1059 read_file = get_fstab_file ();
1061 file = setmntent (read_file, "r");
1068 while (! getmntent (file, &mntent))
1070 gboolean is_read_only = FALSE;
1071 gboolean is_user_mountable = FALSE;
1072 gboolean is_loopback = FALSE;
1074 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
1075 (strcmp (mntent.mnt_mountp, "swap") == 0) ||
1076 (strcmp (mntent.mnt_mountp, "none") == 0))
1079 #ifdef HAVE_HASMNTOPT
1080 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
1081 is_read_only = TRUE;
1083 if (hasmntopt (&mntent, "lofs") != NULL)
1087 if ((mntent.mnt_fstype != NULL)
1088 #ifdef HAVE_HASMNTOPT
1089 || (hasmntopt (&mntent, "user") != NULL
1090 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
1091 || hasmntopt (&mntent, "pamconsole") != NULL
1092 || hasmntopt (&mntent, "users") != NULL
1093 || hasmntopt (&mntent, "owner") != NULL
1096 is_user_mountable = TRUE;
1098 mount_point = create_unix_mount_point (mntent.mnt_special,
1106 return_list = g_list_prepend (return_list, mount_point);
1110 G_UNLOCK (getmntent);
1112 return g_list_reverse (return_list);
1115 /* mntctl.h (AIX) {{{2 */
1116 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
1118 /* functions to parse /etc/filesystems on aix */
1120 /* read character, ignoring comments (begin with '*', end with '\n' */
1122 aix_fs_getc (FILE *fd)
1126 while ((c = getc (fd)) == '*')
1128 while (((c = getc (fd)) != '\n') && (c != EOF))
1133 /* eat all continuous spaces in a file */
1135 aix_fs_ignorespace (FILE *fd)
1139 while ((c = aix_fs_getc (fd)) != EOF)
1141 if (!g_ascii_isspace (c))
1151 /* read one word from file */
1153 aix_fs_getword (FILE *fd,
1158 aix_fs_ignorespace (fd);
1160 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
1164 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
1176 char mnt_mount[PATH_MAX];
1177 char mnt_special[PATH_MAX];
1178 char mnt_fstype[16];
1179 char mnt_options[128];
1180 } AixMountTableEntry;
1182 /* read mount points properties */
1184 aix_fs_get (FILE *fd,
1185 AixMountTableEntry *prop)
1187 static char word[PATH_MAX] = { 0 };
1188 char value[PATH_MAX];
1193 if (aix_fs_getword (fd, word) == EOF)
1197 word[strlen(word) - 1] = 0;
1198 strcpy (prop->mnt_mount, word);
1200 /* read attributes and value */
1202 while (aix_fs_getword (fd, word) != EOF)
1204 /* test if is attribute or new stanza */
1205 if (word[strlen(word) - 1] == ':')
1209 aix_fs_getword (fd, value);
1212 aix_fs_getword (fd, value);
1214 if (strcmp (word, "dev") == 0)
1215 strcpy (prop->mnt_special, value);
1216 else if (strcmp (word, "vfs") == 0)
1217 strcpy (prop->mnt_fstype, value);
1218 else if (strcmp (word, "options") == 0)
1219 strcpy(prop->mnt_options, value);
1226 _g_get_unix_mount_points (void)
1228 struct mntent *mntent;
1231 GUnixMountPoint *mount_point;
1232 AixMountTableEntry mntent;
1235 read_file = get_fstab_file ();
1237 file = setmntent (read_file, "r");
1243 while (!aix_fs_get (file, &mntent))
1245 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
1247 mount_point = create_unix_mount_point (mntent.mnt_special,
1255 return_list = g_list_prepend (return_list, mount_point);
1261 return g_list_reverse (return_list);
1264 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
1267 _g_get_unix_mount_points (void)
1269 struct fstab *fstab = NULL;
1270 GUnixMountPoint *mount_point;
1272 #ifdef HAVE_SYS_SYSCTL_H
1274 size_t len = sizeof(usermnt);
1283 #ifdef HAVE_SYS_SYSCTL_H
1284 #if defined(HAVE_SYSCTLBYNAME)
1285 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
1286 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
1291 mib[1] = VFS_USERMOUNT;
1292 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1294 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
1299 mib[1] = KERN_USERMOUNT;
1300 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1305 while ((fstab = getfsent ()) != NULL)
1307 gboolean is_read_only = FALSE;
1308 gboolean is_user_mountable = FALSE;
1310 if (strcmp (fstab->fs_vfstype, "swap") == 0)
1313 if (strcmp (fstab->fs_type, "ro") == 0)
1314 is_read_only = TRUE;
1316 #ifdef HAVE_SYS_SYSCTL_H
1319 uid_t uid = getuid ();
1320 if (stat (fstab->fs_file, &sb) == 0)
1322 if (uid == 0 || sb.st_uid == uid)
1323 is_user_mountable = TRUE;
1328 mount_point = create_unix_mount_point (fstab->fs_spec,
1336 return_list = g_list_prepend (return_list, mount_point);
1341 return g_list_reverse (return_list);
1344 #elif defined(__INTERIX)
1346 _g_get_unix_mount_points (void)
1348 return _g_get_unix_mounts ();
1351 /* Common code {{{2 */
1353 #error No g_get_mount_table() implementation for system
1357 get_mounts_timestamp (void)
1359 const char *monitor_file;
1362 monitor_file = get_mtab_monitor_file ();
1365 if (stat (monitor_file, &buf) == 0)
1366 return (guint64)buf.st_mtime;
1370 return mount_poller_time;
1376 get_mount_points_timestamp (void)
1378 const char *monitor_file;
1381 monitor_file = get_fstab_file ();
1384 if (stat (monitor_file, &buf) == 0)
1385 return (guint64)buf.st_mtime;
1391 * g_unix_mounts_get: (skip)
1392 * @time_read: (out) (allow-none): guint64 to contain a timestamp, or %NULL
1394 * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1395 * If @time_read is set, it will be filled with the mount
1396 * timestamp, allowing for checking if the mounts have changed
1397 * with g_unix_mounts_changed_since().
1399 * Returns: (element-type GUnixMountEntry) (transfer full):
1400 * a #GList of the UNIX mounts.
1403 g_unix_mounts_get (guint64 *time_read)
1406 *time_read = get_mounts_timestamp ();
1408 return _g_get_unix_mounts ();
1412 * g_unix_mount_at: (skip)
1413 * @mount_path: path for a possible unix mount.
1414 * @time_read: (out) (allow-none): guint64 to contain a timestamp.
1416 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1417 * is set, it will be filled with a unix timestamp for checking
1418 * if the mounts have changed since with g_unix_mounts_changed_since().
1420 * Returns: (transfer full): a #GUnixMountEntry.
1423 g_unix_mount_at (const char *mount_path,
1427 GUnixMountEntry *mount_entry, *found;
1429 mounts = g_unix_mounts_get (time_read);
1432 for (l = mounts; l != NULL; l = l->next)
1434 mount_entry = l->data;
1436 if (!found && strcmp (mount_path, mount_entry->mount_path) == 0)
1437 found = mount_entry;
1439 g_unix_mount_free (mount_entry);
1441 g_list_free (mounts);
1447 * g_unix_mount_points_get: (skip)
1448 * @time_read: (out) (allow-none): guint64 to contain a timestamp.
1450 * Gets a #GList of #GUnixMountPoint containing the unix mount points.
1451 * If @time_read is set, it will be filled with the mount timestamp,
1452 * allowing for checking if the mounts have changed with
1453 * g_unix_mount_points_changed_since().
1455 * Returns: (element-type GUnixMountPoint) (transfer full):
1456 * a #GList of the UNIX mountpoints.
1459 g_unix_mount_points_get (guint64 *time_read)
1462 *time_read = get_mount_points_timestamp ();
1464 return _g_get_unix_mount_points ();
1468 * g_unix_mounts_changed_since:
1469 * @time: guint64 to contain a timestamp.
1471 * Checks if the unix mounts have changed since a given unix time.
1473 * Returns: %TRUE if the mounts have changed since @time.
1476 g_unix_mounts_changed_since (guint64 time)
1478 return get_mounts_timestamp () != time;
1482 * g_unix_mount_points_changed_since:
1483 * @time: guint64 to contain a timestamp.
1485 * Checks if the unix mount points have changed since a given unix time.
1487 * Returns: %TRUE if the mount points have changed since @time.
1490 g_unix_mount_points_changed_since (guint64 time)
1492 return get_mount_points_timestamp () != time;
1495 /* GUnixMountMonitor {{{1 */
1499 MOUNTPOINTS_CHANGED,
1503 static guint signals[LAST_SIGNAL];
1505 struct _GUnixMountMonitor {
1508 GMainContext *context;
1511 struct _GUnixMountMonitorClass {
1512 GObjectClass parent_class;
1516 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT);
1518 static GContextSpecificGroup mount_monitor_group;
1519 static GFileMonitor *fstab_monitor;
1520 static GFileMonitor *mtab_monitor;
1521 static GSource *proc_mounts_watch_source;
1522 static GList *mount_poller_mounts;
1525 fstab_file_changed (GFileMonitor *monitor,
1528 GFileMonitorEvent event_type,
1531 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1532 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1533 event_type != G_FILE_MONITOR_EVENT_DELETED)
1536 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
1540 mtab_file_changed (GFileMonitor *monitor,
1543 GFileMonitorEvent event_type,
1546 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1547 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1548 event_type != G_FILE_MONITOR_EVENT_DELETED)
1551 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
1555 proc_mounts_changed (GIOChannel *channel,
1559 if (cond & G_IO_ERR)
1560 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
1566 mount_change_poller (gpointer user_data)
1568 GList *current_mounts, *new_it, *old_it;
1569 gboolean has_changed = FALSE;
1571 current_mounts = _g_get_unix_mounts ();
1573 for ( new_it = current_mounts, old_it = mount_poller_mounts;
1574 new_it != NULL && old_it != NULL;
1575 new_it = g_list_next (new_it), old_it = g_list_next (old_it) )
1577 if (g_unix_mount_compare (new_it->data, old_it->data) != 0)
1583 if (!(new_it == NULL && old_it == NULL))
1586 g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
1588 mount_poller_mounts = current_mounts;
1592 mount_poller_time = (guint64) g_get_monotonic_time ();
1593 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
1601 mount_monitor_stop (void)
1605 g_file_monitor_cancel (fstab_monitor);
1606 g_object_unref (fstab_monitor);
1609 if (proc_mounts_watch_source != NULL)
1610 g_source_destroy (proc_mounts_watch_source);
1614 g_file_monitor_cancel (mtab_monitor);
1615 g_object_unref (mtab_monitor);
1618 g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
1622 mount_monitor_start (void)
1626 if (get_fstab_file () != NULL)
1628 file = g_file_new_for_path (get_fstab_file ());
1629 fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1630 g_object_unref (file);
1632 g_signal_connect (fstab_monitor, "changed", (GCallback)fstab_file_changed, NULL);
1635 if (get_mtab_monitor_file () != NULL)
1637 const gchar *mtab_path;
1639 mtab_path = get_mtab_monitor_file ();
1640 /* Monitoring files in /proc/ is special - can't just use GFileMonitor.
1641 * See 'man proc' for more details.
1643 if (g_str_has_prefix (mtab_path, "/proc/"))
1645 GIOChannel *proc_mounts_channel;
1646 GError *error = NULL;
1647 proc_mounts_channel = g_io_channel_new_file (mtab_path, "r", &error);
1648 if (proc_mounts_channel == NULL)
1650 g_warning ("Error creating IO channel for %s: %s (%s, %d)", mtab_path,
1651 error->message, g_quark_to_string (error->domain), error->code);
1652 g_error_free (error);
1656 proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
1657 g_source_set_callback (proc_mounts_watch_source,
1658 (GSourceFunc) proc_mounts_changed,
1660 g_source_attach (proc_mounts_watch_source,
1661 g_main_context_get_thread_default ());
1662 g_source_unref (proc_mounts_watch_source);
1663 g_io_channel_unref (proc_mounts_channel);
1668 file = g_file_new_for_path (mtab_path);
1669 mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1670 g_object_unref (file);
1671 g_signal_connect (mtab_monitor, "changed", (GCallback)mtab_file_changed, NULL);
1676 proc_mounts_watch_source = g_timeout_source_new_seconds (3);
1677 mount_poller_mounts = _g_get_unix_mounts ();
1678 mount_poller_time = (guint64)g_get_monotonic_time ();
1679 g_source_set_callback (proc_mounts_watch_source,
1680 mount_change_poller,
1682 g_source_attach (proc_mounts_watch_source,
1683 g_main_context_get_thread_default ());
1684 g_source_unref (proc_mounts_watch_source);
1689 g_unix_mount_monitor_finalize (GObject *object)
1691 GUnixMountMonitor *monitor;
1693 monitor = G_UNIX_MOUNT_MONITOR (object);
1695 g_context_specific_group_remove (&mount_monitor_group, monitor->context, monitor, mount_monitor_stop);
1697 G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
1701 g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
1703 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1705 gobject_class->finalize = g_unix_mount_monitor_finalize;
1708 * GUnixMountMonitor::mounts-changed:
1709 * @monitor: the object on which the signal is emitted
1711 * Emitted when the unix mounts have changed.
1713 signals[MOUNTS_CHANGED] =
1714 g_signal_new (I_("mounts-changed"),
1715 G_TYPE_FROM_CLASS (klass),
1719 g_cclosure_marshal_VOID__VOID,
1723 * GUnixMountMonitor::mountpoints-changed:
1724 * @monitor: the object on which the signal is emitted
1726 * Emitted when the unix mount points have changed.
1728 signals[MOUNTPOINTS_CHANGED] =
1729 g_signal_new (I_("mountpoints-changed"),
1730 G_TYPE_FROM_CLASS (klass),
1734 g_cclosure_marshal_VOID__VOID,
1739 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1744 * g_unix_mount_monitor_set_rate_limit:
1745 * @mount_monitor: a #GUnixMountMonitor
1746 * @limit_msec: a integer with the limit in milliseconds to
1749 * This function does nothing.
1751 * Before 2.44, this was a partially-effective way of controlling the
1752 * rate at which events would be reported under some uncommon
1753 * circumstances. Since @mount_monitor is a singleton, it also meant
1754 * that calling this function would have side effects for other users of
1759 * Deprecated:2.44:This function does nothing. Don't call it.
1762 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
1768 * g_unix_mount_monitor_get:
1770 * Gets the #GUnixMountMonitor for the current thread-default main
1773 * The mount monitor can be used to monitor for changes to the list of
1774 * mounted filesystems as well as the list of mount points (ie: fstab
1777 * You must only call g_object_unref() on the return value from under
1778 * the same main context as you called this function.
1780 * Returns: (transfer full): the #GUnixMountMonitor.
1785 g_unix_mount_monitor_get (void)
1787 return g_context_specific_group_get (&mount_monitor_group,
1788 G_TYPE_UNIX_MOUNT_MONITOR,
1789 G_STRUCT_OFFSET(GUnixMountMonitor, context),
1790 mount_monitor_start);
1794 * g_unix_mount_monitor_new:
1796 * Deprecated alias for g_unix_mount_monitor_get().
1798 * This function was never a true constructor, which is why it was
1801 * Returns: a #GUnixMountMonitor.
1803 * Deprecated:2.44:Use g_unix_mount_monitor_get() instead.
1806 g_unix_mount_monitor_new (void)
1808 return g_unix_mount_monitor_get ();
1811 /* GUnixMount {{{1 */
1813 * g_unix_mount_free:
1814 * @mount_entry: a #GUnixMountEntry.
1816 * Frees a unix mount.
1819 g_unix_mount_free (GUnixMountEntry *mount_entry)
1821 g_return_if_fail (mount_entry != NULL);
1823 g_free (mount_entry->mount_path);
1824 g_free (mount_entry->device_path);
1825 g_free (mount_entry->filesystem_type);
1826 g_free (mount_entry);
1830 * g_unix_mount_point_free:
1831 * @mount_point: unix mount point to free.
1833 * Frees a unix mount point.
1836 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1838 g_return_if_fail (mount_point != NULL);
1840 g_free (mount_point->mount_path);
1841 g_free (mount_point->device_path);
1842 g_free (mount_point->filesystem_type);
1843 g_free (mount_point->options);
1844 g_free (mount_point);
1848 * g_unix_mount_compare:
1849 * @mount1: first #GUnixMountEntry to compare.
1850 * @mount2: second #GUnixMountEntry to compare.
1852 * Compares two unix mounts.
1854 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1855 * or less than @mount2, respectively.
1858 g_unix_mount_compare (GUnixMountEntry *mount1,
1859 GUnixMountEntry *mount2)
1863 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1865 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1869 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1873 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1877 res = mount1->is_read_only - mount2->is_read_only;
1885 * g_unix_mount_get_mount_path:
1886 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1888 * Gets the mount path for a unix mount.
1890 * Returns: (type filename): the mount path for @mount_entry.
1893 g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
1895 g_return_val_if_fail (mount_entry != NULL, NULL);
1897 return mount_entry->mount_path;
1901 * g_unix_mount_get_device_path:
1902 * @mount_entry: a #GUnixMount.
1904 * Gets the device path for a unix mount.
1906 * Returns: (type filename): a string containing the device path.
1909 g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
1911 g_return_val_if_fail (mount_entry != NULL, NULL);
1913 return mount_entry->device_path;
1917 * g_unix_mount_get_fs_type:
1918 * @mount_entry: a #GUnixMount.
1920 * Gets the filesystem type for the unix mount.
1922 * Returns: a string containing the file system type.
1925 g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
1927 g_return_val_if_fail (mount_entry != NULL, NULL);
1929 return mount_entry->filesystem_type;
1933 * g_unix_mount_is_readonly:
1934 * @mount_entry: a #GUnixMount.
1936 * Checks if a unix mount is mounted read only.
1938 * Returns: %TRUE if @mount_entry is read only.
1941 g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
1943 g_return_val_if_fail (mount_entry != NULL, FALSE);
1945 return mount_entry->is_read_only;
1949 * g_unix_mount_is_system_internal:
1950 * @mount_entry: a #GUnixMount.
1952 * Checks if a unix mount is a system path.
1954 * Returns: %TRUE if the unix mount is for a system path.
1957 g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
1959 g_return_val_if_fail (mount_entry != NULL, FALSE);
1961 return mount_entry->is_system_internal;
1964 /* GUnixMountPoint {{{1 */
1966 * g_unix_mount_point_compare:
1967 * @mount1: a #GUnixMount.
1968 * @mount2: a #GUnixMount.
1970 * Compares two unix mount points.
1972 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1973 * or less than @mount2, respectively.
1976 g_unix_mount_point_compare (GUnixMountPoint *mount1,
1977 GUnixMountPoint *mount2)
1981 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1983 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1987 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1991 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1995 res = g_strcmp0 (mount1->options, mount2->options);
1999 res = mount1->is_read_only - mount2->is_read_only;
2003 res = mount1->is_user_mountable - mount2->is_user_mountable;
2007 res = mount1->is_loopback - mount2->is_loopback;
2015 * g_unix_mount_point_get_mount_path:
2016 * @mount_point: a #GUnixMountPoint.
2018 * Gets the mount path for a unix mount point.
2020 * Returns: (type filename): a string containing the mount path.
2023 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
2025 g_return_val_if_fail (mount_point != NULL, NULL);
2027 return mount_point->mount_path;
2031 * g_unix_mount_point_get_device_path:
2032 * @mount_point: a #GUnixMountPoint.
2034 * Gets the device path for a unix mount point.
2036 * Returns: (type filename): a string containing the device path.
2039 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
2041 g_return_val_if_fail (mount_point != NULL, NULL);
2043 return mount_point->device_path;
2047 * g_unix_mount_point_get_fs_type:
2048 * @mount_point: a #GUnixMountPoint.
2050 * Gets the file system type for the mount point.
2052 * Returns: a string containing the file system type.
2055 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
2057 g_return_val_if_fail (mount_point != NULL, NULL);
2059 return mount_point->filesystem_type;
2063 * g_unix_mount_point_get_options:
2064 * @mount_point: a #GUnixMountPoint.
2066 * Gets the options for the mount point.
2068 * Returns: a string containing the options.
2073 g_unix_mount_point_get_options (GUnixMountPoint *mount_point)
2075 g_return_val_if_fail (mount_point != NULL, NULL);
2077 return mount_point->options;
2081 * g_unix_mount_point_is_readonly:
2082 * @mount_point: a #GUnixMountPoint.
2084 * Checks if a unix mount point is read only.
2086 * Returns: %TRUE if a mount point is read only.
2089 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
2091 g_return_val_if_fail (mount_point != NULL, FALSE);
2093 return mount_point->is_read_only;
2097 * g_unix_mount_point_is_user_mountable:
2098 * @mount_point: a #GUnixMountPoint.
2100 * Checks if a unix mount point is mountable by the user.
2102 * Returns: %TRUE if the mount point is user mountable.
2105 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
2107 g_return_val_if_fail (mount_point != NULL, FALSE);
2109 return mount_point->is_user_mountable;
2113 * g_unix_mount_point_is_loopback:
2114 * @mount_point: a #GUnixMountPoint.
2116 * Checks if a unix mount point is a loopback device.
2118 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
2121 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
2123 g_return_val_if_fail (mount_point != NULL, FALSE);
2125 return mount_point->is_loopback;
2128 static GUnixMountType
2129 guess_mount_type (const char *mount_path,
2130 const char *device_path,
2131 const char *filesystem_type)
2133 GUnixMountType type;
2136 type = G_UNIX_MOUNT_TYPE_UNKNOWN;
2138 if ((strcmp (filesystem_type, "udf") == 0) ||
2139 (strcmp (filesystem_type, "iso9660") == 0) ||
2140 (strcmp (filesystem_type, "cd9660") == 0))
2141 type = G_UNIX_MOUNT_TYPE_CDROM;
2142 else if ((strcmp (filesystem_type, "nfs") == 0) ||
2143 (strcmp (filesystem_type, "nfs4") == 0))
2144 type = G_UNIX_MOUNT_TYPE_NFS;
2145 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
2146 g_str_has_prefix (device_path, "/dev/fd") ||
2147 g_str_has_prefix (device_path, "/dev/floppy"))
2148 type = G_UNIX_MOUNT_TYPE_FLOPPY;
2149 else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
2150 g_str_has_prefix (device_path, "/dev/acd") ||
2151 g_str_has_prefix (device_path, "/dev/cd"))
2152 type = G_UNIX_MOUNT_TYPE_CDROM;
2153 else if (g_str_has_prefix (device_path, "/vol/"))
2155 const char *name = mount_path + strlen ("/");
2157 if (g_str_has_prefix (name, "cdrom"))
2158 type = G_UNIX_MOUNT_TYPE_CDROM;
2159 else if (g_str_has_prefix (name, "floppy") ||
2160 g_str_has_prefix (device_path, "/vol/dev/diskette/"))
2161 type = G_UNIX_MOUNT_TYPE_FLOPPY;
2162 else if (g_str_has_prefix (name, "rmdisk"))
2163 type = G_UNIX_MOUNT_TYPE_ZIP;
2164 else if (g_str_has_prefix (name, "jaz"))
2165 type = G_UNIX_MOUNT_TYPE_JAZ;
2166 else if (g_str_has_prefix (name, "memstick"))
2167 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
2171 basename = g_path_get_basename (mount_path);
2173 if (g_str_has_prefix (basename, "cdr") ||
2174 g_str_has_prefix (basename, "cdwriter") ||
2175 g_str_has_prefix (basename, "burn") ||
2176 g_str_has_prefix (basename, "dvdr"))
2177 type = G_UNIX_MOUNT_TYPE_CDROM;
2178 else if (g_str_has_prefix (basename, "floppy"))
2179 type = G_UNIX_MOUNT_TYPE_FLOPPY;
2180 else if (g_str_has_prefix (basename, "zip"))
2181 type = G_UNIX_MOUNT_TYPE_ZIP;
2182 else if (g_str_has_prefix (basename, "jaz"))
2183 type = G_UNIX_MOUNT_TYPE_JAZ;
2184 else if (g_str_has_prefix (basename, "camera"))
2185 type = G_UNIX_MOUNT_TYPE_CAMERA;
2186 else if (g_str_has_prefix (basename, "memstick") ||
2187 g_str_has_prefix (basename, "memory_stick") ||
2188 g_str_has_prefix (basename, "ram"))
2189 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
2190 else if (g_str_has_prefix (basename, "compact_flash"))
2191 type = G_UNIX_MOUNT_TYPE_CF;
2192 else if (g_str_has_prefix (basename, "smart_media"))
2193 type = G_UNIX_MOUNT_TYPE_SM;
2194 else if (g_str_has_prefix (basename, "sd_mmc"))
2195 type = G_UNIX_MOUNT_TYPE_SDMMC;
2196 else if (g_str_has_prefix (basename, "ipod"))
2197 type = G_UNIX_MOUNT_TYPE_IPOD;
2202 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
2203 type = G_UNIX_MOUNT_TYPE_HD;
2209 * g_unix_mount_guess_type:
2210 * @mount_entry: a #GUnixMount.
2212 * Guesses the type of a unix mount. If the mount type cannot be
2213 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
2215 * Returns: a #GUnixMountType.
2217 static GUnixMountType
2218 g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
2220 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2221 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2222 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2223 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2225 return guess_mount_type (mount_entry->mount_path,
2226 mount_entry->device_path,
2227 mount_entry->filesystem_type);
2231 * g_unix_mount_point_guess_type:
2232 * @mount_point: a #GUnixMountPoint.
2234 * Guesses the type of a unix mount point.
2235 * If the mount type cannot be determined,
2236 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
2238 * Returns: a #GUnixMountType.
2240 static GUnixMountType
2241 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
2243 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2244 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2245 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2246 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2248 return guess_mount_type (mount_point->mount_path,
2249 mount_point->device_path,
2250 mount_point->filesystem_type);
2254 type_to_icon (GUnixMountType type, gboolean is_mount_point, gboolean use_symbolic)
2256 const char *icon_name;
2260 case G_UNIX_MOUNT_TYPE_HD:
2262 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2264 icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
2266 case G_UNIX_MOUNT_TYPE_FLOPPY:
2267 case G_UNIX_MOUNT_TYPE_ZIP:
2268 case G_UNIX_MOUNT_TYPE_JAZ:
2270 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2272 icon_name = use_symbolic ? "media-removable-symbolic" : "media-floppy";
2274 case G_UNIX_MOUNT_TYPE_CDROM:
2276 icon_name = use_symbolic ? "drive-optical-symbolic" : "drive-optical";
2278 icon_name = use_symbolic ? "media-optical-symbolic" : "media-optical";
2280 case G_UNIX_MOUNT_TYPE_NFS:
2281 icon_name = use_symbolic ? "folder-remote-symbolic" : "folder-remote";
2283 case G_UNIX_MOUNT_TYPE_MEMSTICK:
2285 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2287 icon_name = use_symbolic ? "media-removable-symbolic" : "media-flash";
2289 case G_UNIX_MOUNT_TYPE_CAMERA:
2291 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2293 icon_name = use_symbolic ? "camera-photo-symbolic" : "camera-photo";
2295 case G_UNIX_MOUNT_TYPE_IPOD:
2297 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2299 icon_name = use_symbolic ? "multimedia-player-symbolic" : "multimedia-player";
2301 case G_UNIX_MOUNT_TYPE_UNKNOWN:
2304 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2306 icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
2314 * g_unix_mount_guess_name:
2315 * @mount_entry: a #GUnixMountEntry
2317 * Guesses the name of a Unix mount.
2318 * The result is a translated string.
2320 * Returns: A newly allocated string that must
2321 * be freed with g_free()
2324 g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
2328 if (strcmp (mount_entry->mount_path, "/") == 0)
2329 name = g_strdup (_("Filesystem root"));
2331 name = g_filename_display_basename (mount_entry->mount_path);
2337 * g_unix_mount_guess_icon:
2338 * @mount_entry: a #GUnixMountEntry
2340 * Guesses the icon of a Unix mount.
2342 * Returns: (transfer full): a #GIcon
2345 g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
2347 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, FALSE));
2351 * g_unix_mount_guess_symbolic_icon:
2352 * @mount_entry: a #GUnixMountEntry
2354 * Guesses the symbolic icon of a Unix mount.
2356 * Returns: (transfer full): a #GIcon
2361 g_unix_mount_guess_symbolic_icon (GUnixMountEntry *mount_entry)
2363 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, TRUE));
2367 * g_unix_mount_point_guess_name:
2368 * @mount_point: a #GUnixMountPoint
2370 * Guesses the name of a Unix mount point.
2371 * The result is a translated string.
2373 * Returns: A newly allocated string that must
2374 * be freed with g_free()
2377 g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
2381 if (strcmp (mount_point->mount_path, "/") == 0)
2382 name = g_strdup (_("Filesystem root"));
2384 name = g_filename_display_basename (mount_point->mount_path);
2390 * g_unix_mount_point_guess_icon:
2391 * @mount_point: a #GUnixMountPoint
2393 * Guesses the icon of a Unix mount point.
2395 * Returns: (transfer full): a #GIcon
2398 g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
2400 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, FALSE));
2404 * g_unix_mount_point_guess_symbolic_icon:
2405 * @mount_point: a #GUnixMountPoint
2407 * Guesses the symbolic icon of a Unix mount point.
2409 * Returns: (transfer full): a #GIcon
2414 g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount_point)
2416 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, TRUE));
2420 * g_unix_mount_guess_can_eject:
2421 * @mount_entry: a #GUnixMountEntry
2423 * Guesses whether a Unix mount can be ejected.
2425 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
2428 g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
2430 GUnixMountType guessed_type;
2432 guessed_type = g_unix_mount_guess_type (mount_entry);
2433 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2434 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2441 * g_unix_mount_guess_should_display:
2442 * @mount_entry: a #GUnixMountEntry
2444 * Guesses whether a Unix mount should be displayed in the UI.
2446 * Returns: %TRUE if @mount_entry is deemed to be displayable.
2449 g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
2451 const char *mount_path;
2452 const gchar *user_name;
2453 gsize user_name_len;
2455 /* Never display internal mountpoints */
2456 if (g_unix_mount_is_system_internal (mount_entry))
2459 /* Only display things in /media (which are generally user mountable)
2460 and home dir (fuse stuff) and /run/media/$USER */
2461 mount_path = mount_entry->mount_path;
2462 if (mount_path != NULL)
2464 gboolean is_in_runtime_dir = FALSE;
2465 /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
2466 if (g_strstr_len (mount_path, -1, "/.") != NULL)
2469 /* Check /run/media/$USER/ */
2470 user_name = g_get_user_name ();
2471 user_name_len = strlen (user_name);
2472 if (strncmp (mount_path, "/run/media/", sizeof ("/run/media/") - 1) == 0 &&
2473 strncmp (mount_path + sizeof ("/run/media/") - 1, user_name, user_name_len) == 0 &&
2474 mount_path[sizeof ("/run/media/") - 1 + user_name_len] == '/')
2475 is_in_runtime_dir = TRUE;
2477 if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/"))
2480 /* Avoid displaying mounts that are not accessible to the user.
2482 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
2483 * want to avoid g_access() for mount points which can potentially
2484 * block or fail stat()'ing, such as network mounts.
2486 path = g_path_get_dirname (mount_path);
2487 if (g_str_has_prefix (path, "/media/"))
2489 if (g_access (path, R_OK|X_OK) != 0)
2497 if (mount_entry->device_path && mount_entry->device_path[0] == '/')
2500 if (g_stat (mount_entry->device_path, &st) == 0 &&
2501 S_ISBLK(st.st_mode) &&
2502 g_access (mount_path, R_OK|X_OK) != 0)
2508 if (g_str_has_prefix (mount_path, g_get_home_dir ()) &&
2509 mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
2517 * g_unix_mount_point_guess_can_eject:
2518 * @mount_point: a #GUnixMountPoint
2520 * Guesses whether a Unix mount point can be ejected.
2522 * Returns: %TRUE if @mount_point is deemed to be ejectable.
2525 g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
2527 GUnixMountType guessed_type;
2529 guessed_type = g_unix_mount_point_guess_type (mount_point);
2530 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2531 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2537 /* Utility functions {{{1 */
2539 #ifdef HAVE_MNTENT_H
2540 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
2542 _canonicalize_filename (gchar *filename)
2545 gboolean last_was_slash = FALSE;
2552 if (*p == G_DIR_SEPARATOR)
2554 if (!last_was_slash)
2555 *q++ = G_DIR_SEPARATOR;
2557 last_was_slash = TRUE;
2561 if (last_was_slash && *p == '.')
2563 if (*(p + 1) == G_DIR_SEPARATOR ||
2566 if (*(p + 1) == '\0')
2571 else if (*(p + 1) == '.' &&
2572 (*(p + 2) == G_DIR_SEPARATOR ||
2575 if (q > filename + 1)
2578 while (q > filename + 1 &&
2579 *(q - 1) != G_DIR_SEPARATOR)
2583 if (*(p + 2) == '\0')
2591 last_was_slash = FALSE;
2597 last_was_slash = FALSE;
2604 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
2611 _resolve_symlink (const char *file)
2619 f = g_strdup (file);
2621 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK))
2623 link = g_file_read_link (f, &error);
2626 g_error_free (error);
2632 dir = g_path_get_dirname (f);
2633 f1 = g_strdup_printf ("%s/%s", dir, link);
2642 _canonicalize_filename (f);
2647 _resolve_dev_root (void)
2649 static gboolean have_real_dev_root = FALSE;
2650 static char real_dev_root[256];
2651 struct stat statbuf;
2653 /* see if it's cached already */
2654 if (have_real_dev_root)
2657 /* otherwise we're going to find it right away.. */
2658 have_real_dev_root = TRUE;
2660 if (stat ("/dev/root", &statbuf) == 0)
2662 if (! S_ISLNK (statbuf.st_mode))
2664 dev_t root_dev = statbuf.st_dev;
2667 /* see if device with similar major:minor as /dev/root is mention
2668 * in /etc/mtab (it usually is)
2670 f = fopen ("/etc/mtab", "r");
2673 struct mntent *entp;
2674 #ifdef HAVE_GETMNTENT_R
2677 while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL)
2681 while ((entp = getmntent (f)) != NULL)
2684 if (stat (entp->mnt_fsname, &statbuf) == 0 &&
2685 statbuf.st_dev == root_dev)
2687 strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
2688 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2696 #ifndef HAVE_GETMNTENT_R
2697 G_UNLOCK (getmntent);
2701 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2707 resolved = _resolve_symlink ("/dev/root");
2708 if (resolved != NULL)
2710 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
2711 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2719 strcpy (real_dev_root, "/dev/root");
2722 return real_dev_root;
2727 /* vim:set foldmethod=marker: */