int main(int argc, char** argv) { CString sConfig; CString sDataDir = ""; thread_setup(); seedPRNG(); CDebug::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; #endif CZNC::CreateInstance(); while ((iArg = getopt_long(argc, argv, "hvnrcspd:Df", g_LongOpts, &iOptIndex)) != -1) { switch (iArg) { case 'h': GenerateHelp(argv[0]); return 0; case 'v': cout << CZNC::GetTag() << endl; cout << CZNC::GetCompileOptionsString() << endl; return 0; case 'n': CDebug::SetStdoutIsTTY(false); break; case 'r': bAllowRoot = true; break; case 'c': bMakeConf = true; break; case 's': bMakePass = true; break; case 'p': #ifdef HAVE_LIBSSL bMakePem = true; break; #else CUtils::PrintError("ZNC is compiled without SSL support."); return 1; #endif /* HAVE_LIBSSL */ case 'd': sDataDir = CString(optarg); break; case 'f': bForeground = true; break; case 'D': bForeground = true; CDebug::SetDebug(true); break; case '?': default: GenerateHelp(argv[0]); return 1; } } if (optind < argc) { CUtils::PrintError("Unrecognized command line arguments."); CUtils::PrintError("Did you mean to run `/znc " + CString(argv[optind]) + "' in IRC client instead?"); CUtils::PrintError("Hint: `/znc " + CString(argv[optind]) + "' is an alias for `/msg *status " + CString(argv[optind]) + "'"); return 1; } CZNC* pZNC = &CZNC::Get(); pZNC->InitDirs(((argc) ? argv[0] : ""), sDataDir); #ifdef HAVE_LIBSSL if (bMakePem) { pZNC->WritePemFile(); CZNC::DestroyInstance(); return 0; } #endif /* HAVE_LIBSSL */ if (bMakePass) { CString sSalt; CUtils::PrintMessage("Type your new password."); CString sHash = CUtils::GetSaltedHashPass(sSalt); CUtils::PrintMessage("Kill ZNC process, if it's running."); CUtils::PrintMessage( "Then replace password in the <User> section of your config with " "this:"); // Not PrintMessage(), to remove [**] from the beginning, to ease // copypasting std::cout << "<Pass password>" << std::endl; std::cout << "\tMethod = " << CUtils::sDefaultHash << std::endl; std::cout << "\tHash = " << sHash << std::endl; std::cout << "\tSalt = " << sSalt << std::endl; std::cout << "</Pass>" << std::endl; CUtils::PrintMessage( "After that start ZNC again, and you should be able to login with " "the new password."); CZNC::DestroyInstance(); return 0; } { set<CModInfo> ssGlobalMods; set<CModInfo> ssUserMods; set<CModInfo> ssNetworkMods; CUtils::PrintAction("Checking for list of available modules"); pZNC->GetModules().GetAvailableMods(ssGlobalMods, CModInfo::GlobalModule); pZNC->GetModules().GetAvailableMods(ssUserMods, CModInfo::UserModule); pZNC->GetModules().GetAvailableMods(ssNetworkMods, CModInfo::NetworkModule); if (ssGlobalMods.empty() && ssUserMods.empty() && ssNetworkMods.empty()) { CUtils::PrintStatus(false, ""); CUtils::PrintError( "No modules found. Perhaps you didn't install ZNC properly?"); CUtils::PrintError( "Read http://wiki.znc.in/Installation for instructions."); if (!CUtils::GetBoolInput( "Do you really want to run ZNC without any modules?", false)) { CZNC::DestroyInstance(); return 1; } } CUtils::PrintStatus(true, ""); } 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) { CZNC::DestroyInstance(); 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)) { CZNC::DestroyInstance(); return 0; } /* Fall through to normal bootup */ } CString sConfigError; if (!pZNC->ParseConfig(sConfig, sConfigError)) { CUtils::PrintError("Unrecoverable config error."); CZNC::DestroyInstance(); return 1; } if (!pZNC->OnBoot()) { CUtils::PrintError("Exiting due to module boot errors."); CZNC::DestroyInstance(); 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)); CZNC::DestroyInstance(); 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."); CZNC::DestroyInstance(); 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); CDebug::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! } // Handle all signals in separate thread std::unique_ptr<CSignalHandler> SignalHandler(new CSignalHandler(pZNC)); int iRet = 0; try { pZNC->Loop(); } catch (const 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()), nullptr, nullptr, nullptr, nullptr}; int pos = 3; if (CDebug::Debug()) args[pos++] = strdup("--debug"); else if (bForeground) args[pos++] = strdup("--foreground"); if (!CDebug::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 SignalHandler.reset(); CZNC::DestroyInstance(); execvp(args[0], args); CUtils::PrintError("Unable to restart ZNC [" + CString(strerror(errno)) + "]"); } /* Fall through */ default: iRet = 1; } } SignalHandler.reset(); CZNC::DestroyInstance(); CUtils::PrintMessage("Exiting"); return iRet; }
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; }
int main(int argc, char** argv) { CString sConfig; CString sDataDir = ""; seedPRNG(); CDebug::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; #endif while ((iArg = getopt_long(argc, argv, "hvnrcspd:Df", g_LongOpts, &iOptIndex)) != -1) { switch (iArg) { case 'h': GenerateHelp(argv[0]); return 0; case 'v': cout << CZNC::GetTag() << endl; cout << CZNC::GetCompileOptionsString() << endl; return 0; case 'n': CDebug::SetStdoutIsTTY(false); break; case 'r': bAllowRoot = true; break; case 'c': bMakeConf = true; break; case 's': bMakePass = true; break; case 'p': #ifdef HAVE_LIBSSL bMakePem = true; break; #else CUtils::PrintError("ZNC is compiled without SSL support."); return 1; #endif /* HAVE_LIBSSL */ case 'd': sDataDir = CString(optarg); break; case 'f': bForeground = true; break; case 'D': bForeground = true; CDebug::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; } { set<CModInfo> ssGlobalMods; set<CModInfo> ssUserMods; set<CModInfo> ssNetworkMods; CUtils::PrintAction("Checking for list of available modules"); pZNC->GetModules().GetAvailableMods(ssGlobalMods, CModInfo::GlobalModule); pZNC->GetModules().GetAvailableMods(ssUserMods, CModInfo::UserModule); pZNC->GetModules().GetAvailableMods(ssNetworkMods, CModInfo::NetworkModule); if (ssGlobalMods.empty() && ssUserMods.empty() && ssNetworkMods.empty()) { CUtils::PrintStatus(false, ""); CUtils::PrintError("No modules found. Perhaps you didn't install ZNC properly?"); CUtils::PrintError("Read http://wiki.znc.in/Installation for instructions."); if (!CUtils::GetBoolInput("Do you really want to run ZNC without any modules?", false)) { delete pZNC; return 1; } } CUtils::PrintStatus(true, ""); } 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); CDebug::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 (CDebug::Debug()) args[pos++] = strdup("--debug"); else if (bForeground) args[pos++] = strdup("--foreground"); if (!CDebug::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; }