1 /* Copyright (C) 1998-2014 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
:
120 case F2FS_SUPER_MAGIC
:
128 FILE *mtab
= __setmntent ("/proc/mounts", "r");
130 mtab
= __setmntent (_PATH_MOUNTED
, "r");
135 bool success
= false;
136 struct mntent mntbuf
;
139 /* No locking needed. */
140 (void) __fsetlocking (mtab
, FSETLOCKING_BYCALLER
);
143 while (__getmntent_r (mtab
, &mntbuf
, tmpbuf
, sizeof (tmpbuf
)))
145 /* In a first round we look for a given mount point, if
147 if (name
!= NULL
&& strcmp (name
, mntbuf
.mnt_dir
) != 0)
149 /* We need to look at the entry only if the filesystem
150 name matches. If we have a filesystem name. */
151 else if (fsname
!= NULL
152 && strcmp (fsname
, mntbuf
.mnt_type
) != 0
154 || strcmp (fsname2
, mntbuf
.mnt_type
) != 0)
156 || strcmp (fsname3
, mntbuf
.mnt_type
) != 0))
159 /* Find out about the device the current entry is for. */
161 if (stat64 (mntbuf
.mnt_dir
, &fsst
) >= 0
162 && st
->st_dev
== fsst
.st_dev
)
164 /* Bingo, we found the entry for the device FD is on.
165 Now interpret the option string. */
166 char *cp
= mntbuf
.mnt_opts
;
169 while ((opt
= strsep (&cp
, ",")) != NULL
)
170 if (strcmp (opt
, "ro") == 0)
172 else if (strcmp (opt
, "nosuid") == 0)
174 else if (strcmp (opt
, "noexec") == 0)
176 else if (strcmp (opt
, "nodev") == 0)
178 else if (strcmp (opt
, "sync") == 0)
179 result
|= ST_SYNCHRONOUS
;
180 else if (strcmp (opt
, "mand") == 0)
181 result
|= ST_MANDLOCK
;
182 else if (strcmp (opt
, "noatime") == 0)
183 result
|= ST_NOATIME
;
184 else if (strcmp (opt
, "nodiratime") == 0)
185 result
|= ST_NODIRATIME
;
186 else if (strcmp (opt
, "relatime") == 0)
187 result
|= ST_RELATIME
;
189 /* We can stop looking for more entries. */
194 /* Maybe the kernel names for the filesystems changed or the
195 statvfs call got a name which was not the mount point. Check
196 again, this time without checking for name matches first. */
197 if (! success
&& (name
!= NULL
|| fsname
!= NULL
))
200 /* Try without a mount point name. */
204 /* Try without a filesystem name. */
205 assert (fsname
!= NULL
);
206 fsname
= fsname2
= fsname3
= NULL
;
209 /* It is not strictly allowed to use rewind here. But
210 this code is part of the implementation so it is
217 /* Close the file. */
225 extern int __statvfs_getflags (const char *name
, int fstype
,
231 INTERNAL_STATVFS (const char *name
, struct STATVFS
*buf
,
232 struct STATFS
*fsbuf
, struct stat64
*st
)
234 /* Now fill in the fields we have information for. */
235 buf
->f_bsize
= fsbuf
->f_bsize
;
236 /* Linux has the f_frsize size only in later version of the kernel.
237 If the value is not filled in use f_bsize. */
238 buf
->f_frsize
= fsbuf
->f_frsize
?: fsbuf
->f_bsize
;
239 buf
->f_blocks
= fsbuf
->f_blocks
;
240 buf
->f_bfree
= fsbuf
->f_bfree
;
241 buf
->f_bavail
= fsbuf
->f_bavail
;
242 buf
->f_files
= fsbuf
->f_files
;
243 buf
->f_ffree
= fsbuf
->f_ffree
;
244 if (sizeof (buf
->f_fsid
) == sizeof (fsbuf
->f_fsid
))
245 /* The shifting uses 'unsigned long long int' even though the target
246 field might only have 32 bits. This is OK since the 'if' branch
247 is not used in this case but the compiler would still generate
249 buf
->f_fsid
= ((fsbuf
->f_fsid
.__val
[0]
250 & ((1ULL << (8 * sizeof (fsbuf
->f_fsid
.__val
[0]))) - 1))
251 | ((unsigned long long int) fsbuf
->f_fsid
.__val
[1]
252 << (8 * (sizeof (buf
->f_fsid
)
253 - sizeof (fsbuf
->f_fsid
.__val
[0])))));
255 /* We cannot help here. The statvfs element is not large enough to
256 contain both words of the statfs f_fsid field. */
257 buf
->f_fsid
= fsbuf
->f_fsid
.__val
[0];
258 #ifdef _STATVFSBUF_F_UNUSED
261 buf
->f_namemax
= fsbuf
->f_namelen
;
262 memset (buf
->__f_spare
, '\0', sizeof (buf
->__f_spare
));
264 /* What remains to do is to fill the fields f_favail and f_flag. */
266 /* XXX I have no idea how to compute f_favail. Any idea??? */
267 buf
->f_favail
= buf
->f_ffree
;
269 #ifndef __ASSUME_STATFS_F_FLAGS
270 if ((fsbuf
->f_flags
& ST_VALID
) == 0)
271 /* Determining the flags is tricky. We have to read /proc/mounts or
272 the /etc/mtab file and search for the entry which matches the given
273 file. The way we can test for matching filesystem is using the
275 buf
->f_flag
= __statvfs_getflags (name
, fsbuf
->f_type
, st
);
278 buf
->f_flag
= fsbuf
->f_flags
^ ST_VALID
;