passenger 5.0.27 → 5.0.28

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +14 -1
  3. data/CONTRIBUTORS +2 -0
  4. data/Rakefile +6 -5
  5. data/build/agent.rb +1 -1
  6. data/build/basics.rb +6 -71
  7. data/build/misc.rb +2 -2
  8. data/build/nginx.rb +18 -1
  9. data/build/packaging.rb +3 -1
  10. data/build/{cplusplus_support.rb → support/cplusplus.rb} +0 -0
  11. data/build/{cxx_dependency_map.rb → support/cxx_dependency_map.rb} +72 -1
  12. data/build/support/general.rb +106 -0
  13. data/dev/ci/run_travis.sh +9 -0
  14. data/dev/vagrant/nginx_rakefile +1 -1
  15. data/src/agent/Core/ApplicationPool/Options.h +4 -0
  16. data/src/agent/Core/Controller/CheckoutSession.cpp +1 -2
  17. data/src/agent/Core/Controller/InitRequest.cpp +1 -0
  18. data/src/agent/Core/SpawningKit/DirectSpawner.h +12 -0
  19. data/src/agent/Core/SpawningKit/SmartSpawner.h +13 -2
  20. data/src/agent/Core/SpawningKit/Spawner.h +35 -0
  21. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +12 -6
  22. data/src/apache2_module/ConfigurationCommands.cpp +7 -0
  23. data/src/apache2_module/ConfigurationFields.hpp +2 -0
  24. data/src/apache2_module/ConfigurationSetters.cpp +34 -0
  25. data/src/apache2_module/CreateDirConfig.cpp +1 -0
  26. data/src/apache2_module/MergeDirConfig.cpp +7 -0
  27. data/src/apache2_module/SetHeaders.cpp +5 -0
  28. data/src/cxx_supportlib/Constants.h +3 -1
  29. data/src/cxx_supportlib/Logging.h +11 -8
  30. data/src/cxx_supportlib/LveLoggingDecorator.h +92 -0
  31. data/src/cxx_supportlib/MemoryKit/mbuf.cpp +51 -16
  32. data/src/cxx_supportlib/MemoryKit/mbuf.h +27 -24
  33. data/src/cxx_supportlib/ServerKit/HttpServer.h +4 -0
  34. data/src/cxx_supportlib/vendor-copy/adhoc_lve.h +304 -0
  35. data/src/nginx_module/Configuration.c +8 -0
  36. data/src/nginx_module/config +26 -12
  37. data/src/ruby_supportlib/phusion_passenger.rb +8 -8
  38. data/src/ruby_supportlib/phusion_passenger/admin_tools/memory_stats.rb +1 -1
  39. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +8 -0
  40. data/src/ruby_supportlib/phusion_passenger/common_library.rb +2 -2
  41. data/src/ruby_supportlib/phusion_passenger/config/about_command.rb +26 -1
  42. data/src/ruby_supportlib/phusion_passenger/config/main.rb +2 -0
  43. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -0
  44. data/src/ruby_supportlib/phusion_passenger/packaging.rb +1 -1
  45. data/src/ruby_supportlib/phusion_passenger/platform_info/cxx_portability.rb +1 -0
  46. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +1 -1
  47. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +2 -1
  48. metadata +7 -4
