Coverage Report

Created: 2025-07-11 06:40

/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
        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
        status = apr_file_open(&file, filename,
291
                               APR_FOPEN_READ | APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL,
292
                               APR_FPROT_UREAD | APR_FPROT_UWRITE, pool);
293
        if (status != APR_SUCCESS) {
294
            return status;
295
        }
296
297
        status = apr_os_file_get(&tmpfd, file);
298
        if (status != APR_SUCCESS) {
299
            apr_file_close(file); /* ignore errors, we're failing */
300
            apr_file_remove(new_m->filename, new_m->pool);
301
            return status;
302
        }
303
304
        status = apr_file_trunc(file, new_m->realsize);
305
        if (status != APR_SUCCESS && status != APR_ESPIPE) {
306
            apr_file_close(file); /* ignore errors, we're failing */
307
            apr_file_remove(new_m->filename, new_m->pool);
308
            return status;
309
        }
310
311
        new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
312
                           MAP_SHARED, tmpfd, 0);
313
        /* FIXME: check for errors */
314
315
        status = apr_file_close(file);
316
        if (status != APR_SUCCESS) {
317
            return status;
318
        }
319
#endif /* APR_USE_SHMEM_MMAP_TMP */
320
0
#if APR_USE_SHMEM_MMAP_SHM
321
0
        tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0600);
322
0
        if (tmpfd == -1) {
323
0
            return errno;
324
0
        }
325
326
        /* Note that apr_file_trunc() also calls lseek() so wrapping
327
         * the fd into an apr_file_t and doing this indirectly is
328
         * undesirable, see PR 66435. */
329
0
        status = ftruncate(tmpfd, new_m->realsize) < 0 ? errno : APR_SUCCESS;
330
0
        if (status != APR_SUCCESS && status != APR_ESPIPE) {
331
0
            shm_unlink(shm_name); /* we're failing, remove the object */
332
0
            close(tmpfd);
333
0
            return status;
334
0
        }
335
0
        new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
336
0
                           MAP_SHARED, tmpfd, 0);
337
0
        status = (new_m->base == (void *)-1) ? errno : APR_SUCCESS;
338
        /* fd no longer needed once the memory is mapped. */
339
0
        close(tmpfd);
340
0
        if (status) {
341
0
            shm_unlink(shm_name);
342
0
            return status;
343
0
        }
344
0
#endif /* APR_USE_SHMEM_MMAP_SHM */
345
346
        /* store the real size in the metadata */
347
0
        *(apr_size_t*)(new_m->base) = new_m->realsize;
348
        /* metadata isn't usable */
349
0
        new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
350
351
0
        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
352
0
                                  apr_pool_cleanup_null);
353
0
        *m = new_m;
354
0
        return APR_SUCCESS;
355
356
#elif APR_USE_SHMEM_SHMGET
357
        new_m->realsize = reqsize;
358
359
        status = apr_file_open(&file, filename,
360
                               APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL,
361
                               APR_FPROT_UREAD | APR_FPROT_UWRITE, pool);
362
        if (status != APR_SUCCESS) {
363
            return status;
364
        }
365
366
        /* ftok() (on solaris at least) requires that the file actually
367
         * exist before calling ftok(). */
368
        new_m->shmkey = our_ftok(filename);
369
        if (new_m->shmkey == (key_t)-1) {
370
            apr_file_close(file);
371
            return errno;
372
        }
373
374
        if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize,
375
                                   SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) {
376
            apr_file_close(file);
377
            return errno;
378
        }
379
380
        if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
381
            apr_file_close(file);
382
            return errno;
383
        }
384
        new_m->usable = new_m->base;
385
386
        if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) {
387
            apr_file_close(file);
388
            return errno;
389
        }
390
        apr_uid_current(&uid, &gid, pool);
391
        shmbuf.shm_perm.uid = uid;
392
        shmbuf.shm_perm.gid = gid;
393
        if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) {
394
            apr_file_close(file);
395
            return errno;
396
        }
397
398
        nbytes = sizeof(reqsize);
