2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place, Suite 330, Boston, MA 02111-1307 USA
20 /* mount.c - code for handling mount points */
31 #elif HAVE_SYS_UCRED_H
32 /* NetBSD, OSF1, etc */
34 # include <sys/types.h>
35 # include <sys/param.h>
36 # include <sys/ucred.h>
37 # include <sys/mount.h>
39 #elif HAVE_SYS_MNTENT_H
41 # include <sys/mntent.h>
42 # include <sys/mnttab.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
59 /* Map mount points to mntent structures */
60 GHashTable
*fstab_mounts
= NULL
;
63 /* Keys are mount points that the user mounted. Values are ignored. */
64 static GHashTable
*user_mounts
= NULL
;
66 #ifdef HAVE_SYS_MNTENT_H
67 #define THE_FSTAB VFSTAB
69 #define THE_FSTAB "/etc/fstab"
72 /* Static prototypes */
73 #ifdef DO_MOUNT_POINTS
74 static void read_table(void);
75 static void clear_table(void);
76 static time_t read_time(char *path
);
77 static gboolean
free_mp(gpointer key
, gpointer value
, gpointer data
);
81 /****************************************************************
82 * EXTERNAL INTERFACE *
83 ****************************************************************/
87 fstab_mounts
= g_hash_table_new(g_str_hash
, g_str_equal
);
88 user_mounts
= g_hash_table_new_full(g_str_hash
, g_str_equal
,
91 #ifdef DO_MOUNT_POINTS
92 fstab_time
= read_time(THE_FSTAB
);
97 /* If force is true then ignore the timestamps */
98 void mount_update(gboolean force
)
100 #ifdef DO_MOUNT_POINTS
103 time
= read_time(THE_FSTAB
);
104 if (force
|| time
!= fstab_time
)
109 #endif /* DO_MOUNT_POINTS */
112 /* The user has just finished mounting/unmounting this path.
113 * Update the list of user-mounted filesystems.
115 void mount_user_mount(const char *path
)
117 if (mount_is_mounted(path
, NULL
, NULL
))
118 g_hash_table_insert(user_mounts
, pathdup(path
), "yes");
120 g_hash_table_remove(user_mounts
, path
);
123 /* TRUE iff this directory is a mount point. Uses python's method to
125 * The function checks whether path's parent, path/.., is on a different device
126 * than path, or whether path/.. and path point to the same i-node on the same
127 * device -- this should detect mount points for all Unix and POSIX variants.
129 * 'info' and 'parent' are both optional, saving one stat() each.
131 gboolean
mount_is_mounted(const guchar
*path
, struct stat
*info
,
134 struct stat info_path
, info_parent
;
139 if (stat(path
, &info_path
))
140 return FALSE
; /* Doesn't exist => not mount point :-) */
146 parent
= &info_parent
;
147 tmp
= g_strconcat(path
, "/..", NULL
);
148 if (stat(tmp
, &info_parent
))
156 if (info
->st_dev
!= parent
->st_dev
)
159 if (info
->st_ino
== parent
->st_ino
)
160 return TRUE
; /* Same device and inode */
165 /* TRUE if this mount point was mounted by the user, and still is */
166 gboolean
mount_is_user_mounted(const gchar
*path
)
171 real
= pathdup(path
);
173 retval
= g_hash_table_lookup(user_mounts
, path
) != NULL
;
177 /* Check the status is up-to-date */
178 mount_user_mount(real
);
179 retval
= g_hash_table_lookup(user_mounts
, path
) != NULL
;
187 /****************************************************************
188 * INTERNAL FUNCTIONS *
189 ****************************************************************/
192 #ifdef DO_MOUNT_POINTS
194 static gboolean
free_mp(gpointer key
, gpointer value
, gpointer data
)
196 MountPoint
*mp
= (MountPoint
*) value
;
205 /* Remove all entries from mounts table, freeing them as we go */
206 static void clear_table(void)
208 g_hash_table_foreach_remove(fstab_mounts
, free_mp
, NULL
);
211 /* Return the mtime of a file */
212 static time_t read_time(char *path
)
217 err
= stat(path
, &info
);
219 g_return_val_if_fail(err
== 0, 0);
221 return info
.st_mtime
;
224 # ifdef HAVE_MNTENT_H
225 static void read_table(void)
236 tab
= setmntent(THE_FSTAB
, "r");
237 g_return_if_fail(tab
!= NULL
);
244 fcntl(fileno(tab
), F_SETLKW
, &lb
);
247 while ((ent
= getmntent(tab
)))
249 if (strcmp(ent
->mnt_dir
, "swap") == 0)
252 mp
= g_malloc(sizeof(MountPoint
));
253 mp
->name
= g_strdup(ent
->mnt_fsname
);
254 mp
->dir
= g_strdup(ent
->mnt_dir
);
256 g_hash_table_insert(fstab_mounts
, mp
->dir
, mp
);
262 # elif HAVE_SYS_MNTENT_H
263 static void read_table(void)
274 tab
= fopen(THE_FSTAB
, "r");
275 g_return_if_fail(tab
!= NULL
);
282 fcntl(fileno(tab
), F_SETLKW
, &lb
);
285 while (getmntent(tab
, &ent
)==0)
287 if (strcmp(ent
.mnt_special
, "swap") == 0)
290 mp
= g_malloc(sizeof(MountPoint
));
291 mp
->dir
= g_strdup(ent
.mnt_mountp
);
292 mp
->name
= g_strdup(ent
.mnt_special
);
294 g_hash_table_insert(fstab_mounts
, mp
->dir
, mp
);
300 # elif HAVE_SYS_UCRED_H /* We don't have getmntent(), etc */
302 static void read_table(void)
311 g_return_if_fail(tab
!= 0);
313 while ((ent
= getfsent()))
315 if (strcmp(ent
->fs_vfstype
, "swap") == 0)
317 if (strcmp(ent
->fs_vfstype
, "kernfs") == 0)
320 mp
= g_malloc(sizeof(MountPoint
));
321 mp
->name
= g_strdup(ent
->fs_spec
); /* block special device name */
322 mp
->dir
= g_strdup(ent
->fs_file
); /* file system path prefix */
324 g_hash_table_insert(fstab_mounts
, mp
->dir
, mp
);
330 # endif /* HAVE_MNTENT_H */
332 #endif /* DO_MOUNT_POINTS */
334 gchar
*mount_get_fs_size(const gchar
*dir
)
338 #if defined(HAVE_STATVFS)
340 #elif defined(HAVE_STATFS)
343 unsigned long long total
, used
, avail
;
348 #if defined(HAVE_STATVFS)
349 ok
=statvfs(dir
, &buf
)==0;
350 #elif defined(HAVE_STATFS)
351 ok
=statfs(dir
, &buf
)==0;
356 #if defined(HAVE_STATVFS)
357 total
=buf
.f_frsize
*(unsigned long long) buf
.f_blocks
;
358 used
=buf
.f_frsize
*(unsigned long long) (buf
.f_blocks
-buf
.f_bfree
);
359 avail
=buf
.f_frsize
*(unsigned long long) buf
.f_bavail
;
360 #elif defined(HAVE_STATFS)
361 total
=buf
.f_bsize
*(unsigned long long) buf
.f_blocks
;
362 used
=buf
.f_bsize
*(unsigned long long) (buf
.f_blocks
-buf
.f_bfree
);
363 avail
=buf
.f_bsize
*(unsigned long long) buf
.f_bavail
;
366 fused
=100.*(total
-used
)/((gdouble
) total
);
370 tmp1
=g_strdup(format_size(total
));
371 tmp2
=g_strdup(format_size(used
));
372 str
=g_strdup_printf(_("%s total, %s used, %s free (%.1f %%)"),
373 tmp1
, tmp2
, format_size(avail
), fused
);