r4523: Updated headers:
[rox-filer/ma.git] / ROX-Filer / src / mount.c
blob0a5ac748d893a778488c771832b2d45c6b9f25f1
1 /*
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)
8 * any later version.
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
13 * more details.
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 */
22 #include "config.h"
23 #include <stdio.h>
24 #include <string.h>
25 #ifdef HAVE_FCNTL_H
26 #include <fcntl.h>
27 #endif
28 #ifdef HAVE_MNTENT_H
29 /* Linux, etc */
30 # include <mntent.h>
31 #elif HAVE_SYS_UCRED_H
32 /* NetBSD, OSF1, etc */
33 # include <fstab.h>
34 # include <sys/types.h>
35 # include <sys/param.h>
36 # include <sys/ucred.h>
37 # include <sys/mount.h>
38 # include <stdlib.h>
39 #elif HAVE_SYS_MNTENT_H
40 /* SunOS */
41 # include <sys/mntent.h>
42 # include <sys/mnttab.h>
43 #endif
44 #include <sys/time.h>
45 #ifdef HAVE_SYS_VFS_H
46 #include <sys/vfs.h>
47 #endif
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
50 #endif
52 #include <gtk/gtk.h>
54 #include "global.h"
56 #include "mount.h"
57 #include "support.h"
59 /* Map mount points to mntent structures */
60 GHashTable *fstab_mounts = NULL;
61 time_t fstab_time;
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
68 #else
69 #define THE_FSTAB "/etc/fstab"
70 #endif
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);
78 #endif
81 /****************************************************************
82 * EXTERNAL INTERFACE *
83 ****************************************************************/
85 void mount_init(void)
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,
89 g_free, NULL);
91 #ifdef DO_MOUNT_POINTS
92 fstab_time = read_time(THE_FSTAB);
93 read_table();
94 #endif
97 /* If force is true then ignore the timestamps */
98 void mount_update(gboolean force)
100 #ifdef DO_MOUNT_POINTS
101 time_t time;
103 time = read_time(THE_FSTAB);
104 if (force || time != fstab_time)
106 fstab_time = time;
107 read_table();
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");
119 else
120 g_hash_table_remove(user_mounts, path);
123 /* TRUE iff this directory is a mount point. Uses python's method to
124 * check:
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,
132 struct stat *parent)
134 struct stat info_path, info_parent;
136 if (!info)
138 info = &info_path;
139 if (stat(path, &info_path))
140 return FALSE; /* Doesn't exist => not mount point :-) */
143 if (!parent)
145 guchar *tmp;
146 parent = &info_parent;
147 tmp = g_strconcat(path, "/..", NULL);
148 if (stat(tmp, &info_parent))
150 g_free(tmp);
151 return FALSE;
153 g_free(tmp);
156 if (info->st_dev != parent->st_dev)
157 return TRUE;
159 if (info->st_ino == parent->st_ino)
160 return TRUE; /* Same device and inode */
162 return FALSE;
165 /* TRUE if this mount point was mounted by the user, and still is */
166 gboolean mount_is_user_mounted(const gchar *path)
168 gboolean retval;
169 gchar *real;
171 real = pathdup(path);
173 retval = g_hash_table_lookup(user_mounts, path) != NULL;
175 if (retval)
177 /* Check the status is up-to-date */
178 mount_user_mount(real);
179 retval = g_hash_table_lookup(user_mounts, path) != NULL;
182 g_free(real);
184 return retval;
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;
198 g_free(mp->name);
199 g_free(mp->dir);
200 g_free(mp);
202 return TRUE;
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)
214 struct stat info;
215 int err = 0;
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)
227 FILE *tab;
228 struct mntent *ent;
229 MountPoint *mp;
230 # ifdef HAVE_FCNTL_H
231 struct flock lb;
232 # endif
234 clear_table();
236 tab = setmntent(THE_FSTAB, "r");
237 g_return_if_fail(tab != NULL);
239 # ifdef HAVE_FCNTL_H
240 lb.l_type = F_RDLCK;
241 lb.l_whence = 0;
242 lb.l_start = 0;
243 lb.l_len = 0;
244 fcntl(fileno(tab), F_SETLKW, &lb);
245 # endif
247 while ((ent = getmntent(tab)))
249 if (strcmp(ent->mnt_dir, "swap") == 0)
250 continue;
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);
259 endmntent(tab);
262 # elif HAVE_SYS_MNTENT_H
263 static void read_table(void)
265 FILE *tab;
266 struct mnttab ent;
267 MountPoint *mp;
268 # ifdef HAVE_FCNTL_H
269 struct flock lb;
270 # endif
272 clear_table();
274 tab = fopen(THE_FSTAB, "r");
275 g_return_if_fail(tab != NULL);
277 # ifdef HAVE_FCNTL_H
278 lb.l_type = F_RDLCK;
279 lb.l_whence = 0;
280 lb.l_start = 0;
281 lb.l_len = 0;
282 fcntl(fileno(tab), F_SETLKW, &lb);
283 # endif
285 while (getmntent(tab, &ent)==0)
287 if (strcmp(ent.mnt_special, "swap") == 0)
288 continue;
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);
297 fclose(tab);
300 # elif HAVE_SYS_UCRED_H /* We don't have getmntent(), etc */
302 static void read_table(void)
304 int tab;
305 struct fstab *ent;
306 MountPoint *mp;
308 clear_table();
310 tab = setfsent();
311 g_return_if_fail(tab != 0);
313 while ((ent = getfsent()))
315 if (strcmp(ent->fs_vfstype, "swap") == 0)
316 continue;
317 if (strcmp(ent->fs_vfstype, "kernfs") == 0)
318 continue;
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);
327 endfsent();
330 # endif /* HAVE_MNTENT_H */
332 #endif /* DO_MOUNT_POINTS */
334 gchar *mount_get_fs_size(const gchar *dir)
336 int ok=FALSE;
338 #if defined(HAVE_STATVFS)
339 struct statvfs buf;
340 #elif defined(HAVE_STATFS)
341 struct statfs buf;
342 #endif
343 unsigned long long total, used, avail;
344 gdouble fused;
345 gchar *str;
346 gchar *tmp1, *tmp2;
348 #if defined(HAVE_STATVFS)
349 ok=statvfs(dir, &buf)==0;
350 #elif defined(HAVE_STATFS)
351 ok=statfs(dir, &buf)==0;
352 #endif
353 if(!ok)
354 return NULL;
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;
364 #endif
365 if(total>0)
366 fused=100.*(total-used)/((gdouble) total);
367 else
368 fused=0.0;
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);
375 g_free(tmp1);
376 g_free(tmp2);
378 return str;