| 1 | /* Determine directory for shm/sem files. Linux version. |
| 2 | Copyright (C) 2000-2021 Free Software Foundation, Inc. |
| 3 | This file is part of the GNU C Library. |
| 4 | |
| 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. |
| 9 | |
| 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. |
| 14 | |
| 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 | <https://www.gnu.org/licenses/>. */ |
| 18 | |
| 19 | #include "shm-directory.h" |
| 20 | |
| 21 | #include <errno.h> |
| 22 | #include <mntent.h> |
| 23 | #include <paths.h> |
| 24 | #include <stdio.h> |
| 25 | #include <string.h> |
| 26 | #include <sys/statfs.h> |
| 27 | #include <libc-lock.h> |
| 28 | #include "linux_fsinfo.h" |
| 29 | |
| 30 | |
| 31 | /* Mount point of the shared memory filesystem. */ |
| 32 | static struct |
| 33 | { |
| 34 | char *dir; |
| 35 | size_t dirlen; |
| 36 | } mountpoint; |
| 37 | |
| 38 | /* This is the default directory. */ |
| 39 | static const char defaultdir[] = "/dev/shm/" ; |
| 40 | |
| 41 | /* Protect the `mountpoint' variable above. */ |
| 42 | __libc_once_define (static, once); |
| 43 | |
| 44 | |
| 45 | /* Determine where the shmfs is mounted (if at all). */ |
| 46 | static void |
| 47 | where_is_shmfs (void) |
| 48 | { |
| 49 | char buf[512]; |
| 50 | struct statfs f; |
| 51 | struct mntent resmem; |
| 52 | struct mntent *mp; |
| 53 | FILE *fp; |
| 54 | |
| 55 | /* The canonical place is /dev/shm. This is at least what the |
| 56 | documentation tells everybody to do. */ |
| 57 | if (__statfs (defaultdir, &f) == 0 && (f.f_type == SHMFS_SUPER_MAGIC |
| 58 | || f.f_type == RAMFS_MAGIC)) |
| 59 | { |
| 60 | /* It is in the normal place. */ |
| 61 | mountpoint.dir = (char *) defaultdir; |
| 62 | mountpoint.dirlen = sizeof (defaultdir) - 1; |
| 63 | |
| 64 | return; |
| 65 | } |
| 66 | |
| 67 | /* OK, do it the hard way. Look through the /proc/mounts file and if |
| 68 | this does not exist through /etc/fstab to find the mount point. */ |
| 69 | fp = __setmntent ("/proc/mounts" , "r" ); |
| 70 | if (__glibc_unlikely (fp == NULL)) |
| 71 | { |
| 72 | fp = __setmntent (_PATH_MNTTAB, "r" ); |
| 73 | if (__glibc_unlikely (fp == NULL)) |
| 74 | /* There is nothing we can do. Blind guesses are not helpful. */ |
| 75 | return; |
| 76 | } |
| 77 | |
| 78 | /* Now read the entries. */ |
| 79 | while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL) |
| 80 | /* The original name is "shm" but this got changed in early Linux |
| 81 | 2.4.x to "tmpfs". */ |
| 82 | if (strcmp (mp->mnt_type, "tmpfs" ) == 0 |
| 83 | || strcmp (mp->mnt_type, "shm" ) == 0) |
| 84 | { |
| 85 | /* Found it. There might be more than one place where the |
| 86 | filesystem is mounted but one is enough for us. */ |
| 87 | size_t namelen; |
| 88 | |
| 89 | /* First make sure this really is the correct entry. At least |
| 90 | some versions of the kernel give wrong information because |
| 91 | of the implicit mount of the shmfs for SysV IPC. */ |
| 92 | if (__statfs (mp->mnt_dir, &f) != 0 || (f.f_type != SHMFS_SUPER_MAGIC |
| 93 | && f.f_type != RAMFS_MAGIC)) |
| 94 | continue; |
| 95 | |
| 96 | namelen = strlen (mp->mnt_dir); |
| 97 | |
| 98 | if (namelen == 0) |
| 99 | /* Hum, maybe some crippled entry. Keep on searching. */ |
| 100 | continue; |
| 101 | |
| 102 | mountpoint.dir = (char *) malloc (namelen + 2); |
| 103 | if (mountpoint.dir != NULL) |
| 104 | { |
| 105 | char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen); |
| 106 | if (cp[-1] != '/') |
| 107 | *cp++ = '/'; |
| 108 | *cp = '\0'; |
| 109 | mountpoint.dirlen = cp - mountpoint.dir; |
| 110 | } |
| 111 | |
| 112 | break; |
| 113 | } |
| 114 | |
| 115 | /* Close the stream. */ |
| 116 | __endmntent (fp); |
| 117 | } |
| 118 | |
| 119 | |
| 120 | const char * |
| 121 | __shm_directory (size_t *len) |
| 122 | { |
| 123 | /* Determine where the shmfs is mounted. */ |
| 124 | __libc_once (once, where_is_shmfs); |
| 125 | |
| 126 | /* If we don't know the mount points there is nothing we can do. Ever. */ |
| 127 | if (__glibc_unlikely (mountpoint.dir == NULL)) |
| 128 | { |
| 129 | __set_errno (ENOSYS); |
| 130 | return NULL; |
| 131 | } |
| 132 | |
| 133 | *len = mountpoint.dirlen; |
| 134 | return mountpoint.dir; |
| 135 | } |
| 136 | #if IS_IN (libpthread) |
| 137 | hidden_def (__shm_directory) |
| 138 | |
| 139 | /* Make sure the table is freed if we want to free everything before |
| 140 | exiting. */ |
| 141 | void |
| 142 | __shm_directory_freeres (void) |
| 143 | { |
| 144 | if (mountpoint.dir != defaultdir) |
| 145 | free (mountpoint.dir); |
| 146 | } |
| 147 | #endif |
| 148 | |