1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "apr_arch_shm.h" 18#include "apr_arch_file_io.h" 19 20#include "apr_general.h" 21#include "apr_errno.h" 22#include "apr_user.h" 23#include "apr_strings.h" 24#include "apr_hash.h" 25 26#if APR_USE_SHMEM_MMAP_SHM 27/* 28 * For portable use, a shared memory object should be identified by a name of 29 * the form /somename; that is, a null-terminated string of up to NAME_MAX 30 * (i.e., 255) characters consisting of an initial slash, followed by one or 31 * more characters, none of which are slashes. 32 */ 33#ifndef NAME_MAX 34#define NAME_MAX 255 35#endif 36 37/* See proc_mutex.c and sem_open for the reason for all this! */ 38static unsigned int rshash (const char *p) { 39 /* hash function from Robert Sedgwicks 'Algorithms in C' book */ 40 unsigned int b = 378551; 41 unsigned int a = 63689; 42 unsigned int retval = 0; 43 44 for( ; *p; p++) { 45 retval = retval * a + (*p); 46 a *= b; 47 } 48 49 return retval; 50} 51 52static const char *make_shm_open_safe_name(const char *filename, 53 apr_pool_t *pool) 54{ 55 apr_ssize_t flen; 56 unsigned int h1, h2; 57 58 if (filename == NULL) { 59 return NULL; 60 } 61 62 flen = strlen(filename); 63 h1 = (apr_hashfunc_default(filename, &flen) & 0xffffffff); 64 h2 = (rshash(filename) & 0xffffffff); 65 return apr_psprintf(pool, "/ShM.%xH%x", h1, h2); 66 67} 68#endif 69 70#if APR_USE_SHMEM_SHMGET 71static key_t our_ftok(const char *filename) 72{ 73 /* to help avoid collisions while still using 74 * an easily recreated proj_id */ 75 apr_ssize_t slen = strlen(filename); 76 return ftok(filename, 77 (int)apr_hashfunc_default(filename, &slen)); 78} 79#endif 80 81static apr_status_t shm_cleanup_owner(void *m_) 82{ 83 apr_shm_t *m = (apr_shm_t *)m_; 84 85 /* anonymous shared memory */ 86 if (m->filename == NULL) { 87#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON 88 if (munmap(m->base, m->realsize) == -1) { 89 return errno; 90 } 91 return APR_SUCCESS; 92#elif APR_USE_SHMEM_SHMGET_ANON 93 if (shmdt(m->base) == -1) { 94 return errno; 95 } 96 /* This segment will automatically remove itself after all 97 * references have detached. */ 98 return APR_SUCCESS; 99#endif 100 } 101 102 /* name-based shared memory */ 103 else { 104#if APR_USE_SHMEM_MMAP_TMP 105 if (munmap(m->base, m->realsize) == -1) { 106 return errno; 107 } 108 if (access(m->filename, F_OK)) { 109 return APR_SUCCESS; 110 } 111 else { 112 return apr_file_remove(m->filename, m->pool); 113 } 114#elif APR_USE_SHMEM_MMAP_SHM 115 if (munmap(m->base, m->realsize) == -1) { 116 return errno; 117 } 118 if (shm_unlink(make_shm_open_safe_name(m->filename, m->pool)) == -1 && errno != ENOENT) { 119 return errno; 120 } 121 return APR_SUCCESS; 122#elif APR_USE_SHMEM_SHMGET 123 /* Indicate that the segment is to be destroyed as soon 124 * as all processes have detached. This also disallows any 125 * new attachments to the segment. */ 126 if (shmctl(m->shmid, IPC_RMID, NULL) == -1 && errno != EINVAL) { 127 return errno; 128 } 129 if (shmdt(m->base) == -1) { 130 return errno; 131 } 132 if (access(m->filename, F_OK)) { 133 return APR_SUCCESS; 134 } 135 else { 136 return apr_file_remove(m->filename, m->pool); 137 } 138#else 139 return APR_ENOTIMPL; 140#endif 141 } 142} 143 144APR_DECLARE(apr_status_t) apr_shm_create(apr_shm_t **m, 145 apr_size_t reqsize, 146 const char *filename, 147 apr_pool_t *pool) 148{ 149 apr_shm_t *new_m; 150 apr_status_t status; 151#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON 152 struct shmid_ds shmbuf; 153 apr_uid_t uid; 154 apr_gid_t gid; 155#endif 156#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM || \ 157 APR_USE_SHMEM_MMAP_ZERO 158 int tmpfd; 159#endif 160#if APR_USE_SHMEM_SHMGET 161 apr_size_t nbytes; 162#endif 163#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_SHMGET || \ 164 APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM 165 apr_file_t *file; /* file where metadata is stored */ 166#endif 167 168 /* Check if they want anonymous or name-based shared memory */ 169 if (filename == NULL) { 170#if APR_USE_SHMEM_MMAP_ZERO || APR_USE_SHMEM_MMAP_ANON 171 new_m = apr_palloc(pool, sizeof(apr_shm_t)); 172 new_m->pool = pool; 173 new_m->reqsize = reqsize; 174 new_m->realsize = reqsize + 175 APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ 176 new_m->filename = NULL; 177 178#if APR_USE_SHMEM_MMAP_ZERO 179 status = apr_file_open(&file, "/dev/zero", APR_READ | APR_WRITE, 180 APR_OS_DEFAULT, pool); 181 if (status != APR_SUCCESS) { 182 return status; 183 } 184 status = apr_os_file_get(&tmpfd, file); 185 if (status != APR_SUCCESS) { 186 return status; 187 } 188 189 new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, 190 MAP_SHARED, tmpfd, 0); 191 if (new_m->base == (void *)MAP_FAILED) { 192 return errno; 193 } 194 195 status = apr_file_close(file); 196 if (status != APR_SUCCESS) { 197 return status; 198 } 199 200 /* store the real size in the metadata */ 201 *(apr_size_t*)(new_m->base) = new_m->realsize; 202 /* metadata isn't usable */ 203 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); 204 205 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, 206 apr_pool_cleanup_null); 207 *m = new_m; 208 return APR_SUCCESS; 209 210#elif APR_USE_SHMEM_MMAP_ANON 211 new_m->base = mmap(NULL, new_m->realsize, PROT_READ|PROT_WRITE, 212 MAP_ANON|MAP_SHARED, -1, 0); 213 if (new_m->base == (void *)MAP_FAILED) { 214 return errno; 215 } 216 217 /* store the real size in the metadata */ 218 *(apr_size_t*)(new_m->base) = new_m->realsize; 219 /* metadata isn't usable */ 220 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); 221 222 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, 223 apr_pool_cleanup_null); 224 *m = new_m; 225 return APR_SUCCESS; 226 227#endif /* APR_USE_SHMEM_MMAP_ZERO */ 228#elif APR_USE_SHMEM_SHMGET_ANON 229 new_m = apr_palloc(pool, sizeof(apr_shm_t)); 230 new_m->pool = pool; 231 new_m->reqsize = reqsize; 232 new_m->realsize = reqsize; 233 new_m->filename = NULL; 234 new_m->shmkey = IPC_PRIVATE; 235 if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, 236 SHM_R | SHM_W | IPC_CREAT)) < 0) { 237 return errno; 238 } 239 240 if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { 241 return errno; 242 } 243 new_m->usable = new_m->base; 244 245 if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { 246 return errno; 247 } 248 apr_uid_current(&uid, &gid, pool); 249 shmbuf.shm_perm.uid = uid; 250 shmbuf.shm_perm.gid = gid; 251 if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { 252 return errno; 253 } 254 255 /* Remove the segment once use count hits zero. 256 * We will not attach to this segment again, since it is 257 * anonymous memory, so it is ok to mark it for deletion. 258 */ 259 if (shmctl(new_m->shmid, IPC_RMID, NULL) == -1) { 260 return errno; 261 } 262 263 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, 264 apr_pool_cleanup_null); 265 *m = new_m; 266 return APR_SUCCESS; 267#else 268 /* It is an error if they want anonymous memory but we don't have it. */ 269 return APR_ENOTIMPL; /* requested anonymous but we don't have it */ 270#endif 271 } 272 273 /* Name-based shared memory */ 274 else { 275 new_m = apr_palloc(pool, sizeof(apr_shm_t)); 276 new_m->pool = pool; 277 new_m->reqsize = reqsize; 278 new_m->filename = apr_pstrdup(pool, filename); 279#if APR_USE_SHMEM_MMAP_SHM 280 const char *shm_name = make_shm_open_safe_name(filename, pool); 281#endif 282#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM 283 new_m->realsize = reqsize + 284 APR_ALIGN_DEFAULT(sizeof(apr_size_t)); /* room for metadata */ 285 /* FIXME: Ignore error for now. * 286 * status = apr_file_remove(file, pool);*/ 287 status = APR_SUCCESS; 288 289#if APR_USE_SHMEM_MMAP_TMP 290 /* FIXME: Is APR_OS_DEFAULT sufficient? */ 291 status = apr_file_open(&file, filename, 292 APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, 293 APR_OS_DEFAULT, pool); 294 if (status != APR_SUCCESS) { 295 return status; 296 } 297 298 status = apr_os_file_get(&tmpfd, file); 299 if (status != APR_SUCCESS) { 300 apr_file_close(file); /* ignore errors, we're failing */ 301 apr_file_remove(new_m->filename, new_m->pool); 302 return status; 303 } 304 305 status = apr_file_trunc(file, new_m->realsize); 306 if (status != APR_SUCCESS && status != APR_ESPIPE) { 307 apr_file_close(file); /* ignore errors, we're failing */ 308 apr_file_remove(new_m->filename, new_m->pool); 309 return status; 310 } 311 312 new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, 313 MAP_SHARED, tmpfd, 0); 314 /* FIXME: check for errors */ 315 316 status = apr_file_close(file); 317 if (status != APR_SUCCESS) { 318 return status; 319 } 320#endif /* APR_USE_SHMEM_MMAP_TMP */ 321#if APR_USE_SHMEM_MMAP_SHM 322 /* FIXME: SysV uses 0600... should we? */ 323 tmpfd = shm_open(shm_name, O_RDWR | O_CREAT | O_EXCL, 0644); 324 if (tmpfd == -1) { 325 return errno; 326 } 327 328 status = apr_os_file_put(&file, &tmpfd, 329 APR_READ | APR_WRITE | APR_CREATE | APR_EXCL, 330 pool); 331 if (status != APR_SUCCESS) { 332 return status; 333 } 334 335 status = apr_file_trunc(file, new_m->realsize); 336 if (status != APR_SUCCESS && status != APR_ESPIPE) { 337 shm_unlink(shm_name); /* we're failing, remove the object */ 338 return status; 339 } 340 new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, 341 MAP_SHARED, tmpfd, 0); 342 343 /* FIXME: check for errors */ 344 345 status = apr_file_close(file); 346 if (status != APR_SUCCESS) { 347 return status; 348 } 349#endif /* APR_USE_SHMEM_MMAP_SHM */ 350 351 /* store the real size in the metadata */ 352 *(apr_size_t*)(new_m->base) = new_m->realsize; 353 /* metadata isn't usable */ 354 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); 355 356 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, 357 apr_pool_cleanup_null); 358 *m = new_m; 359 return APR_SUCCESS; 360 361#elif APR_USE_SHMEM_SHMGET 362 new_m->realsize = reqsize; 363 364 /* FIXME: APR_OS_DEFAULT is too permissive, switch to 600 I think. */ 365 status = apr_file_open(&file, filename, 366 APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_EXCL, 367 APR_OS_DEFAULT, pool); 368 if (status != APR_SUCCESS) { 369 return status; 370 } 371 372 /* ftok() (on solaris at least) requires that the file actually 373 * exist before calling ftok(). */ 374 new_m->shmkey = our_ftok(filename); 375 if (new_m->shmkey == (key_t)-1) { 376 apr_file_close(file); 377 return errno; 378 } 379 380 if ((new_m->shmid = shmget(new_m->shmkey, new_m->realsize, 381 SHM_R | SHM_W | IPC_CREAT | IPC_EXCL)) < 0) { 382 apr_file_close(file); 383 return errno; 384 } 385 386 if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { 387 apr_file_close(file); 388 return errno; 389 } 390 new_m->usable = new_m->base; 391 392 if (shmctl(new_m->shmid, IPC_STAT, &shmbuf) == -1) { 393 apr_file_close(file); 394 return errno; 395 } 396 apr_uid_current(&uid, &gid, pool); 397 shmbuf.shm_perm.uid = uid; 398 shmbuf.shm_perm.gid = gid; 399 if (shmctl(new_m->shmid, IPC_SET, &shmbuf) == -1) { 400 apr_file_close(file); 401 return errno; 402 } 403 404 nbytes = sizeof(reqsize); 405 status = apr_file_write(file, (const void *)&reqsize, 406 &nbytes); 407 if (status != APR_SUCCESS) { 408 apr_file_close(file); 409 return status; 410 } 411 status = apr_file_close(file); 412 if (status != APR_SUCCESS) { 413 return status; 414 } 415 416 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_owner, 417 apr_pool_cleanup_null); 418 *m = new_m; 419 return APR_SUCCESS; 420 421#else 422 return APR_ENOTIMPL; 423#endif 424 } 425} 426 427APR_DECLARE(apr_status_t) apr_shm_create_ex(apr_shm_t **m, 428 apr_size_t reqsize, 429 const char *filename, 430 apr_pool_t *p, 431 apr_int32_t flags) 432{ 433 return apr_shm_create(m, reqsize, filename, p); 434} 435 436APR_DECLARE(apr_status_t) apr_shm_remove(const char *filename, 437 apr_pool_t *pool) 438{ 439#if APR_USE_SHMEM_SHMGET 440 apr_status_t status; 441 apr_file_t *file; 442 key_t shmkey; 443 int shmid; 444#endif 445 446#if APR_USE_SHMEM_MMAP_TMP 447 return apr_file_remove(filename, pool); 448#elif APR_USE_SHMEM_MMAP_SHM 449 const char *shm_name = make_shm_open_safe_name(filename, pool); 450 if (shm_unlink(shm_name) == -1) { 451 return errno; 452 } 453 return APR_SUCCESS; 454#elif APR_USE_SHMEM_SHMGET 455 /* Presume that the file already exists; just open for writing */ 456 status = apr_file_open(&file, filename, APR_FOPEN_WRITE, 457 APR_OS_DEFAULT, pool); 458 if (status) { 459 return status; 460 } 461 462 /* ftok() (on solaris at least) requires that the file actually 463 * exist before calling ftok(). */ 464 shmkey = our_ftok(filename); 465 if (shmkey == (key_t)-1) { 466 goto shm_remove_failed; 467 } 468 469 apr_file_close(file); 470 471 if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) < 0) { 472 goto shm_remove_failed; 473 } 474 475 /* Indicate that the segment is to be destroyed as soon 476 * as all processes have detached. This also disallows any 477 * new attachments to the segment. */ 478 if (shmctl(shmid, IPC_RMID, NULL) == -1) { 479 goto shm_remove_failed; 480 } 481 return apr_file_remove(filename, pool); 482 483shm_remove_failed: 484 status = errno; 485 /* ensure the file has been removed anyway. */ 486 apr_file_remove(filename, pool); 487 return status; 488#else 489 490 /* No support for anonymous shm */ 491 return APR_ENOTIMPL; 492#endif 493} 494 495APR_DECLARE(apr_status_t) apr_shm_delete(apr_shm_t *m) 496{ 497 if (m->filename) { 498 return apr_shm_remove(m->filename, m->pool); 499 } 500 else { 501 return APR_ENOTIMPL; 502 } 503} 504 505APR_DECLARE(apr_status_t) apr_shm_destroy(apr_shm_t *m) 506{ 507 return apr_pool_cleanup_run(m->pool, m, shm_cleanup_owner); 508} 509 510static apr_status_t shm_cleanup_attach(void *m_) 511{ 512 apr_shm_t *m = (apr_shm_t *)m_; 513 514 if (m->filename == NULL) { 515 /* It doesn't make sense to detach from an anonymous memory segment. */ 516 return APR_EINVAL; 517 } 518 else { 519#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM 520 if (munmap(m->base, m->realsize) == -1) { 521 return errno; 522 } 523 return APR_SUCCESS; 524#elif APR_USE_SHMEM_SHMGET 525 if (shmdt(m->base) == -1) { 526 return errno; 527 } 528 return APR_SUCCESS; 529#else 530 return APR_ENOTIMPL; 531#endif 532 } 533} 534 535APR_DECLARE(apr_status_t) apr_shm_attach(apr_shm_t **m, 536 const char *filename, 537 apr_pool_t *pool) 538{ 539 if (filename == NULL) { 540 /* It doesn't make sense to attach to a segment if you don't know 541 * the filename. */ 542 return APR_EINVAL; 543 } 544 else { 545#if APR_USE_SHMEM_MMAP_TMP || APR_USE_SHMEM_MMAP_SHM 546 apr_shm_t *new_m; 547 apr_status_t status; 548 int tmpfd; 549 apr_file_t *file; /* file where metadata is stored */ 550 apr_size_t nbytes; 551 552 new_m = apr_palloc(pool, sizeof(apr_shm_t)); 553 new_m->pool = pool; 554 new_m->filename = apr_pstrdup(pool, filename); 555#if APR_USE_SHMEM_MMAP_SHM 556 const char *shm_name = make_shm_open_safe_name(filename, pool); 557 558 /* FIXME: SysV uses 0600... should we? */ 559 tmpfd = shm_open(shm_name, O_RDWR, 0644); 560 if (tmpfd == -1) { 561 return errno; 562 } 563 564 status = apr_os_file_put(&file, &tmpfd, 565 APR_READ | APR_WRITE, 566 pool); 567 if (status != APR_SUCCESS) { 568 return status; 569 } 570 571#elif APR_USE_SHMEM_MMAP_TMP 572 status = apr_file_open(&file, filename, 573 APR_READ | APR_WRITE, 574 APR_OS_DEFAULT, pool); 575 if (status != APR_SUCCESS) { 576 return status; 577 } 578 status = apr_os_file_get(&tmpfd, file); 579 if (status != APR_SUCCESS) { 580 return status; 581 } 582#else 583 return APR_ENOTIMPL; 584#endif 585 586 nbytes = sizeof(new_m->realsize); 587 status = apr_file_read(file, (void *)&(new_m->realsize), 588 &nbytes); 589 if (status != APR_SUCCESS) { 590 return status; 591 } 592 593 status = apr_os_file_get(&tmpfd, file); 594 if (status != APR_SUCCESS) { 595 apr_file_close(file); /* ignore errors, we're failing */ 596 apr_file_remove(new_m->filename, new_m->pool); 597 return status; 598 } 599 600 new_m->reqsize = new_m->realsize - sizeof(apr_size_t); 601 602 new_m->base = mmap(NULL, new_m->realsize, PROT_READ | PROT_WRITE, 603 MAP_SHARED, tmpfd, 0); 604 /* FIXME: check for errors */ 605 606 status = apr_file_close(file); 607 if (status != APR_SUCCESS) { 608 return status; 609 } 610 611 /* metadata isn't part of the usable segment */ 612 new_m->usable = (char *)new_m->base + APR_ALIGN_DEFAULT(sizeof(apr_size_t)); 613 614 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, 615 apr_pool_cleanup_null); 616 *m = new_m; 617 return APR_SUCCESS; 618 619#elif APR_USE_SHMEM_SHMGET 620 apr_shm_t *new_m; 621 apr_status_t status; 622 apr_file_t *file; /* file where metadata is stored */ 623 apr_size_t nbytes; 624 625 new_m = apr_palloc(pool, sizeof(apr_shm_t)); 626 627 status = apr_file_open(&file, filename, 628 APR_FOPEN_READ, APR_OS_DEFAULT, pool); 629 if (status != APR_SUCCESS) { 630 return status; 631 } 632 633 nbytes = sizeof(new_m->reqsize); 634 status = apr_file_read(file, (void *)&(new_m->reqsize), 635 &nbytes); 636 if (status != APR_SUCCESS) { 637 return status; 638 } 639 status = apr_file_close(file); 640 if (status != APR_SUCCESS) { 641 return status; 642 } 643 644 new_m->filename = apr_pstrdup(pool, filename); 645 new_m->pool = pool; 646 new_m->shmkey = our_ftok(filename); 647 if (new_m->shmkey == (key_t)-1) { 648 return errno; 649 } 650 if ((new_m->shmid = shmget(new_m->shmkey, 0, SHM_R | SHM_W)) == -1) { 651 return errno; 652 } 653 if ((new_m->base = shmat(new_m->shmid, NULL, 0)) == (void *)-1) { 654 return errno; 655 } 656 new_m->usable = new_m->base; 657 new_m->realsize = new_m->reqsize; 658 659 apr_pool_cleanup_register(new_m->pool, new_m, shm_cleanup_attach, 660 apr_pool_cleanup_null); 661 *m = new_m; 662 return APR_SUCCESS; 663 664#else 665 return APR_ENOTIMPL; 666#endif 667 } 668} 669 670APR_DECLARE(apr_status_t) apr_shm_attach_ex(apr_shm_t **m, 671 const char *filename, 672 apr_pool_t *pool, 673 apr_int32_t flags) 674{ 675 return apr_shm_attach(m, filename, pool); 676} 677 678APR_DECLARE(apr_status_t) apr_shm_detach(apr_shm_t *m) 679{ 680 apr_status_t rv = shm_cleanup_attach(m); 681 apr_pool_cleanup_kill(m->pool, m, shm_cleanup_attach); 682 return rv; 683} 684 685APR_DECLARE(void *) apr_shm_baseaddr_get(const apr_shm_t *m) 686{ 687 return m->usable; 688} 689 690APR_DECLARE(apr_size_t) apr_shm_size_get(const apr_shm_t *m) 691{ 692 return m->reqsize; 693} 694 695APR_PERMS_SET_IMPLEMENT(shm) 696{ 697#if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON 698 struct shmid_ds shmbuf; 699 int shmid; 700 apr_shm_t *m = (apr_shm_t *)theshm; 701 702 if ((shmid = shmget(m->shmkey, 0, SHM_R | SHM_W)) == -1) { 703 return errno; 704 } 705 shmbuf.shm_perm.uid = uid; 706 shmbuf.shm_perm.gid = gid; 707 shmbuf.shm_perm.mode = apr_unix_perms2mode(perms); 708 if (shmctl(shmid, IPC_SET, &shmbuf) == -1) { 709 return errno; 710 } 711 return APR_SUCCESS; 712#else 713 return APR_ENOTIMPL; 714#endif 715} 716 717APR_POOL_IMPLEMENT_ACCESSOR(shm) 718 719APR_DECLARE(apr_status_t) apr_os_shm_get(apr_os_shm_t *osshm, 720 apr_shm_t *shm) 721{ 722 return APR_ENOTIMPL; 723} 724 725APR_DECLARE(apr_status_t) apr_os_shm_put(apr_shm_t **m, 726 apr_os_shm_t *osshm, 727 apr_pool_t *pool) 728{ 729 return APR_ENOTIMPL; 730} 731 732