Add <sys/auxv.h> and getauxval.
[glibc.git] / sysdeps / unix / sysv / linux / internal_statvfs.c
blob30b12f2e0ce131d6eac256b6890a2b7d1ebbf6b6
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/>. */
19 #include <assert.h>
20 #include <errno.h>
21 #include <mntent.h>
22 #include <paths.h>
23 #include <stdbool.h>
24 #include <stdio_ext.h>
25 #include <string.h>
26 #include <sys/mount.h>
27 #include <sys/stat.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
38 #ifndef STATFS
39 # define STATFS statfs
40 # define STATVFS statvfs
41 # define INTERNAL_STATVFS __internal_statvfs
44 # ifndef __ASSUME_STATFS_F_FLAGS
45 int
46 __statvfs_getflags (const char *name, int fstype, struct stat64 *st)
48 if (st == NULL)
49 return 0;
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. */
56 switch (fstype)
58 case EXT2_SUPER_MAGIC:
59 fsname = "ext4";
60 fsname2 = "ext3";
61 fsname3 = "ext2";
62 break;
63 case DEVPTS_SUPER_MAGIC:
64 fsname= "devpts";
65 break;
66 case SHMFS_SUPER_MAGIC:
67 fsname = "tmpfs";
68 break;
69 case PROC_SUPER_MAGIC:
70 fsname = "proc";
71 break;
72 case USBDEVFS_SUPER_MAGIC:
73 fsname = "usbdevfs";
74 break;
75 case AUTOFS_SUPER_MAGIC:
76 fsname = "autofs";
77 break;
78 case NFS_SUPER_MAGIC:
79 fsname = "nfs";
80 break;
81 case SYSFS_MAGIC:
82 fsname = "sysfs";
83 break;
84 case REISERFS_SUPER_MAGIC:
85 fsname = "reiserfs";
86 break;
87 case XFS_SUPER_MAGIC:
88 fsname = "xfs";
89 break;
90 case JFS_SUPER_MAGIC:
91 fsname = "jfs";
92 break;
93 case HPFS_SUPER_MAGIC:
94 fsname = "hpfs";
95 break;
96 case DEVFS_SUPER_MAGIC:
97 fsname = "devfs";
98 break;
99 case ISOFS_SUPER_MAGIC:
100 fsname = "iso9660";
101 break;
102 case MSDOS_SUPER_MAGIC:
103 fsname = "msdos";
104 break;
105 case NTFS_SUPER_MAGIC:
106 fsname = "ntfs";
107 break;
108 case LOGFS_MAGIC_U32:
109 fsname = "logfs";
110 break;
111 case BTRFS_SUPER_MAGIC:
112 fsname = "btrfs";
113 break;
114 case CGROUP_SUPER_MAGIC:
115 fsname = "cgroup";
116 break;
117 case LUSTRE_SUPER_MAGIC:
118 fsname = "lustre";
119 break;
122 FILE *mtab = __setmntent ("/proc/mounts", "r");
123 if (mtab == NULL)
124 mtab = __setmntent (_PATH_MOUNTED, "r");
126 int result = 0;
127 if (mtab != NULL)
129 bool success = false;
130 struct mntent mntbuf;
131 char tmpbuf[1024];
133 /* No locking needed. */
134 (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER);
136 again:
137 while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf)))
139 /* In a first round we look for a given mount point, if
140 we have a name. */
141 if (name != NULL && strcmp (name, mntbuf.mnt_dir) != 0)
142 continue;
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
147 && (fsname2 == NULL
148 || strcmp (fsname2, mntbuf.mnt_type) != 0)
149 && (fsname3 == NULL
150 || strcmp (fsname3, mntbuf.mnt_type) != 0))
151 continue;
153 /* Find out about the device the current entry is for. */
154 struct stat64 fsst;
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;
161 char *opt;
163 while ((opt = strsep (&cp, ",")) != NULL)
164 if (strcmp (opt, "ro") == 0)
165 result |= ST_RDONLY;
166 else if (strcmp (opt, "nosuid") == 0)
167 result |= ST_NOSUID;
168 else if (strcmp (opt, "noexec") == 0)
169 result |= ST_NOEXEC;
170 else if (strcmp (opt, "nodev") == 0)
171 result |= ST_NODEV;
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. */
184 success = true;
185 break;
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))
193 if (name != NULL)
194 /* Try without a mount point name. */
195 name = NULL;
196 else
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
205 acceptable. */
206 rewind (mtab);
208 goto again;
211 /* Close the file. */
212 __endmntent (mtab);
215 return result;
217 # endif
218 #else
219 extern int __statvfs_getflags (const char *name, int fstype,
220 struct stat64 *st);
221 #endif
224 void
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
242 warnings. */
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])))));
248 else
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
253 buf->__f_unused = 0;
254 #endif
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
268 device number. */
269 buf->f_flag = __statvfs_getflags (name, fsbuf->f_type, st);
270 else
271 #endif
272 buf->f_flag = fsbuf->f_flags ^ ST_VALID;