RSS Git Download  Clone
Raw Blame History
/*******************************************************************************
 *	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;
Control*	control;
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);
	bt.dumpBacktraceFile("/var/log/tmsPuServerCrash", strBuf);
	_exit(1);
}

void sigAbort(int sig, siginfo_t* sigInfo, void* context){
	control->abort();
	_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;
	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);

	signalSet(SIGINT, sigAbort);
	signalSet(SIGTERM, sigAbort);

#if !COREDUMP
	// Setup signals for program crash
	signalSet(SIGSEGV, sigCrash);
	signalSet(SIGHUP, sigCrash);
	signalSet(SIGILL, sigCrash);
	signalSet(SIGABRT, sigCrash);
	signalSet(SIGFPE, sigCrash);
	signalSet(SIGBUS, sigCrash);
#endif

	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;
}