/****************************************************************************
|
| Copyright (c) 2006 Novell, Inc.
| All Rights Reserved.
|
| This program is free software; you can redistribute it and/or
| modify it under the terms of version 2 of the GNU General Public License as
| published by the Free Software Foundation.
|
| 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, contact Novell, Inc.
|
| To contact Novell about this file by physical or electronic mail,
| you may find current contact information at www.novell.com
|
|***************************************************************************
/**
@author Brad Nicholes
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "omcclp.h"
#include "omcclpc.h"
#include "omcclpprogram.h"
#include "omcclpcommand.h"
#include "omcclpcommon.h"
#include "omcclpcmdalias.h"
#include "omcclpdenv.h"
#include <readline/readline.h>
#include <readline/history.h>
#include <signal.h>
#include <pthread.h>
#include <openwbem/OW_Assertion.hpp>
#include <openwbem/OW_CmdLineParser.hpp>
#include <openwbem/OW_CerrLogger.hpp>
#include <openwbem/OW_Format.hpp>
#include <openwbem/OW_Format.hpp>
#include <openwbem/OW_Select.hpp>
using namespace OW_NAMESPACE;
using namespace OMCCLP;
void init_rl ();
UnnamedPipeRef sigPipe(UnnamedPipe::createUnnamedPipe());
enum tag_OPTIONS
{
E_CMDOPT_HELP,
E_CMDOPT_URL, // specify URL
E_CMDOPT_NS, // specify namespace
E_CMDOPT_CONFIG, // specify configuration file
E_CMDOPT_CMD, // specify a single command
E_CMDOPT_DEBUG, // specify a debug mode
};
CmdLineParser::Option g_options[] =
{
{E_CMDOPT_CMD, 'c', "command", CmdLineParser::E_REQUIRED_ARG, 0, "Execute a single command from the command line."},
{E_CMDOPT_CONFIG, 'f', "config", CmdLineParser::E_REQUIRED_ARG, 0, "Alternate configuration file. Default is omcclp.conf."},
{E_CMDOPT_HELP, 'h', "help", CmdLineParser::E_NO_ARG, 0, "Show help about options."},
{E_CMDOPT_NS, 'n', "ns", CmdLineParser::E_REQUIRED_ARG, 0, "Alternate CIM namespace to be used in place of the namespace specified in the configuration file"},
{E_CMDOPT_URL, 'u', "url", CmdLineParser::E_REQUIRED_ARG, 0, "Alternate CIM URL to be used in place of the URL specified in the configuration file."},
{E_CMDOPT_DEBUG, 'd', "debug", CmdLineParser::E_NO_ARG, 0, "Start the CLP application in debug mode."},
{0, 0, 0, CmdLineParser::E_NO_ARG, 0, 0}
};
OMCCLPProgram *gclp = NULL; // global pointer to the main program object
void usage()
{
cerr << PROG_NAME << " " << PROG_VERSION
<< " Server Management Command Line Protocol" << CLPENDL;
cerr << "Copyright (C) 2006 by Novell Inc." << CLPENDL;
cerr << "Usage: " << PROG_NAME << " [OPTIONS]" << CLPENDL;
cout << CLPENDL << CmdLineParser::getUsage(g_options) << CLPENDL;
}
void printCmdLineParserExceptionMessage(CmdLineParserException& e)
{
switch (e.getErrorCode())
{
case CmdLineParser::E_INVALID_OPTION:
cerr << "unknown option: " << e.getMessage() << CLPENDL;
break;
case CmdLineParser::E_MISSING_ARGUMENT:
cerr << "missing argument for option: " << e.getMessage() << CLPENDL;
break;
case CmdLineParser::E_INVALID_NON_OPTION_ARG:
cerr << "invalid non-option argument: " << e.getMessage() << CLPENDL;
break;
case CmdLineParser::E_MISSING_OPTION:
cerr << "missing required option: " << e.getMessage() << CLPENDL;
break;
default:
cerr << "failed parsing command line options: " << e << CLPENDL;
break;
}
}
namespace OMCCLP {
///////////////////////////////////////////////////////////
void OMCCLPServerThread::shutdown()
{
OW_LOG_DEBUG(m_logger, "OMCCLPServer::shuttingDown called...");
if(!m_running)
{
OW_LOG_INFO(m_logger, "OMCCLPServer::shuttingDown called, "
"but OMCCLPServer is not running");
return;
}
m_shuttingDown = true;
// Tell run method to wake up
m_sigPipe->writeInt(1);
OW_LOG_DEBUG(m_logger, "OMCCLPServer::shuttingDown waiting on thread barrier");
m_threadBarrier.wait();
OW_LOG_DEBUG(m_logger, "OMCCLPServer::shuttingDown shutdown complete");
}
/* This thread main function should be roughly
equivalent to the main() function in the
OMCCLPD.cpp file. */
Int32 OMCCLPServerThread::run()
{
int cc;
bool initialized = false;
OMCClpdEnvRef env = OMCClpdEnv::instance();
LoggerRef logger(new CerrLogger);
NonRecursiveMutexLock localLock(m_guard);
localLock.release();
m_sigPipe = env->getSigPipe();
try
{
if (m_data_filename.length())
env->setConfigItem(OMCClpdConfigOpts::CONFIG_FILE_opt,
m_data_filename);
env->init();
m_logger = env->getLogger(OMCClpdEnv::COMPONENT_NAME);
initialized = true;
}
catch (Exception& e)
{
cerr << "* EXCEPTION CAUGHT IN clp server startup!" << CLPENDL;
cerr << Format("* %1", e) << CLPENDL;
}
catch (std::exception& e)
{
cerr << "* EXCEPTION CAUGHT IN clp server startup!" << CLPENDL;
cerr << Format("* Message: %1", e.what()) << CLPENDL;
}
catch (...)
{
cerr << "* UNKNOWN EXCEPTION CAUGHT IN clpd MAIN!" << CLPENDL;
}
if (initialized)
{
OW_LOG_DEBUG(m_logger, "clpd Environment initialized");
try
{
int sig;
env->startServices();
m_running = true;
OW_LOG_INFO(m_logger, "clpd is now running");
m_condition.notifyAll();
while(!m_shuttingDown)
{
// runSelectEngine will only return once something has been put into
// the signal pipe or an error has happened
env->runSelectEngine();
if ((cc = sigPipe->readInt(&sig)) == -1)
{
continue;
}
OW_LOG_INFO(m_logger, "clp server received shutdown notification."
" Initiating shutdown.");
env->shutdown();
}
}
catch (Exception& e)
{
OW_LOG_FATAL_ERROR(m_logger, "* EXCEPTION CAUGHT IN clpd MAIN!");
OW_LOG_FATAL_ERROR(m_logger, Format("* %1", e));
}
catch (std::exception& e)
{
OW_LOG_FATAL_ERROR(m_logger, "* std::exception CAUGHT IN clpd MAIN!");
OW_LOG_FATAL_ERROR(m_logger, Format("* Message: %1", e.what()));
}
catch (...)
{
OW_LOG_FATAL_ERROR(m_logger, "* UNKNOWN EXCEPTION CAUGHT IN clpd MAIN!");
}
m_running = false;
OW_LOG_DEBUG(m_logger, "OMCCLPServer::run waiting to exit the CLP server thread");
m_threadBarrier.wait();
}
else
{
cerr << "Exiting CLP server thread" << CLPENDL;
m_condition.notifyAll();
return -1;
}
return 0;
}
///////////////////////////////////////////////////////////
void OMCCLPClientThread::shutdown()
{
if(!m_running)
{
return;
}
m_shuttingDown = true;
((OMCCLPClient*)gclp)->shutdown();
}
/* This thread main function should be roughly
equivalent to the main() function in the
OMCCLPC.cpp file. */
Int32 OMCCLPClientThread::run()
{
/*XXX Need to create and use a logger here
just like in the clp server thread.
The logger should be passed to the
OMCCLPClient object to be used there.*/
OMCCLPClient clp(cout);
int ret = 0;
// Set the global pointer to the program object so that
// it can be referenced by other objects.
gclp = &clp;
cout << "hello world" << CLPENDL;
/* Initialize the readline library */
init_rl();
try
{
if (clp.initializeCLPSession() &&
clp.createCLPSessionInfo(clp.getCIMClient()))
{
m_running = true;
StringArray cmdScripts = clp.getScriptFilenames();
if (!cmdScripts.empty())
{
for (int i=0; i < cmdScripts.size(); i++)
clp.run(cmdScripts[i]);
}
else
{
clp.run();
}
m_running = false;
}
}
catch (AssertionException& a)
{
cerr << "Caught Assertion: " << a << CLPENDL;
ret = 1;
}
catch (Exception& e)
{
cerr << e << CLPENDL;
ret = 1;
}
//cerr << "Exit recieved. Client returning" << CLPENDL;
/* Signal a shutdown */
sigPipe->writeInt(0);
return ret;
}
}
//////////////////////////////////////////////////////////////////////////////
void sigHandler(int sig)
{
if (sigPipe)
{
sigPipe->writeInt(sig);
}
}
//////////////////////////////////////////////////////////////////////////////
void
ignoreSignal(int sig)
{
signal(sig, SIG_IGN);
}
//////////////////////////////////////////////////////////////////////////////
void
handleSignal(int sig)
{
signal(sig, sigHandler);
}
//////////////////////////////////////////////////////////////////////////////
void
setupSigHandler(bool dbgFlg)
{
ignoreSignal(SIGINT);
handleSignal(SIGTERM);
handleSignal(SIGHUP);
ignoreSignal(SIGTTIN);
ignoreSignal(SIGTTOU);
ignoreSignal(SIGTSTP);
ignoreSignal(SIGPOLL);
ignoreSignal(SIGIO);
ignoreSignal(SIGPIPE);
ignoreSignal(SIGIOT);
ignoreSignal(SIGCONT);
ignoreSignal(SIGURG);
ignoreSignal(SIGXCPU);
ignoreSignal(SIGXFSZ);
ignoreSignal(SIGVTALRM);
ignoreSignal(SIGPROF);
ignoreSignal(SIGPWR);
}
/**
* Main program starting point
*/
int main (int argc, char *argv[])
{
Condition cond;
NonRecursiveMutex lock;
OMCCLPServerThread clpsvrt(cond, lock);
int cc, c;
cout << "hello world" << CLPENDL;
try
{
NonRecursiveMutexLock localLock(lock);
// parse command line, and build the urlList
CmdLineParser parser(argc, argv, g_options, CmdLineParser::E_NON_OPTION_ARGS_ALLOWED);
if (parser.isSet(E_CMDOPT_HELP))
{
usage();
return 0;
}
if (parser.isSet(E_CMDOPT_CONFIG))
{
String val = parser.getOptionValue(E_CMDOPT_CONFIG);
clpsvrt.setConfFilename(val);
}
else
clpsvrt.setConfFilename(OMCCLP_SYSCONF_DIR"/omcclp.conf");
if (parser.isSet(E_CMDOPT_DEBUG))
{
clpsvrt.setDebugMode(true);
}
/* Start the server and wait for it to initialize. */
clpsvrt.start();
cond.wait(localLock);
localLock.release();
if (clpsvrt.running())
{
OMCCLPClientThread clpt;
if (parser.isSet(E_CMDOPT_URL))
{
String val = parser.getOptionValue(E_CMDOPT_URL);
clpt.setCIMURL(val);
}
if (parser.isSet(E_CMDOPT_NS))
{
String val = parser.getOptionValue(E_CMDOPT_NS);
clpt.setCIMNamespace(val);
}
if (parser.isSet(E_CMDOPT_CONFIG))
{
String val = parser.getOptionValue(E_CMDOPT_CONFIG);
clpt.setConfFilename(val);
}
else
clpt.setConfFilename(OMCCLP_SYSCONF_DIR"/omcclp.conf");
if (parser.isSet(E_CMDOPT_CMD))
{
String val = parser.getOptionValue(E_CMDOPT_CMD);
clpt.setExecCmd(val);
}
clpt.setScriptFilenames(parser.getNonOptionArgs());
/* Start the client after the server has completed its startup. */
clpt.start();
setupSigHandler(true);
SelectTypeArray selArray;
selArray.push_back(sigPipe->getSelectObj());
sigPipe->setBlocking(UnnamedPipe::E_NONBLOCKING);
/* This select loop will only return if a signal
has been recieved and the sigpipe has been
written to. */
do {
Select::select(selArray);
if ((cc = sigPipe->readInt(&c)) == -1)
{
continue;
}
break;
} while (true);
/* Call the server and client shutdown to make sure
that everything has been cleaned up. */
clpt.shutdown();
clpsvrt.shutdown();
return 0;
}
}
catch (CmdLineParserException& e)
{
printCmdLineParserExceptionMessage(e);
usage();
}
catch (AssertionException& a)
{
cerr << "Caught Assertion: " << a << CLPENDL;
}
catch (CIMException& e)
{
cerr << "ERROR: CIMException:" << e.getMessage() << CLPENDL;
}
catch (Exception& e)
{
cerr << "ERROR: Exception:" << e.getMessage() << CLPENDL;
}
catch (std::exception& e)
{
cerr << "ERROR: sdtException:" << e.what() << CLPENDL;
}
catch (...)
{
cerr << "ERROR: UnknownException." << CLPENDL;
}
return 1;
}