Fix the build
[glib.git] / gio / gunixmounts.c
blob1713df30667f718bb91879e18f711137c8cc4449
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 NULL
280 const char *ignore_devices[] = {
281 "none",
282 "sunrpc",
283 "devpts",
284 "nfsd",
285 "/dev/loop",
286 "/dev/vn",
287 NULL
290 if (is_in (fs, ignore_fs))
291 return TRUE;
293 if (is_in (device, ignore_devices))
294 return TRUE;
296 if (g_unix_is_mount_path_system_internal (mountpoint))
297 return TRUE;
299 return FALSE;
302 #ifdef HAVE_MNTENT_H
304 static char *
305 get_mtab_read_file (void)
307 #ifdef _PATH_MOUNTED
308 # ifdef __linux__
309 return "/proc/mounts";
310 # else
311 return _PATH_MOUNTED;
312 # endif
313 #else
314 return "/etc/mtab";
315 #endif
318 static char *
319 get_mtab_monitor_file (void)
321 #ifdef _PATH_MOUNTED
322 return _PATH_MOUNTED;
323 #else
324 return "/etc/mtab";
325 #endif
328 #ifndef HAVE_GETMNTENT_R
329 G_LOCK_DEFINE_STATIC(getmntent);
330 #endif
332 static GList *
333 _g_get_unix_mounts ()
335 #ifdef HAVE_GETMNTENT_R
336 struct mntent ent;
337 char buf[1024];
338 #endif
339 struct mntent *mntent;
340 FILE *file;
341 char *read_file;
342 GUnixMountEntry *mount_entry;
343 GHashTable *mounts_hash;
344 GList *return_list;
346 read_file = get_mtab_read_file ();
348 file = setmntent (read_file, "r");
349 if (file == NULL)
350 return NULL;
352 return_list = NULL;
354 mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
356 #ifdef HAVE_GETMNTENT_R
357 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
358 #else
359 G_LOCK (getmntent);
360 while ((mntent = getmntent (file)) != NULL)
361 #endif
363 /* ignore any mnt_fsname that is repeated and begins with a '/'
365 * We do this to avoid being fooled by --bind mounts, since
366 * these have the same device as the location they bind to.
367 * Its not an ideal solution to the problem, but it's likely that
368 * the most important mountpoint is first and the --bind ones after
369 * that aren't as important. So it should work.
371 * The '/' is to handle procfs, tmpfs and other no device mounts.
373 if (mntent->mnt_fsname != NULL &&
374 mntent->mnt_fsname[0] == '/' &&
375 g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
376 continue;
378 mount_entry = g_new0 (GUnixMountEntry, 1);
379 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
380 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
381 mount_entry->device_path = g_strdup (_resolve_dev_root ());
382 else
383 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
384 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
386 #if defined (HAVE_HASMNTOPT)
387 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
388 mount_entry->is_read_only = TRUE;
389 #endif
391 mount_entry->is_system_internal =
392 guess_system_internal (mount_entry->mount_path,
393 mount_entry->filesystem_type,
394 mount_entry->device_path);
396 g_hash_table_insert (mounts_hash,
397 mount_entry->device_path,
398 mount_entry->device_path);
400 return_list = g_list_prepend (return_list, mount_entry);
402 g_hash_table_destroy (mounts_hash);
404 endmntent (file);
406 #ifndef HAVE_GETMNTENT_R
407 G_UNLOCK (getmntent);
408 #endif
410 return g_list_reverse (return_list);
413 #elif defined (HAVE_SYS_MNTTAB_H)
415 G_LOCK_DEFINE_STATIC(getmntent);
417 static char *
418 get_mtab_read_file (void)
420 #ifdef _PATH_MOUNTED
421 return _PATH_MOUNTED;
422 #else
423 return "/etc/mnttab";
424 #endif
427 static char *
428 get_mtab_monitor_file (void)
430 return get_mtab_read_file ();
433 static GList *
434 _g_get_unix_mounts (void)
436 struct mnttab mntent;
437 FILE *file;
438 char *read_file;
439 GUnixMountEntry *mount_entry;
440 GList *return_list;
442 read_file = get_mtab_read_file ();
444 file = setmntent (read_file, "r");
445 if (file == NULL)
446 return NULL;
448 return_list = NULL;
450 G_LOCK (getmntent);
451 while (! getmntent (file, &mntent))
453 mount_entry = g_new0 (GUnixMountEntry, 1);
455 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
456 mount_entry->device_path = g_strdup (mntent.mnt_special);
457 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
459 #if defined (HAVE_HASMNTOPT)
460 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
461 mount_entry->is_read_only = TRUE;
462 #endif
464 mount_entry->is_system_internal =
465 guess_system_internal (mount_entry->mount_path,
466 mount_entry->filesystem_type,
467 mount_entry->device_path);
469 return_list = g_list_prepend (return_list, mount_entry);
472 endmntent (file);
474 G_UNLOCK (getmntent);
476 return g_list_reverse (return_list);
479 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
481 static char *
482 get_mtab_monitor_file (void)
484 return NULL;
487 static GList *
488 _g_get_unix_mounts (void)
490 struct vfs_ent *fs_info;
491 struct vmount *vmount_info;
492 int vmount_number;
493 unsigned int vmount_size;
494 int current;
495 GList *return_list;
497 if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
499 g_warning ("Unable to know the number of mounted volumes\n");
501 return NULL;
504 vmount_info = (struct vmount*)g_malloc (vmount_size);
506 vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
508 if (vmount_info->vmt_revision != VMT_REVISION)
509 g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
511 if (vmount_number < 0)
513 g_warning ("Unable to recover mounted volumes information\n");
515 g_free (vmount_info);
516 return NULL;
519 return_list = NULL;
520 while (vmount_number > 0)
522 mount_entry = g_new0 (GUnixMountEntry, 1);
524 mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT));
525 mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB));
526 /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
527 mount_entry->is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
529 fs_info = getvfsbytype (vmount_info->vmt_gfstype);
531 if (fs_info == NULL)
532 mount_entry->filesystem_type = g_strdup ("unknown");
533 else
534 mount_entry->filesystem_type = g_strdup (fs_info->vfsent_name);
536 mount_entry->is_system_internal =
537 guess_system_internal (mount_entry->mount_path,
538 mount_entry->filesystem_type,
539 mount_entry->device_path);
541 return_list = g_list_prepend (return_list, mount_entry);
543 vmount_info = (struct vmount *)( (char*)vmount_info
544 + vmount_info->vmt_length);
545 vmount_number--;
549 g_free (vmount_info);
551 return g_list_reverse (return_list);
554 #elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
556 static char *
557 get_mtab_monitor_file (void)
559 return NULL;
562 static GList *
563 _g_get_unix_mounts (void)
565 struct statfs *mntent = NULL;
566 int num_mounts, i;
567 GUnixMountEntry *mount_entry;
568 GList *return_list;
570 /* Pass MNT_NOWAIT to avoid blocking trying to update NFS mounts. */
571 if ((num_mounts = getmntinfo (&mntent, MNT_NOWAIT)) == 0)
572 return NULL;
574 return_list = NULL;
576 for (i = 0; i < num_mounts; i++)
578 mount_entry = g_new0 (GUnixMountEntry, 1);
580 mount_entry->mount_path = g_strdup (mntent[i].f_mntonname);
581 mount_entry->device_path = g_strdup (mntent[i].f_mntfromname);
582 mount_entry->filesystem_type = g_strdup (mntent[i].f_fstypename);
583 if (mntent[i].f_flags & MNT_RDONLY)
584 mount_entry->is_read_only = TRUE;
586 mount_entry->is_system_internal =
587 guess_system_internal (mount_entry->mount_path,
588 mount_entry->filesystem_type,
589 mount_entry->device_path);
591 return_list = g_list_prepend (return_list, mount_entry);
594 return g_list_reverse (return_list);
596 #else
597 #error No _g_get_unix_mounts() implementation for system
598 #endif
600 /* _g_get_unix_mount_points():
601 * read the fstab.
602 * don't return swap and ignore mounts.
605 static char *
606 get_fstab_file (void)
608 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
609 /* AIX */
610 return "/etc/filesystems";
611 #elif defined(_PATH_MNTTAB)
612 return _PATH_MNTTAB;
613 #elif defined(VFSTAB)
614 return VFSTAB;
615 #else
616 return "/etc/fstab";
617 #endif
620 #ifdef HAVE_MNTENT_H
621 static GList *
622 _g_get_unix_mount_points (void)
624 #ifdef HAVE_GETMNTENT_R
625 struct mntent ent;
626 char buf[1024];
627 #endif
628 struct mntent *mntent;
629 FILE *file;
630 char *read_file;
631 GUnixMountPoint *mount_entry;
632 GList *return_list;
634 read_file = get_fstab_file ();
636 file = setmntent (read_file, "r");
637 if (file == NULL)
638 return NULL;
640 return_list = NULL;
642 #ifdef HAVE_GETMNTENT_R
643 while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
644 #else
645 G_LOCK (getmntent);
646 while ((mntent = getmntent (file)) != NULL)
647 #endif
649 if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
650 (strcmp (mntent->mnt_dir, "swap") == 0))
651 continue;
653 mount_entry = g_new0 (GUnixMountPoint, 1);
654 mount_entry->mount_path = g_strdup (mntent->mnt_dir);
655 if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
656 mount_entry->device_path = g_strdup (_resolve_dev_root ());
657 else
658 mount_entry->device_path = g_strdup (mntent->mnt_fsname);
659 mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
661 #ifdef HAVE_HASMNTOPT
662 if (hasmntopt (mntent, MNTOPT_RO) != NULL)
663 mount_entry->is_read_only = TRUE;
665 if (hasmntopt (mntent, "loop") != NULL)
666 mount_entry->is_loopback = TRUE;
668 #endif
670 if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
671 #ifdef HAVE_HASMNTOPT
672 || (hasmntopt (mntent, "user") != NULL
673 && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
674 || hasmntopt (mntent, "pamconsole") != NULL
675 || hasmntopt (mntent, "users") != NULL
676 || hasmntopt (mntent, "owner") != NULL
677 #endif
679 mount_entry->is_user_mountable = TRUE;
681 return_list = g_list_prepend (return_list, mount_entry);
684 endmntent (file);
686 #ifndef HAVE_GETMNTENT_R
687 G_UNLOCK (getmntent);
688 #endif
690 return g_list_reverse (return_list);
693 #elif defined (HAVE_SYS_MNTTAB_H)
695 static GList *
696 _g_get_unix_mount_points (void)
698 struct mnttab mntent;
699 FILE *file;
700 char *read_file;
701 GUnixMountPoint *mount_entry;
702 GList *return_list;
704 read_file = get_fstab_file ();
706 file = setmntent (read_file, "r");
707 if (file == NULL)
708 return NULL;
710 return_list = NULL;
712 G_LOCK (getmntent);
713 while (! getmntent (file, &mntent))
715 if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
716 (strcmp (mntent.mnt_mountp, "swap") == 0))
717 continue;
719 mount_entry = g_new0 (GUnixMountPoint, 1);
721 mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
722 mount_entry->device_path = g_strdup (mntent.mnt_special);
723 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
725 #ifdef HAVE_HASMNTOPT
726 if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
727 mount_entry->is_read_only = TRUE;
729 if (hasmntopt (&mntent, "lofs") != NULL)
730 mount_entry->is_loopback = TRUE;
731 #endif
733 if ((mntent.mnt_fstype != NULL)
734 #ifdef HAVE_HASMNTOPT
735 || (hasmntopt (&mntent, "user") != NULL
736 && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
737 || hasmntopt (&mntent, "pamconsole") != NULL
738 || hasmntopt (&mntent, "users") != NULL
739 || hasmntopt (&mntent, "owner") != NULL
740 #endif
742 mount_entry->is_user_mountable = TRUE;
745 return_list = g_list_prepend (return_list, mount_entry);
748 endmntent (file);
749 G_UNLOCK (getmntent);
751 return g_list_reverse (return_list);
753 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
755 /* functions to parse /etc/filesystems on aix */
757 /* read character, ignoring comments (begin with '*', end with '\n' */
758 static int
759 aix_fs_getc (FILE *fd)
761 int c;
763 while ((c = getc (fd)) == '*')
765 while (((c = getc (fd)) != '\n') && (c != EOF))
770 /* eat all continuous spaces in a file */
771 static int
772 aix_fs_ignorespace (FILE *fd)
774 int c;
776 while ((c = aix_fs_getc (fd)) != EOF)
778 if (!g_ascii_isspace (c))
780 ungetc (c,fd);
781 return c;
785 return EOF;
788 /* read one word from file */
789 static int
790 aix_fs_getword (FILE *fd,
791 char *word)
793 int c;
795 aix_fs_ignorespace (fd);
797 while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
799 if (c == '"')
801 while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
802 *word++ = c;
803 else
804 *word++ = c;
807 *word = 0;
809 return c;
812 typedef struct {
813 char mnt_mount[PATH_MAX];
814 char mnt_special[PATH_MAX];
815 char mnt_fstype[16];
816 char mnt_options[128];
817 } AixMountTableEntry;
819 /* read mount points properties */
820 static int
821 aix_fs_get (FILE *fd,
822 AixMountTableEntry *prop)
824 static char word[PATH_MAX] = { 0 };
825 char value[PATH_MAX];
827 /* read stanza */
828 if (word[0] == 0)
830 if (aix_fs_getword (fd, word) == EOF)
831 return EOF;
834 word[strlen(word) - 1] = 0;
835 strcpy (prop->mnt_mount, word);
837 /* read attributes and value */
839 while (aix_fs_getword (fd, word) != EOF)
841 /* test if is attribute or new stanza */
842 if (word[strlen(word) - 1] == ':')
843 return 0;
845 /* read "=" */
846 aix_fs_getword (fd, value);
848 /* read value */
849 aix_fs_getword (fd, value);
851 if (strcmp (word, "dev") == 0)
852 strcpy (prop->mnt_special, value);
853 else if (strcmp (word, "vfs") == 0)
854 strcpy (prop->mnt_fstype, value);
855 else if (strcmp (word, "options") == 0)
856 strcpy(prop->mnt_options, value);
859 return 0;
862 static GList *
863 _g_get_unix_mount_points (void)
865 struct mntent *mntent;
866 FILE *file;
867 char *read_file;
868 GUnixMountPoint *mount_entry;
869 AixMountTableEntry mntent;
870 GList *return_list;
872 read_file = get_fstab_file ();
874 file = setmntent (read_file, "r");
875 if (file == NULL)
876 return NULL;
878 return_list = NULL;
880 while (!aix_fs_get (file, &mntent))
882 if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
884 mount_entry = g_new0 (GUnixMountPoint, 1);
887 mount_entry->mount_path = g_strdup (mntent.mnt_mount);
888 mount_entry->device_path = g_strdup (mntent.mnt_special);
889 mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
890 mount_entry->is_read_only = TRUE;
891 mount_entry->is_user_mountable = TRUE;
893 return_list = g_list_prepend (return_list, mount_entry);
897 endmntent (file);
899 return g_list_reverse (return_list);
902 #elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
904 static GList *
905 _g_get_unix_mount_points (void)
907 struct fstab *fstab = NULL;
908 GUnixMountPoint *mount_entry;
909 GList *return_list;
910 #ifdef HAVE_SYS_SYSCTL_H
911 int usermnt = 0;
912 size_t len = sizeof(usermnt);
913 struct stat sb;
914 #endif
916 if (!setfsent ())
917 return NULL;
919 return_list = NULL;
921 #ifdef HAVE_SYS_SYSCTL_H
922 #if defined(HAVE_SYSCTLBYNAME)
923 sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
924 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
926 int mib[2];
928 mib[0] = CTL_VFS;
929 mib[1] = VFS_USERMOUNT;
930 sysctl (mib, 2, &usermnt, &len, NULL, 0);
932 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
934 int mib[2];
936 mib[0] = CTL_KERN;
937 mib[1] = KERN_USERMOUNT;
938 sysctl (mib, 2, &usermnt, &len, NULL, 0);
940 #endif
941 #endif
943 while ((fstab = getfsent ()) != NULL)
945 if (strcmp (fstab->fs_vfstype, "swap") == 0)
946 continue;
948 mount_entry = g_new0 (GUnixMountPoint, 1);
950 mount_entry->mount_path = g_strdup (fstab->fs_file);
951 mount_entry->device_path = g_strdup (fstab->fs_spec);
952 mount_entry->filesystem_type = g_strdup (fstab->fs_vfstype);
954 if (strcmp (fstab->fs_type, "ro") == 0)
955 mount_entry->is_read_only = TRUE;
957 #ifdef HAVE_SYS_SYSCTL_H
958 if (usermnt != 0)
960 uid_t uid = getuid ();
961 if (stat (fstab->fs_file, &sb) == 0)
963 if (uid == 0 || sb.st_uid == uid)
964 mount_entry->is_user_mountable = TRUE;
967 #endif
969 return_list = g_list_prepend (return_list, mount_entry);
972 endfsent ();
974 return g_list_reverse (return_list);
976 #else
977 #error No g_get_mount_table() implementation for system
978 #endif
980 static guint64
981 get_mounts_timestamp (void)
983 const char *monitor_file;
984 struct stat buf;
986 monitor_file = get_mtab_monitor_file ();
987 if (monitor_file)
989 if (stat (monitor_file, &buf) == 0)
990 return (guint64)buf.st_mtime;
992 return 0;
995 static guint64
996 get_mount_points_timestamp (void)
998 const char *monitor_file;
999 struct stat buf;
1001 monitor_file = get_fstab_file ();
1002 if (monitor_file)
1004 if (stat (monitor_file, &buf) == 0)
1005 return (guint64)buf.st_mtime;
1007 return 0;
1011 * g_unix_mounts_get:
1012 * @time_read: guint64 to contain a timestamp.
1014 * Gets a #GList of strings containing the unix mounts.
1015 * If @time_read is set, it will be filled with the mount
1016 * timestamp, allowing for checking if the mounts have changed
1017 * with g_unix_mounts_changed_since().
1019 * Returns: a #GList of the UNIX mounts.
1021 GList *
1022 g_unix_mounts_get (guint64 *time_read)
1024 if (time_read)
1025 *time_read = get_mounts_timestamp ();
1027 return _g_get_unix_mounts ();
1031 * g_unix_mount_at:
1032 * @mount_path: path for a possible unix mount.
1033 * @time_read: guint64 to contain a timestamp.
1035 * Gets a #GUnixMountEntry for a given mount path. If @time_read
1036 * is set, it will be filled with a unix timestamp for checking
1037 * if the mounts have changed since with g_unix_mounts_changed_since().
1039 * Returns: a #GUnixMount.
1041 GUnixMountEntry *
1042 g_unix_mount_at (const char *mount_path,
1043 guint64 *time_read)
1045 GList *mounts, *l;
1046 GUnixMountEntry *mount_entry, *found;
1048 mounts = g_unix_mounts_get (time_read);
1050 found = NULL;
1051 for (l = mounts; l != NULL; l = l->next)
1053 mount_entry = l->data;
1055 if (strcmp (mount_path, mount_entry->mount_path) == 0)
1056 found = mount_entry;
1057 else
1058 g_unix_mount_free (mount_entry);
1061 g_list_free (mounts);
1063 return found;
1067 * g_unix_mount_points_get:
1068 * @time_read: guint64 to contain a timestamp.
1070 * Gets a #GList of strings containing the unix mount points.
1071 * If @time_read is set, it will be filled with the mount timestamp,
1072 * allowing for checking if the mounts have changed with
1073 * g_unix_mounts_points_changed_since().
1075 * Returns: a #GList of the UNIX mountpoints.
1077 GList *
1078 g_unix_mount_points_get (guint64 *time_read)
1080 if (time_read)
1081 *time_read = get_mount_points_timestamp ();
1083 return _g_get_unix_mount_points ();
1087 * g_unix_mounts_changed_since:
1088 * @time: guint64 to contain a timestamp.
1090 * Checks if the unix mounts have changed since a given unix time.
1092 * Returns: %TRUE if the mounts have changed since @time.
1094 gboolean
1095 g_unix_mounts_changed_since (guint64 time)
1097 return get_mounts_timestamp () != time;
1101 * g_unix_mount_points_changed_since:
1102 * @time: guint64 to contain a timestamp.
1104 * Checks if the unix mount points have changed since a given unix time.
1106 * Returns: %TRUE if the mount points have changed since @time.
1108 gboolean
1109 g_unix_mount_points_changed_since (guint64 time)
1111 return get_mount_points_timestamp () != time;
1114 static void
1115 g_unix_mount_monitor_finalize (GObject *object)
1117 GUnixMountMonitor *monitor;
1119 monitor = G_UNIX_MOUNT_MONITOR (object);
1121 if (monitor->fstab_monitor)
1123 g_file_monitor_cancel (monitor->fstab_monitor);
1124 g_object_unref (monitor->fstab_monitor);
1127 if (monitor->mtab_monitor)
1129 g_file_monitor_cancel (monitor->mtab_monitor);
1130 g_object_unref (monitor->mtab_monitor);
1133 the_mount_monitor = NULL;
1135 if (G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize)
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:
1149 * Emitted when the unix mounts have changed.
1150 **/
1151 signals[MOUNTS_CHANGED] =
1152 g_signal_new ("mounts_changed",
1153 G_TYPE_FROM_CLASS (klass),
1154 G_SIGNAL_RUN_LAST,
1156 NULL, NULL,
1157 g_cclosure_marshal_VOID__VOID,
1158 G_TYPE_NONE, 0);
1160 * GUnixMountMonitor::mountpoints-changed:
1162 * Emitted when the unix mount points have changed.
1164 signals[MOUNTPOINTS_CHANGED] =
1165 g_signal_new ("mountpoints_changed",
1166 G_TYPE_FROM_CLASS (klass),
1167 G_SIGNAL_RUN_LAST,
1169 NULL, NULL,
1170 g_cclosure_marshal_VOID__VOID,
1171 G_TYPE_NONE, 0);
1174 static void
1175 fstab_file_changed (GFileMonitor *monitor,
1176 GFile *file,
1177 GFile *other_file,
1178 GFileMonitorEvent event_type,
1179 gpointer user_data)
1181 GUnixMountMonitor *mount_monitor;
1183 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1184 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1185 event_type != G_FILE_MONITOR_EVENT_DELETED)
1186 return;
1188 mount_monitor = user_data;
1189 g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0);
1192 static void
1193 mtab_file_changed (GFileMonitor *monitor,
1194 GFile *file,
1195 GFile *other_file,
1196 GFileMonitorEvent event_type,
1197 gpointer user_data)
1199 GUnixMountMonitor *mount_monitor;
1201 if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1202 event_type != G_FILE_MONITOR_EVENT_CREATED &&
1203 event_type != G_FILE_MONITOR_EVENT_DELETED)
1204 return;
1206 mount_monitor = user_data;
1207 g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
1210 static void
1211 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1213 GFile *file;
1215 if (get_fstab_file () != NULL)
1217 file = g_file_new_for_path (get_fstab_file ());
1218 monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1219 g_object_unref (file);
1221 g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor);
1224 if (get_mtab_monitor_file () != NULL)
1226 file = g_file_new_for_path (get_mtab_monitor_file ());
1227 monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
1228 g_object_unref (file);
1230 g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor);
1235 * g_unix_mount_monitor_set_rate_limit:
1236 * @mount_monitor: a #GUnixMountMonitor.
1237 * @limit_msecs: a integer with the limit in milliseconds to
1238 * poll for changes.
1240 * Sets the rate limit to which the @mount_monitor will report
1241 * consecutive change events to the mount and mount point entry files.
1243 * Since: 2.18
1245 void
1246 g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
1247 int limit_msec)
1249 g_return_if_fail (G_IS_UNIX_MOUNT_MONITOR (mount_monitor));
1251 if (mount_monitor->fstab_monitor != NULL)
1252 g_file_monitor_set_rate_limit (mount_monitor->fstab_monitor, limit_msec);
1254 if (mount_monitor->mtab_monitor != NULL)
1255 g_file_monitor_set_rate_limit (mount_monitor->mtab_monitor, limit_msec);
1259 * g_unix_mount_monitor_new:
1261 * Gets a new #GUnixMountMonitor. The default rate limit for which the
1262 * monitor will report consecutive changes for the mount and mount
1263 * point entry files is the default for a #GFileMonitor. Use
1264 * g_unix_mount_monitor_set_rate_limit() to change this.
1266 * Returns: a #GUnixMountMonitor.
1268 GUnixMountMonitor *
1269 g_unix_mount_monitor_new (void)
1271 if (the_mount_monitor == NULL)
1273 the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL);
1274 return the_mount_monitor;
1277 return g_object_ref (the_mount_monitor);
1281 * g_unix_mount_free:
1282 * @mount_entry: a #GUnixMount.
1284 * Frees a unix mount.
1286 void
1287 g_unix_mount_free (GUnixMountEntry *mount_entry)
1289 g_return_if_fail (mount_entry != NULL);
1291 g_free (mount_entry->mount_path);
1292 g_free (mount_entry->device_path);
1293 g_free (mount_entry->filesystem_type);
1294 g_free (mount_entry);
1298 * g_unix_mount_point_free:
1299 * @mount_point: unix mount point to free.
1301 * Frees a unix mount point.
1303 void
1304 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1306 g_return_if_fail (mount_point != NULL);
1308 g_free (mount_point->mount_path);
1309 g_free (mount_point->device_path);
1310 g_free (mount_point->filesystem_type);
1311 g_free (mount_point);
1314 static int
1315 strcmp_null (const char *str1,
1316 const char *str2)
1318 if (str1 == str2)
1319 return 0;
1320 if (str1 == NULL && str2 != NULL)
1321 return -1;
1322 if (str1 != NULL && str2 == NULL)
1323 return 1;
1324 return strcmp (str1, str2);
1328 * g_unix_mount_compare:
1329 * @mount1: first #GUnixMountEntry to compare.
1330 * @mount2: second #GUnixMountEntry to compare.
1332 * Compares two unix mounts.
1334 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1335 * or less than @mount2, respectively.
1337 gint
1338 g_unix_mount_compare (GUnixMountEntry *mount1,
1339 GUnixMountEntry *mount2)
1341 int res;
1343 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1345 res = strcmp_null (mount1->mount_path, mount2->mount_path);
1346 if (res != 0)
1347 return res;
1349 res = strcmp_null (mount1->device_path, mount2->device_path);
1350 if (res != 0)
1351 return res;
1353 res = strcmp_null (mount1->filesystem_type, mount2->filesystem_type);
1354 if (res != 0)
1355 return res;
1357 res = mount1->is_read_only - mount2->is_read_only;
1358 if (res != 0)
1359 return res;
1361 return 0;
1365 * g_unix_mount_get_mount_path:
1366 * @mount_entry: input #GUnixMountEntry to get the mount path for.
1368 * Gets the mount path for a unix mount.
1370 * Returns: the mount path for @mount_entry.
1372 const char *
1373 g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
1375 g_return_val_if_fail (mount_entry != NULL, NULL);
1377 return mount_entry->mount_path;
1381 * g_unix_mount_get_device_path:
1382 * @mount_entry: a #GUnixMount.
1384 * Gets the device path for a unix mount.
1386 * Returns: a string containing the device path.
1388 const char *
1389 g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
1391 g_return_val_if_fail (mount_entry != NULL, NULL);
1393 return mount_entry->device_path;
1397 * g_unix_mount_get_fs_type:
1398 * @mount_entry: a #GUnixMount.
1400 * Gets the filesystem type for the unix mount.
1402 * Returns: a string containing the file system type.
1404 const char *
1405 g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
1407 g_return_val_if_fail (mount_entry != NULL, NULL);
1409 return mount_entry->filesystem_type;
1413 * g_unix_mount_is_readonly:
1414 * @mount_entry: a #GUnixMount.
1416 * Checks if a unix mount is mounted read only.
1418 * Returns: %TRUE if @mount_entry is read only.
1420 gboolean
1421 g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
1423 g_return_val_if_fail (mount_entry != NULL, FALSE);
1425 return mount_entry->is_read_only;
1429 * g_unix_mount_is_system_internal:
1430 * @mount_entry: a #GUnixMount.
1432 * Checks if a unix mount is a system path.
1434 * Returns: %TRUE if the unix mount is for a system path.
1436 gboolean
1437 g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
1439 g_return_val_if_fail (mount_entry != NULL, FALSE);
1441 return mount_entry->is_system_internal;
1445 * g_unix_mount_point_compare:
1446 * @mount1: a #GUnixMount.
1447 * @mount2: a #GUnixMount.
1449 * Compares two unix mount points.
1451 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
1452 * or less than @mount2, respectively.
1454 gint
1455 g_unix_mount_point_compare (GUnixMountPoint *mount1,
1456 GUnixMountPoint *mount2)
1458 int res;
1460 g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1462 res = strcmp_null (mount1->mount_path, mount2->mount_path);
1463 if (res != 0)
1464 return res;
1466 res = strcmp_null (mount1->device_path, mount2->device_path);
1467 if (res != 0)
1468 return res;
1470 res = strcmp_null (mount1->filesystem_type, mount2->filesystem_type);
1471 if (res != 0)
1472 return res;
1474 res = mount1->is_read_only - mount2->is_read_only;
1475 if (res != 0)
1476 return res;
1478 res = mount1->is_user_mountable - mount2->is_user_mountable;
1479 if (res != 0)
1480 return res;
1482 res = mount1->is_loopback - mount2->is_loopback;
1483 if (res != 0)
1484 return res;
1486 return 0;
1490 * g_unix_mount_point_get_mount_path:
1491 * @mount_point: a #GUnixMountPoint.
1493 * Gets the mount path for a unix mount point.
1495 * Returns: a string containing the mount path.
1497 const char *
1498 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
1500 g_return_val_if_fail (mount_point != NULL, NULL);
1502 return mount_point->mount_path;
1506 * g_unix_mount_point_get_device_path:
1507 * @mount_point: a #GUnixMountPoint.
1509 * Gets the device path for a unix mount point.
1511 * Returns: a string containing the device path.
1513 const char *
1514 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
1516 g_return_val_if_fail (mount_point != NULL, NULL);
1518 return mount_point->device_path;
1522 * g_unix_mount_point_get_fs_type:
1523 * @mount_point: a #GUnixMountPoint.
1525 * Gets the file system type for the mount point.
1527 * Returns: a string containing the file system type.
1529 const char *
1530 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
1532 g_return_val_if_fail (mount_point != NULL, NULL);
1534 return mount_point->filesystem_type;
1538 * g_unix_mount_point_is_readonly:
1539 * @mount_point: a #GUnixMountPoint.
1541 * Checks if a unix mount point is read only.
1543 * Returns: %TRUE if a mount point is read only.
1545 gboolean
1546 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
1548 g_return_val_if_fail (mount_point != NULL, FALSE);
1550 return mount_point->is_read_only;
1554 * g_unix_mount_point_is_user_mountable:
1555 * @mount_point: a #GUnixMountPoint.
1557 * Checks if a unix mount point is mountable by the user.
1559 * Returns: %TRUE if the mount point is user mountable.
1561 gboolean
1562 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
1564 g_return_val_if_fail (mount_point != NULL, FALSE);
1566 return mount_point->is_user_mountable;
1570 * g_unix_mount_point_is_loopback:
1571 * @mount_point: a #GUnixMountPoint.
1573 * Checks if a unix mount point is a loopback device.
1575 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
1577 gboolean
1578 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
1580 g_return_val_if_fail (mount_point != NULL, FALSE);
1582 return mount_point->is_loopback;
1585 static GUnixMountType
1586 guess_mount_type (const char *mount_path,
1587 const char *device_path,
1588 const char *filesystem_type)
1590 GUnixMountType type;
1591 char *basename;
1593 type = G_UNIX_MOUNT_TYPE_UNKNOWN;
1595 if ((strcmp (filesystem_type, "udf") == 0) ||
1596 (strcmp (filesystem_type, "iso9660") == 0) ||
1597 (strcmp (filesystem_type, "cd9660") == 0))
1598 type = G_UNIX_MOUNT_TYPE_CDROM;
1599 else if ((strcmp (filesystem_type, "nfs") == 0) ||
1600 (strcmp (filesystem_type, "nfs4") == 0))
1601 type = G_UNIX_MOUNT_TYPE_NFS;
1602 else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
1603 g_str_has_prefix (device_path, "/dev/fd") ||
1604 g_str_has_prefix (device_path, "/dev/floppy"))
1605 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1606 else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
1607 g_str_has_prefix (device_path, "/dev/acd") ||
1608 g_str_has_prefix (device_path, "/dev/cd"))
1609 type = G_UNIX_MOUNT_TYPE_CDROM;
1610 else if (g_str_has_prefix (device_path, "/vol/"))
1612 const char *name = mount_path + strlen ("/");
1614 if (g_str_has_prefix (name, "cdrom"))
1615 type = G_UNIX_MOUNT_TYPE_CDROM;
1616 else if (g_str_has_prefix (name, "floppy") ||
1617 g_str_has_prefix (device_path, "/vol/dev/diskette/"))
1618 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1619 else if (g_str_has_prefix (name, "rmdisk"))
1620 type = G_UNIX_MOUNT_TYPE_ZIP;
1621 else if (g_str_has_prefix (name, "jaz"))
1622 type = G_UNIX_MOUNT_TYPE_JAZ;
1623 else if (g_str_has_prefix (name, "memstick"))
1624 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1626 else
1628 basename = g_path_get_basename (mount_path);
1630 if (g_str_has_prefix (basename, "cdr") ||
1631 g_str_has_prefix (basename, "cdwriter") ||
1632 g_str_has_prefix (basename, "burn") ||
1633 g_str_has_prefix (basename, "dvdr"))
1634 type = G_UNIX_MOUNT_TYPE_CDROM;
1635 else if (g_str_has_prefix (basename, "floppy"))
1636 type = G_UNIX_MOUNT_TYPE_FLOPPY;
1637 else if (g_str_has_prefix (basename, "zip"))
1638 type = G_UNIX_MOUNT_TYPE_ZIP;
1639 else if (g_str_has_prefix (basename, "jaz"))
1640 type = G_UNIX_MOUNT_TYPE_JAZ;
1641 else if (g_str_has_prefix (basename, "camera"))
1642 type = G_UNIX_MOUNT_TYPE_CAMERA;
1643 else if (g_str_has_prefix (basename, "memstick") ||
1644 g_str_has_prefix (basename, "memory_stick") ||
1645 g_str_has_prefix (basename, "ram"))
1646 type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1647 else if (g_str_has_prefix (basename, "compact_flash"))
1648 type = G_UNIX_MOUNT_TYPE_CF;
1649 else if (g_str_has_prefix (basename, "smart_media"))
1650 type = G_UNIX_MOUNT_TYPE_SM;
1651 else if (g_str_has_prefix (basename, "sd_mmc"))
1652 type = G_UNIX_MOUNT_TYPE_SDMMC;
1653 else if (g_str_has_prefix (basename, "ipod"))
1654 type = G_UNIX_MOUNT_TYPE_IPOD;
1656 g_free (basename);
1659 if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
1660 type = G_UNIX_MOUNT_TYPE_HD;
1662 return type;
1666 * g_unix_mount_guess_type:
1667 * @mount_entry: a #GUnixMount.
1669 * Guesses the type of a unix mount. If the mount type cannot be
1670 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1672 * Returns: a #GUnixMountType.
1674 static GUnixMountType
1675 g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
1677 g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1678 g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1679 g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1680 g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1682 return guess_mount_type (mount_entry->mount_path,
1683 mount_entry->device_path,
1684 mount_entry->filesystem_type);
1688 * g_unix_mount_point_guess_type:
1689 * @mount_point: a #GUnixMountPoint.
1691 * Guesses the type of a unix mount point.
1692 * If the mount type cannot be determined,
1693 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
1695 * Returns: a #GUnixMountType.
1697 static GUnixMountType
1698 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
1700 g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1701 g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1702 g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1703 g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1705 return guess_mount_type (mount_point->mount_path,
1706 mount_point->device_path,
1707 mount_point->filesystem_type);
1710 static const char *
1711 type_to_icon (GUnixMountType type, gboolean is_mount_point)
1713 const char *icon_name;
1715 switch (type)
1717 case G_UNIX_MOUNT_TYPE_HD:
1718 if (is_mount_point)
1719 icon_name = "drive-removable-media";
1720 else
1721 icon_name = "drive-harddisk";
1722 break;
1723 case G_UNIX_MOUNT_TYPE_FLOPPY:
1724 case G_UNIX_MOUNT_TYPE_ZIP:
1725 case G_UNIX_MOUNT_TYPE_JAZ:
1726 if (is_mount_point)
1727 icon_name = "drive-removable-media";
1728 else
1729 icon_name = "media-floppy";
1730 break;
1731 case G_UNIX_MOUNT_TYPE_CDROM:
1732 if (is_mount_point)
1733 icon_name = "drive-optical";
1734 else
1735 icon_name = "media-optical";
1736 break;
1737 case G_UNIX_MOUNT_TYPE_NFS:
1738 /* TODO: Would like a better icon here... */
1739 if (is_mount_point)
1740 icon_name = "drive-removable-media";
1741 else
1742 icon_name = "drive-harddisk";
1743 break;
1744 case G_UNIX_MOUNT_TYPE_MEMSTICK:
1745 if (is_mount_point)
1746 icon_name = "drive-removable-media";
1747 else
1748 icon_name = "media-flash";
1749 break;
1750 case G_UNIX_MOUNT_TYPE_CAMERA:
1751 if (is_mount_point)
1752 icon_name = "drive-removable-media";
1753 else
1754 icon_name = "camera-photo";
1755 break;
1756 case G_UNIX_MOUNT_TYPE_IPOD:
1757 if (is_mount_point)
1758 icon_name = "drive-removable-media";
1759 else
1760 icon_name = "multimedia-player";
1761 break;
1762 case G_UNIX_MOUNT_TYPE_UNKNOWN:
1763 default:
1764 if (is_mount_point)
1765 icon_name = "drive-removable-media";
1766 else
1767 icon_name = "drive-harddisk";
1768 break;
1771 return icon_name;
1775 * g_unix_mount_guess_name:
1776 * @mount_entry: a #GUnixMountEntry
1778 * Guesses the name of a Unix mount.
1779 * The result is a translated string.
1781 * Returns: A newly allocated string that must
1782 * be freed with g_free()
1784 char *
1785 g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
1787 char *name;
1789 if (strcmp (mount_entry->mount_path, "/") == 0)
1790 name = g_strdup (_("Filesystem root"));
1791 else
1792 name = g_filename_display_basename (mount_entry->mount_path);
1794 return name;
1798 * g_unix_mount_guess_icon:
1799 * @mount_entry: a #GUnixMountEntry
1801 * Guesses the icon of a Unix mount.
1803 * Returns: a #GIcon
1805 GIcon *
1806 g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
1808 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE));
1812 * g_unix_mount_point_guess_name:
1813 * @mount_point: a #GUnixMountPoint
1815 * Guesses the name of a Unix mount point.
1816 * The result is a translated string.
1818 * Returns: A newly allocated string that must
1819 * be freed with g_free()
1821 char *
1822 g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
1824 char *name;
1826 if (strcmp (mount_point->mount_path, "/") == 0)
1827 name = g_strdup (_("Filesystem root"));
1828 else
1829 name = g_filename_display_basename (mount_point->mount_path);
1831 return name;
1835 * g_unix_mount_point_guess_icon:
1836 * @mount_point: a #GUnixMountPoint
1838 * Guesses the icon of a Unix mount point.
1840 * Returns: a #GIcon
1842 GIcon *
1843 g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
1845 return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE));
1849 * g_unix_mount_guess_can_eject:
1850 * @mount_entry: a #GUnixMountEntry
1852 * Guesses whether a Unix mount can be ejected.
1854 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
1856 gboolean
1857 g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
1859 GUnixMountType guessed_type;
1861 guessed_type = g_unix_mount_guess_type (mount_entry);
1862 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
1863 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
1864 return TRUE;
1866 return FALSE;
1870 * g_unix_mount_guess_should_display:
1871 * @mount_entry: a #GUnixMountEntry
1873 * Guesses whether a Unix mount should be displayed in the UI.
1875 * Returns: %TRUE if @mount_entry is deemed to be displayable.
1877 gboolean
1878 g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
1880 const char *mount_path;
1882 /* Never display internal mountpoints */
1883 if (g_unix_mount_is_system_internal (mount_entry))
1884 return FALSE;
1886 /* Only display things in /media (which are generally user mountable)
1887 and home dir (fuse stuff) */
1888 mount_path = mount_entry->mount_path;
1889 if (mount_path != NULL)
1891 if (g_str_has_prefix (mount_path, "/media/")) {
1892 char *path;
1893 /* Avoid displaying mounts that are not accessible to the user.
1895 * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
1896 * want to avoid g_access() for every mount point.
1898 path = g_path_get_dirname (mount_path);
1899 if (g_str_has_prefix (path, "/media/"))
1901 if (g_access (path, R_OK|X_OK) != 0) {
1902 g_free (path);
1903 return FALSE;
1906 g_free (path);
1907 return TRUE;
1910 if (g_str_has_prefix (mount_path, g_get_home_dir ()) && mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
1911 return TRUE;
1914 return FALSE;
1918 * g_unix_mount_point_guess_can_eject:
1919 * @mount_point: a #GUnixMountPoint
1921 * Guesses whether a Unix mount point can be ejected.
1923 * Returns: %TRUE if @mount_point is deemed to be ejectable.
1925 gboolean
1926 g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
1928 GUnixMountType guessed_type;
1930 guessed_type = g_unix_mount_point_guess_type (mount_point);
1931 if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
1932 guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
1933 return TRUE;
1935 return FALSE;
1939 /* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
1940 static void
1941 _canonicalize_filename (gchar *filename)
1943 gchar *p, *q;
1944 gboolean last_was_slash = FALSE;
1946 p = filename;
1947 q = filename;
1949 while (*p)
1951 if (*p == G_DIR_SEPARATOR)
1953 if (!last_was_slash)
1954 *q++ = G_DIR_SEPARATOR;
1956 last_was_slash = TRUE;
1958 else
1960 if (last_was_slash && *p == '.')
1962 if (*(p + 1) == G_DIR_SEPARATOR ||
1963 *(p + 1) == '\0')
1965 if (*(p + 1) == '\0')
1966 break;
1968 p += 1;
1970 else if (*(p + 1) == '.' &&
1971 (*(p + 2) == G_DIR_SEPARATOR ||
1972 *(p + 2) == '\0'))
1974 if (q > filename + 1)
1976 q--;
1977 while (q > filename + 1 &&
1978 *(q - 1) != G_DIR_SEPARATOR)
1979 q--;
1982 if (*(p + 2) == '\0')
1983 break;
1985 p += 2;
1987 else
1989 *q++ = *p;
1990 last_was_slash = FALSE;
1993 else
1995 *q++ = *p;
1996 last_was_slash = FALSE;
2000 p++;
2003 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
2004 q--;
2006 *q = '\0';
2009 static char *
2010 _resolve_symlink (const char *file)
2012 GError *error;
2013 char *dir;
2014 char *link;
2015 char *f;
2016 char *f1;
2018 f = g_strdup (file);
2020 while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) {
2021 link = g_file_read_link (f, &error);
2022 if (link == NULL) {
2023 g_error_free (error);
2024 g_free (f);
2025 f = NULL;
2026 goto out;
2029 dir = g_path_get_dirname (f);
2030 f1 = g_strdup_printf ("%s/%s", dir, link);
2031 g_free (dir);
2032 g_free (link);
2033 g_free (f);
2034 f = f1;
2037 out:
2038 if (f != NULL)
2039 _canonicalize_filename (f);
2040 return f;
2043 #ifdef HAVE_MNTENT_H
2044 static const char *
2045 _resolve_dev_root (void)
2047 static gboolean have_real_dev_root = FALSE;
2048 static char real_dev_root[256];
2049 struct stat statbuf;
2051 /* see if it's cached already */
2052 if (have_real_dev_root)
2053 goto found;
2055 /* otherwise we're going to find it right away.. */
2056 have_real_dev_root = TRUE;
2058 if (stat ("/dev/root", &statbuf) == 0) {
2059 if (! S_ISLNK (statbuf.st_mode)) {
2060 dev_t root_dev = statbuf.st_dev;
2061 FILE *f;
2062 char buf[1024];
2064 /* see if device with similar major:minor as /dev/root is mention
2065 * in /etc/mtab (it usually is)
2067 f = fopen ("/etc/mtab", "r");
2068 if (f != NULL) {
2069 struct mntent *entp;
2070 #ifdef HAVE_GETMNTENT_R
2071 struct mntent ent;
2072 while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL) {
2073 #else
2074 G_LOCK (getmntent);
2075 while ((entp = getmntent (f)) != NULL) {
2076 #endif
2077 if (stat (entp->mnt_fsname, &statbuf) == 0 &&
2078 statbuf.st_dev == root_dev) {
2079 strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
2080 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2081 fclose (f);
2082 goto found;
2086 endmntent (f);
2088 #ifndef HAVE_GETMNTENT_R
2089 G_UNLOCK (getmntent);
2090 #endif
2093 /* no, that didn't work.. next we could scan /dev ... but I digress.. */
2095 } else {
2096 char *resolved;
2097 resolved = _resolve_symlink ("/dev/root");
2098 if (resolved != NULL) {
2099 strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
2100 real_dev_root[sizeof (real_dev_root) - 1] = '\0';
2101 g_free (resolved);
2102 goto found;
2107 /* bah sucks.. */
2108 strcpy (real_dev_root, "/dev/root");
2110 found:
2111 return real_dev_root;
2113 #endif
2115 #define __G_UNIX_MOUNTS_C__
2116 #include "gioaliasdef.c"