From ef8de4644e03ec6b88f83a8c44f311793e63e7ab Mon Sep 17 00:00:00 2001 From: Alex Rousskov Date: Wed, 26 Oct 2011 10:33:46 -0600 Subject: [PATCH] Name shared memory segments in a more portable way to make shm_open() work on FreeBSD and some other OSes. Linux and friends use "/slashless-name" template for shared memory segment IDs. HPUX and friends use "/full/path/to/some/file". FreeBSD uses the former or the latter, depending on version and jail context. We now distinguish the above cases and prefix the internal segment ID accordingly. The above analysis and its implementation are based on the boost::interprocess code. To make matters worse, the right prefix for path-based OSes depends on whether we are running an [installed] Squid binary or just a "make check" test case. For test cases, we cannot use PREFIX-based paths because they may not exist. Instead, we use the current directory. This is consistent with TESTDIR (i.e., cache_dir location) which each fs test case defines to be in the current directory. Finally, the segment name may clash with cache_dir name on path-based OSes. We now append ".shm" to the segment name to reduce the likelihood of a collision. TODO: Should StoreMap/etc (or their creators) append "map"/etc to their IDs? --- CREDITS | 33 +++++++++++++++++++++++++++++++++ compat/Makefile.am | 1 + compat/shm.cc | 28 ++++++++++++++++++++++++++++ compat/shm.h | 4 ++++ src/ipc/mem/Segment.cc | 15 +++++++++++++-- src/ipc/mem/Segment.h | 2 ++ src/tests/testRock.cc | 3 +++ 7 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 compat/shm.cc diff --git a/CREDITS b/CREDITS index e6c4887db1..b115ff1a0b 100644 --- a/CREDITS +++ b/CREDITS @@ -570,3 +570,36 @@ icons/silk/: documentation for the software which includes the set or a subset of the icons contained within. +============================================================================== + +shm_portable_segment_name_is_path() implementation: + + Derived from boost/interprocess/shared_memory_object.hpp and + boost/interprocess/detail/workaround.hpp at http://www.boost.org/ + + (C) Copyright Ion Gaztanaga 2005-2009. + Distributed under the Boost Software License, Version 1.0 + + Boost Software License - Version 1.0 - August 17th, 2003 + + Permission is hereby granted, free of charge, to any person or organization + obtaining a copy of the software and accompanying documentation covered by + this license (the "Software") to use, reproduce, display, distribute, + execute, and transmit the Software, and to prepare derivative works of the + Software, and to permit third-parties to whom the Software is furnished to + do so, all subject to the following: + + The copyright notices in the Software and this entire statement, including + the above license grant, this restriction and the following disclaimer, + must be included in all copies of the Software, in whole or in part, and + all derivative works of the Software, unless such copies or derivative + works are solely in the form of machine-executable object code generated by + a source language processor. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. diff --git a/compat/Makefile.am b/compat/Makefile.am index 8667bb0c65..7b3f7b8cfc 100644 --- a/compat/Makefile.am +++ b/compat/Makefile.am @@ -32,6 +32,7 @@ libcompat_squid_a_SOURCES = \ initgroups.h \ osdetect.h \ psignal.h \ + shm.cc \ shm.h \ stdio.h \ stdvarargs.h \ diff --git a/compat/shm.cc b/compat/shm.cc new file mode 100644 index 0000000000..431df0a1a9 --- /dev/null +++ b/compat/shm.cc @@ -0,0 +1,28 @@ +#include "config.h" +#include "compat/shm.h" + +#if defined(__FreeBSD__) && (__FreeBSD__ >= 7) +# include +#endif + + +/* + * Some systems have filesystem-based resources and interpret segment names + * as file paths. The so-called 'portable' "/name" format does not work well + * for them. And, according to Boost::interprocess, recent FreeBSD versions + * make this decision depending on whether the shm_open() caller is jailed! + */ +bool +shm_portable_segment_name_is_path() +{ +#if defined(_SQUID_HPUX_) || defined(_SQUID_OSF_) || defined(__vms) || (defined(_SQUID_FREEBSD_) && (__FreeBSD__ < 7)) + return true; +#elif defined(_SQUID_FREEBSD_) + int jailed = 0; + size_t len = sizeof(jailed); + ::sysctlbyname("security.jail.jailed", &jailed, &len, NULL, 0); + return !jailed; +#else + return false; +#endif +} diff --git a/compat/shm.h b/compat/shm.h index c9135d5969..873a44c40d 100644 --- a/compat/shm.h +++ b/compat/shm.h @@ -42,4 +42,8 @@ extern "C" { #endif /* HAVE_SHM */ + +/// Determines whether segment names are iterpreted as full file paths. +bool shm_portable_segment_name_is_path(); + #endif /* SQUID_COMPAT_CPU_H */ diff --git a/src/ipc/mem/Segment.cc b/src/ipc/mem/Segment.cc index 00b4f61a94..c9bee080ff 100644 --- a/src/ipc/mem/Segment.cc +++ b/src/ipc/mem/Segment.cc @@ -16,6 +16,10 @@ #include #include + +// test cases change this +const char *Ipc::Mem::Segment::BasePath = DEFAULT_STATEDIR; + void * Ipc::Mem::Segment::reserve(size_t chunkSize) { @@ -169,11 +173,16 @@ Ipc::Mem::Segment::statSize(const char *context) const return s.st_size; } -/// Generate name for shared memory segment. Replaces all slashes with dots. +/// Generate name for shared memory segment. Starts with a prefix required +/// for cross-platform portability and replaces all slashes in ID with dots. String Ipc::Mem::Segment::GenerateName(const char *id) { - String name("/squid-"); + assert(BasePath); + static const bool nameIsPath = shm_portable_segment_name_is_path(); + String name(nameIsPath ? BasePath : "/squid-"); + + // append id, replacing slashes with dots for (const char *slash = strchr(id, '/'); slash; slash = strchr(id, '/')) { if (id != slash) { name.append(id, slash - id); @@ -182,6 +191,8 @@ Ipc::Mem::Segment::GenerateName(const char *id) id = slash + 1; } name.append(id); + + name.append(".shm"); // to distinguish from non-segments when nameIsPath return name; } diff --git a/src/ipc/mem/Segment.h b/src/ipc/mem/Segment.h index 28966f298f..b8e36f04b1 100644 --- a/src/ipc/mem/Segment.h +++ b/src/ipc/mem/Segment.h @@ -35,6 +35,8 @@ public: void *mem() { return reserve(0); } ///< pointer to the next chunk void *reserve(size_t chunkSize); ///< reserve and return the next chunk + /// common path of all segment names in path-based environments + static const char *BasePath; private: diff --git a/src/tests/testRock.cc b/src/tests/testRock.cc index e8f62b1c0a..600fe828dc 100644 --- a/src/tests/testRock.cc +++ b/src/tests/testRock.cc @@ -40,6 +40,9 @@ testRock::setUp() if (0 > system ("rm -rf " TESTDIR)) throw std::runtime_error("Failed to clean test work directory"); + // use current directory for shared segments (on path-based OSes) + Ipc::Mem::Segment::BasePath = ""; + Store::Root(new StoreController); store = new Rock::SwapDir(); -- 2.47.2