/*******************************************************************************
* Main.cc Tms process
* T.Barnaby, BEAM Ltd, 2007-02-07
*******************************************************************************
*/
#include <stdio.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <main.h>
#include <Control.h>
#include <BDebug.h>
#include <ucontext.h>
#include <Debug.h>
#define COREDUMP 0
typedef void (*SigFunction)(int, siginfo_t*, void*);
Config config;
int realTime;
void sigCrash(int sig, siginfo_t* sigInfo, void* context){
ucontext_t* ucontext = (ucontext_t*)context;
char strBuf[1024];
time_t t;
BDebugBacktrace bt;
t = time(0);
sprintf(strBuf, "TmsPuServer: Version %s crashed with signal %d at location: 0x%x accessing 0x%p on %s",
VERSION, sig, ucontext->uc_mcontext.gregs[REG_EIP], sigInfo->si_addr, ctime(&t));
bt.dumpBacktraceSyslog(strBuf);
bt.dumpBacktraceStdout(strBuf);
_exit(1);
}
void signalSet(int sigNumber, SigFunction sigFunction){
struct sigaction sigAction;
sigAction.sa_sigaction = sigFunction;
sigemptyset(&sigAction.sa_mask);
sigAction.sa_flags = SA_SIGINFO;
sigAction.sa_restorer = 0;
sigaction(sigNumber, &sigAction, 0);
}
void usage(){
fprintf(stderr, "Usage: tmsPuServer [-d n]\n");
fprintf(stderr, " -f : Run in the foreground\n");
fprintf(stderr, " -d n : Debug level n\n");
fprintf(stderr, " -n n : Set the number of this PuServer\n");
}
int main(int argc, char** argv){
BError err;
Control* control;
int a;
BString s;
int db = 0;
int dbFixed = 0;
int foreground = 0;
int number = 0;
sigset_t sigm;
struct rlimit rlim;
// Allow process to lock 500M of available memory
rlim.rlim_max = 500*1024*1024;
rlim.rlim_cur = rlim.rlim_max;
if(setrlimit(RLIMIT_MEMLOCK, &rlim))
perror("Unable to enable memory locking");
#if COREDUMP
rlim.rlim_max = 1024*1024*1024;
rlim.rlim_cur = rlim.rlim_max;
if(setrlimit(RLIMIT_CORE, &rlim))
perror("Unable to enable core dump");
printf("Set to core dump\n");
#endif
// Relinqish root ownership
if(geteuid() == 0){
realTime = 1;
seteuid(getuid());
setegid(getgid());
}
// Lock in all of the pages of this application
if(mlockall(MCL_CURRENT | MCL_FUTURE) < 0)
fprintf(stderr, "Warning: unable to lock in memory pages\n");
// Make sure master thread ignores termination signals sent to the other threads
// Also ignore file size signal, the write function will return an error instead.
sigemptyset(&sigm);
sigaddset(&sigm, SIGUSR1);
sigaddset(&sigm, SIGXFSZ);
sigaddset(&sigm, SIGPIPE);
sigaddset(&sigm, SIGALRM);
sigprocmask(SIG_BLOCK, &sigm, 0);
// Setup signals for program crash
signalSet(SIGSEGV, sigCrash);
signalSet(SIGHUP, sigCrash);
signalSet(SIGILL, sigCrash);
signalSet(SIGABRT, sigCrash);
signalSet(SIGFPE, sigCrash);
signalSet(SIGBUS, sigCrash);
openlog("TmsPuServer", LOG_CONS, LOG_DAEMON);
nprintf("TmsPuServer version: %s started\n", VERSION);
for(a = 1; a < argc; a++){
if(argv[a][0] == '-'){
switch(argv[a][1]){
case 'f':
foreground = 1;
break;
case 'd':
if(argc <= (a + 1)){
usage();
return 1;
}
setDebug(strtol(argv[++a], 0, 0));
dbFixed = 1;
break;
case 'n':
if(argc <= (a + 1)){
usage();
return 1;
}
number = strtol(argv[++a], 0, 0);
break;
default: usage(); return 1;
}
}
}
// Open and read configuration
if(config.open("tmsPuServerDebug.conf"))
if(config.open("tmsPuServer.conf"))
config.open("/etc/tmsPuServer.conf");
config.read();
if(!dbFixed){
s = config.findValue("Debug:");
if(s != ""){
db = strtol(s, 0, 0);
setDebug(db);
}
}
// Create daemon process
if(!foreground)
daemon(0, 0);
// Create main control class
control = new Control(dbFixed);
if(err = control->init(number)){
eprintf("Error: %s\n", err.getString().retStr());
printf("Error: %s\n", err.getString().retStr());
return 1;
}
control->run();
return 0;
}