diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/shm-directory.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/shm-directory.c | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/shm-directory.c b/sysdeps/unix/sysv/linux/shm-directory.c new file mode 100644 index 0000000000..9340f9c331 --- /dev/null +++ b/sysdeps/unix/sysv/linux/shm-directory.c @@ -0,0 +1,144 @@ +/* Determine directory for shm/sem files. Linux version. + Copyright (C) 2000-2014 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 + <http://www.gnu.org/licenses/>. */ + +#include "shm-directory.h" + +#include <errno.h> +#include <mntent.h> +#include <paths.h> +#include <stdio.h> +#include <string.h> +#include <sys/statfs.h> +#include <bits/libc-lock.h> +#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; +} + + +/* 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); +} |