4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2003, 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)
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
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 */
33 #elif HAVE_SYS_UCRED_H
34 /* NetBSD, OSF1, etc */
36 # include <sys/types.h>
37 # include <sys/param.h>
38 # include <sys/ucred.h>
39 # include <sys/mount.h>
41 #elif HAVE_SYS_MNTENT_H
43 # include <sys/mntent.h>
44 # include <sys/mnttab.h>
51 #include <sys/statvfs.h>
61 /* Map mount points to mntent structures */
62 GHashTable
*fstab_mounts
= NULL
;
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
71 #define THE_FSTAB "/etc/fstab"
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
);
83 /****************************************************************
84 * EXTERNAL INTERFACE *
85 ****************************************************************/
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
,
93 #ifdef DO_MOUNT_POINTS
94 fstab_time
= read_time(THE_FSTAB
);
99 /* If force is true then ignore the timestamps */
100 void mount_update(gboolean force
)
102 #ifdef DO_MOUNT_POINTS
105 time
= read_time(THE_FSTAB
);
106 if (force
|| time
!= fstab_time
)
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");
122 g_hash_table_remove(user_mounts
, path
);
125 /* TRUE iff this directory is a mount point. Uses python's method to
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
,
136 struct stat info_path
, info_parent
;
141 if (stat(path
, &info_path
))
142 return FALSE
; /* Doesn't exist => not mount point :-) */
148 parent
= &info_parent
;
149 tmp
= g_strconcat(path
, "/..", NULL
);
150 if (stat(tmp
, &info_parent
))
158 if (info
->st_dev
!= parent
->st_dev
)
161 if (info
->st_ino
== parent
->st_ino
)
162 return TRUE
; /* Same device and inode */
167 /* TRUE if this mount point was mounted by the user, and still is */
168 gboolean
mount_is_user_mounted(const gchar
*path
)
173 real
= pathdup(path
);
175 retval
= g_hash_table_lookup(user_mounts
, path
) != NULL
;
179 /* Check the status is up-to-date */
180 mount_user_mount(real
);
181 retval
= g_hash_table_lookup(user_mounts
, path
) != NULL
;
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
;
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
)
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)
238 tab
= setmntent(THE_FSTAB
, "r");
239 g_return_if_fail(tab
!= NULL
);
246 fcntl(fileno(tab
), F_SETLKW
, &lb
);
249 while ((ent
= getmntent(tab
)))
251 if (strcmp(ent
->mnt_dir
, "swap") == 0)
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
);
264 # elif HAVE_SYS_MNTENT_H
265 static void read_table(void)
276 tab
= fopen(THE_FSTAB
, "r");
277 g_return_if_fail(tab
!= NULL
);
284 fcntl(fileno(tab
), F_SETLKW
, &lb
);
287 while (getmntent(tab
, &ent
)==0)
289 if (strcmp(ent
.mnt_special
, "swap") == 0)
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
);
302 # elif HAVE_SYS_UCRED_H /* We don't have getmntent(), etc */
304 static void read_table(void)
313 g_return_if_fail(tab
!= 0);
315 while ((ent
= getfsent()))
317 if (strcmp(ent
->fs_vfstype
, "swap") == 0)
319 if (strcmp(ent
->fs_vfstype
, "kernfs") == 0)
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
);
332 # endif /* HAVE_MNTENT_H */
334 #endif /* DO_MOUNT_POINTS */
336 gchar
*mount_get_fs_size(const gchar
*dir
)
340 #if defined(HAVE_STATVFS)
342 #elif defined(HAVE_STATFS)
345 unsigned long long total
, used
, avail
;
350 #if defined(HAVE_STATVFS)
351 ok
=statvfs(dir
, &buf
)==0;
352 #elif defined(HAVE_STATFS)
353 ok
=statfs(dir
, &buf
)==0;
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
;
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
;
368 fused
=100.*(total
-used
)/((gdouble
) total
);
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
);