Converted README to markdown
[rox-filer.git] / ROX-Filer / src / mount.c
blob9bb9bce871076881123a4400d834326b3aa3126f
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 #include <errno.h>
26 #ifdef HAVE_FCNTL_H
27 #include <fcntl.h>
28 #endif
29 #ifdef HAVE_MNTENT_H
30 /* Linux, etc */
31 # include <mntent.h>
32 #elif HAVE_SYS_UCRED_H
33 /* NetBSD, OSF1, etc */
34 # include <fstab.h>
35 # include <sys/types.h>
36 # include <sys/param.h>
37 # include <sys/ucred.h>
38 # include <sys/mount.h>
39 # include <stdlib.h>
40 #elif HAVE_SYS_MNTENT_H
41 /* SunOS */
42 # include <sys/mntent.h>
43 # include <sys/mnttab.h>
44 #endif
45 #include <sys/time.h>
46 #ifdef HAVE_SYS_VFS_H
47 #include <sys/vfs.h>
48 #endif
49 #ifdef HAVE_SYS_STATVFS_H
50 #include <sys/statvfs.h>
51 #endif
53 #include <gtk/gtk.h>
55 #include "global.h"
57 #include "mount.h"
58 #include "support.h"
60 /* Map mount points to mntent structures */
61 GHashTable *fstab_mounts = NULL;
62 time_t fstab_time;
64 /* Keys are mount points that the user mounted. Values are ignored. */
65 static GHashTable *user_mounts = NULL;
67 #ifdef HAVE_SYS_MNTENT_H
68 #define THE_FSTAB VFSTAB
69 #else
70 #define THE_FSTAB "/etc/fstab"
71 #endif
73 /* Static prototypes */
74 #ifdef DO_MOUNT_POINTS
75 static void read_table(void);
76 static void clear_table(void);
77 static time_t read_time(char *path);
78 static gboolean free_mp(gpointer key, gpointer value, gpointer data);
79 #endif
82 /****************************************************************
83 * EXTERNAL INTERFACE *
84 ****************************************************************/
86 void mount_init(void)
88 fstab_mounts = g_hash_table_new(g_str_hash, g_str_equal);
89 user_mounts = g_hash_table_new_full(g_str_hash, g_str_equal,
90 g_free, NULL);
92 #ifdef DO_MOUNT_POINTS
93 if(file_exists(THE_FSTAB))
95 fstab_time = read_time(THE_FSTAB);
97 } else {
98 fstab_time = 0;
100 #if defined(HAVE_MNTENT_H) || defined(HAVE_SYS_MNTENT_H)
101 /* We need THE_FSTAB for these implementations, but
102 * it is missing */
103 g_warning(_("File system table \"%s\" not found, cannot monitor system mounts"), THE_FSTAB);
104 #endif
106 read_table();
107 #endif
110 /* If force is true then ignore the timestamps */
111 void mount_update(gboolean force)
113 #ifdef DO_MOUNT_POINTS
114 time_t time;
116 time = read_time(THE_FSTAB);
117 if (force || time != fstab_time)
119 fstab_time = time;
120 read_table();
122 #endif /* DO_MOUNT_POINTS */
125 /* The user has just finished mounting/unmounting this path.
126 * Update the list of user-mounted filesystems.
128 void mount_user_mount(const char *path)
130 if (mount_is_mounted(path, NULL, NULL))
131 g_hash_table_insert(user_mounts, pathdup(path), "yes");
132 else
133 g_hash_table_remove(user_mounts, path);
136 /* TRUE iff this directory is a mount point. Uses python's method to
137 * check:
138 * The function checks whether path's parent, path/.., is on a different device
139 * than path, or whether path/.. and path point to the same i-node on the same
140 * device -- this should detect mount points for all Unix and POSIX variants.
142 * 'info' and 'parent' are both optional, saving one stat() each.
144 gboolean mount_is_mounted(const guchar *path, struct stat *info,
145 struct stat *parent)
147 struct stat info_path, info_parent;
149 if (!info)
151 info = &info_path;
152 if (stat(path, &info_path))
153 return FALSE; /* Doesn't exist => not mount point :-) */
156 if (!parent)
158 guchar *tmp;
159 parent = &info_parent;
160 tmp = g_strconcat(path, "/..", NULL);
161 if (stat(tmp, &info_parent))
163 g_free(tmp);
164 return FALSE;
166 g_free(tmp);
169 if (info->st_dev != parent->st_dev)
170 return TRUE;
172 if (info->st_ino == parent->st_ino)
173 return TRUE; /* Same device and inode */
175 return FALSE;
178 /* TRUE if this mount point was mounted by the user, and still is */
179 gboolean mount_is_user_mounted(const gchar *path)
181 gboolean retval;
182 gchar *real;
184 real = pathdup(path);
186 retval = g_hash_table_lookup(user_mounts, path) != NULL;
188 if (retval)
190 /* Check the status is up-to-date */
191 mount_user_mount(real);
192 retval = g_hash_table_lookup(user_mounts, path) != NULL;
195 g_free(real);
197 return retval;
200 /****************************************************************
201 * INTERNAL FUNCTIONS *
202 ****************************************************************/
205 #ifdef DO_MOUNT_POINTS
207 static gboolean free_mp(gpointer key, gpointer value, gpointer data)
209 MountPoint *mp = (MountPoint *) value;
211 g_free(mp->name);
212 g_free(mp->dir);
213 g_free(mp);
215 return TRUE;
218 /* Remove all entries from mounts table, freeing them as we go */
219 static void clear_table(void)
221 g_hash_table_foreach_remove(fstab_mounts, free_mp, NULL);
224 /* Return the mtime of a file - only used for the fstab file */
225 static time_t read_time(char *path)
227 struct stat info;
228 int err = 0;
230 err = stat(path, &info);
232 /* Don't print an error if the file is missing, just return the
233 * epoch (change if used for more than the fstab?) */
234 if(err && errno==ENOENT)
235 return 0;
236 g_return_val_if_fail(err == 0, 0);
238 return info.st_mtime;
241 # ifdef HAVE_MNTENT_H
242 static void read_table(void)
244 FILE *tab;
245 struct mntent *ent;
246 MountPoint *mp;
247 # ifdef HAVE_FCNTL_H
248 struct flock lb;
249 # endif
251 clear_table();
252 if(!file_exists(THE_FSTAB))
253 return;
255 tab = setmntent(THE_FSTAB, "r");
256 g_return_if_fail(tab != NULL);
258 # ifdef HAVE_FCNTL_H
259 lb.l_type = F_RDLCK;
260 lb.l_whence = 0;
261 lb.l_start = 0;
262 lb.l_len = 0;
263 fcntl(fileno(tab), F_SETLKW, &lb);
264 # endif
266 while ((ent = getmntent(tab)))
268 if (strcmp(ent->mnt_dir, "swap") == 0)
269 continue;
271 mp = g_malloc(sizeof(MountPoint));
272 mp->name = g_strdup(ent->mnt_fsname);
273 mp->dir = g_strdup(ent->mnt_dir);
275 g_hash_table_insert(fstab_mounts, mp->dir, mp);
278 endmntent(tab);
281 # elif HAVE_SYS_MNTENT_H
282 static void read_table(void)
284 FILE *tab;
285 struct mnttab ent;
286 MountPoint *mp;
287 # ifdef HAVE_FCNTL_H
288 struct flock lb;
289 # endif
291 clear_table();
292 if(!file_exists(THE_FSTAB))
293 return;
295 tab = fopen(THE_FSTAB, "r");
296 g_return_if_fail(tab != NULL);
298 # ifdef HAVE_FCNTL_H
299 lb.l_type = F_RDLCK;
300 lb.l_whence = 0;
301 lb.l_start = 0;
302 lb.l_len = 0;
303 fcntl(fileno(tab), F_SETLKW, &lb);
304 # endif
306 while (getmntent(tab, &ent)==0)
308 if (strcmp(ent.mnt_special, "swap") == 0)
309 continue;
311 mp = g_malloc(sizeof(MountPoint));
312 mp->dir = g_strdup(ent.mnt_mountp);
313 mp->name = g_strdup(ent.mnt_special);
315 g_hash_table_insert(fstab_mounts, mp->dir, mp);
318 fclose(tab);
321 # elif HAVE_SYS_UCRED_H /* We don't have getmntent(), etc */
323 static void read_table(void)
325 int tab;
326 struct fstab *ent;
327 MountPoint *mp;
329 clear_table();
331 tab = setfsent();
332 g_return_if_fail(tab != 0);
334 while ((ent = getfsent()))
336 if (strcmp(ent->fs_vfstype, "swap") == 0)
337 continue;
338 if (strcmp(ent->fs_vfstype, "kernfs") == 0)
339 continue;
341 mp = g_malloc(sizeof(MountPoint));
342 mp->name = g_strdup(ent->fs_spec); /* block special device name */
343 mp->dir = g_strdup(ent->fs_file); /* file system path prefix */
345 g_hash_table_insert(fstab_mounts, mp->dir, mp);
348 endfsent();
351 # endif /* HAVE_MNTENT_H */
353 #endif /* DO_MOUNT_POINTS */
355 gchar *mount_get_fs_size(const gchar *dir)
357 int ok=FALSE;
359 #if defined(HAVE_STATVFS)
360 struct statvfs buf;
361 #elif defined(HAVE_STATFS)
362 struct statfs buf;
363 #endif
364 unsigned long long total, used, avail;
365 gdouble fused;
366 gchar *str;
367 gchar *tmp1, *tmp2;
369 #if defined(HAVE_STATVFS)
370 ok=statvfs(dir, &buf)==0;
371 #elif defined(HAVE_STATFS)
372 ok=statfs(dir, &buf)==0;
373 #endif
374 if(!ok)
375 return NULL;
377 #if defined(HAVE_STATVFS)
378 total=buf.f_frsize*(unsigned long long) buf.f_blocks;
379 used=buf.f_frsize*(unsigned long long) (buf.f_blocks-buf.f_bfree);
380 avail=buf.f_frsize*(unsigned long long) buf.f_bavail;
381 #elif defined(HAVE_STATFS)
382 total=buf.f_bsize*(unsigned long long) buf.f_blocks;
383 used=buf.f_bsize*(unsigned long long) (buf.f_blocks-buf.f_bfree);
384 avail=buf.f_bsize*(unsigned long long) buf.f_bavail;
385 #endif
386 if(total>0)
387 fused=100.*(total-used)/((gdouble) total);
388 else
389 fused=0.0;
391 tmp1=g_strdup(format_size(total));
392 tmp2=g_strdup(format_size(used));
393 str=g_strdup_printf(_("%s total, %s used, %s free (%.1f %%)"),
394 tmp1, tmp2, format_size(avail), fused);
396 g_free(tmp1);
397 g_free(tmp2);
399 return str;