Coverage Report

Created: 2023-03-26 06:28

/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