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! */
38static 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
52static 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
71static 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
81static 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
144APR_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
427APR_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
436APR_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
483shm_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
495APR_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
505APR_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
510static 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
535APR_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
670APR_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
678APR_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
685APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m)
686{
687    return m->usable;
688}
689
690APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m)
691{
692    return m->reqsize;
693}
694
695APR_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
717APR_POOL_IMPLEMENT_ACCESSOR(shm)
718
719APR_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
725APR_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