adchpp-docker/src/adchppd/adchppdu.cpp

248 lines
5.0 KiB
C++

/*
* 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 <adchpp/adchpp.h>
#include <adchpp/common.h>
#include <adchpp/Util.h>
#include <adchpp/version.h>
#include <adchpp/File.h>
#include <adchpp/Core.h>
#include <adchpp/shared_ptr.h>
#include <signal.h>
#include <limits.h>
#include <locale.h>
#include "adchppd.h"
using namespace std;
using namespace adchpp;
static FILE* pidFile;
static string pidFileName;
static bool asdaemon = false;
static shared_ptr<Core> 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 <fcntl.h>
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 <sys/wait.h>
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 <configdir>] [-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 <directory>\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 <pid-file>\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);
}
}