1 /* Copyright (C) 1998-2006, 2010, 2011 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 #include <stdio_ext.h>
27 #include <sys/mount.h>
29 #include <sys/statfs.h>
30 #include <sys/statvfs.h>
31 #include "linux_fsinfo.h"
32 #include "kernel-features.h"
35 /* Special internal-only bit value. */
36 #define ST_VALID 0x0020
40 # define STATFS statfs
41 # define STATVFS statvfs
42 # define INTERNAL_STATVFS __internal_statvfs
45 # ifndef __ASSUME_STATFS_F_FLAGS
47 __statvfs_getflags (const char *name, int fstype, struct stat64 *st)
52 const char *fsname = NULL;
53 const char *fsname2 = NULL;
54 const char *fsname3 = NULL;
56 /* Map the filesystem type we got from the statfs call to a string. */
59 case EXT2_SUPER_MAGIC:
64 case DEVPTS_SUPER_MAGIC:
67 case SHMFS_SUPER_MAGIC:
70 case PROC_SUPER_MAGIC:
73 case USBDEVFS_SUPER_MAGIC:
76 case AUTOFS_SUPER_MAGIC:
85 case REISERFS_SUPER_MAGIC:
94 case HPFS_SUPER_MAGIC:
97 case DEVFS_SUPER_MAGIC:
100 case ISOFS_SUPER_MAGIC:
103 case MSDOS_SUPER_MAGIC:
106 case NTFS_SUPER_MAGIC:
109 case LOGFS_MAGIC_U32:
112 case BTRFS_SUPER_MAGIC:
115 case CGROUP_SUPER_MAGIC:
118 case LUSTRE_SUPER_MAGIC:
123 FILE *mtab = __setmntent ("/proc/mounts", "r");
125 mtab = __setmntent (_PATH_MOUNTED, "r");
130 bool success = false;
131 struct mntent mntbuf;
134 /* No locking needed. */
135 (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER);
138 while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf)))
140 /* In a first round we look for a given mount point, if
142 if (name != NULL && strcmp (name, mntbuf.mnt_dir) != 0)
144 /* We need to look at the entry only if the filesystem
145 name matches. If we have a filesystem name. */
146 else if (fsname != NULL
147 && strcmp (fsname, mntbuf.mnt_type) != 0
149 || strcmp (fsname2, mntbuf.mnt_type) != 0)
151 || strcmp (fsname3, mntbuf.mnt_type) != 0))
154 /* Find out about the device the current entry is for. */
156 if (stat64 (mntbuf.mnt_dir, &fsst) >= 0
157 && st->st_dev == fsst.st_dev)
159 /* Bingo, we found the entry for the device FD is on.
160 Now interpret the option string. */
161 char *cp = mntbuf.mnt_opts;
164 while ((opt = strsep (&cp, ",")) != NULL)
165 if (strcmp (opt, "ro") == 0)
167 else if (strcmp (opt, "nosuid") == 0)
169 else if (strcmp (opt, "noexec") == 0)
171 else if (strcmp (opt, "nodev") == 0)
173 else if (strcmp (opt, "sync") == 0)
174 result |= ST_SYNCHRONOUS;
175 else if (strcmp (opt, "mand") == 0)
176 result |= ST_MANDLOCK;
177 else if (strcmp (opt, "noatime") == 0)
178 result |= ST_NOATIME;
179 else if (strcmp (opt, "nodiratime") == 0)
180 result |= ST_NODIRATIME;
181 else if (strcmp (opt, "relatime") == 0)
182 result |= ST_RELATIME;
184 /* We can stop looking for more entries. */
189 /* Maybe the kernel names for the filesystems changed or the
190 statvfs call got a name which was not the mount point. Check
191 again, this time without checking for name matches first. */
192 if (! success && (name != NULL || fsname != NULL))
195 /* Try without a mount point name. */
199 /* Try without a filesystem name. */
200 assert (fsname != NULL);
201 fsname = fsname2 = fsname3 = NULL;
204 /* It is not strictly allowed to use rewind here. But
205 this code is part of the implementation so it is
212 /* Close the file. */
220 extern int __statvfs_getflags (const char *name, int fstype,
226 INTERNAL_STATVFS (const char *name, struct STATVFS *buf,
227 struct STATFS *fsbuf, struct stat64 *st)
229 /* Now fill in the fields we have information for. */
230 buf->f_bsize = fsbuf->f_bsize;
231 /* Linux has the f_frsize size only in later version of the kernel.
232 If the value is not filled in use f_bsize. */
233 buf->f_frsize = fsbuf->f_frsize ?: fsbuf->f_bsize;
234 buf->f_blocks = fsbuf->f_blocks;
235 buf->f_bfree = fsbuf->f_bfree;
236 buf->f_bavail = fsbuf->f_bavail;
237 buf->f_files = fsbuf->f_files;
238 buf->f_ffree = fsbuf->f_ffree;
239 if (sizeof (buf->f_fsid) == sizeof (fsbuf->f_fsid))
240 /* The shifting uses 'unsigned long long int' even though the target
241 field might only have 32 bits. This is OK since the 'if' branch
242 is not used in this case but the compiler would still generate
244 buf->f_fsid = ((fsbuf->f_fsid.__val[0]
245 & ((1ULL << (8 * sizeof (fsbuf->f_fsid.__val[0]))) - 1))
246 | ((unsigned long long int) fsbuf->f_fsid.__val[1]
247 << (8 * (sizeof (buf->f_fsid)
248 - sizeof (fsbuf->f_fsid.__val[0])))));
250 /* We cannot help here. The statvfs element is not large enough to
251 contain both words of the statfs f_fsid field. */
252 buf->f_fsid = fsbuf->f_fsid.__val[0];
253 #ifdef _STATVFSBUF_F_UNUSED
256 buf->f_namemax = fsbuf->f_namelen;
257 memset (buf->__f_spare, '\0', sizeof (buf->__f_spare));
259 /* What remains to do is to fill the fields f_favail and f_flag. */
261 /* XXX I have no idea how to compute f_favail. Any idea??? */
262 buf->f_favail = buf->f_ffree;
264 #ifndef __ASSUME_STATFS_F_FLAGS
265 if ((fsbuf->f_flags & ST_VALID) == 0)
266 /* Determining the flags is tricky. We have to read /proc/mounts or
267 the /etc/mtab file and search for the entry which matches the given
268 file. The way we can test for matching filesystem is using the
270 buf->f_flag = __statvfs_getflags (name, fsbuf->f_type, st);
273 buf->f_flag = fsbuf->f_flags ^ ST_VALID;