r3768: Updated years.
[rox-filer.git] / ROX-Filer / src / mount.c
blobff7981f570f55c307e817bd7aabaeeec43d9021d
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2005, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* mount.c - code for handling mount points */
24 #include "config.h"
25 #include <stdio.h>
26 #include <string.h>
27 #ifdef HAVE_FCNTL_H
28 #include <fcntl.h>
29 #endif
30 #ifdef HAVE_MNTENT_H
31 /* Linux, etc */
32 # include <mntent.h>
33 #elif HAVE_SYS_UCRED_H
34 /* NetBSD, OSF1, etc */
35 # include <fstab.h>
36 # include <sys/types.h>
37 # include <sys/param.h>
38 # include <sys/ucred.h>
39 # include <sys/mount.h>
40 # include <stdlib.h>
41 #elif HAVE_SYS_MNTENT_H
42 /* SunOS */
43 # include <sys/mntent.h>
44 # include <sys/mnttab.h>
45 #endif
46 #include <sys/time.h>
47 #ifdef HAVE_SYS_VFS_H
48 #include <sys/vfs.h>
49 #endif
50 #ifdef HAVE_SYS_STATVFS_H
51 #include <sys/statvfs.h>
52 #endif
54 #include <gtk/gtk.h>
56 #include "global.h"
58 #include "mount.h"
59 #include "support.h"
61 /* Map mount points to mntent structures */
62 GHashTable *fstab_mounts = NULL;
63 time_t fstab_time;
65 /* Keys are mount points that the user mounted. Values are ignored. */
66 static GHashTable *user_mounts = NULL;
68 #ifdef HAVE_SYS_MNTENT_H
69 #define THE_FSTAB VFSTAB
70 #else
71 #define THE_FSTAB "/etc/fstab"
72 #endif
74 /* Static prototypes */
75 #ifdef DO_MOUNT_POINTS
76 static void read_table(void);
77 static void clear_table(void);
78 static time_t read_time(char *path);
79 static gboolean free_mp(gpointer key, gpointer value, gpointer data);
80 #endif
83 /****************************************************************
84 * EXTERNAL INTERFACE *
85 ****************************************************************/
87 void mount_init(void)
89 fstab_mounts = g_hash_table_new(g_str_hash, g_str_equal);
90 user_mounts = g_hash_table_new_full(g_str_hash, g_str_equal,
91 g_free, NULL);
93 #ifdef DO_MOUNT_POINTS
94 fstab_time = read_time(THE_FSTAB);
95 read_table();
96 #endif
99 /* If force is true then ignore the timestamps */
100 void mount_update(gboolean force)
102 #ifdef DO_MOUNT_POINTS
103 time_t time;
105 time = read_time(THE_FSTAB);
106 if (force || time != fstab_time)
108 fstab_time = time;
109 read_table();
111 #endif /* DO_MOUNT_POINTS */
114 /* The user has just finished mounting/unmounting this path.
115 * Update the list of user-mounted filesystems.
117 void mount_user_mount(const char *path)
119 if (mount_is_mounted(path, NULL, NULL))
120 g_hash_table_insert(user_mounts, pathdup(path), "yes");
121 else
122 g_hash_table_remove(user_mounts, path);
125 /* TRUE iff this directory is a mount point. Uses python's method to
126 * check:
127 * The function checks whether path's parent, path/.., is on a different device
128 * than path, or whether path/.. and path point to the same i-node on the same
129 * device -- this should detect mount points for all Unix and POSIX variants.
131 * 'info' and 'parent' are both optional, saving one stat() each.
133 gboolean mount_is_mounted(const guchar *path, struct stat *info,
134 struct stat *parent)
136 struct stat info_path, info_parent;
138 if (!info)
140 info = &info_path;
141 if (stat(path, &info_path))
142 return FALSE; /* Doesn't exist => not mount point :-) */
145 if (!parent)
147 guchar *tmp;
148 parent = &info_parent;
149 tmp = g_strconcat(path, "/..", NULL);
150 if (stat(tmp, &info_parent))
152 g_free(tmp);
153 return FALSE;
155 g_free(tmp);
158 if (info->st_dev != parent->st_dev)
159 return TRUE;
161 if (info->st_ino == parent->st_ino)
162 return TRUE; /* Same device and inode */
164 return FALSE;
167 /* TRUE if this mount point was mounted by the user, and still is */
168 gboolean mount_is_user_mounted(const gchar *path)
170 gboolean retval;
171 gchar *real;
173 real = pathdup(path);
175 retval = g_hash_table_lookup(user_mounts, path) != NULL;
177 if (retval)
179 /* Check the status is up-to-date */
180 mount_user_mount(real);
181 retval = g_hash_table_lookup(user_mounts, path) != NULL;
184 g_free(real);
186 return retval;
189 /****************************************************************
190 * INTERNAL FUNCTIONS *
191 ****************************************************************/
194 #ifdef DO_MOUNT_POINTS
196 static gboolean free_mp(gpointer key, gpointer value, gpointer data)
198 MountPoint *mp = (MountPoint *) value;
200 g_free(mp->name);
201 g_free(mp->dir);
202 g_free(mp);
204 return TRUE;
207 /* Remove all entries from mounts table, freeing them as we go */
208 static void clear_table(void)
210 g_hash_table_foreach_remove(fstab_mounts, free_mp, NULL);
213 /* Return the mtime of a file */
214 static time_t read_time(char *path)
216 struct stat info;
217 int err = 0;
219 err = stat(path, &info);
221 g_return_val_if_fail(err == 0, 0);
223 return info.st_mtime;
226 # ifdef HAVE_MNTENT_H
227 static void read_table(void)
229 FILE *tab;
230 struct mntent *ent;
231 MountPoint *mp;
232 # ifdef HAVE_FCNTL_H
233 struct flock lb;
234 # endif
236 clear_table();
238 tab = setmntent(THE_FSTAB, "r");
239 g_return_if_fail(tab != NULL);
241 # ifdef HAVE_FCNTL_H
242 lb.l_type = F_RDLCK;
243 lb.l_whence = 0;
244 lb.l_start = 0;
245 lb.l_len = 0;
246 fcntl(fileno(tab), F_SETLKW, &lb);
247 # endif
249 while ((ent = getmntent(tab)))
251 if (strcmp(ent->mnt_dir, "swap") == 0)
252 continue;
254 mp = g_malloc(sizeof(MountPoint));
255 mp->name = g_strdup(ent->mnt_fsname);
256 mp->dir = g_strdup(ent->mnt_dir);
258 g_hash_table_insert(fstab_mounts, mp->dir, mp);
261 endmntent(tab);
264 # elif HAVE_SYS_MNTENT_H
265 static void read_table(void)
267 FILE *tab;
268 struct mnttab ent;
269 MountPoint *mp;
270 # ifdef HAVE_FCNTL_H
271 struct flock lb;
272 # endif
274 clear_table();
276 tab = fopen(THE_FSTAB, "r");
277 g_return_if_fail(tab != NULL);
279 # ifdef HAVE_FCNTL_H
280 lb.l_type = F_RDLCK;
281 lb.l_whence = 0;
282 lb.l_start = 0;
283 lb.l_len = 0;
284 fcntl(fileno(tab), F_SETLKW, &lb);
285 # endif
287 while (getmntent(tab, &ent)==0)
289 if (strcmp(ent.mnt_special, "swap") == 0)
290 continue;
292 mp = g_malloc(sizeof(MountPoint));
293 mp->dir = g_strdup(ent.mnt_mountp);
294 mp->name = g_strdup(ent.mnt_special);
296 g_hash_table_insert(fstab_mounts, mp->dir, mp);
299 fclose(tab);
302 # elif HAVE_SYS_UCRED_H /* We don't have getmntent(), etc */
304 static void read_table(void)
306 int tab;
307 struct fstab *ent;
308 MountPoint *mp;
310 clear_table();
312 tab = setfsent();
313 g_return_if_fail(tab != 0);
315 while ((ent = getfsent()))
317 if (strcmp(ent->fs_vfstype, "swap") == 0)
318 continue;
319 if (strcmp(ent->fs_vfstype, "kernfs") == 0)
320 continue;
322 mp = g_malloc(sizeof(MountPoint));
323 mp->name = g_strdup(ent->fs_spec); /* block special device name */
324 mp->dir = g_strdup(ent->fs_file); /* file system path prefix */
326 g_hash_table_insert(fstab_mounts, mp->dir, mp);
329 endfsent();
332 # endif /* HAVE_MNTENT_H */
334 #endif /* DO_MOUNT_POINTS */
336 gchar *mount_get_fs_size(const gchar *dir)
338 int ok=FALSE;
340 #if defined(HAVE_STATVFS)
341 struct statvfs buf;
342 #elif defined(HAVE_STATFS)
343 struct statfs buf;
344 #endif
345 unsigned long long total, used, avail;
346 gdouble fused;
347 gchar *str;
348 gchar *tmp1, *tmp2;
350 #if defined(HAVE_STATVFS)
351 ok=statvfs(dir, &buf)==0;
352 #elif defined(HAVE_STATFS)
353 ok=statfs(dir, &buf)==0;
354 #endif
355 if(!ok)
356 return NULL;
358 #if defined(HAVE_STATVFS)
359 total=buf.f_frsize*(unsigned long long) buf.f_blocks;
360 used=buf.f_frsize*(unsigned long long) (buf.f_blocks-buf.f_bfree);
361 avail=buf.f_frsize*(unsigned long long) buf.f_bavail;
362 #elif defined(HAVE_STATFS)
363 total=buf.f_bsize*(unsigned long long) buf.f_blocks;
364 used=buf.f_bsize*(unsigned long long) (buf.f_blocks-buf.f_bfree);
365 avail=buf.f_bsize*(unsigned long long) buf.f_bavail;
366 #endif
367 if(total>0)
368 fused=100.*(total-used)/((gdouble) total);
369 else
370 fused=0.0;
372 tmp1=g_strdup(format_size(total));
373 tmp2=g_strdup(format_size(used));
374 str=g_strdup_printf(_("%s total, %s used, %s free (%.1f %%)"),
375 tmp1, tmp2, format_size(avail), fused);
377 g_free(tmp1);
378 g_free(tmp2);
380 return str;