da23bd4c0c0deeb5c8ef6a55eab0ccf3f228d4ec
[platform/upstream/glib.git] / gio / gunixmounts.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #ifndef HAVE_SYSCTLBYNAME
29 #ifdef HAVE_SYS_PARAM_H
30 #include <sys/param.h>
31 #endif
32 #ifdef HAVE_SYS_POLL_H
33 #include <sys/poll.h>
34 #endif
35 #endif
36 #ifdef HAVE_POLL_H
37 #include <poll.h>
38 #endif
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <sys/time.h>
42 #include <errno.h>
43 #include <string.h>
44 #include <signal.h>
45
46 #include "gunixmounts.h"
47 #include "gfile.h"
48 #include "gfilemonitor.h"
49
50 struct _GUnixMount {
51   char *mount_path;
52   char *device_path;
53   char *filesystem_type;
54   gboolean is_read_only;
55   gboolean is_system_internal;
56 };
57
58 struct _GUnixMountPoint {
59   char *mount_path;
60   char *device_path;
61   char *filesystem_type;
62   gboolean is_read_only;
63   gboolean is_user_mountable;
64   gboolean is_loopback;
65 };
66
67 enum {
68   MOUNTS_CHANGED,
69   MOUNTPOINTS_CHANGED,
70   LAST_SIGNAL
71 };
72
73 static guint signals[LAST_SIGNAL];
74
75 struct _GUnixMountMonitor {
76   GObject parent;
77
78   GFileMonitor *fstab_monitor;
79   GFileMonitor *mtab_monitor;
80 };
81
82 struct _GUnixMountMonitorClass {
83   GObjectClass parent_class;
84 };
85   
86 static GUnixMountMonitor *the_mount_monitor = NULL;
87
88 static GList *_g_get_unix_mounts (void);
89 static GList *_g_get_unix_mount_points (void);
90
91 G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT);
92
93 #define MOUNT_POLL_INTERVAL 4000
94
95 #ifdef HAVE_SYS_MNTTAB_H
96 #define MNTOPT_RO       "ro"
97 #endif
98
99 #ifdef HAVE_MNTENT_H
100 #include <mntent.h>
101 #elif defined (HAVE_SYS_MNTTAB_H)
102 #include <sys/mnttab.h>
103 #endif
104
105 #ifdef HAVE_SYS_VFSTAB_H
106 #include <sys/vfstab.h>
107 #endif
108
109 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
110 #include <sys/mntctl.h>
111 #include <sys/vfs.h>
112 #include <sys/vmount.h>
113 #include <fshelp.h>
114 #endif
115
116 #if defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
117 #include <sys/ucred.h>
118 #include <sys/mount.h>
119 #include <fstab.h>
120 #ifdef HAVE_SYS_SYSCTL_H
121 #include <sys/sysctl.h>
122 #endif
123 #endif
124
125 #ifndef HAVE_SETMNTENT
126 #define setmntent(f,m) fopen(f,m)
127 #endif
128 #ifndef HAVE_ENDMNTENT
129 #define endmntent(f) fclose(f)
130 #endif
131
132 static gboolean
133 is_in (const char *value, const char *set[])
134 {
135   int i;
136   for (i = 0; set[i] != NULL; i++)
137     {
138       if (strcmp (set[i], value) == 0)
139         return TRUE;
140     }
141   return FALSE;
142 }
143
144 static gboolean
145 guess_system_internal (const char *mountpoint,
146                        const char *fs,
147                        const char *device)
148 {
149   const char *ignore_fs[] = {
150     "auto",
151     "autofs",
152     "devfs",
153     "devpts",
154     "kernfs",
155     "linprocfs",
156     "proc",
157     "procfs",
158     "ptyfs",
159     "rootfs",
160     "selinuxfs",
161     "sysfs",
162     "tmpfs",
163     "usbfs",
164     "nfsd",
165     NULL
166   };
167   const char *ignore_devices[] = {
168     "none",
169     "sunrpc",
170     "devpts",
171     "nfsd",
172     "/dev/loop",
173     "/dev/vn",
174     NULL
175   };
176   const char *ignore_mountpoints[] = {
177     /* Includes all FHS 2.3 toplevel dirs */
178     "/bin",
179     "/boot",
180     "/dev",
181     "/etc",
182     "/home",
183     "/lib",
184     "/lib64",
185     "/media",
186     "/mnt",
187     "/opt",
188     "/root",
189     "/sbin",
190     "/srv",
191     "/tmp",
192     "/usr",
193     "/var",
194     "/proc",
195     "/sbin",
196     "/net",
197     NULL
198   };
199   
200   if (is_in (fs, ignore_fs))
201     return TRUE;
202   
203   if (is_in (device, ignore_devices))
204     return TRUE;
205
206   if (is_in (mountpoint, ignore_mountpoints))
207     return TRUE;
208   
209   if (g_str_has_prefix (mountpoint, "/dev") ||
210       g_str_has_prefix (mountpoint, "/proc") ||
211       g_str_has_prefix (mountpoint, "/sys"))
212     return TRUE;
213
214   if (strstr (mountpoint, "/.gvfs") != NULL)
215     return TRUE;
216   
217   return FALSE;
218 }
219
220 #ifdef HAVE_MNTENT_H
221
222 static char *
223 get_mtab_read_file (void)
224 {
225 #ifdef _PATH_MOUNTED
226 # ifdef __linux__
227   return "/proc/mounts";
228 # else
229   return _PATH_MOUNTED;
230 # endif
231 #else   
232   return "/etc/mtab";
233 #endif
234 }
235
236 static char *
237 get_mtab_monitor_file (void)
238 {
239 #ifdef _PATH_MOUNTED
240   return _PATH_MOUNTED;
241 #else   
242   return "/etc/mtab";
243 #endif
244 }
245
246 G_LOCK_DEFINE_STATIC(getmntent);
247
248 static GList *
249 _g_get_unix_mounts ()
250 {
251   struct mntent *mntent;
252   FILE *file;
253   char *read_file;
254   GUnixMount *mount_entry;
255   GHashTable *mounts_hash;
256   GList *return_list;
257   
258   read_file = get_mtab_read_file ();
259
260   file = setmntent (read_file, "r");
261   if (file == NULL)
262     return NULL;
263
264   return_list = NULL;
265   
266   mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
267   
268   G_LOCK (getmntent);
269   while ((mntent = getmntent (file)) != NULL)
270     {
271       /* ignore any mnt_fsname that is repeated and begins with a '/'
272        *
273        * We do this to avoid being fooled by --bind mounts, since
274        * these have the same device as the location they bind to.
275        * Its not an ideal solution to the problem, but its likely that
276        * the most important mountpoint is first and the --bind ones after
277        * that aren't as important. So it should work.
278        *
279        * The '/' is to handle procfs, tmpfs and other no device mounts.
280        */
281       if (mntent->mnt_fsname != NULL &&
282           mntent->mnt_fsname[0] == '/' &&
283           g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
284         continue;
285       
286       mount_entry = g_new0 (GUnixMount, 1);
287       mount_entry->mount_path = g_strdup (mntent->mnt_dir);
288       mount_entry->device_path = g_strdup (mntent->mnt_fsname);
289       mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
290       
291 #if defined (HAVE_HASMNTOPT)
292       if (hasmntopt (mntent, MNTOPT_RO) != NULL)
293         mount_entry->is_read_only = TRUE;
294 #endif
295       
296       mount_entry->is_system_internal =
297         guess_system_internal (mount_entry->mount_path,
298                                mount_entry->filesystem_type,
299                                mount_entry->device_path);
300       
301       g_hash_table_insert (mounts_hash,
302                            mount_entry->device_path,
303                            mount_entry->device_path);
304       
305       return_list = g_list_prepend (return_list, mount_entry);
306     }
307   g_hash_table_destroy (mounts_hash);
308   
309   endmntent (file);
310
311   G_UNLOCK (getmntent);
312   
313   return g_list_reverse (return_list);
314 }
315
316 #elif defined (HAVE_SYS_MNTTAB_H)
317
318 G_LOCK_DEFINE_STATIC(getmntent);
319
320 static char *
321 get_mtab_read_file (void)
322 {
323 #ifdef _PATH_MOUNTED
324   return _PATH_MOUNTED;
325 #else   
326   return "/etc/mnttab";
327 #endif
328 }
329
330 static char *
331 get_mtab_monitor_file (void)
332 {
333   return get_mtab_read_file ();
334 }
335
336 static GList *
337 _g_get_unix_mounts (void)
338 {
339   struct mnttab mntent;
340   FILE *file;
341   char *read_file;
342   GUnixMount *mount_entry;
343   GList *return_list;
344   
345   read_file = get_mtab_read_file ();
346   
347   file = setmntent (read_file, "r");
348   if (file == NULL)
349     return NULL;
350   
351   return_list = NULL;
352   
353   G_LOCK (getmntent);
354   while (! getmntent (file, &mntent))
355     {
356       mount_entry = g_new0 (GUnixMount, 1);
357       
358       mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
359       mount_entry->device_path = g_strdup (mntent.mnt_special);
360       mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
361       
362 #if defined (HAVE_HASMNTOPT)
363       if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
364         mount_entry->is_read_only = TRUE;
365 #endif
366
367       mount_entry->is_system_internal =
368         guess_system_internal (mount_entry->mount_path,
369                                mount_entry->filesystem_type,
370                                mount_entry->device_path);
371       
372       return_list = g_list_prepend (return_list, mount_entry);
373     }
374   
375   endmntent (file);
376   
377   G_UNLOCK (getmntent);
378   
379   return g_list_reverse (return_list);
380 }
381
382 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
383
384 static char *
385 get_mtab_monitor_file (void)
386 {
387   return NULL;
388 }
389
390 static GList *
391 _g_get_unix_mounts (void)
392 {
393   struct vfs_ent *fs_info;
394   struct vmount *vmount_info;
395   int vmount_number;
396   unsigned int vmount_size;
397   int current;
398   GList *return_list;
399   
400   if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
401     {
402       g_warning ("Unable to know the number of mounted volumes\n");
403       
404       return NULL;
405     }
406
407   vmount_info = (struct vmount*)g_malloc (vmount_size);
408
409   vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
410   
411   if (vmount_info->vmt_revision != VMT_REVISION)
412     g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
413
414   if (vmount_number < 0)
415     {
416       g_warning ("Unable to recover mounted volumes information\n");
417       
418       g_free (vmount_info);
419       return NULL;
420     }
421   
422   return_list = NULL;
423   while (vmount_number > 0)
424     {
425       mount_entry = g_new0 (GUnixMount, 1);
426       
427       mount_entry->device_path = g_strdup (vmt2dataptr (vmount_info, VMT_OBJECT));
428       mount_entry->mount_path = g_strdup (vmt2dataptr (vmount_info, VMT_STUB));
429       /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
430       mount_entry->is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
431
432       fs_info = getvfsbytype (vmount_info->vmt_gfstype);
433       
434       if (fs_info == NULL)
435         mount_entry->filesystem_type = g_strdup ("unknown");
436       else
437         mount_entry->filesystem_type = g_strdup (fs_info->vfsent_name);
438
439       mount_entry->is_system_internal =
440         guess_system_internal (mount_entry->mount_path,
441                                mount_entry->filesystem_type,
442                                mount_entry->device_path);
443       
444       return_list = g_list_prepend (return_list, mount_entry);
445       
446       vmount_info = (struct vmount *)( (char*)vmount_info 
447                                        + vmount_info->vmt_length);
448       vmount_number--;
449     }
450   
451   
452   g_free (vmount_info);
453   
454   return g_list_reverse (return_list);
455 }
456
457 #elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
458
459 static char *
460 get_mtab_monitor_file (void)
461 {
462   return NULL;
463 }
464
465 static GList *
466 _g_get_unix_mounts (void)
467 {
468   struct statfs *mntent = NULL;
469   int num_mounts, i;
470   GUnixMount *mount_entry;
471   GList *return_list;
472   
473   /* Pass MNT_NOWAIT to avoid blocking trying to update NFS mounts. */
474   if ((num_mounts = getmntinfo (&mntent, MNT_NOWAIT)) == 0)
475     return NULL;
476   
477   return_list = NULL;
478   
479   for (i = 0; i < num_mounts; i++)
480     {
481       mount_entry = g_new0 (GUnixMount, 1);
482       
483       mount_entry->mount_path = g_strdup (mntent[i].f_mntonname);
484       mount_entry->device_path = g_strdup (mntent[i].f_mntfromname);
485       mount_entry->filesystem_type = g_strdup (mntent[i].f_fstypename);
486       if (mntent[i].f_flags & MNT_RDONLY)
487         mount_entry->is_read_only = TRUE;
488
489       mount_entry->is_system_internal =
490         guess_system_internal (mount_entry->mount_path,
491                                mount_entry->filesystem_type,
492                                mount_entry->device_path);
493       
494       return_list = g_list_prepend (return_list, mount_entry);
495     }
496   
497   return g_list_reverse (return_list);
498 }
499 #else
500 #error No _g_get_unix_mounts() implementation for system
501 #endif
502
503 /* _g_get_unix_mount_points():
504  * read the fstab.
505  * don't return swap and ignore mounts.
506  */
507
508 static char *
509 get_fstab_file (void)
510 {
511 #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
512   /* AIX */
513   return "/etc/filesystems";
514 #elif defined(_PATH_MNTTAB)
515   return _PATH_MNTTAB;
516 #elif defined(VFSTAB)
517   return VFSTAB;
518 #else
519   return "/etc/fstab";
520 #endif
521 }
522
523 #ifdef HAVE_MNTENT_H
524 static GList *
525 _g_get_unix_mount_points (void)
526 {
527   struct mntent *mntent;
528   FILE *file;
529   char *read_file;
530   GUnixMountPoint *mount_entry;
531   GList *return_list;
532   
533   read_file = get_fstab_file ();
534   
535   file = setmntent (read_file, "r");
536   if (file == NULL)
537     return NULL;
538
539   return_list = NULL;
540   
541   G_LOCK (getmntent);
542   while ((mntent = getmntent (file)) != NULL)
543     {
544       if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
545           (strcmp (mntent->mnt_dir, "swap") == 0))
546         continue;
547       
548       mount_entry = g_new0 (GUnixMountPoint, 1);
549       mount_entry->mount_path = g_strdup (mntent->mnt_dir);
550       mount_entry->device_path = g_strdup (mntent->mnt_fsname);
551       mount_entry->filesystem_type = g_strdup (mntent->mnt_type);
552       
553 #ifdef HAVE_HASMNTOPT
554       if (hasmntopt (mntent, MNTOPT_RO) != NULL)
555         mount_entry->is_read_only = TRUE;
556       
557       if (hasmntopt (mntent, "loop") != NULL)
558         mount_entry->is_loopback = TRUE;
559       
560 #endif
561       
562       if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
563 #ifdef HAVE_HASMNTOPT
564           || (hasmntopt (mntent, "user") != NULL
565               && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
566           || hasmntopt (mntent, "pamconsole") != NULL
567           || hasmntopt (mntent, "users") != NULL
568           || hasmntopt (mntent, "owner") != NULL
569 #endif
570           )
571         mount_entry->is_user_mountable = TRUE;
572       
573       return_list = g_list_prepend (return_list, mount_entry);
574     }
575   
576   endmntent (file);
577   G_UNLOCK (getmntent);
578   
579   return g_list_reverse (return_list);
580 }
581
582 #elif defined (HAVE_SYS_MNTTAB_H)
583
584 static GList *
585 _g_get_unix_mount_points (void)
586 {
587   struct mnttab mntent;
588   FILE *file;
589   char *read_file;
590   GUnixMountPoint *mount_entry;
591   GList *return_list;
592   
593   read_file = get_fstab_file ();
594   
595   file = setmntent (read_file, "r");
596   if (file == NULL)
597     return NULL;
598
599   return_list = NULL;
600   
601   G_LOCK (getmntent);
602   while (! getmntent (file, &mntent))
603     {
604       if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
605           (strcmp (mntent.mnt_mountp, "swap") == 0))
606         continue;
607       
608       mount_entry = g_new0 (GUnixMountPoint, 1);
609       
610       mount_entry->mount_path = g_strdup (mntent.mnt_mountp);
611       mount_entry->device_path = g_strdup (mntent.mnt_special);
612       mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
613       
614 #ifdef HAVE_HASMNTOPT
615       if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
616         mount_entry->is_read_only = TRUE;
617       
618       if (hasmntopt (&mntent, "lofs") != NULL)
619         mount_entry->is_loopback = TRUE;
620 #endif
621       
622       if ((mntent.mnt_fstype != NULL)
623 #ifdef HAVE_HASMNTOPT
624           || (hasmntopt (&mntent, "user") != NULL
625               && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
626           || hasmntopt (&mntent, "pamconsole") != NULL
627           || hasmntopt (&mntent, "users") != NULL
628           || hasmntopt (&mntent, "owner") != NULL
629 #endif
630           )
631         mount_entry->is_user_mountable = TRUE;
632       
633       
634       return_list = g_list_prepend (return_list, mount_entry);
635     }
636   
637   endmntent (file);
638   G_UNLOCK (getmntent);
639   
640   return g_list_reverse (return_list);
641 }
642 #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
643
644 /* functions to parse /etc/filesystems on aix */
645
646 /* read character, ignoring comments (begin with '*', end with '\n' */
647 static int
648 aix_fs_getc (FILE *fd)
649 {
650   int c;
651   
652   while ((c = getc (fd)) == '*')
653     {
654       while (((c = getc (fd)) != '\n') && (c != EOF))
655         ;
656     }
657 }
658
659 /* eat all continuous spaces in a file */
660 static int
661 aix_fs_ignorespace (FILE *fd)
662 {
663   int c;
664   
665   while ((c = aix_fs_getc (fd)) != EOF)
666     {
667       if (!g_ascii_isspace (c))
668         {
669           ungetc (c,fd);
670           return c;
671         }
672     }
673   
674   return EOF;
675 }
676
677 /* read one word from file */
678 static int
679 aix_fs_getword (FILE *fd, char *word)
680 {
681   int c;
682   
683   aix_fs_ignorespace (fd);
684
685   while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
686     {
687       if (c == '"')
688         {
689           while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
690             *word++ = c;
691           else
692             *word++ = c;
693         }
694     }
695   *word = 0;
696   
697   return c;
698 }
699
700 typedef struct {
701   char mnt_mount[PATH_MAX];
702   char mnt_special[PATH_MAX];
703   char mnt_fstype[16];
704   char mnt_options[128];
705 } AixMountTableEntry;
706
707 /* read mount points properties */
708 static int
709 aix_fs_get (FILE *fd, AixMountTableEntry *prop)
710 {
711   static char word[PATH_MAX] = { 0 };
712   char value[PATH_MAX];
713   
714   /* read stanza */
715   if (word[0] == 0)
716     {
717       if (aix_fs_getword (fd, word) == EOF)
718         return EOF;
719     }
720
721   word[strlen(word) - 1] = 0;
722   strcpy (prop->mnt_mount, word);
723   
724   /* read attributes and value */
725   
726   while (aix_fs_getword (fd, word) != EOF)
727     {
728       /* test if is attribute or new stanza */
729       if (word[strlen(word) - 1] == ':')
730         return 0;
731       
732       /* read "=" */
733       aix_fs_getword (fd, value);
734       
735       /* read value */
736       aix_fs_getword (fd, value);
737       
738       if (strcmp (word, "dev") == 0)
739         strcpy (prop->mnt_special, value);
740       else if (strcmp (word, "vfs") == 0)
741         strcpy (prop->mnt_fstype, value);
742       else if (strcmp (word, "options") == 0)
743         strcpy(prop->mnt_options, value);
744     }
745   
746   return 0;
747 }
748
749 static GList *
750 _g_get_unix_mount_points (void)
751 {
752   struct mntent *mntent;
753   FILE *file;
754   char *read_file;
755   GUnixMountPoint *mount_entry;
756   AixMountTableEntry mntent;
757   GList *return_list;
758   
759   read_file = get_fstab_file ();
760   
761   file = setmntent (read_file, "r");
762   if (file == NULL)
763     return NULL;
764   
765   return_list = NULL;
766   
767   while (!aix_fs_get (file, &mntent))
768     {
769       if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
770         {
771           mount_entry = g_new0 (GUnixMountPoint, 1);
772           
773           
774           mount_entry->mount_path = g_strdup (mntent.mnt_mount);
775           mount_entry->device_path = g_strdup (mntent.mnt_special);
776           mount_entry->filesystem_type = g_strdup (mntent.mnt_fstype);
777           mount_entry->is_read_only = TRUE;
778           mount_entry->is_user_mountable = TRUE;
779           
780           return_list = g_list_prepend (return_list, mount_entry);
781         }
782     }
783         
784   endmntent (file);
785   
786   return g_list_reverse (return_list);
787 }
788
789 #elif defined(HAVE_GETMNTINFO) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
790
791 static GList *
792 _g_get_unix_mount_points (void)
793 {
794   struct fstab *fstab = NULL;
795   GUnixMountPoint *mount_entry;
796   GList *return_list;
797 #ifdef HAVE_SYS_SYSCTL_H
798   int usermnt = 0;
799   size_t len = sizeof(usermnt);
800   struct stat sb;
801 #endif
802   
803   if (!setfsent ())
804     return NULL;
805
806   return_list = NULL;
807   
808 #ifdef HAVE_SYS_SYSCTL_H
809 #if defined(HAVE_SYSCTLBYNAME)
810   sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
811 #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
812   {
813     int mib[2];
814     
815     mib[0] = CTL_VFS;
816     mib[1] = VFS_USERMOUNT;
817     sysctl (mib, 2, &usermnt, &len, NULL, 0);
818   }
819 #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
820   {
821     int mib[2];
822     
823     mib[0] = CTL_KERN;
824     mib[1] = KERN_USERMOUNT;
825     sysctl (mib, 2, &usermnt, &len, NULL, 0);
826   }
827 #endif
828 #endif
829   
830   while ((fstab = getfsent ()) != NULL)
831     {
832       if (strcmp (fstab->fs_vfstype, "swap") == 0)
833         continue;
834       
835       mount_entry = g_new0 (GUnixMountPoint, 1);
836       
837       mount_entry->mount_path = g_strdup (fstab->fs_file);
838       mount_entry->device_path = g_strdup (fstab->fs_spec);
839       mount_entry->filesystem_type = g_strdup (fstab->fs_vfstype);
840       
841       if (strcmp (fstab->fs_type, "ro") == 0)
842         mount_entry->is_read_only = TRUE;
843
844 #ifdef HAVE_SYS_SYSCTL_H
845       if (usermnt != 0)
846         {
847           uid_t uid = getuid ();
848           if (stat (fstab->fs_file, &sb) == 0)
849             {
850               if (uid == 0 || sb.st_uid == uid)
851                 mount_entry->is_user_mountable = TRUE;
852             }
853         }
854 #endif
855
856       return_list = g_list_prepend (return_list, mount_entry);
857     }
858   
859   endfsent ();
860   
861   return g_list_reverse (return_list);
862 }
863 #else
864 #error No g_get_mount_table() implementation for system
865 #endif
866
867 static guint64
868 get_mounts_timestamp (void)
869 {
870   const char *monitor_file;
871   struct stat buf;
872
873   monitor_file = get_mtab_monitor_file ();
874   if (monitor_file)
875     {
876       if (stat (monitor_file, &buf) == 0)
877         return (guint64)buf.st_mtime;
878     }
879   return 0;
880 }
881
882 static guint64
883 get_mount_points_timestamp (void)
884 {
885   const char *monitor_file;
886   struct stat buf;
887
888   monitor_file = get_fstab_file ();
889   if (monitor_file)
890     {
891       if (stat (monitor_file, &buf) == 0)
892         return (guint64)buf.st_mtime;
893     }
894   return 0;
895 }
896
897 /**
898  * g_get_unix_mounts:
899  * @time_read: guint64 to contain a timestamp.
900  * 
901  * Returns a #GList of the UNIX mounts. If @time_read
902  * is set, it will be filled with the mount timestamp.
903  **/
904 GList *
905 g_get_unix_mounts (guint64 *time_read)
906 {
907   if (time_read)
908     *time_read = get_mounts_timestamp ();
909
910   return _g_get_unix_mounts ();
911 }
912
913 /**
914  * g_get_unix_mount_at:
915  * @mount_path: path to mount.
916  * @time_read: guint64 to contain a timestamp.
917  * 
918  * Returns a #GUnixMount. If @time_read
919  * is set, it will be filled with the mount timestamp.
920  **/
921 GUnixMount *
922 g_get_unix_mount_at (const char *mount_path,
923                      guint64 *time_read)
924 {
925   GList *mounts, *l;
926   GUnixMount *mount_entry, *found;
927   
928   mounts = g_get_unix_mounts (time_read);
929
930   found = NULL;
931   for (l = mounts; l != NULL; l = l->next)
932     {
933       mount_entry = l->data;
934
935       if (strcmp (mount_path, mount_entry->mount_path) == 0)
936         found = mount_entry;
937       else
938         g_unix_mount_free (mount_entry);
939       
940     }
941   g_list_free (mounts);
942
943   return found;
944 }
945
946 /**
947  * g_get_unix_mount_points:
948  * @time_read: guint64 to contain a timestamp.
949  * 
950  * Returns a #GList of the UNIX mountpoints. If @time_read
951  * is set, it will be filled with the mount timestamp.
952  **/
953 GList *
954 g_get_unix_mount_points (guint64 *time_read)
955 {
956   if (time_read)
957     *time_read = get_mount_points_timestamp ();
958
959   return _g_get_unix_mount_points ();
960 }
961
962 /**
963  * g_unix_mounts_change_since:
964  * @time: guint64 to contain a timestamp.
965  * 
966  * Returns %TRUE if the mounts have changed since @time. 
967  **/
968 gboolean
969 g_unix_mounts_changed_since (guint64 time)
970 {
971   return get_mounts_timestamp () != time;
972 }
973
974 /**
975  * g_unix_mount_points_change_since:
976  * @time: guint64 to contain a timestamp.
977  * 
978  * Returns %TRUE if the mount points have changed since @time. 
979  **/
980 gboolean
981 g_unix_mount_points_changed_since (guint64 time)
982 {
983   return get_mount_points_timestamp () != time;
984 }
985
986 static void
987 g_unix_mount_monitor_finalize (GObject *object)
988 {
989   GUnixMountMonitor *monitor;
990   
991   monitor = G_UNIX_MOUNT_MONITOR (object);
992
993   if (monitor->fstab_monitor)
994     {
995       g_file_monitor_cancel (monitor->fstab_monitor);
996       g_object_unref (monitor->fstab_monitor);
997     }
998   
999   if (monitor->mtab_monitor)
1000     {
1001       g_file_monitor_cancel (monitor->mtab_monitor);
1002       g_object_unref (monitor->mtab_monitor);
1003     }
1004
1005   the_mount_monitor = NULL;
1006   
1007   if (G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize)
1008     (*G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize) (object);
1009 }
1010
1011
1012 static void
1013 g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
1014 {
1015   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1016
1017   gobject_class->finalize = g_unix_mount_monitor_finalize;
1018   
1019   signals[MOUNTS_CHANGED] =
1020     g_signal_new ("mounts_changed",
1021                   G_TYPE_FROM_CLASS (klass),
1022                   G_SIGNAL_RUN_LAST,
1023                   0,
1024                   NULL, NULL,
1025                   g_cclosure_marshal_VOID__VOID,
1026                   G_TYPE_NONE, 0);
1027   
1028   signals[MOUNTPOINTS_CHANGED] =
1029     g_signal_new ("mountpoints_changed",
1030                   G_TYPE_FROM_CLASS (klass),
1031                   G_SIGNAL_RUN_LAST,
1032                   0,
1033                   NULL, NULL,
1034                   g_cclosure_marshal_VOID__VOID,
1035                   G_TYPE_NONE, 0);
1036 }
1037
1038 static void
1039 fstab_file_changed (GFileMonitor* monitor,
1040                     GFile* file,
1041                     GFile* other_file,
1042                     GFileMonitorEvent event_type,
1043                     gpointer user_data)
1044 {
1045   GUnixMountMonitor *mount_monitor;
1046
1047   if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1048       event_type != G_FILE_MONITOR_EVENT_CREATED &&
1049       event_type != G_FILE_MONITOR_EVENT_DELETED)
1050     return;
1051
1052   mount_monitor = user_data;
1053   g_signal_emit (mount_monitor, signals[MOUNTPOINTS_CHANGED], 0);
1054 }
1055
1056 static void
1057 mtab_file_changed (GFileMonitor* monitor,
1058                    GFile* file,
1059                    GFile* other_file,
1060                    GFileMonitorEvent event_type,
1061                    gpointer user_data)
1062 {
1063   GUnixMountMonitor *mount_monitor;
1064
1065   if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
1066       event_type != G_FILE_MONITOR_EVENT_CREATED &&
1067       event_type != G_FILE_MONITOR_EVENT_DELETED)
1068     return;
1069   
1070   mount_monitor = user_data;
1071   g_signal_emit (mount_monitor, signals[MOUNTS_CHANGED], 0);
1072 }
1073
1074 static void
1075 g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
1076 {
1077   GFile *file;
1078     
1079   if (get_fstab_file () != NULL)
1080     {
1081       file = g_file_new_for_path (get_fstab_file ());
1082       monitor->fstab_monitor = g_file_monitor_file (file, 0, NULL);
1083       g_object_unref (file);
1084       
1085       g_signal_connect (monitor->fstab_monitor, "changed", (GCallback)fstab_file_changed, monitor);
1086     }
1087   
1088   if (get_mtab_monitor_file () != NULL)
1089     {
1090       file = g_file_new_for_path (get_mtab_monitor_file ());
1091       monitor->mtab_monitor = g_file_monitor_file (file, 0, NULL);
1092       g_object_unref (file);
1093       
1094       g_signal_connect (monitor->mtab_monitor, "changed", (GCallback)mtab_file_changed, monitor);
1095     }
1096 }
1097
1098 /**
1099  * g_unix_mount_monitor_new:
1100  * 
1101  * Returns a new #GUnixMountMonitor. 
1102  **/
1103 GUnixMountMonitor *
1104 g_unix_mount_monitor_new (void)
1105 {
1106   if (the_mount_monitor == NULL)
1107     {
1108       the_mount_monitor = g_object_new (G_TYPE_UNIX_MOUNT_MONITOR, NULL);
1109       return the_mount_monitor;
1110     }
1111   
1112   return g_object_ref (the_mount_monitor);
1113 }
1114
1115 /**
1116  * g_unix_mount_free:
1117  * @mount_entry: a #GUnixMount.
1118  * 
1119  **/
1120 void
1121 g_unix_mount_free (GUnixMount *mount_entry)
1122 {
1123   g_return_if_fail (mount_entry != NULL);
1124
1125   g_free (mount_entry->mount_path);
1126   g_free (mount_entry->device_path);
1127   g_free (mount_entry->filesystem_type);
1128   g_free (mount_entry);
1129 }
1130
1131 /**
1132  * g_unix_mount_point_free:
1133  * @mount_point: 
1134  * 
1135  **/
1136 void
1137 g_unix_mount_point_free (GUnixMountPoint *mount_point)
1138 {
1139   g_return_if_fail (mount_point != NULL);
1140
1141   g_free (mount_point->mount_path);
1142   g_free (mount_point->device_path);
1143   g_free (mount_point->filesystem_type);
1144   g_free (mount_point);
1145 }
1146
1147 static int
1148 strcmp_null (const char *str1,
1149              const char *str2)
1150 {
1151   if (str1 == str2)
1152     return 0;
1153   if (str1 == NULL && str2 != NULL) 
1154     return -1;
1155   if (str1 != NULL && str2 == NULL)
1156     return 1;
1157   return strcmp (str1, str2);
1158 }
1159
1160 /**
1161  * g_unix_mount_compare:
1162  * @mount1: first #GUnixMount to compare.
1163  * @mount2: second #GUnixMount to compare.
1164  * 
1165  * Returns 1, 0 or -1 if @mount1 is greater than, equal to,
1166  * or less than @mount2, respectively. 
1167  **/
1168 gint
1169 g_unix_mount_compare (GUnixMount      *mount1,
1170                       GUnixMount      *mount2)
1171 {
1172   int res;
1173
1174   g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1175   
1176   res = strcmp_null (mount1->mount_path, mount2->mount_path);
1177   if (res != 0)
1178     return res;
1179         
1180   res = strcmp_null (mount1->device_path, mount2->device_path);
1181   if (res != 0)
1182     return res;
1183         
1184   res = strcmp_null (mount1->filesystem_type, mount2->filesystem_type);
1185   if (res != 0)
1186     return res;
1187
1188   res =  mount1->is_read_only - mount2->is_read_only;
1189   if (res != 0)
1190     return res;
1191   
1192   return 0;
1193 }
1194
1195 /**
1196  * g_unix_mount_get_mount_path:
1197  * @mount_entry: input #GUnixMount to get the mount path for.
1198  * 
1199  * Returns the mount path for @mount_entry.
1200  * 
1201  **/
1202 const char *
1203 g_unix_mount_get_mount_path (GUnixMount *mount_entry)
1204 {
1205   g_return_val_if_fail (mount_entry != NULL, NULL);
1206
1207   return mount_entry->mount_path;
1208 }
1209
1210 /**
1211  * g_unix_mount_get_device_path:
1212  * @mount_entry: a #GUnixMount.
1213  * 
1214  **/
1215 const char *
1216 g_unix_mount_get_device_path (GUnixMount *mount_entry)
1217 {
1218   g_return_val_if_fail (mount_entry != NULL, NULL);
1219
1220   return mount_entry->device_path;
1221 }
1222
1223 /**
1224  * g_unix_mount_get_fs_type:
1225  * @mount_entry: a #GUnixMount.
1226  * 
1227  **/
1228 const char *
1229 g_unix_mount_get_fs_type (GUnixMount *mount_entry)
1230 {
1231   g_return_val_if_fail (mount_entry != NULL, NULL);
1232
1233   return mount_entry->filesystem_type;
1234 }
1235
1236 /**
1237  * g_unix_mount_is_readonly:
1238  * @mount_entry: a #GUnixMount.
1239  * 
1240  * Returns %TRUE if @mount_entry is read only.
1241  * 
1242  **/
1243 gboolean
1244 g_unix_mount_is_readonly (GUnixMount *mount_entry)
1245 {
1246   g_return_val_if_fail (mount_entry != NULL, FALSE);
1247
1248   return mount_entry->is_read_only;
1249 }
1250
1251 /**
1252  * g_unix_mount_is_system_internal:
1253  * @mount_entry: a #GUnixMount.
1254  * 
1255  **/
1256 gboolean
1257 g_unix_mount_is_system_internal (GUnixMount *mount_entry)
1258 {
1259   g_return_val_if_fail (mount_entry != NULL, FALSE);
1260
1261   return mount_entry->is_system_internal;
1262 }
1263
1264 /**
1265  * g_unix_mount_point_compare:
1266  * @mount1: a #GUnixMount.
1267  * @mount2: a #GUnixMount.
1268  * 
1269  * Returns 1, 0 or -1 if @mount1 is greater than, equal to,
1270  * or less than @mount2, respectively.
1271  **/
1272 gint
1273 g_unix_mount_point_compare (GUnixMountPoint *mount1,
1274                             GUnixMountPoint *mount2)
1275 {
1276   int res;
1277
1278   g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
1279
1280   res = strcmp_null (mount1->mount_path, mount2->mount_path);
1281   if (res != 0) 
1282     return res;
1283         
1284   res = strcmp_null (mount1->device_path, mount2->device_path);
1285   if (res != 0) 
1286     return res;
1287         
1288   res = strcmp_null (mount1->filesystem_type, mount2->filesystem_type);
1289   if (res != 0) 
1290     return res;
1291
1292   res =  mount1->is_read_only - mount2->is_read_only;
1293   if (res != 0) 
1294     return res;
1295
1296   res = mount1->is_user_mountable - mount2->is_user_mountable;
1297   if (res != 0) 
1298     return res;
1299
1300   res = mount1->is_loopback - mount2->is_loopback;
1301   if (res != 0)
1302     return res;
1303   
1304   return 0;
1305 }
1306
1307 /**
1308  * g_unix_mount_point_get_mount_path:
1309  * @mount_point: a #GUnixMount.
1310  * 
1311  **/
1312 const char *
1313 g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
1314 {
1315   g_return_val_if_fail (mount_point != NULL, NULL);
1316
1317   return mount_point->mount_path;
1318 }
1319
1320 /**
1321  * g_unix_mount_point_get_device_path:
1322  * @mount_point: a #GUnixMount.
1323  * 
1324  **/
1325 const char *
1326 g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
1327 {
1328   g_return_val_if_fail (mount_point != NULL, NULL);
1329
1330   return mount_point->device_path;
1331 }
1332
1333 /**
1334  * g_unix_mount_point_get_fs_type:
1335  * @mount_point: a #GUnixMount.
1336  * 
1337  **/
1338 const char *
1339 g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
1340 {
1341   g_return_val_if_fail (mount_point != NULL, NULL);
1342
1343   return mount_point->filesystem_type;
1344 }
1345
1346 /**
1347  * g_unix_mount_point_is_readonly:
1348  * @mount_point: a #GUnixMount.
1349  * 
1350  **/
1351 gboolean
1352 g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
1353 {
1354   g_return_val_if_fail (mount_point != NULL, FALSE);
1355
1356   return mount_point->is_read_only;
1357 }
1358
1359 /**
1360  * g_unix_mount_point_is_user_mountable:
1361  * @mount_point:  a #GUnixMount.
1362  * 
1363  **/
1364 gboolean
1365 g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
1366 {
1367   g_return_val_if_fail (mount_point != NULL, FALSE);
1368
1369   return mount_point->is_user_mountable;
1370 }
1371
1372 /**
1373  * g_unix_mount_point_is_loopback:
1374  * @mount_point:  a #GUnixMount.
1375  * 
1376  **/
1377 gboolean
1378 g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
1379 {
1380   g_return_val_if_fail (mount_point != NULL, FALSE);
1381
1382   return mount_point->is_loopback;
1383 }
1384
1385 static GUnixMountType
1386 guess_mount_type (const char *mount_path,
1387                   const char *device_path,
1388                   const char *filesystem_type)
1389 {
1390   GUnixMountType type;
1391   char *basename;
1392
1393   type = G_UNIX_MOUNT_TYPE_UNKNOWN;
1394   
1395   if ((strcmp (filesystem_type, "udf") == 0) ||
1396       (strcmp (filesystem_type, "iso9660") == 0) ||
1397       (strcmp (filesystem_type, "cd9660") == 0))
1398     type = G_UNIX_MOUNT_TYPE_CDROM;
1399   else if (strcmp (filesystem_type, "nfs") == 0)
1400     type = G_UNIX_MOUNT_TYPE_NFS;
1401   else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
1402            g_str_has_prefix (device_path, "/dev/fd") ||
1403            g_str_has_prefix (device_path, "/dev/floppy"))
1404     type = G_UNIX_MOUNT_TYPE_FLOPPY;
1405   else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
1406            g_str_has_prefix (device_path, "/dev/acd") ||
1407            g_str_has_prefix (device_path, "/dev/cd"))
1408     type = G_UNIX_MOUNT_TYPE_CDROM;
1409   else if (g_str_has_prefix (device_path, "/vol/"))
1410     {
1411       const char *name = mount_path + strlen ("/");
1412       
1413       if (g_str_has_prefix (name, "cdrom"))
1414         type = G_UNIX_MOUNT_TYPE_CDROM;
1415       else if (g_str_has_prefix (name, "floppy") ||
1416                g_str_has_prefix (device_path, "/vol/dev/diskette/")) 
1417         type = G_UNIX_MOUNT_TYPE_FLOPPY;
1418       else if (g_str_has_prefix (name, "rmdisk")) 
1419         type = G_UNIX_MOUNT_TYPE_ZIP;
1420       else if (g_str_has_prefix (name, "jaz"))
1421         type = G_UNIX_MOUNT_TYPE_JAZ;
1422       else if (g_str_has_prefix (name, "memstick"))
1423         type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1424     }
1425   else
1426     {
1427       basename = g_path_get_basename (mount_path);
1428       
1429       if (g_str_has_prefix (basename, "cdrom") ||
1430           g_str_has_prefix (basename, "cdwriter") ||
1431           g_str_has_prefix (basename, "burn") ||
1432           g_str_has_prefix (basename, "cdr") ||
1433           g_str_has_prefix (basename, "cdrw") ||
1434           g_str_has_prefix (basename, "dvdrom") ||
1435           g_str_has_prefix (basename, "dvdram") ||
1436           g_str_has_prefix (basename, "dvdr") ||
1437           g_str_has_prefix (basename, "dvdrw") ||
1438           g_str_has_prefix (basename, "cdrom_dvdrom") ||
1439           g_str_has_prefix (basename, "cdrom_dvdram") ||
1440           g_str_has_prefix (basename, "cdrom_dvdr") ||
1441           g_str_has_prefix (basename, "cdrom_dvdrw") ||
1442           g_str_has_prefix (basename, "cdr_dvdrom") ||
1443           g_str_has_prefix (basename, "cdr_dvdram") ||
1444           g_str_has_prefix (basename, "cdr_dvdr") ||
1445           g_str_has_prefix (basename, "cdr_dvdrw") ||
1446           g_str_has_prefix (basename, "cdrw_dvdrom") ||
1447           g_str_has_prefix (basename, "cdrw_dvdram") ||
1448           g_str_has_prefix (basename, "cdrw_dvdr") ||
1449           g_str_has_prefix (basename, "cdrw_dvdrw"))
1450         type = G_UNIX_MOUNT_TYPE_CDROM;
1451       else if (g_str_has_prefix (basename, "floppy"))
1452         type = G_UNIX_MOUNT_TYPE_FLOPPY;
1453       else if (g_str_has_prefix (basename, "zip"))
1454         type = G_UNIX_MOUNT_TYPE_ZIP;
1455       else if (g_str_has_prefix (basename, "jaz"))
1456         type = G_UNIX_MOUNT_TYPE_JAZ;
1457       else if (g_str_has_prefix (basename, "camera"))
1458         type = G_UNIX_MOUNT_TYPE_CAMERA;
1459       else if (g_str_has_prefix (basename, "memstick") ||
1460                g_str_has_prefix (basename, "memory_stick") ||
1461                g_str_has_prefix (basename, "ram"))
1462         type = G_UNIX_MOUNT_TYPE_MEMSTICK;
1463       else if (g_str_has_prefix (basename, "compact_flash"))
1464         type = G_UNIX_MOUNT_TYPE_CF;
1465       else if (g_str_has_prefix (basename, "smart_media"))
1466         type = G_UNIX_MOUNT_TYPE_SM;
1467       else if (g_str_has_prefix (basename, "sd_mmc"))
1468         type = G_UNIX_MOUNT_TYPE_SDMMC;
1469       else if (g_str_has_prefix (basename, "ipod"))
1470         type = G_UNIX_MOUNT_TYPE_IPOD;
1471       
1472       g_free (basename);
1473     }
1474   
1475   if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
1476     type = G_UNIX_MOUNT_TYPE_HD;
1477   
1478   return type;
1479 }
1480
1481 /**
1482  * g_unix_mount_guess_type:
1483  * @mount_entry: a #GUnixMount.
1484  * 
1485  **/
1486 GUnixMountType
1487 g_unix_mount_guess_type (GUnixMount *mount_entry)
1488 {
1489   g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1490   g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1491   g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1492   g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1493
1494   return guess_mount_type (mount_entry->mount_path,
1495                            mount_entry->device_path,
1496                            mount_entry->filesystem_type);
1497 }
1498
1499 /**
1500  * g_unix_mount_point_guess_type:
1501  * @mount_point: a #GUnixMount.
1502  * 
1503  **/
1504 GUnixMountType
1505 g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
1506 {
1507   g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1508   g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1509   g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1510   g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
1511
1512   return guess_mount_type (mount_point->mount_path,
1513                            mount_point->device_path,
1514                            mount_point->filesystem_type);
1515 }