int main(int argc, char **argv) 
{ 
    InitModuleObjects();

    addAbortHandler(ControlHandler);

    try
    { 
        StringBuffer codeDirectory;
        splitFilename(argv[0], &codeDirectory, &codeDirectory, NULL, NULL);
        if (!codeDirectory.length())
            codeDirectory.append(".");
        
        execSvr.setown(new CEclAgentExecutionServer());
        execSvr->start(codeDirectory);
    } 
    catch (...)
    {
        printf("Unexpected error running agentexec server\r\n");
    }
    if (execSvr)
    {
        execSvr->stop();
    }

    releaseAtoms();
    ExitModuleObjects();

    return 0;
} 
int main(int argc, char **argv) 
{ 
    InitModuleObjects();

    addAbortHandler(ControlHandler);

    try
    { 
        execSvr.setown(new CEclAgentExecutionServer());
        execSvr->start();
    } 
    catch (...)
    {
        printf("Unexpected error running agentexec server\r\n");
    }
    if (execSvr)
    {
        execSvr->stop();
    }

    releaseAtoms();
    ExitModuleObjects();

    return 0;
} 
int main(int argc, char* argv[])
{
    InitModuleObjects();
    // These are the internal unit tests covered by other modules and libraries
    Array objects;
    objects.append(*(new LoadedObject ("jhtree")));
    objects.append(*(new LoadedObject ("roxiemem")));
    objects.append(*(new LoadedObject ("thorhelper")));

    queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_time);
    CppUnit::TextUi::TestRunner runner;
    if (argc==1)
    {
        CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
        runner.addTest( registry.makeTest() );
    }
    else 
    {
        for (int name = 1; name < argc; name++)
        {
            CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry(argv[name]);
            runner.addTest( registry.makeTest() );
        }
    }
    bool wasSucessful = runner.run( "", false );
    ExitModuleObjects();
    releaseAtoms();
    return wasSucessful;
}
Exemple #4
0
void fatal(const char *format, ...)
{
    va_list      args;

    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    fflush(stderr);
    releaseAtoms();
    ExitModuleObjects();
    _exit(2);
}
Exemple #5
0
BOOL WINAPI ModuleExitHandler ( DWORD dwCtrlType ) 
{ 
    switch( dwCtrlType ) 
    { 
        case CTRL_BREAK_EVENT:  // use Ctrl+C or Ctrl+Break to simulate 
        case CTRL_C_EVENT:      // SERVICE_CONTROL_STOP in debug mode 
        case CTRL_CLOSE_EVENT:
        case CTRL_LOGOFF_EVENT:
        case CTRL_SHUTDOWN_EVENT:
            ExitModuleObjects();
    }
    return FALSE; 
} 
Exemple #6
0
void usage()
{
    fprintf(stderr, "Usage: dumpkey dataset [options]\n"
        "Options:\n"
        "  node=[n]            - dump node n (0 = just header)\n"
        "  fpos=[n]            - dump node at offset fpos\n"
        "  recs=[n]            - dump n rows\n"
        "  -H                  - hex display\n"
        "  -R                  - raw output\n"
                    );
    fflush(stderr);
    releaseAtoms();
    ExitModuleObjects();
    _exit(2);
}
void usage(int exitval = 2)
{
    printf("Usage:\n"
           "scheduleadmin help\n"
           "scheduleadmin <DALI> add <WUID>\n"
           "scheduleadmin <DALI> remove <WUID>\n"
           "scheduleadmin <DALI> removeall\n"
           "scheduleadmin <DALI> servers\n"
           "scheduleadmin <DALI> list <eclserver> (<event name>)\n"
           "scheduleadmin <DALI> monitor <eclserver> (<event name>)\n"
           "scheduleadmin <DALI> cleanup\n"
           "scheduleadmin <DALI> push eventname eventtext (<wuid>)\n"
#if _DEBUG
           "scheduleadmin <DALI> testpull <eclserver queue>\n"
#endif
           );
    releaseAtoms();
    ExitModuleObjects();
    exit(exitval);
}
Exemple #8
0
void usage()
{
    printf("USAGE: uttest [options] iprange\n");
    printf("Options are:\n");
    printf("--enableSocketMaxSetting\n"
        "--jumboFrames\n"
        "--udpLocalWriteSocketSize nn\n"
        "--udpRetryBusySenders nn\n"
        "--maxPacketsPerSender nn\n"
        "--udpSnifferEnabled 0|1\n"     
        "--udpTraceCategories nn\n"
        "--udpTraceLevel nn\n"
        "--dontSendToSelf\n"
        "--sendSize nnMB\n"
        "--rawSpeedTest\n"
        "--rawBufferSize nn\n"
        );
    ExitModuleObjects();
    releaseAtoms();
    exit(1);
}
Exemple #9
0
int main(int argc, char* argv[])
{
    loadDlls();
    InitModuleObjects();
    queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_time);
    CppUnit::TextUi::TestRunner runner;
    if (argc==1)
    {
        CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry();
        runner.addTest( registry.makeTest() );
    }
    else 
    {
        for (int name = 1; name < argc; name++)
        {
            CppUnit::TestFactoryRegistry &registry = CppUnit::TestFactoryRegistry::getRegistry(argv[name]);
            runner.addTest( registry.makeTest() );
        }
    }
    bool wasSucessful = runner.run( "", false );
    ExitModuleObjects();
    releaseAtoms();
    return wasSucessful;
}
Exemple #10
0
int main( int argc, char *argv[]  )
{
#if defined(WIN32) && defined(_DEBUG)
    int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
    tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag( tmpFlag );
#endif

    InitModuleObjects();

    addAbortHandler(ControlHandler);
    EnableSEHtoExceptionMapping();

    dummyProc();
#ifndef __64BIT__
    // Restrict stack sizes on 32-bit systems
    Thread::setDefaultStackSize(0x10000);   // NB under windows requires linker setting (/stack:)
#endif

#ifdef _WIN32
    Owned<CReleaseMutex> globalNamedMutex;
#endif 

    if (globals)
        globals->Release();

    {
        Owned<IFile> iFile = createIFile("thor.xml");
        globals = iFile->exists() ? createPTree(*iFile, ipt_caseInsensitive) : createPTree("Thor", ipt_caseInsensitive);
    }
    unsigned multiThorMemoryThreshold = 0;

    Owned<IException> unregisterException;
    try
    {
        if (argc==1)
        {
            usage();
            return 1;
        }
        cmdArgs = argv+1;
        mergeCmdParams(globals);
        cmdArgs = argv+1;

        const char *master = globals->queryProp("@MASTER");
        if (!master)
            usage();

        const char *slave = globals->queryProp("@SLAVE");
        if (slave)
        {
            slfEp.set(slave);
            localHostToNIC(slfEp);
        }
        else 
            slfEp.setLocalHost(0);

        mySlaveNum = globals->getPropInt("@SLAVENUM");

        setMachinePortBase(slfEp.port);
        slfEp.port = getMachinePortBase();
        startSlaveLog();

        setSlaveAffinity(globals->getPropInt("@SLAVEPROCESSNUM"));

        startMPServer(getFixedPort(TPORT_mp));
#ifdef USE_MP_LOG
        startLogMsgParentReceiver();
        LOG(MCdebugProgress, thorJob, "MPServer started on port %d", getFixedPort(TPORT_mp));
#endif

        SocketEndpoint masterEp(master);
        localHostToNIC(masterEp);
        setMasterPortBase(masterEp.port);
        markNodeCentral(masterEp);
        if (RegisterSelf(masterEp))
        {
            if (globals->getPropBool("Debug/@slaveDaliClient"))
                enableThorSlaveAsDaliClient();

            IDaFileSrvHook *daFileSrvHook = queryDaFileSrvHook();
            if (daFileSrvHook) // probably always installed
                daFileSrvHook->addFilters(globals->queryPropTree("NAS"), &slfEp);

            StringBuffer thorPath;
            globals->getProp("@thorPath", thorPath);
            recursiveCreateDirectory(thorPath.str());
            int err = _chdir(thorPath.str());
            if (err)
            {
                IException *e = makeErrnoExceptionV(-1, "Failed to change dir to '%s'", thorPath.str());
                FLLOG(MCexception(e), thorJob, e);
                throw e;
            }

// Initialization from globals
            setIORetryCount(globals->getPropInt("Debug/@ioRetries")); // default == 0 == off

            StringBuffer str;
            if (globals->getProp("@externalProgDir", str.clear()))
                _mkdir(str.str());
            else
                globals->setProp("@externalProgDir", thorPath);

            const char * overrideBaseDirectory = globals->queryProp("@thorDataDirectory");
            const char * overrideReplicateDirectory = globals->queryProp("@thorReplicateDirectory");
            StringBuffer datadir;
            StringBuffer repdir;
            if (getConfigurationDirectory(globals->queryPropTree("Directories"),"data","thor",globals->queryProp("@name"),datadir))
                overrideBaseDirectory = datadir.str();
            if (getConfigurationDirectory(globals->queryPropTree("Directories"),"mirror","thor",globals->queryProp("@name"),repdir))
                overrideReplicateDirectory = repdir.str();
            if (overrideBaseDirectory&&*overrideBaseDirectory)
                setBaseDirectory(overrideBaseDirectory, false);
            if (overrideReplicateDirectory&&*overrideBaseDirectory)
                setBaseDirectory(overrideReplicateDirectory, true);
            StringBuffer tempDirStr;
            if (getConfigurationDirectory(globals->queryPropTree("Directories"),"temp","thor",globals->queryProp("@name"), tempDirStr))
                globals->setProp("@thorTempDirectory", tempDirStr.str());
            else
                tempDirStr.append(globals->queryProp("@thorTempDirectory"));
            addPathSepChar(tempDirStr).append(getMachinePortBase());

            logDiskSpace(); // Log before temp space is cleared
            SetTempDir(tempDirStr.str(), "thtmp", true);

            useMemoryMappedRead(globals->getPropBool("@useMemoryMappedRead"));

            LOG(MCdebugProgress, thorJob, "ThorSlave Version LCR - %d.%d started",THOR_VERSION_MAJOR,THOR_VERSION_MINOR);
            StringBuffer url;
            LOG(MCdebugProgress, thorJob, "Slave %s - temporary dir set to : %s", slfEp.getUrlStr(url).str(), queryTempDir());
#ifdef _WIN32
            ULARGE_INTEGER userfree;
            ULARGE_INTEGER total;
            ULARGE_INTEGER free;
            if (GetDiskFreeSpaceEx("c:\\",&userfree,&total,&free)&&total.QuadPart) {
                unsigned pc = (unsigned)(free.QuadPart*100/total.QuadPart);
                LOG(MCdebugProgress, thorJob, "Total disk space = %" I64F "d k", total.QuadPart/1000);
                LOG(MCdebugProgress, thorJob, "Free  disk space = %" I64F "d k", free.QuadPart/1000);
                LOG(MCdebugProgress, thorJob, "%d%% disk free\n",pc);
            }
#endif
            if (getConfigurationDirectory(globals->queryPropTree("Directories"),"query","thor",globals->queryProp("@name"),str.clear()))
                globals->setProp("@query_so_dir", str.str());
            else
                globals->getProp("@query_so_dir", str.clear());
            if (str.length())
            {
                if (globals->getPropBool("Debug/@dllsToSlaves", true))
                {
                    StringBuffer uniqSoPath;
                    if (PATHSEPCHAR == str.charAt(str.length()-1))
                        uniqSoPath.append(str.length()-1, str.str());
                    else
                        uniqSoPath.append(str);
                    uniqSoPath.append("_").append(getMachinePortBase());
                    str.swapWith(uniqSoPath);
                    globals->setProp("@query_so_dir", str.str());
                }
                PROGLOG("Using querySo directory: %s", str.str());
                recursiveCreateDirectory(str.str());
            }
     
            multiThorMemoryThreshold = globals->getPropInt("@multiThorMemoryThreshold")*0x100000;
            if (multiThorMemoryThreshold) {
                StringBuffer lgname;
                if (!globals->getProp("@multiThorResourceGroup",lgname))
                    globals->getProp("@nodeGroup",lgname);
                if (lgname.length()) {
                    Owned<ILargeMemLimitNotify> notify = createMultiThorResourceMutex(lgname.str());
                    setMultiThorMemoryNotify(multiThorMemoryThreshold,notify);
                    PROGLOG("Multi-Thor resource limit for %s set to %" I64F "d",lgname.str(),(__int64)multiThorMemoryThreshold);
                }   
                else
                    multiThorMemoryThreshold = 0;
            }
            slaveMain(jobListenerStopped);
        }

        LOG(MCdebugProgress, thorJob, "ThorSlave terminated OK");
    }
    catch (IException *e) 
    {
        if (!jobListenerStopped)
            FLLOG(MCexception(e), thorJob, e,"ThorSlave");
        unregisterException.setown(e);
    }
    ClearTempDirs();

    if (multiThorMemoryThreshold)
        setMultiThorMemoryNotify(0,NULL);
    roxiemem::releaseRoxieHeap();

    if (unregisterException.get())
        UnregisterSelf(unregisterException);

    if (globals->getPropBool("Debug/@slaveDaliClient"))
        disableThorSlaveAsDaliClient();

#ifdef USE_MP_LOG
    stopLogMsgReceivers();
#endif
    stopMPServer();
    ::Release(globals);
    releaseAtoms(); // don't know why we can't use a module_exit to destruct these...

    ExitModuleObjects(); // not necessary, atexit will call, but good for leak checking
    return 0;
}
Exemple #11
0
int main(int argc, const char *argv[])
{
    InitModuleObjects();

    int ret = 0;
    bool dryRun = false;
    bool offline = false;
    StringAttr daliServer, envPath;

    enum CmdType { cmd_none, cmd_swap, cmd_auto, cmd_history, cmd_email, cmd_swapped, cmd_reset, cmd_resetspares, cmd_addspares, cmd_removespares, cmd_resethistory };
    CmdType cmd = cmd_none;

    ArgvIterator iter(argc, argv);

    try
    {
        bool stop=false;
        StringArray params;
        for (; !ret&&!iter.done(); iter.next())
        {
            const char *arg = iter.query();
            if ('-' == *arg)
            {
                bool value;
                if (iter.matchFlag(value, "-dryrun"))
                    dryRun = value;
                else if (iter.matchFlag(value, "-offline"))
                    offline = value;
                else
                {
                    PROGLOG("Unknown option");
                    ret = 2;
                    usage();
                    break;
                }
            }
            else
            {
                switch (cmd)
                {
                    case cmd_none:
                        if (strieq("swap", arg))
                            cmd = cmd_swap;
                        else if (strieq("auto", arg))
                            cmd = cmd_auto;
                        else if (strieq("history", arg))
                            cmd = cmd_history;
                        else if (strieq("email", arg))
                            cmd = cmd_email;
                        else if (strieq("swapped", arg))
                            cmd = cmd_swapped;
                        else if (strieq("reset", arg))
                            cmd = cmd_reset;
                        else if (strieq("resetspares", arg))
                            cmd = cmd_resetspares;
                        else if (strieq("addspares", arg))
                            cmd = cmd_addspares;
                        else if (strieq("removespares", arg))
                            cmd = cmd_removespares;
                        else if (strieq("resethistory", arg))
                            cmd = cmd_resethistory;
                        else
                        {
                            PROGLOG("Unknown command");
                            usage();
                            ret = 2;
                        }
                        break;
                    default:
                        params.append(iter.query());
                        break;
                }
            }
        }
        unsigned requiredParams=UINT_MAX;
        switch (cmd)
        {
            case cmd_swap:
                requiredParams = 4;
                break;
            case cmd_addspares:
            case cmd_removespares:
                requiredParams = 3;
                break;
            case cmd_auto:
            case cmd_history:
            case cmd_email:
            case cmd_swapped:
            case cmd_reset:
            case cmd_resetspares:
            case cmd_resethistory:
                requiredParams = 2;
                break;
        }
        if (params.ordinality() < requiredParams)
        {
            usage();
            ret = 2;
        }
        else
        {
            StringAttr daliServer = params.item(0);
            StringAttr clusterName = params.item(1);

            DaliClient dclient(daliServer);
            StringBuffer logname;
            splitFilename(argv[0], NULL, NULL, &logname, NULL);
            addFileTimestamp(logname, true);
            logname.append(".log");
            StringBuffer lf;
            openLogFile(lf, logname.str(),0,false,true);
            queryStderrLogMsgHandler()->setMessageFields(MSGFIELD_prefix);

            Owned<IRemoteConnection> conn = querySDS().connect("/Environment", myProcessSession(), RTM_LOCK_READ, SDS_LOCK_TIMEOUT);
            IPropertyTree *environment = conn->queryRoot();
            StringBuffer xpath("Software/ThorCluster[@name=\"");
            xpath.append(clusterName).append("\"]");
            IPropertyTree *cluster = environment->queryPropTree(xpath.str());
            if (!cluster)
            {
                PROGLOG("Unknown cluster: %s", clusterName.get());
                ret = 3;
            }
            if (!ret)
            {
                Owned<IPropertyTree> options = createPTreeFromIPT(cluster);
                conn.clear();
                if (options&&options->getPropBool("@enableSysLog",true))
                    UseSysLogForOperatorMessages();

                switch (cmd)
                {
                    case cmd_auto:
                    {
                        if (!autoSwapNode(clusterName, dryRun))
                            ret = 3;
                        break;
                    }
                    case cmd_swap:
                    {
                        const char *oldip=params.item(2);
                        const char *newip=params.item(3);
                        if (!swapNode(clusterName, oldip, newip))
                            ret = 3;
                        break;
                    }
                    case cmd_history:
                    case cmd_swapped:
                    case cmd_email:
                    {
                        unsigned days = params.isItem(2) ? atoi(params.item(2)) : 0; // for history or swapped
                        switch (cmd)
                        {
                            case cmd_history:
                                swapNodeHistory(clusterName, days, NULL);
                                break;
                            case cmd_swapped:
                                swappedList(clusterName, days, NULL);
                                break;
                            case cmd_email:
                            {
                                bool sendSwapped = false;
                                bool sendHistory = false;
                                if (params.isItem(2))
                                {
                                    if (strieq("swapped", params.item(2)))
                                        sendSwapped = true;
                                    else if (strieq("history", params.item(2)))
                                        sendHistory = true;
                                }
                                emailSwap(clusterName, NULL, true, sendSwapped, sendHistory);
                                break;
                            }
                        }
                        break;
                    }
                    case cmd_reset:
                    case cmd_resetspares:
                    {
                        StringBuffer response;
                        if (!resetClusterGroup(clusterName, "ThorCluster", cmd==cmd_resetspares, response))
                        {
                            WARNLOG("%s", response.str());
                            ret = 3;
                        }
                        break;
                    }
                    case cmd_addspares:
                    case cmd_removespares:
                    {
                        SocketEndpointArray allEps;
                        unsigned p=2;
                        do
                        {
                            const char *ipOrRange = params.item(p);
                            SocketEndpointArray epa;
                            epa.fromText(ipOrRange, 0);
                            ForEachItemIn(e, epa)
                                allEps.append(epa.item(e));
                            p++;
                        }
                        while (p<params.ordinality());
                        StringBuffer response;
                        bool res;
                        if (cmd == cmd_addspares)
                            res = addClusterSpares(clusterName, "ThorCluster", allEps, response);
                        else
                            res = removeClusterSpares(clusterName, "ThorCluster", allEps, response);
                        if (!res)
                        {
                            WARNLOG("%s", response.str());
                            ret = 3;
                        }
                        break;
                    }
                    case cmd_resethistory:
                    {
                        Owned<IRemoteConnection> conn = querySDS().connect("/SwapNode", myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT);
                        if (conn)
                        {
                            StringBuffer groupName;
                            getClusterGroupName(*options, groupName);
                            VStringBuffer xpath("Thor[@group=\"%s\"]", groupName.str());
                            if (conn->queryRoot()->removeProp(xpath.str()))
                                PROGLOG("SwapNode info for cluster %s removed", clusterName.get());
                            else
                                PROGLOG("SwapNode info for cluster %s not found", clusterName.get());
                        }
                        break;
                    }
                }
            }
        }
        UseSysLogForOperatorMessages(false);
    }
    catch (IException *e) {
        EXCLOG(e,"SWAPNODE");
        e->Release();
        ret = -1;
    }

    ExitModuleObjects();
    return ret;
}
Exemple #12
0
int main(int argc, const char **argv)
{
#ifdef _WIN32
    _setmode( _fileno( stdout ), _O_BINARY );
    _setmode( _fileno( stdin ), _O_BINARY );
#endif
    Owned<IProperties> globals = createProperties("dumpkey.ini", true);
    for (int i = 1; i < argc; i++)
    {
        if (argv[i][0] == '-')
            doOption(argv[i]);
        else if (strchr(argv[i], '='))
            globals->loadProp(argv[i]);
        else
            globals->setProp("keyfile", argv[i]);
    }
    try
    {
        StringBuffer logname("dumpkey.");
        logname.append(GetCachedHostName()).append(".");
        StringBuffer lf;
        openLogFile(lf, logname.append("log").str());
        
        Owned <IKeyIndex> index;
        const char * keyName = globals->queryProp("keyfile");
        if (keyName)
            index.setown(createKeyIndex(keyName, 0, false, false));
        else
            usage();
        Owned <IKeyCursor> cursor = index->getCursor(NULL);

        size32_t key_size = index->keySize();
        Owned<IFile> in = createIFile(keyName);
        Owned<IFileIO> io = in->open(IFOread);
        if (!io)
            throw MakeStringException(999, "Failed to open file %s", keyName);
        Owned<CKeyHdr> header = new CKeyHdr;
        MemoryAttr block(sizeof(KeyHdr));
        io->read(0, sizeof(KeyHdr), (void *)block.get());
        header->load(*(KeyHdr*)block.get());
        unsigned nodeSize = header->getNodeSize();

        if (!optRaw)
        {
            printf("Key '%s'\nkeySize=%d NumParts=%x, Top=%d\n", keyName, key_size, index->numParts(), index->isTopLevelKey());
            printf("File size = %"I64F"d, nodes = %"I64F"d\n", in->size(), in->size() / nodeSize - 1);
            printf("rootoffset=%"I64F"d[%"I64F"d]\n", header->getRootFPos(), header->getRootFPos()/nodeSize);
        }
        char *buffer = (char*)alloca(key_size);

        if (globals->hasProp("node"))
        {
            if (stricmp(globals->queryProp("node"), "all")==0)
            {
            }
            else
            {
                int node = globals->getPropInt("node");
                if (node != 0)
                    index->dumpNode(stdout, node * nodeSize, globals->getPropInt("recs", 0), optRaw);
            }
        }
        else if (globals->hasProp("fpos"))
        {
            index->dumpNode(stdout, globals->getPropInt("fpos"), globals->getPropInt("recs", 0), optRaw);
        }
        else
        {
            bool backwards=false;
            bool ok;
            if (globals->hasProp("end"))
            {
                memset(buffer, 0, key_size);
                strcpy(buffer, globals->queryProp("end"));
                ok = cursor->ltEqual(buffer, buffer);
                backwards = true;
            }
            else if (globals->hasProp("start"))
            {
                memset(buffer, 0, key_size);
                strcpy(buffer, globals->queryProp("start"));
                ok = cursor->gtEqual(buffer, buffer);
            }
            else
                ok = cursor->first(buffer);
            
            unsigned count = globals->getPropInt("recs", 1);
            while (ok && count--)
            {
                offset_t pos = cursor->getFPos();
                unsigned __int64 seq = cursor->getSequence();
                size32_t size = cursor->getSize();
                if (optRaw)
                {
                    fwrite(buffer, 1, size, stdout);
                }
                else if (optHex)
                {
                    for (unsigned i = 0; i < size; i++)
                        printf("%02x", ((unsigned char) buffer[i]) & 0xff);
                    printf("  :%"I64F"u:%012"I64F"x\n", seq, pos);
                }
                else
                    printf("%.*s  :%"I64F"u:%012"I64F"x\n", size, buffer, seq, pos);
                if (backwards)
                    ok = cursor->prev(buffer);
                else
                    ok = cursor->next(buffer);
            }
        }
    }
    catch (IException *E)
    {
        StringBuffer msg;
        E->errorMessage(msg);
        E->Release();
        fatal("%s", msg.str());
    }
    releaseAtoms();
    ExitModuleObjects();
    return 0;
}