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, see
17 <http://www.gnu.org/licenses/>. */
24 #include <stdio_ext.h>
26 #include <sys/mount.h>
28 #include <sys/statfs.h>
29 #include <sys/statvfs.h>
30 #include "linux_fsinfo.h"
31 #include <kernel-features.h>
34 /* Special internal-only bit value. */
35 #define ST_VALID 0x0020
39 # define STATFS statfs
40 # define STATVFS statvfs
41 # define INTERNAL_STATVFS __internal_statvfs
44 # ifndef __ASSUME_STATFS_F_FLAGS
46 __statvfs_getflags (const char *name
, int fstype
, struct stat64
*st
)
51 const char *fsname
= NULL
;
52 const char *fsname2
= NULL
;
53 const char *fsname3
= NULL
;
55 /* Map the filesystem type we got from the statfs call to a string. */
58 case EXT2_SUPER_MAGIC
:
63 case DEVPTS_SUPER_MAGIC
:
66 case SHMFS_SUPER_MAGIC
:
69 case PROC_SUPER_MAGIC
:
72 case USBDEVFS_SUPER_MAGIC
:
75 case AUTOFS_SUPER_MAGIC
:
84 case REISERFS_SUPER_MAGIC
:
93 case HPFS_SUPER_MAGIC
:
96 case DEVFS_SUPER_MAGIC
:
99 case ISOFS_SUPER_MAGIC
:
102 case MSDOS_SUPER_MAGIC
:
105 case NTFS_SUPER_MAGIC
:
108 case LOGFS_MAGIC_U32
:
111 case BTRFS_SUPER_MAGIC
:
114 case CGROUP_SUPER_MAGIC
:
117 case LUSTRE_SUPER_MAGIC
:
122 FILE *mtab
= __setmntent ("/proc/mounts", "r");
124 mtab
= __setmntent (_PATH_MOUNTED
, "r");
129 bool success
= false;
130 struct mntent mntbuf
;
133 /* No locking needed. */
134 (void) __fsetlocking (mtab
, FSETLOCKING_BYCALLER
);
137 while (__getmntent_r (mtab
, &mntbuf
, tmpbuf
, sizeof (tmpbuf
)))
139 /* In a first round we look for a given mount point, if
141 if (name
!= NULL
&& strcmp (name
, mntbuf
.mnt_dir
) != 0)
143 /* We need to look at the entry only if the filesystem
144 name matches. If we have a filesystem name. */
145 else if (fsname
!= NULL
146 && strcmp (fsname
, mntbuf
.mnt_type
) != 0
148 || strcmp (fsname2
, mntbuf
.mnt_type
) != 0)
150 || strcmp (fsname3
, mntbuf
.mnt_type
) != 0))
153 /* Find out about the device the current entry is for. */
155 if (stat64 (mntbuf
.mnt_dir
, &fsst
) >= 0
156 && st
->st_dev
== fsst
.st_dev
)
158 /* Bingo, we found the entry for the device FD is on.
159 Now interpret the option string. */
160 char *cp
= mntbuf
.mnt_opts
;
163 while ((opt
= strsep (&cp
, ",")) != NULL
)
164 if (strcmp (opt
, "ro") == 0)
166 else if (strcmp (opt
, "nosuid") == 0)
168 else if (strcmp (opt
, "noexec") == 0)
170 else if (strcmp (opt
, "nodev") == 0)
172 else if (strcmp (opt
, "sync") == 0)
173 result
|= ST_SYNCHRONOUS
;
174 else if (strcmp (opt
, "mand") == 0)
175 result
|= ST_MANDLOCK
;
176 else if (strcmp (opt
, "noatime") == 0)
177 result
|= ST_NOATIME
;
178 else if (strcmp (opt
, "nodiratime") == 0)
179 result
|= ST_NODIRATIME
;
180 else if (strcmp (opt
, "relatime") == 0)
181 result
|= ST_RELATIME
;
183 /* We can stop looking for more entries. */
188 /* Maybe the kernel names for the filesystems changed or the
189 statvfs call got a name which was not the mount point. Check
190 again, this time without checking for name matches first. */
191 if (! success
&& (name
!= NULL
|| fsname
!= NULL
))
194 /* Try without a mount point name. */
198 /* Try without a filesystem name. */
199 assert (fsname
!= NULL
);
200 fsname
= fsname2
= fsname3
= NULL
;
203 /* It is not strictly allowed to use rewind here. But
204 this code is part of the implementation so it is
211 /* Close the file. */
219 extern int __statvfs_getflags (const char *name
, int fstype
,
225 INTERNAL_STATVFS (const char *name
, struct STATVFS
*buf
,
226 struct STATFS
*fsbuf
, struct stat64
*st
)
228 /* Now fill in the fields we have information for. */
229 buf
->f_bsize
= fsbuf
->f_bsize
;
230 /* Linux has the f_frsize size only in later version of the kernel.
231 If the value is not filled in use f_bsize. */
232 buf
->f_frsize
= fsbuf
->f_frsize
?: fsbuf
->f_bsize
;
233 buf
->f_blocks
= fsbuf
->f_blocks
;
234 buf
->f_bfree
= fsbuf
->f_bfree
;
235 buf
->f_bavail
= fsbuf
->f_bavail
;
236 buf
->f_files
= fsbuf
->f_files
;
237 buf
->f_ffree
= fsbuf
->f_ffree
;
238 if (sizeof (buf
->f_fsid
) == sizeof (fsbuf
->f_fsid
))
239 /* The shifting uses 'unsigned long long int' even though the target
240 field might only have 32 bits. This is OK since the 'if' branch
241 is not used in this case but the compiler would still generate
243 buf
->f_fsid
= ((fsbuf
->f_fsid
.__val
[0]
244 & ((1ULL << (8 * sizeof (fsbuf
->f_fsid
.__val
[0]))) - 1))
245 | ((unsigned long long int) fsbuf
->f_fsid
.__val
[1]
246 << (8 * (sizeof (buf
->f_fsid
)
247 - sizeof (fsbuf
->f_fsid
.__val
[0])))));
249 /* We cannot help here. The statvfs element is not large enough to
250 contain both words of the statfs f_fsid field. */
251 buf
->f_fsid
= fsbuf
->f_fsid
.__val
[0];
252 #ifdef _STATVFSBUF_F_UNUSED
255 buf
->f_namemax
= fsbuf
->f_namelen
;
256 memset (buf
->__f_spare
, '\0', sizeof (buf
->__f_spare
));
258 /* What remains to do is to fill the fields f_favail and f_flag. */
260 /* XXX I have no idea how to compute f_favail. Any idea??? */
261 buf
->f_favail
= buf
->f_ffree
;
263 #ifndef __ASSUME_STATFS_F_FLAGS
264 if ((fsbuf
->f_flags
& ST_VALID
) == 0)
265 /* Determining the flags is tricky. We have to read /proc/mounts or
266 the /etc/mtab file and search for the entry which matches the given
267 file. The way we can test for matching filesystem is using the
269 buf
->f_flag
= __statvfs_getflags (name
, fsbuf
->f_type
, st
);
272 buf
->f_flag
= fsbuf
->f_flags
^ ST_VALID
;