]>
Commit | Line | Data |
---|---|---|
d4697bc9 | 1 | /* Copyright (C) 2000-2014 Free Software Foundation, Inc. |
a63be9f7 UD |
2 | This file is part of the GNU C Library. |
3 | ||
4 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either | |
7 | version 2.1 of the License, or (at your option) any later version. | |
a63be9f7 UD |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 12 | Lesser General Public License for more details. |
a63be9f7 | 13 | |
41bdb6e2 | 14 | You should have received a copy of the GNU Lesser General Public |
59ba27a6 PE |
15 | License along with the GNU C Library; if not, see |
16 | <http://www.gnu.org/licenses/>. */ | |
a63be9f7 UD |
17 | |
18 | #include <errno.h> | |
19 | #include <fcntl.h> | |
20 | #include <mntent.h> | |
21 | #include <paths.h> | |
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | #include <unistd.h> | |
26 | #include <sys/mman.h> | |
27 | #include <sys/statfs.h> | |
28 | #include <bits/libc-lock.h> | |
afdda55a | 29 | #include "linux_fsinfo.h" |
a63be9f7 UD |
30 | |
31 | ||
a63be9f7 UD |
32 | /* Mount point of the shared memory filesystem. */ |
33 | static struct | |
34 | { | |
35 | char *dir; | |
36 | size_t dirlen; | |
37 | } mountpoint; | |
38 | ||
39 | /* This is the default directory. */ | |
301909fb | 40 | static const char defaultdir[] = "/dev/shm/"; |
a63be9f7 UD |
41 | |
42 | /* Protect the `mountpoint' variable above. */ | |
43 | __libc_once_define (static, once); | |
44 | ||
45 | ||
46 | /* Determine where the shmfs is mounted (if at all). */ | |
47 | static void | |
48 | where_is_shmfs (void) | |
49 | { | |
50 | char buf[512]; | |
51 | struct statfs f; | |
52 | struct mntent resmem; | |
53 | struct mntent *mp; | |
54 | FILE *fp; | |
55 | ||
b26a9120 | 56 | /* The canonical place is /dev/shm. This is at least what the |
a63be9f7 | 57 | documentation tells everybody to do. */ |
d674667c MF |
58 | if (__statfs (defaultdir, &f) == 0 && (f.f_type == SHMFS_SUPER_MAGIC |
59 | || f.f_type == RAMFS_MAGIC)) | |
a63be9f7 UD |
60 | { |
61 | /* It is in the normal place. */ | |
62 | mountpoint.dir = (char *) defaultdir; | |
480a06df | 63 | mountpoint.dirlen = sizeof (defaultdir) - 1; |
a63be9f7 UD |
64 | |
65 | return; | |
66 | } | |
67 | ||
68 | /* OK, do it the hard way. Look through the /proc/mounts file and if | |
69 | this does not exist through /etc/fstab to find the mount point. */ | |
70 | fp = __setmntent ("/proc/mounts", "r"); | |
a1ffb40e | 71 | if (__glibc_unlikely (fp == NULL)) |
a63be9f7 UD |
72 | { |
73 | fp = __setmntent (_PATH_MNTTAB, "r"); | |
a1ffb40e | 74 | if (__glibc_unlikely (fp == NULL)) |
a63be9f7 UD |
75 | /* There is nothing we can do. Blind guesses are not helpful. */ |
76 | return; | |
77 | } | |
78 | ||
79 | /* Now read the entries. */ | |
80 | while ((mp = __getmntent_r (fp, &resmem, buf, sizeof buf)) != NULL) | |
9db02f0b AJ |
81 | /* The original name is "shm" but this got changed in early Linux |
82 | 2.4.x to "tmpfs". */ | |
d674667c MF |
83 | if (strcmp (mp->mnt_type, "tmpfs") == 0 |
84 | || strcmp (mp->mnt_type, "shm") == 0) | |
a63be9f7 UD |
85 | { |
86 | /* Found it. There might be more than one place where the | |
87 | filesystem is mounted but one is enough for us. */ | |
301909fb UD |
88 | size_t namelen; |
89 | ||
90 | /* First make sure this really is the correct entry. At least | |
91 | some versions of the kernel give wrong information because | |
92 | of the implicit mount of the shmfs for SysV IPC. */ | |
d674667c MF |
93 | if (__statfs (mp->mnt_dir, &f) != 0 || (f.f_type != SHMFS_SUPER_MAGIC |
94 | && f.f_type != RAMFS_MAGIC)) | |
301909fb UD |
95 | continue; |
96 | ||
97 | namelen = strlen (mp->mnt_dir); | |
a63be9f7 UD |
98 | |
99 | if (namelen == 0) | |
100 | /* Hum, maybe some crippled entry. Keep on searching. */ | |
101 | continue; | |
102 | ||
103 | mountpoint.dir = (char *) malloc (namelen + 2); | |
104 | if (mountpoint.dir != NULL) | |
105 | { | |
106 | char *cp = __mempcpy (mountpoint.dir, mp->mnt_dir, namelen); | |
107 | if (cp[-1] != '/') | |
108 | *cp++ = '/'; | |
109 | *cp = '\0'; | |
110 | mountpoint.dirlen = cp - mountpoint.dir; | |
111 | } | |
112 | ||
113 | break; | |
114 | } | |
115 | ||
116 | /* Close the stream. */ | |
117 | __endmntent (fp); | |
118 | } | |
119 | ||
120 | ||
121 | /* Open shared memory object. This implementation assumes the shmfs | |
122 | implementation introduced in the late 2.3.x kernel series to be | |
b26a9120 | 123 | available. Normally the filesystem will be mounted at /dev/shm but |
a63be9f7 UD |
124 | we fall back on searching for the actual mount point should opening |
125 | such a file fail. */ | |
126 | int | |
127 | shm_open (const char *name, int oflag, mode_t mode) | |
128 | { | |
129 | size_t namelen; | |
130 | char *fname; | |
fb125e0c | 131 | int fd; |
a63be9f7 UD |
132 | |
133 | /* Determine where the shmfs is mounted. */ | |
134 | __libc_once (once, where_is_shmfs); | |
135 | ||
136 | /* If we don't know the mount points there is nothing we can do. Ever. */ | |
137 | if (mountpoint.dir == NULL) | |
138 | { | |
139 | __set_errno (ENOSYS); | |
140 | return -1; | |
141 | } | |
142 | ||
143 | /* Construct the filename. */ | |
144 | while (name[0] == '/') | |
145 | ++name; | |
146 | ||
5d30d853 OB |
147 | namelen = strlen (name); |
148 | ||
149 | /* Validate the filename. */ | |
b20de2c3 | 150 | if (name[0] == '\0' || namelen > NAME_MAX || strchr (name, '/') != NULL) |
a63be9f7 | 151 | { |
a63be9f7 UD |
152 | __set_errno (EINVAL); |
153 | return -1; | |
154 | } | |
155 | ||
a63be9f7 UD |
156 | fname = (char *) alloca (mountpoint.dirlen + namelen + 1); |
157 | __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen), | |
158 | name, namelen + 1); | |
159 | ||
160 | /* And get the file descriptor. | |
161 | XXX Maybe we should test each descriptor whether it really is for a | |
162 | file on the shmfs. If this is what should be done the whole function | |
163 | should be revamped since we can determine whether shmfs is available | |
164 | while trying to open the file, all in one turn. */ | |
74385da5 JM |
165 | fd = open (fname, oflag | O_CLOEXEC | O_NOFOLLOW, mode); |
166 | if (fd == -1 && __glibc_unlikely (errno == EISDIR)) | |
ee4e5a3d UD |
167 | /* It might be better to fold this error with EINVAL since |
168 | directory names are just another example for unsuitable shared | |
169 | object names and the standard does not mention EISDIR. */ | |
170 | __set_errno (EINVAL); | |
fb125e0c UD |
171 | |
172 | return fd; | |
a63be9f7 UD |
173 | } |
174 | ||
175 | ||
176 | /* Unlink a shared memory object. */ | |
177 | int | |
178 | shm_unlink (const char *name) | |
179 | { | |
180 | size_t namelen; | |
181 | char *fname; | |
182 | ||
183 | /* Determine where the shmfs is mounted. */ | |
184 | __libc_once (once, where_is_shmfs); | |
185 | ||
186 | if (mountpoint.dir == NULL) | |
187 | { | |
188 | /* We cannot find the shmfs. If `name' is really a shared | |
189 | memory object it must have been created by another process | |
190 | and we have no idea where that process found the mountpoint. */ | |
191 | __set_errno (ENOENT); | |
192 | return -1; | |
193 | } | |
194 | ||
195 | /* Construct the filename. */ | |
196 | while (name[0] == '/') | |
197 | ++name; | |
198 | ||
5d30d853 OB |
199 | namelen = strlen (name); |
200 | ||
201 | /* Validate the filename. */ | |
b20de2c3 | 202 | if (name[0] == '\0' || namelen > NAME_MAX || strchr (name, '/') != NULL) |
a63be9f7 | 203 | { |
a63be9f7 UD |
204 | __set_errno (ENOENT); |
205 | return -1; | |
206 | } | |
207 | ||
a63be9f7 UD |
208 | fname = (char *) alloca (mountpoint.dirlen + namelen + 1); |
209 | __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen), | |
210 | name, namelen + 1); | |
211 | ||
ba334988 | 212 | /* And remove the file. */ |
f9a06dc1 UD |
213 | int ret = unlink (fname); |
214 | if (ret < 0 && errno == EPERM) | |
215 | __set_errno (EACCES); | |
216 | return ret; | |
a63be9f7 UD |
217 | } |
218 | ||
219 | ||
c877418f RM |
220 | /* Make sure the table is freed if we want to free everything before |
221 | exiting. */ | |
222 | libc_freeres_fn (freeit) | |
a63be9f7 | 223 | { |
b26a9120 | 224 | if (mountpoint.dir != defaultdir) |
a63be9f7 UD |
225 | free (mountpoint.dir); |
226 | } |