Example #1
0
int main(int argc, char** argv) {
	CString sConfig;
	CString sDataDir = "";

	seedPRNG();
	// Win32 doesn't support shell escape codes, so we do this.
	CUtils::SetStdoutIsTTY(false);

	CString sConsoleTitle = "ZNC " + CZNC::GetVersion();
	SetConsoleTitle(sConsoleTitle.c_str());

	// register Ctrl handler
	if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)ConsoleCtrlHandler, TRUE) == NULL)
	{
		CUtils::PrintMessage("Couldn't register console Ctrl handler function!");
	}

	// this prevents open()/read() and friends from stripping \r
	// from files... simply adding _O_BINARY to the modes doesn't seem
	// to be enough for some reason...
	// if we don't do this, Template.cpp will break
	// because it uses string.size() for file pos
	// calculations.
	_set_fmode(_O_BINARY);

#ifdef HAVE_LIBSSL
	CRYPTO_malloc_init();
#endif

	// make sure the stuff in ZNC.dll matches this exe's version... bad crashes otherwise.
	if(CZNC::GetCoreVersion() != MODVERSION)
	{
		CUtils::PrintError("The version number in ZNC.dll doesn't match. Aborting.");
		return 1;
	}

	// process command line arguments

	int iArg, iOptIndex = -1;
	bool bMakeConf = false;
	bool bMakePass = false;
	bool bAllowRoot = false;

