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