1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#include "apr_arch_shm.h"
18251875Speter
19251875Speter#include "apr_general.h"
20251875Speter#include "apr_errno.h"
21251875Speter#include "apr_user.h"
22251875Speter#include "apr_strings.h"
23269847Speter#include "apr_hash.h"
24251875Speter
25269847Speter#if APR_USE_SHMEM_MMAP_SHM
26269847Speter/*
27269847Speter *   For portable use, a shared memory object should be identified by a name of
28269847Speter *   the form /somename; that is, a null-terminated string of up to NAME_MAX
29269847Speter *   (i.e., 255) characters consisting of an initial slash, followed by one or
30269847Speter *   more characters, none of which are slashes.
31269847Speter */
32269847Speter#ifndef NAME_MAX
33269847Speter#define NAME_MAX 255
34269847Speter#endif
35269847Speter
36269847Speter/* See proc_mutex.c and sem_open for the reason for all this! */
37269847Speterstatic unsigned int rshash (const char *p) {
38269847Speter    /* hash function from Robert Sedgwicks 'Algorithms in C' book */
39269847Speter    unsigned int b    = 378551;
40269847Speter    unsigned int a    = 63689;
41269847Speter    unsigned int retval = 0;
42269847Speter
43269847Speter    for( ; *p; p++) {
44269847Speter        retval = retval * a + (*p);
45269847Speter        a *= b;
46269847Speter    }
47269847Speter
48269847Speter    return retval;
49269847Speter}
50269847Speter
51269847Speterstatic const char *make_shm_open_safe_name(const char *filename,
52269847Speter                                           apr_pool_t *pool)
53269847Speter{
54269847Speter    apr_ssize_t flen;
55269847Speter    unsigned int h1, h2;
56269847Speter
57269847Speter    if (filename == NULL) {
58269847Speter        return NULL;
59269847Speter    }
60269847Speter
61269847Speter    flen = strlen(filename);
62269847Speter    h1 = (apr_hashfunc_default(filename, &flen) & 0xffffffff);
63269847Speter    h2 = (rshash(filename) & 0xffffffff);
64269847Speter    return apr_psprintf(pool, "/ShM.%xH%x", h1, h2);
65269847Speter
66269847Speter}
67269847Speter#endif
68269847Speter
69269847Speter#if APR_USE_SHMEM_SHMGET
70269847Speterstatic key_t our_ftok(const char *filename)
71269847Speter{
72269847Speter    /* to help avoid collisions while still using
73269847Speter     * an easily recreated proj_id */
74269847Speter    apr_ssize_t slen = strlen(filename);
75269847Speter    return ftok(filename,
76269847Speter                (int)apr_hashfunc_default(filename, &slen));
77269847Speter}
78269847Speter#endif
79269847Speter
80251875Speterstatic apr_status_t shm_cleanup_owner(void *m_)
81251875Speter{
82251875Speter    apr_shm_t *m = (apr_shm_t *)m_;
83251875Speter
84251875Speter    /* anonymous shared memory */
85251875Speter    if (m->filename == NULL) {
86251875Speter#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
87251875Speter        if (munmap(m->base, m->realsize) == -1) {
88251875Speter            return errno;
89251875Speter        }
90251875Speter        return APR_SUCCESS;
91251875Speter#elif APR_USE_SHMEM_SHMGET_ANON
92251875Speter        if (shmdt(m->base) == -1) {
93251875Speter            return errno;
94251875Speter        }
95251875Speter        /* This segment will automatically remove itself after all
96251875Speter         * references have detached. */
97251875Speter        return APR_SUCCESS;
98251875Speter#endif
99251875Speter    }
100251875Speter
101251875Speter    /* name-based shared memory */
102251875Speter    else {
103251875Speter#if APR_USE_SHMEM_MMAP_TMP
104251875Speter        if (munmap(m->base, m->realsize) == -1) {
105251875Speter            return errno;
106251875Speter        }
107251875Speter        if (access(m->filename, F_OK)) {
108251875Speter            return APR_SUCCESS;
109251875Speter        }
110251875Speter        else {
111251875Speter            return apr_file_remove(m->filename, m->pool);
112251875Speter        }
113251875Speter#elif APR_USE_SHMEM_MMAP_SHM
114251875Speter        if (munmap(m->base, m->realsize) == -1) {
115251875Speter            return errno;
116251875Speter        }
117269847Speter        if (shm_unlink(make_shm_open_safe_name(m->filename, m->pool)) == -1 && errno != ENOENT) {
118251875Speter            return errno;
119251875Speter        }
120251875Speter        return APR_SUCCESS;
121251875Speter#elif APR_USE_SHMEM_SHMGET
122251875Speter        /* Indicate that the segment is to be destroyed as soon
123251875Speter         * as all processes have detached. This also disallows any
124251875Speter         * new attachments to the segment. */
125251875Speter        if (shmctl(m->shmid, IPC_RMID, NULL) == -1 && errno != EINVAL) {
126251875Speter            return errno;
127251875Speter        }
128251875Speter        if (shmdt(m->base) == -1) {
129251875Speter            return errno;
130251875Speter        }
131251875Speter        if (access(m->filename, F_OK)) {
132251875Speter            return APR_SUCCESS;
133251875Speter        }
134251875Speter        else {
135251875Speter            return apr_file_remove(m->filename, m->pool);
136251875Speter        }
137251875Speter#else
138251875Speter        return APR_ENOTIMPL;
139251875Speter#endif
140251875Speter    }
141251875Speter}
142251875Speter
143251875SpeterAPR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m,
144251875Speter                                         apr_size_t reqsize,
145251875Speter                                         const char *filename,
146251875Speter                                         apr_pool_t *pool)
147251875Speter{
148251875Speter    apr_shm_t *new_m;
149251875Speter    apr_status_t status;
150251875Speter#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON
151251875Speter    struct shmid_ds shmbuf;
152251875Speter    apr_uid_t uid;
153251875Speter    apr_gid_t gid;
154251875Speter#endif
155251875Speter#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \
156251875Speter    APR_USE_SHMEM_MMAP_ZERO
157251875Speter    int tmpfd;
158251875Speter#endif
159251875Speter#if APR_USE_SHMEM_SHMGET
160251875Speter    apr_size_t nbytes;
161251875Speter    key_t shmkey;
162251875Speter#endif
163251875Speter#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_SHMGET || \
164251875Speter    APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
165251875Speter    apr_file_t *file;   /* file where metadata is stored */
166251875Speter#endif
167251875Speter
168251875Speter    /* Check if they want anonymous or name-based shared memory */
169251875Speter    if (filename == NULL) {
170251875Speter#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON
171251875Speter        new_m = apr_palloc(pool, sizeof(apr_shm_t));
172251875Speter        new_m->pool = pool;
173251875Speter        new_m->reqsize = reqsize;
174251875Speter        new_m->realsize = reqsize +
175251875Speter            APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */
176251875Speter        new_m->filename = NULL;
177251875Speter
178251875Speter#if APR_USE_SHMEM_MMAP_ZERO
179251875Speter        status = apr_file_open(&file, "/dev/zero", APR_READ | APR_WRITE,
180251875Speter                               APR_OS_DEFAULT, pool);
181251875Speter        if (status != APR_SUCCESS) {
182251875Speter            return status;
183251875Speter        }
184251875Speter        status = apr_os_file_get(&tmpfd, file);
185251875Speter        if (status != APR_SUCCESS) {
186251875Speter            return status;
187251875Speter        }
188251875Speter
189251875Speter        new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE,
190251875Speter                           MAP_SHARED, tmpfd, 0);
191251875Speter        if (new_m->base == (void *)MAP_FAILED) {
192251875Speter            return errno;
193251875Speter        }
194251875Speter
195251875Speter        status = apr_file_close(file);
196251875Speter        if (status != APR_SUCCESS) {
197251875Speter            return status;
198251875Speter        }
199251875Speter
200251875Speter        /* store the real size in the metadata */
201251875Speter        *(apr_size_t*)(new_m->base) = new_m->realsize;
202251875Speter        /* metadata isn't usable */
203251875Speter        new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
204251875Speter
205251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
206251875Speter                                  apr_pool_cleanup_null);
207251875Speter        *m = new_m;
208251875Speter        return APR_SUCCESS;
209251875Speter
210251875Speter#elif APR_USE_SHMEM_MMAP_ANON
211251875Speter        new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE,
212251875Speter                           MAP_ANON|MAP_SHARED, -1, 0);
213251875Speter        if (new_m->base == (void *)MAP_FAILED) {
214251875Speter            return errno;
215251875Speter        }
216251875Speter
217251875Speter        /* store the real size in the metadata */
218251875Speter        *(apr_size_t*)(new_m->base) = new_m->realsize;
219251875Speter        /* metadata isn't usable */
220251875Speter        new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
221251875Speter
222251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
223251875Speter                                  apr_pool_cleanup_null);
224251875Speter        *m = new_m;
225251875Speter        return APR_SUCCESS;
226251875Speter
227251875Speter#endif /* APR_USE_SHMEM_MMAP_ZERO */
228251875Speter#elif APR_USE_SHMEM_SHMGET_ANON
229251875Speter        new_m = apr_palloc(pool, sizeof(apr_shm_t));
230251875Speter        new_m->pool = pool;
231251875Speter        new_m->reqsize = reqsize;
232251875Speter        new_m->realsize = reqsize;
233251875Speter        new_m->filename = NULL;
234251875Speter
235251875Speter        if ((new_m->shmid = shmget(IPC_PRIVATE, new_m->realsize,
236251875Speter                                   SHM_R | SHM_W | IPC_CREAT)) < 0) {
237251875Speter            return errno;
238251875Speter        }
239251875Speter
240251875Speter        if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
241251875Speter            return errno;
242251875Speter        }
243251875Speter        new_m->usable = new_m->base;
244251875Speter
245251875Speter        if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) {
246251875Speter            return errno;
247251875Speter        }
248251875Speter        apr_uid_current(&uid, &gid, pool);
249251875Speter        shmbuf.shm_perm.uid = uid;
250251875Speter        shmbuf.shm_perm.gid = gid;
251251875Speter        if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) {
252251875Speter            return errno;
253251875Speter        }
254251875Speter
255251875Speter        /* Remove the segment once use count hits zero.
256251875Speter         * We will not attach to this segment again, since it is
257251875Speter         * anonymous memory, so it is ok to mark it for deletion.
258251875Speter         */
259251875Speter        if (shmctl(new_m->shmid, IPC_RMID, NULL) == -1) {
260251875Speter            return errno;
261251875Speter        }
262251875Speter
263251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
264251875Speter                                  apr_pool_cleanup_null);
265251875Speter        *m = new_m;
266251875Speter        return APR_SUCCESS;
267251875Speter#else
268251875Speter        /* It is an error if they want anonymous memory but we don't have it. */
269251875Speter        return APR_ENOTIMPL; /* requested anonymous but we don't have it */
270251875Speter#endif
271251875Speter    }
272251875Speter
273251875Speter    /* Name-based shared memory */
274251875Speter    else {
275251875Speter        new_m = apr_palloc(pool, sizeof(apr_shm_t));
276251875Speter        new_m->pool = pool;
277251875Speter        new_m->reqsize = reqsize;
278251875Speter        new_m->filename = apr_pstrdup(pool, filename);
279269847Speter#if APR_USE_SHMEM_MMAP_SHM
280269847Speter        const char *shm_name = make_shm_open_safe_name(filename, pool);
281269847Speter#endif
282251875Speter#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
283251875Speter        new_m->realsize = reqsize +
284251875Speter            APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */
285251875Speter        /* FIXME: Ignore error for now. *
286251875Speter         * status = apr_file_remove(file, pool);*/
287251875Speter        status = APR_SUCCESS;
288251875Speter
289251875Speter#if APR_USE_SHMEM_MMAP_TMP
290251875Speter        /* FIXME: Is APR_OS_DEFAULT sufficient? */
291251875Speter        status = apr_file_open(&file, filename,
292251875Speter                               APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
293251875Speter                               APR_OS_DEFAULT, pool);
294251875Speter        if (status != APR_SUCCESS) {
295251875Speter            return status;
296251875Speter        }
297251875Speter
298251875Speter        status = apr_os_file_get(&tmpfd, file);
299251875Speter        if (status != APR_SUCCESS) {
300251875Speter            apr_file_close(file); /* ignore errors, we're failing */
301251875Speter            apr_file_remove(new_m->filename, new_m->pool);
302251875Speter            return status;
303251875Speter        }
304251875Speter
305251875Speter        status = apr_file_trunc(file, new_m->realsize);
306269847Speter        if (status != APR_SUCCESS && status != APR_ESPIPE) {
307251875Speter            apr_file_close(file); /* ignore errors, we're failing */
308251875Speter            apr_file_remove(new_m->filename, new_m->pool);
309251875Speter            return status;
310251875Speter        }
311251875Speter
312251875Speter        new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
313251875Speter                           MAP_SHARED, tmpfd, 0);
314251875Speter        /* FIXME: check for errors */
315251875Speter
316251875Speter        status = apr_file_close(file);
317251875Speter        if (status != APR_SUCCESS) {
318251875Speter            return status;
319251875Speter        }
320251875Speter#endif /* APR_USE_SHMEM_MMAP_TMP */
321251875Speter#if APR_USE_SHMEM_MMAP_SHM
322269847Speter        /* FIXME: SysV uses 0600... should we? */
323269847Speter        tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644);
324251875Speter        if (tmpfd == -1) {
325251875Speter            return errno;
326251875Speter        }
327251875Speter
328251875Speter        status = apr_os_file_put(&file, &tmpfd,
329251875Speter                                 APR_READ | APR_WRITE | APR_CREATE | APR_EXCL,
330251875Speter                                 pool);
331251875Speter        if (status != APR_SUCCESS) {
332251875Speter            return status;
333251875Speter        }
334251875Speter
335251875Speter        status = apr_file_trunc(file, new_m->realsize);
336269847Speter        if (status != APR_SUCCESS && status != APR_ESPIPE) {
337269847Speter            shm_unlink(shm_name); /* we're failing, remove the object */
338251875Speter            return status;
339251875Speter        }
340269847Speter        new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
341251875Speter                           MAP_SHARED, tmpfd, 0);
342251875Speter
343251875Speter        /* FIXME: check for errors */
344251875Speter
345251875Speter        status = apr_file_close(file);
346251875Speter        if (status != APR_SUCCESS) {
347251875Speter            return status;
348251875Speter        }
349251875Speter#endif /* APR_USE_SHMEM_MMAP_SHM */
350251875Speter
351251875Speter        /* store the real size in the metadata */
352251875Speter        *(apr_size_t*)(new_m->base) = new_m->realsize;
353251875Speter        /* metadata isn't usable */
354251875Speter        new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
355251875Speter
356251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
357251875Speter                                  apr_pool_cleanup_null);
358251875Speter        *m = new_m;
359251875Speter        return APR_SUCCESS;
360251875Speter
361251875Speter#elif APR_USE_SHMEM_SHMGET
362251875Speter        new_m->realsize = reqsize;
363251875Speter
364251875Speter        /* FIXME: APR_OS_DEFAULT is too permissive, switch to 600 I think. */
365251875Speter        status = apr_file_open(&file, filename,
366251875Speter                               APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL,
367251875Speter                               APR_OS_DEFAULT, pool);
368251875Speter        if (status != APR_SUCCESS) {
369251875Speter            return status;
370251875Speter        }
371251875Speter
372251875Speter        /* ftok() (on solaris at least) requires that the file actually
373251875Speter         * exist before calling ftok(). */
374269847Speter        shmkey = our_ftok(filename);
375251875Speter        if (shmkey == (key_t)-1) {
376269847Speter            apr_file_close(file);
377251875Speter            return errno;
378251875Speter        }
379251875Speter
380251875Speter        if ((new_m->shmid = shmget(shmkey, new_m->realsize,
381251875Speter                                   SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) {
382269847Speter            apr_file_close(file);
383251875Speter            return errno;
384251875Speter        }
385251875Speter
386251875Speter        if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
387269847Speter            apr_file_close(file);
388251875Speter            return errno;
389251875Speter        }
390251875Speter        new_m->usable = new_m->base;
391251875Speter
392251875Speter        if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) {
393269847Speter            apr_file_close(file);
394251875Speter            return errno;
395251875Speter        }
396251875Speter        apr_uid_current(&uid, &gid, pool);
397251875Speter        shmbuf.shm_perm.uid = uid;
398251875Speter        shmbuf.shm_perm.gid = gid;
399251875Speter        if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) {
400269847Speter            apr_file_close(file);
401251875Speter            return errno;
402251875Speter        }
403251875Speter
404251875Speter        nbytes = sizeof(reqsize);
405251875Speter        status = apr_file_write(file, (const void *)&reqsize,
406251875Speter                                &nbytes);
407251875Speter        if (status != APR_SUCCESS) {
408269847Speter            apr_file_close(file);
409251875Speter            return status;
410251875Speter        }
411251875Speter        status = apr_file_close(file);
412251875Speter        if (status != APR_SUCCESS) {
413251875Speter            return status;
414251875Speter        }
415251875Speter
416251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
417251875Speter                                  apr_pool_cleanup_null);
418251875Speter        *m = new_m;
419251875Speter        return APR_SUCCESS;
420251875Speter
421251875Speter#else
422251875Speter        return APR_ENOTIMPL;
423251875Speter#endif
424251875Speter    }
425251875Speter}
426251875Speter
427269847SpeterAPR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m,
428269847Speter                                            apr_size_t reqsize,
429269847Speter                                            const char *filename,
430269847Speter                                            apr_pool_t *p,
431269847Speter                                            apr_int32_t flags)
432269847Speter{
433269847Speter    return apr_shm_create(m, reqsize, filename, p);
434269847Speter}
435269847Speter
436251875SpeterAPR_DECLARE(apr_status_t) apr_shm_remove(const char *filename,
437251875Speter                                         apr_pool_t *pool)
438251875Speter{
439251875Speter#if APR_USE_SHMEM_SHMGET
440251875Speter    apr_status_t status;
441251875Speter    apr_file_t *file;
442251875Speter    key_t shmkey;
443251875Speter    int shmid;
444251875Speter#endif
445251875Speter
446251875Speter#if APR_USE_SHMEM_MMAP_TMP
447251875Speter    return apr_file_remove(filename, pool);
448251875Speter#elif APR_USE_SHMEM_MMAP_SHM
449269847Speter    const char *shm_name = make_shm_open_safe_name(filename, pool);
450269847Speter    if (shm_unlink(shm_name) == -1) {
451251875Speter        return errno;
452251875Speter    }
453251875Speter    return APR_SUCCESS;
454251875Speter#elif APR_USE_SHMEM_SHMGET
455251875Speter    /* Presume that the file already exists; just open for writing */
456251875Speter    status = apr_file_open(&file, filename, APR_FOPEN_WRITE,
457251875Speter                           APR_OS_DEFAULT, pool);
458251875Speter    if (status) {
459251875Speter        return status;
460251875Speter    }
461251875Speter
462251875Speter    /* ftok() (on solaris at least) requires that the file actually
463251875Speter     * exist before calling ftok(). */
464269847Speter    shmkey = our_ftok(filename);
465251875Speter    if (shmkey == (key_t)-1) {
466251875Speter        goto shm_remove_failed;
467251875Speter    }
468251875Speter
469251875Speter    apr_file_close(file);
470251875Speter
471251875Speter    if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) {
472251875Speter        goto shm_remove_failed;
473251875Speter    }
474251875Speter
475251875Speter    /* Indicate that the segment is to be destroyed as soon
476251875Speter     * as all processes have detached. This also disallows any
477251875Speter     * new attachments to the segment. */
478251875Speter    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
479251875Speter        goto shm_remove_failed;
480251875Speter    }
481251875Speter    return apr_file_remove(filename, pool);
482251875Speter
483251875Spetershm_remove_failed:
484251875Speter    status = errno;
485251875Speter    /* ensure the file has been removed anyway. */
486251875Speter    apr_file_remove(filename, pool);
487251875Speter    return status;
488251875Speter#else
489251875Speter
490251875Speter    /* No support for anonymous shm */
491251875Speter    return APR_ENOTIMPL;
492251875Speter#endif
493251875Speter}
494251875Speter
495251875SpeterAPR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m)
496251875Speter{
497251875Speter    return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner);
498251875Speter}
499251875Speter
500251875Speterstatic apr_status_t shm_cleanup_attach(void *m_)
501251875Speter{
502251875Speter    apr_shm_t *m = (apr_shm_t *)m_;
503251875Speter
504251875Speter    if (m->filename == NULL) {
505251875Speter        /* It doesn't make sense to detach from an anonymous memory segment. */
506251875Speter        return APR_EINVAL;
507251875Speter    }
508251875Speter    else {
509251875Speter#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
510251875Speter        if (munmap(m->base, m->realsize) == -1) {
511251875Speter            return errno;
512251875Speter        }
513251875Speter        return APR_SUCCESS;
514251875Speter#elif APR_USE_SHMEM_SHMGET
515251875Speter        if (shmdt(m->base) == -1) {
516251875Speter            return errno;
517251875Speter        }
518251875Speter        return APR_SUCCESS;
519251875Speter#else
520251875Speter        return APR_ENOTIMPL;
521251875Speter#endif
522251875Speter    }
523251875Speter}
524251875Speter
525251875SpeterAPR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m,
526251875Speter                                         const char *filename,
527251875Speter                                         apr_pool_t *pool)
528251875Speter{
529251875Speter    if (filename == NULL) {
530251875Speter        /* It doesn't make sense to attach to a segment if you don't know
531251875Speter         * the filename. */
532251875Speter        return APR_EINVAL;
533251875Speter    }
534251875Speter    else {
535251875Speter#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
536251875Speter        apr_shm_t *new_m;
537251875Speter        apr_status_t status;
538251875Speter        int tmpfd;
539251875Speter        apr_file_t *file;   /* file where metadata is stored */
540251875Speter        apr_size_t nbytes;
541251875Speter
542251875Speter        new_m = apr_palloc(pool, sizeof(apr_shm_t));
543251875Speter        new_m->pool = pool;
544251875Speter        new_m->filename = apr_pstrdup(pool, filename);
545269847Speter#if APR_USE_SHMEM_MMAP_SHM
546269847Speter        const char *shm_name = make_shm_open_safe_name(filename, pool);
547251875Speter
548269847Speter        /* FIXME: SysV uses 0600... should we? */
549269847Speter        tmpfd = shm_open(shm_name, O_RDWR, 0644);
550269847Speter        if (tmpfd == -1) {
551269847Speter            return errno;
552269847Speter        }
553269847Speter
554269847Speter        status = apr_os_file_put(&file, &tmpfd,
555269847Speter                                 APR_READ | APR_WRITE,
556269847Speter                                 pool);
557269847Speter        if (status != APR_SUCCESS) {
558269847Speter            return status;
559269847Speter        }
560269847Speter
561269847Speter#elif APR_USE_SHMEM_MMAP_TMP
562251875Speter        status = apr_file_open(&file, filename,
563251875Speter                               APR_READ | APR_WRITE,
564251875Speter                               APR_OS_DEFAULT, pool);
565251875Speter        if (status != APR_SUCCESS) {
566251875Speter            return status;
567251875Speter        }
568251875Speter        status = apr_os_file_get(&tmpfd, file);
569251875Speter        if (status != APR_SUCCESS) {
570251875Speter            return status;
571251875Speter        }
572269847Speter#else
573269847Speter        return APR_ENOTIMPL;
574269847Speter#endif
575251875Speter
576251875Speter        nbytes = sizeof(new_m->realsize);
577251875Speter        status = apr_file_read(file, (void *)&(new_m->realsize),
578251875Speter                               &nbytes);
579251875Speter        if (status != APR_SUCCESS) {
580251875Speter            return status;
581251875Speter        }
582251875Speter
583251875Speter        status = apr_os_file_get(&tmpfd, file);
584251875Speter        if (status != APR_SUCCESS) {
585251875Speter            apr_file_close(file); /* ignore errors, we're failing */
586251875Speter            apr_file_remove(new_m->filename, new_m->pool);
587251875Speter            return status;
588251875Speter        }
589251875Speter
590251875Speter        new_m->reqsize = new_m->realsize - sizeof(apr_size_t);
591251875Speter
592251875Speter        new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
593251875Speter                           MAP_SHARED, tmpfd, 0);
594251875Speter        /* FIXME: check for errors */
595251875Speter
596251875Speter        status = apr_file_close(file);
597251875Speter        if (status != APR_SUCCESS) {
598251875Speter            return status;
599251875Speter        }
600251875Speter
601251875Speter        /* metadata isn't part of the usable segment */
602251875Speter        new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
603251875Speter
604251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
605251875Speter                                  apr_pool_cleanup_null);
606251875Speter        *m = new_m;
607251875Speter        return APR_SUCCESS;
608251875Speter
609251875Speter#elif APR_USE_SHMEM_SHMGET
610251875Speter        apr_shm_t *new_m;
611251875Speter        apr_status_t status;
612251875Speter        apr_file_t *file;   /* file where metadata is stored */
613251875Speter        apr_size_t nbytes;
614251875Speter        key_t shmkey;
615251875Speter
616251875Speter        new_m = apr_palloc(pool, sizeof(apr_shm_t));
617251875Speter
618251875Speter        status = apr_file_open(&file, filename,
619251875Speter                               APR_FOPEN_READ, APR_OS_DEFAULT, pool);
620251875Speter        if (status != APR_SUCCESS) {
621251875Speter            return status;
622251875Speter        }
623251875Speter
624251875Speter        nbytes = sizeof(new_m->reqsize);
625251875Speter        status = apr_file_read(file, (void *)&(new_m->reqsize),
626251875Speter                               &nbytes);
627251875Speter        if (status != APR_SUCCESS) {
628251875Speter            return status;
629251875Speter        }
630251875Speter        status = apr_file_close(file);
631251875Speter        if (status != APR_SUCCESS) {
632251875Speter            return status;
633251875Speter        }
634251875Speter
635251875Speter        new_m->filename = apr_pstrdup(pool, filename);
636251875Speter        new_m->pool = pool;
637269847Speter        shmkey = our_ftok(filename);
638251875Speter        if (shmkey == (key_t)-1) {
639251875Speter            return errno;
640251875Speter        }
641251875Speter        if ((new_m->shmid = shmget(shmkey, 0, SHM_R | SHM_W)) == -1) {
642251875Speter            return errno;
643251875Speter        }
644251875Speter        if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
645251875Speter            return errno;
646251875Speter        }
647251875Speter        new_m->usable = new_m->base;
648251875Speter        new_m->realsize = new_m->reqsize;
649251875Speter
650251875Speter        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
651251875Speter                                  apr_pool_cleanup_null);
652251875Speter        *m = new_m;
653251875Speter        return APR_SUCCESS;
654251875Speter
655251875Speter#else
656251875Speter        return APR_ENOTIMPL;
657251875Speter#endif
658251875Speter    }
659251875Speter}
660251875Speter
661269847SpeterAPR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m,
662269847Speter                                            const char *filename,
663269847Speter                                            apr_pool_t *pool,
664269847Speter                                            apr_int32_t flags)
665269847Speter{
666269847Speter    return apr_shm_attach(m, filename, pool);
667269847Speter}
668269847Speter
669251875SpeterAPR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m)
670251875Speter{
671251875Speter    apr_status_t rv = shm_cleanup_attach(m);
672251875Speter    apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach);
673251875Speter    return rv;
674251875Speter}
675251875Speter
676251875SpeterAPR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m)
677251875Speter{
678251875Speter    return m->usable;
679251875Speter}
680251875Speter
681251875SpeterAPR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m)
682251875Speter{
683251875Speter    return m->reqsize;
684251875Speter}
685251875Speter
686251875SpeterAPR_POOL_IMPLEMENT_ACCESSOR(shm)
687251875Speter
688251875SpeterAPR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm,
689251875Speter                                         apr_shm_t *shm)
690251875Speter{
691251875Speter    return APR_ENOTIMPL;
692251875Speter}
693251875Speter
694251875SpeterAPR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m,
695251875Speter                                         apr_os_shm_t *osshm,
696251875Speter                                         apr_pool_t *pool)
697251875Speter{
698251875Speter    return APR_ENOTIMPL;
699251875Speter}
700251875Speter
701