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"
67 #include "glocalfileprivate.h"
69 #include "gfilemonitor.h"
71 #include "gthemedicon.h"
72 #include "gcontextspecificgroup.h"
76 static const char *_resolve_dev_root (void);
81 * @include: gio/gunixmounts.h
82 * @short_description: UNIX mounts
84 * Routines for managing mounted UNIX mount points and paths.
86 * Note that `<gio/gunixmounts.h>` belongs to the UNIX-specific GIO
87 * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config
93 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
94 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
95 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
96 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
97 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
98 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
99 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
100 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
101 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
102 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
103 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
104 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
105 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
107 * Types of UNIX mounts.
110 G_UNIX_MOUNT_TYPE_UNKNOWN
,
111 G_UNIX_MOUNT_TYPE_FLOPPY
,
112 G_UNIX_MOUNT_TYPE_CDROM
,
113 G_UNIX_MOUNT_TYPE_NFS
,
114 G_UNIX_MOUNT_TYPE_ZIP
,
115 G_UNIX_MOUNT_TYPE_JAZ
,
116 G_UNIX_MOUNT_TYPE_MEMSTICK
,
117 G_UNIX_MOUNT_TYPE_CF
,
118 G_UNIX_MOUNT_TYPE_SM
,
119 G_UNIX_MOUNT_TYPE_SDMMC
,
120 G_UNIX_MOUNT_TYPE_IPOD
,
121 G_UNIX_MOUNT_TYPE_CAMERA
,
125 struct _GUnixMountEntry
{
128 char *filesystem_type
;
129 gboolean is_read_only
;
130 gboolean is_system_internal
;
133 struct _GUnixMountPoint
{
136 char *filesystem_type
;
138 gboolean is_read_only
;
139 gboolean is_user_mountable
;
140 gboolean is_loopback
;
143 static GList
*_g_get_unix_mounts (void);
144 static GList
*_g_get_unix_mount_points (void);
146 static guint64 mount_poller_time
= 0;
148 #ifdef HAVE_SYS_MNTTAB_H
149 #define MNTOPT_RO "ro"
155 #include <libmount/libmount.h>
157 #elif defined (HAVE_SYS_MNTTAB_H)
158 #include <sys/mnttab.h>
161 #ifdef HAVE_SYS_VFSTAB_H
162 #include <sys/vfstab.h>
165 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
166 #include <sys/mntctl.h>
168 #include <sys/vmount.h>
172 #if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
173 #include <sys/param.h>
174 #include <sys/ucred.h>
175 #include <sys/mount.h>
177 #ifdef HAVE_SYS_SYSCTL_H
178 #include <sys/sysctl.h>
182 #ifndef HAVE_SETMNTENT
183 #define setmntent(f,m) fopen(f,m)
185 #ifndef HAVE_ENDMNTENT
186 #define endmntent(f) fclose(f)
190 is_in (const char *value
, const char *set
[])
193 for (i
= 0; set
[i
] != NULL
; i
++)
195 if (strcmp (set
[i
], value
) == 0)
202 * g_unix_is_mount_path_system_internal:
203 * @mount_path: (type filename): a mount path, e.g. `/media/disk` or `/usr`
205 * Determines if @mount_path is considered an implementation of the
206 * OS. This is primarily used for hiding mountable and mounted volumes
207 * that only are used in the OS and has little to no relevance to the
210 * Returns: %TRUE if @mount_path is considered an implementation detail
214 g_unix_is_mount_path_system_internal (const char *mount_path
)
216 const char *ignore_mountpoints
[] = {
217 /* Includes all FHS 2.3 toplevel dirs and other specialized
218 * directories that we want to hide from the user.
220 "/", /* we already have "Filesystem root" in Nautilus */
223 "/compat/linux/proc",
252 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
255 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
263 if (is_in (mount_path
, ignore_mountpoints
))
266 if (g_str_has_prefix (mount_path
, "/dev/") ||
267 g_str_has_prefix (mount_path
, "/proc/") ||
268 g_str_has_prefix (mount_path
, "/sys/"))
271 if (g_str_has_suffix (mount_path
, "/.gvfs"))
278 guess_system_internal (const char *mountpoint
,
282 const char *ignore_fs
[] = {
306 const char *ignore_devices
[] = {
316 if (is_in (fs
, ignore_fs
))
319 if (is_in (device
, ignore_devices
))
322 if (g_unix_is_mount_path_system_internal (mountpoint
))
328 /* GUnixMounts (ie: mtab) implementations {{{1 */
330 static GUnixMountEntry
*
331 create_unix_mount_entry (const char *device_path
,
332 const char *mount_path
,
333 const char *filesystem_type
,
334 gboolean is_read_only
)
336 GUnixMountEntry
*mount_entry
= NULL
;
338 mount_entry
= g_new0 (GUnixMountEntry
, 1);
339 mount_entry
->device_path
= g_strdup (device_path
);
340 mount_entry
->mount_path
= g_strdup (mount_path
);
341 mount_entry
->filesystem_type
= g_strdup (filesystem_type
);
342 mount_entry
->is_read_only
= is_read_only
;
344 mount_entry
->is_system_internal
=
345 guess_system_internal (mount_entry
->mount_path
,
346 mount_entry
->filesystem_type
,
347 mount_entry
->device_path
);
351 static GUnixMountPoint
*
352 create_unix_mount_point (const char *device_path
,
353 const char *mount_path
,
354 const char *filesystem_type
,
356 gboolean is_read_only
,
357 gboolean is_user_mountable
,
358 gboolean is_loopback
)
360 GUnixMountPoint
*mount_point
= NULL
;
362 mount_point
= g_new0 (GUnixMountPoint
, 1);
363 mount_point
->device_path
= g_strdup (device_path
);
364 mount_point
->mount_path
= g_strdup (mount_path
);
365 mount_point
->filesystem_type
= g_strdup (filesystem_type
);
366 mount_point
->options
= g_strdup (options
);
367 mount_point
->is_read_only
= is_read_only
;
368 mount_point
->is_user_mountable
= is_user_mountable
;
369 mount_point
->is_loopback
= is_loopback
;
374 /* mntent.h (Linux, GNU, NSS) {{{2 */
379 /* For documentation on /proc/self/mountinfo see
380 * http://www.kernel.org/doc/Documentation/filesystems/proc.txt
382 #define PROC_MOUNTINFO_PATH "/proc/self/mountinfo"
385 _g_get_unix_mounts (void)
387 struct libmnt_table
*table
= NULL
;
388 struct libmnt_context
*ctxt
= NULL
;
389 struct libmnt_iter
* iter
= NULL
;
390 struct libmnt_fs
*fs
= NULL
;
391 GUnixMountEntry
*mount_entry
= NULL
;
392 GList
*return_list
= NULL
;
394 ctxt
= mnt_new_context ();
395 mnt_context_get_mtab (ctxt
, &table
);
399 iter
= mnt_new_iter (MNT_ITER_FORWARD
);
400 while (mnt_table_next_fs (table
, iter
, &fs
) == 0)
402 const char *device_path
= NULL
;
403 char *mount_options
= NULL
;
404 unsigned long mount_flags
= 0;
405 gboolean is_read_only
= FALSE
;
407 if (!mnt_table_is_fs_mounted (table
, fs
))
410 device_path
= mnt_fs_get_source (fs
);
411 if (g_strcmp0 (device_path
, "/dev/root") == 0)
412 device_path
= _resolve_dev_root ();
414 mount_options
= mnt_fs_strdup_options (fs
);
417 mnt_optstr_get_flags (mount_options
, &mount_flags
, mnt_get_builtin_optmap (MNT_LINUX_MAP
));
418 g_free (mount_options
);
420 is_read_only
= (mount_flags
& MS_RDONLY
) ? TRUE
: FALSE
;
422 mount_entry
= create_unix_mount_entry (device_path
,
423 mnt_fs_get_target (fs
),
424 mnt_fs_get_fstype (fs
),
427 return_list
= g_list_prepend (return_list
, mount_entry
);
429 mnt_free_iter (iter
);
432 mnt_free_context (ctxt
);
434 return g_list_reverse (return_list
);
440 get_mtab_read_file (void)
444 return "/proc/mounts";
446 return _PATH_MOUNTED
;
453 #ifndef HAVE_GETMNTENT_R
454 G_LOCK_DEFINE_STATIC(getmntent
);
458 _g_get_unix_mounts (void)
460 #ifdef HAVE_GETMNTENT_R
464 struct mntent
*mntent
;
467 GUnixMountEntry
*mount_entry
;
468 GHashTable
*mounts_hash
;
471 read_file
= get_mtab_read_file ();
473 file
= setmntent (read_file
, "r");
479 mounts_hash
= g_hash_table_new (g_str_hash
, g_str_equal
);
481 #ifdef HAVE_GETMNTENT_R
482 while ((mntent
= getmntent_r (file
, &ent
, buf
, sizeof (buf
))) != NULL
)
485 while ((mntent
= getmntent (file
)) != NULL
)
488 const char *device_path
= NULL
;
489 gboolean is_read_only
= FALSE
;
491 /* ignore any mnt_fsname that is repeated and begins with a '/'
493 * We do this to avoid being fooled by --bind mounts, since
494 * these have the same device as the location they bind to.
495 * It's not an ideal solution to the problem, but it's likely that
496 * the most important mountpoint is first and the --bind ones after
497 * that aren't as important. So it should work.
499 * The '/' is to handle procfs, tmpfs and other no device mounts.
501 if (mntent
->mnt_fsname
!= NULL
&&
502 mntent
->mnt_fsname
[0] == '/' &&
503 g_hash_table_lookup (mounts_hash
, mntent
->mnt_fsname
))
506 if (g_strcmp0 (mntent
->mnt_fsname
, "/dev/root") == 0)
507 device_path
= _resolve_dev_root ();
509 device_path
= mntent
->mnt_fsname
;
511 #if defined (HAVE_HASMNTOPT)
512 if (hasmntopt (mntent
, MNTOPT_RO
) != NULL
)
516 mount_entry
= create_unix_mount_entry (device_path
,
521 g_hash_table_insert (mounts_hash
,
522 mount_entry
->device_path
,
523 mount_entry
->device_path
);
525 return_list
= g_list_prepend (return_list
, mount_entry
);
527 g_hash_table_destroy (mounts_hash
);
531 #ifndef HAVE_GETMNTENT_R
532 G_UNLOCK (getmntent
);
535 return g_list_reverse (return_list
);
538 #endif /* HAVE_LIBMOUNT */
541 get_mtab_monitor_file (void)
543 static char *mountinfo_path
= NULL
;
548 if (mountinfo_path
!= NULL
)
549 return mountinfo_path
;
552 /* If using libmount we'll have the logic in place to read mountinfo */
553 if (stat (PROC_MOUNTINFO_PATH
, &buf
) == 0)
555 mountinfo_path
= PROC_MOUNTINFO_PATH
;
556 return mountinfo_path
;
562 mountinfo_path
= "/proc/mounts";
564 mountinfo_path
= _PATH_MOUNTED
;
567 mountinfo_path
= "/etc/mtab";
570 return mountinfo_path
;
574 #elif defined (HAVE_SYS_MNTTAB_H)
576 G_LOCK_DEFINE_STATIC(getmntent
);
579 get_mtab_read_file (void)
582 return _PATH_MOUNTED
;
584 return "/etc/mnttab";
589 get_mtab_monitor_file (void)
591 return get_mtab_read_file ();
595 _g_get_unix_mounts (void)
597 struct mnttab mntent
;
600 GUnixMountEntry
*mount_entry
;
603 read_file
= get_mtab_read_file ();
605 file
= setmntent (read_file
, "r");
612 while (! getmntent (file
, &mntent
))
614 gboolean is_read_only
= FALSE
;
616 #if defined (HAVE_HASMNTOPT)
617 if (hasmntopt (&mntent
, MNTOPT_RO
) != NULL
)
621 mount_entry
= create_unix_mount_entry (mntent
.mnt_special
,
626 return_list
= g_list_prepend (return_list
, mount_entry
);
631 G_UNLOCK (getmntent
);
633 return g_list_reverse (return_list
);
636 /* mntctl.h (AIX) {{{2 */
637 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
640 get_mtab_monitor_file (void)
646 _g_get_unix_mounts (void)
648 struct vfs_ent
*fs_info
;
649 struct vmount
*vmount_info
;
651 unsigned int vmount_size
;
655 if (mntctl (MCTL_QUERY
, sizeof (vmount_size
), &vmount_size
) != 0)
657 g_warning ("Unable to know the number of mounted volumes\n");
662 vmount_info
= (struct vmount
*)g_malloc (vmount_size
);
664 vmount_number
= mntctl (MCTL_QUERY
, vmount_size
, vmount_info
);
666 if (vmount_info
->vmt_revision
!= VMT_REVISION
)
667 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION
, vmount_info
->vmt_revision
);
669 if (vmount_number
< 0)
671 g_warning ("Unable to recover mounted volumes information\n");
673 g_free (vmount_info
);
678 while (vmount_number
> 0)
680 gboolean is_read_only
= FALSE
;
682 fs_info
= getvfsbytype (vmount_info
->vmt_gfstype
);
684 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
685 is_read_only
= (vmount_info
->vmt_flags
& MNT_READONLY
) ? 1 : 0;
687 mount_entry
= create_unix_mount_entry (vmt2dataptr (vmount_info
, VMT_OBJECT
),
688 vmt2dataptr (vmount_info
, VMT_STUB
),
689 fs_info
== NULL
? "unknown" : fs_info
->vfsent_name
,
692 return_list
= g_list_prepend (return_list
, mount_entry
);
694 vmount_info
= (struct vmount
*)( (char*)vmount_info
695 + vmount_info
->vmt_length
);
699 g_free (vmount_info
);
701 return g_list_reverse (return_list
);
704 /* sys/mount.h {{{2 */
705 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
708 get_mtab_monitor_file (void)
714 _g_get_unix_mounts (void)
716 #if defined(USE_STATVFS)
717 struct statvfs
*mntent
= NULL
;
718 #elif defined(USE_STATFS)
719 struct statfs
*mntent
= NULL
;
721 #error statfs juggling failed
725 GUnixMountEntry
*mount_entry
;
728 /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
729 #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
730 num_mounts
= getvfsstat (NULL
, 0, ST_NOWAIT
);
731 #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
732 num_mounts
= getfsstat (NULL
, 0, MNT_NOWAIT
);
734 if (num_mounts
== -1)
737 bufsize
= num_mounts
* sizeof (*mntent
);
738 mntent
= g_malloc (bufsize
);
739 #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
740 num_mounts
= getvfsstat (mntent
, bufsize
, ST_NOWAIT
);
741 #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
742 num_mounts
= getfsstat (mntent
, bufsize
, MNT_NOWAIT
);
744 if (num_mounts
== -1)
749 for (i
= 0; i
< num_mounts
; i
++)
751 gboolean is_read_only
= FALSE
;
753 #if defined(USE_STATVFS)
754 if (mntent
[i
].f_flag
& ST_RDONLY
)
755 #elif defined(USE_STATFS)
756 if (mntent
[i
].f_flags
& MNT_RDONLY
)
758 #error statfs juggling failed
762 mount_entry
= create_unix_mount_entry (mntent
[i
].f_mntfromname
,
763 mntent
[i
].f_mntonname
,
764 mntent
[i
].f_fstypename
,
767 return_list
= g_list_prepend (return_list
, mount_entry
);
772 return g_list_reverse (return_list
);
776 #elif defined(__INTERIX)
779 get_mtab_monitor_file (void)
785 _g_get_unix_mounts (void)
788 GList
* return_list
= NULL
;
789 char filename
[9 + NAME_MAX
];
791 dirp
= opendir ("/dev/fs");
794 g_warning ("unable to read /dev/fs!");
800 struct statvfs statbuf
;
802 struct dirent
* result
;
804 if (readdir_r (dirp
, &entry
, &result
) || result
== NULL
)
807 strcpy (filename
, "/dev/fs/");
808 strcat (filename
, entry
.d_name
);
810 if (statvfs (filename
, &statbuf
) == 0)
812 GUnixMountEntry
* mount_entry
= g_new0(GUnixMountEntry
, 1);
814 mount_entry
->mount_path
= g_strdup (statbuf
.f_mntonname
);
815 mount_entry
->device_path
= g_strdup (statbuf
.f_mntfromname
);
816 mount_entry
->filesystem_type
= g_strdup (statbuf
.f_fstypename
);
818 if (statbuf
.f_flag
& ST_RDONLY
)
819 mount_entry
->is_read_only
= TRUE
;
821 return_list
= g_list_prepend(return_list
, mount_entry
);
825 return_list
= g_list_reverse (return_list
);
832 /* Common code {{{2 */
834 #error No _g_get_unix_mounts() implementation for system
837 /* GUnixMountPoints (ie: fstab) implementations {{{1 */
839 /* _g_get_unix_mount_points():
841 * don't return swap and ignore mounts.
845 get_fstab_file (void)
848 return (char *) mnt_get_fstab_path ();
850 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
852 return "/etc/filesystems";
853 #elif defined(_PATH_MNTTAB)
855 #elif defined(VFSTAB)
863 /* mntent.h (Linux, GNU, NSS) {{{2 */
869 _g_get_unix_mount_points (void)
871 struct libmnt_table
*table
= NULL
;
872 struct libmnt_context
*ctxt
= NULL
;
873 struct libmnt_iter
* iter
= NULL
;
874 struct libmnt_fs
*fs
= NULL
;
875 GUnixMountPoint
*mount_point
= NULL
;
876 GList
*return_list
= NULL
;
878 ctxt
= mnt_new_context ();
879 mnt_context_get_fstab (ctxt
, &table
);
883 iter
= mnt_new_iter (MNT_ITER_FORWARD
);
884 while (mnt_table_next_fs (table
, iter
, &fs
) == 0)
886 const char *device_path
= NULL
;
887 const char *mount_path
= NULL
;
888 const char *mount_fstype
= NULL
;
889 char *mount_options
= NULL
;
890 gboolean is_read_only
= FALSE
;
891 gboolean is_user_mountable
= FALSE
;
892 gboolean is_loopback
= FALSE
;
894 mount_path
= mnt_fs_get_target (fs
);
895 if ((strcmp (mount_path
, "ignore") == 0) ||
896 (strcmp (mount_path
, "swap") == 0) ||
897 (strcmp (mount_path
, "none") == 0))
900 mount_fstype
= mnt_fs_get_fstype (fs
);
901 mount_options
= mnt_fs_strdup_options (fs
);
904 unsigned long mount_flags
= 0;
905 unsigned long userspace_flags
= 0;
907 mnt_optstr_get_flags (mount_options
, &mount_flags
, mnt_get_builtin_optmap (MNT_LINUX_MAP
));
908 mnt_optstr_get_flags (mount_options
, &userspace_flags
, mnt_get_builtin_optmap (MNT_USERSPACE_MAP
));
910 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
911 if (mount_flags
& MS_BIND
)
913 g_free (mount_options
);
917 is_read_only
= (mount_flags
& MS_RDONLY
) != 0;
918 is_loopback
= (userspace_flags
& MNT_MS_LOOP
) != 0;
920 if ((mount_fstype
!= NULL
&& g_strcmp0 ("supermount", mount_fstype
) == 0) ||
921 ((userspace_flags
& MNT_MS_USER
) &&
922 (g_strstr_len (mount_options
, -1, "user_xattr") == NULL
)) ||
923 (g_strstr_len (mount_options
, -1, "pamconsole") == NULL
) ||
924 (userspace_flags
& MNT_MS_USERS
) ||
925 (userspace_flags
& MNT_MS_OWNER
))
927 is_user_mountable
= TRUE
;
931 device_path
= mnt_fs_get_source (fs
);
932 if (g_strcmp0 (device_path
, "/dev/root") == 0)
933 device_path
= _resolve_dev_root ();
935 mount_point
= create_unix_mount_point (device_path
,
943 g_free (mount_options
);
945 return_list
= g_list_prepend (return_list
, mount_point
);
947 mnt_free_iter (iter
);
950 mnt_free_context (ctxt
);
952 return g_list_reverse (return_list
);
958 _g_get_unix_mount_points (void)
960 #ifdef HAVE_GETMNTENT_R
964 struct mntent
*mntent
;
967 GUnixMountPoint
*mount_point
;
970 read_file
= get_fstab_file ();
972 file
= setmntent (read_file
, "r");
978 #ifdef HAVE_GETMNTENT_R
979 while ((mntent
= getmntent_r (file
, &ent
, buf
, sizeof (buf
))) != NULL
)
982 while ((mntent
= getmntent (file
)) != NULL
)
985 const char *device_path
= NULL
;
986 gboolean is_read_only
= FALSE
;
987 gboolean is_user_mountable
= FALSE
;
988 gboolean is_loopback
= FALSE
;
990 if ((strcmp (mntent
->mnt_dir
, "ignore") == 0) ||
991 (strcmp (mntent
->mnt_dir
, "swap") == 0) ||
992 (strcmp (mntent
->mnt_dir
, "none") == 0))
995 #ifdef HAVE_HASMNTOPT
996 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
997 if (hasmntopt (mntent
, "bind"))
1001 if (strcmp (mntent
->mnt_fsname
, "/dev/root") == 0)
1002 device_path
= _resolve_dev_root ();
1004 device_path
= mntent
->mnt_fsname
;
1006 #ifdef HAVE_HASMNTOPT
1007 if (hasmntopt (mntent
, MNTOPT_RO
) != NULL
)
1008 is_read_only
= TRUE
;
1010 if (hasmntopt (mntent
, "loop") != NULL
)
1015 if ((mntent
->mnt_type
!= NULL
&& strcmp ("supermount", mntent
->mnt_type
) == 0)
1016 #ifdef HAVE_HASMNTOPT
1017 || (hasmntopt (mntent
, "user") != NULL
1018 && hasmntopt (mntent
, "user") != hasmntopt (mntent
, "user_xattr"))
1019 || hasmntopt (mntent
, "pamconsole") != NULL
1020 || hasmntopt (mntent
, "users") != NULL
1021 || hasmntopt (mntent
, "owner") != NULL
1024 is_user_mountable
= TRUE
;
1026 mount_point
= create_unix_mount_point (device_path
,
1034 return_list
= g_list_prepend (return_list
, mount_point
);
1039 #ifndef HAVE_GETMNTENT_R
1040 G_UNLOCK (getmntent
);
1043 return g_list_reverse (return_list
);
1046 #endif /* HAVE_LIBMOUNT */
1049 #elif defined (HAVE_SYS_MNTTAB_H)
1052 _g_get_unix_mount_points (void)
1054 struct mnttab mntent
;
1057 GUnixMountPoint
*mount_point
;
1060 read_file
= get_fstab_file ();
1062 file
= setmntent (read_file
, "r");
1069 while (! getmntent (file
, &mntent
))
1071 gboolean is_read_only
= FALSE
;
1072 gboolean is_user_mountable
= FALSE
;
1073 gboolean is_loopback
= FALSE
;
1075 if ((strcmp (mntent
.mnt_mountp
, "ignore") == 0) ||
1076 (strcmp (mntent
.mnt_mountp
, "swap") == 0) ||
1077 (strcmp (mntent
.mnt_mountp
, "none") == 0))
1080 #ifdef HAVE_HASMNTOPT
1081 if (hasmntopt (&mntent
, MNTOPT_RO
) != NULL
)
1082 is_read_only
= TRUE
;
1084 if (hasmntopt (&mntent
, "lofs") != NULL
)
1088 if ((mntent
.mnt_fstype
!= NULL
)
1089 #ifdef HAVE_HASMNTOPT
1090 || (hasmntopt (&mntent
, "user") != NULL
1091 && hasmntopt (&mntent
, "user") != hasmntopt (&mntent
, "user_xattr"))
1092 || hasmntopt (&mntent
, "pamconsole") != NULL
1093 || hasmntopt (&mntent
, "users") != NULL
1094 || hasmntopt (&mntent
, "owner") != NULL
1097 is_user_mountable
= TRUE
;
1099 mount_point
= create_unix_mount_point (mntent
.mnt_special
,
1107 return_list
= g_list_prepend (return_list
, mount_point
);
1111 G_UNLOCK (getmntent
);
1113 return g_list_reverse (return_list
);
1116 /* mntctl.h (AIX) {{{2 */
1117 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
1119 /* functions to parse /etc/filesystems on aix */
1121 /* read character, ignoring comments (begin with '*', end with '\n' */
1123 aix_fs_getc (FILE *fd
)
1127 while ((c
= getc (fd
)) == '*')
1129 while (((c
= getc (fd
)) != '\n') && (c
!= EOF
))
1134 /* eat all continuous spaces in a file */
1136 aix_fs_ignorespace (FILE *fd
)
1140 while ((c
= aix_fs_getc (fd
)) != EOF
)
1142 if (!g_ascii_isspace (c
))
1152 /* read one word from file */
1154 aix_fs_getword (FILE *fd
,
1159 aix_fs_ignorespace (fd
);
1161 while (((c
= aix_fs_getc (fd
)) != EOF
) && !g_ascii_isspace (c
))
1165 while (((c
= aix_fs_getc (fd
)) != EOF
) && (c
!= '"'))
1177 char mnt_mount
[PATH_MAX
];
1178 char mnt_special
[PATH_MAX
];
1179 char mnt_fstype
[16];
1180 char mnt_options
[128];
1181 } AixMountTableEntry
;
1183 /* read mount points properties */
1185 aix_fs_get (FILE *fd
,
1186 AixMountTableEntry
*prop
)
1188 static char word
[PATH_MAX
] = { 0 };
1189 char value
[PATH_MAX
];
1194 if (aix_fs_getword (fd
, word
) == EOF
)
1198 word
[strlen(word
) - 1] = 0;
1199 strcpy (prop
->mnt_mount
, word
);
1201 /* read attributes and value */
1203 while (aix_fs_getword (fd
, word
) != EOF
)
1205 /* test if is attribute or new stanza */
1206 if (word
[strlen(word
) - 1] == ':')
1210 aix_fs_getword (fd
, value
);
1213 aix_fs_getword (fd
, value
);
1215 if (strcmp (word
, "dev") == 0)
1216 strcpy (prop
->mnt_special
, value
);
1217 else if (strcmp (word
, "vfs") == 0)
1218 strcpy (prop
->mnt_fstype
, value
);
1219 else if (strcmp (word
, "options") == 0)
1220 strcpy(prop
->mnt_options
, value
);
1227 _g_get_unix_mount_points (void)
1229 struct mntent
*mntent
;
1232 GUnixMountPoint
*mount_point
;
1233 AixMountTableEntry mntent
;
1236 read_file
= get_fstab_file ();
1238 file
= setmntent (read_file
, "r");
1244 while (!aix_fs_get (file
, &mntent
))
1246 if (strcmp ("cdrfs", mntent
.mnt_fstype
) == 0)
1248 mount_point
= create_unix_mount_point (mntent
.mnt_special
,
1256 return_list
= g_list_prepend (return_list
, mount_point
);
1262 return g_list_reverse (return_list
);
1265 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
1268 _g_get_unix_mount_points (void)
1270 struct fstab
*fstab
= NULL
;
1271 GUnixMountPoint
*mount_point
;
1273 #ifdef HAVE_SYS_SYSCTL_H
1275 size_t len
= sizeof(usermnt
);
1284 #ifdef HAVE_SYS_SYSCTL_H
1285 #if defined(HAVE_SYSCTLBYNAME)
1286 sysctlbyname ("vfs.usermount", &usermnt
, &len
, NULL
, 0);
1287 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
1292 mib
[1] = VFS_USERMOUNT
;
1293 sysctl (mib
, 2, &usermnt
, &len
, NULL
, 0);
1295 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
1300 mib
[1] = KERN_USERMOUNT
;
1301 sysctl (mib
, 2, &usermnt
, &len
, NULL
, 0);
1306 while ((fstab
= getfsent ()) != NULL
)
1308 gboolean is_read_only
= FALSE
;
1309 gboolean is_user_mountable
= FALSE
;
1311 if (strcmp (fstab
->fs_vfstype
, "swap") == 0)
1314 if (strcmp (fstab
->fs_type
, "ro") == 0)
1315 is_read_only
= TRUE
;
1317 #ifdef HAVE_SYS_SYSCTL_H
1320 uid_t uid
= getuid ();
1321 if (stat (fstab
->fs_file
, &sb
) == 0)
1323 if (uid
== 0 || sb
.st_uid
== uid
)
1324 is_user_mountable
= TRUE
;
1329 mount_point
= create_unix_mount_point (fstab
->fs_spec
,
1337 return_list
= g_list_prepend (return_list
, mount_point
);
1342 return g_list_reverse (return_list
);
1345 #elif defined(__INTERIX)
1347 _g_get_unix_mount_points (void)
1349 return _g_get_unix_mounts ();
1352 /* Common code {{{2 */
1354 #error No g_get_mount_table() implementation for system
1358 get_mounts_timestamp (void)
1360 const char *monitor_file
;
1363 monitor_file
= get_mtab_monitor_file ();
1366 if (stat (monitor_file
, &buf
) == 0)
1367 return (guint64
)buf
.st_mtime
;
1371 return mount_poller_time
;
1377 get_mount_points_timestamp (void)
1379 const char *monitor_file
;
1382 monitor_file
= get_fstab_file ();
1385 if (stat (monitor_file
, &buf
) == 0)
1386 return (guint64
)buf
.st_mtime
;
1392 * g_unix_mounts_get: (skip)
1393 * @time_read: (out) (optional): guint64 to contain a timestamp, or %NULL
1395 * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1396 * If @time_read is set, it will be filled with the mount
1397 * timestamp, allowing for checking if the mounts have changed
1398 * with g_unix_mounts_changed_since().
1400 * Returns: (element-type GUnixMountEntry) (transfer full):
1401 * a #GList of the UNIX mounts.
1404 g_unix_mounts_get (guint64
*time_read
)
1407 *time_read
= get_mounts_timestamp ();
1409 return _g_get_unix_mounts ();
1413 * g_unix_mount_at: (skip)
1414 * @mount_path: path for a possible unix mount.
1415 * @time_read: (out) (optional): guint64 to contain a timestamp.
1417 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1418 * is set, it will be filled with a unix timestamp for checking
1419 * if the mounts have changed since with g_unix_mounts_changed_since().
1421 * Returns: (transfer full): a #GUnixMountEntry.
1424 g_unix_mount_at (const char *mount_path
,
1428 GUnixMountEntry
*mount_entry
, *found
;
1430 mounts
= g_unix_mounts_get (time_read
);
1433 for (l
= mounts
; l
!= NULL
; l
= l
->next
)
1435 mount_entry
= l
->data
;
1437 if (!found
&& strcmp (mount_path
, mount_entry
->mount_path
) == 0)
1438 found
= mount_entry
;
1440 g_unix_mount_free (mount_entry
);
1442 g_list_free (mounts
);
1448 * g_unix_mount_for: (skip)
1449 * @file_path: file path on some unix mount.
1450 * @time_read: (out) (optional): guint64 to contain a timestamp.
1452 * Gets a #GUnixMountEntry for a given file path. If @time_read
1453 * is set, it will be filled with a unix timestamp for checking
1454 * if the mounts have changed since with g_unix_mounts_changed_since().
1456 * Returns: (transfer full): a #GUnixMountEntry.
1461 g_unix_mount_for (const char *file_path
,
1464 GUnixMountEntry
*entry
;
1466 g_return_val_if_fail (file_path
!= NULL
, NULL
);
1468 entry
= g_unix_mount_at (file_path
, time_read
);
1473 topdir
= _g_local_file_find_topdir_for (file_path
);
1476 entry
= g_unix_mount_at (topdir
, time_read
);
1485 * g_unix_mount_points_get: (skip)
1486 * @time_read: (out) (optional): guint64 to contain a timestamp.
1488 * Gets a #GList of #GUnixMountPoint containing the unix mount points.
1489 * If @time_read is set, it will be filled with the mount timestamp,
1490 * allowing for checking if the mounts have changed with
1491 * g_unix_mount_points_changed_since().
1493 * Returns: (element-type GUnixMountPoint) (transfer full):
1494 * a #GList of the UNIX mountpoints.
1497 g_unix_mount_points_get (guint64
*time_read
)
1500 *time_read
= get_mount_points_timestamp ();
1502 return _g_get_unix_mount_points ();
1506 * g_unix_mounts_changed_since:
1507 * @time: guint64 to contain a timestamp.
1509 * Checks if the unix mounts have changed since a given unix time.
1511 * Returns: %TRUE if the mounts have changed since @time.
1514 g_unix_mounts_changed_since (guint64 time
)
1516 return get_mounts_timestamp () != time
;
1520 * g_unix_mount_points_changed_since:
1521 * @time: guint64 to contain a timestamp.
1523 * Checks if the unix mount points have changed since a given unix time.
1525 * Returns: %TRUE if the mount points have changed since @time.
1528 g_unix_mount_points_changed_since (guint64 time
)
1530 return get_mount_points_timestamp () != time
;
1533 /* GUnixMountMonitor {{{1 */
1537 MOUNTPOINTS_CHANGED
,
1541 static guint signals
[LAST_SIGNAL
];
1543 struct _GUnixMountMonitor
{
1546 GMainContext
*context
;
1549 struct _GUnixMountMonitorClass
{
1550 GObjectClass parent_class
;
1554 G_DEFINE_TYPE (GUnixMountMonitor
, g_unix_mount_monitor
, G_TYPE_OBJECT
);
1556 static GContextSpecificGroup mount_monitor_group
;
1557 static GFileMonitor
*fstab_monitor
;
1558 static GFileMonitor
*mtab_monitor
;
1559 static GSource
*proc_mounts_watch_source
;
1560 static GList
*mount_poller_mounts
;
1563 fstab_file_changed (GFileMonitor
*monitor
,
1566 GFileMonitorEvent event_type
,
1569 if (event_type
!= G_FILE_MONITOR_EVENT_CHANGED
&&
1570 event_type
!= G_FILE_MONITOR_EVENT_CREATED
&&
1571 event_type
!= G_FILE_MONITOR_EVENT_DELETED
)
1574 g_context_specific_group_emit (&mount_monitor_group
, signals
[MOUNTPOINTS_CHANGED
]);
1578 mtab_file_changed (GFileMonitor
*monitor
,
1581 GFileMonitorEvent event_type
,
1584 if (event_type
!= G_FILE_MONITOR_EVENT_CHANGED
&&
1585 event_type
!= G_FILE_MONITOR_EVENT_CREATED
&&
1586 event_type
!= G_FILE_MONITOR_EVENT_DELETED
)
1589 g_context_specific_group_emit (&mount_monitor_group
, signals
[MOUNTS_CHANGED
]);
1593 proc_mounts_changed (GIOChannel
*channel
,
1597 if (cond
& G_IO_ERR
)
1598 g_context_specific_group_emit (&mount_monitor_group
, signals
[MOUNTS_CHANGED
]);
1604 mount_change_poller (gpointer user_data
)
1606 GList
*current_mounts
, *new_it
, *old_it
;
1607 gboolean has_changed
= FALSE
;
1609 current_mounts
= _g_get_unix_mounts ();
1611 for ( new_it
= current_mounts
, old_it
= mount_poller_mounts
;
1612 new_it
!= NULL
&& old_it
!= NULL
;
1613 new_it
= g_list_next (new_it
), old_it
= g_list_next (old_it
) )
1615 if (g_unix_mount_compare (new_it
->data
, old_it
->data
) != 0)
1621 if (!(new_it
== NULL
&& old_it
== NULL
))
1624 g_list_free_full (mount_poller_mounts
, (GDestroyNotify
) g_unix_mount_free
);
1626 mount_poller_mounts
= current_mounts
;
1630 mount_poller_time
= (guint64
) g_get_monotonic_time ();
1631 g_context_specific_group_emit (&mount_monitor_group
, signals
[MOUNTPOINTS_CHANGED
]);
1639 mount_monitor_stop (void)
1643 g_file_monitor_cancel (fstab_monitor
);
1644 g_object_unref (fstab_monitor
);
1647 if (proc_mounts_watch_source
!= NULL
)
1648 g_source_destroy (proc_mounts_watch_source
);
1652 g_file_monitor_cancel (mtab_monitor
);
1653 g_object_unref (mtab_monitor
);
1656 g_list_free_full (mount_poller_mounts
, (GDestroyNotify
) g_unix_mount_free
);
1660 mount_monitor_start (void)
1664 if (get_fstab_file () != NULL
)
1666 file
= g_file_new_for_path (get_fstab_file ());
1667 fstab_monitor
= g_file_monitor_file (file
, 0, NULL
, NULL
);
1668 g_object_unref (file
);
1670 g_signal_connect (fstab_monitor
, "changed", (GCallback
)fstab_file_changed
, NULL
);
1673 if (get_mtab_monitor_file () != NULL
)
1675 const gchar
*mtab_path
;
1677 mtab_path
= get_mtab_monitor_file ();
1678 /* Monitoring files in /proc/ is special - can't just use GFileMonitor.
1679 * See 'man proc' for more details.
1681 if (g_str_has_prefix (mtab_path
, "/proc/"))
1683 GIOChannel
*proc_mounts_channel
;
1684 GError
*error
= NULL
;
1685 proc_mounts_channel
= g_io_channel_new_file (mtab_path
, "r", &error
);
1686 if (proc_mounts_channel
== NULL
)
1688 g_warning ("Error creating IO channel for %s: %s (%s, %d)", mtab_path
,
1689 error
->message
, g_quark_to_string (error
->domain
), error
->code
);
1690 g_error_free (error
);
1694 proc_mounts_watch_source
= g_io_create_watch (proc_mounts_channel
, G_IO_ERR
);
1695 g_source_set_callback (proc_mounts_watch_source
,
1696 (GSourceFunc
) proc_mounts_changed
,
1698 g_source_attach (proc_mounts_watch_source
,
1699 g_main_context_get_thread_default ());
1700 g_source_unref (proc_mounts_watch_source
);
1701 g_io_channel_unref (proc_mounts_channel
);
1706 file
= g_file_new_for_path (mtab_path
);
1707 mtab_monitor
= g_file_monitor_file (file
, 0, NULL
, NULL
);
1708 g_object_unref (file
);
1709 g_signal_connect (mtab_monitor
, "changed", (GCallback
)mtab_file_changed
, NULL
);
1714 proc_mounts_watch_source
= g_timeout_source_new_seconds (3);
1715 mount_poller_mounts
= _g_get_unix_mounts ();
1716 mount_poller_time
= (guint64
)g_get_monotonic_time ();
1717 g_source_set_callback (proc_mounts_watch_source
,
1718 mount_change_poller
,
1720 g_source_attach (proc_mounts_watch_source
,
1721 g_main_context_get_thread_default ());
1722 g_source_unref (proc_mounts_watch_source
);
1727 g_unix_mount_monitor_finalize (GObject
*object
)
1729 GUnixMountMonitor
*monitor
;
1731 monitor
= G_UNIX_MOUNT_MONITOR (object
);
1733 g_context_specific_group_remove (&mount_monitor_group
, monitor
->context
, monitor
, mount_monitor_stop
);
1735 G_OBJECT_CLASS (g_unix_mount_monitor_parent_class
)->finalize (object
);
1739 g_unix_mount_monitor_class_init (GUnixMountMonitorClass
*klass
)
1741 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
1743 gobject_class
->finalize
= g_unix_mount_monitor_finalize
;
1746 * GUnixMountMonitor::mounts-changed:
1747 * @monitor: the object on which the signal is emitted
1749 * Emitted when the unix mounts have changed.
1751 signals
[MOUNTS_CHANGED
] =
1752 g_signal_new (I_("mounts-changed"),
1753 G_TYPE_FROM_CLASS (klass
),
1757 g_cclosure_marshal_VOID__VOID
,
1761 * GUnixMountMonitor::mountpoints-changed:
1762 * @monitor: the object on which the signal is emitted
1764 * Emitted when the unix mount points have changed.
1766 signals
[MOUNTPOINTS_CHANGED
] =
1767 g_signal_new (I_("mountpoints-changed"),
1768 G_TYPE_FROM_CLASS (klass
),
1772 g_cclosure_marshal_VOID__VOID
,
1777 g_unix_mount_monitor_init (GUnixMountMonitor
*monitor
)
1782 * g_unix_mount_monitor_set_rate_limit:
1783 * @mount_monitor: a #GUnixMountMonitor
1784 * @limit_msec: a integer with the limit in milliseconds to
1787 * This function does nothing.
1789 * Before 2.44, this was a partially-effective way of controlling the
1790 * rate at which events would be reported under some uncommon
1791 * circumstances. Since @mount_monitor is a singleton, it also meant
1792 * that calling this function would have side effects for other users of
1797 * Deprecated:2.44:This function does nothing. Don't call it.
1800 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor
*mount_monitor
,
1806 * g_unix_mount_monitor_get:
1808 * Gets the #GUnixMountMonitor for the current thread-default main
1811 * The mount monitor can be used to monitor for changes to the list of
1812 * mounted filesystems as well as the list of mount points (ie: fstab
1815 * You must only call g_object_unref() on the return value from under
1816 * the same main context as you called this function.
1818 * Returns: (transfer full): the #GUnixMountMonitor.
1823 g_unix_mount_monitor_get (void)
1825 return g_context_specific_group_get (&mount_monitor_group
,
1826 G_TYPE_UNIX_MOUNT_MONITOR
,
1827 G_STRUCT_OFFSET(GUnixMountMonitor
, context
),
1828 mount_monitor_start
);
1832 * g_unix_mount_monitor_new:
1834 * Deprecated alias for g_unix_mount_monitor_get().
1836 * This function was never a true constructor, which is why it was
1839 * Returns: a #GUnixMountMonitor.
1841 * Deprecated:2.44:Use g_unix_mount_monitor_get() instead.
1844 g_unix_mount_monitor_new (void)
1846 return g_unix_mount_monitor_get ();
1849 /* GUnixMount {{{1 */
1851 * g_unix_mount_free:
1852 * @mount_entry: a #GUnixMountEntry.
1854 * Frees a unix mount.
1857 g_unix_mount_free (GUnixMountEntry
*mount_entry
)
1859 g_return_if_fail (mount_entry
!= NULL
);
1861 g_free (mount_entry
->mount_path
);
1862 g_free (mount_entry
->device_path
);
1863 g_free (mount_entry
->filesystem_type
);
1864 g_free (mount_entry
);
1868 * g_unix_mount_point_free:
1869 * @mount_point: unix mount point to free.
1871 * Frees a unix mount point.
1874 g_unix_mount_point_free (GUnixMountPoint
*mount_point
)
1876 g_return_if_fail (mount_point
!= NULL
);
1878 g_free (mount_point
->mount_path
);
1879 g_free (mount_point
->device_path
);
1880 g_free (mount_point
->filesystem_type
);
1881 g_free (mount_point
->options
);
1882 g_free (mount_point
);
1886 * g_unix_mount_compare:
1887 * @mount1: first #GUnixMountEntry to compare.
1888 * @mount2: second #GUnixMountEntry to compare.
1890 * Compares two unix mounts.
1892 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1893 * or less than @mount2, respectively.
1896 g_unix_mount_compare (GUnixMountEntry
*mount1
,
1897 GUnixMountEntry
*mount2
)
1901 g_return_val_if_fail (mount1
!= NULL
&& mount2
!= NULL
, 0);
1903 res
= g_strcmp0 (mount1
->mount_path
, mount2
->mount_path
);
1907 res
= g_strcmp0 (mount1
->device_path
, mount2
->device_path
);
1911 res
= g_strcmp0 (mount1
->filesystem_type
, mount2
->filesystem_type
);
1915 res
= mount1
->is_read_only
- mount2
->is_read_only
;
1923 * g_unix_mount_get_mount_path:
1924 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1926 * Gets the mount path for a unix mount.
1928 * Returns: (type filename): the mount path for @mount_entry.
1931 g_unix_mount_get_mount_path (GUnixMountEntry
*mount_entry
)
1933 g_return_val_if_fail (mount_entry
!= NULL
, NULL
);
1935 return mount_entry
->mount_path
;
1939 * g_unix_mount_get_device_path:
1940 * @mount_entry: a #GUnixMount.
1942 * Gets the device path for a unix mount.
1944 * Returns: (type filename): a string containing the device path.
1947 g_unix_mount_get_device_path (GUnixMountEntry
*mount_entry
)
1949 g_return_val_if_fail (mount_entry
!= NULL
, NULL
);
1951 return mount_entry
->device_path
;
1955 * g_unix_mount_get_fs_type:
1956 * @mount_entry: a #GUnixMount.
1958 * Gets the filesystem type for the unix mount.
1960 * Returns: a string containing the file system type.
1963 g_unix_mount_get_fs_type (GUnixMountEntry
*mount_entry
)
1965 g_return_val_if_fail (mount_entry
!= NULL
, NULL
);
1967 return mount_entry
->filesystem_type
;
1971 * g_unix_mount_is_readonly:
1972 * @mount_entry: a #GUnixMount.
1974 * Checks if a unix mount is mounted read only.
1976 * Returns: %TRUE if @mount_entry is read only.
1979 g_unix_mount_is_readonly (GUnixMountEntry
*mount_entry
)
1981 g_return_val_if_fail (mount_entry
!= NULL
, FALSE
);
1983 return mount_entry
->is_read_only
;
1987 * g_unix_mount_is_system_internal:
1988 * @mount_entry: a #GUnixMount.
1990 * Checks if a unix mount is a system path.
1992 * Returns: %TRUE if the unix mount is for a system path.
1995 g_unix_mount_is_system_internal (GUnixMountEntry
*mount_entry
)
1997 g_return_val_if_fail (mount_entry
!= NULL
, FALSE
);
1999 return mount_entry
->is_system_internal
;
2002 /* GUnixMountPoint {{{1 */
2004 * g_unix_mount_point_compare:
2005 * @mount1: a #GUnixMount.
2006 * @mount2: a #GUnixMount.
2008 * Compares two unix mount points.
2010 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
2011 * or less than @mount2, respectively.
2014 g_unix_mount_point_compare (GUnixMountPoint
*mount1
,
2015 GUnixMountPoint
*mount2
)
2019 g_return_val_if_fail (mount1
!= NULL
&& mount2
!= NULL
, 0);
2021 res
= g_strcmp0 (mount1
->mount_path
, mount2
->mount_path
);
2025 res
= g_strcmp0 (mount1
->device_path
, mount2
->device_path
);
2029 res
= g_strcmp0 (mount1
->filesystem_type
, mount2
->filesystem_type
);
2033 res
= g_strcmp0 (mount1
->options
, mount2
->options
);
2037 res
= mount1
->is_read_only
- mount2
->is_read_only
;
2041 res
= mount1
->is_user_mountable
- mount2
->is_user_mountable
;
2045 res
= mount1
->is_loopback
- mount2
->is_loopback
;
2053 * g_unix_mount_point_get_mount_path:
2054 * @mount_point: a #GUnixMountPoint.
2056 * Gets the mount path for a unix mount point.
2058 * Returns: (type filename): a string containing the mount path.
2061 g_unix_mount_point_get_mount_path (GUnixMountPoint
*mount_point
)
2063 g_return_val_if_fail (mount_point
!= NULL
, NULL
);
2065 return mount_point
->mount_path
;
2069 * g_unix_mount_point_get_device_path:
2070 * @mount_point: a #GUnixMountPoint.
2072 * Gets the device path for a unix mount point.
2074 * Returns: (type filename): a string containing the device path.
2077 g_unix_mount_point_get_device_path (GUnixMountPoint
*mount_point
)
2079 g_return_val_if_fail (mount_point
!= NULL
, NULL
);
2081 return mount_point
->device_path
;
2085 * g_unix_mount_point_get_fs_type:
2086 * @mount_point: a #GUnixMountPoint.
2088 * Gets the file system type for the mount point.
2090 * Returns: a string containing the file system type.
2093 g_unix_mount_point_get_fs_type (GUnixMountPoint
*mount_point
)
2095 g_return_val_if_fail (mount_point
!= NULL
, NULL
);
2097 return mount_point
->filesystem_type
;
2101 * g_unix_mount_point_get_options:
2102 * @mount_point: a #GUnixMountPoint.
2104 * Gets the options for the mount point.
2106 * Returns: a string containing the options.
2111 g_unix_mount_point_get_options (GUnixMountPoint
*mount_point
)
2113 g_return_val_if_fail (mount_point
!= NULL
, NULL
);
2115 return mount_point
->options
;
2119 * g_unix_mount_point_is_readonly:
2120 * @mount_point: a #GUnixMountPoint.
2122 * Checks if a unix mount point is read only.
2124 * Returns: %TRUE if a mount point is read only.
2127 g_unix_mount_point_is_readonly (GUnixMountPoint
*mount_point
)
2129 g_return_val_if_fail (mount_point
!= NULL
, FALSE
);
2131 return mount_point
->is_read_only
;
2135 * g_unix_mount_point_is_user_mountable:
2136 * @mount_point: a #GUnixMountPoint.
2138 * Checks if a unix mount point is mountable by the user.
2140 * Returns: %TRUE if the mount point is user mountable.
2143 g_unix_mount_point_is_user_mountable (GUnixMountPoint
*mount_point
)
2145 g_return_val_if_fail (mount_point
!= NULL
, FALSE
);
2147 return mount_point
->is_user_mountable
;
2151 * g_unix_mount_point_is_loopback:
2152 * @mount_point: a #GUnixMountPoint.
2154 * Checks if a unix mount point is a loopback device.
2156 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
2159 g_unix_mount_point_is_loopback (GUnixMountPoint
*mount_point
)
2161 g_return_val_if_fail (mount_point
!= NULL
, FALSE
);
2163 return mount_point
->is_loopback
;
2166 static GUnixMountType
2167 guess_mount_type (const char *mount_path
,
2168 const char *device_path
,
2169 const char *filesystem_type
)
2171 GUnixMountType type
;
2174 type
= G_UNIX_MOUNT_TYPE_UNKNOWN
;
2176 if ((strcmp (filesystem_type
, "udf") == 0) ||
2177 (strcmp (filesystem_type
, "iso9660") == 0) ||
2178 (strcmp (filesystem_type
, "cd9660") == 0))
2179 type
= G_UNIX_MOUNT_TYPE_CDROM
;
2180 else if ((strcmp (filesystem_type
, "nfs") == 0) ||
2181 (strcmp (filesystem_type
, "nfs4") == 0))
2182 type
= G_UNIX_MOUNT_TYPE_NFS
;
2183 else if (g_str_has_prefix (device_path
, "/vol/dev/diskette/") ||
2184 g_str_has_prefix (device_path
, "/dev/fd") ||
2185 g_str_has_prefix (device_path
, "/dev/floppy"))
2186 type
= G_UNIX_MOUNT_TYPE_FLOPPY
;
2187 else if (g_str_has_prefix (device_path
, "/dev/cdrom") ||
2188 g_str_has_prefix (device_path
, "/dev/acd") ||
2189 g_str_has_prefix (device_path
, "/dev/cd"))
2190 type
= G_UNIX_MOUNT_TYPE_CDROM
;
2191 else if (g_str_has_prefix (device_path
, "/vol/"))
2193 const char *name
= mount_path
+ strlen ("/");
2195 if (g_str_has_prefix (name
, "cdrom"))
2196 type
= G_UNIX_MOUNT_TYPE_CDROM
;
2197 else if (g_str_has_prefix (name
, "floppy") ||
2198 g_str_has_prefix (device_path
, "/vol/dev/diskette/"))
2199 type
= G_UNIX_MOUNT_TYPE_FLOPPY
;
2200 else if (g_str_has_prefix (name
, "rmdisk"))
2201 type
= G_UNIX_MOUNT_TYPE_ZIP
;
2202 else if (g_str_has_prefix (name
, "jaz"))
2203 type
= G_UNIX_MOUNT_TYPE_JAZ
;
2204 else if (g_str_has_prefix (name
, "memstick"))
2205 type
= G_UNIX_MOUNT_TYPE_MEMSTICK
;
2209 basename
= g_path_get_basename (mount_path
);
2211 if (g_str_has_prefix (basename
, "cdr") ||
2212 g_str_has_prefix (basename
, "cdwriter") ||
2213 g_str_has_prefix (basename
, "burn") ||
2214 g_str_has_prefix (basename
, "dvdr"))
2215 type
= G_UNIX_MOUNT_TYPE_CDROM
;
2216 else if (g_str_has_prefix (basename
, "floppy"))
2217 type
= G_UNIX_MOUNT_TYPE_FLOPPY
;
2218 else if (g_str_has_prefix (basename
, "zip"))
2219 type
= G_UNIX_MOUNT_TYPE_ZIP
;
2220 else if (g_str_has_prefix (basename
, "jaz"))
2221 type
= G_UNIX_MOUNT_TYPE_JAZ
;
2222 else if (g_str_has_prefix (basename
, "camera"))
2223 type
= G_UNIX_MOUNT_TYPE_CAMERA
;
2224 else if (g_str_has_prefix (basename
, "memstick") ||
2225 g_str_has_prefix (basename
, "memory_stick") ||
2226 g_str_has_prefix (basename
, "ram"))
2227 type
= G_UNIX_MOUNT_TYPE_MEMSTICK
;
2228 else if (g_str_has_prefix (basename
, "compact_flash"))
2229 type
= G_UNIX_MOUNT_TYPE_CF
;
2230 else if (g_str_has_prefix (basename
, "smart_media"))
2231 type
= G_UNIX_MOUNT_TYPE_SM
;
2232 else if (g_str_has_prefix (basename
, "sd_mmc"))
2233 type
= G_UNIX_MOUNT_TYPE_SDMMC
;
2234 else if (g_str_has_prefix (basename
, "ipod"))
2235 type
= G_UNIX_MOUNT_TYPE_IPOD
;
2240 if (type
== G_UNIX_MOUNT_TYPE_UNKNOWN
)
2241 type
= G_UNIX_MOUNT_TYPE_HD
;
2247 * g_unix_mount_guess_type:
2248 * @mount_entry: a #GUnixMount.
2250 * Guesses the type of a unix mount. If the mount type cannot be
2251 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
2253 * Returns: a #GUnixMountType.
2255 static GUnixMountType
2256 g_unix_mount_guess_type (GUnixMountEntry
*mount_entry
)
2258 g_return_val_if_fail (mount_entry
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2259 g_return_val_if_fail (mount_entry
->mount_path
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2260 g_return_val_if_fail (mount_entry
->device_path
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2261 g_return_val_if_fail (mount_entry
->filesystem_type
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2263 return guess_mount_type (mount_entry
->mount_path
,
2264 mount_entry
->device_path
,
2265 mount_entry
->filesystem_type
);
2269 * g_unix_mount_point_guess_type:
2270 * @mount_point: a #GUnixMountPoint.
2272 * Guesses the type of a unix mount point.
2273 * If the mount type cannot be determined,
2274 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
2276 * Returns: a #GUnixMountType.
2278 static GUnixMountType
2279 g_unix_mount_point_guess_type (GUnixMountPoint
*mount_point
)
2281 g_return_val_if_fail (mount_point
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2282 g_return_val_if_fail (mount_point
->mount_path
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2283 g_return_val_if_fail (mount_point
->device_path
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2284 g_return_val_if_fail (mount_point
->filesystem_type
!= NULL
, G_UNIX_MOUNT_TYPE_UNKNOWN
);
2286 return guess_mount_type (mount_point
->mount_path
,
2287 mount_point
->device_path
,
2288 mount_point
->filesystem_type
);
2292 type_to_icon (GUnixMountType type
, gboolean is_mount_point
, gboolean use_symbolic
)
2294 const char *icon_name
;
2298 case G_UNIX_MOUNT_TYPE_HD
:
2300 icon_name
= use_symbolic
? "drive-removable-media-symbolic" : "drive-removable-media";
2302 icon_name
= use_symbolic
? "drive-harddisk-symbolic" : "drive-harddisk";
2304 case G_UNIX_MOUNT_TYPE_FLOPPY
:
2305 case G_UNIX_MOUNT_TYPE_ZIP
:
2306 case G_UNIX_MOUNT_TYPE_JAZ
:
2308 icon_name
= use_symbolic
? "drive-removable-media-symbolic" : "drive-removable-media";
2310 icon_name
= use_symbolic
? "media-removable-symbolic" : "media-floppy";
2312 case G_UNIX_MOUNT_TYPE_CDROM
:
2314 icon_name
= use_symbolic
? "drive-optical-symbolic" : "drive-optical";
2316 icon_name
= use_symbolic
? "media-optical-symbolic" : "media-optical";
2318 case G_UNIX_MOUNT_TYPE_NFS
:
2319 icon_name
= use_symbolic
? "folder-remote-symbolic" : "folder-remote";
2321 case G_UNIX_MOUNT_TYPE_MEMSTICK
:
2323 icon_name
= use_symbolic
? "drive-removable-media-symbolic" : "drive-removable-media";
2325 icon_name
= use_symbolic
? "media-removable-symbolic" : "media-flash";
2327 case G_UNIX_MOUNT_TYPE_CAMERA
:
2329 icon_name
= use_symbolic
? "drive-removable-media-symbolic" : "drive-removable-media";
2331 icon_name
= use_symbolic
? "camera-photo-symbolic" : "camera-photo";
2333 case G_UNIX_MOUNT_TYPE_IPOD
:
2335 icon_name
= use_symbolic
? "drive-removable-media-symbolic" : "drive-removable-media";
2337 icon_name
= use_symbolic
? "multimedia-player-symbolic" : "multimedia-player";
2339 case G_UNIX_MOUNT_TYPE_UNKNOWN
:
2342 icon_name
= use_symbolic
? "drive-removable-media-symbolic" : "drive-removable-media";
2344 icon_name
= use_symbolic
? "drive-harddisk-symbolic" : "drive-harddisk";
2352 * g_unix_mount_guess_name:
2353 * @mount_entry: a #GUnixMountEntry
2355 * Guesses the name of a Unix mount.
2356 * The result is a translated string.
2358 * Returns: A newly allocated string that must
2359 * be freed with g_free()
2362 g_unix_mount_guess_name (GUnixMountEntry
*mount_entry
)
2366 if (strcmp (mount_entry
->mount_path
, "/") == 0)
2367 name
= g_strdup (_("Filesystem root"));
2369 name
= g_filename_display_basename (mount_entry
->mount_path
);
2375 * g_unix_mount_guess_icon:
2376 * @mount_entry: a #GUnixMountEntry
2378 * Guesses the icon of a Unix mount.
2380 * Returns: (transfer full): a #GIcon
2383 g_unix_mount_guess_icon (GUnixMountEntry
*mount_entry
)
2385 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry
), FALSE
, FALSE
));
2389 * g_unix_mount_guess_symbolic_icon:
2390 * @mount_entry: a #GUnixMountEntry
2392 * Guesses the symbolic icon of a Unix mount.
2394 * Returns: (transfer full): a #GIcon
2399 g_unix_mount_guess_symbolic_icon (GUnixMountEntry
*mount_entry
)
2401 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry
), FALSE
, TRUE
));
2405 * g_unix_mount_point_guess_name:
2406 * @mount_point: a #GUnixMountPoint
2408 * Guesses the name of a Unix mount point.
2409 * The result is a translated string.
2411 * Returns: A newly allocated string that must
2412 * be freed with g_free()
2415 g_unix_mount_point_guess_name (GUnixMountPoint
*mount_point
)
2419 if (strcmp (mount_point
->mount_path
, "/") == 0)
2420 name
= g_strdup (_("Filesystem root"));
2422 name
= g_filename_display_basename (mount_point
->mount_path
);
2428 * g_unix_mount_point_guess_icon:
2429 * @mount_point: a #GUnixMountPoint
2431 * Guesses the icon of a Unix mount point.
2433 * Returns: (transfer full): a #GIcon
2436 g_unix_mount_point_guess_icon (GUnixMountPoint
*mount_point
)
2438 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point
), TRUE
, FALSE
));
2442 * g_unix_mount_point_guess_symbolic_icon:
2443 * @mount_point: a #GUnixMountPoint
2445 * Guesses the symbolic icon of a Unix mount point.
2447 * Returns: (transfer full): a #GIcon
2452 g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint
*mount_point
)
2454 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point
), TRUE
, TRUE
));
2458 * g_unix_mount_guess_can_eject:
2459 * @mount_entry: a #GUnixMountEntry
2461 * Guesses whether a Unix mount can be ejected.
2463 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
2466 g_unix_mount_guess_can_eject (GUnixMountEntry
*mount_entry
)
2468 GUnixMountType guessed_type
;
2470 guessed_type
= g_unix_mount_guess_type (mount_entry
);
2471 if (guessed_type
== G_UNIX_MOUNT_TYPE_IPOD
||
2472 guessed_type
== G_UNIX_MOUNT_TYPE_CDROM
)
2479 * g_unix_mount_guess_should_display:
2480 * @mount_entry: a #GUnixMountEntry
2482 * Guesses whether a Unix mount should be displayed in the UI.
2484 * Returns: %TRUE if @mount_entry is deemed to be displayable.
2487 g_unix_mount_guess_should_display (GUnixMountEntry
*mount_entry
)
2489 const char *mount_path
;
2490 const gchar
*user_name
;
2491 gsize user_name_len
;
2493 /* Never display internal mountpoints */
2494 if (g_unix_mount_is_system_internal (mount_entry
))
2497 /* Only display things in /media (which are generally user mountable)
2498 and home dir (fuse stuff) and /run/media/$USER */
2499 mount_path
= mount_entry
->mount_path
;
2500 if (mount_path
!= NULL
)
2502 gboolean is_in_runtime_dir
= FALSE
;
2503 /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
2504 if (g_strstr_len (mount_path
, -1, "/.") != NULL
)
2507 /* Check /run/media/$USER/ */
2508 user_name
= g_get_user_name ();
2509 user_name_len
= strlen (user_name
);
2510 if (strncmp (mount_path
, "/run/media/", sizeof ("/run/media/") - 1) == 0 &&
2511 strncmp (mount_path
+ sizeof ("/run/media/") - 1, user_name
, user_name_len
) == 0 &&
2512 mount_path
[sizeof ("/run/media/") - 1 + user_name_len
] == '/')
2513 is_in_runtime_dir
= TRUE
;
2515 if (is_in_runtime_dir
|| g_str_has_prefix (mount_path
, "/media/"))
2518 /* Avoid displaying mounts that are not accessible to the user.
2520 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
2521 * want to avoid g_access() for mount points which can potentially
2522 * block or fail stat()'ing, such as network mounts.
2524 path
= g_path_get_dirname (mount_path
);
2525 if (g_str_has_prefix (path
, "/media/"))
2527 if (g_access (path
, R_OK
|X_OK
) != 0)
2535 if (mount_entry
->device_path
&& mount_entry
->device_path
[0] == '/')
2538 if (g_stat (mount_entry
->device_path
, &st
) == 0 &&
2539 S_ISBLK(st
.st_mode
) &&
2540 g_access (mount_path
, R_OK
|X_OK
) != 0)
2546 if (g_str_has_prefix (mount_path
, g_get_home_dir ()) &&
2547 mount_path
[strlen (g_get_home_dir())] == G_DIR_SEPARATOR
)
2555 * g_unix_mount_point_guess_can_eject:
2556 * @mount_point: a #GUnixMountPoint
2558 * Guesses whether a Unix mount point can be ejected.
2560 * Returns: %TRUE if @mount_point is deemed to be ejectable.
2563 g_unix_mount_point_guess_can_eject (GUnixMountPoint
*mount_point
)
2565 GUnixMountType guessed_type
;
2567 guessed_type
= g_unix_mount_point_guess_type (mount_point
);
2568 if (guessed_type
== G_UNIX_MOUNT_TYPE_IPOD
||
2569 guessed_type
== G_UNIX_MOUNT_TYPE_CDROM
)
2575 /* Utility functions {{{1 */
2577 #ifdef HAVE_MNTENT_H
2578 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
2580 _canonicalize_filename (gchar
*filename
)
2583 gboolean last_was_slash
= FALSE
;
2590 if (*p
== G_DIR_SEPARATOR
)
2592 if (!last_was_slash
)
2593 *q
++ = G_DIR_SEPARATOR
;
2595 last_was_slash
= TRUE
;
2599 if (last_was_slash
&& *p
== '.')
2601 if (*(p
+ 1) == G_DIR_SEPARATOR
||
2604 if (*(p
+ 1) == '\0')
2609 else if (*(p
+ 1) == '.' &&
2610 (*(p
+ 2) == G_DIR_SEPARATOR
||
2613 if (q
> filename
+ 1)
2616 while (q
> filename
+ 1 &&
2617 *(q
- 1) != G_DIR_SEPARATOR
)
2621 if (*(p
+ 2) == '\0')
2629 last_was_slash
= FALSE
;
2635 last_was_slash
= FALSE
;
2642 if (q
> filename
+ 1 && *(q
- 1) == G_DIR_SEPARATOR
)
2649 _resolve_symlink (const char *file
)
2657 f
= g_strdup (file
);
2659 while (g_file_test (f
, G_FILE_TEST_IS_SYMLINK
))
2661 link
= g_file_read_link (f
, &error
);
2664 g_error_free (error
);
2670 dir
= g_path_get_dirname (f
);
2671 f1
= g_strdup_printf ("%s/%s", dir
, link
);
2680 _canonicalize_filename (f
);
2685 _resolve_dev_root (void)
2687 static gboolean have_real_dev_root
= FALSE
;
2688 static char real_dev_root
[256];
2689 struct stat statbuf
;
2691 /* see if it's cached already */
2692 if (have_real_dev_root
)
2695 /* otherwise we're going to find it right away.. */
2696 have_real_dev_root
= TRUE
;
2698 if (stat ("/dev/root", &statbuf
) == 0)
2700 if (! S_ISLNK (statbuf
.st_mode
))
2702 dev_t root_dev
= statbuf
.st_dev
;
2705 /* see if device with similar major:minor as /dev/root is mention
2706 * in /etc/mtab (it usually is)
2708 f
= fopen ("/etc/mtab", "r");
2711 struct mntent
*entp
;
2712 #ifdef HAVE_GETMNTENT_R
2715 while ((entp
= getmntent_r (f
, &ent
, buf
, sizeof (buf
))) != NULL
)
2719 while ((entp
= getmntent (f
)) != NULL
)
2722 if (stat (entp
->mnt_fsname
, &statbuf
) == 0 &&
2723 statbuf
.st_dev
== root_dev
)
2725 strncpy (real_dev_root
, entp
->mnt_fsname
, sizeof (real_dev_root
) - 1);
2726 real_dev_root
[sizeof (real_dev_root
) - 1] = '\0';
2734 #ifndef HAVE_GETMNTENT_R
2735 G_UNLOCK (getmntent
);
2739 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2745 resolved
= _resolve_symlink ("/dev/root");
2746 if (resolved
!= NULL
)
2748 strncpy (real_dev_root
, resolved
, sizeof (real_dev_root
) - 1);
2749 real_dev_root
[sizeof (real_dev_root
) - 1] = '\0';
2757 strcpy (real_dev_root
, "/dev/root");
2760 return real_dev_root
;
2765 /* vim:set foldmethod=marker: */