/* Determine where the shmfs is mounted (if at all). */ static void where_is_shmfs (void) { char buf[512]; struct statfs f; struct mntent resmem; struct mntent *mp; FILE *fp; /* The canonical place is /dev/shm. This is at least what the documentation tells everybody to do. */ if (__statfs (defaultdir, &f) == 0 && f.f_type == SHMFS_SUPER_MAGIC) { /* It is in the normal place. */ mountpoint.dir = (char *) defaultdir; mountpoint.dirlen = sizeof (defaultdir) - 1; return; } /* OK, do it the hard way. Look through the /proc/mounts file and if this does not exist through /etc/fstab to find the mount point. */ fp = __setmntent ("/proc/mounts", "r"); if (__builtin_expect (fp == NULL, 0)) { fp = __setmntent (_PATH_MNTTAB, "r"); if (__builtin_expect (fp == NULL, 0)) /* There is nothing we can do. Blind guesses are not helpful. */ return; } /* Now read the entries. */ while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL) /* The original name is "shm" but this got changed in early Linux 2.4.x to "tmpfs". */ if (strcmp (mp->mnt_type, "tmpfs") == 0 || strcmp (mp->mnt_type, "shm") == 0) { /* Found it. There might be more than one place where the filesystem is mounted but one is enough for us. */ size_t namelen; /* First make sure this really is the correct entry. At least some versions of the kernel give wrong information because of the implicit mount of the shmfs for SysV IPC. */ if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC) continue; namelen = strlen (mp->mnt_dir); if (namelen == 0) /* Hum, maybe some crippled entry. Keep on searching. */ continue; mountpoint.dir = (char *) malloc (namelen + 2); if (mountpoint.dir != NULL) { char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen); if (cp[-1] != '/') *cp++ = '/'; *cp = '\0'; mountpoint.dirlen = cp - mountpoint.dir; } break; } /* Close the stream. */ __endmntent (fp); }
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; case SYSFS_MAGIC: fsname = "sysfs"; break; case REISERFS_SUPER_MAGIC: fsname = "reiserfs"; break; case XFS_SUPER_MAGIC: fsname = "xfs"; break; case JFS_SUPER_MAGIC: fsname = "jfs"; break; case HPFS_SUPER_MAGIC: fsname = "hpfs"; break; case DEVFS_SUPER_MAGIC: fsname = "devfs"; break; case ISOFS_SUPER_MAGIC: fsname = "iso9660"; break; case MSDOS_SUPER_MAGIC: fsname = "msdos"; break; case NTFS_SUPER_MAGIC: fsname = "ntfs"; 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; else if (strcmp (opt, "relatime") == 0) result |= ST_RELATIME; /* 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; }
static long int distinguish_extX (const struct statfs *fsbuf, const char *file, int fd) { char buf[64]; char path[PATH_MAX]; struct stat64 st; if ((file == NULL ? fstat64 (fd, &st) : stat64 (file, &st)) != 0) /* Strange. The statfd call worked, but stat fails. Default to the more pessimistic value. */ return EXT2_LINK_MAX; __snprintf (buf, sizeof (buf), "/sys/dev/block/%u:%u", gnu_dev_major (st.st_dev), gnu_dev_minor (st.st_dev)); ssize_t n = __readlink (buf, path, sizeof (path)); if (n != -1 && n < sizeof (path)) { path[n] = '\0'; char *base = strdupa (basename (path)); __snprintf (path, sizeof (path), "/sys/fs/ext4/%s", base); return __access (path, F_OK) == 0 ? EXT4_LINK_MAX : EXT2_LINK_MAX; } /* XXX Is there a better way to distinguish ext2/3 from ext4 than iterating over the mounted filesystems and compare the device numbers? */ FILE *mtab = __setmntent ("/proc/mounts", "r"); if (mtab == NULL) mtab = __setmntent (_PATH_MOUNTED, "r"); /* By default be conservative. */ long int result = EXT2_LINK_MAX; if (mtab != NULL) { struct mntent mntbuf; char tmpbuf[1024]; /* No locking needed. */ (void) __fsetlocking (mtab, FSETLOCKING_BYCALLER); while (__getmntent_r (mtab, &mntbuf, tmpbuf, sizeof (tmpbuf))) { if (strcmp (mntbuf.mnt_type, "ext2") != 0 && strcmp (mntbuf.mnt_type, "ext3") != 0 && strcmp (mntbuf.mnt_type, "ext4") != 0) continue; struct stat64 fsst; if (stat64 (mntbuf.mnt_dir, &fsst) >= 0 && st.st_dev == fsst.st_dev) { if (strcmp (mntbuf.mnt_type, "ext4") == 0) result = EXT4_LINK_MAX; break; } } /* Close the file. */ __endmntent (mtab); } return result; }