]>
Commit | Line | Data |
---|---|---|
a334319f | 1 | /* Copyright (C) 2000, 2001, 2002, 2003, 2004 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 AJ |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, write to the Free | |
16 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
17 | 02111-1307 USA. */ | |
a63be9f7 UD |
18 | |
19 | #include <errno.h> | |
20 | #include <fcntl.h> | |
21 | #include <mntent.h> | |
22 | #include <paths.h> | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | #include <sys/mman.h> | |
28 | #include <sys/statfs.h> | |
29 | #include <bits/libc-lock.h> | |
afdda55a | 30 | #include "linux_fsinfo.h" |
a63be9f7 UD |
31 | |
32 | ||
a63be9f7 UD |
33 | /* Mount point of the shared memory filesystem. */ |
34 | static struct | |
35 | { | |
36 | char *dir; | |
37 | size_t dirlen; | |
38 | } mountpoint; | |
39 | ||
40 | /* This is the default directory. */ | |
301909fb | 41 | static const char defaultdir[] = "/dev/shm/"; |
a63be9f7 UD |
42 | |
43 | /* Protect the `mountpoint' variable above. */ | |
44 | __libc_once_define (static, once); | |
45 | ||
46 | ||
47 | /* Determine where the shmfs is mounted (if at all). */ | |
48 | static void | |
49 | where_is_shmfs (void) | |
50 | { | |
51 | char buf[512]; | |
52 | struct statfs f; | |
53 | struct mntent resmem; | |
54 | struct mntent *mp; | |
55 | FILE *fp; | |
56 | ||
b26a9120 | 57 | /* The canonical place is /dev/shm. This is at least what the |
a63be9f7 | 58 | documentation tells everybody to do. */ |
480a06df | 59 | if (__statfs (defaultdir, &f) == 0 && f.f_type == SHMFS_SUPER_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"); | |
71 | if (__builtin_expect (fp == NULL, 0)) | |
72 | { | |
73 | fp = __setmntent (_PATH_MNTTAB, "r"); | |
74 | if (__builtin_expect (fp == NULL, 0)) | |
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". */ | |
957b83ab | 83 | if (strcmp (mp->mnt_type, "tmpfs") == 0 |
a334319f | 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. */ | |
93 | if (__statfs (mp->mnt_dir, &f) != 0 || f.f_type != SHMFS_SUPER_MAGIC) | |
94 | continue; | |
95 | ||
96 | namelen = strlen (mp->mnt_dir); | |
a63be9f7 UD |
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 | /* Open shared memory object. This implementation assumes the shmfs | |
121 | implementation introduced in the late 2.3.x kernel series to be | |
b26a9120 | 122 | available. Normally the filesystem will be mounted at /dev/shm but |
a63be9f7 UD |
123 | we fall back on searching for the actual mount point should opening |
124 | such a file fail. */ | |
125 | int | |
126 | shm_open (const char *name, int oflag, mode_t mode) | |
127 | { | |
128 | size_t namelen; | |
129 | char *fname; | |
fb125e0c | 130 | int fd; |
a63be9f7 UD |
131 | |
132 | /* Determine where the shmfs is mounted. */ | |
133 | __libc_once (once, where_is_shmfs); | |
134 | ||
135 | /* If we don't know the mount points there is nothing we can do. Ever. */ | |
136 | if (mountpoint.dir == NULL) | |
137 | { | |
138 | __set_errno (ENOSYS); | |
139 | return -1; | |
140 | } | |
141 | ||
142 | /* Construct the filename. */ | |
143 | while (name[0] == '/') | |
144 | ++name; | |
145 | ||
146 | if (name[0] == '\0') | |
147 | { | |
148 | /* The name "/" is not supported. */ | |
149 | __set_errno (EINVAL); | |
150 | return -1; | |
151 | } | |
152 | ||
153 | namelen = strlen (name); | |
154 | fname = (char *) alloca (mountpoint.dirlen + namelen + 1); | |
155 | __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen), | |
156 | name, namelen + 1); | |
157 | ||
158 | /* And get the file descriptor. | |
159 | XXX Maybe we should test each descriptor whether it really is for a | |
160 | file on the shmfs. If this is what should be done the whole function | |
161 | should be revamped since we can determine whether shmfs is available | |
162 | while trying to open the file, all in one turn. */ | |
28d2fb9a | 163 | fd = open (fname, oflag | O_NOFOLLOW, mode); |
fb125e0c UD |
164 | if (fd != -1) |
165 | { | |
166 | /* We got a descriptor. Now set the FD_CLOEXEC bit. */ | |
167 | int flags = fcntl (fd, F_GETFD, 0); | |
168 | ||
169 | if (__builtin_expect (flags, 0) >= 0) | |
170 | { | |
171 | flags |= FD_CLOEXEC; | |
172 | flags = fcntl (fd, F_SETFD, flags); | |
173 | } | |
174 | ||
175 | if (flags == -1) | |
176 | { | |
177 | /* Something went wrong. We cannot return the descriptor. */ | |
178 | int save_errno = errno; | |
179 | close (fd); | |
180 | fd = -1; | |
181 | __set_errno (save_errno); | |
182 | } | |
183 | } | |
ee4e5a3d UD |
184 | else if (__builtin_expect (errno == EISDIR, 0)) |
185 | /* It might be better to fold this error with EINVAL since | |
186 | directory names are just another example for unsuitable shared | |
187 | object names and the standard does not mention EISDIR. */ | |
188 | __set_errno (EINVAL); | |
fb125e0c UD |
189 | |
190 | return fd; | |
a63be9f7 UD |
191 | } |
192 | ||
193 | ||
194 | /* Unlink a shared memory object. */ | |
195 | int | |
196 | shm_unlink (const char *name) | |
197 | { | |
198 | size_t namelen; | |
199 | char *fname; | |
200 | ||
201 | /* Determine where the shmfs is mounted. */ | |
202 | __libc_once (once, where_is_shmfs); | |
203 | ||
204 | if (mountpoint.dir == NULL) | |
205 | { | |
206 | /* We cannot find the shmfs. If `name' is really a shared | |
207 | memory object it must have been created by another process | |
208 | and we have no idea where that process found the mountpoint. */ | |
209 | __set_errno (ENOENT); | |
210 | return -1; | |
211 | } | |
212 | ||
213 | /* Construct the filename. */ | |
214 | while (name[0] == '/') | |
215 | ++name; | |
216 | ||
217 | if (name[0] == '\0') | |
218 | { | |
219 | /* The name "/" is not supported. */ | |
220 | __set_errno (ENOENT); | |
221 | return -1; | |
222 | } | |
223 | ||
224 | namelen = strlen (name); | |
225 | fname = (char *) alloca (mountpoint.dirlen + namelen + 1); | |
226 | __mempcpy (__mempcpy (fname, mountpoint.dir, mountpoint.dirlen), | |
227 | name, namelen + 1); | |
228 | ||
ba334988 | 229 | /* And remove the file. */ |
f9a06dc1 UD |
230 | int ret = unlink (fname); |
231 | if (ret < 0 && errno == EPERM) | |
232 | __set_errno (EACCES); | |
233 | return ret; | |
a63be9f7 UD |
234 | } |
235 | ||
236 | ||
c877418f RM |
237 | /* Make sure the table is freed if we want to free everything before |
238 | exiting. */ | |
239 | libc_freeres_fn (freeit) | |
a63be9f7 | 240 | { |
b26a9120 | 241 | if (mountpoint.dir != defaultdir) |
a63be9f7 UD |
242 | free (mountpoint.dir); |
243 | } |