#ifdef HAVE_LIBSSL
	bool bMakePem = false;

	while ((iArg = getopt_long(argc, argv, "hvcspd:D", g_LongOpts, &iOptIndex)) != -1) {
#else
	while ((iArg = getopt_long(argc, argv, "hvcsd:D", g_LongOpts, &iOptIndex)) != -1) {
#endif /* HAVE_LIBSSL */
		switch (iArg) {
		case 'h':
			GenerateHelp(argv[0]);
			return 0;
		case 'v':
			cout << CZNC::GetTag() << endl;
			return 0;
		case 'c':
			bMakeConf = true;
			break;
		case 's':
			bMakePass = true;
			break;
#ifdef HAVE_LIBSSL
		case 'p':
			bMakePem = true;
			break;
#endif /* HAVE_LIBSSL */
		case 'd':
			sDataDir = CString(optarg);
			break;
		case 'D':
			CUtils::SetDebug(true);
			break;
		case '?':
		default:
			GenerateHelp(argv[0]);
			return 1;
		}
	}

	if (optind < argc) {
		sConfig = argv[optind];
	}

	if (!InitCsocket()) {
		CUtils::PrintError("Failed to initialize Csocket!");
		exit(-1);
	}

	CZNC* pZNC = &CZNC::Get();
	pZNC->InitDirs(((argc) ? argv[0] : ""), sDataDir);

#ifdef HAVE_LIBSSL
	if (bMakePem) {
		pZNC->WritePemFile();

		delete pZNC;
		return 0;
	}
#endif /* HAVE_LIBSSL */

	if (bMakePass) {
		CString sSalt;
		CString sHash = CUtils::GetSaltedHashPass(sSalt);
		CUtils::PrintMessage("Use this in the <User> section of your config:");
		CUtils::PrintMessage("Pass = "******"#" + sHash + "#" + sSalt + "#");

		delete pZNC;
		return 0;
	}

#ifndef RUN_FROM_SOURCE
	if (CFile::Exists(pZNC->GetCurPath() + "/znc-uninstalled.pc")) {
		CUtils::PrintError("It looks like you are running znc without installing it first.");
		CUtils::PrintError("Recompile with --enable-run-from-source if you intend to do that.");
	}
#endif

	if (bMakeConf) {
		if (!pZNC->WriteNewConfig(sConfig)) {
			delete pZNC;
			return 0;
		}
		/* Fall through to normal bootup */
	}

	if (!pZNC->ParseConfig(sConfig)) {
		if(argc < 2)
		{
			CUtils::PrintMessage("\n");
			CUtils::PrintMessage("Press any key to continue...");
			_getch();
		}
		else
		{
			CUtils::PrintError("Unrecoverable config error.");
		}
		delete pZNC;
		return 1;
	}

	if (!pZNC->OnBoot()) {
		CUtils::PrintError("Exiting due to module boot errors.");
		delete pZNC;
		return 1;
	}

	// removed: checks for isRoot, bForeground, forking and signal handlers

	int iRet = 0;

	CUtils::PrintMessage("\n\n***************************************************");
	CUtils::PrintMessage("** ZNC is now running. Do not close this window. **");
	CUtils::PrintMessage("***************************************************\n\n");

	try {
		pZNC->Loop(&g_bMainLoop);
		CUtils::PrintMessage("Terminating ...");	
	} catch (CException e) {
		switch (e.GetType()) {
			case CException::EX_Shutdown:
				iRet = 0;
				CUtils::PrintMessage("************** Shutting down ZNC... **************");
				break;
			case CException::EX_Restart: {
				// strdup() because GCC is stupid
				char *args[] = {
					strdup(argv[0]),
					strdup("--datadir"),
					strdup(pZNC->GetZNCPath().c_str()),
					NULL,
					NULL,
					NULL,
					NULL,
					NULL
				};
				int pos = 3;
				if (CUtils::Debug())
					args[pos++] = strdup("--debug");
#if 0
				else if (bForeground)
					args[pos++] = strdup("--foreground");
				if (!CUtils::StdoutIsTTY())
					args[pos++] = strdup("--no-color");
				if (bAllowRoot)
					args[pos++] = strdup("--allow-root");
#endif
				args[pos++] = strdup(pZNC->GetConfigFile().c_str());
				// The above code adds 4 entries to args tops
				// which means the array should be big enough

				CUtils::PrintMessage("************** Restarting ZNC... **************");
				delete pZNC; /* stuff screws up real bad if we don't close all sockets etc. */
				pZNC = NULL;

				execvp(args[0], args);
				CUtils::PrintError("Unable to restart znc [" + CString(strerror(errno)) + "]");
			} /* Fall through */
			default:
				iRet = 1;
		}
	}

	delete pZNC;

#ifdef _DEBUG
	::_getch();
#endif

	return iRet;
}
Example #2
0
File: main.cpp Project: flakes/znc
int main(int argc, char** argv) {
	CString sConfig;
	CString sDataDir = "";

	seedPRNG();
	CUtils::SetStdoutIsTTY(isatty(1));

	int iArg, iOptIndex = -1;
	bool bMakeConf = false;
	bool bMakePass = false;
	bool bAllowRoot = false;
	bool bForeground = false;
#ifdef ALWAYS_RUN_IN_FOREGROUND
	bForeground = true;
#endif
#ifdef HAVE_LIBSSL
	bool bMakePem = false;

	while ((iArg = getopt_long(argc, argv, "hvnrcspd:Df", g_LongOpts, &iOptIndex)) != -1) {
#else
	while ((iArg = getopt_long(argc, argv, "hvnrcsd:Df", g_LongOpts, &iOptIndex)) != -1) {
#endif /* HAVE_LIBSSL */
		switch (iArg) {
		case 'h':
			GenerateHelp(argv[0]);
			return 0;
		case 'v':
			cout << CZNC::GetTag() << endl;
			return 0;
		case 'n':
			CUtils::SetStdoutIsTTY(false);
			break;
		case 'r':
			bAllowRoot = true;
			break;
		case 'c':
			bMakeConf = true;
			break;
		case 's':
			bMakePass = true;
			break;
#ifdef HAVE_LIBSSL
		case 'p':
			bMakePem = true;
			break;
#endif /* HAVE_LIBSSL */
		case 'd':
			sDataDir = CString(optarg);
			break;
		case 'f':
			bForeground = true;
			break;
		case 'D':
			bForeground = true;
			CUtils::SetDebug(true);
			break;
		case '?':
		default:
			GenerateHelp(argv[0]);
			return 1;
		}
	}

	if (optind < argc) {
		CUtils::PrintError("Specifying a config file as an argument isn't supported anymore.");
		CUtils::PrintError("Use --datadir instead.");
		return 1;
	}

	CZNC* pZNC = &CZNC::Get();
	pZNC->InitDirs(((argc) ? argv[0] : ""), sDataDir);

#ifdef HAVE_LIBSSL
	if (bMakePem) {
		pZNC->WritePemFile();

		delete pZNC;
		return 0;
	}
#endif /* HAVE_LIBSSL */

	if (bMakePass) {
		CString sSalt;
		CString sHash = CUtils::GetSaltedHashPass(sSalt);
		CUtils::PrintMessage("Use this in the <User> section of your config:");
		CUtils::PrintMessage("Pass = "******"#" + sHash + "#" + sSalt + "#");

		delete pZNC;
		return 0;
	}

#ifndef RUN_FROM_SOURCE
	if (CFile::Exists(pZNC->GetCurPath() + "/znc-uninstalled.pc")) {
		CUtils::PrintError("It looks like you are running ZNC without installing it first.");
		CUtils::PrintError("Recompile with --enable-run-from-source if you intend to do that.");
	}
#endif

	if (isRoot()) {
		CUtils::PrintError("You are running ZNC as root! Don't do that! There are not many valid");
		CUtils::PrintError("reasons for this and it can, in theory, cause great damage!");
		if (!bAllowRoot) {
			delete pZNC;
			return 1;
		}
		CUtils::PrintError("You have been warned.");
		CUtils::PrintError("Hit CTRL+C now if you don't want to run ZNC as root.");
		CUtils::PrintError("ZNC will start in 30 seconds.");
		sleep(30);
	}

	if (bMakeConf) {
		if (!pZNC->WriteNewConfig(sConfig)) {
			delete pZNC;
			return 0;
		}
		/* Fall through to normal bootup */
	}

	if (!pZNC->ParseConfig(sConfig)) {
		CUtils::PrintError("Unrecoverable config error.");
		delete pZNC;
		return 1;
	}

	if (!pZNC->OnBoot()) {
		CUtils::PrintError("Exiting due to module boot errors.");
		delete pZNC;
		return 1;
	}

	if (bForeground) {
		int iPid = getpid();
		CUtils::PrintMessage("Staying open for debugging [pid: " + CString(iPid) + "]");

		pZNC->WritePidFile(iPid);
		CUtils::PrintMessage(CZNC::GetTag());
	} else {
		CUtils::PrintAction("Forking into the background");

		int iPid = fork();

		if (iPid == -1) {
			CUtils::PrintStatus(false, strerror(errno));
			delete pZNC;
			return 1;
		}

		if (iPid > 0) {
			// We are the parent. We are done and will go to bed.
			CUtils::PrintStatus(true, "[pid: " + CString(iPid) + "]");

			pZNC->WritePidFile(iPid);
			CUtils::PrintMessage(CZNC::GetTag());
			/* Don't destroy pZNC here or it will delete the pid file. */
			return 0;
		}

		/* fcntl() locks don't necessarily propagate to forked()
		 *   children.  Reacquire the lock here.  Use the blocking
		 *   call to avoid race condition with parent exiting.
		 */
		if (!pZNC->WaitForChildLock()) {
			CUtils::PrintError("Child was unable to obtain lock on config file.");
			delete pZNC;
			return 1;
		}

		// Redirect std in/out/err to /dev/null
		close(0); open("/dev/null", O_RDONLY);
		close(1); open("/dev/null", O_WRONLY);
		close(2); open("/dev/null", O_WRONLY);

		CUtils::SetStdoutIsTTY(false);

		// We are the child. There is no way we can be a process group
		// leader, thus setsid() must succeed.
		setsid();
		// Now we are in our own process group and session (no
		// controlling terminal). We are independent!
	}

	struct sigaction sa;
	sa.sa_flags = 0;
	sigemptyset(&sa.sa_mask);

	sa.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sa, (struct sigaction*) NULL);

	sa.sa_handler = signalHandler;
	sigaction(SIGHUP,  &sa, (struct sigaction*) NULL);
	sigaction(SIGUSR1, &sa, (struct sigaction*) NULL);

	// Once this signal is caught, the signal handler is reset
	// to SIG_DFL. This avoids endless loop with signals.
	sa.sa_flags = SA_RESETHAND;
	sa.sa_handler = die;
	sigaction(SIGINT,  &sa, (struct sigaction*) NULL);
	sigaction(SIGQUIT, &sa, (struct sigaction*) NULL);
	sigaction(SIGTERM, &sa, (struct sigaction*) NULL);

	int iRet = 0;

	try {
		pZNC->Loop();
	} catch (CException e) {
		switch (e.GetType()) {
			case CException::EX_Shutdown:
				iRet = 0;
				break;
			case CException::EX_Restart: {
				// strdup() because GCC is stupid
				char *args[] = {
					strdup(argv[0]),
					strdup("--datadir"),
					strdup(pZNC->GetZNCPath().c_str()),
					NULL,
					NULL,
					NULL,
					NULL
				};
				int pos = 3;
				if (CUtils::Debug())
					args[pos++] = strdup("--debug");
				else if (bForeground)
					args[pos++] = strdup("--foreground");
				if (!CUtils::StdoutIsTTY())
					args[pos++] = strdup("--no-color");
				if (bAllowRoot)
					args[pos++] = strdup("--allow-root");
				// The above code adds 3 entries to args tops
				// which means the array should be big enough

				delete pZNC;
				execvp(args[0], args);
				CUtils::PrintError("Unable to restart ZNC [" + CString(strerror(errno)) + "]");
			} /* Fall through */
			default:
				iRet = 1;
		}
	}

	delete pZNC;

	return iRet;
}