passenger 5.3.4 → 5.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +13 -0
  3. data/CODE_OF_CONDUCT.md +1 -1
  4. data/build/cxx_tests.rb +12 -1
  5. data/build/misc.rb +2 -1
  6. data/build/packaging.rb +2 -0
  7. data/build/support/cplusplus.rb +2 -2
  8. data/build/support/cxx_dependency_map.rb +653 -383
  9. data/dev/configkit-schemas/index.json +105 -3
  10. data/dev/show-latest-crashlog-dir +27 -0
  11. data/resources/templates/standalone/http.erb +2 -0
  12. data/src/agent/Core/AdminPanelConnector.h +2 -2
  13. data/src/agent/Core/ApplicationPool/Context.h +5 -1
  14. data/src/agent/Core/ApplicationPool/Group.h +2 -0
  15. data/src/agent/Core/ApplicationPool/Group/LifetimeAndBasics.cpp +5 -0
  16. data/src/agent/Core/ApplicationPool/Group/Miscellaneous.cpp +2 -1
  17. data/src/agent/Core/ApplicationPool/Group/ProcessListManagement.cpp +1 -1
  18. data/src/agent/Core/ApplicationPool/Group/StateInspection.cpp +12 -19
  19. data/src/agent/Core/ApplicationPool/Options.h +35 -31
  20. data/src/agent/Core/ApplicationPool/Pool/GroupUtils.cpp +2 -1
  21. data/src/agent/Core/ApplicationPool/Socket.h +1 -1
  22. data/src/agent/Core/Config.h +38 -7
  23. data/src/agent/Core/ConfigChange.cpp +13 -1
  24. data/src/agent/Core/Controller.h +3 -1
  25. data/src/agent/Core/Controller/Config.h +14 -11
  26. data/src/agent/Core/Controller/InitRequest.cpp +6 -5
  27. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +3 -0
  28. data/src/agent/Core/CoreMain.cpp +149 -34
  29. data/src/agent/Core/OptionParser.h +12 -1
  30. data/src/agent/Core/SpawningKit/Config.h +1 -1
  31. data/src/agent/Core/SpawningKit/Context.h +7 -1
  32. data/src/agent/Core/SpawningKit/Exceptions.h +15 -12
  33. data/src/agent/Core/SpawningKit/README.md +34 -17
  34. data/src/agent/Core/SpawningKit/Spawner.h +5 -3
  35. data/src/agent/Core/SpawningKit/UserSwitchingRules.h +5 -2
  36. data/src/agent/Core/TelemetryCollector.h +674 -0
  37. data/src/agent/Shared/Fundamentals/AbortHandler.cpp +309 -83
  38. data/src/agent/Shared/Fundamentals/AbortHandler.h +18 -3
  39. data/src/agent/Watchdog/Config.h +21 -4
  40. data/src/agent/Watchdog/WatchdogMain.cpp +4 -1
  41. data/src/apache2_module/ConfigGeneral/AutoGeneratedDefinitions.cpp +10 -0
  42. data/src/apache2_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.cpp +5 -0
  43. data/src/apache2_module/ConfigGeneral/AutoGeneratedSetterFuncs.cpp +30 -0
  44. data/src/apache2_module/DirectoryMapper.h +24 -36
  45. data/src/apache2_module/Hooks.cpp +13 -5
  46. data/src/apache2_module/ServerConfig/AutoGeneratedManifestGeneration.cpp +20 -0
  47. data/src/apache2_module/ServerConfig/AutoGeneratedStruct.h +24 -0
  48. data/src/cxx_supportlib/AppTypeDetector/CBindings.cpp +136 -0
  49. data/src/cxx_supportlib/AppTypeDetector/CBindings.h +73 -0
  50. data/src/cxx_supportlib/{AppTypes.h → AppTypeDetector/Detector.h} +59 -132
  51. data/src/cxx_supportlib/ConfigKit/README.md +90 -2
  52. data/src/cxx_supportlib/ConfigKit/Schema.h +58 -13
  53. data/src/cxx_supportlib/ConfigKit/Store.h +128 -4
  54. data/src/cxx_supportlib/Constants.h +1 -1
  55. data/src/cxx_supportlib/ProcessManagement/Ruby.cpp +3 -3
  56. data/src/cxx_supportlib/ProcessManagement/Ruby.h +7 -2
  57. data/src/cxx_supportlib/ProcessManagement/Spawn.cpp +14 -7
  58. data/src/cxx_supportlib/ProcessManagement/Spawn.h +21 -2
  59. data/src/cxx_supportlib/ResourceLocator.h +1 -1
  60. data/src/cxx_supportlib/ServerKit/ClientRef.h +17 -7
  61. data/src/cxx_supportlib/ServerKit/HttpRequestRef.h +17 -7
  62. data/src/cxx_supportlib/Utils/IOUtils.cpp +2 -1
  63. data/src/cxx_supportlib/Utils/ProcessMetricsCollector.h +9 -6
  64. data/src/cxx_supportlib/WrapperRegistry/CBindings.cpp +85 -0
  65. data/src/cxx_supportlib/WrapperRegistry/CBindings.h +56 -0
  66. data/src/cxx_supportlib/WrapperRegistry/Entry.h +112 -0
  67. data/src/cxx_supportlib/WrapperRegistry/README.md +37 -0
  68. data/src/cxx_supportlib/WrapperRegistry/Registry.h +309 -0
  69. data/src/helper-scripts/download_binaries/extconf.rb +6 -2
  70. data/src/nginx_module/ConfigGeneral/AutoGeneratedDefinitions.c +16 -0
  71. data/src/nginx_module/ConfigGeneral/AutoGeneratedManifestDefaultsInitialization.c +6 -0
  72. data/src/nginx_module/ConfigGeneral/AutoGeneratedSetterFuncs.c +24 -0
  73. data/src/nginx_module/ContentHandler.c +34 -13
  74. data/src/nginx_module/ContentHandler.h +3 -3
  75. data/src/nginx_module/MainConfig/AutoGeneratedCreateFunction.c +11 -0
  76. data/src/nginx_module/MainConfig/AutoGeneratedManifestGeneration.c +23 -0
  77. data/src/nginx_module/MainConfig/AutoGeneratedStruct.h +8 -0
  78. data/src/nginx_module/config +2 -1
  79. data/src/nginx_module/ngx_http_passenger_module.c +9 -3
  80. data/src/nginx_module/ngx_http_passenger_module.h +4 -2
  81. data/src/ruby_supportlib/phusion_passenger.rb +2 -1
  82. data/src/ruby_supportlib/phusion_passenger/apache2/config_options.rb +13 -0
  83. data/src/ruby_supportlib/phusion_passenger/common_library.rb +8 -5
  84. data/src/ruby_supportlib/phusion_passenger/config/download_agent_command.rb +6 -2
  85. data/src/ruby_supportlib/phusion_passenger/config/download_nginx_engine_command.rb +6 -2
  86. data/src/ruby_supportlib/phusion_passenger/native_support.rb +7 -3
  87. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +15 -0
  88. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +11 -1
  89. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +3 -1
  90. metadata +12 -4
  91. data/src/cxx_supportlib/AppTypes.cpp +0 -109
