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