/src/httpd/srclib/apr/shmem/unix/shm.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include "apr_arch_shm.h" |
18 | | #include "apr_arch_file_io.h" |
19 | | |
20 | | #include "apr_general.h" |
21 | | #include "apr_errno.h" |
22 | | #include "apr_user.h" |
23 | | #include "apr_strings.h" |
24 | | #include "apr_hash.h" |
25 | | |
26 | | #if APR_USE_SHMEM_MMAP_SHM |
27 | | /* |
28 | | * For portable use, a shared memory object should be identified by a name of |
29 | | * the form /somename; that is, a null-terminated string of up to NAME_MAX |
30 | | * (i.e., 255) characters consisting of an initial slash, followed by one or |
31 | | * more characters, none of which are slashes. |
32 | | */ |
33 | | #ifndef NAME_MAX |
34 | | #define NAME_MAX 255 |
35 | | #endif |
36 | | |
37 | | /* See proc_mutex.c and sem_open for the reason for all this! */ |
38 | 0 | static unsigned int rshash (const char *p) { |
39 | | /* hash function from Robert Sedgwicks 'Algorithms in C' book */ |
40 | 0 | unsigned int b = 378551; |
41 | 0 | unsigned int a = 63689; |
42 | 0 | unsigned int retval = 0; |
43 | |
|
44 | 0 | for( ; *p; p++) { |
45 | 0 | retval = retval * a + (*p); |
46 | 0 | a *= b; |
47 | 0 | } |
48 | |
|
49 | 0 | return retval; |
50 | 0 | } |
51 | | |
52 | | static const char *make_shm_open_safe_name(const char *filename, |
53 | | apr_pool_t *pool) |
54 | 0 | { |
55 | 0 | apr_ssize_t flen; |
56 | 0 | unsigned int h1, h2; |
57 | |
|
58 | 0 | if (filename == NULL) { |
59 | 0 | return NULL; |
60 | 0 | } |
61 | | |
62 | 0 | flen = strlen(filename); |
63 | 0 | h1 = (apr_hashfunc_default(filename, &flen) & 0xffffffff); |
64 | 0 | h2 = (rshash(filename) & 0xffffffff); |
65 | 0 | return apr_psprintf(pool, "/ShM.%xH%x", h1, h2); |
66 | |
|
67 | 0 | } |
68 | | #endif |
69 | | |
70 | | #if APR_USE_SHMEM_SHMGET |
71 | | static key_t our_ftok(const char *filename) |
72 | | { |
73 | | /* to help avoid collisions while still using |
74 | | * an easily recreated proj_id */ |
75 | | apr_ssize_t slen = strlen(filename); |
76 | | return ftok(filename, |
77 | | (int)apr_hashfunc_default(filename, &slen)); |
78 | | } |
79 | | #endif |
80 | | |
81 | | static apr_status_t shm_cleanup_owner(void *m_) |
82 | 0 | { |
83 | 0 | apr_shm_t *m = (apr_shm_t *)m_; |
84 | | |
85 | | /* anonymous shared memory */ |
86 | 0 | if (m->filename == NULL) { |
87 | 0 | #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON |
88 | 0 | if (munmap(m->base, m->realsize) == -1) { |
89 | 0 | return errno; |
90 | 0 | } |
91 | 0 | return APR_SUCCESS; |
92 | | #elif APR_USE_SHMEM_SHMGET_ANON |
93 | | if (shmdt(m->base) == -1) { |
94 | | return errno; |
95 | | } |
96 | | /* This segment will automatically remove itself after all |
97 | | * references have detached. */ |
98 | | return APR_SUCCESS; |
99 | | #endif |
100 | 0 | } |
101 | | |
102 | | /* name-based shared memory */ |
103 | 0 | else { |
104 | | #if APR_USE_SHMEM_MMAP_TMP |
105 | | if (munmap(m->base, m->realsize) == -1) { |
106 | | return errno; |
107 | | } |
108 | | if (access(m->filename, F_OK)) { |
109 | | return APR_SUCCESS; |
110 | | } |
111 | | else { |
112 | | return apr_file_remove(m->filename, m->pool); |
113 | | } |
114 | | #elif APR_USE_SHMEM_MMAP_SHM |
115 | 0 | if (munmap(m->base, m->realsize) == -1) { |
116 | 0 | return errno; |
117 | 0 | } |
118 | 0 | if (shm_unlink(make_shm_open_safe_name(m->filename, m->pool)) == -1 && errno != ENOENT) { |
119 | 0 | return errno; |
120 | 0 | } |
121 | 0 | return APR_SUCCESS; |
122 | | #elif APR_USE_SHMEM_SHMGET |
123 | | /* Indicate that the segment is to be destroyed as soon |
124 | | * as all processes have detached. This also disallows any |
125 | | * new attachments to the segment. */ |
126 | | if (shmctl(m->shmid, IPC_RMID, NULL) == -1 && errno != EINVAL) { |
127 | | return errno; |
128 | | } |
129 | | if (shmdt(m->base) == -1) { |
130 | | return errno; |
131 | | } |
132 | | if (access(m->filename, F_OK)) { |
133 | | return APR_SUCCESS; |
134 | | } |
135 | | else { |
136 | | return apr_file_remove(m->filename, m->pool); |
137 | | } |
138 | | #else |
139 | | return APR_ENOTIMPL; |
140 | | #endif |
141 | 0 | } |
142 | 0 | } |
143 | | |
144 | | APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, |
145 | | apr_size_t reqsize, |
146 | | const char *filename, |
147 | | apr_pool_t *pool) |
148 | 0 | { |
149 | 0 | apr_shm_t *new_m; |
150 | 0 | apr_status_t status; |
151 | | #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON |
152 | | struct shmid_ds shmbuf; |
153 | | apr_uid_t uid; |
154 | | apr_gid_t gid; |
155 | | #endif |
156 | 0 | #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \ |
157 | 0 | APR_USE_SHMEM_MMAP_ZERO |
158 | 0 | int tmpfd; |
159 | 0 | #endif |
160 | | #if APR_USE_SHMEM_SHMGET |
161 | | apr_size_t nbytes; |
162 | | #endif |
163 | | #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_SHMGET || \ |
164 | | APR_USE_SHMEM_MMAP_TMP |
165 | | apr_file_t *file; /* file where metadata is stored */ |
166 | | #endif |
167 | | |
168 | | /* Check if they want anonymous or name-based shared memory */ |
169 | 0 | if (filename == NULL) { |
170 | 0 | #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON |
171 | 0 | new_m = apr_palloc(pool, sizeof(apr_shm_t)); |
172 | 0 | new_m->pool = pool; |
173 | 0 | new_m->reqsize = reqsize; |
174 | 0 | new_m->realsize = reqsize + |
175 | 0 | APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ |
176 | 0 | new_m->filename = NULL; |
177 | |
|
178 | | #if APR_USE_SHMEM_MMAP_ZERO |
179 | | status = apr_file_open(&file, "/dev/zero", APR_FOPEN_READ | APR_FOPEN_WRITE, |
180 | | APR_FPROT_OS_DEFAULT, pool); |
181 | | if (status != APR_SUCCESS) { |
182 | | return status; |
183 | | } |
184 | | status = apr_os_file_get(&tmpfd, file); |
185 | | if (status != APR_SUCCESS) { |
186 | | return status; |
187 | | } |
188 | | |
189 | | new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, |
190 | | MAP_SHARED, tmpfd, 0); |
191 | | if (new_m->base == (void *)MAP_FAILED) { |
192 | | return errno; |
193 | | } |
194 | | |
195 | | status = apr_file_close(file); |
196 | | if (status != APR_SUCCESS) { |
197 | | return status; |
198 | | } |
199 | | |
200 | | /* store the real size in the metadata */ |
201 | | *(apr_size_t*)(new_m->base) = new_m->realsize; |
202 | | /* metadata isn't usable */ |
203 | | new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); |
204 | | |
205 | | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, |
206 | | apr_pool_cleanup_null); |
207 | | *m = new_m; |
208 | | return APR_SUCCESS; |
209 | | |
210 | | #elif APR_USE_SHMEM_MMAP_ANON |
211 | 0 | new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, |
212 | 0 | MAP_ANON|MAP_SHARED, -1, 0); |
213 | 0 | if (new_m->base == (void *)MAP_FAILED) { |
214 | 0 | return errno; |
215 | 0 | } |
216 | | |
217 | | /* store the real size in the metadata */ |
218 | 0 | *(apr_size_t*)(new_m->base) = new_m->realsize; |
219 | | /* metadata isn't usable */ |
220 | 0 | new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); |
221 | |
|
222 | 0 | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, |
223 | 0 | apr_pool_cleanup_null); |
224 | 0 | *m = new_m; |
225 | 0 | return APR_SUCCESS; |
226 | |
|
227 | 0 | #endif /* APR_USE_SHMEM_MMAP_ZERO */ |
228 | | #elif APR_USE_SHMEM_SHMGET_ANON |
229 | | new_m = apr_palloc(pool, sizeof(apr_shm_t)); |
230 | | new_m->pool = pool; |
231 | | new_m->reqsize = reqsize; |
232 | | new_m->realsize = reqsize; |
233 | | new_m->filename = NULL; |
234 | | new_m->shmkey = IPC_PRIVATE; |
235 | | if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, |
236 | | SHM_R | SHM_W | IPC_CREAT)) < 0) { |
237 | | return errno; |
238 | | } |
239 | | |
240 | | if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { |
241 | | return errno; |
242 | | } |
243 | | new_m->usable = new_m->base; |
244 | | |
245 | | if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { |
246 | | return errno; |
247 | | } |
248 | | apr_uid_current(&uid, &gid, pool); |
249 | | shmbuf.shm_perm.uid = uid; |
250 | | shmbuf.shm_perm.gid = gid; |
251 | | if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { |
252 | | return errno; |
253 | | } |
254 | | |
255 | | /* Remove the segment once use count hits zero. |
256 | | * We will not attach to this segment again, since it is |
257 | | * anonymous memory, so it is ok to mark it for deletion. |
258 | | */ |
259 | | if (shmctl(new_m->shmid, IPC_RMID, NULL) == -1) { |
260 | | return errno; |
261 | | } |
262 | | |
263 | | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, |
264 | | apr_pool_cleanup_null); |
265 | | *m = new_m; |
266 | | return APR_SUCCESS; |
267 | | #else |
268 | | /* It is an error if they want anonymous memory but we don't have it. */ |
269 | | return APR_ENOTIMPL; /* requested anonymous but we don't have it */ |
270 | | #endif |
271 | 0 | } |
272 | | |
273 | | /* Name-based shared memory */ |
274 | 0 | else { |
275 | 0 | new_m = apr_palloc(pool, sizeof(apr_shm_t)); |
276 | 0 | new_m->pool = pool; |
277 | 0 | new_m->reqsize = reqsize; |
278 | 0 | new_m->filename = apr_pstrdup(pool, filename); |
279 | 0 | #if APR_USE_SHMEM_MMAP_SHM |
280 | 0 | const char *shm_name = make_shm_open_safe_name(filename, pool); |
281 | 0 | #endif |
282 | 0 | #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM |
283 | 0 | new_m->realsize = reqsize + |
284 | 0 | APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ |
285 | | /* FIXME: Ignore error for now. * |
286 | | * status = apr_file_remove(file, pool);*/ |
287 | 0 | status = APR_SUCCESS; |
288 | |
|
289 | | #if APR_USE_SHMEM_MMAP_TMP |
290 | | /* FIXME: Is APR_FPROT_OS_DEFAULT sufficient? */ |
291 | | status = apr_file_open(&file, filename, |
292 | | APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, |
293 | | APR_FPROT_OS_DEFAULT, pool); |
294 | | if (status != APR_SUCCESS) { |
295 | | return status; |
296 | | } |
297 | | |
298 | | status = apr_os_file_get(&tmpfd, file); |
299 | | if (status != APR_SUCCESS) { |
300 | | apr_file_close(file); /* ignore errors, we're failing */ |
301 | | apr_file_remove(new_m->filename, new_m->pool); |
302 | | return status; |
303 | | } |
304 | | |
305 | | status = apr_file_trunc(file, new_m->realsize); |
306 | | if (status != APR_SUCCESS && status != APR_ESPIPE) { |
307 | | apr_file_close(file); /* ignore errors, we're failing */ |
308 | | apr_file_remove(new_m->filename, new_m->pool); |
309 | | return status; |
310 | | } |
311 | | |
312 | | new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, |
313 | | MAP_SHARED, tmpfd, 0); |
314 | | /* FIXME: check for errors */ |
315 | | |
316 | | status = apr_file_close(file); |
317 | | if (status != APR_SUCCESS) { |
318 | | return status; |
319 | | } |
320 | | #endif /* APR_USE_SHMEM_MMAP_TMP */ |
321 | 0 | #if APR_USE_SHMEM_MMAP_SHM |
322 | | /* FIXME: SysV uses 0600... should we? */ |
323 | 0 | tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644); |
324 | 0 | if (tmpfd == -1) { |
325 | 0 | return errno; |
326 | 0 | } |
327 | | |
328 | | /* Note that apr_file_trunc() also calls lseek() so wrapping |
329 | | * the fd into an apr_file_t and doing this indirectly is |
330 | | * undesirable, see PR 66435. */ |
331 | 0 | status = ftruncate(tmpfd, new_m->realsize) < 0 ? errno : APR_SUCCESS; |
332 | 0 | if (status != APR_SUCCESS && status != APR_ESPIPE) { |
333 | 0 | shm_unlink(shm_name); /* we're failing, remove the object */ |
334 | 0 | close(tmpfd); |
335 | 0 | return status; |
336 | 0 | } |
337 | 0 | new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, |
338 | 0 | MAP_SHARED, tmpfd, 0); |
339 | 0 | status = (new_m->base == (void *)-1) ? errno : APR_SUCCESS; |
340 | | /* fd no longer needed once the memory is mapped. */ |
341 | 0 | close(tmpfd); |
342 | 0 | if (status) { |
343 | 0 | shm_unlink(shm_name); |
344 | 0 | return status; |
345 | 0 | } |
346 | 0 | #endif /* APR_USE_SHMEM_MMAP_SHM */ |
347 | | |
348 | | /* store the real size in the metadata */ |
349 | 0 | *(apr_size_t*)(new_m->base) = new_m->realsize; |
350 | | /* metadata isn't usable */ |
351 | 0 | new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); |
352 | |
|
353 | 0 | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, |
354 | 0 | apr_pool_cleanup_null); |
355 | 0 | *m = new_m; |
356 | 0 | return APR_SUCCESS; |
357 | |
|
358 | | #elif APR_USE_SHMEM_SHMGET |
359 | | new_m->realsize = reqsize; |
360 | | |
361 | | /* FIXME: APR_FPROT_OS_DEFAULT is too permissive, switch to 600 I think. */ |
362 | | status = apr_file_open(&file, filename, |
363 | | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, |
364 | | APR_FPROT_OS_DEFAULT, pool); |
365 | | if (status != APR_SUCCESS) { |
366 | | return status; |
367 | | } |
368 | | |
369 | | /* ftok() (on solaris at least) requires that the file actually |
370 | | * exist before calling ftok(). */ |
371 | | new_m->shmkey = our_ftok(filename); |
372 | | if (new_m->shmkey == (key_t)-1) { |
373 | | apr_file_close(file); |
374 | | return errno; |
375 | | } |
376 | | |
377 | | if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, |
378 | | SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) { |
379 | | apr_file_close(file); |
380 | | return errno; |
381 | | } |
382 | | |
383 | | if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { |
384 | | apr_file_close(file); |
385 | | return errno; |
386 | | } |
387 | | new_m->usable = new_m->base; |
388 | | |
389 | | if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { |
390 | | apr_file_close(file); |
391 | | return errno; |
392 | | } |
393 | | apr_uid_current(&uid, &gid, pool); |
394 | | shmbuf.shm_perm.uid = uid; |
395 | | shmbuf.shm_perm.gid = gid; |
396 | | if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { |
397 | | apr_file_close(file); |
398 | | return errno; |
399 | | } |
400 | | |
401 | | nbytes = sizeof(reqsize); |
402 | | status = apr_file_write(file, (const void *)&reqsize, |
403 | | &nbytes); |
404 | | if (status != APR_SUCCESS) { |
405 | | apr_file_close(file); |
406 | | return status; |
407 | | } |
408 | | status = apr_file_close(file); |
409 | | if (status != APR_SUCCESS) { |
410 | | return status; |
411 | | } |
412 | | |
413 | | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, |
414 | | apr_pool_cleanup_null); |
415 | | *m = new_m; |
416 | | return APR_SUCCESS; |
417 | | |
418 | | #else |
419 | | return APR_ENOTIMPL; |
420 | | #endif |
421 | 0 | } |
422 | 0 | } |
423 | | |
424 | | APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, |
425 | | apr_size_t reqsize, |
426 | | const char *filename, |
427 | | apr_pool_t *p, |
428 | | apr_int32_t flags) |
429 | 0 | { |
430 | 0 | return apr_shm_create(m, reqsize, filename, p); |
431 | 0 | } |
432 | | |
433 | | APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, |
434 | | apr_pool_t *pool) |
435 | 0 | { |
436 | | #if APR_USE_SHMEM_SHMGET |
437 | | apr_status_t status; |
438 | | apr_file_t *file; |
439 | | key_t shmkey; |
440 | | int shmid; |
441 | | #endif |
442 | |
|
443 | | #if APR_USE_SHMEM_MMAP_TMP |
444 | | return apr_file_remove(filename, pool); |
445 | | #elif APR_USE_SHMEM_MMAP_SHM |
446 | 0 | const char *shm_name = make_shm_open_safe_name(filename, pool); |
447 | 0 | if (shm_unlink(shm_name) == -1) { |
448 | 0 | return errno; |
449 | 0 | } |
450 | 0 | return APR_SUCCESS; |
451 | | #elif APR_USE_SHMEM_SHMGET |
452 | | /* Presume that the file already exists; just open for writing */ |
453 | | status = apr_file_open(&file, filename, APR_FOPEN_WRITE, |
454 | | APR_FPROT_OS_DEFAULT, pool); |
455 | | if (status) { |
456 | | return status; |
457 | | } |
458 | | |
459 | | /* ftok() (on solaris at least) requires that the file actually |
460 | | * exist before calling ftok(). */ |
461 | | shmkey = our_ftok(filename); |
462 | | if (shmkey == (key_t)-1) { |
463 | | goto shm_remove_failed; |
464 | | } |
465 | | |
466 | | apr_file_close(file); |
467 | | |
468 | | if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) { |
469 | | goto shm_remove_failed; |
470 | | } |
471 | | |
472 | | /* Indicate that the segment is to be destroyed as soon |
473 | | * as all processes have detached. This also disallows any |
474 | | * new attachments to the segment. */ |
475 | | if (shmctl(shmid, IPC_RMID, NULL) == -1) { |
476 | | goto shm_remove_failed; |
477 | | } |
478 | | return apr_file_remove(filename, pool); |
479 | | |
480 | | shm_remove_failed: |
481 | | status = errno; |
482 | | /* ensure the file has been removed anyway. */ |
483 | | apr_file_remove(filename, pool); |
484 | | return status; |
485 | | #else |
486 | | |
487 | | /* No support for anonymous shm */ |
488 | | return APR_ENOTIMPL; |
489 | | #endif |
490 | 0 | } |
491 | | |
492 | | APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m) |
493 | 0 | { |
494 | 0 | if (m->filename) { |
495 | 0 | return apr_shm_remove(m->filename, m->pool); |
496 | 0 | } |
497 | 0 | else { |
498 | 0 | return APR_ENOTIMPL; |
499 | 0 | } |
500 | 0 | } |
501 | | |
502 | | APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m) |
503 | 0 | { |
504 | 0 | return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner); |
505 | 0 | } |
506 | | |
507 | | static apr_status_t shm_cleanup_attach(void *m_) |
508 | 0 | { |
509 | 0 | apr_shm_t *m = (apr_shm_t *)m_; |
510 | |
|
511 | 0 | if (m->filename == NULL) { |
512 | | /* It doesn't make sense to detach from an anonymous memory segment. */ |
513 | 0 | return APR_EINVAL; |
514 | 0 | } |
515 | 0 | else { |
516 | 0 | #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM |
517 | 0 | if (munmap(m->base, m->realsize) == -1) { |
518 | 0 | return errno; |
519 | 0 | } |
520 | 0 | return APR_SUCCESS; |
521 | | #elif APR_USE_SHMEM_SHMGET |
522 | | if (shmdt(m->base) == -1) { |
523 | | return errno; |
524 | | } |
525 | | return APR_SUCCESS; |
526 | | #else |
527 | | return APR_ENOTIMPL; |
528 | | #endif |
529 | 0 | } |
530 | 0 | } |
531 | | |
532 | | APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, |
533 | | const char *filename, |
534 | | apr_pool_t *pool) |
535 | 0 | { |
536 | 0 | if (filename == NULL) { |
537 | | /* It doesn't make sense to attach to a segment if you don't know |
538 | | * the filename. */ |
539 | 0 | return APR_EINVAL; |
540 | 0 | } |
541 | 0 | else { |
542 | 0 | #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM |
543 | 0 | apr_shm_t *new_m; |
544 | 0 | apr_status_t status; |
545 | 0 | int tmpfd; |
546 | 0 | apr_file_t *file; /* file where metadata is stored */ |
547 | 0 | apr_size_t nbytes; |
548 | |
|
549 | 0 | new_m = apr_palloc(pool, sizeof(apr_shm_t)); |
550 | 0 | new_m->pool = pool; |
551 | 0 | new_m->filename = apr_pstrdup(pool, filename); |
552 | 0 | #if APR_USE_SHMEM_MMAP_SHM |
553 | 0 | const char *shm_name = make_shm_open_safe_name(filename, pool); |
554 | | |
555 | | /* FIXME: SysV uses 0600... should we? */ |
556 | 0 | tmpfd = shm_open(shm_name, O_RDWR, 0644); |
557 | 0 | if (tmpfd == -1) { |
558 | 0 | return errno; |
559 | 0 | } |
560 | | |
561 | 0 | status = apr_os_file_put(&file, &tmpfd, |
562 | 0 | APR_READ | APR_WRITE, |
563 | 0 | pool); |
564 | 0 | if (status != APR_SUCCESS) { |
565 | 0 | return status; |
566 | 0 | } |
567 | | |
568 | | #elif APR_USE_SHMEM_MMAP_TMP |
569 | | status = apr_file_open(&file, filename, |
570 | | APR_FOPEN_READ | APR_FOPEN_WRITE, |
571 | | APR_FPROT_OS_DEFAULT, pool); |
572 | | if (status != APR_SUCCESS) { |
573 | | return status; |
574 | | } |
575 | | status = apr_os_file_get(&tmpfd, file); |
576 | | if (status != APR_SUCCESS) { |
577 | | return status; |
578 | | } |
579 | | #else |
580 | | return APR_ENOTIMPL; |
581 | | #endif |
582 | | |
583 | 0 | nbytes = sizeof(new_m->realsize); |
584 | 0 | status = apr_file_read(file, (void *)&(new_m->realsize), |
585 | 0 | &nbytes); |
586 | 0 | if (status != APR_SUCCESS) { |
587 | 0 | return status; |
588 | 0 | } |
589 | | |
590 | 0 | status = apr_os_file_get(&tmpfd, file); |
591 | 0 | if (status != APR_SUCCESS) { |
592 | 0 | apr_file_close(file); /* ignore errors, we're failing */ |
593 | 0 | apr_file_remove(new_m->filename, new_m->pool); |
594 | 0 | return status; |
595 | 0 | } |
596 | | |
597 | 0 | new_m->reqsize = new_m->realsize - sizeof(apr_size_t); |
598 | |
|
599 | 0 | new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, |
600 | 0 | MAP_SHARED, tmpfd, 0); |
601 | | /* FIXME: check for errors */ |
602 | |
|
603 | 0 | status = apr_file_close(file); |
604 | 0 | if (status != APR_SUCCESS) { |
605 | 0 | return status; |
606 | 0 | } |
607 | | |
608 | | /* metadata isn't part of the usable segment */ |
609 | 0 | new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); |
610 | |
|
611 | 0 | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, |
612 | 0 | apr_pool_cleanup_null); |
613 | 0 | *m = new_m; |
614 | 0 | return APR_SUCCESS; |
615 | |
|
616 | | #elif APR_USE_SHMEM_SHMGET |
617 | | apr_shm_t *new_m; |
618 | | apr_status_t status; |
619 | | apr_file_t *file; /* file where metadata is stored */ |
620 | | apr_size_t nbytes; |
621 | | |
622 | | new_m = apr_palloc(pool, sizeof(apr_shm_t)); |
623 | | |
624 | | status = apr_file_open(&file, filename, |
625 | | APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, pool); |
626 | | if (status != APR_SUCCESS) { |
627 | | return status; |
628 | | } |
629 | | |
630 | | nbytes = sizeof(new_m->reqsize); |
631 | | status = apr_file_read(file, (void *)&(new_m->reqsize), |
632 | | &nbytes); |
633 | | if (status != APR_SUCCESS) { |
634 | | return status; |
635 | | } |
636 | | status = apr_file_close(file); |
637 | | if (status != APR_SUCCESS) { |
638 | | return status; |
639 | | } |
640 | | |
641 | | new_m->filename = apr_pstrdup(pool, filename); |
642 | | new_m->pool = pool; |
643 | | new_m->shmkey = our_ftok(filename); |
644 | | if (new_m->shmkey == (key_t)-1) { |
645 | | return errno; |
646 | | } |
647 | | if ((new_m->shmid = shmget(new_m->shmkey, 0, SHM_R | SHM_W)) == -1) { |
648 | | return errno; |
649 | | } |
650 | | if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { |
651 | | return errno; |
652 | | } |
653 | | new_m->usable = new_m->base; |
654 | | new_m->realsize = new_m->reqsize; |
655 | | |
656 | | apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, |
657 | | apr_pool_cleanup_null); |
658 | | *m = new_m; |
659 | | return APR_SUCCESS; |
660 | | |
661 | | #else |
662 | | return APR_ENOTIMPL; |
663 | | #endif |
664 | 0 | } |
665 | 0 | } |
666 | | |
667 | | APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, |
668 | | const char *filename, |
669 | | apr_pool_t *pool, |
670 | | apr_int32_t flags) |
671 | 0 | { |
672 | 0 | return apr_shm_attach(m, filename, pool); |
673 | 0 | } |
674 | | |
675 | | APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m) |
676 | 0 | { |
677 | 0 | apr_status_t rv = shm_cleanup_attach(m); |
678 | 0 | apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach); |
679 | 0 | return rv; |
680 | 0 | } |
681 | | |
682 | | APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m) |
683 | 0 | { |
684 | 0 | return m->usable; |
685 | 0 | } |
686 | | |
687 | | APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) |
688 | 0 | { |
689 | 0 | return m->reqsize; |
690 | 0 | } |
691 | | |
692 | | APR_PERMS_SET_IMPLEMENT(shm) |
693 | 0 | { |
694 | | #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON |
695 | | struct shmid_ds shmbuf; |
696 | | int shmid; |
697 | | apr_shm_t *m = (apr_shm_t *)theshm; |
698 | | |
699 | | if ((shmid = shmget(m->shmkey, 0, SHM_R | SHM_W)) == -1) { |
700 | | return errno; |
701 | | } |
702 | | shmbuf.shm_perm.uid = uid; |
703 | | shmbuf.shm_perm.gid = gid; |
704 | | shmbuf.shm_perm.mode = apr_unix_perms2mode(perms); |
705 | | if (shmctl(shmid, IPC_SET, &shmbuf) == -1) { |
706 | | return errno; |
707 | | } |
708 | | return APR_SUCCESS; |
709 | | #else |
710 | 0 | return APR_ENOTIMPL; |
711 | 0 | #endif |
712 | 0 | } |
713 | | |
714 | | APR_POOL_IMPLEMENT_ACCESSOR(shm) |
715 | | |
716 | | APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, |
717 | | apr_shm_t *shm) |
718 | 0 | { |
719 | 0 | return APR_ENOTIMPL; |
720 | 0 | } |
721 | | |
722 | | APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, |
723 | | apr_os_shm_t *osshm, |
724 | | apr_pool_t *pool) |
725 | 0 | { |
726 | 0 | return APR_ENOTIMPL; |
727 | 0 | } |
728 | | |