@@ -339,13 +339,13 @@ void printAppOutput(pid_t pid, const char *channelName, const char *message, uns
339
339
  void setPrintAppOutputAsDebuggingMessages(bool enabled);
340
340
 
341
341
  /** Print a [BUG] error message and abort with a stack trace. */
342
- #define P_BUG(expr) \
342
+ #define P_BUG_WITH_FORMATTER_CODE(varname, code) \
343
343
  do { \
344
344
  TRACE_POINT(); \
345
345
  const char *_exprStr; \
346
- Passenger::FastStringStream<> sstream; \
347
- sstream << expr; \
348
- _exprStr = Passenger::_strdupFastStringStream(sstream); \
346
+ Passenger::FastStringStream<> varname; \
347
+ code \
348
+ _exprStr = Passenger::_strdupFastStringStream(varname); \
349
349
  Passenger::lastAssertionFailure.filename = __FILE__; \
350
350
  Passenger::lastAssertionFailure.line = __LINE__; \
351
351
  Passenger::lastAssertionFailure.function = __PRETTY_FUNCTION__; \
@@ -354,13 +354,13 @@ void setPrintAppOutputAsDebuggingMessages(bool enabled);
354
354
  abort(); \
355
355
  } while (false)
356
356
 
357
- #define P_BUG_UTP(expr) \
357
+ #define P_BUG_UTP_WITH_FORMATTER_CODE(varname, code) \
358
358
  do { \
359
359
  UPDATE_TRACE_POINT(); \
360
360
  const char *_exprStr; \
361
- Passenger::FastStringStream<> sstream; \
362
- sstream << expr; \
363
- _exprStr = Passenger::_strdupFastStringStream(sstream); \
361
+ Passenger::FastStringStream<> varname; \
362
+ code \
363
+ _exprStr = Passenger::_strdupFastStringStream(varname); \
364
364
  Passenger::lastAssertionFailure.filename = __FILE__; \
365
365
  Passenger::lastAssertionFailure.line = __LINE__; \
366
366
  Passenger::lastAssertionFailure.function = __PRETTY_FUNCTION__; \
@@ -369,6 +369,9 @@ void setPrintAppOutputAsDebuggingMessages(bool enabled);
369
369
  abort(); \
370
370
  } while (false)
371
371
 
372
+ #define P_BUG(expr) P_BUG_WITH_FORMATTER_CODE( _sstream , _sstream << expr; )
373
+ #define P_BUG_UTP(expr) P_BUG_UTP_WITH_FORMATTER_CODE( _sstream , _sstream << expr; )
374
+
372
375
  #define P_ASSERT_EQ(value, expected) \
373
376
  do { \
374
377
  if (OXT_UNLIKELY(value != expected)) { \
@@ -0,0 +1,92 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2010-2016 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+ #ifndef _PASSENGER_LVE_LOGGING_DECORATOR_H_
27
+ #define _PASSENGER_LVE_LOGGING_DECORATOR_H_
28
+
29
+ #include <Logging.h>
30
+ #include <adhoc_lve.h>
31
+ #include <string>
32
+ #include <sys/types.h>
33
+ #include <unistd.h>
34
+
35
+ namespace Passenger {
36
+
37
+
38
+ class LveLoggingDecorator {
39
+ public:
40
+ static adhoc_lve::LibLve &lveInitOnce() {
41
+ std::string initOneTimeError;
42
+ adhoc_lve::LibLve &lveLibHandle = adhoc_lve::LveInitSignleton::getInstance(&initOneTimeError);
43
+
44
+ if (!lveLibHandle.is_lve_available()) {
45
+ P_DEBUG("LVE lib is not available");
46
+ } else if (lveLibHandle.is_error()) {
47
+ if (!initOneTimeError.empty())
48
+ P_ERROR("LVE init error: " << initOneTimeError);
49
+ } else {
50
+ P_DEBUG("LVE get instance (or init) success");
51
+ }
52
+
53
+ return lveLibHandle;
54
+ }
55
+
56
+ static void logLveEnter(const adhoc_lve::LveEnter &lveEnter, uid_t uid, uid_t min_uid) {
57
+ if (lveEnter.lveInstance().is_lve_ready() && lveEnter.is_error()) {
58
+ P_ERROR("LVE enter [pid " << ::getpid() << ", uid " << uid
59
+ << ", min_uid " << min_uid
60
+ << "] error: " << lveEnter.error());
61
+ } else if (lveEnter.is_entered()) {
62
+ P_DEBUG("LVE enter [pid " << ::getpid() << ", uid " << uid
63
+ << ", min_uid " << min_uid
64
+ << "] success");
65
+ } else {
66
+ P_DEBUG("LVE not in [pid " << ::getpid() << ", uid " << uid
67
+ << ", min_uid " << min_uid << "]");
68
+ }
69
+ }
70
+
71
+ static void lveExitCallback(bool entered, const std::string &exit_error) {
72
+ if (!entered) {
73
+ return;
74
+ }
75
+
76
+ try {
77
+ bool is_error = !exit_error.empty();
78
+ if (is_error) {
79
+ P_ERROR("LVE exit [pid " << ::getpid() << "] error: " << exit_error);
80
+ } else {
81
+ P_DEBUG("LVE exit [pid " << ::getpid() << "] success");
82
+ }
83
+ } catch(...) {
84
+ // Can be called from adhoc_lve::LveEnter destructor while stack unwinding.
85
+ }
86
+ }
87
+ }; // class LveLoggingDecorator
88
+
89
+
90
+ } // namespace Passenger
91
+
92
+ #endif /* _PASSENGER_LVE_LOGGING_DECORATOR_H_ */
@@ -1,6 +1,7 @@
1
1
  /*
2
2
  * twemproxy - A fast and lightweight proxy for memcached protocol.
3
3
  * Copyright (C) 2011 Twitter, Inc.
4
+ * Copyright (C) 2014-2016 Phusion Holding B.V.
4
5
  *
5
6
  * Licensed under the Apache License, Version 2.0 (the "License");
6
7
  * you may not use this file except in compliance with the License.
@@ -19,15 +20,29 @@
19
20
  #include <cstring>
20
21
  #include <oxt/macros.hpp>
21
22
  #include <oxt/thread.hpp>
22
- #include <cstring>
23
+ #include <oxt/backtrace.hpp>
23
24
  #include <algorithm>
25
+ #include <ostream>
24
26
  #include <MemoryKit/mbuf.h>
27
+ #include <Logging.h>
25
28
 
26
29
  namespace Passenger {
27
30
  namespace MemoryKit {
28
31
 
29
32
  //#define MBUF_DEBUG
30
33
 
34
+ #define ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, expr) \
35
+ do { \
36
+ if (OXT_UNLIKELY(!(expr))) { \
37
+ P_BUG_WITH_FORMATTER_CODE(stream, \
38
+ stream << "Assertion failed: " #expr "\n"; \
39
+ mbuf_block_print(mbuf_block, stream); \
40
+ ); \
41
+ } \
42
+ } while (false)
43
+
44
+ static void mbuf_block_print(struct mbuf_block *mbuf_block, std::ostream &stream);
45
+
31
46
 
32
47
  static void
33
48
  _mbuf_block_mark_as_active(struct mbuf_pool *pool, struct mbuf_block *mbuf_block)
@@ -115,7 +130,7 @@ _mbuf_block_get(struct mbuf_pool *pool)
115
130
  pool->nfree_mbuf_blockq--;
116
131
  STAILQ_REMOVE_HEAD(&pool->free_mbuf_blockq, next);
117
132
 
118
- assert(mbuf_block->magic == MBUF_BLOCK_MAGIC);
133
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->magic == MBUF_BLOCK_MAGIC);
119
134
  _mbuf_block_mark_as_active(pool, mbuf_block);
120
135
  return mbuf_block;
121
136
  }
@@ -143,8 +158,9 @@ mbuf_block_get(struct mbuf_pool *pool)
143
158
  mbuf_block->start = buf;
144
159
  mbuf_block->end = buf + pool->mbuf_block_offset;
145
160
 
146
- assert(mbuf_block->end - mbuf_block->start == (int)pool->mbuf_block_offset);
147
- assert(mbuf_block->start < mbuf_block->end);
161
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block,
162
+ mbuf_block->end - mbuf_block->start == (int) pool->mbuf_block_offset);
163
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->start < mbuf_block->end);
148
164
 
149
165
  #ifdef MBUF_DEBUG
150
166
  printf("[%p] mbuf_block get %p\n", oxt::thread_signature, mbuf_block);
@@ -171,8 +187,10 @@ mbuf_block_new_standalone(struct mbuf_pool *pool, size_t size)
171
187
  mbuf_block->end = buf + size;
172
188
  mbuf_block->offset = block_offset;
173
189
 
174
- assert(mbuf_block->end - mbuf_block->start == (int)size);
175
- assert(mbuf_block->start < mbuf_block->end);
190
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block,
191
+ mbuf_block->end - mbuf_block->start == (int) size);
192
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block,
193
+ mbuf_block->start < mbuf_block->end);
176
194
 
177
195
  #ifdef MBUF_DEBUG
178
196
  printf("[%p] mbuf_block new standalone %p\n", oxt::thread_signature, mbuf_block);
@@ -190,8 +208,8 @@ mbuf_block_free(struct mbuf_block *mbuf_block)
190
208
  printf("[%p] mbuf_block free %p\n", oxt::thread_signature, mbuf_block);
191
209
  #endif
192
210
 
193
- assert(STAILQ_NEXT(mbuf_block, next) == NULL);
194
- assert(mbuf_block->magic == MBUF_BLOCK_MAGIC);
211
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, STAILQ_NEXT(mbuf_block, next) == NULL);
212
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->magic == MBUF_BLOCK_MAGIC);
195
213
 
196
214
  #ifdef MBUF_ENABLE_DEBUGGING
197
215
  TAILQ_REMOVE(&mbuf_block->pool->active_mbuf_blockq, mbuf_block, active_q);
@@ -215,11 +233,11 @@ mbuf_block_put(struct mbuf_block *mbuf_block)
215
233
  printf("[%p] mbuf_block put %p\n", oxt::thread_signature, mbuf_block);
216
234
  #endif
217
235
 
218
- assert(STAILQ_NEXT(mbuf_block, next) == NULL);
219
- assert(mbuf_block->magic == MBUF_BLOCK_MAGIC);
220
- assert(mbuf_block->refcount == 0);
221
- assert(mbuf_block->pool->nactive_mbuf_blockq > 0);
222
- assert(mbuf_block->offset == 0);
236
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, STAILQ_NEXT(mbuf_block, next) == NULL);
237
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->magic == MBUF_BLOCK_MAGIC);
238
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->refcount == 0);
239
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->pool->nactive_mbuf_blockq > 0);
240
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->offset == 0);
223
241
 
224
242
  mbuf_block->refcount = 1;
225
243
  mbuf_block->pool->nfree_mbuf_blockq++;
@@ -312,7 +330,7 @@ mbuf_block_unref(struct mbuf_block *mbuf_block)
312
330
  oxt::thread_signature, mbuf_block,
313
331
  mbuf_block->refcount, mbuf_block->refcount - 1);
314
332
  #endif
315
- assert(mbuf_block->refcount > 0);
333
+ ASSERT_MBUF_BLOCK_PROPERTY(mbuf_block, mbuf_block->refcount > 0);
316
334
  mbuf_block->refcount--;
317
335
  if (mbuf_block->refcount == 0) {
318
336
  if (mbuf_block->offset > 0) {
@@ -338,7 +356,7 @@ mbuf_get(struct mbuf_pool *pool)
338
356
  return mbuf();
339
357
  }
340
358
 
341
- assert(block->refcount == 1);
359
+ ASSERT_MBUF_BLOCK_PROPERTY(block, block->refcount == 1);
342
360
  block->refcount--;
343
361
  return mbuf(block, 0, block->end - block->start);
344
362
  }
@@ -356,11 +374,28 @@ mbuf_get_with_size(struct mbuf_pool *pool, size_t size)
356
374
  return mbuf();
357
375
  }
358
376
 
359
- assert(block->refcount == 1);
377
+ ASSERT_MBUF_BLOCK_PROPERTY(block, block->refcount == 1);
360
378
  block->refcount--;
361
379
  return mbuf(block, 0, size);
362
380
  }
363
381
 
382
+ static void
383
+ mbuf_block_print(struct mbuf_block *mbuf_block, std::ostream &stream)
384
+ {
385
+ stream << "mbuf_block: " << (void *) mbuf_block << "\n"
386
+ "mbuf_block.magic: " << mbuf_block->magic << "\n"
387
+ "mbuf_block.next: " << (void *) STAILQ_NEXT(mbuf_block, next) << "\n"
388
+ "mbuf_block.start: " << (void *) mbuf_block->start << "\n"
389
+ "mbuf_block.end: " << (void *) mbuf_block->end << "\n"
390
+ "mbuf_block.refcount: " << mbuf_block->refcount << "\n"
391
+ "mbuf_block.offset: " << mbuf_block->offset << "\n"
392
+ "mbuf_block.pool: " << (void *) mbuf_block->pool << "\n"
393
+ "mbuf_block.pool.nfree_mbuf_blockq: " << mbuf_block->pool->nfree_mbuf_blockq << "\n"
394
+ "mbuf_block.pool.nactive_mbuf_blockq: " << mbuf_block->pool->nactive_mbuf_blockq << "\n"
395
+ "mbuf_block.pool.mbuf_block_chunk_size: " << mbuf_block->pool->mbuf_block_chunk_size << "\n"
396
+ "mbuf_block.pool.mbuf_block_offset: " << mbuf_block->pool->mbuf_block_offset << "\n";
397
+ }
398
+
364
399
 
365
400
  template<typename Address>
366
401
  static Address clamp(Address value, Address min, Address max) {
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * twemproxy - A fast and lightweight proxy for memcached protocol.
3
3
  * Copyright (C) 2011 Twitter, Inc.
4
- * Copyright (c) 2014-2015 Phusion Holding B.V.
4
+ * Copyright (C) 2014-2016 Phusion Holding B.V.
5
5
  *
6
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
7
  * you may not use this file except in compliance with the License.
@@ -200,36 +200,39 @@ public:
200
200
 
201
201
  // Copy assignment.
202
202
  mbuf &operator=(BOOST_COPY_ASSIGN_REF(mbuf) mbuf) {
203
- struct mbuf_block *old_block = mbuf_block;
204
-
205
- mbuf_block = mbuf.mbuf_block;
206
- start = mbuf.start;
207
- end = mbuf.end;
208
-
209
- if (mbuf.mbuf_block != NULL) {
210
- mbuf_block_ref(mbuf.mbuf_block);
211
- }
212
- if (old_block != NULL) {
213
- mbuf_block_unref(old_block);
203
+ if (&mbuf != this) {
204
+ struct mbuf_block *old_block = mbuf_block;
205
+
206
+ mbuf_block = mbuf.mbuf_block;
207
+ start = mbuf.start;
208
+ end = mbuf.end;
209
+
210
+ if (mbuf.mbuf_block != NULL) {
211
+ mbuf_block_ref(mbuf.mbuf_block);
212
+ }
213
+ if (old_block != NULL) {
214
+ mbuf_block_unref(old_block);
215
+ }
214
216
  }
215
217
  return *this;
216
218
  }
217
219
 
218
220
  // Move assignment.
219
221
  mbuf &operator=(BOOST_RV_REF(mbuf) mbuf) {
220
- struct mbuf_block *old_block = mbuf_block;
221
-
222
- mbuf_block = mbuf.mbuf_block;
223
- start = mbuf.start;
224
- end = mbuf.end;
225
- mbuf.mbuf_block = NULL;
226
- mbuf.start = NULL;
227
- mbuf.end = NULL;
228
-
229
- if (old_block != NULL) {
230
- mbuf_block_unref(old_block);
222
+ if (&mbuf != this) {
223
+ struct mbuf_block *old_block = mbuf_block;
224
+
225
+ mbuf_block = mbuf.mbuf_block;
226
+ start = mbuf.start;
227
+ end = mbuf.end;
228
+ mbuf.mbuf_block = NULL;
229
+ mbuf.start = NULL;
230
+ mbuf.end = NULL;
231
+
232
+ if (old_block != NULL) {
233
+ mbuf_block_unref(old_block);
234
+ }
231
235
  }
232
-
233
236
  return *this;
234
237
  }
235
238
 
@@ -161,6 +161,10 @@ private:
161
161
  } else {
162
162
  SKC_TRACE(client, 3, "Request object destroyed; not added to freelist " <<
163
163
  "because it's full (" << freeRequestCount << ")");
164
+ if (request->pool != NULL) {
165
+ psg_destroy_pool(request->pool);
166
+ request->pool = NULL;
167
+ }
164
168
  delete request;
165
169
  }
166
170
 
@@ -0,0 +1,304 @@
1
+ /*
2
+ * Phusion Passenger - https://www.phusionpassenger.com/
3
+ * Copyright (c) 2011-2016 Phusion Holding B.V.
4
+ *
5
+ * "Passenger", "Phusion Passenger" and "Union Station" are registered
6
+ * trademarks of Phusion Holding B.V.
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ * of this software and associated documentation files (the "Software"), to deal
10
+ * in the Software without restriction, including without limitation the rights
11
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ * copies of the Software, and to permit persons to whom the Software is
13
+ * furnished to do so, subject to the following conditions:
14
+ *
15
+ * The above copyright notice and this permission notice shall be included in
16
+ * all copies or substantial portions of the Software.
17
+ *
18
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ * THE SOFTWARE.
25
+ */
26
+ #ifndef _ADHOC_LVE_H_
27
+ #define _ADHOC_LVE_H_
28
+
29
+ // A library for using CloudLinux's LVE technology.
30
+ // https://www.cloudlinux.com/lve-manage.php
31
+ // http://docs.cloudlinux.com/understanding_lve.html
32
+
33
+ #include <functional>
34
+ #include <cstdlib>
35
+ #include <cstddef>
36
+ #include <sstream>
37
+
38
+ #include <boost/shared_ptr.hpp>
39
+ #include <boost/scoped_ptr.hpp>
40
+ #include <boost/thread/once.hpp>
41
+
42
+ #include <sys/types.h>
43
+ #include <unistd.h>
44
+ #include <dlfcn.h>
45
+ #include <errno.h>
46
+ #include <stdint.h>
47
+
48
+
49
+ namespace adhoc_lve {
50
+
51
+ struct liblve;
52
+
53
+ enum liblve_enter_flags {
54
+ LVE_NO_UBC = 1 << 0,
55
+ LVE_NO_NAMESPACE = 1 << 1,
56
+ LVE_NO_MAXENTER = 1 << 2,
57
+ LVE_SILENCE = 1 << 3,
58
+ };
59
+
60
+ typedef void* (*liblve_alloc) (size_t size);
61
+ typedef void (*liblve_free) (void *ptr);
62
+
63
+ /**
64
+ * initializes and create instance of LVE
65
+ * args
66
+ * allocator - pointer to function to allocate memory
67
+ * returns
68
+ * NULL on error, errno will be set.
69
+ * errno will be EINVAL if wrong version of library is used
70
+ * liblve otherwise
71
+ */
72
+ typedef struct liblve* (*init_lve_function_ptr_t)(liblve_alloc alloc, liblve_free free);
73
+
74
+ /**
75
+ * destroy lve library instance
76
+ * args:
77
+ * lve = instantiated liblive instance
78
+ * return 0 on success
79
+ * negative number on error. errno will be set
80
+ */
81
+ typedef int (*destroy_lve_function_ptr_t)(struct liblve *lve);
82
+
83
+ /**
84
+ * enter into virutal environment
85
+ * args:
86
+ * lve = fully initialized liblve instance
87
+ * lve_id = id associated with LVE
88
+ * cookie = pointer to cookie, which returned if task correctly migrated
89
+ * in LVE and used to exit from this LVE
90
+ * return codes:
91
+ * 0 = on success, negative number means error:
92
+ * -EPERM - don't have permission to call, or called from outside root LVE
93
+ * -ENOMEM - don't have memory to allocate new LVE
94
+ * -EFAULT - cookie is bad pointer
95
+ */
96
+ typedef int (*lve_enter_flags_function_ptr_t)
97
+ (struct liblve *lve,
98
+ uint32_t lve_id,
99
+ uint32_t *cookie,
100
+ int liblve_enter_flags);
101
+
102
+ /**
103
+ * exit from virtual environment, same as lve_leave
104
+ * args:
105
+ * lve = fully init liblve instance
106
+ * cookie - pointer to cookie returned from lve_enter
107
+ * return codes:
108
+ * 0 = none error, all less zero is errors:
109
+ * -ESRCH = task not in virutal environment
110
+ * -EFAULT = bad cookie pointer
111
+ * -EINVAL = cookie not match to stored in context
112
+ */
113
+ typedef int (*lve_exit_function_ptr_t)(struct liblve *lve, uint32_t *cookie);
114
+
115
+ typedef int (*jail_function_ptr_t)(const struct passwd *, char*);
116
+
117
+ /**
118
+ * Must be used once per app instances
119
+ */
120
+ class LibLve : private boost::noncopyable {
121
+ public:
122
+
123
+ #ifdef LIBLVE_LOAD
124
+ # error LIBLVE_LOAD macro redifinition
125
+ #else
126
+ # define LIBLVE_LOAD(fname) \
127
+ fname ## _function_ptr = \
128
+ (fname ## _function_ptr_t) dlsym(liblve_handle.get(), #fname); \
129
+ if (!fname ## _function_ptr && err_buf.str().empty()) \
130
+ init_error = (std::string) "Failed to init LVE library " + ::dlerror()
131
+
132
+ LibLve()
133
+ : init_lve_function_ptr (NULL)
134
+ , destroy_lve_function_ptr (NULL)
135
+ , lve_enter_flags_function_ptr (NULL)
136
+ , lve_exit_function_ptr (NULL)
137
+ {
138
+ void *handle = ::dlopen("liblve.so.0", RTLD_LAZY);
139
+ if (handle) {
140
+ liblve_handle.reset(handle, ::dlclose);
141
+ } else {
142
+ // No liblve found, but it is OK and we are running
143
+ // on non LVE capable system
144
+ return;
145
+ }
146
+
147
+ std::ostringstream err_buf;
148
+
149
+ LIBLVE_LOAD(init_lve);
150
+ LIBLVE_LOAD(destroy_lve);
151
+ LIBLVE_LOAD(lve_enter_flags);
152
+ LIBLVE_LOAD(lve_exit);
153
+ LIBLVE_LOAD(jail);
154
+
155
+ if (!err_buf.str().empty())
156
+ {
157
+ init_error = err_buf.str();
158
+ return;
159
+ }
160
+
161
+ struct liblve* init_handle = init_lve_function_ptr(std::malloc, std::free);
162
+ if (!init_handle)
163
+ err_buf << "init_lve error [" << errno << "]";
164
+ else
165
+ lve_init_handle.reset(init_handle, destroy_lve_function_ptr);
166
+
167
+ init_error = err_buf.str();
168
+ }
169
+
170
+ #undef LIBLVE_LOAD
171
+ #endif
172
+
173
+ bool is_error() const { return !init_error.empty(); }
174
+ const std::string& error() const { return init_error; }
175
+
176
+ bool is_lve_available() const { return (bool) liblve_handle; }
177
+ bool is_lve_ready() const { return is_lve_available() && !is_error(); }
178
+
179
+ int jail(const struct passwd *pw, std::string& jail_err) const
180
+ {
181
+ char error_msg[8192];
182
+ int rc = jail_function_ptr(pw, error_msg);
183
+ if (rc < 0)
184
+ jail_err.assign(error_msg);
185
+ return rc;
186
+ }
187
+
188
+ private:
189
+ friend class LveEnter;
190
+
191
+ /**
192
+ * using boost::shared_ptr because of scoped_ptr does not allow
193
+ * to specify custom destructor
194
+ */
195
+ boost::shared_ptr<void> liblve_handle;
196
+ boost::shared_ptr<struct liblve> lve_init_handle;
197
+
198
+ init_lve_function_ptr_t init_lve_function_ptr;
199
+ destroy_lve_function_ptr_t destroy_lve_function_ptr;
200
+ lve_enter_flags_function_ptr_t lve_enter_flags_function_ptr;
201
+ lve_exit_function_ptr_t lve_exit_function_ptr;
202
+ jail_function_ptr_t jail_function_ptr;
203
+
204
+ std::string init_error;
205
+ };
206
+
207
+ class LveInitSignleton {
208
+ public:
209
+ static LibLve& getInstance(std::string* outInitOneTimeError) {
210
+ if (!instance())
211
+ {
212
+ static boost::once_flag flag = BOOST_ONCE_INIT;
213
+ boost::call_once(flag, initOnce, outInitOneTimeError);
214
+ }
215
+
216
+ return *instance();
217
+ }
218
+ private:
219
+ typedef boost::scoped_ptr<LibLve> lvelib_scoped_ptr;
220
+
221
+ static lvelib_scoped_ptr& instance() {
222
+ static lvelib_scoped_ptr lvelib_scoped_ptr;
223
+ return lvelib_scoped_ptr;
224
+ }
225
+
226
+ static void initOnce(std::string *err_buf) {
227
+ instance().reset(new LibLve);
228
+
229
+ if (instance()->is_error() && err_buf)
230
+ *err_buf = instance()->error();
231
+ }
232
+ };
233
+
234
+ class LveEnter : private boost::noncopyable {
235
+ public:
236
+ typedef void (*exit_callback_t)(bool entered, const std::string& exit_error);
237
+
238
+ LveEnter(LibLve& lve, uint32_t uid, uint32_t cfg_min_uid, exit_callback_t cb)
239
+ : ctx(lve)
240
+ , cookie(0)
241
+ , entered(false)
242
+ , exit_callback(cb)
243
+ {
244
+ enter(uid, cfg_min_uid);
245
+ }
246
+ ~LveEnter()
247
+ {
248
+ exit();
249
+ }
250
+
251
+ LveEnter& enter(uint32_t uid, uint32_t min_uid) {
252
+ bool is_enter_lve_allowed = (min_uid <= uid);
253
+
254
+ if (!is_enter_lve_allowed || !ctx.is_lve_ready() || entered)
255
+ return *this;
256
+
257
+ int err = ctx.lve_enter_flags_function_ptr(ctx.lve_init_handle.get(),
258
+ uid,
259
+ &cookie,
260
+ LVE_NO_MAXENTER|LVE_SILENCE);
261
+ if (!err)
262
+ entered = true;
263
+ else
264
+ enter_exit_error << "lve_enter_flags error [" << err << "]";
265
+
266
+ return *this;
267
+ }
268
+
269
+ LveEnter& exit() {
270
+ const bool memento (entered);
271
+
272
+ if (entered)
273
+ {
274
+ int err = ctx.lve_exit_function_ptr(ctx.lve_init_handle.get(), &cookie);
275
+ if (err)
276
+ enter_exit_error << "lve_exit error [" << err << "]";
277
+
278
+ entered = false;
279
+ }
280
+
281
+ if (exit_callback)
282
+ exit_callback(memento, enter_exit_error.str());
283
+
284
+ return *this;
285
+ }
286
+
287
+ bool is_entered() const { return entered; }
288
+ bool is_error() const { return !enter_exit_error.str().empty(); }
289
+ std::string error() const { return enter_exit_error.str(); }
290
+
291
+ LibLve& lveInstance() { return ctx; }
292
+ const LibLve& lveInstance() const { return ctx; }
293
+
294
+ private:
295
+ LibLve &ctx;
296
+ uint32_t cookie;
297
+ bool entered;
298
+ std::ostringstream enter_exit_error;
299
+ exit_callback_t exit_callback;
300
+ };
301
+
302
+ } // adhoc_lve ns
303
+
304
+ #endif /* _ADHOC_LVE_H_ */