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! */
rshash(const char * p)38 static unsigned int rshash (const char *p) {
39     /* hash function from Robert Sedgwicks 'Algorithms in C' book */
40     unsigned int b    = 378551;
41     unsigned int a    = 63689;
42     unsigned int retval = 0;
43 
44     for( ; *p; p++) {
45         retval = retval * a + (*p);
46         a *= b;
47     }
48 
49     return retval;
50 }
51 
make_shm_open_safe_name(const char * filename,apr_pool_t * pool)52 static const char *make_shm_open_safe_name(const char *filename,
53                                            apr_pool_t *pool)
54 {
55     apr_ssize_t flen;
56     unsigned int h1, h2;
57 
58     if (filename == NULL) {
59         return NULL;
60     }
61 
62     flen = strlen(filename);
63     h1 = (apr_hashfunc_default(filename, &flen) & 0xffffffff);
64     h2 = (rshash(filename) & 0xffffffff);
65     return apr_psprintf(pool, "/ShM.%xH%x", h1, h2);
66 
67 }
68 #endif
69 
70 #if APR_USE_SHMEM_SHMGET
our_ftok(const char * filename)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 
shm_cleanup_owner(void * m_)81 static apr_status_t shm_cleanup_owner(void *m_)
82 {
83     apr_shm_t *m = (apr_shm_t *)m_;
84 
85     /* anonymous shared memory */
86     if (m->filename == NULL) {
87 #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
88         if (munmap(m->base, m->realsize) == -1) {
89             return errno;
90         }
91         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     }
101 
102     /* name-based shared memory */
103     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         if (munmap(m->base, m->realsize) == -1) {
116             return errno;
117         }
118         if (shm_unlink(make_shm_open_safe_name(m->filename, m->pool)) == -1 && errno != ENOENT) {
119             return errno;
120         }
121         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     }
142 }
143 
apr_shm_create(apr_shm_t ** m,apr_size_t reqsize,const char * filename,apr_pool_t * pool)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 {
149     apr_shm_t *new_m;
150     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 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \
157     APR_USE_SHMEM_MMAP_ZERO
158     int tmpfd;
159 #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 || APR_USE_SHMEM_MMAP_SHM
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     if (filename == NULL) {
170 #if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
171         new_m = apr_palloc(pool, sizeof(apr_shm_t));
172         new_m->pool = pool;
173         new_m->reqsize = reqsize;
174         new_m->realsize = reqsize +
175             APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */
176         new_m->filename = NULL;
177 
178 #if APR_USE_SHMEM_MMAP_ZERO
179         status = apr_file_open(&file, "/dev/zero", APR_READ | APR_WRITE,
180                                APR_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         new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE,
212                            MAP_ANON|MAP_SHARED, -1, 0);
213         if (new_m->base == (void *)MAP_FAILED) {
214             return errno;
215         }
216 
217         /* store the real size in the metadata */
218         *(apr_size_t*)(new_m->base) = new_m->realsize;
219         /* metadata isn't usable */
220         new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
221 
222         apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
223                                   apr_pool_cleanup_null);
224         *m = new_m;
225         return APR_SUCCESS;
226 
227 #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     }
272 
273     /* Name-based shared memory */
274     else {
275         new_m = apr_palloc(pool, sizeof(apr_shm_t));
276         new_m->pool = pool;
277         new_m->reqsize = reqsize;
278         new_m->filename = apr_pstrdup(pool, filename);
279 #if APR_USE_SHMEM_MMAP_SHM
280         const char *shm_name = make_shm_open_safe_name(filename, pool);
281 #endif
282 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
283         new_m->realsize = reqsize +
284             APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */
285         /* FIXME: Ignore error for now. *
286          * status = apr_file_remove(file, pool);*/
287         status = APR_SUCCESS;
288 
289 #if APR_USE_SHMEM_MMAP_TMP
290         /* FIXME: Is APR_OS_DEFAULT sufficient? */
291         status = apr_file_open(&file, filename,
292                                APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
293                                APR_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 #if APR_USE_SHMEM_MMAP_SHM
322         /* FIXME: SysV uses 0600... should we? */
323         tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644);
324         if (tmpfd == -1) {
325             return errno;
326         }
327 
328         status = apr_os_file_put(&file, &tmpfd,
329                                  APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
330                                  pool);
331         if (status != APR_SUCCESS) {
332             return status;
333         }
334 
335         status = apr_file_trunc(file, new_m->realsize);
336         if (status != APR_SUCCESS && status != APR_ESPIPE) {
337             shm_unlink(shm_name); /* we're failing, remove the object */
338             return status;
339         }
340         new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
341                            MAP_SHARED, tmpfd, 0);
342 
343         /* FIXME: check for errors */
344 
345         status = apr_file_close(file);
346         if (status != APR_SUCCESS) {
347             return status;
348         }
349 #endif /* APR_USE_SHMEM_MMAP_SHM */
350 
351         /* store the real size in the metadata */
352         *(apr_size_t*)(new_m->base) = new_m->realsize;
353         /* metadata isn't usable */
354         new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
355 
356         apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
357                                   apr_pool_cleanup_null);
358         *m = new_m;
359         return APR_SUCCESS;
360 
361 #elif APR_USE_SHMEM_SHMGET
362         new_m->realsize = reqsize;
363 
364         /* FIXME: APR_OS_DEFAULT is too permissive, switch to 600 I think. */
365         status = apr_file_open(&file, filename,
366                                APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL,
367                                APR_OS_DEFAULT, pool);
368         if (status != APR_SUCCESS) {
369             return status;
370         }
371 
372         /* ftok() (on solaris at least) requires that the file actually
373          * exist before calling ftok(). */
374         new_m->shmkey = our_ftok(filename);
375         if (new_m->shmkey == (key_t)-1) {
376             apr_file_close(file);
377             return errno;
378         }
379 
380         if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize,
381                                    SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) {
382             apr_file_close(file);
383             return errno;
384         }
385 
386         if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
387             apr_file_close(file);
388             return errno;
389         }
390         new_m->usable = new_m->base;
391 
392         if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) {
393             apr_file_close(file);
394             return errno;
395         }
396         apr_uid_current(&uid, &gid, pool);
397         shmbuf.shm_perm.uid = uid;
398         shmbuf.shm_perm.gid = gid;
399         if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) {
400             apr_file_close(file);
401             return errno;
402         }
403 
404         nbytes = sizeof(reqsize);
405         status = apr_file_write(file, (const void *)&reqsize,
406                                 &nbytes);
407         if (status != APR_SUCCESS) {
408             apr_file_close(file);
409             return status;
410         }
411         status = apr_file_close(file);
412         if (status != APR_SUCCESS) {
413             return status;
414         }
415 
416         apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
417                                   apr_pool_cleanup_null);
418         *m = new_m;
419         return APR_SUCCESS;
420 
421 #else
422         return APR_ENOTIMPL;
423 #endif
424     }
425 }
426 
apr_shm_create_ex(apr_shm_t ** m,apr_size_t reqsize,const char * filename,apr_pool_t * p,apr_int32_t flags)427 APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m,
428                                             apr_size_t reqsize,
429                                             const char *filename,
430                                             apr_pool_t *p,
431                                             apr_int32_t flags)
432 {
433     return apr_shm_create(m, reqsize, filename, p);
434 }
435 
apr_shm_remove(const char * filename,apr_pool_t * pool)436 APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename,
437                                          apr_pool_t *pool)
438 {
439 #if APR_USE_SHMEM_SHMGET
440     apr_status_t status;
441     apr_file_t *file;
442     key_t shmkey;
443     int shmid;
444 #endif
445 
446 #if APR_USE_SHMEM_MMAP_TMP
447     return apr_file_remove(filename, pool);
448 #elif APR_USE_SHMEM_MMAP_SHM
449     const char *shm_name = make_shm_open_safe_name(filename, pool);
450     if (shm_unlink(shm_name) == -1) {
451         return errno;
452     }
453     return APR_SUCCESS;
454 #elif APR_USE_SHMEM_SHMGET
455     /* Presume that the file already exists; just open for writing */
456     status = apr_file_open(&file, filename, APR_FOPEN_WRITE,
457                            APR_OS_DEFAULT, pool);
458     if (status) {
459         return status;
460     }
461 
462     /* ftok() (on solaris at least) requires that the file actually
463      * exist before calling ftok(). */
464     shmkey = our_ftok(filename);
465     if (shmkey == (key_t)-1) {
466         goto shm_remove_failed;
467     }
468 
469     apr_file_close(file);
470 
471     if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) {
472         goto shm_remove_failed;
473     }
474 
475     /* Indicate that the segment is to be destroyed as soon
476      * as all processes have detached. This also disallows any
477      * new attachments to the segment. */
478     if (shmctl(shmid, IPC_RMID, NULL) == -1) {
479         goto shm_remove_failed;
480     }
481     return apr_file_remove(filename, pool);
482 
483 shm_remove_failed:
484     status = errno;
485     /* ensure the file has been removed anyway. */
486     apr_file_remove(filename, pool);
487     return status;
488 #else
489 
490     /* No support for anonymous shm */
491     return APR_ENOTIMPL;
492 #endif
493 }
494 
apr_shm_delete(apr_shm_t * m)495 APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m)
496 {
497     if (m->filename) {
498         return apr_shm_remove(m->filename, m->pool);
499     }
500     else {
501         return APR_ENOTIMPL;
502     }
503 }
504 
apr_shm_destroy(apr_shm_t * m)505 APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m)
506 {
507     return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner);
508 }
509 
shm_cleanup_attach(void * m_)510 static apr_status_t shm_cleanup_attach(void *m_)
511 {
512     apr_shm_t *m = (apr_shm_t *)m_;
513 
514     if (m->filename == NULL) {
515         /* It doesn't make sense to detach from an anonymous memory segment. */
516         return APR_EINVAL;
517     }
518     else {
519 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
520         if (munmap(m->base, m->realsize) == -1) {
521             return errno;
522         }
523         return APR_SUCCESS;
524 #elif APR_USE_SHMEM_SHMGET
525         if (shmdt(m->base) == -1) {
526             return errno;
527         }
528         return APR_SUCCESS;
529 #else
530         return APR_ENOTIMPL;
531 #endif
532     }
533 }
534 
apr_shm_attach(apr_shm_t ** m,const char * filename,apr_pool_t * pool)535 APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m,
536                                          const char *filename,
537                                          apr_pool_t *pool)
538 {
539     if (filename == NULL) {
540         /* It doesn't make sense to attach to a segment if you don't know
541          * the filename. */
542         return APR_EINVAL;
543     }
544     else {
545 #if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
546         apr_shm_t *new_m;
547         apr_status_t status;
548         int tmpfd;
549         apr_file_t *file;   /* file where metadata is stored */
550         apr_size_t nbytes;
551 
552         new_m = apr_palloc(pool, sizeof(apr_shm_t));
553         new_m->pool = pool;
554         new_m->filename = apr_pstrdup(pool, filename);
555 #if APR_USE_SHMEM_MMAP_SHM
556         const char *shm_name = make_shm_open_safe_name(filename, pool);
557 
558         /* FIXME: SysV uses 0600... should we? */
559         tmpfd = shm_open(shm_name, O_RDWR, 0644);
560         if (tmpfd == -1) {
561             return errno;
562         }
563 
564         status = apr_os_file_put(&file, &tmpfd,
565                                  APR_READ | APR_WRITE,
566                                  pool);
567         if (status != APR_SUCCESS) {
568             return status;
569         }
570 
571 #elif APR_USE_SHMEM_MMAP_TMP
572         status = apr_file_open(&file, filename,
573                                APR_READ | APR_WRITE,
574                                APR_OS_DEFAULT, pool);
575         if (status != APR_SUCCESS) {
576             return status;
577         }
578         status = apr_os_file_get(&tmpfd, file);
579         if (status != APR_SUCCESS) {
580             return status;
581         }
582 #else
583         return APR_ENOTIMPL;
584 #endif
585 
586         nbytes = sizeof(new_m->realsize);
587         status = apr_file_read(file, (void *)&(new_m->realsize),
588                                &nbytes);
589         if (status != APR_SUCCESS) {
590             return status;
591         }
592 
593         status = apr_os_file_get(&tmpfd, file);
594         if (status != APR_SUCCESS) {
595             apr_file_close(file); /* ignore errors, we're failing */
596             apr_file_remove(new_m->filename, new_m->pool);
597             return status;
598         }
599 
600         new_m->reqsize = new_m->realsize - sizeof(apr_size_t);
601 
602         new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
603                            MAP_SHARED, tmpfd, 0);
604         /* FIXME: check for errors */
605 
606         status = apr_file_close(file);
607         if (status != APR_SUCCESS) {
608             return status;
609         }
610 
611         /* metadata isn't part of the usable segment */
612         new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
613 
614         apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
615                                   apr_pool_cleanup_null);
616         *m = new_m;
617         return APR_SUCCESS;
618 
619 #elif APR_USE_SHMEM_SHMGET
620         apr_shm_t *new_m;
621         apr_status_t status;
622         apr_file_t *file;   /* file where metadata is stored */
623         apr_size_t nbytes;
624 
625         new_m = apr_palloc(pool, sizeof(apr_shm_t));
626 
627         status = apr_file_open(&file, filename,
628                                APR_FOPEN_READ, APR_OS_DEFAULT, pool);
629         if (status != APR_SUCCESS) {
630             return status;
631         }
632 
633         nbytes = sizeof(new_m->reqsize);
634         status = apr_file_read(file, (void *)&(new_m->reqsize),
635                                &nbytes);
636         if (status != APR_SUCCESS) {
637             return status;
638         }
639         status = apr_file_close(file);
640         if (status != APR_SUCCESS) {
641             return status;
642         }
643 
644         new_m->filename = apr_pstrdup(pool, filename);
645         new_m->pool = pool;
646         new_m->shmkey = our_ftok(filename);
647         if (new_m->shmkey == (key_t)-1) {
648             return errno;
649         }
650         if ((new_m->shmid = shmget(new_m->shmkey, 0, SHM_R | SHM_W)) == -1) {
651             return errno;
652         }
653         if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
654             return errno;
655         }
656         new_m->usable = new_m->base;
657         new_m->realsize = new_m->reqsize;
658 
659         apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
660                                   apr_pool_cleanup_null);
661         *m = new_m;
662         return APR_SUCCESS;
663 
664 #else
665         return APR_ENOTIMPL;
666 #endif
667     }
668 }
669 
apr_shm_attach_ex(apr_shm_t ** m,const char * filename,apr_pool_t * pool,apr_int32_t flags)670 APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m,
671                                             const char *filename,
672                                             apr_pool_t *pool,
673                                             apr_int32_t flags)
674 {
675     return apr_shm_attach(m, filename, pool);
676 }
677 
apr_shm_detach(apr_shm_t * m)678 APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m)
679 {
680     apr_status_t rv = shm_cleanup_attach(m);
681     apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach);
682     return rv;
683 }
684 
apr_shm_baseaddr_get(const apr_shm_t * m)685 APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m)
686 {
687     return m->usable;
688 }
689 
apr_shm_size_get(const apr_shm_t * m)690 APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m)
691 {
692     return m->reqsize;
693 }
694 
APR_PERMS_SET_IMPLEMENT(shm)695 APR_PERMS_SET_IMPLEMENT(shm)
696 {
697 #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON
698     struct shmid_ds shmbuf;
699     int shmid;
700     apr_shm_t *m = (apr_shm_t *)theshm;
701 
702     if ((shmid = shmget(m->shmkey, 0, SHM_R | SHM_W)) == -1) {
703         return errno;
704     }
705     shmbuf.shm_perm.uid  = uid;
706     shmbuf.shm_perm.gid  = gid;
707     shmbuf.shm_perm.mode = apr_unix_perms2mode(perms);
708     if (shmctl(shmid, IPC_SET, &shmbuf) == -1) {
709         return errno;
710     }
711     return APR_SUCCESS;
712 #else
713     return APR_ENOTIMPL;
714 #endif
715 }
716 
717 APR_POOL_IMPLEMENT_ACCESSOR(shm)
718 
APR_DECLARE(apr_status_t)719 APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm,
720                                          apr_shm_t *shm)
721 {
722     return APR_ENOTIMPL;
723 }
724 
apr_os_shm_put(apr_shm_t ** m,apr_os_shm_t * osshm,apr_pool_t * pool)725 APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m,
726                                          apr_os_shm_t *osshm,
727                                          apr_pool_t *pool)
728 {
729     return APR_ENOTIMPL;
730 }
731 
732