Update Friulian translation
[glib.git] / gio / gunixmounts.c
blobce6a2fcb74ba48dd44f7ae24e91212427dbad704
1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
4 *
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.1 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>
23 /* Prologue {{{1 */
25 #include "config.h"
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #ifndef HAVE_SYSCTLBYNAME
31 #ifdef HAVE_SYS_PARAM_H
32 #include <sys/param.h>
33 #endif
34 #endif
35 #ifdef HAVE_POLL
36 #include <poll.h>
37 #endif
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <sys/time.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <signal.h>
44 #include <gstdio.h>
45 #include <dirent.h>
47 #if HAVE_SYS_STATFS_H
48 #include <sys/statfs.h>
49 #endif
50 #if HAVE_SYS_STATVFS_H
51 #include <sys/statvfs.h>
52 #endif
53 #if HAVE_SYS_VFS_H
54 #include <sys/vfs.h>
55 #elif HAVE_SYS_MOUNT_H
56 #if HAVE_SYS_PARAM_H
57 #include <sys/param.h>
58 #endif
59 #include <sys/mount.h>
60 #endif
62 #ifndef O_BINARY
63 #define O_BINARY 0
64 #endif
66 #include "gunixmounts.h"
67 #include "glocalfileprivate.h"
68 #include "gfile.h"
69 #include "gfilemonitor.h"
70 #include "glibintl.h"
71 #include "gthemedicon.h"
72 #include "gcontextspecificgroup.h"
75 #ifdef HAVE_MNTENT_H
76 static const char *_resolve_dev_root (void);
77 #endif
79 /**
80 * SECTION:gunixmounts
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
88 * file when using it.
91 /**
92 * GUnixMountType:
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.
109 typedef enum {
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,
122 G_UNIX_MOUNT_TYPE_HD
123 } GUnixMountType;
125 struct _GUnixMountEntry {
126 char *mount_path;
127 char *device_path;
128 char *filesystem_type;
129 gboolean is_read_only;
130 gboolean is_system_internal;
133 G_DEFINE_BOXED_TYPE (GUnixMountEntry, g_unix_mount_entry,
134 g_unix_mount_copy, g_unix_mount_free)
136 struct _GUnixMountPoint {
137 char *mount_path;
138 char *device_path;
139 char *filesystem_type;
140 char *options;
141 gboolean is_read_only;
142 gboolean is_user_mountable;
143 gboolean is_loopback;
146 G_DEFINE_BOXED_TYPE (GUnixMountPoint, g_unix_mount_point,
147 g_unix_mount_point_copy, g_unix_mount_point_free)
149 static GList *_g_get_unix_mounts (void);
150 static GList *_g_get_unix_mount_points (void);
152 static guint64 mount_poller_time = 0;
154 #ifdef HAVE_SYS_MNTTAB_H
155 #define MNTOPT_RO "ro"
156 #endif
158 #ifdef HAVE_MNTENT_H
159 #include <mntent.h>
160 #ifdef HAVE_LIBMOUNT
161 #include <libmount/libmount.h>
162 #endif
163 #elif defined (HAVE_SYS_MNTTAB_H)
164 #include <sys/mnttab.h>
165 #endif
167 #ifdef HAVE_SYS_VFSTAB_H
168 #include <sys/vfstab.h>
169 #endif
171 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
172 #include <sys/mntctl.h>
173 #include <sys/vfs.h>
174 #include <sys/vmount.h>
175 #include <fshelp.h>
176 #endif
178 #if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
179 #include <sys/param.h>
180 #include <sys/ucred.h>
181 #include <sys/mount.h>
182 #include <fstab.h>
183 #ifdef HAVE_SYS_SYSCTL_H
184 #include <sys/sysctl.h>
185 #endif
186 #endif
188 #ifndef HAVE_SETMNTENT
189 #define setmntent(f,m) fopen(f,m)
190 #endif
191 #ifndef HAVE_ENDMNTENT
192 #define endmntent(f) fclose(f)
193 #endif
195 static gboolean
196 is_in (const char *value, const char *set[])
198 int i;
199 for (i = 0; set[i] != NULL; i++)
201 if (strcmp (set[i], value) == 0)
202 return TRUE;
204 return FALSE;
208 * g_unix_is_mount_path_system_internal:
209 * @mount_path: (type filename): a mount path, e.g. `/media/disk` or `/usr`
211 * Determines if @mount_path is considered an implementation of the
212 * OS. This is primarily used for hiding mountable and mounted volumes
213 * that only are used in the OS and has little to no relevance to the
214 * casual user.
216 * Returns: %TRUE if @mount_path is considered an implementation detail
217 * of the OS.
219 gboolean
220 g_unix_is_mount_path_system_internal (const char *mount_path)
222 const char *ignore_mountpoints[] = {
223 /* Includes all FHS 2.3 toplevel dirs and other specialized
224 * directories that we want to hide from the user.
226 "/", /* we already have "Filesystem root" in Nautilus */
227 "/bin",
228 "/boot",
229 "/compat/linux/proc",
230 "/compat/linux/sys",
231 "/dev",
232 "/etc",
233 "/home",
234 "/lib",
235 "/lib64",
236 "/libexec",
237 "/live/cow",
238 "/live/image",
239 "/media",
240 "/mnt",
241 "/opt",
242 "/rescue",
243 "/root",
244 "/sbin",
245 "/srv",
246 "/tmp",
247 "/usr",
248 "/usr/X11R6",
249 "/usr/local",
250 "/usr/obj",
251 "/usr/ports",
252 "/usr/src",
253 "/usr/xobj",
254 "/var",
255 "/var/crash",
256 "/var/local",
257 "/var/log",
258 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
259 "/var/mail",
260 "/var/run",
261 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
262 "/proc",
263 "/sbin",
264 "/net",
265 "/sys",
266 NULL
269 if (is_in (mount_path, ignore_mountpoints))
270 return TRUE;
272 if (g_str_has_prefix (mount_path, "/dev/") ||
273 g_str_has_prefix (mount_path, "/proc/") ||
274 g_str_has_prefix (mount_path, "/sys/"))
275 return TRUE;
277 if (g_str_has_suffix (mount_path, "/.gvfs"))
278 return TRUE;
280 return FALSE;
283 static gboolean
284 guess_system_internal (const char *mountpoint,
285 const char *fs,
286 const char *device)
288 const char *ignore_fs[] = {
289 "auto",
290 "autofs",
291 "devfs",
292 "devpts",
293 "ecryptfs",
294 "fdescfs",
295 "kernfs",
296 "linprocfs",
297 "mfs",
298 "nullfs",
299 "proc",
300 "procfs",
301 "ptyfs",
302 "rootfs",
303 "selinuxfs",
304 "sysfs",
305 "tmpfs",
306 "usbfs",
307 "nfsd",
308 "rpc_pipefs",
309 "zfs",
310 NULL
312 const char *ignore_devices[] = {
313 "none",
314 "sunrpc",
315 "devpts",
316 "nfsd",
317 "/dev/loop",
318 "/dev/vn",
319 NULL
322 if (is_in (fs, ignore_fs))
323 return TRUE;
325 if (is_in (device, ignore_devices))
326 return TRUE;
328 if (g_unix_is_mount_path_system_internal (mountpoint))
329 return TRUE;
331 return FALSE;
334 /* GUnixMounts (ie: mtab) implementations {{{1 */
336 static GUnixMountEntry *
337 create_unix_mount_entry (const char *device_path,
338 const char *mount_path,
339 const char *filesystem_type,
340 gboolean is_read_only)
342 GUnixMountEntry *mount_entry = NULL;
344 mount_entry = g_new0 (GUnixMountEntry, 1);
345 mount_entry->device_path = g_strdup (device_path);
346 mount_entry->mount_path = g_strdup (mount_path);
347 mount_entry->filesystem_type = g_strdup (filesystem_type);
348 mount_entry->is_read_only = is_read_only;
350 mount_entry->is_system_internal =
351 guess_system_internal (mount_entry->mount_path,
352 mount_entry->filesystem_type,
353 mount_entry->device_path);
354 return mount_entry;
357 static GUnixMountPoint *
358 create_unix_mount_point (const char *device_path,
359 const char *mount_path,
360 const char *filesystem_type,
361 const char *options,
362 gboolean is_read_only,
363 gboolean is_user_mountable,
364 gboolean is_loopback)
366 GUnixMountPoint *mount_point = NULL;
368 mount_point = g_new0 (GUnixMountPoint, 1);
369 mount_point->device_path = g_strdup (device_path);
370 mount_point->mount_path = g_strdup (mount_path);
371 mount_point->filesystem_type = g_strdup (filesystem_type);
372 mount_point->options = g_strdup (options);
373 mount_point->is_read_only = is_read_only;
374 mount_point->is_user_mountable = is_user_mountable;
375 mount_point->is_loopback = is_loopback;
377 return mount_point;
380 /* mntent.h (Linux, GNU, NSS) {{{2 */
381 #ifdef HAVE_MNTENT_H
383 #ifdef HAVE_LIBMOUNT
385 /* For documentation on /proc/self/mountinfo see
386 * http://www.kernel.org/doc/Documentation/filesystems/proc.txt
388 #define PROC_MOUNTINFO_PATH "/proc/self/mountinfo"
390 static GList *
391 _g_get_unix_mounts (void)
393 struct libmnt_table *table = NULL;
394 struct libmnt_iter* iter = NULL;
395 struct libmnt_fs *fs = NULL;
396 GUnixMountEntry *mount_entry = NULL;
397 GList *return_list = NULL;
399 table = mnt_new_table ();
400 if (mnt_table_parse_mtab (table, NULL) < 0)
401 goto out;
403 iter = mnt_new_iter (MNT_ITER_FORWARD);
404 while (mnt_table_next_fs (table, iter, &fs) == 0)
406 const char *device_path = NULL;
407 char *mount_options = NULL;
408 unsigned long mount_flags = 0;
409 gboolean is_read_only = FALSE;
411 device_path = mnt_fs_get_source (fs);
412 if (g_strcmp0 (device_path, "/dev/root") == 0)
413 device_path = _resolve_dev_root ();
415 mount_options = mnt_fs_strdup_options (fs);
416 if (mount_options)
418 mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
419 g_free (mount_options);
421 is_read_only = (mount_flags & MS_RDONLY) ? TRUE : FALSE;
423 mount_entry = create_unix_mount_entry (device_path,
424 mnt_fs_get_target (fs),
425 mnt_fs_get_fstype (fs),
426 is_read_only);
428 return_list = g_list_prepend (return_list, mount_entry);
430 mnt_free_iter (iter);
432 out:
433 mnt_unref_table (table);
435 return g_list_reverse (return_list);
438 #else
440 static const char *
441 get_mtab_read_file (void)
443 #ifdef _PATH_MOUNTED
444 # ifdef __linux__
445 return "/proc/mounts";
446 # else
447 return _PATH_MOUNTED;
448 # endif
449 #else
450 return "/etc/mtab";
451 #endif
454 #ifndef HAVE_GETMNTENT_R
455 G_LOCK_DEFINE_STATIC(getmntent);
456 #endif
458 static GList *
459 _g_get_unix_mounts (void)
461 #ifdef HAVE_GETMNTENT_R
462 struct mntent ent;
463 char buf[1024];
464 #endif
465 struct mntent *mntent;
466 FILE *file;
467 const char *read_file;
468 GUnixMountEntry *mount_entry;
469 GHashTable *mounts_hash;
470 GList *return_list;
472 read_file = get_mtab_read_file ();
474 file = setmntent (read_file, "r");
475 if (file == NULL)
476 return NULL;
478 return_list = NULL;
480 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
482 #ifdef HAVE_GETMNTENT_R
483 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
484 #else
485 G_LOCK (getmntent);
486 while ((mntent = getmntent (file)) != NULL)
487 #endif
489 const char *device_path = NULL;
490 gboolean is_read_only = FALSE;
492 /* ignore any mnt_fsname that is repeated and begins with a '/'
494 * We do this to avoid being fooled by --bind mounts, since
495 * these have the same device as the location they bind to.
496 * It's not an ideal solution to the problem, but it's likely that
497 * the most important mountpoint is first and the --bind ones after
498 * that aren't as important. So it should work.
500 * The '/' is to handle procfs, tmpfs and other no device mounts.
502 if (mntent->mnt_fsname != NULL &&
503 mntent->mnt_fsname[0] == '/' &&
504 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
505 continue;
507 if (g_strcmp0 (mntent->mnt_fsname, "/dev/root") == 0)
508 device_path = _resolve_dev_root ();
509 else
510 device_path = mntent->mnt_fsname;
512 #if defined (HAVE_HASMNTOPT)
513 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
514 is_read_only = TRUE;
515 #endif
517 mount_entry = create_unix_mount_entry (device_path,
518 mntent->mnt_dir,
519 mntent->mnt_type,
520 is_read_only);
522 g_hash_table_insert (mounts_hash,
523 mount_entry->device_path,
524 mount_entry->device_path);
526 return_list = g_list_prepend (return_list, mount_entry);
528 g_hash_table_destroy (mounts_hash);
530 endmntent (file);
532 #ifndef HAVE_GETMNTENT_R
533 G_UNLOCK (getmntent);
534 #endif
536 return g_list_reverse (return_list);
539 #endif /* HAVE_LIBMOUNT */
541 static const char *
542 get_mtab_monitor_file (void)
544 static const char *mountinfo_path = NULL;
545 #ifdef HAVE_LIBMOUNT
546 struct stat buf;
547 #endif
549 if (mountinfo_path != NULL)
550 return mountinfo_path;
552 #ifdef HAVE_LIBMOUNT
553 /* The mtab file is still used by some distros, so it has to be monitored in
554 * order to avoid races between g_unix_mounts_get and "mounts-changed" signal:
555 * https://bugzilla.gnome.org/show_bug.cgi?id=782814
557 if (mnt_has_regular_mtab (&mountinfo_path, NULL))
559 return mountinfo_path;
562 if (stat (PROC_MOUNTINFO_PATH, &buf) == 0)
564 mountinfo_path = PROC_MOUNTINFO_PATH;
565 return mountinfo_path;
567 #endif
569 #ifdef _PATH_MOUNTED
570 # ifdef __linux__
571 mountinfo_path = "/proc/mounts";
572 # else
573 mountinfo_path = _PATH_MOUNTED;
574 # endif
575 #else
576 mountinfo_path = "/etc/mtab";
577 #endif
579 return mountinfo_path;
582 /* mnttab.h {{{2 */
583 #elif defined (HAVE_SYS_MNTTAB_H)
585 G_LOCK_DEFINE_STATIC(getmntent);
587 static const char *
588 get_mtab_read_file (void)
590 #ifdef _PATH_MOUNTED
591 return _PATH_MOUNTED;
592 #else
593 return "/etc/mnttab";
594 #endif
597 static const char *
598 get_mtab_monitor_file (void)
600 return get_mtab_read_file ();
603 static GList *
604 _g_get_unix_mounts (void)
606 struct mnttab mntent;
607 FILE *file;
608 const char *read_file;
609 GUnixMountEntry *mount_entry;
610 GList *return_list;
612 read_file = get_mtab_read_file ();
614 file = setmntent (read_file, "r");
615 if (file == NULL)
616 return NULL;
618 return_list = NULL;
620 G_LOCK (getmntent);
621 while (! getmntent (file, &mntent))
623 gboolean is_read_only = FALSE;
625 #if defined (HAVE_HASMNTOPT)
626 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
627 is_read_only = TRUE;
628 #endif
630 mount_entry = create_unix_mount_entry (mntent.mnt_special,
631 mntent.mnt_mountp,
632 mntent.mnt_fstype,
633 is_read_only);
635 return_list = g_list_prepend (return_list, mount_entry);
638 endmntent (file);
640 G_UNLOCK (getmntent);
642 return g_list_reverse (return_list);
645 /* mntctl.h (AIX) {{{2 */
646 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
648 static const char *
649 get_mtab_monitor_file (void)
651 return NULL;
654 static GList *
655 _g_get_unix_mounts (void)
657 struct vfs_ent *fs_info;
658 struct vmount *vmount_info;
659 int vmount_number;
660 unsigned int vmount_size;
661 int current;
662 GList *return_list;
664 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
666 g_warning ("Unable to know the number of mounted volumes\n");
668 return NULL;
671 vmount_info = (struct vmount*)g_malloc (vmount_size);
673 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
675 if (vmount_info->vmt_revision != VMT_REVISION)
676 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
678 if (vmount_number < 0)
680 g_warning ("Unable to recover mounted volumes information\n");
682 g_free (vmount_info);
683 return NULL;
686 return_list = NULL;
687 while (vmount_number > 0)
689 gboolean is_read_only = FALSE;
691 fs_info = getvfsbytype (vmount_info->vmt_gfstype);
693 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
694 is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
696 mount_entry = create_unix_mount_entry (vmt2dataptr (vmount_info, VMT_OBJECT),
697 vmt2dataptr (vmount_info, VMT_STUB),
698 fs_info == NULL ? "unknown" : fs_info->vfsent_name,
699 is_read_only);
701 return_list = g_list_prepend (return_list, mount_entry);
703 vmount_info = (struct vmount *)( (char*)vmount_info
704 + vmount_info->vmt_length);
705 vmount_number--;
708 g_free (vmount_info);
710 return g_list_reverse (return_list);
713 /* sys/mount.h {{{2 */
714 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
716 static const char *
717 get_mtab_monitor_file (void)
719 return NULL;
722 static GList *
723 _g_get_unix_mounts (void)
725 #if defined(USE_STATVFS)
726 struct statvfs *mntent = NULL;
727 #elif defined(USE_STATFS)
728 struct statfs *mntent = NULL;
729 #else
730 #error statfs juggling failed
731 #endif
732 size_t bufsize;
733 int num_mounts, i;
734 GUnixMountEntry *mount_entry;
735 GList *return_list;
737 /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
738 #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
739 num_mounts = getvfsstat (NULL, 0, ST_NOWAIT);
740 #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
741 num_mounts = getfsstat (NULL, 0, MNT_NOWAIT);
742 #endif
743 if (num_mounts == -1)
744 return NULL;
746 bufsize = num_mounts * sizeof (*mntent);
747 mntent = g_malloc (bufsize);
748 #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
749 num_mounts = getvfsstat (mntent, bufsize, ST_NOWAIT);
750 #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
751 num_mounts = getfsstat (mntent, bufsize, MNT_NOWAIT);
752 #endif
753 if (num_mounts == -1)
754 return NULL;
756 return_list = NULL;
758 for (i = 0; i < num_mounts; i++)
760 gboolean is_read_only = FALSE;
762 #if defined(USE_STATVFS)
763 if (mntent[i].f_flag & ST_RDONLY)
764 #elif defined(USE_STATFS)
765 if (mntent[i].f_flags & MNT_RDONLY)
766 #else
767 #error statfs juggling failed
768 #endif
769 is_read_only = TRUE;
771 mount_entry = create_unix_mount_entry (mntent[i].f_mntfromname,
772 mntent[i].f_mntonname,
773 mntent[i].f_fstypename,
774 is_read_only);
776 return_list = g_list_prepend (return_list, mount_entry);
779 g_free (mntent);
781 return g_list_reverse (return_list);
784 /* Interix {{{2 */
785 #elif defined(__INTERIX)
787 static const char *
788 get_mtab_monitor_file (void)
790 return NULL;
793 static GList *
794 _g_get_unix_mounts (void)
796 DIR *dirp;
797 GList* return_list = NULL;
798 char filename[9 + NAME_MAX];
800 dirp = opendir ("/dev/fs");
801 if (!dirp)
803 g_warning ("unable to read /dev/fs!");
804 return NULL;
807 while (1)
809 struct statvfs statbuf;
810 struct dirent entry;
811 struct dirent* result;
813 if (readdir_r (dirp, &entry, &result) || result == NULL)
814 break;
816 strcpy (filename, "/dev/fs/");
817 strcat (filename, entry.d_name);
819 if (statvfs (filename, &statbuf) == 0)
821 GUnixMountEntry* mount_entry = g_new0(GUnixMountEntry, 1);
823 mount_entry->mount_path = g_strdup (statbuf.f_mntonname);
824 mount_entry->device_path = g_strdup (statbuf.f_mntfromname);
825 mount_entry->filesystem_type = g_strdup (statbuf.f_fstypename);
827 if (statbuf.f_flag & ST_RDONLY)
828 mount_entry->is_read_only = TRUE;
830 return_list = g_list_prepend(return_list, mount_entry);
834 return_list = g_list_reverse (return_list);
836 closedir (dirp);
838 return return_list;
841 /* Common code {{{2 */
842 #else
843 #error No _g_get_unix_mounts() implementation for system
844 #endif
846 /* GUnixMountPoints (ie: fstab) implementations {{{1 */
848 /* _g_get_unix_mount_points():
849 * read the fstab.
850 * don't return swap and ignore mounts.
853 static char *
854 get_fstab_file (void)
856 #ifdef HAVE_LIBMOUNT
857 return (char *) mnt_get_fstab_path ();
858 #else
859 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
860 /* AIX */
861 return "/etc/filesystems";
862 #elif defined(_PATH_MNTTAB)
863 return _PATH_MNTTAB;
864 #elif defined(VFSTAB)
865 return VFSTAB;
866 #else
867 return "/etc/fstab";
868 #endif
869 #endif
872 /* mntent.h (Linux, GNU, NSS) {{{2 */
873 #ifdef HAVE_MNTENT_H
875 #ifdef HAVE_LIBMOUNT
877 static GList *
878 _g_get_unix_mount_points (void)
880 struct libmnt_table *table = NULL;
881 struct libmnt_iter* iter = NULL;
882 struct libmnt_fs *fs = NULL;
883 GUnixMountPoint *mount_point = NULL;
884 GList *return_list = NULL;
886 table = mnt_new_table ();
887 if (mnt_table_parse_mtab (table, NULL) < 0)
888 goto out;
890 iter = mnt_new_iter (MNT_ITER_FORWARD);
891 while (mnt_table_next_fs (table, iter, &fs) == 0)
893 const char *device_path = NULL;
894 const char *mount_path = NULL;
895 const char *mount_fstype = NULL;
896 char *mount_options = NULL;
897 gboolean is_read_only = FALSE;
898 gboolean is_user_mountable = FALSE;
899 gboolean is_loopback = FALSE;
901 mount_path = mnt_fs_get_target (fs);
902 if ((strcmp (mount_path, "ignore") == 0) ||
903 (strcmp (mount_path, "swap") == 0) ||
904 (strcmp (mount_path, "none") == 0))
905 continue;
907 mount_fstype = mnt_fs_get_fstype (fs);
908 mount_options = mnt_fs_strdup_options (fs);
909 if (mount_options)
911 unsigned long mount_flags = 0;
912 unsigned long userspace_flags = 0;
914 mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
915 mnt_optstr_get_flags (mount_options, &userspace_flags, mnt_get_builtin_optmap (MNT_USERSPACE_MAP));
917 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
918 if (mount_flags & MS_BIND)
920 g_free (mount_options);
921 continue;
924 is_read_only = (mount_flags & MS_RDONLY) != 0;
925 is_loopback = (userspace_flags & MNT_MS_LOOP) != 0;
927 if ((mount_fstype != NULL && g_strcmp0 ("supermount", mount_fstype) == 0) ||
928 ((userspace_flags & MNT_MS_USER) &&
929 (g_strstr_len (mount_options, -1, "user_xattr") == NULL)) ||
930 (g_strstr_len (mount_options, -1, "pamconsole") == NULL) ||
931 (userspace_flags & MNT_MS_USERS) ||
932 (userspace_flags & MNT_MS_OWNER))
934 is_user_mountable = TRUE;
938 device_path = mnt_fs_get_source (fs);
939 if (g_strcmp0 (device_path, "/dev/root") == 0)
940 device_path = _resolve_dev_root ();
942 mount_point = create_unix_mount_point (device_path,
943 mount_path,
944 mount_fstype,
945 mount_options,
946 is_read_only,
947 is_user_mountable,
948 is_loopback);
949 if (mount_options)
950 g_free (mount_options);
952 return_list = g_list_prepend (return_list, mount_point);
954 mnt_free_iter (iter);
956 out:
957 mnt_unref_table (table);
959 return g_list_reverse (return_list);
962 #else
964 static GList *
965 _g_get_unix_mount_points (void)
967 #ifdef HAVE_GETMNTENT_R
968 struct mntent ent;
969 char buf[1024];
970 #endif
971 struct mntent *mntent;
972 FILE *file;
973 char *read_file;
974 GUnixMountPoint *mount_point;
975 GList *return_list;
977 read_file = get_fstab_file ();
979 file = setmntent (read_file, "r");
980 if (file == NULL)
981 return NULL;
983 return_list = NULL;
985 #ifdef HAVE_GETMNTENT_R
986 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
987 #else
988 G_LOCK (getmntent);
989 while ((mntent = getmntent (file)) != NULL)
990 #endif
992 const char *device_path = NULL;
993 gboolean is_read_only = FALSE;
994 gboolean is_user_mountable = FALSE;
995 gboolean is_loopback = FALSE;
997 if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
998 (strcmp (mntent->mnt_dir, "swap") == 0) ||
999 (strcmp (mntent->mnt_dir, "none") == 0))
1000 continue;
1002 #ifdef HAVE_HASMNTOPT
1003 /* We ignore bind fstab entries, as we ignore bind mounts anyway */
1004 if (hasmntopt (mntent, "bind"))
1005 continue;
1006 #endif
1008 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
1009 device_path = _resolve_dev_root ();
1010 else
1011 device_path = mntent->mnt_fsname;
1013 #ifdef HAVE_HASMNTOPT
1014 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
1015 is_read_only = TRUE;
1017 if (hasmntopt (mntent, "loop") != NULL)
1018 is_loopback = TRUE;
1020 #endif
1022 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
1023 #ifdef HAVE_HASMNTOPT
1024 || (hasmntopt (mntent, "user") != NULL
1025 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
1026 || hasmntopt (mntent, "pamconsole") != NULL
1027 || hasmntopt (mntent, "users") != NULL
1028 || hasmntopt (mntent, "owner") != NULL
1029 #endif
1031 is_user_mountable = TRUE;
1033 mount_point = create_unix_mount_point (device_path,
1034 mntent->mnt_dir,
1035 mntent->mnt_type,
1036 mntent->mnt_opts,
1037 is_read_only,
1038 is_user_mountable,
1039 is_loopback);
1041 return_list = g_list_prepend (return_list, mount_point);
1044 endmntent (file);
1046 #ifndef HAVE_GETMNTENT_R
1047 G_UNLOCK (getmntent);
1048 #endif
1050 return g_list_reverse (return_list);
1053 #endif /* HAVE_LIBMOUNT */
1055 /* mnttab.h {{{2 */
1056 #elif defined (HAVE_SYS_MNTTAB_H)
1058 static GList *
1059 _g_get_unix_mount_points (void)
1061 struct mnttab mntent;
1062 FILE *file;
1063 char *read_file;
1064 GUnixMountPoint *mount_point;
1065 GList *return_list;
1067 read_file = get_fstab_file ();
1069 file = setmntent (read_file, "r");
1070 if (file == NULL)
1071 return NULL;
1073 return_list = NULL;
1075 G_LOCK (getmntent);
1076 while (! getmntent (file, &mntent))
1078 gboolean is_read_only = FALSE;
1079 gboolean is_user_mountable = FALSE;
1080 gboolean is_loopback = FALSE;
1082 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
1083 (strcmp (mntent.mnt_mountp, "swap") == 0) ||
1084 (strcmp (mntent.mnt_mountp, "none") == 0))
1085 continue;
1087 #ifdef HAVE_HASMNTOPT
1088 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
1089 is_read_only = TRUE;
1091 if (hasmntopt (&mntent, "lofs") != NULL)
1092 is_loopback = TRUE;
1093 #endif
1095 if ((mntent.mnt_fstype != NULL)
1096 #ifdef HAVE_HASMNTOPT
1097 || (hasmntopt (&mntent, "user") != NULL
1098 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
1099 || hasmntopt (&mntent, "pamconsole") != NULL
1100 || hasmntopt (&mntent, "users") != NULL
1101 || hasmntopt (&mntent, "owner") != NULL
1102 #endif
1104 is_user_mountable = TRUE;
1106 mount_point = create_unix_mount_point (mntent.mnt_special,
1107 mntent.mnt_mountp,
1108 mntent.mnt_fstype,
1109 mntent.mnt_mntopts,
1110 is_read_only,
1111 is_user_mountable,
1112 is_loopback);
1114 return_list = g_list_prepend (return_list, mount_point);
1117 endmntent (file);
1118 G_UNLOCK (getmntent);
1120 return g_list_reverse (return_list);
1123 /* mntctl.h (AIX) {{{2 */
1124 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
1126 /* functions to parse /etc/filesystems on aix */
1128 /* read character, ignoring comments (begin with '*', end with '\n' */
1129 static int
1130 aix_fs_getc (FILE *fd)
1132 int c;
1134 while ((c = getc (fd)) == '*')
1136 while (((c = getc (fd)) != '\n') && (c != EOF))
1141 /* eat all continuous spaces in a file */
1142 static int
1143 aix_fs_ignorespace (FILE *fd)
1145 int c;
1147 while ((c = aix_fs_getc (fd)) != EOF)
1149 if (!g_ascii_isspace (c))
1151 ungetc (c,fd);
1152 return c;
1156 return EOF;
1159 /* read one word from file */
1160 static int
1161 aix_fs_getword (FILE *fd,
1162 char *word)
1164 int c;
1166 aix_fs_ignorespace (fd);
1168 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
1170 if (c == '"')
1172 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
1173 *word++ = c;
1174 else
1175 *word++ = c;
1178 *word = 0;
1180 return c;
1183 typedef struct {
1184 char mnt_mount[PATH_MAX];
1185 char mnt_special[PATH_MAX];
1186 char mnt_fstype[16];
1187 char mnt_options[128];
1188 } AixMountTableEntry;
1190 /* read mount points properties */
1191 static int
1192 aix_fs_get (FILE *fd,
1193 AixMountTableEntry *prop)
1195 static char word[PATH_MAX] = { 0 };
1196 char value[PATH_MAX];
1198 /* read stanza */
1199 if (word[0] == 0)
1201 if (aix_fs_getword (fd, word) == EOF)
1202 return EOF;
1205 word[strlen(word) - 1] = 0;
1206 strcpy (prop->mnt_mount, word);
1208 /* read attributes and value */
1210 while (aix_fs_getword (fd, word) != EOF)
1212 /* test if is attribute or new stanza */
1213 if (word[strlen(word) - 1] == ':')
1214 return 0;
1216 /* read "=" */
1217 aix_fs_getword (fd, value);
1219 /* read value */
1220 aix_fs_getword (fd, value);
1222 if (strcmp (word, "dev") == 0)
1223 strcpy (prop->mnt_special, value);
1224 else if (strcmp (word, "vfs") == 0)
1225 strcpy (prop->mnt_fstype, value);
1226 else if (strcmp (word, "options") == 0)
1227 strcpy(prop->mnt_options, value);
1230 return 0;
1233 static GList *
1234 _g_get_unix_mount_points (void)
1236 struct mntent *mntent;
1237 FILE *file;
1238 char *read_file;
1239 GUnixMountPoint *mount_point;
1240 AixMountTableEntry mntent;
1241 GList *return_list;
1243 read_file = get_fstab_file ();
1245 file = setmntent (read_file, "r");
1246 if (file == NULL)
1247 return NULL;
1249 return_list = NULL;
1251 while (!aix_fs_get (file, &mntent))
1253 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
1255 mount_point = create_unix_mount_point (mntent.mnt_special,
1256 mntent.mnt_mount,
1257 mntent.mnt_fstype,
1258 mntent.mnt_options,
1259 TRUE,
1260 TRUE,
1261 FALSE);
1263 return_list = g_list_prepend (return_list, mount_point);
1267 endmntent (file);
1269 return g_list_reverse (return_list);
1272 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
1274 static GList *
1275 _g_get_unix_mount_points (void)
1277 struct fstab *fstab = NULL;
1278 GUnixMountPoint *mount_point;
1279 GList *return_list;
1280 #ifdef HAVE_SYS_SYSCTL_H
1281 int usermnt = 0;
1282 size_t len = sizeof(usermnt);
1283 struct stat sb;
1284 #endif
1286 if (!setfsent ())
1287 return NULL;
1289 return_list = NULL;
1291 #ifdef HAVE_SYS_SYSCTL_H
1292 #if defined(HAVE_SYSCTLBYNAME)
1293 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
1294 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
1296 int mib[2];
1298 mib[0] = CTL_VFS;
1299 mib[1] = VFS_USERMOUNT;
1300 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1302 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
1304 int mib[2];
1306 mib[0] = CTL_KERN;
1307 mib[1] = KERN_USERMOUNT;
1308 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1310 #endif
1311 #endif
1313 while ((fstab = getfsent ()) != NULL)
1315 gboolean is_read_only = FALSE;
1316 gboolean is_user_mountable = FALSE;
1318 if (strcmp (fstab->fs_vfstype, "swap") == 0)
1319 continue;
1321 if (strcmp (fstab->fs_type, "ro") == 0)
1322 is_read_only = TRUE;
1324 #ifdef HAVE_SYS_SYSCTL_H
1325 if (usermnt != 0)
1327 uid_t uid = getuid ();
1328 if (stat (fstab->fs_file, &sb) == 0)
1330 if (uid == 0 || sb.st_uid == uid)
1331 is_user_mountable = TRUE;
1334 #endif
1336 mount_point = create_unix_mount_point (fstab->fs_spec,
1337 fstab->fs_file,
1338 fstab->fs_vfstype,
1339 fstab->fs_mntops,
1340 is_read_only,
1341 is_user_mountable,
1342 FALSE);
1344 return_list = g_list_prepend (return_list, mount_point);
1347 endfsent ();
1349 return g_list_reverse (return_list);
1351 /* Interix {{{2 */
1352 #elif defined(__INTERIX)
1353 static GList *
1354 _g_get_unix_mount_points (void)
1356 return _g_get_unix_mounts ();
1359 /* Common code {{{2 */
1360 #else
1361 #error No g_get_mount_table() implementation for system
1362 #endif
1364 static guint64
1365 get_mounts_timestamp (void)
1367 const char *monitor_file;
1368 struct stat buf;
1370 monitor_file = get_mtab_monitor_file ();
1371 if (monitor_file)
1373 if (stat (monitor_file, &buf) == 0)
1374 return (guint64)buf.st_mtime;
1376 else
1378 return mount_poller_time;
1380 return 0;
1383 static guint64
1384 get_mount_points_timestamp (void)
1386 const char *monitor_file;
1387 struct stat buf;
1389 monitor_file = get_fstab_file ();
1390 if (monitor_file)
1392 if (stat (monitor_file, &buf) == 0)
1393 return (guint64)buf.st_mtime;
1395 return 0;
1399 * g_unix_mounts_get:
1400 * @time_read: (out) (optional): guint64 to contain a timestamp, or %NULL
1402 * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1403 * If @time_read is set, it will be filled with the mount
1404 * timestamp, allowing for checking if the mounts have changed
1405 * with g_unix_mounts_changed_since().
1407 * Returns: (element-type GUnixMountEntry) (transfer full):
1408 * a #GList of the UNIX mounts.
1410 GList *
1411 g_unix_mounts_get (guint64 *time_read)
1413 if (time_read)
1414 *time_read = get_mounts_timestamp ();
1416 return _g_get_unix_mounts ();
1420 * g_unix_mount_at:
1421 * @mount_path: (type filename): path for a possible unix mount.
1422 * @time_read: (out) (optional): guint64 to contain a timestamp.
1424 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1425 * is set, it will be filled with a unix timestamp for checking
1426 * if the mounts have changed since with g_unix_mounts_changed_since().
1428 * Returns: (transfer full): a #GUnixMountEntry.
1430 GUnixMountEntry *
1431 g_unix_mount_at (const char *mount_path,
1432 guint64 *time_read)
1434 GList *mounts, *l;
1435 GUnixMountEntry *mount_entry, *found;
1437 mounts = g_unix_mounts_get (time_read);
1439 found = NULL;
1440 for (l = mounts; l != NULL; l = l->next)
1442 mount_entry = l->data;
1444 if (!found && strcmp (mount_path, mount_entry->mount_path) == 0)
1445 found = mount_entry;
1446 else
1447 g_unix_mount_free (mount_entry);
1449 g_list_free (mounts);
1451 return found;
1455 * g_unix_mount_for:
1456 * @file_path: (type filename): file path on some unix mount.
1457 * @time_read: (out) (optional): guint64 to contain a timestamp.
1459 * Gets a #GUnixMountEntry for a given file path. If @time_read
1460 * is set, it will be filled with a unix timestamp for checking
1461 * if the mounts have changed since with g_unix_mounts_changed_since().
1463 * Returns: (transfer full): a #GUnixMountEntry.
1465 * Since: 2.52
1467 GUnixMountEntry *
1468 g_unix_mount_for (const char *file_path,
1469 guint64 *time_read)
1471 GUnixMountEntry *entry;
1473 g_return_val_if_fail (file_path != NULL, NULL);
1475 entry = g_unix_mount_at (file_path, time_read);
1476 if (entry == NULL)
1478 char *topdir;
1480 topdir = _g_local_file_find_topdir_for (file_path);
1481 if (topdir != NULL)
1483 entry = g_unix_mount_at (topdir, time_read);
1484 g_free (topdir);
1488 return entry;
1492 * g_unix_mount_points_get:
1493 * @time_read: (out) (optional): guint64 to contain a timestamp.
1495 * Gets a #GList of #GUnixMountPoint containing the unix mount points.
1496 * If @time_read is set, it will be filled with the mount timestamp,
1497 * allowing for checking if the mounts have changed with
1498 * g_unix_mount_points_changed_since().
1500 * Returns: (element-type GUnixMountPoint) (transfer full):
1501 * a #GList of the UNIX mountpoints.
1503 GList *
1504 g_unix_mount_points_get (guint64 *time_read)
1506 if (time_read)
1507 *time_read = get_mount_points_timestamp ();
1509 return _g_get_unix_mount_points ();
1513 * g_unix_mounts_changed_since:
1514 * @time: guint64 to contain a timestamp.
1516 * Checks if the unix mounts have changed since a given unix time.
1518 * Returns: %TRUE if the mounts have changed since @time.
1520 gboolean
1521 g_unix_mounts_changed_since (guint64 time)
1523 return get_mounts_timestamp () != time;
1527 * g_unix_mount_points_changed_since:
1528 * @time: guint64 to contain a timestamp.
1530 * Checks if the unix mount points have changed since a given unix time.
1532 * Returns: %TRUE if the mount points have changed since @time.
1534 gboolean
1535 g_unix_mount_points_changed_since (guint64 time)
1537 return get_mount_points_timestamp () != time;
1540 /* GUnixMountMonitor {{{1 */
1542 enum {
1543 MOUNTS_CHANGED,
1544 MOUNTPOINTS_CHANGED,
1545 LAST_SIGNAL
1548 static guint signals[LAST_SIGNAL];
1550 struct _GUnixMountMonitor {
1551 GObject parent;
1553 GMainContext *context;
1556 struct _GUnixMountMonitorClass {
1557 GObjectClass parent_class;
1561 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT)
1563 static GContextSpecificGroup mount_monitor_group;
1564 static GFileMonitor *fstab_monitor;
1565 static GFileMonitor *mtab_monitor;
1566 static GSource *proc_mounts_watch_source;
1567 static GList *mount_poller_mounts;
1569 static void
1570 fstab_file_changed (GFileMonitor *monitor,
1571 GFile *file,
1572 GFile *other_file,
1573 GFileMonitorEvent event_type,
1574 gpointer user_data)
1576 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1577 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1578 event_type != G_FILE_MONITOR_EVENT_DELETED)
1579 return;
1581 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
1584 static void
1585 mtab_file_changed (GFileMonitor *monitor,
1586 GFile *file,
1587 GFile *other_file,
1588 GFileMonitorEvent event_type,
1589 gpointer user_data)
1591 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1592 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1593 event_type != G_FILE_MONITOR_EVENT_DELETED)
1594 return;
1596 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
1599 static gboolean
1600 proc_mounts_changed (GIOChannel *channel,
1601 GIOCondition cond,
1602 gpointer user_data)
1604 if (cond & G_IO_ERR)
1605 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
1607 return TRUE;
1610 static gboolean
1611 mount_change_poller (gpointer user_data)
1613 GList *current_mounts, *new_it, *old_it;
1614 gboolean has_changed = FALSE;
1616 current_mounts = _g_get_unix_mounts ();
1618 for ( new_it = current_mounts, old_it = mount_poller_mounts;
1619 new_it != NULL && old_it != NULL;
1620 new_it = g_list_next (new_it), old_it = g_list_next (old_it) )
1622 if (g_unix_mount_compare (new_it->data, old_it->data) != 0)
1624 has_changed = TRUE;
1625 break;
1628 if (!(new_it == NULL && old_it == NULL))
1629 has_changed = TRUE;
1631 g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
1633 mount_poller_mounts = current_mounts;
1635 if (has_changed)
1637 mount_poller_time = (guint64) g_get_monotonic_time ();
1638 g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
1641 return TRUE;
1645 static void
1646 mount_monitor_stop (void)
1648 if (fstab_monitor)
1650 g_file_monitor_cancel (fstab_monitor);
1651 g_object_unref (fstab_monitor);
1654 if (proc_mounts_watch_source != NULL)
1655 g_source_destroy (proc_mounts_watch_source);
1657 if (mtab_monitor)
1659 g_file_monitor_cancel (mtab_monitor);
1660 g_object_unref (mtab_monitor);
1663 g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
1666 static void
1667 mount_monitor_start (void)
1669 GFile *file;
1671 if (get_fstab_file () != NULL)
1673 file = g_file_new_for_path (get_fstab_file ());
1674 fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1675 g_object_unref (file);
1677 g_signal_connect (fstab_monitor, "changed", (GCallback)fstab_file_changed, NULL);
1680 if (get_mtab_monitor_file () != NULL)
1682 const gchar *mtab_path;
1684 mtab_path = get_mtab_monitor_file ();
1685 /* Monitoring files in /proc/ is special - can't just use GFileMonitor.
1686 * See 'man proc' for more details.
1688 if (g_str_has_prefix (mtab_path, "/proc/"))
1690 GIOChannel *proc_mounts_channel;
1691 GError *error = NULL;
1692 proc_mounts_channel = g_io_channel_new_file (mtab_path, "r", &error);
1693 if (proc_mounts_channel == NULL)
1695 g_warning ("Error creating IO channel for %s: %s (%s, %d)", mtab_path,
1696 error->message, g_quark_to_string (error->domain), error->code);
1697 g_error_free (error);
1699 else
1701 proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
1702 g_source_set_callback (proc_mounts_watch_source,
1703 (GSourceFunc) proc_mounts_changed,
1704 NULL, NULL);
1705 g_source_attach (proc_mounts_watch_source,
1706 g_main_context_get_thread_default ());
1707 g_source_unref (proc_mounts_watch_source);
1708 g_io_channel_unref (proc_mounts_channel);
1711 else
1713 file = g_file_new_for_path (mtab_path);
1714 mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1715 g_object_unref (file);
1716 g_signal_connect (mtab_monitor, "changed", (GCallback)mtab_file_changed, NULL);
1719 else
1721 proc_mounts_watch_source = g_timeout_source_new_seconds (3);
1722 mount_poller_mounts = _g_get_unix_mounts ();
1723 mount_poller_time = (guint64)g_get_monotonic_time ();
1724 g_source_set_callback (proc_mounts_watch_source,
1725 mount_change_poller,
1726 NULL, NULL);
1727 g_source_attach (proc_mounts_watch_source,
1728 g_main_context_get_thread_default ());
1729 g_source_unref (proc_mounts_watch_source);
1733 static void
1734 g_unix_mount_monitor_finalize (GObject *object)
1736 GUnixMountMonitor *monitor;
1738 monitor = G_UNIX_MOUNT_MONITOR (object);
1740 g_context_specific_group_remove (&mount_monitor_group, monitor->context, monitor, mount_monitor_stop);
1742 G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
1745 static void
1746 g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
1748 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1750 gobject_class->finalize = g_unix_mount_monitor_finalize;
1753 * GUnixMountMonitor::mounts-changed:
1754 * @monitor: the object on which the signal is emitted
1756 * Emitted when the unix mounts have changed.
1758 signals[MOUNTS_CHANGED] =
1759 g_signal_new (I_("mounts-changed"),
1760 G_TYPE_FROM_CLASS (klass),
1761 G_SIGNAL_RUN_LAST,
1763 NULL, NULL,
1764 g_cclosure_marshal_VOID__VOID,
1765 G_TYPE_NONE, 0);
1768 * GUnixMountMonitor::mountpoints-changed:
1769 * @monitor: the object on which the signal is emitted
1771 * Emitted when the unix mount points have changed.
1773 signals[MOUNTPOINTS_CHANGED] =
1774 g_signal_new (I_("mountpoints-changed"),
1775 G_TYPE_FROM_CLASS (klass),
1776 G_SIGNAL_RUN_LAST,
1778 NULL, NULL,
1779 g_cclosure_marshal_VOID__VOID,
1780 G_TYPE_NONE, 0);
1783 static void
1784 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1789 * g_unix_mount_monitor_set_rate_limit:
1790 * @mount_monitor: a #GUnixMountMonitor
1791 * @limit_msec: a integer with the limit in milliseconds to
1792 * poll for changes.
1794 * This function does nothing.
1796 * Before 2.44, this was a partially-effective way of controlling the
1797 * rate at which events would be reported under some uncommon
1798 * circumstances. Since @mount_monitor is a singleton, it also meant
1799 * that calling this function would have side effects for other users of
1800 * the monitor.
1802 * Since: 2.18
1804 * Deprecated:2.44:This function does nothing. Don't call it.
1806 void
1807 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
1808 gint limit_msec)
1813 * g_unix_mount_monitor_get:
1815 * Gets the #GUnixMountMonitor for the current thread-default main
1816 * context.
1818 * The mount monitor can be used to monitor for changes to the list of
1819 * mounted filesystems as well as the list of mount points (ie: fstab
1820 * entries).
1822 * You must only call g_object_unref() on the return value from under
1823 * the same main context as you called this function.
1825 * Returns: (transfer full): the #GUnixMountMonitor.
1827 * Since: 2.44
1829 GUnixMountMonitor *
1830 g_unix_mount_monitor_get (void)
1832 return g_context_specific_group_get (&mount_monitor_group,
1833 G_TYPE_UNIX_MOUNT_MONITOR,
1834 G_STRUCT_OFFSET(GUnixMountMonitor, context),
1835 mount_monitor_start);
1839 * g_unix_mount_monitor_new:
1841 * Deprecated alias for g_unix_mount_monitor_get().
1843 * This function was never a true constructor, which is why it was
1844 * renamed.
1846 * Returns: a #GUnixMountMonitor.
1848 * Deprecated:2.44:Use g_unix_mount_monitor_get() instead.
1850 GUnixMountMonitor *
1851 g_unix_mount_monitor_new (void)
1853 return g_unix_mount_monitor_get ();
1856 /* GUnixMount {{{1 */
1858 * g_unix_mount_free:
1859 * @mount_entry: a #GUnixMountEntry.
1861 * Frees a unix mount.
1863 void
1864 g_unix_mount_free (GUnixMountEntry *mount_entry)
1866 g_return_if_fail (mount_entry != NULL);
1868 g_free (mount_entry->mount_path);
1869 g_free (mount_entry->device_path);
1870 g_free (mount_entry->filesystem_type);
1871 g_free (mount_entry);
1875 * g_unix_mount_copy:
1876 * @mount_entry: a #GUnixMountEntry.
1878 * Makes a copy of @mount_entry.
1880 * Returns: (transfer full): a new #GUnixMountEntry
1882 * Since: 2.54
1884 GUnixMountEntry *
1885 g_unix_mount_copy (GUnixMountEntry *mount_entry)
1887 GUnixMountEntry *copy;
1889 g_return_val_if_fail (mount_entry != NULL, NULL);
1891 copy = g_new0 (GUnixMountEntry, 1);
1892 copy->mount_path = g_strdup (mount_entry->mount_path);
1893 copy->device_path = g_strdup (mount_entry->device_path);
1894 copy->filesystem_type = g_strdup (mount_entry->filesystem_type);
1895 copy->is_read_only = mount_entry->is_read_only;
1896 copy->is_system_internal = mount_entry->is_system_internal;
1898 return copy;
1902 * g_unix_mount_point_free:
1903 * @mount_point: unix mount point to free.
1905 * Frees a unix mount point.
1907 void
1908 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1910 g_return_if_fail (mount_point != NULL);
1912 g_free (mount_point->mount_path);
1913 g_free (mount_point->device_path);
1914 g_free (mount_point->filesystem_type);
1915 g_free (mount_point->options);
1916 g_free (mount_point);
1920 * g_unix_mount_point_copy:
1921 * @mount_point: a #GUnixMountPoint.
1923 * Makes a copy of @mount_point.
1925 * Returns: (transfer full): a new #GUnixMountPoint
1927 * Since: 2.54
1929 GUnixMountPoint*
1930 g_unix_mount_point_copy (GUnixMountPoint *mount_point)
1932 GUnixMountPoint *copy;
1934 g_return_val_if_fail (mount_point != NULL, NULL);
1936 copy = g_new0 (GUnixMountPoint, 1);
1937 copy->mount_path = g_strdup (mount_point->mount_path);
1938 copy->device_path = g_strdup (mount_point->device_path);
1939 copy->filesystem_type = g_strdup (mount_point->filesystem_type);
1940 copy->options = g_strdup (mount_point->options);
1941 copy->is_read_only = mount_point->is_read_only;
1942 copy->is_user_mountable = mount_point->is_user_mountable;
1943 copy->is_loopback = mount_point->is_loopback;
1945 return copy;
1949 * g_unix_mount_compare:
1950 * @mount1: first #GUnixMountEntry to compare.
1951 * @mount2: second #GUnixMountEntry to compare.
1953 * Compares two unix mounts.
1955 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1956 * or less than @mount2, respectively.
1958 gint
1959 g_unix_mount_compare (GUnixMountEntry *mount1,
1960 GUnixMountEntry *mount2)
1962 int res;
1964 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1966 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1967 if (res != 0)
1968 return res;
1970 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1971 if (res != 0)
1972 return res;
1974 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1975 if (res != 0)
1976 return res;
1978 res = mount1->is_read_only - mount2->is_read_only;
1979 if (res != 0)
1980 return res;
1982 return 0;
1986 * g_unix_mount_get_mount_path:
1987 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1989 * Gets the mount path for a unix mount.
1991 * Returns: (type filename): the mount path for @mount_entry.
1993 const gchar *
1994 g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
1996 g_return_val_if_fail (mount_entry != NULL, NULL);
1998 return mount_entry->mount_path;
2002 * g_unix_mount_get_device_path:
2003 * @mount_entry: a #GUnixMount.
2005 * Gets the device path for a unix mount.
2007 * Returns: (type filename): a string containing the device path.
2009 const gchar *
2010 g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
2012 g_return_val_if_fail (mount_entry != NULL, NULL);
2014 return mount_entry->device_path;
2018 * g_unix_mount_get_fs_type:
2019 * @mount_entry: a #GUnixMount.
2021 * Gets the filesystem type for the unix mount.
2023 * Returns: a string containing the file system type.
2025 const gchar *
2026 g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
2028 g_return_val_if_fail (mount_entry != NULL, NULL);
2030 return mount_entry->filesystem_type;
2034 * g_unix_mount_is_readonly:
2035 * @mount_entry: a #GUnixMount.
2037 * Checks if a unix mount is mounted read only.
2039 * Returns: %TRUE if @mount_entry is read only.
2041 gboolean
2042 g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
2044 g_return_val_if_fail (mount_entry != NULL, FALSE);
2046 return mount_entry->is_read_only;
2050 * g_unix_mount_is_system_internal:
2051 * @mount_entry: a #GUnixMount.
2053 * Checks if a unix mount is a system path.
2055 * Returns: %TRUE if the unix mount is for a system path.
2057 gboolean
2058 g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
2060 g_return_val_if_fail (mount_entry != NULL, FALSE);
2062 return mount_entry->is_system_internal;
2065 /* GUnixMountPoint {{{1 */
2067 * g_unix_mount_point_compare:
2068 * @mount1: a #GUnixMount.
2069 * @mount2: a #GUnixMount.
2071 * Compares two unix mount points.
2073 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
2074 * or less than @mount2, respectively.
2076 gint
2077 g_unix_mount_point_compare (GUnixMountPoint *mount1,
2078 GUnixMountPoint *mount2)
2080 int res;
2082 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
2084 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
2085 if (res != 0)
2086 return res;
2088 res = g_strcmp0 (mount1->device_path, mount2->device_path);
2089 if (res != 0)
2090 return res;
2092 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
2093 if (res != 0)
2094 return res;
2096 res = g_strcmp0 (mount1->options, mount2->options);
2097 if (res != 0)
2098 return res;
2100 res = mount1->is_read_only - mount2->is_read_only;
2101 if (res != 0)
2102 return res;
2104 res = mount1->is_user_mountable - mount2->is_user_mountable;
2105 if (res != 0)
2106 return res;
2108 res = mount1->is_loopback - mount2->is_loopback;
2109 if (res != 0)
2110 return res;
2112 return 0;
2116 * g_unix_mount_point_get_mount_path:
2117 * @mount_point: a #GUnixMountPoint.
2119 * Gets the mount path for a unix mount point.
2121 * Returns: (type filename): a string containing the mount path.
2123 const gchar *
2124 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
2126 g_return_val_if_fail (mount_point != NULL, NULL);
2128 return mount_point->mount_path;
2132 * g_unix_mount_point_get_device_path:
2133 * @mount_point: a #GUnixMountPoint.
2135 * Gets the device path for a unix mount point.
2137 * Returns: (type filename): a string containing the device path.
2139 const gchar *
2140 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
2142 g_return_val_if_fail (mount_point != NULL, NULL);
2144 return mount_point->device_path;
2148 * g_unix_mount_point_get_fs_type:
2149 * @mount_point: a #GUnixMountPoint.
2151 * Gets the file system type for the mount point.
2153 * Returns: a string containing the file system type.
2155 const gchar *
2156 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
2158 g_return_val_if_fail (mount_point != NULL, NULL);
2160 return mount_point->filesystem_type;
2164 * g_unix_mount_point_get_options:
2165 * @mount_point: a #GUnixMountPoint.
2167 * Gets the options for the mount point.
2169 * Returns: a string containing the options.
2171 * Since: 2.32
2173 const gchar *
2174 g_unix_mount_point_get_options (GUnixMountPoint *mount_point)
2176 g_return_val_if_fail (mount_point != NULL, NULL);
2178 return mount_point->options;
2182 * g_unix_mount_point_is_readonly:
2183 * @mount_point: a #GUnixMountPoint.
2185 * Checks if a unix mount point is read only.
2187 * Returns: %TRUE if a mount point is read only.
2189 gboolean
2190 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
2192 g_return_val_if_fail (mount_point != NULL, FALSE);
2194 return mount_point->is_read_only;
2198 * g_unix_mount_point_is_user_mountable:
2199 * @mount_point: a #GUnixMountPoint.
2201 * Checks if a unix mount point is mountable by the user.
2203 * Returns: %TRUE if the mount point is user mountable.
2205 gboolean
2206 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
2208 g_return_val_if_fail (mount_point != NULL, FALSE);
2210 return mount_point->is_user_mountable;
2214 * g_unix_mount_point_is_loopback:
2215 * @mount_point: a #GUnixMountPoint.
2217 * Checks if a unix mount point is a loopback device.
2219 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
2221 gboolean
2222 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
2224 g_return_val_if_fail (mount_point != NULL, FALSE);
2226 return mount_point->is_loopback;
2229 static GUnixMountType
2230 guess_mount_type (const char *mount_path,
2231 const char *device_path,
2232 const char *filesystem_type)
2234 GUnixMountType type;
2235 char *basename;
2237 type = G_UNIX_MOUNT_TYPE_UNKNOWN;
2239 if ((strcmp (filesystem_type, "udf") == 0) ||
2240 (strcmp (filesystem_type, "iso9660") == 0) ||
2241 (strcmp (filesystem_type, "cd9660") == 0))
2242 type = G_UNIX_MOUNT_TYPE_CDROM;
2243 else if ((strcmp (filesystem_type, "nfs") == 0) ||
2244 (strcmp (filesystem_type, "nfs4") == 0))
2245 type = G_UNIX_MOUNT_TYPE_NFS;
2246 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
2247 g_str_has_prefix (device_path, "/dev/fd") ||
2248 g_str_has_prefix (device_path, "/dev/floppy"))
2249 type = G_UNIX_MOUNT_TYPE_FLOPPY;
2250 else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
2251 g_str_has_prefix (device_path, "/dev/acd") ||
2252 g_str_has_prefix (device_path, "/dev/cd"))
2253 type = G_UNIX_MOUNT_TYPE_CDROM;
2254 else if (g_str_has_prefix (device_path, "/vol/"))
2256 const char *name = mount_path + strlen ("/");
2258 if (g_str_has_prefix (name, "cdrom"))
2259 type = G_UNIX_MOUNT_TYPE_CDROM;
2260 else if (g_str_has_prefix (name, "floppy") ||
2261 g_str_has_prefix (device_path, "/vol/dev/diskette/"))
2262 type = G_UNIX_MOUNT_TYPE_FLOPPY;
2263 else if (g_str_has_prefix (name, "rmdisk"))
2264 type = G_UNIX_MOUNT_TYPE_ZIP;
2265 else if (g_str_has_prefix (name, "jaz"))
2266 type = G_UNIX_MOUNT_TYPE_JAZ;
2267 else if (g_str_has_prefix (name, "memstick"))
2268 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
2270 else
2272 basename = g_path_get_basename (mount_path);
2274 if (g_str_has_prefix (basename, "cdr") ||
2275 g_str_has_prefix (basename, "cdwriter") ||
2276 g_str_has_prefix (basename, "burn") ||
2277 g_str_has_prefix (basename, "dvdr"))
2278 type = G_UNIX_MOUNT_TYPE_CDROM;
2279 else if (g_str_has_prefix (basename, "floppy"))
2280 type = G_UNIX_MOUNT_TYPE_FLOPPY;
2281 else if (g_str_has_prefix (basename, "zip"))
2282 type = G_UNIX_MOUNT_TYPE_ZIP;
2283 else if (g_str_has_prefix (basename, "jaz"))
2284 type = G_UNIX_MOUNT_TYPE_JAZ;
2285 else if (g_str_has_prefix (basename, "camera"))
2286 type = G_UNIX_MOUNT_TYPE_CAMERA;
2287 else if (g_str_has_prefix (basename, "memstick") ||
2288 g_str_has_prefix (basename, "memory_stick") ||
2289 g_str_has_prefix (basename, "ram"))
2290 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
2291 else if (g_str_has_prefix (basename, "compact_flash"))
2292 type = G_UNIX_MOUNT_TYPE_CF;
2293 else if (g_str_has_prefix (basename, "smart_media"))
2294 type = G_UNIX_MOUNT_TYPE_SM;
2295 else if (g_str_has_prefix (basename, "sd_mmc"))
2296 type = G_UNIX_MOUNT_TYPE_SDMMC;
2297 else if (g_str_has_prefix (basename, "ipod"))
2298 type = G_UNIX_MOUNT_TYPE_IPOD;
2300 g_free (basename);
2303 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
2304 type = G_UNIX_MOUNT_TYPE_HD;
2306 return type;
2310 * g_unix_mount_guess_type:
2311 * @mount_entry: a #GUnixMount.
2313 * Guesses the type of a unix mount. If the mount type cannot be
2314 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
2316 * Returns: a #GUnixMountType.
2318 static GUnixMountType
2319 g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
2321 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2322 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2323 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2324 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2326 return guess_mount_type (mount_entry->mount_path,
2327 mount_entry->device_path,
2328 mount_entry->filesystem_type);
2332 * g_unix_mount_point_guess_type:
2333 * @mount_point: a #GUnixMountPoint.
2335 * Guesses the type of a unix mount point.
2336 * If the mount type cannot be determined,
2337 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
2339 * Returns: a #GUnixMountType.
2341 static GUnixMountType
2342 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
2344 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2345 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2346 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2347 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
2349 return guess_mount_type (mount_point->mount_path,
2350 mount_point->device_path,
2351 mount_point->filesystem_type);
2354 static const char *
2355 type_to_icon (GUnixMountType type, gboolean is_mount_point, gboolean use_symbolic)
2357 const char *icon_name;
2359 switch (type)
2361 case G_UNIX_MOUNT_TYPE_HD:
2362 if (is_mount_point)
2363 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2364 else
2365 icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
2366 break;
2367 case G_UNIX_MOUNT_TYPE_FLOPPY:
2368 case G_UNIX_MOUNT_TYPE_ZIP:
2369 case G_UNIX_MOUNT_TYPE_JAZ:
2370 if (is_mount_point)
2371 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2372 else
2373 icon_name = use_symbolic ? "media-removable-symbolic" : "media-floppy";
2374 break;
2375 case G_UNIX_MOUNT_TYPE_CDROM:
2376 if (is_mount_point)
2377 icon_name = use_symbolic ? "drive-optical-symbolic" : "drive-optical";
2378 else
2379 icon_name = use_symbolic ? "media-optical-symbolic" : "media-optical";
2380 break;
2381 case G_UNIX_MOUNT_TYPE_NFS:
2382 icon_name = use_symbolic ? "folder-remote-symbolic" : "folder-remote";
2383 break;
2384 case G_UNIX_MOUNT_TYPE_MEMSTICK:
2385 if (is_mount_point)
2386 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2387 else
2388 icon_name = use_symbolic ? "media-removable-symbolic" : "media-flash";
2389 break;
2390 case G_UNIX_MOUNT_TYPE_CAMERA:
2391 if (is_mount_point)
2392 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2393 else
2394 icon_name = use_symbolic ? "camera-photo-symbolic" : "camera-photo";
2395 break;
2396 case G_UNIX_MOUNT_TYPE_IPOD:
2397 if (is_mount_point)
2398 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2399 else
2400 icon_name = use_symbolic ? "multimedia-player-symbolic" : "multimedia-player";
2401 break;
2402 case G_UNIX_MOUNT_TYPE_UNKNOWN:
2403 default:
2404 if (is_mount_point)
2405 icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
2406 else
2407 icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
2408 break;
2411 return icon_name;
2415 * g_unix_mount_guess_name:
2416 * @mount_entry: a #GUnixMountEntry
2418 * Guesses the name of a Unix mount.
2419 * The result is a translated string.
2421 * Returns: A newly allocated string that must
2422 * be freed with g_free()
2424 gchar *
2425 g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
2427 char *name;
2429 if (strcmp (mount_entry->mount_path, "/") == 0)
2430 name = g_strdup (_("Filesystem root"));
2431 else
2432 name = g_filename_display_basename (mount_entry->mount_path);
2434 return name;
2438 * g_unix_mount_guess_icon:
2439 * @mount_entry: a #GUnixMountEntry
2441 * Guesses the icon of a Unix mount.
2443 * Returns: (transfer full): a #GIcon
2445 GIcon *
2446 g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
2448 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, FALSE));
2452 * g_unix_mount_guess_symbolic_icon:
2453 * @mount_entry: a #GUnixMountEntry
2455 * Guesses the symbolic icon of a Unix mount.
2457 * Returns: (transfer full): a #GIcon
2459 * Since: 2.34
2461 GIcon *
2462 g_unix_mount_guess_symbolic_icon (GUnixMountEntry *mount_entry)
2464 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, TRUE));
2468 * g_unix_mount_point_guess_name:
2469 * @mount_point: a #GUnixMountPoint
2471 * Guesses the name of a Unix mount point.
2472 * The result is a translated string.
2474 * Returns: A newly allocated string that must
2475 * be freed with g_free()
2477 gchar *
2478 g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
2480 char *name;
2482 if (strcmp (mount_point->mount_path, "/") == 0)
2483 name = g_strdup (_("Filesystem root"));
2484 else
2485 name = g_filename_display_basename (mount_point->mount_path);
2487 return name;
2491 * g_unix_mount_point_guess_icon:
2492 * @mount_point: a #GUnixMountPoint
2494 * Guesses the icon of a Unix mount point.
2496 * Returns: (transfer full): a #GIcon
2498 GIcon *
2499 g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
2501 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, FALSE));
2505 * g_unix_mount_point_guess_symbolic_icon:
2506 * @mount_point: a #GUnixMountPoint
2508 * Guesses the symbolic icon of a Unix mount point.
2510 * Returns: (transfer full): a #GIcon
2512 * Since: 2.34
2514 GIcon *
2515 g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount_point)
2517 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, TRUE));
2521 * g_unix_mount_guess_can_eject:
2522 * @mount_entry: a #GUnixMountEntry
2524 * Guesses whether a Unix mount can be ejected.
2526 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
2528 gboolean
2529 g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
2531 GUnixMountType guessed_type;
2533 guessed_type = g_unix_mount_guess_type (mount_entry);
2534 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2535 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2536 return TRUE;
2538 return FALSE;
2542 * g_unix_mount_guess_should_display:
2543 * @mount_entry: a #GUnixMountEntry
2545 * Guesses whether a Unix mount should be displayed in the UI.
2547 * Returns: %TRUE if @mount_entry is deemed to be displayable.
2549 gboolean
2550 g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
2552 const char *mount_path;
2553 const gchar *user_name;
2554 gsize user_name_len;
2556 /* Never display internal mountpoints */
2557 if (g_unix_mount_is_system_internal (mount_entry))
2558 return FALSE;
2560 /* Only display things in /media (which are generally user mountable)
2561 and home dir (fuse stuff) and /run/media/$USER */
2562 mount_path = mount_entry->mount_path;
2563 if (mount_path != NULL)
2565 gboolean is_in_runtime_dir = FALSE;
2566 /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
2567 if (g_strstr_len (mount_path, -1, "/.") != NULL)
2568 return FALSE;
2570 /* Check /run/media/$USER/ */
2571 user_name = g_get_user_name ();
2572 user_name_len = strlen (user_name);
2573 if (strncmp (mount_path, "/run/media/", sizeof ("/run/media/") - 1) == 0 &&
2574 strncmp (mount_path + sizeof ("/run/media/") - 1, user_name, user_name_len) == 0 &&
2575 mount_path[sizeof ("/run/media/") - 1 + user_name_len] == '/')
2576 is_in_runtime_dir = TRUE;
2578 if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/"))
2580 char *path;
2581 /* Avoid displaying mounts that are not accessible to the user.
2583 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
2584 * want to avoid g_access() for mount points which can potentially
2585 * block or fail stat()'ing, such as network mounts.
2587 path = g_path_get_dirname (mount_path);
2588 if (g_str_has_prefix (path, "/media/"))
2590 if (g_access (path, R_OK|X_OK) != 0)
2592 g_free (path);
2593 return FALSE;
2596 g_free (path);
2598 if (mount_entry->device_path && mount_entry->device_path[0] == '/')
2600 struct stat st;
2601 if (g_stat (mount_entry->device_path, &st) == 0 &&
2602 S_ISBLK(st.st_mode) &&
2603 g_access (mount_path, R_OK|X_OK) != 0)
2604 return FALSE;
2606 return TRUE;
2609 if (g_str_has_prefix (mount_path, g_get_home_dir ()) &&
2610 mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
2611 return TRUE;
2614 return FALSE;
2618 * g_unix_mount_point_guess_can_eject:
2619 * @mount_point: a #GUnixMountPoint
2621 * Guesses whether a Unix mount point can be ejected.
2623 * Returns: %TRUE if @mount_point is deemed to be ejectable.
2625 gboolean
2626 g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
2628 GUnixMountType guessed_type;
2630 guessed_type = g_unix_mount_point_guess_type (mount_point);
2631 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2632 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2633 return TRUE;
2635 return FALSE;
2638 /* Utility functions {{{1 */
2640 #ifdef HAVE_MNTENT_H
2641 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
2642 static void
2643 _canonicalize_filename (gchar *filename)
2645 gchar *p, *q;
2646 gboolean last_was_slash = FALSE;
2648 p = filename;
2649 q = filename;
2651 while (*p)
2653 if (*p == G_DIR_SEPARATOR)
2655 if (!last_was_slash)
2656 *q++ = G_DIR_SEPARATOR;
2658 last_was_slash = TRUE;
2660 else
2662 if (last_was_slash && *p == '.')
2664 if (*(p + 1) == G_DIR_SEPARATOR ||
2665 *(p + 1) == '\0')
2667 if (*(p + 1) == '\0')
2668 break;
2670 p += 1;
2672 else if (*(p + 1) == '.' &&
2673 (*(p + 2) == G_DIR_SEPARATOR ||
2674 *(p + 2) == '\0'))
2676 if (q > filename + 1)
2678 q--;
2679 while (q > filename + 1 &&
2680 *(q - 1) != G_DIR_SEPARATOR)
2681 q--;
2684 if (*(p + 2) == '\0')
2685 break;
2687 p += 2;
2689 else
2691 *q++ = *p;
2692 last_was_slash = FALSE;
2695 else
2697 *q++ = *p;
2698 last_was_slash = FALSE;
2702 p++;
2705 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
2706 q--;
2708 *q = '\0';
2711 static char *
2712 _resolve_symlink (const char *file)
2714 GError *error;
2715 char *dir;
2716 char *link;
2717 char *f;
2718 char *f1;
2720 f = g_strdup (file);
2722 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK))
2724 link = g_file_read_link (f, &error);
2725 if (link == NULL)
2727 g_error_free (error);
2728 g_free (f);
2729 f = NULL;
2730 goto out;
2733 dir = g_path_get_dirname (f);
2734 f1 = g_strdup_printf ("%s/%s", dir, link);
2735 g_free (dir);
2736 g_free (link);
2737 g_free (f);
2738 f = f1;
2741 out:
2742 if (f != NULL)
2743 _canonicalize_filename (f);
2744 return f;
2747 static const char *
2748 _resolve_dev_root (void)
2750 static gboolean have_real_dev_root = FALSE;
2751 static char real_dev_root[256];
2752 struct stat statbuf;
2754 /* see if it's cached already */
2755 if (have_real_dev_root)
2756 goto found;
2758 /* otherwise we're going to find it right away.. */
2759 have_real_dev_root = TRUE;
2761 if (stat ("/dev/root", &statbuf) == 0)
2763 if (! S_ISLNK (statbuf.st_mode))
2765 dev_t root_dev = statbuf.st_dev;
2766 FILE *f;
2768 /* see if device with similar major:minor as /dev/root is mention
2769 * in /etc/mtab (it usually is)
2771 f = fopen ("/etc/mtab", "r");
2772 if (f != NULL)
2774 struct mntent *entp;
2775 #ifdef HAVE_GETMNTENT_R
2776 struct mntent ent;
2777 char buf[1024];
2778 while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL)
2780 #else
2781 G_LOCK (getmntent);
2782 while ((entp = getmntent (f)) != NULL)
2784 #endif
2785 if (stat (entp->mnt_fsname, &statbuf) == 0 &&
2786 statbuf.st_dev == root_dev)
2788 strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
2789 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2790 fclose (f);
2791 goto found;
2795 endmntent (f);
2797 #ifndef HAVE_GETMNTENT_R
2798 G_UNLOCK (getmntent);
2799 #endif
2802 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2805 else
2807 char *resolved;
2808 resolved = _resolve_symlink ("/dev/root");
2809 if (resolved != NULL)
2811 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
2812 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2813 g_free (resolved);
2814 goto found;
2819 /* bah sucks.. */
2820 strcpy (real_dev_root, "/dev/root");
2822 found:
2823 return real_dev_root;
2825 #endif
2827 /* Epilogue {{{1 */
2828 /* vim:set foldmethod=marker: */