@@ -59,6 +59,7 @@
59
59
  #include <LoggingKit/LoggingKit.h>
60
60
  #include <LoggingKit/Context.h>
61
61
  #include <ResourceLocator.h>
62
+ #include <RandomGenerator.h>
62
63
  #include <ProcessManagement/Utils.h>
63
64
  #include <Utils.h>
64
65
  #include <Utils/AsyncSignalSafeUtils.h>
@@ -70,6 +71,9 @@ namespace Fundamentals {
70
71
  using namespace std;
71
72
  namespace ASSU = AsyncSignalSafeUtils;
72
73
 
74
+ #define RANDOM_TOKEN_SIZE 6
75
+ #define MAX_RANDOM_TOKENS 256
76
+
73
77
 
74
78
  struct AbortHandlerContext {
75
79
  const AbortHandlerConfig *config;
@@ -80,6 +84,12 @@ struct AbortHandlerContext {
80
84
  char *backtraceSanitizerCommand;
81
85
  bool backtraceSanitizerPassProgramInfo;
82
86
 
87
+ /**
88
+ * A string of RANDOM_TOKEN_SIZE * MAX_RANDOM_SIZES bytes.
89
+ * Used by createCrashLogDir() to find a unique directory name.
90
+ */
91
+ char *randomTokens;
92
+
83
93
  int emergencyPipe1[2];
84
94
  int emergencyPipe2[2];
85
95
 
@@ -92,8 +102,12 @@ struct AbortHandlerWorkingState {
92
102
  pid_t pid;
93
103
  int signo;
94
104
  siginfo_t *info;
105
+
95
106
  char messagePrefix[32];
96
107
  char messageBuf[1024];
108
+
109
+ char crashLogDir[256];
110
+ int crashLogDirFd;
97
111
  };
98
112
 
99
113
  typedef void (*Callback)(AbortHandlerWorkingState &state, void *userData);
@@ -116,6 +130,34 @@ write_nowarn(int fd, const void *buf, size_t n) {
116
130
  ASSU::writeNoWarn(fd, buf, n);
117
131
  }
118
132
 
133
+ static void
134
+ printCrashLogFileCreated(AbortHandlerWorkingState &state, const char *fname) {
135
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
136
+ char *pos = state.messageBuf;
137
+ pos = ASSU::appendData(pos, end, "Dumping to ");
138
+ pos = ASSU::appendData(pos, end, state.crashLogDir);
139
+ pos = ASSU::appendData(pos, end, "/");
140
+ pos = ASSU::appendData(pos, end, fname);
141
+ pos = ASSU::appendData(pos, end, "\n");
142
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
143
+ }
144
+
145
+ static void
146
+ printCrashLogFileCreationError(AbortHandlerWorkingState &state, const char *fname, int e) {
147
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
148
+ char *pos = state.messageBuf;
149
+ pos = ASSU::appendData(pos, end, "Error creating ");
150
+ pos = ASSU::appendData(pos, end, state.crashLogDir);
151
+ pos = ASSU::appendData(pos, end, "/");
152
+ pos = ASSU::appendData(pos, end, fname);
153
+ pos = ASSU::appendData(pos, end, ": ");
154
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
155
+ pos = ASSU::appendData(pos, end, " (errno=");
156
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
157
+ pos = ASSU::appendData(pos, end, ")\n");
158
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
159
+ }
160
+
119
161
  static char *
120
162
  appendSignalName(char *pos, const char *end, int signo) {
121
163
  switch (signo) {
@@ -289,8 +331,61 @@ runInSubprocessWithTimeLimit(AbortHandlerWorkingState &state, Callback callback,
289
331
  }
290
332
  }
291
333
 
334
+ static void
335
+ dumpUlimits(AbortHandlerWorkingState &state) {
336
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
337
+ char *pos = state.messageBuf;
338
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
339
+ pos = ASSU::appendData(pos, end, " ] Dumping ulimits...\n");
340
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
341
+
342
+ int fd = -1;
343
+ if (state.crashLogDirFd != -1) {
344
+ fd = openat(state.crashLogDirFd, "ulimits.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
345
+ if (fd != -1) {
346
+ printCrashLogFileCreated(state, "ulimits.log");
347
+ } else {
348
+ printCrashLogFileCreationError(state, "ulimits.log", errno);
349
+ }
350
+ }
351
+
352
+ pid_t pid = asyncFork();
353
+ int status;
354
+ if (pid == 0) {
355
+ if (fd != -1) {
356
+ dup2(fd, STDOUT_FILENO);
357
+ dup2(fd, STDERR_FILENO);
358
+ }
359
+ closeAllFileDescriptors(2, true);
360
+ execlp("ulimit", "ulimit", "-a", (const char * const) 0);
361
+ // On Linux 'ulimit' is a shell builtin, not a command.
362
+ execlp("/bin/sh", "/bin/sh", "-c", "ulimit -a", (const char * const) 0);
363
+ _exit(1);
364
+ } else if (pid == -1) {
365
+ ASSU::printError("ERROR: Could not fork a process to dump the ulimit!\n");
366
+ } else if (waitpid(pid, &status, 0) != pid || status != 0) {
367
+ ASSU::printError("ERROR: Could not run 'ulimit -a'!\n");
368
+ }
369
+
370
+ if (fd != -1) {
371
+ close(fd);
372
+ }
373
+ }
374
+
292
375
  static void
293
376
  dumpFileDescriptorInfoWithLsof(AbortHandlerWorkingState &state, void *userData) {
377
+ if (state.crashLogDirFd != -1) {
378
+ int fd = openat(state.crashLogDirFd, "fds.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
379
+ if (fd != -1) {
380
+ printCrashLogFileCreated(state, "fds.log");
381
+ dup2(fd, STDOUT_FILENO);
382
+ dup2(fd, STDERR_FILENO);
383
+ close(fd);
384
+ } else {
385
+ printCrashLogFileCreationError(state, "fds.log", errno);
386
+ }
387
+ }
388
+
294
389
  char *pos = state.messageBuf;
295
390
  const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
296
391
  pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
@@ -306,15 +401,38 @@ dumpFileDescriptorInfoWithLsof(AbortHandlerWorkingState &state, void *userData)
306
401
  }
307
402
 
308
403
  static void
309
- dumpFileDescriptorInfoWithLs(AbortHandlerWorkingState &state) {
404
+ dumpFileDescriptorInfoWithLs(AbortHandlerWorkingState &state, const char *path) {
310
405
  pid_t pid;
406
+ int fd = -1;
311
407
  int status;
312
408
 
409
+ if (state.crashLogDirFd != -1) {
410
+ fd = openat(state.crashLogDirFd, "fds.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
411
+ if (fd != -1) {
412
+ printCrashLogFileCreated(state, "fds.log");
413
+ } else {
414
+ printCrashLogFileCreationError(state, "fds.log", errno);
415
+ }
416
+ }
417
+
313
418
  pid = asyncFork();
314
419
  if (pid == 0) {
420
+ if (fd != -1) {
421
+ dup2(fd, STDOUT_FILENO);
422
+ dup2(fd, STDERR_FILENO);
423
+ }
424
+
425
+ const char *end = state.messageBuf + sizeof(state.messageBuf);
426
+ char *pos = state.messageBuf;
427
+ pos = ASSU::appendData(pos, end, "Running: ls -lv ");
428
+ pos = ASSU::appendData(pos, end, path);
429
+ pos = ASSU::appendData(pos, end, "\n");
430
+ pos = ASSU::appendData(pos, end, "--------------------------\n");
431
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
432
+
315
433
  closeAllFileDescriptors(2, true);
316
434
  // The '-v' is for natural sorting on Linux. On BSD -v means something else but it's harmless.
317
- execlp("ls", "ls", "-lv", state.messageBuf, (const char * const) 0);
435
+ execlp("ls", "ls", "-lv", path, (const char * const) 0);
318
436
 
319
437
  const char *command[] = { "ls", NULL };
320
438
  printExecError2(command, errno, state.messageBuf, sizeof(state.messageBuf));
@@ -324,6 +442,10 @@ dumpFileDescriptorInfoWithLs(AbortHandlerWorkingState &state) {
324
442
  } else if (waitpid(pid, &status, 0) != pid || status != 0) {
325
443
  ASSU::printError("ERROR: Could not run 'ls' to dump file descriptor information!\n");
326
444
  }
445
+
446
+ if (fd != -1) {
447
+ close(fd);
448
+ }
327
449
  }
328
450
 
329
451
  static void
@@ -342,41 +464,58 @@ dumpFileDescriptorInfo(AbortHandlerWorkingState &state) {
342
464
  status = runInSubprocessWithTimeLimit(state, dumpFileDescriptorInfoWithLsof, NULL, 4000);
343
465
 
344
466
  if (status != 0) {
467
+ char path[256];
345
468
  ASSU::printError("Falling back to another mechanism for dumping file descriptors.\n");
346
469
 
347
- pos = messageBuf;
470
+ pos = path;
471
+ end = path + sizeof(path) - 1;
348
472
  pos = ASSU::appendData(pos, end, "/proc/");
349
473
  pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
350
474
  pos = ASSU::appendData(pos, end, "/fd");
351
475
  *pos = '\0';
352
- if (stat(messageBuf, &buf) == 0) {
353
- dumpFileDescriptorInfoWithLs(state);
354
- } else {
355
- pos = messageBuf;
356
- pos = ASSU::appendData(pos, end, "/dev/fd");
357
- *pos = '\0';
358
- if (stat(messageBuf, &buf) == 0) {
359
- dumpFileDescriptorInfoWithLs(state);
360
- } else {
361
- pos = messageBuf;
362
- pos = ASSU::appendData(pos, end, "ERROR: No other file descriptor dumping mechanism on current platform detected.\n");
363
- write_nowarn(STDERR_FILENO, messageBuf, pos - messageBuf);
364
- }
476
+ if (stat(path, &buf) == 0) {
477
+ dumpFileDescriptorInfoWithLs(state, path);
478
+ return;
479
+ }
480
+
481
+ pos = path;
482
+ pos = ASSU::appendData(pos, end, "/dev/fd");
483
+ *pos = '\0';
484
+ if (stat(path, &buf) == 0) {
485
+ dumpFileDescriptorInfoWithLs(state, path);
486
+ return;
365
487
  }
488
+
489
+ pos = messageBuf;
490
+ pos = ASSU::appendData(pos, end, "ERROR: No other file descriptor dumping mechanism on current platform detected.\n");
491
+ write_nowarn(STDERR_FILENO, messageBuf, pos - messageBuf);
366
492
  }
367
493
  }
368
494
 
369
495
  static void
370
496
  dumpWithCrashWatch(AbortHandlerWorkingState &state) {
371
- char *pos;
372
- const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
497
+ int fd = -1;
373
498
 
374
- pos = state.messageBuf;
499
+ if (state.crashLogDirFd != -1) {
500
+ fd = openat(state.crashLogDirFd, "backtrace.log", O_WRONLY | O_CREAT | O_TRUNC, 0600);
501
+ if (fd != -1) {
502
+ printCrashLogFileCreated(state, "backtrace.log");
503
+ } else {
504
+ printCrashLogFileCreationError(state, "backtrace.log", errno);
505
+ }
506
+ }
507
+
508
+ char *pos = state.messageBuf;
509
+ const char *end = state.messageBuf + sizeof(state.messageBuf) - 1;
375
510
  pos = ASSU::appendInteger<pid_t, 10>(pos, end, state.pid);
376
511
  *pos = '\0';
377
512
 
378
513
  pid_t child = asyncFork();
379
514
  if (child == 0) {
515
+ if (fd != -1) {
516
+ dup2(fd, STDOUT_FILENO);
517
+ dup2(fd, STDERR_FILENO);
518
+ }
380
519
  closeAllFileDescriptors(2, true);
381
520
  execlp(ctx->config->ruby, ctx->config->ruby, ctx->crashWatchCommand,
382
521
  ctx->rubyLibDir, ctx->installSpec, "--dump",
@@ -400,6 +539,10 @@ dumpWithCrashWatch(AbortHandlerWorkingState &state) {
400
539
  } else {
401
540
  waitpid(child, NULL, 0);
402
541
  }
542
+
543
+ if (fd != -1) {
544
+ close(fd);
545
+ }
403
546
  }
404
547
 
405
548
  #ifdef LIBC_HAS_BACKTRACE_FUNC
@@ -508,7 +651,22 @@ dumpWithCrashWatch(AbortHandlerWorkingState &state) {
508
651
 
509
652
  static void
510
653
  runCustomDiagnosticsDumper(AbortHandlerWorkingState &state, void *userData) {
511
- ctx->config->diagnosticsDumper(ctx->config->diagnosticsDumperUserData);
654
+ unsigned int i = static_cast<unsigned int>(reinterpret_cast<boost::uintptr_t>(userData));
655
+ const AbortHandlerConfig::DiagnosticsDumper &dumper = ctx->config->diagnosticsDumpers[i];
656
+
657
+ if (state.crashLogDirFd != -1) {
658
+ int fd = openat(state.crashLogDirFd, dumper.logFileName, O_WRONLY | O_CREAT | O_TRUNC, 0600);
659
+ if (fd != -1) {
660
+ printCrashLogFileCreated(state, dumper.logFileName);
661
+ dup2(fd, STDOUT_FILENO);
662
+ dup2(fd, STDERR_FILENO);
663
+ close(fd);
664
+ } else {
665
+ printCrashLogFileCreationError(state, dumper.logFileName, errno);
666
+ }
667
+ }
668
+
669
+ dumper.func(dumper.userData);
512
670
  }
513
671
 
514
672
  // This function is performed in a child process.
@@ -521,7 +679,7 @@ dumpDiagnostics(AbortHandlerWorkingState &state) {
521
679
 
522
680
  pos = state.messageBuf;
523
681
  pos = ASSU::appendData(pos, end, state.messagePrefix);
524
- pos = ASSU::appendData(pos, end, " ] Date, uname and ulimits:\n");
682
+ pos = ASSU::appendData(pos, end, " ] Date and uname:\n");
525
683
  write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
526
684
 
527
685
  // Dump human-readable time string and string.
@@ -548,20 +706,6 @@ dumpDiagnostics(AbortHandlerWorkingState &state) {
548
706
  ASSU::printError("ERROR: Could not run 'uname -mprsv'!\n");
549
707
  }
550
708
 
551
- // Dump ulimit.
552
- pid = asyncFork();
553
- if (pid == 0) {
554
- closeAllFileDescriptors(2, true);
555
- execlp("ulimit", "ulimit", "-a", (const char * const) 0);
556
- // On Linux 'ulimit' is a shell builtin, not a command.
557
- execlp("/bin/sh", "/bin/sh", "-c", "ulimit -a", (const char * const) 0);
558
- _exit(1);
559
- } else if (pid == -1) {
560
- ASSU::printError("ERROR: Could not fork a process to dump the ulimit!\n");
561
- } else if (waitpid(pid, &status, 0) != pid || status != 0) {
562
- ASSU::printError("ERROR: Could not run 'ulimit -a'!\n");
563
- }
564
-
565
709
  pos = state.messageBuf;
566
710
  pos = ASSU::appendData(pos, end, state.messagePrefix);
567
711
  pos = ASSU::appendData(pos, end, " ] " PROGRAM_NAME " version: " PASSENGER_VERSION "\n");
@@ -604,13 +748,24 @@ dumpDiagnostics(AbortHandlerWorkingState &state) {
604
748
 
605
749
  ASSU::printError("--------------------------------------\n");
606
750
 
607
- if (ctx->config->diagnosticsDumper != NULL) {
751
+ dumpUlimits(state);
752
+
753
+ ASSU::printError("--------------------------------------\n");
754
+
755
+ for (unsigned int i = 0; i < AbortHandlerConfig::MAX_DIAGNOSTICS_DUMPERS; i++) {
756
+ const AbortHandlerConfig::DiagnosticsDumper &diagnosticsDumper = ctx->config->diagnosticsDumpers[i];
757
+ if (diagnosticsDumper.func == NULL) {
758
+ continue;
759
+ }
760
+
608
761
  pos = state.messageBuf;
609
762
  pos = ASSU::appendData(pos, end, state.messagePrefix);
610
- pos = ASSU::appendData(pos, end, " ] Dumping additional diagnostical information...\n");
763
+ pos = ASSU::appendData(pos, end, " ] Dumping ");
764
+ pos = ASSU::appendData(pos, end, diagnosticsDumper.name);
765
+ pos = ASSU::appendData(pos, end, "...\n");
611
766
  write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
612
- ASSU::printError("--------------------------------------\n");
613
- runInSubprocessWithTimeLimit(state, runCustomDiagnosticsDumper, NULL, 2000);
767
+ runInSubprocessWithTimeLimit(state, runCustomDiagnosticsDumper,
768
+ reinterpret_cast<void *>(static_cast<boost::uintptr_t>(i)), 2000);
614
769
  ASSU::printError("--------------------------------------\n");
615
770
  }
616
771
 
@@ -630,46 +785,109 @@ dumpDiagnostics(AbortHandlerWorkingState &state) {
630
785
  } else {
631
786
  write_nowarn(STDERR_FILENO, "\n", 1);
632
787
  }
788
+
789
+ if (state.crashLogDir[0] != '\0') {
790
+ ASSU::printError("--------------------------------------\n");
791
+ pos = state.messageBuf;
792
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
793
+ pos = ASSU::appendData(pos, end, " ] **************** LOOK HERE FOR CRASH DETAILS *****************\n\n");
794
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
795
+ pos = ASSU::appendData(pos, end, " ] Crash log dumped to this directory:\n");
796
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
797
+ pos = ASSU::appendData(pos, end, " ] ");
798
+ pos = ASSU::appendData(pos, end, state.crashLogDir);
799
+ pos = ASSU::appendData(pos, end, "\n\n");
800
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
801
+ pos = ASSU::appendData(pos, end, " ] **************** LOOK ABOVE FOR CRASH DETAILS ****************\n");
802
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
803
+ }
633
804
  }
634
805
 
635
806
  static bool
636
- createCrashLogFile(char *filename, size_t bufSize, time_t t) {
637
- char *pos = filename;
638
- const char *end = filename + bufSize - 1;
639
- pos = ASSU::appendData(pos, end, "/var/tmp/passenger-crash-log.");
640
- pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
641
- *pos = '\0';
642
-
643
- int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
644
- if (fd == -1) {
645
- pos = filename;
646
- pos = ASSU::appendData(pos, end, ctx->tmpDir);
647
- pos = ASSU::appendData(pos, end, "/passenger-crash-log.");
648
- pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
807
+ createCrashLogDir(AbortHandlerWorkingState &state, time_t t) {
808
+ char *suffixBegin = state.crashLogDir;
809
+ const char *end = state.crashLogDir + sizeof(state.crashLogDir) - 1;
810
+ suffixBegin = ASSU::appendData(suffixBegin, end, "/var/tmp/passenger-crash-log.");
811
+ suffixBegin = ASSU::appendInteger<time_t, 10>(suffixBegin, end, t);
812
+ suffixBegin = ASSU::appendData(suffixBegin, end, ".");
813
+
814
+ // Try a bunch of times to find and create a unique path.
815
+ for (unsigned int i = 0; i < MAX_RANDOM_TOKENS; i++) {
816
+ char *pos = suffixBegin;
817
+ pos = ASSU::appendData(pos, end, ctx->randomTokens + RANDOM_TOKEN_SIZE * i,
818
+ RANDOM_TOKEN_SIZE);
649
819
  *pos = '\0';
650
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600);
651
- }
652
- if (fd == -1) {
653
- *filename = '\0';
654
- return false;
655
- } else {
656
- close(fd);
820
+
821
+ int ret;
822
+ do {
823
+ ret = mkdir(state.crashLogDir, 0700);
824
+ } while (ret == -1 && errno == EINTR);
825
+ if (ret == -1) {
826
+ if (errno == EEXIST) {
827
+ // Directory exists; try again.
828
+ continue;
829
+ } else {
830
+ int e = errno;
831
+ end = state.messageBuf + sizeof(state.messageBuf);
832
+ pos = state.messageBuf;
833
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
834
+ pos = ASSU::appendData(pos, end, " ] Error creating directory ");
835
+ pos = ASSU::appendData(pos, end, state.crashLogDir);
836
+ pos = ASSU::appendData(pos, end, " for storing crash log: ");
837
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
838
+ pos = ASSU::appendData(pos, end, " (errno=");
839
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
840
+ pos = ASSU::appendData(pos, end, ")\n");
841
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
842
+ state.crashLogDir[0] = '\0';
843
+ return false;
844
+ }
845
+ }
846
+
847
+ do {
848
+ state.crashLogDirFd = open(state.crashLogDir, O_RDONLY);
849
+ } while (state.crashLogDirFd == -1 && errno == EINTR);
850
+ if (state.crashLogDirFd == -1) {
851
+ int e = errno;
852
+ end = state.messageBuf + sizeof(state.messageBuf);
853
+ pos = state.messageBuf;
854
+ pos = ASSU::appendData(pos, end, state.messagePrefix);
855
+ pos = ASSU::appendData(pos, end, " ] Error opening created directory ");
856
+ pos = ASSU::appendData(pos, end, state.crashLogDir);
857
+ pos = ASSU::appendData(pos, end, " for storing crash log: ");
858
+ pos = ASSU::appendData(pos, end, ASSU::limitedStrerror(e));
859
+ pos = ASSU::appendData(pos, end, " (errno=");
860
+ pos = ASSU::appendInteger<int, 10>(pos, end, e);
861
+ pos = ASSU::appendData(pos, end, ")\n");
862
+ write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
863
+ state.crashLogDir[0] = '\0';
864
+ return false;
865
+ }
866
+
657
867
  return true;
658
868
  }
869
+
870
+ state.crashLogDir[0] = '\0';
871
+ return false;
659
872
  }
660
873
 
661
- static void
662
- forkAndRedirectToTee(char *filename) {
663
- pid_t pid;
874
+ static bool
875
+ forkAndRedirectToTeeAndMainLogFile(const char *crashLogDir) {
664
876
  int p[2];
665
-
666
877
  if (pipe(p) == -1) {
667
- // Signal error condition.
668
- *filename = '\0';
669
- return;
878
+ return false;
670
879
  }
671
880
 
672
- pid = asyncFork();
881
+ char filename[300];
882
+ char *pos = filename;
883
+ const char *end = filename + sizeof(filename) - 1;
884
+
885
+ pos = ASSU::appendData(pos, end, crashLogDir);
886
+ pos = ASSU::appendData(pos, end, "/");
887
+ pos = ASSU::appendData(pos, end, "main.log");
888
+ *pos = '\0';
889
+
890
+ pid_t pid = asyncFork();
673
891
  if (pid == 0) {
674
892
  close(p[1]);
675
893
  dup2(p[0], STDIN_FILENO);
@@ -680,13 +898,15 @@ forkAndRedirectToTee(char *filename) {
680
898
  execlp("/usr/bin/cat", "cat", (const char * const) 0);
681
899
  ASSU::printError("ERROR: cannot execute 'tee' or 'cat'; crash log will be lost!\n");
682
900
  _exit(1);
901
+ return false;
683
902
  } else if (pid == -1) {
684
903
  ASSU::printError("ERROR: cannot fork a process for executing 'tee'\n");
685
- *filename = '\0';
904
+ return false;
686
905
  } else {
687
906
  close(p[0]);
688
907
  dup2(p[1], STDOUT_FILENO);
689
908
  dup2(p[1], STDERR_FILENO);
909
+ return true;
690
910
  }
691
911
  }
692
912
 
@@ -717,7 +937,6 @@ abortHandler(int signo, siginfo_t *info, void *_unused) {
717
937
  state.info = info;
718
938
  pid_t child;
719
939
  time_t t = time(NULL);
720
- char crashLogFile[256];
721
940
 
722
941
  ctx->callCount++;
723
942
  if (ctx->callCount > 1) {
@@ -756,13 +975,6 @@ abortHandler(int signo, siginfo_t *info, void *_unused) {
756
975
 
757
976
  closeEmergencyPipes();
758
977
 
759
- /* We want to dump the entire crash log to both stderr and a log file.
760
- * We use 'tee' for this.
761
- */
762
- if (createCrashLogFile(crashLogFile, sizeof(crashLogFile), t)) {
763
- forkAndRedirectToTee(crashLogFile);
764
- }
765
-
766
978
  {
767
979
  const char *end = state.messagePrefix + sizeof(state.messagePrefix);
768
980
  char *pos = state.messagePrefix;
@@ -771,8 +983,19 @@ abortHandler(int signo, siginfo_t *info, void *_unused) {
771
983
  *pos = '\0';
772
984
  }
773
985
 
986
+ /* We want to dump the entire crash log to both stderr and a log file.
987
+ * We use 'tee' for this.
988
+ */
989
+ state.crashLogDir[0] = '\0';
990
+ state.crashLogDirFd = -1;
991
+ if (createCrashLogDir(state, t)) {
992
+ forkAndRedirectToTeeAndMainLogFile(state.crashLogDir);
993
+ }
994
+
774
995
  const char *end = state.messageBuf + sizeof(state.messageBuf);
775
996
  char *pos = state.messageBuf;
997
+ // Print a \n just in case we're aborting in the middle of a non-terminated line.
998
+ pos = ASSU::appendData(pos, end, "\n");
776
999
  pos = ASSU::appendData(pos, end, state.messagePrefix);
777
1000
  pos = ASSU::appendData(pos, end, ", timestamp=");
778
1001
  pos = ASSU::appendInteger<time_t, 10>(pos, end, t);
@@ -786,14 +1009,14 @@ abortHandler(int signo, siginfo_t *info, void *_unused) {
786
1009
  write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
787
1010
 
788
1011
  pos = state.messageBuf;
789
- if (*crashLogFile != '\0') {
1012
+ if (state.crashLogDir[0] != '\0') {
790
1013
  pos = ASSU::appendData(pos, end, state.messagePrefix);
791
- pos = ASSU::appendData(pos, end, " ] Crash log dumped to ");
792
- pos = ASSU::appendData(pos, end, crashLogFile);
793
- pos = ASSU::appendData(pos, end, "\n");
1014
+ pos = ASSU::appendData(pos, end, " ] Crash log files will be dumped to ");
1015
+ pos = ASSU::appendData(pos, end, state.crashLogDir);
1016
+ pos = ASSU::appendData(pos, end, " <--- ******* LOOK HERE FOR DETAILS!!! *******\n");
794
1017
  } else {
795
1018
  pos = ASSU::appendData(pos, end, state.messagePrefix);
796
- pos = ASSU::appendData(pos, end, " ] Could not create crash log file, so dumping to stderr only.\n");
1019
+ pos = ASSU::appendData(pos, end, " ] Could not create crash log directory, so dumping to stderr only.\n");
797
1020
  }
798
1021
  write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
799
1022
 
@@ -869,7 +1092,7 @@ abortHandler(int signo, siginfo_t *info, void *_unused) {
869
1092
  int e = errno;
870
1093
  pos = state.messageBuf;
871
1094
  pos = ASSU::appendData(pos, end, state.messagePrefix);
872
- pos = ASSU::appendData(pos, end, "] Could fork a child process for dumping diagnostics: fork() failed with errno=");
1095
+ pos = ASSU::appendData(pos, end, "] Could not fork a child process for dumping diagnostics: fork() failed with errno=");
873
1096
  pos = ASSU::appendInteger<int, 10>(pos, end, e);
874
1097
  pos = ASSU::appendData(pos, end, "\n");
875
1098
  write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
@@ -884,7 +1107,7 @@ abortHandler(int signo, siginfo_t *info, void *_unused) {
884
1107
  int e = errno;
885
1108
  pos = state.messageBuf;
886
1109
  pos = ASSU::appendData(pos, end, state.messagePrefix);
887
- pos = ASSU::appendData(pos, end, " ] Could fork a child process for dumping diagnostics: fork() failed with errno=");
1110
+ pos = ASSU::appendData(pos, end, " ] Could not fork a child process for dumping diagnostics: fork() failed with errno=");
888
1111
  pos = ASSU::appendInteger<int, 10>(pos, end, e);
889
1112
  pos = ASSU::appendData(pos, end, "\n");
890
1113
  write_nowarn(STDERR_FILENO, state.messageBuf, pos - state.messageBuf);
@@ -905,6 +1128,8 @@ installAbortHandler(const AbortHandlerConfig *config) {
905
1128
 
906
1129
  ctx->config = config;
907
1130
  ctx->backtraceSanitizerPassProgramInfo = true;
1131
+ ctx->randomTokens = strdup(RandomGenerator().generateAsciiString(
1132
+ MAX_RANDOM_TOKENS * RANDOM_TOKEN_SIZE).c_str());
908
1133
  ctx->emergencyPipe1[0] = -1;
909
1134
  ctx->emergencyPipe1[1] = -1;
910
1135
  ctx->emergencyPipe2[0] = -1;
@@ -1038,6 +1263,7 @@ shutdownAbortHandler() {
1038
1263
  free(ctx->tmpDir);
1039
1264
  free(ctx->crashWatchCommand);
1040
1265
  free(ctx->backtraceSanitizerCommand);
1266
+ free(ctx->randomTokens);
1041
1267
  free(ctx->alternativeStack);
1042
1268
  closeEmergencyPipes();
1043
1269
  delete ctx;