399
        status = apr_file_write(file, (const void *)&reqsize,
400
                                &nbytes);
401
        if (status != APR_SUCCESS) {
402
            apr_file_close(file);
403
            return status;
404
        }
405
        status = apr_file_close(file);
406
        if (status != APR_SUCCESS) {
407
            return status;
408
        }
409
410
        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner,
411
                                  apr_pool_cleanup_null);
412
        *m = new_m;
413
        return APR_SUCCESS;
414
415
#else
416
        return APR_ENOTIMPL;
417
#endif
418
0
    }
419
0
}
420
421
APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m,
422
                                            apr_size_t reqsize,
423
                                            const char *filename,
424
                                            apr_pool_t *p,
425
                                            apr_int32_t flags)
426
0
{
427
0
    return apr_shm_create(m, reqsize, filename, p);
428
0
}
429
430
APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename,
431
                                         apr_pool_t *pool)
432
0
{
433
#if APR_USE_SHMEM_SHMGET
434
    apr_status_t status;
435
    apr_file_t *file;
436
    key_t shmkey;
437
    int shmid;
438
#endif
439
440
#if APR_USE_SHMEM_MMAP_TMP
441
    return apr_file_remove(filename, pool);
442
#elif APR_USE_SHMEM_MMAP_SHM
443
    const char *shm_name = make_shm_open_safe_name(filename, pool);
444
0
    if (shm_unlink(shm_name) == -1) {
445
0
        return errno;
446
0
    }
447
0
    return APR_SUCCESS;
448
#elif APR_USE_SHMEM_SHMGET
449
    /* Presume that the file already exists; just open for writing */
450
    status = apr_file_open(&file, filename, APR_FOPEN_WRITE,
451
                           APR_FPROT_OS_DEFAULT, pool);
452
    if (status) {
453
        return status;
454
    }
455
456
    /* ftok() (on solaris at least) requires that the file actually
457
     * exist before calling ftok(). */
458
    shmkey = our_ftok(filename);
459
    if (shmkey == (key_t)-1) {
460
        goto shm_remove_failed;
461
    }
462
463
    apr_file_close(file);
464
465
    if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) {
466
        goto shm_remove_failed;
467
    }
468
469
    /* Indicate that the segment is to be destroyed as soon
470
     * as all processes have detached. This also disallows any
471
     * new attachments to the segment. */
472
    if (shmctl(shmid, IPC_RMID, NULL) == -1) {
473
        goto shm_remove_failed;
474
    }
475
    return apr_file_remove(filename, pool);
476
477
shm_remove_failed:
478
    status = errno;
479
    /* ensure the file has been removed anyway. */
480
    apr_file_remove(filename, pool);
481
    return status;
482
#else
483
484
    /* No support for anonymous shm */
485
    return APR_ENOTIMPL;
486
#endif
487
0
}
488
489
APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m)
490
0
{
491
0
    if (m->filename) {
492
0
        return apr_shm_remove(m->filename, m->pool);
493
0
    }
494
0
    else {
495
0
        return APR_ENOTIMPL;
496
0
    }
497
0
}
498
499
APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m)
500
0
{
501
0
    return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner);
502
0
}
503
504
static apr_status_t shm_cleanup_attach(void *m_)
505
0
{
506
0
    apr_shm_t *m = (apr_shm_t *)m_;
507
508
0
    if (m->filename == NULL) {
509
        /* It doesn't make sense to detach from an anonymous memory segment. */
510
0
        return APR_EINVAL;
511
0
    }
512
0
    else {
513
0
#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
514
0
        if (munmap(m->base, m->realsize) == -1) {
515
0
            return errno;
516
0
        }
517
0
        return APR_SUCCESS;
518
#elif APR_USE_SHMEM_SHMGET
519
        if (shmdt(m->base) == -1) {
520
            return errno;
521
        }
522
        return APR_SUCCESS;
523
#else
524
        return APR_ENOTIMPL;
525
#endif
526
0
    }
527
0
}
528
529
APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m,
530
                                         const char *filename,
531
                                         apr_pool_t *pool)
