/* Determine directory for shm/sem files. Linux version. Copyright (C) 2000-2017 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ #include "shm-directory.h" #include #include #include #include #include #include #include #include "linux_fsinfo.h" /* Mount point of the shared memory filesystem. */ static struct { char *dir; size_t dirlen; } mountpoint; /* This is the default directory. */ static const char defaultdir[] = "/dev/shm/"; /* Protect the `mountpoint' variable above. */ __libc_once_define (static, once); /* 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 || f.f_type == RAMFS_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 (__glibc_unlikely (fp == NULL)) { fp = __setmntent (_PATH_MNTTAB, "r"); if (__glibc_unlikely (fp == NULL)) /* 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 && f.f_type != RAMFS_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); } const char * __shm_directory (size_t *len) { /* Determine where the shmfs is mounted. */ __libc_once (once, where_is_shmfs); /* If we don't know the mount points there is nothing we can do. Ever. */ if (__glibc_unlikely (mountpoint.dir == NULL)) { __set_errno (ENOSYS); return NULL; } *len = mountpoint.dirlen; return mountpoint.dir; } #if IS_IN (libpthread) hidden_def (__shm_directory) #endif /* Make sure the table is freed if we want to free everything before exiting. */ libc_freeres_fn (freeit) { if (mountpoint.dir != defaultdir) free (mountpoint.dir); }