diff options
-rw-r--r-- | sysdeps/unix/sysv/linux/internal_statvfs.c | 259 |
1 files changed, 134 insertions, 125 deletions
diff --git a/sysdeps/unix/sysv/linux/internal_statvfs.c b/sysdeps/unix/sysv/linux/internal_statvfs.c index 1331bb0bee..ea26729d55 100644 --- a/sysdeps/unix/sysv/linux/internal_statvfs.c +++ b/sysdeps/unix/sysv/linux/internal_statvfs.c @@ -35,6 +35,138 @@ # define STATFS statfs # define STATVFS statvfs # define INTERNAL_STATVFS __internal_statvfs + + +int +__statvfs_getflags (const char *name, int fstype, struct stat64 *st) +{ + if (st == NULL) + return 0; + + const char *fsname = NULL; + const char *fsname2 = NULL; + + /* Map the filesystem type we got from the statfs call to a string. */ + switch (fstype) + { + case EXT2_SUPER_MAGIC: + fsname = "ext3"; + fsname2 = "ext2"; + break; + case DEVPTS_SUPER_MAGIC: + fsname= "devpts"; + break; + case SHMFS_SUPER_MAGIC: + fsname = "tmpfs"; + break; + case PROC_SUPER_MAGIC: + fsname = "proc"; + break; + case USBDEVFS_SUPER_MAGIC: + fsname = "usbdevfs"; + break; + case AUTOFS_SUPER_MAGIC: + fsname = "autofs"; + break; + case NFS_SUPER_MAGIC: + fsname = "nfs"; + break; + } + + FILE *mtab = __setmntent ("/proc/mounts", "r"); + if (mtab == NULL) + mtab = __setmntent (_PATH_MOUNTED, "r"); + + int result = 0; + if (mtab != NULL) + { + bool success = false; + struct mntent mntbuf; + char tmpbuf[1024]; + + /* No locking needed. */ + (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER); + + again: + while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf))) + { + /* In a first round we look for a given mount point, if + we have a name. */ + if (name != NULL && strcmp (name, mntbuf.mnt_dir) != 0) + continue; + /* We need to look at the entry only if the filesystem + name matches. If we have a filesystem name. */ + else if (fsname != NULL + && strcmp (fsname, mntbuf.mnt_type) != 0 + && (fsname2 == NULL + || strcmp (fsname2, mntbuf.mnt_type) != 0)) + continue; + + /* Find out about the device the current entry is for. */ + struct stat64 fsst; + if (stat64 (mntbuf.mnt_dir, &fsst) >= 0 + && st->st_dev == fsst.st_dev) + { + /* Bingo, we found the entry for the device FD is on. + Now interpret the option string. */ + char *cp = mntbuf.mnt_opts; + char *opt; + + while ((opt = strsep (&cp, ",")) != NULL) + if (strcmp (opt, "ro") == 0) + result |= ST_RDONLY; + else if (strcmp (opt, "nosuid") == 0) + result |= ST_NOSUID; + else if (strcmp (opt, "noexec") == 0) + result |= ST_NOEXEC; + else if (strcmp (opt, "nodev") == 0) + result |= ST_NODEV; + else if (strcmp (opt, "sync") == 0) + result |= ST_SYNCHRONOUS; + else if (strcmp (opt, "mand") == 0) + result |= ST_MANDLOCK; + else if (strcmp (opt, "noatime") == 0) + result |= ST_NOATIME; + else if (strcmp (opt, "nodiratime") == 0) + result |= ST_NODIRATIME; + + /* We can stop looking for more entries. */ + success = true; + break; + } + } + /* Maybe the kernel names for the filesystems changed or the + statvfs call got a name which was not the mount point. Check + again, this time without checking for name matches first. */ + if (! success && (name != NULL || fsname != NULL)) + { + if (name != NULL) + /* Try without a mount point name. */ + name = NULL; + else + { + /* Try without a filesystem name. */ + assert (fsname != NULL); + fsname = fsname2 = NULL; + } + + /* It is not strictly allowed to use rewind here. But + this code is part of the implementation so it is + acceptable. */ + rewind (mtab); + + goto again; + } + + /* Close the file. */ + __endmntent (mtab); + } + + return result; +} +#else +extern int __statvfs_getflags (const char *name, int fstype, + struct stat64 *st); #endif @@ -65,7 +197,7 @@ INTERNAL_STATVFS (const char *name, struct STATVFS *buf, buf->__f_unused = 0; #endif buf->f_namemax = fsbuf->f_namelen; - memset (buf->__f_spare, '\0', 6 * sizeof (int)); + memset (buf->__f_spare, '\0', sizeof (buf->__f_spare)); /* What remains to do is to fill the fields f_favail and f_flag. */ @@ -76,128 +208,5 @@ INTERNAL_STATVFS (const char *name, struct STATVFS *buf, the /etc/mtab file and search for the entry which matches the given file. The way we can test for matching filesystem is using the device number. */ - buf->f_flag = 0; - if (st != NULL) - { - struct mntent mntbuf; - FILE *mtab; - const char *fsname = NULL; - const char *fsname2 = NULL; - bool success = false; - - /* Map the filesystem type we got from the statfs call to a string. */ - switch (fsbuf->f_type) - { - case EXT2_SUPER_MAGIC: - fsname = "ext3"; - fsname2 = "ext2"; - break; - case DEVPTS_SUPER_MAGIC: - fsname= "devpts"; - break; - case SHMFS_SUPER_MAGIC: - fsname = "tmpfs"; - break; - case PROC_SUPER_MAGIC: - fsname = "proc"; - break; - case USBDEVFS_SUPER_MAGIC: - fsname = "usbdevfs"; - break; - case AUTOFS_SUPER_MAGIC: - fsname = "autofs"; - break; - case NFS_SUPER_MAGIC: - fsname = "nfs"; - break; - } - - mtab = __setmntent ("/proc/mounts", "r"); - if (mtab == NULL) - mtab = __setmntent (_PATH_MOUNTED, "r"); - - if (mtab != NULL) - { - char tmpbuf[1024]; - - /* No locking needed. */ - (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER); - - again: - while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf))) - { - /* In a first round we look for a given mount point, if - we have a name. */ - if (name != NULL && strcmp (name, mntbuf.mnt_dir) != 0) - continue; - /* We need to look at the entry only if the filesystem - name matches. If we have a filesystem name. */ - else if (fsname != NULL - && strcmp (fsname, mntbuf.mnt_type) != 0 - && (fsname2 == NULL - || strcmp (fsname2, mntbuf.mnt_type) != 0)) - continue; - - /* Find out about the device the current entry is for. */ - struct stat64 fsst; - if (stat64 (mntbuf.mnt_dir, &fsst) >= 0 - && st->st_dev == fsst.st_dev) - { - /* Bingo, we found the entry for the device FD is on. - Now interpret the option string. */ - char *cp = mntbuf.mnt_opts; - char *opt; - - while ((opt = strsep (&cp, ",")) != NULL) - if (strcmp (opt, "ro") == 0) - buf->f_flag |= ST_RDONLY; - else if (strcmp (opt, "nosuid") == 0) - buf->f_flag |= ST_NOSUID; - else if (strcmp (opt, "noexec") == 0) - buf->f_flag |= ST_NOEXEC; - else if (strcmp (opt, "nodev") == 0) - buf->f_flag |= ST_NODEV; - else if (strcmp (opt, "sync") == 0) - buf->f_flag |= ST_SYNCHRONOUS; - else if (strcmp (opt, "mand") == 0) - buf->f_flag |= ST_MANDLOCK; - else if (strcmp (opt, "noatime") == 0) - buf->f_flag |= ST_NOATIME; - else if (strcmp (opt, "nodiratime") == 0) - buf->f_flag |= ST_NODIRATIME; - - /* We can stop looking for more entries. */ - success = true; - break; - } - } - /* Maybe the kernel names for the filesystems changed or the - statvfs call got a name which was not the mount point. - Check again, this time without checking for name matches - first. */ - if (! success && (name != NULL || fsname != NULL)) - { - if (name != NULL) - /* Try without a mount point name. */ - name = NULL; - else - { - /* Try without a filesystem name. */ - assert (fsname != NULL); - fsname = fsname2 = NULL; - } - - /* It is not strictly allowed to use rewind here. But - this code is part of the implementation so it is - acceptable. */ - rewind (mtab); - - goto again; - } - - /* Close the file. */ - __endmntent (mtab); - - } - } + buf->f_flag = __statvfs_getflags (name, fsbuf->f_type, st); } |