532
0
{
533
0
    if (filename == NULL) {
534
        /* It doesn't make sense to attach to a segment if you don't know
535
         * the filename. */
536
0
        return APR_EINVAL;
537
0
    }
538
0
    else {
539
0
#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM
540
0
        apr_shm_t *new_m;
541
0
        apr_status_t status;
542
0
        int tmpfd;
543
0
        apr_file_t *file;   /* file where metadata is stored */
544
0
        apr_size_t nbytes;
545
546
0
        new_m = apr_palloc(pool, sizeof(apr_shm_t));
547
0
        new_m->pool = pool;
548
0
        new_m->filename = apr_pstrdup(pool, filename);
549
0
#if APR_USE_SHMEM_MMAP_SHM
550
0
        const char *shm_name = make_shm_open_safe_name(filename, pool);
551
552
0
        tmpfd = shm_open(shm_name, O_RDWR, 0600);
553
0
        if (tmpfd == -1) {
554
0
            return errno;
555
0
        }
556
557
0
        status = apr_os_file_put(&file, &tmpfd,
558
0
                                 APR_READ | APR_WRITE,
559
0
                                 pool);
560
0
        if (status != APR_SUCCESS) {
561
0
            return status;
562
0
        }
563
564
#elif APR_USE_SHMEM_MMAP_TMP
565
        status = apr_file_open(&file, filename,
566
                               APR_FOPEN_READ | APR_FOPEN_WRITE,
567
                               APR_FPROT_OS_DEFAULT, pool);
568
        if (status != APR_SUCCESS) {
569
            return status;
570
        }
571
        status = apr_os_file_get(&tmpfd, file);
572
        if (status != APR_SUCCESS) {
573
            return status;
574
        }
575
#else
576
        return APR_ENOTIMPL;
577
#endif
578
579
0
        nbytes = sizeof(new_m->realsize);
580
0
        status = apr_file_read(file, (void *)&(new_m->realsize),
581
0
                               &nbytes);
582
0
        if (status != APR_SUCCESS) {
583
0
            return status;
584
0
        }
585
586
0
        status = apr_os_file_get(&tmpfd, file);
587
0
        if (status != APR_SUCCESS) {
588
0
            apr_file_close(file); /* ignore errors, we're failing */
589
0
            apr_file_remove(new_m->filename, new_m->pool);
590
0
            return status;
591
0
        }
592
593
0
        new_m->reqsize = new_m->realsize - sizeof(apr_size_t);
594
595
0
        new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE,
596
0
                           MAP_SHARED, tmpfd, 0);
597
        /* FIXME: check for errors */
598
599
0
        status = apr_file_close(file);
600
0
        if (status != APR_SUCCESS) {
601
0
            return status;
602
0
        }
603
604
        /* metadata isn't part of the usable segment */
605
0
        new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t));
606
607
0
        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
608
0
                                  apr_pool_cleanup_null);
609
0
        *m = new_m;
610
0
        return APR_SUCCESS;
611
612
#elif APR_USE_SHMEM_SHMGET
613
        apr_shm_t *new_m;
614
        apr_status_t status;
615
        apr_file_t *file;   /* file where metadata is stored */
616
        apr_size_t nbytes;
617
618
        new_m = apr_palloc(pool, sizeof(apr_shm_t));
619
620
        status = apr_file_open(&file, filename,
621
                               APR_FOPEN_READ, APR_FPROT_OS_DEFAULT, pool);
622
        if (status != APR_SUCCESS) {
623
            return status;
624
        }
625
626
        nbytes = sizeof(new_m->reqsize);
627
        status = apr_file_read(file, (void *)&(new_m->reqsize),
628
                               &nbytes);
629
        if (status != APR_SUCCESS) {
630
            return status;
631
        }
632
        status = apr_file_close(file);
633
        if (status != APR_SUCCESS) {
634
            return status;
635
        }
636
637
        new_m->filename = apr_pstrdup(pool, filename);
638
        new_m->pool = pool;
639
        new_m->shmkey = our_ftok(filename);
