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 */
32 #elif HAVE_SYS_UCRED_H
33 /* NetBSD, OSF1, etc */
35 # include <sys/types.h>
36 # include <sys/param.h>
37 # include <sys/ucred.h>
38 # include <sys/mount.h>
40 #elif HAVE_SYS_MNTENT_H
42 # include <sys/mntent.h>
43 # include <sys/mnttab.h>
49 #ifdef HAVE_SYS_STATVFS_H
50 #include <sys/statvfs.h>
60 /* Map mount points to mntent structures */
61 GHashTable
*fstab_mounts
= NULL
;
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
70 #define THE_FSTAB "/etc/fstab"
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
);
82 /****************************************************************
83 * EXTERNAL INTERFACE *
84 ****************************************************************/
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
,
92 #ifdef DO_MOUNT_POINTS
93 if(file_exists(THE_FSTAB
))
95 fstab_time
= read_time(THE_FSTAB
);
100 #if defined(HAVE_MNTENT_H) || defined(HAVE_SYS_MNTENT_H)
101 /* We need THE_FSTAB for these implementations, but
103 g_warning(_("File system table \"%s\" not found, cannot monitor system mounts"), THE_FSTAB
);
110 /* If force is true then ignore the timestamps */
111 void mount_update(gboolean force
)
113 #ifdef DO_MOUNT_POINTS
116 time
= read_time(THE_FSTAB
);
117 if (force
|| time
!= fstab_time
)
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");
133 g_hash_table_remove(user_mounts
, path
);
136 /* TRUE iff this directory is a mount point. Uses python's method to
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
,
147 struct stat info_path
, info_parent
;
152 if (stat(path
, &info_path
))
153 return FALSE
; /* Doesn't exist => not mount point :-) */
159 parent
= &info_parent
;
160 tmp
= g_strconcat(path
, "/..", NULL
);
161 if (stat(tmp
, &info_parent
))
169 if (info
->st_dev
!= parent
->st_dev
)
172 if (info
->st_ino
== parent
->st_ino
)
173 return TRUE
; /* Same device and inode */
178 /* TRUE if this mount point was mounted by the user, and still is */
179 gboolean
mount_is_user_mounted(const gchar
*path
)
184 real
= pathdup(path
);
186 retval
= g_hash_table_lookup(user_mounts
, path
) != NULL
;
190 /* Check the status is up-to-date */
191 mount_user_mount(real
);
192 retval
= g_hash_table_lookup(user_mounts
, path
) != NULL
;
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
;
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
)
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
)
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)
252 if(!file_exists(THE_FSTAB
))
255 tab
= setmntent(THE_FSTAB
, "r");
256 g_return_if_fail(tab
!= NULL
);
263 fcntl(fileno(tab
), F_SETLKW
, &lb
);
266 while ((ent
= getmntent(tab
)))
268 if (strcmp(ent
->mnt_dir
, "swap") == 0)
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
);
281 # elif HAVE_SYS_MNTENT_H
282 static void read_table(void)
292 if(!file_exists(THE_FSTAB
))
295 tab
= fopen(THE_FSTAB
, "r");
296 g_return_if_fail(tab
!= NULL
);
303 fcntl(fileno(tab
), F_SETLKW
, &lb
);
306 while (getmntent(tab
, &ent
)==0)
308 if (strcmp(ent
.mnt_special
, "swap") == 0)
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
);
321 # elif HAVE_SYS_UCRED_H /* We don't have getmntent(), etc */
323 static void read_table(void)
332 g_return_if_fail(tab
!= 0);
334 while ((ent
= getfsent()))
336 if (strcmp(ent
->fs_vfstype
, "swap") == 0)
338 if (strcmp(ent
->fs_vfstype
, "kernfs") == 0)
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
);
351 # endif /* HAVE_MNTENT_H */
353 #endif /* DO_MOUNT_POINTS */
355 gchar
*mount_get_fs_size(const gchar
*dir
)
359 #if defined(HAVE_STATVFS)
361 #elif defined(HAVE_STATFS)
364 unsigned long long total
, used
, avail
;
369 #if defined(HAVE_STATVFS)
370 ok
=statvfs(dir
, &buf
)==0;
371 #elif defined(HAVE_STATFS)
372 ok
=statfs(dir
, &buf
)==0;
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
;
387 fused
=100.*(total
-used
)/((gdouble
) total
);
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
);