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