Пример #1
0
void setup_sage_signal_handler()
{
    /* Reset the _signals structure */
    memset(&_signals, 0, sizeof(_signals));

    /* Save the default signal mask */
    sigprocmask(SIG_BLOCK, NULL, &default_sigmask);

    /* Save the signal mask with non-critical signals blocked */
    sigprocmask(SIG_BLOCK, NULL, &sigmask_with_sigint);
    sigaddset(&sigmask_with_sigint, SIGHUP);
    sigaddset(&sigmask_with_sigint, SIGINT);
    sigaddset(&sigmask_with_sigint, SIGALRM);

    /* Install signal handlers */
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    /* Block non-critical signals during the signal handlers */
    sigemptyset(&sa.sa_mask);
    sigaddset(&sa.sa_mask, SIGHUP);
    sigaddset(&sa.sa_mask, SIGINT);
    sigaddset(&sa.sa_mask, SIGALRM);

    sa.sa_handler = sage_interrupt_handler;
    if (sigaction(SIGHUP, &sa, NULL)) {perror("sigaction"); exit(1);}
    if (sigaction(SIGINT, &sa, NULL)) {perror("sigaction"); exit(1);}
    sa.sa_handler = sage_signal_handler;
    /* Allow signals during signal handling, we have code to deal with
     * this case. */
    sa.sa_flags |= SA_NODEFER;
    if (sigaction(SIGILL, &sa, NULL)) {perror("sigaction"); exit(1);}
    if (sigaction(SIGABRT, &sa, NULL)) {perror("sigaction"); exit(1);}
    if (sigaction(SIGFPE, &sa, NULL)) {perror("sigaction"); exit(1);}
    if (sigaction(SIGBUS, &sa, NULL)) {perror("sigaction"); exit(1);}
    if (sigaction(SIGSEGV, &sa, NULL)) {perror("sigaction"); exit(1);}

    /* If the CPU architecture is x86, check whether the EMMS
     * instruction is supported by executing it and catching a
     * possible SIGILL (illegal instruction signal). */
#ifdef CPU_ARCH_x86
    if (!cpu_has_emms)
    {
        if (sig_on_no_except())  /* try: */
        {
            asm("emms");
            sig_off();
            cpu_has_emms = 1;
        }
        else  /* except: */
        {
            PyErr_Clear();  /* Clear Python exception */
        }
    }
#endif
}
Пример #2
0
void QueryCvarProvider::InitCookie()
{
	if (m_engine_cvar_cookie) return;

	DebugMessage("Trying to get g_iQueryCvarCookie ...");

	basic_string modulename("engine");

#ifdef GNUC
	if (SourceSdk::InterfacesProxy::m_game != SourceSdk::CounterStrikeGlobalOffensive)
	{
		modulename.append("_srv");
	}
#endif

#ifdef WIN32
	modulename.append(".dll");

	HMODULE engine_module_handle(GetModuleHandleA(modulename.c_str()));

	mem_byte * pstart(nullptr);
	mem_byte * pend(nullptr);
	if (engine_module_handle != NULL)
	{
		MODULEINFO modinfo;

		K32GetModuleInformation(GetCurrentProcess(), engine_module_handle, &modinfo, sizeof(MODULEINFO));

		pstart = (mem_byte*)modinfo.lpBaseOfDll;
		pend = pstart + 0x44A400;

		mem_byte *sig_code(nullptr);
		mem_byte * sig_mask(nullptr);
		size_t sig_size(0);
		size_t sig_off(0);

		if (SourceSdk::InterfacesProxy::m_game == SourceSdk::CounterStrikeGlobalOffensive)
		{
			sig_code = new mem_byte[156]
			{
				0x55, 0x8B, 0xEC, 0x83,
				0xE4, 0xF8, 0x83, 0xEC,
				0x3C, 0x56, 0x8B, 0x75,
				0x08, 0x2B, 0x35, 0xD4,
				0x12, 0x7B, 0x10, 0xC1,
				0xFE, 0x04, 0x83, 0xFE,
				0x01, 0x7C, 0x08, 0x3B,
				0x35, 0x98, 0x11, 0x7B,
				0x10, 0x7E, 0x0D, 0x68,
				0xB0, 0x39, 0x4A, 0x10,
				0xE8, 0x63, 0x0B, 0x06,
				0x00, 0x83, 0xC4, 0x04,
				0xA1, 0x8C, 0x11, 0x7B,
				0x10, 0x8D, 0x4C, 0x24,
				0x08, 0x8B, 0x74, 0xB0,
				0xFC, 0x8D, 0x46, 0x04,
				0xF7, 0xDE, 0x1B, 0xF6,
				0x23, 0xF0, 0xE8, 0x15,
				0x4F, 0xEF, 0xFF, 0xA1,
				0x38, 0xCE, 0x52, 0x10,
				0x8B, 0xC8, 0xFF, 0x75,
				0x0C, 0x83, 0x4C, 0x24,
				0x24, 0x01, 0x40, 0x89,
				0x4C, 0x24, 0x1C, 0x8D,
				0x4C, 0x24, 0x10, 0xA3,
				0x38, 0xCE, 0x52, 0x10,
				0xE8, 0x53, 0x5F, 0xFF,
				0xFF, 0x8B, 0x06, 0x8D,
				0x4C, 0x24, 0x08, 0x83,
				0x4C, 0x24, 0x20, 0x01,
				0xF7, 0x5C, 0x24, 0x18,
				0x6A, 0x00, 0x6A, 0x00,
				0x51, 0x8B, 0xCE, 0xFF,
				0x50, 0x7C, 0x8B, 0x74,
				0x24, 0x18, 0x8D, 0x4C,
				0x24, 0x08, 0xE8, 0x5D,
				0x18, 0xEF, 0xFF, 0x8B,
				0xC6, 0x5E, 0x8B, 0xE5,
				0x5D, 0xC2, 0x08, 0x00
			};

			sig_mask = new mem_byte[156]
			{
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF
			};

			sig_off = 0x4C;
			sig_size = 156;
		}
		else
		{
			sig_code = new mem_byte[105]
			{
				0x55, 0x8B, 0xEC, 0x81,
				0xEC, 0x18, 0x01, 0x00,
				0x00, 0xA1, 0x7C, 0x2A, //T
				0x3C, 0x10, 0x8B, 0xC8,
				0x40, 0xC6, 0x85, 0xEC,
				0xFE, 0xFF, 0xFF, 0x01,
				0x80, 0x7D, 0x10, 0x00,
				0xA3, 0x7C, 0x2A, 0x3C, //T
				0x10, 0x8B, 0x45, 0x0C,
				0xC7, 0x85, 0xF0, 0xFE,
				0xFF, 0xFF, 0x00, 0x00,
				0x00, 0x00, 0xC7, 0x85,
				0xE8, 0xFE, 0xFF, 0xFF,
				0x60, 0x51, 0x2F, 0x10,
				0x89, 0x8D, 0xF8, 0xFE,
				0xFF, 0xFF, 0x89, 0x85,
				0xFC, 0xFE, 0xFF, 0xFF,
				0x75, 0x08, 0xF7, 0xD9,
				0x89, 0x8D, 0xF8, 0xFE,
				0xFF, 0xFF, 0x8B, 0x4D,
				0x08, 0x8D, 0x95, 0xE8,
				0xFE, 0xFF, 0xFF, 0x6A,
				0x00, 0x52, 0x8B, 0x01,
				0xFF, 0x50, 0x74, 0x8B,
				0x85, 0xF8, 0xFE, 0xFF,
				0xFF, 0x8B, 0xE5, 0x5D,
				0xC3
			};

			sig_mask = new mem_byte[105]
			{
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00, //T
				0x00, 0x00, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00, //T
				0x00, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF
			};

			sig_off = 0xA;
			sig_size = 105;
		}

		sig_ctx ctx(sig_code, sig_mask, sig_size, sig_off);

#else
	modulename.append(".so");

	basic_string relpath(Helpers::format("./bin/%s", modulename.c_str()));

	void ** modinfo = (void **)dlopen(relpath.c_str(), RTLD_NOW | RTLD_NOLOAD);
	void * engine_module_handle = nullptr;
	if (modinfo != NULL)
	{

		//mm_module_handle = dlsym(modinfo, ".init_proc");
		// FIXME : Use link_map to get memory bounds of the module
		engine_module_handle = *modinfo;
		dlclose(modinfo);
	}
	if (engine_module_handle)
	{
		mem_byte * pstart = (mem_byte*)engine_module_handle;
		mem_byte * pend = pstart + 0x44A400;
		mem_byte *sig_code(nullptr);
		mem_byte * sig_mask(nullptr);
		size_t sig_size(0);
		size_t sig_off(0);

		if (SourceSdk::InterfacesProxy::m_game == SourceSdk::CounterStrikeGlobalOffensive)
		{
			sig_code = new mem_byte[234]
			{
				0x55, 0x89, 0xE5, 0x57,
				0x56, 0x8D, 0x75, 0xC4,
				0x53, 0x83, 0xEC, 0x5C,
				0xC7, 0x45, 0xC0, 0x68,
				0x8A, 0x54, 0x00, 0x0F,
				0xB6, 0x45, 0x10, 0x89,
				0x34, 0x24, 0x8B, 0x7D,
				0x0C, 0x88, 0x45, 0xB7,
				0xE8, 0x0B, 0x4B, 0xF6,
				0xFF, 0x8B, 0x15, 0x38, //T
				0xD5, 0x72, 0x00, 0xC6, //T
				0x45, 0xDC, 0x01, 0x8B,
				0x5D, 0xCC, 0xC7, 0x45,
				0xC0, 0x88, 0x91, 0x54,
				0x00, 0xC7, 0x45, 0xC4,
				0xCC, 0x91, 0x54, 0x00,
				0xC7, 0x45, 0xE0, 0x9C,
				0x4C, 0x7E, 0x00, 0x8D,
				0x42, 0x01, 0x89, 0x55,
				0xD0, 0xA3, 0x38, 0xD5,
				0x72, 0x00, 0x8B, 0x45,
				0xD8, 0x83, 0xC8, 0x03,
				0x81, 0xFB, 0x00, 0x47,
				0x7E, 0x00, 0x89, 0x45,
				0xD8, 0x0F, 0x84, 0x89,
				0x00, 0x00, 0x00, 0x89,
				0x3C, 0x24, 0xE8, 0x75,
				0xC9, 0x62, 0x00, 0x89,
				0x1C, 0x24, 0x8D, 0x5D,
				0xC0, 0x89, 0x44, 0x24,
				0x08, 0x89, 0x7C, 0x24,
				0x04, 0xE8, 0x42, 0x39,
				0x36, 0x00, 0x80, 0x7D,
				0xB7, 0x00, 0x75, 0x0C,
				0x8B, 0x45, 0xD0, 0x83,
				0x4D, 0xD8, 0x01, 0xF7,
				0xD8, 0x89, 0x45, 0xD0,
				0x8B, 0x55, 0x08, 0x8D,
				0x5D, 0xC0, 0x8B, 0x02,
				0xC7, 0x44, 0x24, 0x0C,
				0x00, 0x00, 0x00, 0x00,
				0xC7, 0x44, 0x24, 0x08,
				0x00, 0x00, 0x00, 0x00,
				0x89, 0x5C, 0x24, 0x04,
				0x89, 0x14, 0x24, 0xFF,
				0x90, 0x80, 0x00, 0x00,
				0x00, 0x8B, 0x55, 0xE0,
				0xC7, 0x45, 0xC0, 0x88,
				0x91, 0x54, 0x00, 0x8B,
				0x5D, 0xD0, 0xC7, 0x45,
				0xC4, 0xCC, 0x91, 0x54,
				0x00, 0x8D, 0x4A, 0xF4,
				0x81, 0xF9, 0x90, 0x4C,
				0x7E, 0x00, 0x75, 0x37,
				0x89, 0x34, 0x24, 0xE8,
				0x40, 0x4B, 0xF6, 0xFF,
				0x83, 0xC4, 0x5C, 0x89,
				0xD8, 0x5B, 0x5E, 0x5F,
				0x5D, 0xC3
			};

			sig_mask = new mem_byte[234]
			{
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0x00, //T
				0x00, 0x00, 0x00, 0xFF, //T
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00,
				0x00, 0x00, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00,
				0x00, 0x00, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00,
				0x00, 0x00, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00,
				0x00, 0x00, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0x00, 0x00, 0x00, 0x00,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF
			};

			sig_off = 39;
			sig_size = 234;
		}
		else
		{
			sig_code = new mem_byte[116]
			{
				0x55, 0x89, 0xE5, 0x81,
				0xEC, 0x38, 0x01, 0x00,
				0x00, 0xA1, 0x70, 0xBF, //T
				0x2C, 0x00, 0xC6, 0x85,
				0xDC, 0xFE, 0xFF, 0xFF,
				0x01, 0xC7, 0x85, 0xE0,
				0xFE, 0xFF, 0xFF, 0x00,
				0x00, 0x00, 0x00, 0x80,
				0x7D, 0x10, 0x00, 0xC7,
				0x85, 0xD8, 0xFE, 0xFF,
				0xFF, 0x68, 0x2E, 0x23,
				0x00, 0x8B, 0x55, 0x08,
				0x8D, 0x48, 0x01, 0x89,
				0x85, 0xE8, 0xFE, 0xFF,
				0xFF, 0x89, 0x0D, 0x70, //T
				0xBF, 0x2C, 0x00, 0x8B,
				0x4D, 0x0C, 0x89, 0x8D,
				0xEC, 0xFE, 0xFF, 0xFF,
				0x75, 0x08, 0xF7, 0xD8,
				0x89, 0x85, 0xE8, 0xFE,
				0xFF, 0xFF, 0x8B, 0x02,
				0x8D, 0x8D, 0xD8, 0xFE,
				0xFF, 0xFF, 0xC7, 0x44,
				0x24, 0x08, 0x00, 0x00,
				0x00, 0x00, 0x89, 0x4C,
				0x24, 0x04, 0x89, 0x14,
				0x24, 0xFF, 0x50, 0x78,
				0x8B, 0x85, 0xE8, 0xFE,
				0xFF, 0xFF, 0xC9, 0xC3
			};

			sig_mask = new mem_byte[116]
			{
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0x00, 0x00, //T
				0x00, 0x00, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0x00, 0x00, 0x00,
				0x00, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0x00, //T
				0x00, 0x00, 0x00, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
				0xFF, 0xFF, 0xFF, 0xFF,
			};

			sig_off = 0xA;
			sig_size = 116;
		}

		sig_ctx ctx(sig_code, sig_mask, sig_size, sig_off);

#endif

		ScanMemoryRegion(pstart, pend, &ctx);

		if (ctx.m_out != nullptr)
		{
			m_engine_cvar_cookie = reinterpret_cast<SourceSdk::QueryCvarCookie_t *>(*(reinterpret_cast<size_t**>(ctx.m_out)));

			if (m_engine_cvar_cookie != nullptr)
			{
				DebugMessage(Helpers::format("g_iQueryCvarCookie = %d", *m_engine_cvar_cookie));
			}
			else
			{
				g_Logger.Msg<MSG_ERROR>("Failed to get g_iQueryCvarCookie.");
			}
		}
		else
		{
			g_Logger.Msg<MSG_ERROR>("Sigscan failed for g_iQueryCvarCookie.");
		}

		if (sig_mask)
			delete[] sig_mask;
		if (sig_code)
			delete[] sig_code;
	}
	else
	{
		DebugMessage("engine module not found.");
	}
	}

void QueryCvarProvider::FixQueryCvarCookie()
{
	if (m_engine_cvar_cookie)
	{
		if (*m_engine_cvar_cookie < 1 || *m_engine_cvar_cookie == std::numeric_limits<SourceSdk::QueryCvarCookie_t>::max())
		{
			*m_engine_cvar_cookie = 1;
		}
	}
}

SourceSdk::QueryCvarCookie_t QueryCvarProvider::StartQueryCvarValue(SourceSdk::edict_t * pEntity, const char * pName)
{
	FixQueryCvarCookie();
	return SourceSdk::InterfacesProxy::GetServerPluginHelpers()->StartQueryCvarValue(pEntity, pName);
}
Пример #3
0
int main(int argc, char **argv) {
     time_t now;

     /* Initialise route, runq and job classes */
     now = time(NULL);
     route_init(NULL, 0);
     route_register(&rt_filea_method);
     route_register(&rt_fileov_method);
     route_register(&rt_stdin_method);
     route_register(&rt_stdout_method);
     route_register(&rt_stderr_method);
     if ( ! elog_init(1, "job test", NULL))
	  elog_die(FATAL, "didn't initialise elog\n");
     sig_init();
     callback_init();
     runq_init(now);
     meth_init();
     job_init();

     /* Test should fail due to incorrect method */
     elog_printf(DEBUG, "Expect a complaint! -> ");
     if (job_add(5, 5, 0, 1, "test1a1", "internal_test", "stdout", 
		  "stderr", 100, NULL, "echo \"Hello, world\"") != -1)
     {
	  elog_die(FATAL, "[1a] Shouldn't be able to add\n");
     }

     /* Single test in five seconds, never to run */
     if (job_add(5, 5, 0, 1, "test1a2", "internal_test", "stdout", 
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1a] Can't add\n");
     }
				/* Attention: some white box testing */
     itree_first(runq_event);
     if (itree_getkey(runq_event) != now+5) {
	  elog_die(FATAL, "[1a] Queued at an incorrect time\n");
     }
     job_clear();
     if (!itree_empty(runq_event) || !itree_empty(runq_tab)) {
	  elog_die(FATAL, 
		  "[1a] Trees not emptied. runq_events=%d, runq_tab=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab));
     }
     now = time(NULL);
     
     /* Two tests both in five seconds, never to run */
     if (job_add(5, 5, 0, 1, "test1b1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1b] Can't add first\n");
     }
     if (job_add(5, 5, 0, 1, "test1b2", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1b] Can't add second\n");
     }
     itree_first(runq_event);
     if (itree_getkey(runq_event) != now+5) {
	  elog_die(FATAL, "[1b] First queued at an incorrect time\n");
     }
     itree_next(runq_event);
     if (itree_getkey(runq_event) != now+5) {
	  elog_die(FATAL, "[1b] Second queued at an incorrect time\n");
     }
     job_clear();
     if (!itree_empty(runq_event) || !itree_empty(runq_tab)) {
	  elog_die(FATAL, 
		  "[1b] Trees not emptied. runq_events=%d, runq_tab=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab));
     }
     now = time(NULL);

     /* Two tests one in five seconds, the other in six, never to run */
     if (job_add(6, 6, 0, 1, "test1c1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1c] Can't add first\n");
     }
     if (job_add(now+5, 5, 0, 1, "test1c2", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1c] Can't add second\n");
     }
     itree_first(runq_event);
     if (itree_getkey(runq_event) != now+5) {
	  elog_die(FATAL, "[1c] First queued at an incorrect time\n");
     }
     itree_next(runq_event);
     if (itree_getkey(runq_event) != now+6) {
	  elog_die(FATAL, "[1c] Second queued at an incorrect time\n");
     }
     job_clear();
     if (!itree_empty(runq_event) || !itree_empty(runq_tab)) {
	  elog_die(FATAL, 
		  "[1c] Trees not emptied. runq_events=%d, runq_tab=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab));
     }
     now = time(NULL);
     
     /* Continuous single test supposed to start two seconds ago, 
      * next run in three; never to run */
     if (job_add(-2, 5, 0, 0, "test1d1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1d] Can't add\n");
     }
     itree_first(runq_event);
     if (itree_getkey(runq_event) != now+3) {
	  elog_die(FATAL, 
		  "[1d] Event queued at an incorrect time: bad=%d good=%ld\n", 
		  itree_getkey(runq_event), now+3);
     }
     job_clear();
     if (runq_nsched() > 0) {
	  elog_die(FATAL, "[1d] Still active work scheduled. runq_events=%d, "
		  "runq_tab=%d runq_nsched()=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab), runq_nsched());
	  runq_dump();
     }
     now = time(NULL);
     
     /* Two continous tests, starting two seconds ago, next next run in four;
      * never to run */
     if (job_add(-2, 6, 0, 0, "test1e1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1e] Can't add first\n");
     }
     if (job_add(-3, 5, 0, 0, "test1e2", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1e] Can't add second\n");
     }
     itree_first(runq_event);
     while (((struct runq_work*) itree_get(runq_event))->expired)
	  itree_next(runq_event);
     if (itree_getkey(runq_event) != now+2) {
	  elog_die(FATAL, "[1e] First queued at an incorrect time\n");
     }
     itree_next(runq_event);
     while (((struct runq_work*) itree_get(runq_event))->expired)
	  itree_next(runq_event);
     if (itree_getkey(runq_event) != now+4) {
	  elog_die(FATAL, "[1e] Second queued at an incorrect time\n");
     }
     job_clear();
     if (runq_nsched() > 0) {
	  elog_die(FATAL, "[1e] Still active work scheduled. runq_events=%d, "
		  "runq_tab=%d runq_nsched()=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab), runq_nsched());
	  runq_dump();
     }
     now = time(NULL);
     
     /* Two 5 run jobs, scheduled to start 10 seconds ago, with periods
      * of 5 and 6 seconds; never to run */
     if (job_add(-10, 6, 0, 5, "test1f1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1f] Can't add first\n");
     }
     if (job_add(-10, 5, 0, 5, "test1f2", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1f] Can't add second\n");
     }

     itree_first(runq_event);
     while (((struct runq_work*) itree_get(runq_event))->expired)
	  itree_next(runq_event);
     if (itree_getkey(runq_event) != now+2) {
	  elog_die(FATAL, "[1f] First queued at an incorrect time\n");
     }
     itree_next(runq_event);
     while (((struct runq_work*) itree_get(runq_event))->expired)
	  itree_next(runq_event);
     if (itree_getkey(runq_event) != now+5) {
	  elog_die(FATAL, "[1f] Second queued at an incorrect time\n");
     }
     job_clear();
     if (runq_nsched() > 0) {
	  elog_die(FATAL, "[1f] Still active work scheduled. runq_events=%d, "
		  "runq_tab=%d runq_nsched()=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab), runq_nsched());
	  runq_dump();
     }
     now = time(NULL);
     
     /* Two 5 run jobs, scheduled to start 100 seconds ago, with periods
      * of 5 and 6 seconds; they should never be scheduled */
     if (job_add(-100, 6, 0, 5, "test1g1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1g] Can't add first\n");
     }
     if (job_add(-100, 5, 0, 5, "test1g2", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1g] Can't add second\n");
     }
     if (runq_nsched() > 0) {
	  elog_die(FATAL, "[1g] Still active work scheduled. runq_events=%d, "
		  "runq_tab=%d runq_nsched()=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab), runq_nsched());
	  runq_dump();
     }
     job_clear();
     now = time(NULL);

     /* Two five run tests, starting at different times in the past,
      * five runs each wittth different periods; they should both
      * run now */
     if (job_add(-24, 6, 0, 5, "test1h1", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1h] Can't add first\n");
     }
     if (job_add(-20, 5, 0, 5, "test1h2", "internal_test", "stdout",
		  "stderr", 100, "exec", "echo \"Hello, world\"") == -1)
     {
	  elog_die(FATAL, "[1h] Can't add second\n");
     }
     if (runq_nsched() != 2) {
	  elog_die(FATAL, "[1h] Two jobs should be scheduled not %d\n",
		  runq_nsched());
	  runq_dump();
     }
     sig_on();
     sleep(6);		/* let it run */
     sleep(1);		/* let it run */
     sleep(1);		/* let it run */
     sleep(1);		/* let it run */
     sig_off();
     if (runq_nsched() > 0) {
	  elog_die(FATAL, "[1h] Still active work scheduled. runq_events=%d, "
		  "runq_tab=%d runq_nsched()=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab), runq_nsched());
	  runq_dump();
     }

     job_clear();

#if 0
     /* check all tables/lists are empty */
     if (!itree_empty(runq_event) || !itree_empty(runq_tab)) {
	  elog_die(FATAL, "[1i] Still entries in tables. runq_events=%d, "
		  "runq_tab=%d runq_nsched()=%d\n", 
		  itree_n(runq_event), itree_n(runq_tab), runq_nsched());
	  runq_dump();
     }
#endif

     job_fini();
     meth_fini();
     runq_fini();
     elog_fini();
     route_fini();
     callback_fini();

     printf("%s: tests finished\n", argv[0]);
     exit(0);
}
 char* signature() const {return ((char*) &_sig_off) + sig_off();}