Bug 561807 – inotify_sub.c :: dup_dirname() fails to remove trailing '/'
[glib.git] / gio / gunixmounts.c
blobab50b2e4c09a6da9b54434457457168d5c782c8c
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>
49 #include "gunixmounts.h"
50 #include "gfile.h"
51 #include "gfilemonitor.h"
52 #include "glibintl.h"
53 #include "gthemedicon.h"
55 #include "gioalias.h"
57 static const char *_resolve_dev_root (void);
59 /**
60 * SECTION:gunixmounts
61 * @include: gio/gunixmounts.h
62 * @short_description: Unix Mounts
64 * Routines for managing mounted UNIX mount points and paths.
66 **/
69 * GUnixMountType:
70 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
71 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
72 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
73 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
74 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
75 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
76 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
77 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
78 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
79 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
80 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
81 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
82 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
84 * Types of UNIX mounts.
85 **/
86 typedef enum {
87 G_UNIX_MOUNT_TYPE_UNKNOWN,
88 G_UNIX_MOUNT_TYPE_FLOPPY,
89 G_UNIX_MOUNT_TYPE_CDROM,
90 G_UNIX_MOUNT_TYPE_NFS,
91 G_UNIX_MOUNT_TYPE_ZIP,
92 G_UNIX_MOUNT_TYPE_JAZ,
93 G_UNIX_MOUNT_TYPE_MEMSTICK,
94 G_UNIX_MOUNT_TYPE_CF,
95 G_UNIX_MOUNT_TYPE_SM,
96 G_UNIX_MOUNT_TYPE_SDMMC,
97 G_UNIX_MOUNT_TYPE_IPOD,
98 G_UNIX_MOUNT_TYPE_CAMERA,
99 G_UNIX_MOUNT_TYPE_HD
100 } GUnixMountType;
102 struct _GUnixMountEntry {
103 char *mount_path;
104 char *device_path;
105 char *filesystem_type;
106 gboolean is_read_only;
107 gboolean is_system_internal;
110 struct _GUnixMountPoint {
111 char *mount_path;
112 char *device_path;
113 char *filesystem_type;
114 gboolean is_read_only;
115 gboolean is_user_mountable;
116 gboolean is_loopback;
119 enum {
120 MOUNTS_CHANGED,
121 MOUNTPOINTS_CHANGED,
122 LAST_SIGNAL
125 static guint signals[LAST_SIGNAL];
127 struct _GUnixMountMonitor {
128 GObject parent;
130 GFileMonitor *fstab_monitor;
131 GFileMonitor *mtab_monitor;
134 struct _GUnixMountMonitorClass {
135 GObjectClass parent_class;
138 static GUnixMountMonitor *the_mount_monitor = NULL;
140 static GList *_g_get_unix_mounts (void);
141 static GList *_g_get_unix_mount_points (void);
143 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT);
145 #define MOUNT_POLL_INTERVAL 4000
147 #ifdef HAVE_SYS_MNTTAB_H
148 #define MNTOPT_RO "ro"
149 #endif
151 #ifdef HAVE_MNTENT_H
152 #include <mntent.h>
153 #elif defined (HAVE_SYS_MNTTAB_H)
154 #include <sys/mnttab.h>
155 #endif
157 #ifdef HAVE_SYS_VFSTAB_H
158 #include <sys/vfstab.h>
159 #endif
161 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
162 #include <sys/mntctl.h>
163 #include <sys/vfs.h>
164 #include <sys/vmount.h>
165 #include <fshelp.h>
166 #endif
168 #if defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
169 #include <sys/ucred.h>
170 #include <sys/mount.h>
171 #include <fstab.h>
172 #ifdef HAVE_SYS_SYSCTL_H
173 #include <sys/sysctl.h>
174 #endif
175 #endif
177 #ifndef HAVE_SETMNTENT
178 #define setmntent(f,m) fopen(f,m)
179 #endif
180 #ifndef HAVE_ENDMNTENT
181 #define endmntent(f) fclose(f)
182 #endif
184 static gboolean
185 is_in (const char *value, const char *set[])
187 int i;
188 for (i = 0; set[i] != NULL; i++)
190 if (strcmp (set[i], value) == 0)
191 return TRUE;
193 return FALSE;
197 * g_unix_is_mount_path_system_internal:
198 * @mount_path: a mount path, e.g. <filename>/media/disk</filename>
199 * or <filename>/usr</filename>
201 * Determines if @mount_path is considered an implementation of the
202 * OS. This is primarily used for hiding mountable and mounted volumes
203 * that only are used in the OS and has little to no relevance to the
204 * casual user.
206 * Returns: %TRUE if @mount_path is considered an implementation detail
207 * of the OS.
209 gboolean
210 g_unix_is_mount_path_system_internal (const char *mount_path)
212 const char *ignore_mountpoints[] = {
213 /* Includes all FHS 2.3 toplevel dirs and other specilized
214 * directories that we want to hide from the user.
216 "/", /* we already have "Filesystem root" in Nautilus */
217 "/bin",
218 "/boot",
219 "/dev",
220 "/etc",
221 "/home",
222 "/lib",
223 "/lib64",
224 "/media",
225 "/mnt",
226 "/opt",
227 "/root",
228 "/sbin",
229 "/srv",
230 "/tmp",
231 "/usr",
232 "/usr/local",
233 "/var",
234 "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
235 "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
236 "/proc",
237 "/sbin",
238 "/net",
239 NULL
242 if (is_in (mount_path, ignore_mountpoints))
243 return TRUE;
245 if (g_str_has_prefix (mount_path, "/dev") ||
246 g_str_has_prefix (mount_path, "/proc") ||
247 g_str_has_prefix (mount_path, "/sys"))
248 return TRUE;
250 if (strstr (mount_path, "/.gvfs") != NULL)
251 return TRUE;
253 return FALSE;
256 static gboolean
257 guess_system_internal (const char *mountpoint,
258 const char *fs,
259 const char *device)
261 const char *ignore_fs[] = {
262 "auto",
263 "autofs",
264 "devfs",
265 "devpts",
266 "kernfs",
267 "linprocfs",
268 "proc",
269 "procfs",
270 "ptyfs",
271 "rootfs",
272 "selinuxfs",
273 "sysfs",
274 "tmpfs",
275 "usbfs",
276 "nfsd",
277 "rpc_pipefs",
278 "zfs",
279 NULL
281 const char *ignore_devices[] = {
282 "none",
283 "sunrpc",
284 "devpts",
285 "nfsd",
286 "/dev/loop",
287 "/dev/vn",
288 NULL
291 if (is_in (fs, ignore_fs))
292 return TRUE;
294 if (is_in (device, ignore_devices))
295 return TRUE;
297 if (g_unix_is_mount_path_system_internal (mountpoint))
298 return TRUE;
300 return FALSE;
303 #ifdef HAVE_MNTENT_H
305 static char *
306 get_mtab_read_file (void)
308 #ifdef _PATH_MOUNTED
309 # ifdef __linux__
310 return "/proc/mounts";
311 # else
312 return _PATH_MOUNTED;
313 # endif
314 #else
315 return "/etc/mtab";
316 #endif
319 static char *
320 get_mtab_monitor_file (void)
322 #ifdef _PATH_MOUNTED
323 return _PATH_MOUNTED;
324 #else
325 return "/etc/mtab";
326 #endif
329 #ifndef HAVE_GETMNTENT_R
330 G_LOCK_DEFINE_STATIC(getmntent);
331 #endif
333 static GList *
334 _g_get_unix_mounts ()
336 #ifdef HAVE_GETMNTENT_R
337 struct mntent ent;
338 char buf[1024];
339 #endif
340 struct mntent *mntent;
341 FILE *file;
342 char *read_file;
343 GUnixMountEntry *mount_entry;
344 GHashTable *mounts_hash;
345 GList *return_list;
347 read_file = get_mtab_read_file ();
349 file = setmntent (read_file, "r");
350 if (file == NULL)
351 return NULL;
353 return_list = NULL;
355 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
357 #ifdef HAVE_GETMNTENT_R
358 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
359 #else
360 G_LOCK (getmntent);
361 while ((mntent = getmntent (file)) != NULL)
362 #endif
364 /* ignore any mnt_fsname that is repeated and begins with a '/'
366 * We do this to avoid being fooled by --bind mounts, since
367 * these have the same device as the location they bind to.
368 * Its not an ideal solution to the problem, but it's likely that
369 * the most important mountpoint is first and the --bind ones after
370 * that aren't as important. So it should work.
372 * The '/' is to handle procfs, tmpfs and other no device mounts.
374 if (mntent->mnt_fsname != NULL &&
375 mntent->mnt_fsname[0] == '/' &&
376 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
377 continue;
379 mount_entry = g_new0 (GUnixMountEntry, 1);
380 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
381 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
382 mount_entry->device_path = g_strdup (_resolve_dev_root ());
383 else
384 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
385 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
387 #if defined (HAVE_HASMNTOPT)
388 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
389 mount_entry->is_read_only = TRUE;
390 #endif
392 mount_entry->is_system_internal =
393 guess_system_internal (mount_entry->mount_path,
394 mount_entry->filesystem_type,
395 mount_entry->device_path);
397 g_hash_table_insert (mounts_hash,
398 mount_entry->device_path,
399 mount_entry->device_path);
401 return_list = g_list_prepend (return_list, mount_entry);
403 g_hash_table_destroy (mounts_hash);
405 endmntent (file);
407 #ifndef HAVE_GETMNTENT_R
408 G_UNLOCK (getmntent);
409 #endif
411 return g_list_reverse (return_list);
414 #elif defined (HAVE_SYS_MNTTAB_H)
416 G_LOCK_DEFINE_STATIC(getmntent);
418 static char *
419 get_mtab_read_file (void)
421 #ifdef _PATH_MOUNTED
422 return _PATH_MOUNTED;
423 #else
424 return "/etc/mnttab";
425 #endif
428 static char *
429 get_mtab_monitor_file (void)
431 return get_mtab_read_file ();
434 static GList *
435 _g_get_unix_mounts (void)
437 struct mnttab mntent;
438 FILE *file;
439 char *read_file;
440 GUnixMountEntry *mount_entry;
441 GList *return_list;
443 read_file = get_mtab_read_file ();
445 file = setmntent (read_file, "r");
446 if (file == NULL)
447 return NULL;
449 return_list = NULL;
451 G_LOCK (getmntent);
452 while (! getmntent (file, &mntent))
454 mount_entry = g_new0 (GUnixMountEntry, 1);
456 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
457 mount_entry->device_path = g_strdup (mntent.mnt_special);
458 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
460 #if defined (HAVE_HASMNTOPT)
461 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
462 mount_entry->is_read_only = TRUE;
463 #endif
465 mount_entry->is_system_internal =
466 guess_system_internal (mount_entry->mount_path,
467 mount_entry->filesystem_type,
468 mount_entry->device_path);
470 return_list = g_list_prepend (return_list, mount_entry);
473 endmntent (file);
475 G_UNLOCK (getmntent);
477 return g_list_reverse (return_list);
480 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
482 static char *
483 get_mtab_monitor_file (void)
485 return NULL;
488 static GList *
489 _g_get_unix_mounts (void)
491 struct vfs_ent *fs_info;
492 struct vmount *vmount_info;
493 int vmount_number;
494 unsigned int vmount_size;
495 int current;
496 GList *return_list;
498 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
500 g_warning ("Unable to know the number of mounted volumes\n");
502 return NULL;
505 vmount_info = (struct vmount*)g_malloc (vmount_size);
507 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
509 if (vmount_info->vmt_revision != VMT_REVISION)
510 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
512 if (vmount_number < 0)
514 g_warning ("Unable to recover mounted volumes information\n");
516 g_free (vmount_info);
517 return NULL;
520 return_list = NULL;
521 while (vmount_number > 0)
523 mount_entry = g_new0 (GUnixMountEntry, 1);
525 mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT));
526 mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB));
527 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
528 mount_entry->is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
530 fs_info = getvfsbytype (vmount_info->vmt_gfstype);
532 if (fs_info == NULL)
533 mount_entry->filesystem_type = g_strdup ("unknown");
534 else
535 mount_entry->filesystem_type = g_strdup (fs_info->vfsent_name);
537 mount_entry->is_system_internal =
538 guess_system_internal (mount_entry->mount_path,
539 mount_entry->filesystem_type,
540 mount_entry->device_path);
542 return_list = g_list_prepend (return_list, mount_entry);
544 vmount_info = (struct vmount *)( (char*)vmount_info
545 + vmount_info->vmt_length);
546 vmount_number--;
550 g_free (vmount_info);
552 return g_list_reverse (return_list);
555 #elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
557 static char *
558 get_mtab_monitor_file (void)
560 return NULL;
563 static GList *
564 _g_get_unix_mounts (void)
566 struct statfs *mntent = NULL;
567 int num_mounts, i;
568 GUnixMountEntry *mount_entry;
569 GList *return_list;
571 /* Pass MNT_NOWAIT to avoid blocking trying to update NFS mounts. */
572 if ((num_mounts = getmntinfo (&mntent, MNT_NOWAIT)) == 0)
573 return NULL;
575 return_list = NULL;
577 for (i = 0; i < num_mounts; i++)
579 mount_entry = g_new0 (GUnixMountEntry, 1);
581 mount_entry->mount_path = g_strdup (mntent[i].f_mntonname);
582 mount_entry->device_path = g_strdup (mntent[i].f_mntfromname);
583 mount_entry->filesystem_type = g_strdup (mntent[i].f_fstypename);
584 if (mntent[i].f_flags & MNT_RDONLY)
585 mount_entry->is_read_only = TRUE;
587 mount_entry->is_system_internal =
588 guess_system_internal (mount_entry->mount_path,
589 mount_entry->filesystem_type,
590 mount_entry->device_path);
592 return_list = g_list_prepend (return_list, mount_entry);
595 return g_list_reverse (return_list);
597 #else
598 #error No _g_get_unix_mounts() implementation for system
599 #endif
601 /* _g_get_unix_mount_points():
602 * read the fstab.
603 * don't return swap and ignore mounts.
606 static char *
607 get_fstab_file (void)
609 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
610 /* AIX */
611 return "/etc/filesystems";
612 #elif defined(_PATH_MNTTAB)
613 return _PATH_MNTTAB;
614 #elif defined(VFSTAB)
615 return VFSTAB;
616 #else
617 return "/etc/fstab";
618 #endif
621 #ifdef HAVE_MNTENT_H
622 static GList *
623 _g_get_unix_mount_points (void)
625 #ifdef HAVE_GETMNTENT_R
626 struct mntent ent;
627 char buf[1024];
628 #endif
629 struct mntent *mntent;
630 FILE *file;
631 char *read_file;
632 GUnixMountPoint *mount_entry;
633 GList *return_list;
635 read_file = get_fstab_file ();
637 file = setmntent (read_file, "r");
638 if (file == NULL)
639 return NULL;
641 return_list = NULL;
643 #ifdef HAVE_GETMNTENT_R
644 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
645 #else
646 G_LOCK (getmntent);
647 while ((mntent = getmntent (file)) != NULL)
648 #endif
650 if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
651 (strcmp (mntent->mnt_dir, "swap") == 0))
652 continue;
654 mount_entry = g_new0 (GUnixMountPoint, 1);
655 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
656 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
657 mount_entry->device_path = g_strdup (_resolve_dev_root ());
658 else
659 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
660 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
662 #ifdef HAVE_HASMNTOPT
663 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
664 mount_entry->is_read_only = TRUE;
666 if (hasmntopt (mntent, "loop") != NULL)
667 mount_entry->is_loopback = TRUE;
669 #endif
671 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
672 #ifdef HAVE_HASMNTOPT
673 || (hasmntopt (mntent, "user") != NULL
674 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
675 || hasmntopt (mntent, "pamconsole") != NULL
676 || hasmntopt (mntent, "users") != NULL
677 || hasmntopt (mntent, "owner") != NULL
678 #endif
680 mount_entry->is_user_mountable = TRUE;
682 return_list = g_list_prepend (return_list, mount_entry);
685 endmntent (file);
687 #ifndef HAVE_GETMNTENT_R
688 G_UNLOCK (getmntent);
689 #endif
691 return g_list_reverse (return_list);
694 #elif defined (HAVE_SYS_MNTTAB_H)
696 static GList *
697 _g_get_unix_mount_points (void)
699 struct mnttab mntent;
700 FILE *file;
701 char *read_file;
702 GUnixMountPoint *mount_entry;
703 GList *return_list;
705 read_file = get_fstab_file ();
707 file = setmntent (read_file, "r");
708 if (file == NULL)
709 return NULL;
711 return_list = NULL;
713 G_LOCK (getmntent);
714 while (! getmntent (file, &mntent))
716 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
717 (strcmp (mntent.mnt_mountp, "swap") == 0))
718 continue;
720 mount_entry = g_new0 (GUnixMountPoint, 1);
722 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
723 mount_entry->device_path = g_strdup (mntent.mnt_special);
724 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
726 #ifdef HAVE_HASMNTOPT
727 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
728 mount_entry->is_read_only = TRUE;
730 if (hasmntopt (&mntent, "lofs") != NULL)
731 mount_entry->is_loopback = TRUE;
732 #endif
734 if ((mntent.mnt_fstype != NULL)
735 #ifdef HAVE_HASMNTOPT
736 || (hasmntopt (&mntent, "user") != NULL
737 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
738 || hasmntopt (&mntent, "pamconsole") != NULL
739 || hasmntopt (&mntent, "users") != NULL
740 || hasmntopt (&mntent, "owner") != NULL
741 #endif
743 mount_entry->is_user_mountable = TRUE;
746 return_list = g_list_prepend (return_list, mount_entry);
749 endmntent (file);
750 G_UNLOCK (getmntent);
752 return g_list_reverse (return_list);
754 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
756 /* functions to parse /etc/filesystems on aix */
758 /* read character, ignoring comments (begin with '*', end with '\n' */
759 static int
760 aix_fs_getc (FILE *fd)
762 int c;
764 while ((c = getc (fd)) == '*')
766 while (((c = getc (fd)) != '\n') && (c != EOF))
771 /* eat all continuous spaces in a file */
772 static int
773 aix_fs_ignorespace (FILE *fd)
775 int c;
777 while ((c = aix_fs_getc (fd)) != EOF)
779 if (!g_ascii_isspace (c))
781 ungetc (c,fd);
782 return c;
786 return EOF;
789 /* read one word from file */
790 static int
791 aix_fs_getword (FILE *fd,
792 char *word)
794 int c;
796 aix_fs_ignorespace (fd);
798 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
800 if (c == '"')
802 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
803 *word++ = c;
804 else
805 *word++ = c;
808 *word = 0;
810 return c;
813 typedef struct {
814 char mnt_mount[PATH_MAX];
815 char mnt_special[PATH_MAX];
816 char mnt_fstype[16];
817 char mnt_options[128];
818 } AixMountTableEntry;
820 /* read mount points properties */
821 static int
822 aix_fs_get (FILE *fd,
823 AixMountTableEntry *prop)
825 static char word[PATH_MAX] = { 0 };
826 char value[PATH_MAX];
828 /* read stanza */
829 if (word[0] == 0)
831 if (aix_fs_getword (fd, word) == EOF)
832 return EOF;
835 word[strlen(word) - 1] = 0;
836 strcpy (prop->mnt_mount, word);
838 /* read attributes and value */
840 while (aix_fs_getword (fd, word) != EOF)
842 /* test if is attribute or new stanza */
843 if (word[strlen(word) - 1] == ':')
844 return 0;
846 /* read "=" */
847 aix_fs_getword (fd, value);
849 /* read value */
850 aix_fs_getword (fd, value);
852 if (strcmp (word, "dev") == 0)
853 strcpy (prop->mnt_special, value);
854 else if (strcmp (word, "vfs") == 0)
855 strcpy (prop->mnt_fstype, value);
856 else if (strcmp (word, "options") == 0)
857 strcpy(prop->mnt_options, value);
860 return 0;
863 static GList *
864 _g_get_unix_mount_points (void)
866 struct mntent *mntent;
867 FILE *file;
868 char *read_file;
869 GUnixMountPoint *mount_entry;
870 AixMountTableEntry mntent;
871 GList *return_list;
873 read_file = get_fstab_file ();
875 file = setmntent (read_file, "r");
876 if (file == NULL)
877 return NULL;
879 return_list = NULL;
881 while (!aix_fs_get (file, &mntent))
883 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
885 mount_entry = g_new0 (GUnixMountPoint, 1);
888 mount_entry->mount_path = g_strdup (mntent.mnt_mount);
889 mount_entry->device_path = g_strdup (mntent.mnt_special);
890 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
891 mount_entry->is_read_only = TRUE;
892 mount_entry->is_user_mountable = TRUE;
894 return_list = g_list_prepend (return_list, mount_entry);
898 endmntent (file);
900 return g_list_reverse (return_list);
903 #elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
905 static GList *
906 _g_get_unix_mount_points (void)
908 struct fstab *fstab = NULL;
909 GUnixMountPoint *mount_entry;
910 GList *return_list;
911 #ifdef HAVE_SYS_SYSCTL_H
912 int usermnt = 0;
913 size_t len = sizeof(usermnt);
914 struct stat sb;
915 #endif
917 if (!setfsent ())
918 return NULL;
920 return_list = NULL;
922 #ifdef HAVE_SYS_SYSCTL_H
923 #if defined(HAVE_SYSCTLBYNAME)
924 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
925 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
927 int mib[2];
929 mib[0] = CTL_VFS;
930 mib[1] = VFS_USERMOUNT;
931 sysctl (mib, 2, &usermnt, &len, NULL, 0);
933 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
935 int mib[2];
937 mib[0] = CTL_KERN;
938 mib[1] = KERN_USERMOUNT;
939 sysctl (mib, 2, &usermnt, &len, NULL, 0);
941 #endif
942 #endif
944 while ((fstab = getfsent ()) != NULL)
946 if (strcmp (fstab->fs_vfstype, "swap") == 0)
947 continue;
949 mount_entry = g_new0 (GUnixMountPoint, 1);
951 mount_entry->mount_path = g_strdup (fstab->fs_file);
952 mount_entry->device_path = g_strdup (fstab->fs_spec);
953 mount_entry->filesystem_type = g_strdup (fstab->fs_vfstype);
955 if (strcmp (fstab->fs_type, "ro") == 0)
956 mount_entry->is_read_only = TRUE;
958 #ifdef HAVE_SYS_SYSCTL_H
959 if (usermnt != 0)
961 uid_t uid = getuid ();
962 if (stat (fstab->fs_file, &sb) == 0)
964 if (uid == 0 || sb.st_uid == uid)
965 mount_entry->is_user_mountable = TRUE;
968 #endif
970 return_list = g_list_prepend (return_list, mount_entry);
973 endfsent ();
975 return g_list_reverse (return_list);
977 #else
978 #error No g_get_mount_table() implementation for system
979 #endif
981 static guint64
982 get_mounts_timestamp (void)
984 const char *monitor_file;
985 struct stat buf;
987 monitor_file = get_mtab_monitor_file ();
988 if (monitor_file)
990 if (stat (monitor_file, &buf) == 0)
991 return (guint64)buf.st_mtime;
993 return 0;
996 static guint64
997 get_mount_points_timestamp (void)
999 const char *monitor_file;
1000 struct stat buf;
1002 monitor_file = get_fstab_file ();
1003 if (monitor_file)
1005 if (stat (monitor_file, &buf) == 0)
1006 return (guint64)buf.st_mtime;
1008 return 0;
1012 * g_unix_mounts_get:
1013 * @time_read: guint64 to contain a timestamp.
1015 * Gets a #GList of strings containing the unix mounts.
1016 * If @time_read is set, it will be filled with the mount
1017 * timestamp, allowing for checking if the mounts have changed
1018 * with g_unix_mounts_changed_since().
1020 * Returns: a #GList of the UNIX mounts.
1022 GList *
1023 g_unix_mounts_get (guint64 *time_read)
1025 if (time_read)
1026 *time_read = get_mounts_timestamp ();
1028 return _g_get_unix_mounts ();
1032 * g_unix_mount_at:
1033 * @mount_path: path for a possible unix mount.
1034 * @time_read: guint64 to contain a timestamp.
1036 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1037 * is set, it will be filled with a unix timestamp for checking
1038 * if the mounts have changed since with g_unix_mounts_changed_since().
1040 * Returns: a #GUnixMount.
1042 GUnixMountEntry *
1043 g_unix_mount_at (const char *mount_path,
1044 guint64 *time_read)
1046 GList *mounts, *l;
1047 GUnixMountEntry *mount_entry, *found;
1049 mounts = g_unix_mounts_get (time_read);
1051 found = NULL;
1052 for (l = mounts; l != NULL; l = l->next)
1054 mount_entry = l->data;
1056 if (strcmp (mount_path, mount_entry->mount_path) == 0)
1057 found = mount_entry;
1058 else
1059 g_unix_mount_free (mount_entry);
1062 g_list_free (mounts);
1064 return found;
1068 * g_unix_mount_points_get:
1069 * @time_read: guint64 to contain a timestamp.
1071 * Gets a #GList of strings containing the unix mount points.
1072 * If @time_read is set, it will be filled with the mount timestamp,
1073 * allowing for checking if the mounts have changed with
1074 * g_unix_mounts_points_changed_since().
1076 * Returns: a #GList of the UNIX mountpoints.
1078 GList *
1079 g_unix_mount_points_get (guint64 *time_read)
1081 if (time_read)
1082 *time_read = get_mount_points_timestamp ();
1084 return _g_get_unix_mount_points ();
1088 * g_unix_mounts_changed_since:
1089 * @time: guint64 to contain a timestamp.
1091 * Checks if the unix mounts have changed since a given unix time.
1093 * Returns: %TRUE if the mounts have changed since @time.
1095 gboolean
1096 g_unix_mounts_changed_since (guint64 time)
1098 return get_mounts_timestamp () != time;
1102 * g_unix_mount_points_changed_since:
1103 * @time: guint64 to contain a timestamp.
1105 * Checks if the unix mount points have changed since a given unix time.
1107 * Returns: %TRUE if the mount points have changed since @time.
1109 gboolean
1110 g_unix_mount_points_changed_since (guint64 time)
1112 return get_mount_points_timestamp () != time;
1115 static void
1116 g_unix_mount_monitor_finalize (GObject *object)
1118 GUnixMountMonitor *monitor;
1120 monitor = G_UNIX_MOUNT_MONITOR (object);
1122 if (monitor->fstab_monitor)
1124 g_file_monitor_cancel (monitor->fstab_monitor);
1125 g_object_unref (monitor->fstab_monitor);
1128 if (monitor->mtab_monitor)
1130 g_file_monitor_cancel (monitor->mtab_monitor);
1131 g_object_unref (monitor->mtab_monitor);
1134 the_mount_monitor = NULL;
1136 G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
1140 static void
1141 g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
1143 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1145 gobject_class->finalize = g_unix_mount_monitor_finalize;
1147 * GUnixMountMonitor::mounts-changed:
1148 * @monitor: the object on which the signal is emitted
1150 * Emitted when the unix mounts have changed.
1151 **/
1152 signals[MOUNTS_CHANGED] =
1153 g_signal_new ("mounts-changed",
1154 G_TYPE_FROM_CLASS (klass),
1155 G_SIGNAL_RUN_LAST,
1157 NULL, NULL,
1158 g_cclosure_marshal_VOID__VOID,
1159 G_TYPE_NONE, 0);
1161 * GUnixMountMonitor::mountpoints-changed:
1162 * @monitor: the object on which the signal is emitted
1164 * Emitted when the unix mount points have changed.
1166 signals[MOUNTPOINTS_CHANGED] =
1167 g_signal_new ("mountpoints-changed",
1168 G_TYPE_FROM_CLASS (klass),
1169 G_SIGNAL_RUN_LAST,
1171 NULL, NULL,
1172 g_cclosure_marshal_VOID__VOID,
1173 G_TYPE_NONE, 0);
1176 static void
1177 fstab_file_changed (GFileMonitor *monitor,
1178 GFile *file,
1179 GFile *other_file,
1180 GFileMonitorEvent event_type,
1181 gpointer user_data)
1183 GUnixMountMonitor *mount_monitor;
1185 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1186 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1187 event_type != G_FILE_MONITOR_EVENT_DELETED)
1188 return;
1190 mount_monitor = user_data;
1191 g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0);
1194 static void
1195 mtab_file_changed (GFileMonitor *monitor,
1196 GFile *file,
1197 GFile *other_file,
1198 GFileMonitorEvent event_type,
1199 gpointer user_data)
1201 GUnixMountMonitor *mount_monitor;
1203 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1204 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1205 event_type != G_FILE_MONITOR_EVENT_DELETED)
1206 return;
1208 mount_monitor = user_data;
1209 g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
1212 static void
1213 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1215 GFile *file;
1217 if (get_fstab_file () != NULL)
1219 file = g_file_new_for_path (get_fstab_file ());
1220 monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1221 g_object_unref (file);
1223 g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor);
1226 if (get_mtab_monitor_file () != NULL)
1228 file = g_file_new_for_path (get_mtab_monitor_file ());
1229 monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1230 g_object_unref (file);
1232 g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor);
1237 * g_unix_mount_monitor_set_rate_limit:
1238 * @mount_monitor: a #GUnixMountMonitor
1239 * @limit_msec: a integer with the limit in milliseconds to
1240 * poll for changes.
1242 * Sets the rate limit to which the @mount_monitor will report
1243 * consecutive change events to the mount and mount point entry files.
1245 * Since: 2.18
1247 void
1248 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
1249 int limit_msec)
1251 g_return_if_fail (G_IS_UNIX_MOUNT_MONITOR (mount_monitor));
1253 if (mount_monitor->fstab_monitor != NULL)
1254 g_file_monitor_set_rate_limit (mount_monitor->fstab_monitor, limit_msec);
1256 if (mount_monitor->mtab_monitor != NULL)
1257 g_file_monitor_set_rate_limit (mount_monitor->mtab_monitor, limit_msec);
1261 * g_unix_mount_monitor_new:
1263 * Gets a new #GUnixMountMonitor. The default rate limit for which the
1264 * monitor will report consecutive changes for the mount and mount
1265 * point entry files is the default for a #GFileMonitor. Use
1266 * g_unix_mount_monitor_set_rate_limit() to change this.
1268 * Returns: a #GUnixMountMonitor.
1270 GUnixMountMonitor *
1271 g_unix_mount_monitor_new (void)
1273 if (the_mount_monitor == NULL)
1275 the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL);
1276 return the_mount_monitor;
1279 return g_object_ref (the_mount_monitor);
1283 * g_unix_mount_free:
1284 * @mount_entry: a #GUnixMount.
1286 * Frees a unix mount.
1288 void
1289 g_unix_mount_free (GUnixMountEntry *mount_entry)
1291 g_return_if_fail (mount_entry != NULL);
1293 g_free (mount_entry->mount_path);
1294 g_free (mount_entry->device_path);
1295 g_free (mount_entry->filesystem_type);
1296 g_free (mount_entry);
1300 * g_unix_mount_point_free:
1301 * @mount_point: unix mount point to free.
1303 * Frees a unix mount point.
1305 void
1306 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1308 g_return_if_fail (mount_point != NULL);
1310 g_free (mount_point->mount_path);
1311 g_free (mount_point->device_path);
1312 g_free (mount_point->filesystem_type);
1313 g_free (mount_point);
1317 * g_unix_mount_compare:
1318 * @mount1: first #GUnixMountEntry to compare.
1319 * @mount2: second #GUnixMountEntry to compare.
1321 * Compares two unix mounts.
1323 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1324 * or less than @mount2, respectively.
1326 gint
1327 g_unix_mount_compare (GUnixMountEntry *mount1,
1328 GUnixMountEntry *mount2)
1330 int res;
1332 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1334 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1335 if (res != 0)
1336 return res;
1338 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1339 if (res != 0)
1340 return res;
1342 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1343 if (res != 0)
1344 return res;
1346 res = mount1->is_read_only - mount2->is_read_only;
1347 if (res != 0)
1348 return res;
1350 return 0;
1354 * g_unix_mount_get_mount_path:
1355 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1357 * Gets the mount path for a unix mount.
1359 * Returns: the mount path for @mount_entry.
1361 const char *
1362 g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
1364 g_return_val_if_fail (mount_entry != NULL, NULL);
1366 return mount_entry->mount_path;
1370 * g_unix_mount_get_device_path:
1371 * @mount_entry: a #GUnixMount.
1373 * Gets the device path for a unix mount.
1375 * Returns: a string containing the device path.
1377 const char *
1378 g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
1380 g_return_val_if_fail (mount_entry != NULL, NULL);
1382 return mount_entry->device_path;
1386 * g_unix_mount_get_fs_type:
1387 * @mount_entry: a #GUnixMount.
1389 * Gets the filesystem type for the unix mount.
1391 * Returns: a string containing the file system type.
1393 const char *
1394 g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
1396 g_return_val_if_fail (mount_entry != NULL, NULL);
1398 return mount_entry->filesystem_type;
1402 * g_unix_mount_is_readonly:
1403 * @mount_entry: a #GUnixMount.
1405 * Checks if a unix mount is mounted read only.
1407 * Returns: %TRUE if @mount_entry is read only.
1409 gboolean
1410 g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
1412 g_return_val_if_fail (mount_entry != NULL, FALSE);
1414 return mount_entry->is_read_only;
1418 * g_unix_mount_is_system_internal:
1419 * @mount_entry: a #GUnixMount.
1421 * Checks if a unix mount is a system path.
1423 * Returns: %TRUE if the unix mount is for a system path.
1425 gboolean
1426 g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
1428 g_return_val_if_fail (mount_entry != NULL, FALSE);
1430 return mount_entry->is_system_internal;
1434 * g_unix_mount_point_compare:
1435 * @mount1: a #GUnixMount.
1436 * @mount2: a #GUnixMount.
1438 * Compares two unix mount points.
1440 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1441 * or less than @mount2, respectively.
1443 gint
1444 g_unix_mount_point_compare (GUnixMountPoint *mount1,
1445 GUnixMountPoint *mount2)
1447 int res;
1449 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1451 res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
1452 if (res != 0)
1453 return res;
1455 res = g_strcmp0 (mount1->device_path, mount2->device_path);
1456 if (res != 0)
1457 return res;
1459 res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
1460 if (res != 0)
1461 return res;
1463 res = mount1->is_read_only - mount2->is_read_only;
1464 if (res != 0)
1465 return res;
1467 res = mount1->is_user_mountable - mount2->is_user_mountable;
1468 if (res != 0)
1469 return res;
1471 res = mount1->is_loopback - mount2->is_loopback;
1472 if (res != 0)
1473 return res;
1475 return 0;
1479 * g_unix_mount_point_get_mount_path:
1480 * @mount_point: a #GUnixMountPoint.
1482 * Gets the mount path for a unix mount point.
1484 * Returns: a string containing the mount path.
1486 const char *
1487 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
1489 g_return_val_if_fail (mount_point != NULL, NULL);
1491 return mount_point->mount_path;
1495 * g_unix_mount_point_get_device_path:
1496 * @mount_point: a #GUnixMountPoint.
1498 * Gets the device path for a unix mount point.
1500 * Returns: a string containing the device path.
1502 const char *
1503 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
1505 g_return_val_if_fail (mount_point != NULL, NULL);
1507 return mount_point->device_path;
1511 * g_unix_mount_point_get_fs_type:
1512 * @mount_point: a #GUnixMountPoint.
1514 * Gets the file system type for the mount point.
1516 * Returns: a string containing the file system type.
1518 const char *
1519 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
1521 g_return_val_if_fail (mount_point != NULL, NULL);
1523 return mount_point->filesystem_type;
1527 * g_unix_mount_point_is_readonly:
1528 * @mount_point: a #GUnixMountPoint.
1530 * Checks if a unix mount point is read only.
1532 * Returns: %TRUE if a mount point is read only.
1534 gboolean
1535 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
1537 g_return_val_if_fail (mount_point != NULL, FALSE);
1539 return mount_point->is_read_only;
1543 * g_unix_mount_point_is_user_mountable:
1544 * @mount_point: a #GUnixMountPoint.
1546 * Checks if a unix mount point is mountable by the user.
1548 * Returns: %TRUE if the mount point is user mountable.
1550 gboolean
1551 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
1553 g_return_val_if_fail (mount_point != NULL, FALSE);
1555 return mount_point->is_user_mountable;
1559 * g_unix_mount_point_is_loopback:
1560 * @mount_point: a #GUnixMountPoint.
1562 * Checks if a unix mount point is a loopback device.
1564 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
1566 gboolean
1567 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
1569 g_return_val_if_fail (mount_point != NULL, FALSE);
1571 return mount_point->is_loopback;
1574 static GUnixMountType
1575 guess_mount_type (const char *mount_path,
1576 const char *device_path,
1577 const char *filesystem_type)
1579 GUnixMountType type;
1580 char *basename;
1582 type = G_UNIX_MOUNT_TYPE_UNKNOWN;
1584 if ((strcmp (filesystem_type, "udf") == 0) ||
1585 (strcmp (filesystem_type, "iso9660") == 0) ||
1586 (strcmp (filesystem_type, "cd9660") == 0))
1587 type = G_UNIX_MOUNT_TYPE_CDROM;
1588 else if ((strcmp (filesystem_type, "nfs") == 0) ||
1589 (strcmp (filesystem_type, "nfs4") == 0))
1590 type = G_UNIX_MOUNT_TYPE_NFS;
1591 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
1592 g_str_has_prefix (device_path, "/dev/fd") ||
1593 g_str_has_prefix (device_path, "/dev/floppy"))
1594 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1595 else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
1596 g_str_has_prefix (device_path, "/dev/acd") ||
1597 g_str_has_prefix (device_path, "/dev/cd"))
1598 type = G_UNIX_MOUNT_TYPE_CDROM;
1599 else if (g_str_has_prefix (device_path, "/vol/"))
1601 const char *name = mount_path + strlen ("/");
1603 if (g_str_has_prefix (name, "cdrom"))
1604 type = G_UNIX_MOUNT_TYPE_CDROM;
1605 else if (g_str_has_prefix (name, "floppy") ||
1606 g_str_has_prefix (device_path, "/vol/dev/diskette/"))
1607 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1608 else if (g_str_has_prefix (name, "rmdisk"))
1609 type = G_UNIX_MOUNT_TYPE_ZIP;
1610 else if (g_str_has_prefix (name, "jaz"))
1611 type = G_UNIX_MOUNT_TYPE_JAZ;
1612 else if (g_str_has_prefix (name, "memstick"))
1613 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1615 else
1617 basename = g_path_get_basename (mount_path);
1619 if (g_str_has_prefix (basename, "cdr") ||
1620 g_str_has_prefix (basename, "cdwriter") ||
1621 g_str_has_prefix (basename, "burn") ||
1622 g_str_has_prefix (basename, "dvdr"))
1623 type = G_UNIX_MOUNT_TYPE_CDROM;
1624 else if (g_str_has_prefix (basename, "floppy"))
1625 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1626 else if (g_str_has_prefix (basename, "zip"))
1627 type = G_UNIX_MOUNT_TYPE_ZIP;
1628 else if (g_str_has_prefix (basename, "jaz"))
1629 type = G_UNIX_MOUNT_TYPE_JAZ;
1630 else if (g_str_has_prefix (basename, "camera"))
1631 type = G_UNIX_MOUNT_TYPE_CAMERA;
1632 else if (g_str_has_prefix (basename, "memstick") ||
1633 g_str_has_prefix (basename, "memory_stick") ||
1634 g_str_has_prefix (basename, "ram"))
1635 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1636 else if (g_str_has_prefix (basename, "compact_flash"))
1637 type = G_UNIX_MOUNT_TYPE_CF;
1638 else if (g_str_has_prefix (basename, "smart_media"))
1639 type = G_UNIX_MOUNT_TYPE_SM;
1640 else if (g_str_has_prefix (basename, "sd_mmc"))
1641 type = G_UNIX_MOUNT_TYPE_SDMMC;
1642 else if (g_str_has_prefix (basename, "ipod"))
1643 type = G_UNIX_MOUNT_TYPE_IPOD;
1645 g_free (basename);
1648 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
1649 type = G_UNIX_MOUNT_TYPE_HD;
1651 return type;
1655 * g_unix_mount_guess_type:
1656 * @mount_entry: a #GUnixMount.
1658 * Guesses the type of a unix mount. If the mount type cannot be
1659 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1661 * Returns: a #GUnixMountType.
1663 static GUnixMountType
1664 g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
1666 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1667 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1668 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1669 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1671 return guess_mount_type (mount_entry->mount_path,
1672 mount_entry->device_path,
1673 mount_entry->filesystem_type);
1677 * g_unix_mount_point_guess_type:
1678 * @mount_point: a #GUnixMountPoint.
1680 * Guesses the type of a unix mount point.
1681 * If the mount type cannot be determined,
1682 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1684 * Returns: a #GUnixMountType.
1686 static GUnixMountType
1687 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
1689 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1690 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1691 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1692 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1694 return guess_mount_type (mount_point->mount_path,
1695 mount_point->device_path,
1696 mount_point->filesystem_type);
1699 static const char *
1700 type_to_icon (GUnixMountType type, gboolean is_mount_point)
1702 const char *icon_name;
1704 switch (type)
1706 case G_UNIX_MOUNT_TYPE_HD:
1707 if (is_mount_point)
1708 icon_name = "drive-removable-media";
1709 else
1710 icon_name = "drive-harddisk";
1711 break;
1712 case G_UNIX_MOUNT_TYPE_FLOPPY:
1713 case G_UNIX_MOUNT_TYPE_ZIP:
1714 case G_UNIX_MOUNT_TYPE_JAZ:
1715 if (is_mount_point)
1716 icon_name = "drive-removable-media";
1717 else
1718 icon_name = "media-floppy";
1719 break;
1720 case G_UNIX_MOUNT_TYPE_CDROM:
1721 if (is_mount_point)
1722 icon_name = "drive-optical";
1723 else
1724 icon_name = "media-optical";
1725 break;
1726 case G_UNIX_MOUNT_TYPE_NFS:
1727 /* TODO: Would like a better icon here... */
1728 if (is_mount_point)
1729 icon_name = "drive-removable-media";
1730 else
1731 icon_name = "drive-harddisk";
1732 break;
1733 case G_UNIX_MOUNT_TYPE_MEMSTICK:
1734 if (is_mount_point)
1735 icon_name = "drive-removable-media";
1736 else
1737 icon_name = "media-flash";
1738 break;
1739 case G_UNIX_MOUNT_TYPE_CAMERA:
1740 if (is_mount_point)
1741 icon_name = "drive-removable-media";
1742 else
1743 icon_name = "camera-photo";
1744 break;
1745 case G_UNIX_MOUNT_TYPE_IPOD:
1746 if (is_mount_point)
1747 icon_name = "drive-removable-media";
1748 else
1749 icon_name = "multimedia-player";
1750 break;
1751 case G_UNIX_MOUNT_TYPE_UNKNOWN:
1752 default:
1753 if (is_mount_point)
1754 icon_name = "drive-removable-media";
1755 else
1756 icon_name = "drive-harddisk";
1757 break;
1760 return icon_name;
1764 * g_unix_mount_guess_name:
1765 * @mount_entry: a #GUnixMountEntry
1767 * Guesses the name of a Unix mount.
1768 * The result is a translated string.
1770 * Returns: A newly allocated string that must
1771 * be freed with g_free()
1773 char *
1774 g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
1776 char *name;
1778 if (strcmp (mount_entry->mount_path, "/") == 0)
1779 name = g_strdup (_("Filesystem root"));
1780 else
1781 name = g_filename_display_basename (mount_entry->mount_path);
1783 return name;
1787 * g_unix_mount_guess_icon:
1788 * @mount_entry: a #GUnixMountEntry
1790 * Guesses the icon of a Unix mount.
1792 * Returns: a #GIcon
1794 GIcon *
1795 g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
1797 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE));
1801 * g_unix_mount_point_guess_name:
1802 * @mount_point: a #GUnixMountPoint
1804 * Guesses the name of a Unix mount point.
1805 * The result is a translated string.
1807 * Returns: A newly allocated string that must
1808 * be freed with g_free()
1810 char *
1811 g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
1813 char *name;
1815 if (strcmp (mount_point->mount_path, "/") == 0)
1816 name = g_strdup (_("Filesystem root"));
1817 else
1818 name = g_filename_display_basename (mount_point->mount_path);
1820 return name;
1824 * g_unix_mount_point_guess_icon:
1825 * @mount_point: a #GUnixMountPoint
1827 * Guesses the icon of a Unix mount point.
1829 * Returns: a #GIcon
1831 GIcon *
1832 g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
1834 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE));
1838 * g_unix_mount_guess_can_eject:
1839 * @mount_entry: a #GUnixMountEntry
1841 * Guesses whether a Unix mount can be ejected.
1843 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
1845 gboolean
1846 g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
1848 GUnixMountType guessed_type;
1850 guessed_type = g_unix_mount_guess_type (mount_entry);
1851 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
1852 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
1853 return TRUE;
1855 return FALSE;
1859 * g_unix_mount_guess_should_display:
1860 * @mount_entry: a #GUnixMountEntry
1862 * Guesses whether a Unix mount should be displayed in the UI.
1864 * Returns: %TRUE if @mount_entry is deemed to be displayable.
1866 gboolean
1867 g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
1869 const char *mount_path;
1871 /* Never display internal mountpoints */
1872 if (g_unix_mount_is_system_internal (mount_entry))
1873 return FALSE;
1875 /* Only display things in /media (which are generally user mountable)
1876 and home dir (fuse stuff) */
1877 mount_path = mount_entry->mount_path;
1878 if (mount_path != NULL)
1880 if (g_str_has_prefix (mount_path, "/media/")) {
1881 char *path;
1882 /* Avoid displaying mounts that are not accessible to the user.
1884 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
1885 * want to avoid g_access() for every mount point.
1887 path = g_path_get_dirname (mount_path);
1888 if (g_str_has_prefix (path, "/media/"))
1890 if (g_access (path, R_OK|X_OK) != 0) {
1891 g_free (path);
1892 return FALSE;
1895 g_free (path);
1896 return TRUE;
1899 if (g_str_has_prefix (mount_path, g_get_home_dir ()) && mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
1900 return TRUE;
1903 return FALSE;
1907 * g_unix_mount_point_guess_can_eject:
1908 * @mount_point: a #GUnixMountPoint
1910 * Guesses whether a Unix mount point can be ejected.
1912 * Returns: %TRUE if @mount_point is deemed to be ejectable.
1914 gboolean
1915 g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
1917 GUnixMountType guessed_type;
1919 guessed_type = g_unix_mount_point_guess_type (mount_point);
1920 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
1921 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
1922 return TRUE;
1924 return FALSE;
1928 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
1929 static void
1930 _canonicalize_filename (gchar *filename)
1932 gchar *p, *q;
1933 gboolean last_was_slash = FALSE;
1935 p = filename;
1936 q = filename;
1938 while (*p)
1940 if (*p == G_DIR_SEPARATOR)
1942 if (!last_was_slash)
1943 *q++ = G_DIR_SEPARATOR;
1945 last_was_slash = TRUE;
1947 else
1949 if (last_was_slash && *p == '.')
1951 if (*(p + 1) == G_DIR_SEPARATOR ||
1952 *(p + 1) == '\0')
1954 if (*(p + 1) == '\0')
1955 break;
1957 p += 1;
1959 else if (*(p + 1) == '.' &&
1960 (*(p + 2) == G_DIR_SEPARATOR ||
1961 *(p + 2) == '\0'))
1963 if (q > filename + 1)
1965 q--;
1966 while (q > filename + 1 &&
1967 *(q - 1) != G_DIR_SEPARATOR)
1968 q--;
1971 if (*(p + 2) == '\0')
1972 break;
1974 p += 2;
1976 else
1978 *q++ = *p;
1979 last_was_slash = FALSE;
1982 else
1984 *q++ = *p;
1985 last_was_slash = FALSE;
1989 p++;
1992 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
1993 q--;
1995 *q = '\0';
1998 static char *
1999 _resolve_symlink (const char *file)
2001 GError *error;
2002 char *dir;
2003 char *link;
2004 char *f;
2005 char *f1;
2007 f = g_strdup (file);
2009 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) {
2010 link = g_file_read_link (f, &error);
2011 if (link == NULL) {
2012 g_error_free (error);
2013 g_free (f);
2014 f = NULL;
2015 goto out;
2018 dir = g_path_get_dirname (f);
2019 f1 = g_strdup_printf ("%s/%s", dir, link);
2020 g_free (dir);
2021 g_free (link);
2022 g_free (f);
2023 f = f1;
2026 out:
2027 if (f != NULL)
2028 _canonicalize_filename (f);
2029 return f;
2032 #ifdef HAVE_MNTENT_H
2033 static const char *
2034 _resolve_dev_root (void)
2036 static gboolean have_real_dev_root = FALSE;
2037 static char real_dev_root[256];
2038 struct stat statbuf;
2040 /* see if it's cached already */
2041 if (have_real_dev_root)
2042 goto found;
2044 /* otherwise we're going to find it right away.. */
2045 have_real_dev_root = TRUE;
2047 if (stat ("/dev/root", &statbuf) == 0) {
2048 if (! S_ISLNK (statbuf.st_mode)) {
2049 dev_t root_dev = statbuf.st_dev;
2050 FILE *f;
2051 char buf[1024];
2053 /* see if device with similar major:minor as /dev/root is mention
2054 * in /etc/mtab (it usually is)
2056 f = fopen ("/etc/mtab", "r");
2057 if (f != NULL) {
2058 struct mntent *entp;
2059 #ifdef HAVE_GETMNTENT_R
2060 struct mntent ent;
2061 while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL) {
2062 #else
2063 G_LOCK (getmntent);
2064 while ((entp = getmntent (f)) != NULL) {
2065 #endif
2066 if (stat (entp->mnt_fsname, &statbuf) == 0 &&
2067 statbuf.st_dev == root_dev) {
2068 strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
2069 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2070 fclose (f);
2071 goto found;
2075 endmntent (f);
2077 #ifndef HAVE_GETMNTENT_R
2078 G_UNLOCK (getmntent);
2079 #endif
2082 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2084 } else {
2085 char *resolved;
2086 resolved = _resolve_symlink ("/dev/root");
2087 if (resolved != NULL) {
2088 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
2089 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2090 g_free (resolved);
2091 goto found;
2096 /* bah sucks.. */
2097 strcpy (real_dev_root, "/dev/root");
2099 found:
2100 return real_dev_root;
2102 #endif
2104 #define __G_UNIX_MOUNTS_C__
2105 #include "gioaliasdef.c"