SslAcceptorTmpl<T>::SslAcceptorTmpl(const T& s, Callback callback) : acceptedCallback(callback), handle(s, boost::bind(&SslAcceptorTmpl<T>::readable, this, _1), 0, 0), socket(s) { s.setNonblocking(); ignoreSigpipe(); }
VariantMap initializeAgent(int argc, char *argv[], const char *processName) { TRACE_POINT(); VariantMap options; ignoreSigpipe(); installAbortHandler(); setup_syscall_interruption_support(); setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); try { if (argc == 1) { int ret = fcntl(FEEDBACK_FD, F_GETFL); if (ret == -1) { if (errno == EBADF) { fprintf(stderr, "You're not supposed to start this program from the command line. " "It's used internally by Phusion Passenger.\n"); exit(1); } else { int e = errno; fprintf(stderr, "Encountered an error in feedback file descriptor 3: %s (%d)\n", strerror(e), e); exit(1); } } else { _feedbackFdAvailable = true; options.readFrom(FEEDBACK_FD); if (options.getBool("fire_and_forget", false)) { _feedbackFdAvailable = false; close(FEEDBACK_FD); } } } else { options.readFrom((const char **) argv + 1, argc - 1); } setLogLevel(options.getInt("log_level", false, 0)); if (!options.get("debug_log_file", false).empty()) { if (strcmp(processName, "PassengerWatchdog") == 0) { /* Have the watchdog set STDOUT and STDERR to the debug * log file so that system abort() calls that stuff * are properly logged. */ string filename = options.get("debug_log_file"); options.erase("debug_log_file"); int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644); if (fd == -1) { int e = errno; throw FileSystemException("Cannot open debug log file " + filename, e, filename); } dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); } else { setDebugFile(options.get("debug_log_file").c_str()); } } } catch (const tracable_exception &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); exit(1); } // Change process title. strncpy(argv[0], processName, strlen(argv[0])); for (int i = 1; i < argc; i++) { memset(argv[i], '\0', strlen(argv[i])); } return options; }
static void abortHandler(int signo, siginfo_t *info, void *ctx) { AbortHandlerState state; state.pid = getpid(); state.signo = signo; state.info = info; pid_t child; time_t t = time(NULL); char crashLogFile[256]; abortHandlerCalled++; if (abortHandlerCalled > 1) { // The abort handler itself crashed! char *end = state.messageBuf; end = appendText(end, "[ origpid="); end = appendULL(end, (unsigned long long) state.pid); end = appendText(end, ", pid="); end = appendULL(end, (unsigned long long) getpid()); end = appendText(end, ", timestamp="); end = appendULL(end, (unsigned long long) t); if (abortHandlerCalled == 2) { // This is the first time it crashed. end = appendText(end, " ] Abort handler crashed! signo="); end = appendSignalName(end, state.signo); end = appendText(end, ", reason="); end = appendSignalReason(end, state.info); end = appendText(end, "\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); // Run default signal handler. raise(signo); } else { // This is the second time it crashed, meaning it failed to // invoke the default signal handler to abort the process! end = appendText(end, " ] Abort handler crashed again! Force exiting this time. signo="); end = appendSignalName(end, state.signo); end = appendText(end, ", reason="); end = appendSignalReason(end, state.info); end = appendText(end, "\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); _exit(1); } return; } if (emergencyPipe1[0] != -1) { close(emergencyPipe1[0]); } if (emergencyPipe1[1] != -1) { close(emergencyPipe1[1]); } if (emergencyPipe2[0] != -1) { close(emergencyPipe2[0]); } if (emergencyPipe2[1] != -1) { close(emergencyPipe2[1]); } emergencyPipe1[0] = emergencyPipe1[1] = -1; emergencyPipe2[0] = emergencyPipe2[1] = -1; /* We want to dump the entire crash log to both stderr and a log file. * We use 'tee' for this. */ if (createCrashLogFile(crashLogFile, t)) { forkAndRedirectToTee(crashLogFile); } char *end = state.messagePrefix; end = appendText(end, "[ pid="); end = appendULL(end, (unsigned long long) state.pid); *end = '\0'; end = state.messageBuf; end = appendText(end, state.messagePrefix); end = appendText(end, ", timestamp="); end = appendULL(end, (unsigned long long) t); end = appendText(end, " ] Process aborted! signo="); end = appendSignalName(end, state.signo); end = appendText(end, ", reason="); end = appendSignalReason(end, state.info); end = appendText(end, ", randomSeed="); end = appendULL(end, (unsigned long long) randomSeed); end = appendText(end, "\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); end = state.messageBuf; if (*crashLogFile != '\0') { end = appendText(end, state.messagePrefix); end = appendText(end, " ] Crash log dumped to "); end = appendText(end, crashLogFile); end = appendText(end, "\n"); } else { end = appendText(end, state.messagePrefix); end = appendText(end, " ] Could not create crash log file, so dumping to stderr only.\n"); } write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); if (beepOnAbort) { end = state.messageBuf; end = appendText(end, state.messagePrefix); end = appendText(end, " ] PASSENGER_BEEP_ON_ABORT on, executing beep...\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); child = asyncFork(); if (child == 0) { closeAllFileDescriptors(2, true); #ifdef __APPLE__ execlp("osascript", "osascript", "-e", "beep 2", (const char * const) 0); safePrintErr("Cannot execute 'osascript' command\n"); #else execlp("beep", "beep", (const char * const) 0); safePrintErr("Cannot execute 'beep' command\n"); #endif _exit(1); } else if (child == -1) { int e = errno; end = state.messageBuf; end = appendText(end, state.messagePrefix); end = appendText(end, " ] Could fork a child process for invoking a beep: fork() failed with errno="); end = appendULL(end, e); end = appendText(end, "\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); } } if (stopOnAbort) { end = state.messageBuf; end = appendText(end, state.messagePrefix); end = appendText(end, " ] PASSENGER_STOP_ON_ABORT on, so process stopped. Send SIGCONT when you want to continue.\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); raise(SIGSTOP); } // It isn't safe to call any waiting functions in this signal handler, // not even read() and waitpid() even though they're async signal safe. // So we fork a child process and let it dump as much diagnostics as possible // instead of doing it in this process. child = asyncFork(); if (child == 0) { // Sleep for a short while to allow the parent process to raise SIGSTOP. // usleep() and nanosleep() aren't async signal safe so we use select() // instead. struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 100000; select(0, NULL, NULL, NULL, &tv); resetSignalHandlersAndMask(); child = asyncFork(); if (child == 0) { // OS X: for some reason the SIGPIPE handler may be reset to default after forking. // Later in this program we're going to pipe backtrace_symbols_fd() into the backtrace // sanitizer, which may fail, and we don't want the diagnostics process to crash // with SIGPIPE as a result, so we ignore SIGPIPE again. ignoreSigpipe(); dumpDiagnostics(state); // The child process may or may or may not resume the original process. // We do it ourselves just to be sure. kill(state.pid, SIGCONT); _exit(0); } else if (child == -1) { int e = errno; end = state.messageBuf; end = appendText(end, state.messagePrefix); end = appendText(end, "] Could fork a child process for dumping diagnostics: fork() failed with errno="); end = appendULL(end, e); end = appendText(end, "\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); _exit(1); } else { // Exit immediately so that child process is adopted by init process. _exit(0); } } else if (child == -1) { int e = errno; end = state.messageBuf; end = appendText(end, state.messagePrefix); end = appendText(end, " ] Could fork a child process for dumping diagnostics: fork() failed with errno="); end = appendULL(end, e); end = appendText(end, "\n"); write_nowarn(STDERR_FILENO, state.messageBuf, end - state.messageBuf); } else { raise(SIGSTOP); // Will continue after the child process has done its job. } // Run default signal handler. raise(signo); }
VariantMap initializeAgent(int argc, char *argv[], const char *processName) { VariantMap options; const char *seedStr; seedStr = getenv("PASSENGER_RANDOM_SEED"); if (seedStr == NULL || *seedStr == '\0') { randomSeed = (unsigned int) time(NULL); } else { randomSeed = (unsigned int) atoll(seedStr); } srand(randomSeed); srandom(randomSeed); ignoreSigpipe(); if (hasEnvOption("PASSENGER_ABORT_HANDLER", true)) { shouldDumpWithCrashWatch = hasEnvOption("PASSENGER_DUMP_WITH_CRASH_WATCH", true); beepOnAbort = hasEnvOption("PASSENGER_BEEP_ON_ABORT", false); stopOnAbort = hasEnvOption("PASSENGER_STOP_ON_ABORT", false); IGNORE_SYSCALL_RESULT(pipe(emergencyPipe1)); IGNORE_SYSCALL_RESULT(pipe(emergencyPipe2)); installAbortHandler(); } oxt::initialize(); setup_syscall_interruption_support(); if (getenv("PASSENGER_SIMULATE_SYSCALL_FAILURES")) { initializeSyscallFailureSimulation(processName); } setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); TRACE_POINT(); try { if (argc == 1) { int e; switch (fdIsSocket(FEEDBACK_FD)) { case FISR_YES: _feedbackFdAvailable = true; options.readFrom(FEEDBACK_FD); if (options.getBool("fire_and_forget", false)) { _feedbackFdAvailable = false; close(FEEDBACK_FD); } break; case FISR_NO: fprintf(stderr, "You're not supposed to start this program from the command line. " "It's used internally by Phusion Passenger.\n"); exit(1); break; case FISR_ERROR: e = errno; fprintf(stderr, "Encountered an error in feedback file descriptor 3: %s (%d)\n", strerror(e), e); exit(1); break; } } else { options.readFrom((const char **) argv + 1, argc - 1); } #ifdef __linux__ if (options.has("passenger_root")) { ResourceLocator locator(options.get("passenger_root", true)); string ruby = options.get("default_ruby", false, DEFAULT_RUBY); string path = ruby + " \"" + locator.getHelperScriptsDir() + "/backtrace-sanitizer.rb\""; backtraceSanitizerCommand = strdup(path.c_str()); } #endif if (backtraceSanitizerCommand == NULL) { backtraceSanitizerCommand = "c++filt -n"; backtraceSanitizerPassProgramInfo = false; } options.setDefaultInt("log_level", DEFAULT_LOG_LEVEL); setLogLevel(options.getInt("log_level")); if (!options.get("debug_log_file", false).empty()) { if (strcmp(processName, "PassengerWatchdog") == 0) { /* Have the watchdog set STDOUT and STDERR to the debug * log file so that system abort() calls that stuff * are properly logged. */ string filename = options.get("debug_log_file"); options.erase("debug_log_file"); int fd = open(filename.c_str(), O_CREAT | O_WRONLY | O_APPEND, 0644); if (fd == -1) { int e = errno; throw FileSystemException("Cannot open debug log file " + filename, e, filename); } dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); } else { setDebugFile(options.get("debug_log_file").c_str()); } } } catch (const tracable_exception &e) { P_ERROR("*** ERROR: " << e.what() << "\n" << e.backtrace()); exit(1); } // Change process title. argv0 = strdup(argv[0]); strncpy(argv[0], processName, strlen(argv[0])); for (int i = 1; i < argc; i++) { memset(argv[i], '\0', strlen(argv[i])); } P_DEBUG("Random seed: " << randomSeed); return options; }