示例#1
0
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();
}
示例#2
0
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;
}
示例#3
0
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);
}
示例#4
0
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;
}