/* * Copyright (C) 2006-2016 Jacek Sieka, arnetheduck on gmail point com * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include "adchppd.h" using namespace std; using namespace adchpp; static FILE* pidFile; static string pidFileName; static bool asdaemon = false; static shared_ptr core; static void installHandler(); void breakHandler(int) { if(core) { core->shutdown(); } installHandler(); } static void init() { // Ignore SIGPIPE... struct sigaction sa = { 0 }; sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigset_t mask; sigfillset(&mask); /* Mask all allowed signals, the other threads should inherit this... */ sigdelset(&mask, SIGCONT); sigdelset(&mask, SIGFPE); sigdelset(&mask, SIGILL); sigdelset(&mask, SIGSEGV); sigdelset(&mask, SIGBUS); sigdelset(&mask, SIGINT); sigdelset(&mask, SIGTRAP); pthread_sigmask(SIG_SETMASK, &mask, NULL); installHandler(); if(pidFile != NULL) { fprintf(pidFile, "%d", (int)getpid()); fflush(pidFile); } loadXML(*core, File::makeAbsolutePath(core->getConfigPath(), "adchpp.xml")); } static void installHandler() { struct sigaction sa = { 0 }; sa.sa_handler = breakHandler; sigaction(SIGINT, &sa, NULL); } static void uninit() { if(!asdaemon) printf("Shut down"); if(pidFile != NULL) fclose(pidFile); pidFile = NULL; if(!pidFileName.empty()) unlink(pidFileName.c_str()); } #include static void daemonize() { switch(fork()) { case -1: fprintf(stderr, "First fork failed: %s\n", strerror(errno)); exit(5); case 0: break; default: _exit(0); } if(setsid() < 0) { fprintf(stderr, "setsid failed: %s\n", strerror(errno)); exit(6); } switch(fork()) { case -1: fprintf(stderr, "Second fork failed: %s\n", strerror(errno)); exit(7); case 0: break; default: exit(0); } chdir("/"); close(0); close(1); close(2); open("/dev/null", O_RDWR); dup(0); dup(0); } #include static void runDaemon(const string& configPath) { daemonize(); try { core = Core::create(configPath); init(); core->run(); core.reset(); } catch(const adchpp::Exception& e) { fprintf(stderr, "Failed to start: %s\n", e.what()); } uninit(); } static void runConsole(const string& configPath) { printf("Starting."); fflush(stdout); try { core = Core::create(configPath); printf("."); fflush(stdout); init(); printf(".\n%s running, press ctrl-c to exit...\n", versionString.c_str()); core->run(); core.reset(); } catch(const Exception& e) { fprintf(stderr, "\nFATAL: Can't start ADCH++: %s\n", e.what()); } uninit(); } static void printUsage() { printf("Usage: adchpp [[-c ] [-d]] | [-v] | [-h]\n"); } int main(int argc, char* argv[]) { setlocale(LC_ALL, ""); char buf[PATH_MAX + 1] = { 0 }; char* path = buf; if (readlink("/proc/self/exe", buf, sizeof (buf)) == -1) { path = getenv("_"); } Util::setApp(path == NULL ? argv[0] : path); string configPath = "/etc/adchpp/"; for(int i = 1; i < argc; i++) { if(strcmp(argv[i], "-d") == 0) { asdaemon = true; } else if(strcmp(argv[i], "-v") == 0) { printf("%s\n", versionString.c_str()); return 0; } else if(strcmp(argv[i], "-c") == 0) { if((i + 1) == argc) { fprintf(stderr, "-c \n"); return 1; } i++; string cfg = argv[i]; if(cfg[0] != '/') { fprintf(stderr, "Config dir must be an absolute path\n"); return 2; } if(cfg[cfg.length() - 1] != '/') { cfg+='/'; } configPath = cfg; } else if(strcmp(argv[i], "-p") == 0) { if((i+1) == argc) { fprintf(stderr, "-p \n"); return 1; } i++; pidFileName = argv[i]; } else if(strcmp(argv[i], "-h") == 0) { printUsage(); return 0; } else { fprintf(stderr, "Unknown parameter: %s\n", argv[i]); return 4; } } if(!pidFileName.empty()) { pidFileName = File::makeAbsolutePath(configPath, pidFileName); pidFile = fopen(pidFileName.c_str(), "w"); if(pidFile == NULL) { fprintf(stderr, "Can't open %s for writing\n", pidFileName.c_str()); return 1; } } if(asdaemon) { runDaemon(configPath); } else { runConsole(configPath); } }