Avoid getmntinfo
[glib.git] / gio / gunixmounts.c
blob931bbb9e978d89dc5ca98b4988de868f3048d815
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 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
22 * Author: Alexander Larsson <alexl@redhat.com>
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 #ifdef HAVE_SYS_POLL_H
35 #include <sys/poll.h>
36 #endif
37 #endif
38 #ifdef HAVE_POLL_H
39 #include <poll.h>
40 #endif
41 #include <stdio.h>
42 #include <unistd.h>
43 #include <sys/time.h>
44 #include <errno.h>
45 #include <string.h>
46 #include <signal.h>
47 #include <gstdio.h>
48 #include <dirent.h>
50 #if HAVE_SYS_STATFS_H
51 #include <sys/statfs.h>
52 #endif
53 #if HAVE_SYS_STATVFS_H
54 #include <sys/statvfs.h>
55 #endif
56 #if HAVE_SYS_VFS_H
57 #include <sys/vfs.h>
58 #elif HAVE_SYS_MOUNT_H
59 #if HAVE_SYS_PARAM_H
60 #include <sys/param.h>
61 #endif
62 #include <sys/mount.h>
63 #endif
65 #ifndef O_BINARY
66 #define O_BINARY 0
67 #endif
69 #include "gunixmounts.h"
70 #include "gfile.h"
71 #include "gfilemonitor.h"
72 #include "glibintl.h"
73 #include "gthemedicon.h"
76 #ifdef HAVE_MNTENT_H
77 static const char *_resolve_dev_root (void);
78 #endif
80 /**
81 * SECTION:gunixmounts
82 * @include: gio/gunixmounts.h
83 * @short_description: UNIX mounts
85 * Routines for managing mounted UNIX mount points and paths.
87 * Note that <filename>&lt;gio/gunixmounts.h&gt;</filename> belongs to the
88 * UNIX-specific GIO interfaces, thus you have to use the
89 * <filename>gio-unix-2.0.pc</filename> pkg-config file when using it.
93 * GUnixMountType:
94 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
95 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
96 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
97 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
98 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
99 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
100 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
101 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
102 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
103 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
104 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
105 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
106 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
108 * Types of UNIX mounts.
110 typedef enum {
111 G_UNIX_MOUNT_TYPE_UNKNOWN,
112 G_UNIX_MOUNT_TYPE_FLOPPY,
113 G_UNIX_MOUNT_TYPE_CDROM,
114 G_UNIX_MOUNT_TYPE_NFS,
115 G_UNIX_MOUNT_TYPE_ZIP,
116 G_UNIX_MOUNT_TYPE_JAZ,
117 G_UNIX_MOUNT_TYPE_MEMSTICK,
118 G_UNIX_MOUNT_TYPE_CF,
119 G_UNIX_MOUNT_TYPE_SM,
120 G_UNIX_MOUNT_TYPE_SDMMC,
121 G_UNIX_MOUNT_TYPE_IPOD,
122 G_UNIX_MOUNT_TYPE_CAMERA,
123 G_UNIX_MOUNT_TYPE_HD
124 } GUnixMountType;
126 struct _GUnixMountEntry {
127 char *mount_path;
128 char *device_path;
129 char *filesystem_type;
130 gboolean is_read_only;
131 gboolean is_system_internal;
134 struct _GUnixMountPoint {
135 char *mount_path;
136 char *device_path;
137 char *filesystem_type;
138 gboolean is_read_only;
139 gboolean is_user_mountable;
140 gboolean is_loopback;
143 enum {
144 MOUNTS_CHANGED,
145 MOUNTPOINTS_CHANGED,
146 LAST_SIGNAL
149 static guint signals[LAST_SIGNAL];
151 struct _GUnixMountMonitor {
152 GObject parent;
154 GFileMonitor *fstab_monitor;
155 GFileMonitor *mtab_monitor;
158 struct _GUnixMountMonitorClass {
159 GObjectClass parent_class;
162 static GUnixMountMonitor *the_mount_monitor = NULL;
164 static GList *_g_get_unix_mounts (void);
165 static GList *_g_get_unix_mount_points (void);
167 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT);
169 #define MOUNT_POLL_INTERVAL 4000
171 #ifdef HAVE_SYS_MNTTAB_H
172 #define MNTOPT_RO "ro"
173 #endif
175 #ifdef HAVE_MNTENT_H
176 #include <mntent.h>
177 #elif defined (HAVE_SYS_MNTTAB_H)
178 #include <sys/mnttab.h>
179 #endif
181 #ifdef HAVE_SYS_VFSTAB_H
182 #include <sys/vfstab.h>
183 #endif
185 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
186 #include <sys/mntctl.h>
187 #include <sys/vfs.h>
188 #include <sys/vmount.h>
189 #include <fshelp.h>
190 #endif
192 #if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
193 #include <sys/ucred.h>
194 #include <sys/mount.h>
195 #include <fstab.h>
196 #ifdef HAVE_SYS_SYSCTL_H
197 #include <sys/sysctl.h>
198 #endif
199 #endif
201 #ifndef HAVE_SETMNTENT
202 #define setmntent(f,m) fopen(f,m)
203 #endif
204 #ifndef HAVE_ENDMNTENT
205 #define endmntent(f) fclose(f)
206 #endif
208 static gboolean
209 is_in (const char *value, const char *set[])
211 int i;
212 for (i = 0; set[i] != NULL; i++)
214 if (strcmp (set[i], value) == 0)
215 return TRUE;
217 return FALSE;
221 * g_unix_is_mount_path_system_internal:
222 * @mount_path: a mount path, e.g. <filename>/media/disk</filename>
223 * or <filename>/usr</filename>
225 * Determines if @mount_path is considered an implementation of the
226 * OS. This is primarily used for hiding mountable and mounted volumes
227 * that only are used in the OS and has little to no relevance to the
228 * casual user.
230 * Returns: %TRUE if @mount_path is considered an implementation detail
231 * of the OS.
233 gboolean
234 g_unix_is_mount_path_system_internal (const char *mount_path)
236 const char *ignore_mountpoints[] = {
237 /* Includes all FHS 2.3 toplevel dirs and other specilized
238 * directories that we want to hide from the user.
240 "/", /* we already have "Filesystem root" in Nautilus */
241 "/bin",
242 "/boot",
243 "/dev",
244 "/etc",
245 "/home",
246 "/lib",
247 "/lib64",
248 "/live/cow",
249 "/live/image",
250 "/media",
251 "/mnt",
252 "/opt",
253 "/root",
254 "/sbin",
255 "/srv",
256 "/tmp",
257 "/usr",
258 "/usr/local",
259 "/var",
260 "/var/crash",
261 "/var/local",
262 "/var/log",
263 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
264 "/var/mail",
265 "/var/run",
266 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
267 "/proc",
268 "/sbin",
269 "/net",
270 "/sys",
271 NULL
274 if (is_in (mount_path, ignore_mountpoints))
275 return TRUE;
277 if (g_str_has_prefix (mount_path, "/dev/") ||
278 g_str_has_prefix (mount_path, "/proc/") ||
279 g_str_has_prefix (mount_path, "/sys/"))
280 return TRUE;
282 if (g_str_has_suffix (mount_path, "/.gvfs"))
283 return TRUE;
285 return FALSE;
288 static gboolean
289 guess_system_internal (const char *mountpoint,
290 const char *fs,
291 const char *device)
293 const char *ignore_fs[] = {
294 "auto",
295 "autofs",
296 "devfs",
297 "devpts",
298 "ecryptfs",
299 "kernfs",
300 "linprocfs",
301 "proc",
302 "procfs",
303 "ptyfs",
304 "rootfs",
305 "selinuxfs",
306 "sysfs",
307 "tmpfs",
308 "usbfs",
309 "nfsd",
310 "rpc_pipefs",
311 "zfs",
312 NULL
314 const char *ignore_devices[] = {
315 "none",
316 "sunrpc",
317 "devpts",
318 "nfsd",
319 "/dev/loop",
320 "/dev/vn",
321 NULL
324 if (is_in (fs, ignore_fs))
325 return TRUE;
327 if (is_in (device, ignore_devices))
328 return TRUE;
330 if (g_unix_is_mount_path_system_internal (mountpoint))
331 return TRUE;
333 return FALSE;
336 #ifdef HAVE_MNTENT_H
338 static char *
339 get_mtab_read_file (void)
341 #ifdef _PATH_MOUNTED
342 # ifdef __linux__
343 return "/proc/mounts";
344 # else
345 return _PATH_MOUNTED;
346 # endif
347 #else
348 return "/etc/mtab";
349 #endif
352 static char *
353 get_mtab_monitor_file (void)
355 #ifdef _PATH_MOUNTED
356 return _PATH_MOUNTED;
357 #else
358 return "/etc/mtab";
359 #endif
362 #ifndef HAVE_GETMNTENT_R
363 G_LOCK_DEFINE_STATIC(getmntent);
364 #endif
366 static GList *
367 _g_get_unix_mounts (void)
369 #ifdef HAVE_GETMNTENT_R
370 struct mntent ent;
371 char buf[1024];
372 #endif
373 struct mntent *mntent;
374 FILE *file;
375 char *read_file;
376 GUnixMountEntry *mount_entry;
377 GHashTable *mounts_hash;
378 GList *return_list;
380 read_file = get_mtab_read_file ();
382 file = setmntent (read_file, "r");
383 if (file == NULL)
384 return NULL;
386 return_list = NULL;
388 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
390 #ifdef HAVE_GETMNTENT_R
391 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
392 #else
393 G_LOCK (getmntent);
394 while ((mntent = getmntent (file)) != NULL)
395 #endif
397 /* ignore any mnt_fsname that is repeated and begins with a '/'
399 * We do this to avoid being fooled by --bind mounts, since
400 * these have the same device as the location they bind to.
401 * It's not an ideal solution to the problem, but it's likely that
402 * the most important mountpoint is first and the --bind ones after
403 * that aren't as important. So it should work.
405 * The '/' is to handle procfs, tmpfs and other no device mounts.
407 if (mntent->mnt_fsname != NULL &&
408 mntent->mnt_fsname[0] == '/' &&
409 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
410 continue;
412 mount_entry = g_new0 (GUnixMountEntry, 1);
413 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
414 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
415 mount_entry->device_path = g_strdup (_resolve_dev_root ());
416 else
417 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
418 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
420 #if defined (HAVE_HASMNTOPT)
421 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
422 mount_entry->is_read_only = TRUE;
423 #endif
425 mount_entry->is_system_internal =
426 guess_system_internal (mount_entry->mount_path,
427 mount_entry->filesystem_type,
428 mount_entry->device_path);
430 g_hash_table_insert (mounts_hash,
431 mount_entry->device_path,
432 mount_entry->device_path);
434 return_list = g_list_prepend (return_list, mount_entry);
436 g_hash_table_destroy (mounts_hash);
438 endmntent (file);
440 #ifndef HAVE_GETMNTENT_R
441 G_UNLOCK (getmntent);
442 #endif
444 return g_list_reverse (return_list);
447 #elif defined (HAVE_SYS_MNTTAB_H)
449 G_LOCK_DEFINE_STATIC(getmntent);
451 static char *
452 get_mtab_read_file (void)
454 #ifdef _PATH_MOUNTED
455 return _PATH_MOUNTED;
456 #else
457 return "/etc/mnttab";
458 #endif
461 static char *
462 get_mtab_monitor_file (void)
464 return get_mtab_read_file ();
467 static GList *
468 _g_get_unix_mounts (void)
470 struct mnttab mntent;
471 FILE *file;
472 char *read_file;
473 GUnixMountEntry *mount_entry;
474 GList *return_list;
476 read_file = get_mtab_read_file ();
478 file = setmntent (read_file, "r");
479 if (file == NULL)
480 return NULL;
482 return_list = NULL;
484 G_LOCK (getmntent);
485 while (! getmntent (file, &mntent))
487 mount_entry = g_new0 (GUnixMountEntry, 1);
489 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
490 mount_entry->device_path = g_strdup (mntent.mnt_special);
491 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
493 #if defined (HAVE_HASMNTOPT)
494 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
495 mount_entry->is_read_only = TRUE;
496 #endif
498 mount_entry->is_system_internal =
499 guess_system_internal (mount_entry->mount_path,
500 mount_entry->filesystem_type,
501 mount_entry->device_path);
503 return_list = g_list_prepend (return_list, mount_entry);
506 endmntent (file);
508 G_UNLOCK (getmntent);
510 return g_list_reverse (return_list);
513 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
515 static char *
516 get_mtab_monitor_file (void)
518 return NULL;
521 static GList *
522 _g_get_unix_mounts (void)
524 struct vfs_ent *fs_info;
525 struct vmount *vmount_info;
526 int vmount_number;
527 unsigned int vmount_size;
528 int current;
529 GList *return_list;
531 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
533 g_warning ("Unable to know the number of mounted volumes\n");
535 return NULL;
538 vmount_info = (struct vmount*)g_malloc (vmount_size);
540 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
542 if (vmount_info->vmt_revision != VMT_REVISION)
543 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
545 if (vmount_number < 0)
547 g_warning ("Unable to recover mounted volumes information\n");
549 g_free (vmount_info);
550 return NULL;
553 return_list = NULL;
554 while (vmount_number > 0)
556 mount_entry = g_new0 (GUnixMountEntry, 1);
558 mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT));
559 mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB));
560 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
561 mount_entry->is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
563 fs_info = getvfsbytype (vmount_info->vmt_gfstype);
565 if (fs_info == NULL)
566 mount_entry->filesystem_type = g_strdup ("unknown");
567 else
568 mount_entry->filesystem_type = g_strdup (fs_info->vfsent_name);
570 mount_entry->is_system_internal =
571 guess_system_internal (mount_entry->mount_path,
572 mount_entry->filesystem_type,
573 mount_entry->device_path);
575 return_list = g_list_prepend (return_list, mount_entry);
577 vmount_info = (struct vmount *)( (char*)vmount_info
578 + vmount_info->vmt_length);
579 vmount_number--;
582 g_free (vmount_info);
584 return g_list_reverse (return_list);
587 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
589 static char *
590 get_mtab_monitor_file (void)
592 return NULL;
595 static GList *
596 _g_get_unix_mounts (void)
598 #if defined(HAVE_GETVFSSTAT)
599 struct statvfs *mntent = NULL;
600 #elif defined(HAVE_GETFSSTAT)
601 struct statfs *mntent = NULL;
602 #else
603 #error statfs juggling failed
604 #endif
605 size_t bufsize;
606 int num_mounts, i;
607 GUnixMountEntry *mount_entry;
608 GList *return_list;
610 /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
611 #if defined(HAVE_GETVFSSTAT)
612 num_mounts = getvfsstat (NULL, 0, ST_NOWAIT);
613 #elif defined(HAVE_GETFSSTAT)
614 num_mounts = getfsstat (NULL, 0, MNT_NOWAIT);
615 #endif
616 if (num_mounts == -1)
617 return NULL;
619 bufsize = num_mounts * sizeof (*mntent);
620 mntent = g_malloc (bufsize);
621 #if defined(HAVE_GETVFSSTAT)
622 num_mounts = getvfsstat (mntent, bufsize, ST_NOWAIT);
623 #elif defined(HAVE_GETFSSTAT)
624 num_mounts = getfsstat (mntent, bufsize, MNT_NOWAIT);
625 #endif
626 if (num_mounts == -1)
627 return NULL;
629 return_list = NULL;
631 for (i = 0; i < num_mounts; i++)
633 mount_entry = g_new0 (GUnixMountEntry, 1);
635 mount_entry->mount_path = g_strdup (mntent[i].f_mntonname);
636 mount_entry->device_path = g_strdup (mntent[i].f_mntfromname);
637 mount_entry->filesystem_type = g_strdup (mntent[i].f_fstypename);
638 #if defined(HAVE_GETVFSSTAT)
639 if (mntent[i].f_flag & ST_RDONLY)
640 #elif defined(HAVE_GETFSSTAT)
641 if (mntent[i].f_flags & MNT_RDONLY)
642 #endif
643 mount_entry->is_read_only = TRUE;
645 mount_entry->is_system_internal =
646 guess_system_internal (mount_entry->mount_path,
647 mount_entry->filesystem_type,
648 mount_entry->device_path);
650 return_list = g_list_prepend (return_list, mount_entry);
653 g_free (mntent);
655 return g_list_reverse (return_list);
657 #elif defined(__INTERIX)
659 static char *
660 get_mtab_monitor_file (void)
662 return NULL;
665 static GList *
666 _g_get_unix_mounts (void)
668 DIR *dirp;
669 GList* return_list = NULL;
670 char filename[9 + NAME_MAX];
672 dirp = opendir ("/dev/fs");
673 if (!dirp)
675 g_warning ("unable to read /dev/fs!");
676 return NULL;
679 while (1)
681 struct statvfs statbuf;
682 struct dirent entry;
683 struct dirent* result;
685 if (readdir_r (dirp, &entry, &result) || result == NULL)
686 break;
688 strcpy (filename, "/dev/fs/");
689 strcat (filename, entry.d_name);
691 if (statvfs (filename, &statbuf) == 0)
693 GUnixMountEntry* mount_entry = g_new0(GUnixMountEntry, 1);
695 mount_entry->mount_path = g_strdup (statbuf.f_mntonname);
696 mount_entry->device_path = g_strdup (statbuf.f_mntfromname);
697 mount_entry->filesystem_type = g_strdup (statbuf.f_fstypename);
699 if (statbuf.f_flag & ST_RDONLY)
700 mount_entry->is_read_only = TRUE;
702 return_list = g_list_prepend(return_list, mount_entry);
706 return_list = g_list_reverse (return_list);
708 closedir (dirp);
710 return return_list;
712 #else
713 #error No _g_get_unix_mounts() implementation for system
714 #endif
716 /* _g_get_unix_mount_points():
717 * read the fstab.
718 * don't return swap and ignore mounts.
721 static char *
722 get_fstab_file (void)
724 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
725 /* AIX */
726 return "/etc/filesystems";
727 #elif defined(_PATH_MNTTAB)
728 return _PATH_MNTTAB;
729 #elif defined(VFSTAB)
730 return VFSTAB;
731 #else
732 return "/etc/fstab";
733 #endif
736 #ifdef HAVE_MNTENT_H
737 static GList *
738 _g_get_unix_mount_points (void)
740 #ifdef HAVE_GETMNTENT_R
741 struct mntent ent;
742 char buf[1024];
743 #endif
744 struct mntent *mntent;
745 FILE *file;
746 char *read_file;
747 GUnixMountPoint *mount_entry;
748 GList *return_list;
750 read_file = get_fstab_file ();
752 file = setmntent (read_file, "r");
753 if (file == NULL)
754 return NULL;
756 return_list = NULL;
758 #ifdef HAVE_GETMNTENT_R
759 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
760 #else
761 G_LOCK (getmntent);
762 while ((mntent = getmntent (file)) != NULL)
763 #endif
765 if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
766 (strcmp (mntent->mnt_dir, "swap") == 0))
767 continue;
769 mount_entry = g_new0 (GUnixMountPoint, 1);
770 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
771 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
772 mount_entry->device_path = g_strdup (_resolve_dev_root ());
773 else
774 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
775 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
777 #ifdef HAVE_HASMNTOPT
778 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
779 mount_entry->is_read_only = TRUE;
781 if (hasmntopt (mntent, "loop") != NULL)
782 mount_entry->is_loopback = TRUE;
784 #endif
786 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
787 #ifdef HAVE_HASMNTOPT
788 || (hasmntopt (mntent, "user") != NULL
789 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
790 || hasmntopt (mntent, "pamconsole") != NULL
791 || hasmntopt (mntent, "users") != NULL
792 || hasmntopt (mntent, "owner") != NULL
793 #endif
795 mount_entry->is_user_mountable = TRUE;
797 return_list = g_list_prepend (return_list, mount_entry);
800 endmntent (file);
802 #ifndef HAVE_GETMNTENT_R
803 G_UNLOCK (getmntent);
804 #endif
806 return g_list_reverse (return_list);
809 #elif defined (HAVE_SYS_MNTTAB_H)
811 static GList *
812 _g_get_unix_mount_points (void)
814 struct mnttab mntent;
815 FILE *file;
816 char *read_file;
817 GUnixMountPoint *mount_entry;
818 GList *return_list;
820 read_file = get_fstab_file ();
822 file = setmntent (read_file, "r");
823 if (file == NULL)
824 return NULL;
826 return_list = NULL;
828 G_LOCK (getmntent);
829 while (! getmntent (file, &mntent))
831 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
832 (strcmp (mntent.mnt_mountp, "swap") == 0))
833 continue;
835 mount_entry = g_new0 (GUnixMountPoint, 1);
837 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
838 mount_entry->device_path = g_strdup (mntent.mnt_special);
839 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
841 #ifdef HAVE_HASMNTOPT
842 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
843 mount_entry->is_read_only = TRUE;
845 if (hasmntopt (&mntent, "lofs") != NULL)
846 mount_entry->is_loopback = TRUE;
847 #endif
849 if ((mntent.mnt_fstype != NULL)
850 #ifdef HAVE_HASMNTOPT
851 || (hasmntopt (&mntent, "user") != NULL
852 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
853 || hasmntopt (&mntent, "pamconsole") != NULL
854 || hasmntopt (&mntent, "users") != NULL
855 || hasmntopt (&mntent, "owner") != NULL
856 #endif
858 mount_entry->is_user_mountable = TRUE;
860 return_list = g_list_prepend (return_list, mount_entry);
863 endmntent (file);
864 G_UNLOCK (getmntent);
866 return g_list_reverse (return_list);
868 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
870 /* functions to parse /etc/filesystems on aix */
872 /* read character, ignoring comments (begin with '*', end with '\n' */
873 static int
874 aix_fs_getc (FILE *fd)
876 int c;
878 while ((c = getc (fd)) == '*')
880 while (((c = getc (fd)) != '\n') && (c != EOF))
885 /* eat all continuous spaces in a file */
886 static int
887 aix_fs_ignorespace (FILE *fd)
889 int c;
891 while ((c = aix_fs_getc (fd)) != EOF)
893 if (!g_ascii_isspace (c))
895 ungetc (c,fd);
896 return c;
900 return EOF;
903 /* read one word from file */
904 static int
905 aix_fs_getword (FILE *fd,
906 char *word)
908 int c;
910 aix_fs_ignorespace (fd);
912 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
914 if (c == '"')
916 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
917 *word++ = c;
918 else
919 *word++ = c;
922 *word = 0;
924 return c;
927 typedef struct {
928 char mnt_mount[PATH_MAX];
929 char mnt_special[PATH_MAX];
930 char mnt_fstype[16];
931 char mnt_options[128];
932 } AixMountTableEntry;
934 /* read mount points properties */
935 static int
936 aix_fs_get (FILE *fd,
937 AixMountTableEntry *prop)
939 static char word[PATH_MAX] = { 0 };
940 char value[PATH_MAX];
942 /* read stanza */
943 if (word[0] == 0)
945 if (aix_fs_getword (fd, word) == EOF)
946 return EOF;
949 word[strlen(word) - 1] = 0;
950 strcpy (prop->mnt_mount, word);
952 /* read attributes and value */
954 while (aix_fs_getword (fd, word) != EOF)
956 /* test if is attribute or new stanza */
957 if (word[strlen(word) - 1] == ':')
958 return 0;
960 /* read "=" */
961 aix_fs_getword (fd, value);
963 /* read value */
964 aix_fs_getword (fd, value);
966 if (strcmp (word, "dev") == 0)
967 strcpy (prop->mnt_special, value);
968 else if (strcmp (word, "vfs") == 0)
969 strcpy (prop->mnt_fstype, value);
970 else if (strcmp (word, "options") == 0)
971 strcpy(prop->mnt_options, value);
974 return 0;
977 static GList *
978 _g_get_unix_mount_points (void)
980 struct mntent *mntent;
981 FILE *file;
982 char *read_file;
983 GUnixMountPoint *mount_entry;
984 AixMountTableEntry mntent;
985 GList *return_list;
987 read_file = get_fstab_file ();
989 file = setmntent (read_file, "r");
990 if (file == NULL)
991 return NULL;
993 return_list = NULL;
995 while (!aix_fs_get (file, &mntent))
997 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
999 mount_entry = g_new0 (GUnixMountPoint, 1);
1001 mount_entry->mount_path = g_strdup (mntent.mnt_mount);
1002 mount_entry->device_path = g_strdup (mntent.mnt_special);
1003 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
1004 mount_entry->is_read_only = TRUE;
1005 mount_entry->is_user_mountable = TRUE;
1007 return_list = g_list_prepend (return_list, mount_entry);
1011 endmntent (file);
1013 return g_list_reverse (return_list);
1016 #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
1018 static GList *
1019 _g_get_unix_mount_points (void)
1021 struct fstab *fstab = NULL;
1022 GUnixMountPoint *mount_entry;
1023 GList *return_list;
1024 #ifdef HAVE_SYS_SYSCTL_H
1025 int usermnt = 0;
1026 struct stat sb;
1027 #endif
1029 if (!setfsent ())
1030 return NULL;
1032 return_list = NULL;
1034 #ifdef HAVE_SYS_SYSCTL_H
1035 #if defined(HAVE_SYSCTLBYNAME)
1036 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
1037 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
1039 int mib[2];
1041 mib[0] = CTL_VFS;
1042 mib[1] = VFS_USERMOUNT;
1043 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1045 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
1047 int mib[2];
1049 mib[0] = CTL_KERN;
1050 mib[1] = KERN_USERMOUNT;
1051 sysctl (mib, 2, &usermnt, &len, NULL, 0);
1053 #endif
1054 #endif
1056 while ((fstab = getfsent ()) != NULL)
1058 if (strcmp (fstab->fs_vfstype, "swap") == 0)
1059 continue;
1061 mount_entry = g_new0 (GUnixMountPoint, 1);
1063 mount_entry->mount_path = g_strdup (fstab->fs_file);
1064 mount_entry->device_path = g_strdup (fstab->fs_spec);
1065 mount_entry->filesystem_type = g_strdup (fstab->fs_vfstype);
1067 if (strcmp (fstab->fs_type, "ro") == 0)
1068 mount_entry->is_read_only = TRUE;
1070 #ifdef HAVE_SYS_SYSCTL_H
1071 if (usermnt != 0)
1073 uid_t uid = getuid ();
1074 if (stat (fstab->fs_file, &sb) == 0)
1076 if (uid == 0 || sb.st_uid == uid)
1077 mount_entry->is_user_mountable = TRUE;
1080 #endif
1082 return_list = g_list_prepend (return_list, mount_entry);
1085 endfsent ();
1087 return g_list_reverse (return_list);
1089 #elif defined(__INTERIX)
1090 static GList *
1091 _g_get_unix_mount_points (void)
1093 return _g_get_unix_mounts ();
1095 #else
1096 #error No g_get_mount_table() implementation for system
1097 #endif
1099 static guint64
1100 get_mounts_timestamp (void)
1102 const char *monitor_file;
1103 struct stat buf;
1105 monitor_file = get_mtab_monitor_file ();
1106 if (monitor_file)
1108 if (stat (monitor_file, &buf) == 0)
1109 return (guint64)buf.st_mtime;
1111 return 0;
1114 static guint64
1115 get_mount_points_timestamp (void)
1117 const char *monitor_file;
1118 struct stat buf;
1120 monitor_file = get_fstab_file ();
1121 if (monitor_file)
1123 if (stat (monitor_file, &buf) == 0)
1124 return (guint64)buf.st_mtime;
1126 return 0;
1130 * g_unix_mounts_get: (skip)
1131 * @time_read: (out) (allow-none): guint64 to contain a timestamp, or %NULL
1133 * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1134 * If @time_read is set, it will be filled with the mount
1135 * timestamp, allowing for checking if the mounts have changed
1136 * with g_unix_mounts_changed_since().
1138 * Returns: (element-type GUnixMountEntry) (transfer full):
1139 * a #GList of the UNIX mounts.
1141 GList *
1142 g_unix_mounts_get (guint64 *time_read)
1144 if (time_read)
1145 *time_read = get_mounts_timestamp ();
1147 return _g_get_unix_mounts ();
1151 * g_unix_mount_at: (skip)
1152 * @mount_path: path for a possible unix mount.
1153 * @time_read: (out) (allow-none): guint64 to contain a timestamp.
1155 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1156 * is set, it will be filled with a unix timestamp for checking
1157 * if the mounts have changed since with g_unix_mounts_changed_since().
1159 * Returns: (transfer full): a #GUnixMountEntry.
1161 GUnixMountEntry *
1162 g_unix_mount_at (const char *mount_path,
1163 guint64 *time_read)
1165 GList *mounts, *l;
1166 GUnixMountEntry *mount_entry, *found;
1168 mounts = g_unix_mounts_get (time_read);
1170 found = NULL;
1171 for (l = mounts; l != NULL; l = l->next)
1173 mount_entry = l->data;
1175 if (!found && strcmp (mount_path, mount_entry->mount_path) == 0)
1176 found = mount_entry;
1177 else
1178 g_unix_mount_free (mount_entry);
1180 g_list_free (mounts);
1182 return found;
1186 * g_unix_mount_points_get: (skip)
1187 * @time_read: (out) (allow-none): guint64 to contain a timestamp.
1189 * Gets a #GList of #GUnixMountPoint containing the unix mount points.
1190 * If @time_read is set, it will be filled with the mount timestamp,
1191 * allowing for checking if the mounts have changed with
1192 * g_unix_mount_points_changed_since().
1194 * Returns: (element-type GUnixMountPoint) (transfer full):
1195 * a #GList of the UNIX mountpoints.
1197 GList *
1198 g_unix_mount_points_get (guint64 *time_read)
1200 if (time_read)
1201 *time_read = get_mount_points_timestamp ();
1203 return _g_get_unix_mount_points ();
1207 * g_unix_mounts_changed_since:
1208 * @time: guint64 to contain a timestamp.
1210 * Checks if the unix mounts have changed since a given unix time.
1212 * Returns: %TRUE if the mounts have changed since @time.
1214 gboolean
1215 g_unix_mounts_changed_since (guint64 time)
1217 return get_mounts_timestamp () != time;
1221 * g_unix_mount_points_changed_since:
1222 * @time: guint64 to contain a timestamp.
1224 * Checks if the unix mount points have changed since a given unix time.
1226 * Returns: %TRUE if the mount points have changed since @time.
1228 gboolean
1229 g_unix_mount_points_changed_since (guint64 time)
1231 return get_mount_points_timestamp () != time;
1234 static void
1235 g_unix_mount_monitor_finalize (GObject *object)
1237 GUnixMountMonitor *monitor;
1239 monitor = G_UNIX_MOUNT_MONITOR (object);
1241 if (monitor->fstab_monitor)
1243 g_file_monitor_cancel (monitor->fstab_monitor);
1244 g_object_unref (monitor->fstab_monitor);
1247 if (monitor->mtab_monitor)
1249 g_file_monitor_cancel (monitor->mtab_monitor);
1250 g_object_unref (monitor->mtab_monitor);
1253 the_mount_monitor = NULL;
1255 G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
1259 static void
1260 g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
1262 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1264 gobject_class->finalize = g_unix_mount_monitor_finalize;
1267 * GUnixMountMonitor::mounts-changed:
1268 * @monitor: the object on which the signal is emitted
1270 * Emitted when the unix mounts have changed.
1272 signals[MOUNTS_CHANGED] =
1273 g_signal_new ("mounts-changed",
1274 G_TYPE_FROM_CLASS (klass),
1275 G_SIGNAL_RUN_LAST,
1277 NULL, NULL,
1278 g_cclosure_marshal_VOID__VOID,
1279 G_TYPE_NONE, 0);
1282 * GUnixMountMonitor::mountpoints-changed:
1283 * @monitor: the object on which the signal is emitted
1285 * Emitted when the unix mount points have changed.
1287 signals[MOUNTPOINTS_CHANGED] =
1288 g_signal_new ("mountpoints-changed",
1289 G_TYPE_FROM_CLASS (klass),
1290 G_SIGNAL_RUN_LAST,
1292 NULL, NULL,
1293 g_cclosure_marshal_VOID__VOID,
1294 G_TYPE_NONE, 0);
1297 static void
1298 fstab_file_changed (GFileMonitor *monitor,
1299 GFile *file,
1300 GFile *other_file,
1301 GFileMonitorEvent event_type,
1302 gpointer user_data)
1304 GUnixMountMonitor *mount_monitor;
1306 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1307 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1308 event_type != G_FILE_MONITOR_EVENT_DELETED)
1309 return;
1311 mount_monitor = user_data;
1312 g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0);
1315 static void
1316 mtab_file_changed (GFileMonitor *monitor,
1317 GFile *file,
1318 GFile *other_file,
1319 GFileMonitorEvent event_type,
1320 gpointer user_data)
1322 GUnixMountMonitor *mount_monitor;
1324 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1325 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1326 event_type != G_FILE_MONITOR_EVENT_DELETED)
1327 return;
1329 mount_monitor = user_data;
1330 g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
1333 static void
1334 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1336 GFile *file;
1338 if (get_fstab_file () != NULL)
1340 file = g_file_new_for_path (get_fstab_file ());
1341 monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1342 g_object_unref (file);
1344 g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor);
1347 if (get_mtab_monitor_file () != NULL)
1349 file = g_file_new_for_path (get_mtab_monitor_file ());
1350 monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1351 g_object_unref (file);
1353 g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor);
1358 * g_unix_mount_monitor_set_rate_limit:
1359 * @mount_monitor: a #GUnixMountMonitor
1360 * @limit_msec: a integer with the limit in milliseconds to
1361 * poll for changes.
1363 * Sets the rate limit to which the @mount_monitor will report
1364 * consecutive change events to the mount and mount point entry files.
1366 * Since: 2.18
1368 void
1369 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
1370 gint limit_msec)
1372 g_return_if_fail (G_IS_UNIX_MOUNT_MONITOR (mount_monitor));
1374 if (mount_monitor->fstab_monitor != NULL)
1375 g_file_monitor_set_rate_limit (mount_monitor->fstab_monitor, limit_msec);
1377 if (mount_monitor->mtab_monitor != NULL)
1378 g_file_monitor_set_rate_limit (mount_monitor->mtab_monitor, limit_msec);
1382 * g_unix_mount_monitor_new:
1384 * Gets a new #GUnixMountMonitor. The default rate limit for which the
1385 * monitor will report consecutive changes for the mount and mount
1386 * point entry files is the default for a #GFileMonitor. Use
1387 * g_unix_mount_monitor_set_rate_limit() to change this.
1389 * Returns: a #GUnixMountMonitor.
1391 GUnixMountMonitor *
1392 g_unix_mount_monitor_new (void)
1394 if (the_mount_monitor == NULL)
1396 the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL);
1397 return the_mount_monitor;
1400 return g_object_ref (the_mount_monitor);
1404 * g_unix_mount_free:
1405 * @mount_entry: a #GUnixMount.
1407 * Frees a unix mount.
1409 void
1410 g_unix_mount_free (GUnixMountEntry *mount_entry)
1412 g_return_if_fail (mount_entry != NULL);
1414 g_free (mount_entry->mount_path);
1415 g_free (mount_entry->device_path);
1416 g_free (mount_entry->filesystem_type);
1417 g_free (mount_entry);
1421 * g_unix_mount_point_free:
1422 * @mount_point: unix mount point to free.
1424 * Frees a unix mount point.
1426 void
1427 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1429 g_return_if_fail (mount_point != NULL);
1431 g_free (mount_point->mount_path);
1432 g_free (mount_point->device_path);
1433 g_free (mount_point->filesystem_type);
1434 g_free (mount_point);
1438 * g_unix_mount_compare:
1439 * @mount1: first #GUnixMountEntry to compare.
1440 * @mount2: second #GUnixMountEntry to compare.
1442 * Compares two unix mounts.
1444 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1445 * or less than @mount2, respectively.
1447 gint
1448 g_unix_mount_compare (GUnixMountEntry *mount1,
1449 GUnixMountEntry *mount2)
1451 int res;
1453 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1455 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1456 if (res != 0)
1457 return res;
1459 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1460 if (res != 0)
1461 return res;
1463 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1464 if (res != 0)
1465 return res;
1467 res = mount1->is_read_only - mount2->is_read_only;
1468 if (res != 0)
1469 return res;
1471 return 0;
1475 * g_unix_mount_get_mount_path:
1476 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1478 * Gets the mount path for a unix mount.
1480 * Returns: the mount path for @mount_entry.
1482 const gchar *
1483 g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
1485 g_return_val_if_fail (mount_entry != NULL, NULL);
1487 return mount_entry->mount_path;
1491 * g_unix_mount_get_device_path:
1492 * @mount_entry: a #GUnixMount.
1494 * Gets the device path for a unix mount.
1496 * Returns: a string containing the device path.
1498 const gchar *
1499 g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
1501 g_return_val_if_fail (mount_entry != NULL, NULL);
1503 return mount_entry->device_path;
1507 * g_unix_mount_get_fs_type:
1508 * @mount_entry: a #GUnixMount.
1510 * Gets the filesystem type for the unix mount.
1512 * Returns: a string containing the file system type.
1514 const gchar *
1515 g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
1517 g_return_val_if_fail (mount_entry != NULL, NULL);
1519 return mount_entry->filesystem_type;
1523 * g_unix_mount_is_readonly:
1524 * @mount_entry: a #GUnixMount.
1526 * Checks if a unix mount is mounted read only.
1528 * Returns: %TRUE if @mount_entry is read only.
1530 gboolean
1531 g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
1533 g_return_val_if_fail (mount_entry != NULL, FALSE);
1535 return mount_entry->is_read_only;
1539 * g_unix_mount_is_system_internal:
1540 * @mount_entry: a #GUnixMount.
1542 * Checks if a unix mount is a system path.
1544 * Returns: %TRUE if the unix mount is for a system path.
1546 gboolean
1547 g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
1549 g_return_val_if_fail (mount_entry != NULL, FALSE);
1551 return mount_entry->is_system_internal;
1555 * g_unix_mount_point_compare:
1556 * @mount1: a #GUnixMount.
1557 * @mount2: a #GUnixMount.
1559 * Compares two unix mount points.
1561 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1562 * or less than @mount2, respectively.
1564 gint
1565 g_unix_mount_point_compare (GUnixMountPoint *mount1,
1566 GUnixMountPoint *mount2)
1568 int res;
1570 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1572 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1573 if (res != 0)
1574 return res;
1576 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1577 if (res != 0)
1578 return res;
1580 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1581 if (res != 0)
1582 return res;
1584 res = mount1->is_read_only - mount2->is_read_only;
1585 if (res != 0)
1586 return res;
1588 res = mount1->is_user_mountable - mount2->is_user_mountable;
1589 if (res != 0)
1590 return res;
1592 res = mount1->is_loopback - mount2->is_loopback;
1593 if (res != 0)
1594 return res;
1596 return 0;
1600 * g_unix_mount_point_get_mount_path:
1601 * @mount_point: a #GUnixMountPoint.
1603 * Gets the mount path for a unix mount point.
1605 * Returns: a string containing the mount path.
1607 const gchar *
1608 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
1610 g_return_val_if_fail (mount_point != NULL, NULL);
1612 return mount_point->mount_path;
1616 * g_unix_mount_point_get_device_path:
1617 * @mount_point: a #GUnixMountPoint.
1619 * Gets the device path for a unix mount point.
1621 * Returns: a string containing the device path.
1623 const gchar *
1624 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
1626 g_return_val_if_fail (mount_point != NULL, NULL);
1628 return mount_point->device_path;
1632 * g_unix_mount_point_get_fs_type:
1633 * @mount_point: a #GUnixMountPoint.
1635 * Gets the file system type for the mount point.
1637 * Returns: a string containing the file system type.
1639 const gchar *
1640 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
1642 g_return_val_if_fail (mount_point != NULL, NULL);
1644 return mount_point->filesystem_type;
1648 * g_unix_mount_point_is_readonly:
1649 * @mount_point: a #GUnixMountPoint.
1651 * Checks if a unix mount point is read only.
1653 * Returns: %TRUE if a mount point is read only.
1655 gboolean
1656 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
1658 g_return_val_if_fail (mount_point != NULL, FALSE);
1660 return mount_point->is_read_only;
1664 * g_unix_mount_point_is_user_mountable:
1665 * @mount_point: a #GUnixMountPoint.
1667 * Checks if a unix mount point is mountable by the user.
1669 * Returns: %TRUE if the mount point is user mountable.
1671 gboolean
1672 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
1674 g_return_val_if_fail (mount_point != NULL, FALSE);
1676 return mount_point->is_user_mountable;
1680 * g_unix_mount_point_is_loopback:
1681 * @mount_point: a #GUnixMountPoint.
1683 * Checks if a unix mount point is a loopback device.
1685 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
1687 gboolean
1688 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
1690 g_return_val_if_fail (mount_point != NULL, FALSE);
1692 return mount_point->is_loopback;
1695 static GUnixMountType
1696 guess_mount_type (const char *mount_path,
1697 const char *device_path,
1698 const char *filesystem_type)
1700 GUnixMountType type;
1701 char *basename;
1703 type = G_UNIX_MOUNT_TYPE_UNKNOWN;
1705 if ((strcmp (filesystem_type, "udf") == 0) ||
1706 (strcmp (filesystem_type, "iso9660") == 0) ||
1707 (strcmp (filesystem_type, "cd9660") == 0))
1708 type = G_UNIX_MOUNT_TYPE_CDROM;
1709 else if ((strcmp (filesystem_type, "nfs") == 0) ||
1710 (strcmp (filesystem_type, "nfs4") == 0))
1711 type = G_UNIX_MOUNT_TYPE_NFS;
1712 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
1713 g_str_has_prefix (device_path, "/dev/fd") ||
1714 g_str_has_prefix (device_path, "/dev/floppy"))
1715 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1716 else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
1717 g_str_has_prefix (device_path, "/dev/acd") ||
1718 g_str_has_prefix (device_path, "/dev/cd"))
1719 type = G_UNIX_MOUNT_TYPE_CDROM;
1720 else if (g_str_has_prefix (device_path, "/vol/"))
1722 const char *name = mount_path + strlen ("/");
1724 if (g_str_has_prefix (name, "cdrom"))
1725 type = G_UNIX_MOUNT_TYPE_CDROM;
1726 else if (g_str_has_prefix (name, "floppy") ||
1727 g_str_has_prefix (device_path, "/vol/dev/diskette/"))
1728 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1729 else if (g_str_has_prefix (name, "rmdisk"))
1730 type = G_UNIX_MOUNT_TYPE_ZIP;
1731 else if (g_str_has_prefix (name, "jaz"))
1732 type = G_UNIX_MOUNT_TYPE_JAZ;
1733 else if (g_str_has_prefix (name, "memstick"))
1734 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1736 else
1738 basename = g_path_get_basename (mount_path);
1740 if (g_str_has_prefix (basename, "cdr") ||
1741 g_str_has_prefix (basename, "cdwriter") ||
1742 g_str_has_prefix (basename, "burn") ||
1743 g_str_has_prefix (basename, "dvdr"))
1744 type = G_UNIX_MOUNT_TYPE_CDROM;
1745 else if (g_str_has_prefix (basename, "floppy"))
1746 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1747 else if (g_str_has_prefix (basename, "zip"))
1748 type = G_UNIX_MOUNT_TYPE_ZIP;
1749 else if (g_str_has_prefix (basename, "jaz"))
1750 type = G_UNIX_MOUNT_TYPE_JAZ;
1751 else if (g_str_has_prefix (basename, "camera"))
1752 type = G_UNIX_MOUNT_TYPE_CAMERA;
1753 else if (g_str_has_prefix (basename, "memstick") ||
1754 g_str_has_prefix (basename, "memory_stick") ||
1755 g_str_has_prefix (basename, "ram"))
1756 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1757 else if (g_str_has_prefix (basename, "compact_flash"))
1758 type = G_UNIX_MOUNT_TYPE_CF;
1759 else if (g_str_has_prefix (basename, "smart_media"))
1760 type = G_UNIX_MOUNT_TYPE_SM;
1761 else if (g_str_has_prefix (basename, "sd_mmc"))
1762 type = G_UNIX_MOUNT_TYPE_SDMMC;
1763 else if (g_str_has_prefix (basename, "ipod"))
1764 type = G_UNIX_MOUNT_TYPE_IPOD;
1766 g_free (basename);
1769 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
1770 type = G_UNIX_MOUNT_TYPE_HD;
1772 return type;
1776 * g_unix_mount_guess_type:
1777 * @mount_entry: a #GUnixMount.
1779 * Guesses the type of a unix mount. If the mount type cannot be
1780 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1782 * Returns: a #GUnixMountType.
1784 static GUnixMountType
1785 g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
1787 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1788 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1789 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1790 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1792 return guess_mount_type (mount_entry->mount_path,
1793 mount_entry->device_path,
1794 mount_entry->filesystem_type);
1798 * g_unix_mount_point_guess_type:
1799 * @mount_point: a #GUnixMountPoint.
1801 * Guesses the type of a unix mount point.
1802 * If the mount type cannot be determined,
1803 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1805 * Returns: a #GUnixMountType.
1807 static GUnixMountType
1808 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
1810 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1811 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1812 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1813 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1815 return guess_mount_type (mount_point->mount_path,
1816 mount_point->device_path,
1817 mount_point->filesystem_type);
1820 static const char *
1821 type_to_icon (GUnixMountType type, gboolean is_mount_point)
1823 const char *icon_name;
1825 switch (type)
1827 case G_UNIX_MOUNT_TYPE_HD:
1828 if (is_mount_point)
1829 icon_name = "drive-removable-media";
1830 else
1831 icon_name = "drive-harddisk";
1832 break;
1833 case G_UNIX_MOUNT_TYPE_FLOPPY:
1834 case G_UNIX_MOUNT_TYPE_ZIP:
1835 case G_UNIX_MOUNT_TYPE_JAZ:
1836 if (is_mount_point)
1837 icon_name = "drive-removable-media";
1838 else
1839 icon_name = "media-floppy";
1840 break;
1841 case G_UNIX_MOUNT_TYPE_CDROM:
1842 if (is_mount_point)
1843 icon_name = "drive-optical";
1844 else
1845 icon_name = "media-optical";
1846 break;
1847 case G_UNIX_MOUNT_TYPE_NFS:
1848 /* TODO: Would like a better icon here... */
1849 if (is_mount_point)
1850 icon_name = "drive-removable-media";
1851 else
1852 icon_name = "drive-harddisk";
1853 break;
1854 case G_UNIX_MOUNT_TYPE_MEMSTICK:
1855 if (is_mount_point)
1856 icon_name = "drive-removable-media";
1857 else
1858 icon_name = "media-flash";
1859 break;
1860 case G_UNIX_MOUNT_TYPE_CAMERA:
1861 if (is_mount_point)
1862 icon_name = "drive-removable-media";
1863 else
1864 icon_name = "camera-photo";
1865 break;
1866 case G_UNIX_MOUNT_TYPE_IPOD:
1867 if (is_mount_point)
1868 icon_name = "drive-removable-media";
1869 else
1870 icon_name = "multimedia-player";
1871 break;
1872 case G_UNIX_MOUNT_TYPE_UNKNOWN:
1873 default:
1874 if (is_mount_point)
1875 icon_name = "drive-removable-media";
1876 else
1877 icon_name = "drive-harddisk";
1878 break;
1881 return icon_name;
1885 * g_unix_mount_guess_name:
1886 * @mount_entry: a #GUnixMountEntry
1888 * Guesses the name of a Unix mount.
1889 * The result is a translated string.
1891 * Returns: A newly allocated string that must
1892 * be freed with g_free()
1894 gchar *
1895 g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
1897 char *name;
1899 if (strcmp (mount_entry->mount_path, "/") == 0)
1900 name = g_strdup (_("Filesystem root"));
1901 else
1902 name = g_filename_display_basename (mount_entry->mount_path);
1904 return name;
1908 * g_unix_mount_guess_icon:
1909 * @mount_entry: a #GUnixMountEntry
1911 * Guesses the icon of a Unix mount.
1913 * Returns: (transfer full): a #GIcon
1915 GIcon *
1916 g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
1918 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE));
1922 * g_unix_mount_point_guess_name:
1923 * @mount_point: a #GUnixMountPoint
1925 * Guesses the name of a Unix mount point.
1926 * The result is a translated string.
1928 * Returns: A newly allocated string that must
1929 * be freed with g_free()
1931 gchar *
1932 g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
1934 char *name;
1936 if (strcmp (mount_point->mount_path, "/") == 0)
1937 name = g_strdup (_("Filesystem root"));
1938 else
1939 name = g_filename_display_basename (mount_point->mount_path);
1941 return name;
1945 * g_unix_mount_point_guess_icon:
1946 * @mount_point: a #GUnixMountPoint
1948 * Guesses the icon of a Unix mount point.
1950 * Returns: (transfer full): a #GIcon
1952 GIcon *
1953 g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
1955 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE));
1959 * g_unix_mount_guess_can_eject:
1960 * @mount_entry: a #GUnixMountEntry
1962 * Guesses whether a Unix mount can be ejected.
1964 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
1966 gboolean
1967 g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
1969 GUnixMountType guessed_type;
1971 guessed_type = g_unix_mount_guess_type (mount_entry);
1972 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
1973 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
1974 return TRUE;
1976 return FALSE;
1980 * g_unix_mount_guess_should_display:
1981 * @mount_entry: a #GUnixMountEntry
1983 * Guesses whether a Unix mount should be displayed in the UI.
1985 * Returns: %TRUE if @mount_entry is deemed to be displayable.
1987 gboolean
1988 g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
1990 const char *mount_path;
1992 /* Never display internal mountpoints */
1993 if (g_unix_mount_is_system_internal (mount_entry))
1994 return FALSE;
1996 /* Only display things in /media (which are generally user mountable)
1997 and home dir (fuse stuff) and $XDG_RUNTIME_DIR */
1998 mount_path = mount_entry->mount_path;
1999 if (mount_path != NULL)
2001 gboolean is_in_runtime_dir = FALSE;
2002 /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
2003 if (g_strstr_len (mount_path, -1, "/.") != NULL)
2004 return FALSE;
2006 if (g_getenv ("XDG_RUNTIME_DIR") != NULL && g_str_has_prefix (mount_path, g_get_user_runtime_dir ()))
2007 is_in_runtime_dir = TRUE;
2009 if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/"))
2011 char *path;
2012 /* Avoid displaying mounts that are not accessible to the user.
2014 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
2015 * want to avoid g_access() for mount points which can potentially
2016 * block or fail stat()'ing, such as network mounts.
2018 path = g_path_get_dirname (mount_path);
2019 if (g_str_has_prefix (path, "/media/"))
2021 if (g_access (path, R_OK|X_OK) != 0)
2023 g_free (path);
2024 return FALSE;
2027 g_free (path);
2029 if (mount_entry->device_path && mount_entry->device_path[0] == '/')
2031 struct stat st;
2032 if (g_stat (mount_entry->device_path, &st) == 0 &&
2033 S_ISBLK(st.st_mode) &&
2034 g_access (mount_path, R_OK|X_OK) != 0)
2035 return FALSE;
2037 return TRUE;
2040 if (g_str_has_prefix (mount_path, g_get_home_dir ()) &&
2041 mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
2042 return TRUE;
2045 return FALSE;
2049 * g_unix_mount_point_guess_can_eject:
2050 * @mount_point: a #GUnixMountPoint
2052 * Guesses whether a Unix mount point can be ejected.
2054 * Returns: %TRUE if @mount_point is deemed to be ejectable.
2056 gboolean
2057 g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
2059 GUnixMountType guessed_type;
2061 guessed_type = g_unix_mount_point_guess_type (mount_point);
2062 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
2063 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
2064 return TRUE;
2066 return FALSE;
2069 #ifdef HAVE_MNTENT_H
2070 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
2071 static void
2072 _canonicalize_filename (gchar *filename)
2074 gchar *p, *q;
2075 gboolean last_was_slash = FALSE;
2077 p = filename;
2078 q = filename;
2080 while (*p)
2082 if (*p == G_DIR_SEPARATOR)
2084 if (!last_was_slash)
2085 *q++ = G_DIR_SEPARATOR;
2087 last_was_slash = TRUE;
2089 else
2091 if (last_was_slash && *p == '.')
2093 if (*(p + 1) == G_DIR_SEPARATOR ||
2094 *(p + 1) == '\0')
2096 if (*(p + 1) == '\0')
2097 break;
2099 p += 1;
2101 else if (*(p + 1) == '.' &&
2102 (*(p + 2) == G_DIR_SEPARATOR ||
2103 *(p + 2) == '\0'))
2105 if (q > filename + 1)
2107 q--;
2108 while (q > filename + 1 &&
2109 *(q - 1) != G_DIR_SEPARATOR)
2110 q--;
2113 if (*(p + 2) == '\0')
2114 break;
2116 p += 2;
2118 else
2120 *q++ = *p;
2121 last_was_slash = FALSE;
2124 else
2126 *q++ = *p;
2127 last_was_slash = FALSE;
2131 p++;
2134 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
2135 q--;
2137 *q = '\0';
2140 static char *
2141 _resolve_symlink (const char *file)
2143 GError *error;
2144 char *dir;
2145 char *link;
2146 char *f;
2147 char *f1;
2149 f = g_strdup (file);
2151 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK))
2153 link = g_file_read_link (f, &error);
2154 if (link == NULL)
2156 g_error_free (error);
2157 g_free (f);
2158 f = NULL;
2159 goto out;
2162 dir = g_path_get_dirname (f);
2163 f1 = g_strdup_printf ("%s/%s", dir, link);
2164 g_free (dir);
2165 g_free (link);
2166 g_free (f);
2167 f = f1;
2170 out:
2171 if (f != NULL)
2172 _canonicalize_filename (f);
2173 return f;
2176 static const char *
2177 _resolve_dev_root (void)
2179 static gboolean have_real_dev_root = FALSE;
2180 static char real_dev_root[256];
2181 struct stat statbuf;
2183 /* see if it's cached already */
2184 if (have_real_dev_root)
2185 goto found;
2187 /* otherwise we're going to find it right away.. */
2188 have_real_dev_root = TRUE;
2190 if (stat ("/dev/root", &statbuf) == 0)
2192 if (! S_ISLNK (statbuf.st_mode))
2194 dev_t root_dev = statbuf.st_dev;
2195 FILE *f;
2196 char buf[1024];
2198 /* see if device with similar major:minor as /dev/root is mention
2199 * in /etc/mtab (it usually is)
2201 f = fopen ("/etc/mtab", "r");
2202 if (f != NULL)
2204 struct mntent *entp;
2205 #ifdef HAVE_GETMNTENT_R
2206 struct mntent ent;
2207 while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL)
2209 #else
2210 G_LOCK (getmntent);
2211 while ((entp = getmntent (f)) != NULL)
2213 #endif
2214 if (stat (entp->mnt_fsname, &statbuf) == 0 &&
2215 statbuf.st_dev == root_dev)
2217 strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
2218 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2219 fclose (f);
2220 goto found;
2224 endmntent (f);
2226 #ifndef HAVE_GETMNTENT_R
2227 G_UNLOCK (getmntent);
2228 #endif
2231 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2234 else
2236 char *resolved;
2237 resolved = _resolve_symlink ("/dev/root");
2238 if (resolved != NULL)
2240 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
2241 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2242 g_free (resolved);
2243 goto found;
2248 /* bah sucks.. */
2249 strcpy (real_dev_root, "/dev/root");
2251 found:
2252 return real_dev_root;
2254 #endif