640
        if (new_m->shmkey == (key_t)-1) {
641
            return errno;
642
        }
643
        if ((new_m->shmid = shmget(new_m->shmkey, 0, SHM_R | SHM_W)) == -1) {
644
            return errno;
645
        }
646
        if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) {
647
            return errno;
648
        }
649
        new_m->usable = new_m->base;
650
        new_m->realsize = new_m->reqsize;
651
652
        apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach,
653
                                  apr_pool_cleanup_null);
654
        *m = new_m;
655
        return APR_SUCCESS;
656
657
#else
658
        return APR_ENOTIMPL;
659
#endif
660
0
    }
661
0
}
662
663
APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m,
664
                                            const char *filename,
665
                                            apr_pool_t *pool,
666
                                            apr_int32_t flags)
667
0
{
668
0
    return apr_shm_attach(m, filename, pool);
669
0
}
670
671
APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m)
672
0
{
673
0
    apr_status_t rv = shm_cleanup_attach(m);
674
0
    apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach);
675
0
    return rv;
676
0
}
677
678
APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m)
679
0
{
680
0
    return m->usable;
681
0
}
682
683
APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m)
684
0
{
685
0
    return m->reqsize;
686
0
}
687
688
APR_PERMS_SET_IMPLEMENT(shm)
689
0
{
690
#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON
691
    struct shmid_ds shmbuf;
692
    int shmid;
693
    apr_shm_t *m = (apr_shm_t *)theshm;
694
695
    if ((shmid = shmget(m->shmkey, 0, SHM_R | SHM_W)) == -1) {
696
        return errno;
697
    }
698
    shmbuf.shm_perm.uid  = uid;
699
    shmbuf.shm_perm.gid  = gid;
700
    shmbuf.shm_perm.mode = apr_unix_perms2mode(perms);
701
    if (shmctl(shmid, IPC_SET, &shmbuf) == -1) {
702
        return errno;
703
    }
704
    return APR_SUCCESS;
705
#elif APR_USE_SHMEM_MMAP_SHM && !defined(DARWIN)
706
    /* ### This hangs or fails on MacOS, so skipping this for the
707
     * ENOTIMPL case there - unclear why or if that's fixable. */
708
0
    apr_shm_t *shm = (apr_shm_t *)theshm;
709
0
    const char *shm_name;
710
0
    int fd;
711
0
    apr_status_t rv;
712
713
0
    if (!shm->filename)
714
0
        return APR_ENOTIMPL;
715
716
0
    shm_name = make_shm_open_safe_name(shm->filename, shm->pool);
717
718
0
    fd = shm_open(shm_name, O_RDWR, 0);
719
0
    if (fd == -1)
720
0
        return errno;
721
722
0
    if (fchown(fd, uid, gid)) {
723
0
        rv = errno;
724
0
        close(fd);
725
0
        return rv;
726
0
    }
727
728
0
    if (fchmod(fd, apr_unix_perms2mode(perms))) {
729
0
        rv = errno;
730
0
        close(fd);
731
0
        return rv;
732
0
    }
733
0
    close(fd);
734
0
    return APR_SUCCESS;
735
#elif APR_USE_SHMEM_MMAP_TMP
736
    apr_shm_t *shm = (apr_shm_t *)theshm;
737
738
    if (!shm->filename)
739
        return APR_ENOTIMPL;
740
741
    if (chown(shm->filename, uid, gid))
742
        return errno;
743
744
    if (chmod(shm->filename, apr_unix_perms2mode(perms)))
745
        return errno;
746
747
    return APR_SUCCESS;
748
#else
749
    return APR_ENOTIMPL;
750
#endif
751
0
}
752
753
APR_POOL_IMPLEMENT_ACCESSOR(shm)
754
755
APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm,
756
                                         apr_shm_t *shm)
757
0
{
758
0
    return APR_ENOTIMPL;
759
0
}
760
761
APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m,
762
                                         apr_os_shm_t *osshm,
763
                                         apr_pool_t *pool)
764
0
{
765
0
    return APR_ENOTIMPL;
766
0
}
767