31 #include <sys/types.h>
32 #include <sys/socket.h>
45 #include "DaemonCommandHandler.h"
46 #include "Connection.h"
48 #include "PPTStreamBuf.h"
49 #include "PPTProtocol.h"
50 #include "BESXMLUtils.h"
51 #include "BESInternalFatalError.h"
52 #include "BESInternalError.h"
53 #include "BESSyntaxUserError.h"
55 #include "BESFSFile.h"
57 #include "TheBESKeys.h"
59 #include "BESXMLWriter.h"
60 #include "BESDaemonConstants.h"
64 extern void unblock_signals();
65 extern int start_master_beslistener();
66 extern bool stop_all_beslisteners(
int);
67 extern int master_beslistener_status;
69 void DaemonCommandHandler::load_include_files(vector<string> &files,
const string &keys_file_name)
71 vector<string>::iterator i = files.begin();
72 while (i != files.end())
73 load_include_file(*i++, keys_file_name);
85 void DaemonCommandHandler::load_include_file(
const string &files,
const string &keys_file_name)
92 if (!files.empty() && files[0] ==
'/') {
93 newdir = allfiles.getDirName();
99 string currdir = currfile.getDirName();
101 string alldir = allfiles.getDirName();
103 if ((currdir ==
"./" || currdir ==
".") && (alldir ==
"./" || alldir ==
".")) {
107 if (alldir ==
"./" || alldir ==
".") {
111 newdir = currdir +
"/" + alldir;
118 BESFSDir fsd(newdir, allfiles.getFileName());
119 BESFSDir::fileIterator i = fsd.beginOfFileList();
120 BESFSDir::fileIterator e = fsd.endOfFileList();
121 for (; i != e; i++) {
122 d_pathnames.insert(make_pair((*i).getFileName(), (*i).getFullPath()));
126 DaemonCommandHandler::DaemonCommandHandler(
const string &config) :
130 string d_bes_name = d_bes_conf.substr(d_bes_conf.find_last_of(
'/') + 1);
131 d_pathnames.insert(make_pair(d_bes_name, d_bes_conf));
138 BESDEBUG(
"besdaemon",
"DaemonCommandHandler() - Found BES.Include: " << found << endl);
142 load_include_files(vals, config);
147 map<string, string>::iterator i = d_pathnames.begin();
148 while (i != d_pathnames.end()) {
149 BESDEBUG(
"besdaemon",
150 "DaemonCommandHandler() - d_pathnames: [" << (*i).first <<
"]: " << d_pathnames[(*i).first] << endl);
158 if (!found) d_log_file_name =
"";
167 DaemonCommandHandler::hai_command DaemonCommandHandler::lookup_command(
const string &command)
169 if (command ==
"StopNow")
171 else if (command ==
"Start")
173 else if (command ==
"Exit")
175 else if (command ==
"GetConfig")
176 return HAI_GET_CONFIG;
177 else if (command ==
"SetConfig")
178 return HAI_SET_CONFIG;
179 else if (command ==
"TailLog")
181 else if (command ==
"GetLogContexts")
182 return HAI_GET_LOG_CONTEXTS;
183 else if (command ==
"SetLogContext")
184 return HAI_SET_LOG_CONTEXT;
194 static char *read_file(
const string &name)
197 ifstream::pos_type size;
199 ifstream file(name.c_str(), ios::in | ios::binary | ios::ate);
200 if (file.is_open()) {
202 memblock =
new char[((
unsigned long) size) + 1];
203 file.seekg(0, ios::beg);
204 file.read(memblock, size);
207 memblock[size] =
'\0';
212 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
225 static void write_file(
const string &name,
const string &buffer)
228 string tmp_name = name +
".tmp";
229 ofstream outfile(tmp_name.c_str(), std::ios_base::out);
230 if (outfile.is_open()) {
232 outfile.write(buffer.data(), buffer.length());
237 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
243 ostringstream backup_name;
244 backup_name << name <<
"." << getpid();
245 if (access(backup_name.str().c_str(), F_OK) == -1) {
246 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - No backup file yet" << endl);
248 if (rename(name.c_str(), backup_name.str().c_str()) == -1) {
249 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - : Could not backup file " << name <<
" to " << backup_name.str() << endl);
251 err <<
"(" << errno <<
") " << strerror(errno);
252 throw BESInternalError(
"Could not backup config file: " + name +
": " + err.str(), __FILE__, __LINE__);
257 if (rename(tmp_name.c_str(), name.c_str()) == -1) {
258 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - : Could not complete write " << name <<
" to " << backup_name.str() << endl);
260 err <<
"(" << errno <<
") " << strerror(errno);
261 throw BESInternalError(
"Could not write config file:" + name +
": " + err.str(), __FILE__, __LINE__);
268 static unsigned long move_forward_lines(ifstream &infile,
unsigned long lines)
270 unsigned long count = 0;
271 while (count < lines && !infile.eof() && !infile.fail()) {
272 infile.ignore(1024,
'\n');
282 static unsigned long count_lines(ifstream &infile, ifstream::pos_type pos)
284 infile.seekg(pos, ios::beg);
285 unsigned long count = 0;
286 while (!infile.eof() && !infile.fail()) {
287 infile.ignore(1024,
'\n');
298 static char *read_file_data(ifstream &infile)
301 ifstream::pos_type start_pos = infile.tellg();
302 infile.seekg(0, ios::end);
303 ifstream::pos_type end_pos = infile.tellg();
305 unsigned long size = (end_pos > start_pos) ? end_pos - start_pos : 0;
306 char *memblock =
new char[size + 1];
308 infile.seekg(start_pos, ios::beg);
309 infile.read(memblock, size);
312 memblock[size] =
'\0';
318 static ifstream::pos_type last_start_pos = 0;
319 static unsigned long last_start_line = 0;
328 static char *get_bes_log_lines(
const string &log_file_name,
unsigned long num_lines)
330 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
331 if (!infile.is_open())
332 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
334 if (num_lines == 0) {
336 infile.seekg(0, ios::beg);
337 return read_file_data(infile);
341 unsigned long count = count_lines(infile, last_start_pos) + last_start_line;
345 unsigned long new_start_line = (count >= num_lines) ? count - num_lines + 1 : 0;
348 infile.seekg(last_start_pos, ios::beg);
350 count = move_forward_lines(infile, new_start_line - last_start_line);
353 last_start_line = new_start_line;
354 last_start_pos = infile.tellg();
356 return read_file_data(infile);
366 void DaemonCommandHandler::execute_command(
const string &command,
BESXMLWriter &writer)
369 xmlNode *root_element = NULL;
370 xmlNode *current_node = NULL;
374 vector<string> parseerrors;
380 doc = xmlParseDoc((
const xmlChar*) command.c_str());
385 vector<string>::const_iterator i = parseerrors.begin();
386 vector<string>::const_iterator e = parseerrors.end();
387 for (; i != e; i++) {
388 if (!isfirst && (*i).compare(0, 6,
"Entity") == 0) {
399 root_element = xmlDocGetRootElement(doc);
401 throw BESSyntaxUserError(
"There is no root element in the xml document", __FILE__, __LINE__);
406 map<string, string> props;
408 if (root_name !=
"BesAdminCmd") {
409 string err = (string)
"The root element should be a BesAdminCmd element, name is "
410 + (
char *) root_element->name;
413 if (root_val !=
"") {
414 string err = (string)
"The BesAdminCmd element must not contain a value, " + root_val;
420 current_node = root_element->children;
422 while (current_node) {
423 if (current_node->type == XML_ELEMENT_NODE) {
424 string node_name = (
char *) current_node->name;
425 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Looking for command " << node_name << endl);
433 switch (lookup_command(node_name)) {
435 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received StopNow" << endl);
437 if (stop_all_beslisteners(SIGTERM) ==
false) {
438 if (master_beslistener_status == BESLISTENER_RUNNING) {
443 "Received Stop command but the master beslistener was likely already stopped",
448 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
450 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
456 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received Start" << endl);
460 if (master_beslistener_status == BESLISTENER_RUNNING) {
461 throw BESSyntaxUserError(
"Received Start command but the master beslistener is already running",
465 if (start_master_beslistener() == 0) {
466 BESDEBUG(
"besdaemon",
467 "DaemonCommandHandler::execute_command() - Error starting; master_beslistener_status = " << master_beslistener_status << endl);
468 if (master_beslistener_status == BESLISTENER_RUNNING) {
470 "Received Start command but the master beslistener is already running", __FILE__,
484 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
486 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
493 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received Exit" << endl);
494 stop_all_beslisteners(SIGTERM);
499 case HAI_GET_CONFIG: {
500 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received GetConfig" << endl);
502 if (d_pathnames.empty()) {
509 map<string, string>::iterator i = d_pathnames.begin();
510 while (i != d_pathnames.end()) {
511 BESDEBUG(
"besdaemon",
512 "DaemonCommandHandler::execute_command() - Retrieving " << (*i).first <<
": " << d_pathnames[(*i).first] << endl);
514 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:BesConfig") < 0)
517 if (xmlTextWriterWriteAttribute(writer.get_writer(), (
const xmlChar*)
"module",
518 (
const xmlChar*) (*i).first.c_str()) < 0)
521 char *content = read_file(d_pathnames[(*i).first]);
523 BESDEBUG(
"besdaemon_verbose",
"DaemonCommandHandler::execute_command() - content: " << content << endl);
524 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*)
"\n") < 0)
527 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*) content) < 0)
539 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
547 case HAI_SET_CONFIG: {
548 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetConfig" << endl);
549 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"module");
550 if (!xml_char_module) {
553 string module = (
const char *) xml_char_module;
554 xmlFree(xml_char_module);
556 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetConfig; module: " << module << endl);
558 xmlChar *file_content = xmlNodeListGetString(doc, current_node->children,
true);
562 string content = (
const char *) file_content;
563 xmlFree(file_content);
564 BESDEBUG(
"besdaemon_verbose",
565 "DaemonCommandHandler::execute_command() - Received SetConfig; content: " << endl << content << endl);
567 write_file(d_pathnames[module], content);
569 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
572 if (xmlTextWriterWriteString(writer.get_writer(),
573 (
const xmlChar*)
"\nPlease restart the server for these changes to take affect.\n") < 0)
576 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
583 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received TailLog" << endl);
585 xmlChar *xml_char_lines = xmlGetProp(current_node, (
const xmlChar*)
"lines");
586 if (!xml_char_lines) {
591 long num_lines = strtol((
const char *) xml_char_lines, &endptr, 10 );
592 if (num_lines == 0 && endptr == (
const char *) xml_char_lines) {
594 err <<
"(" << errno <<
") " << strerror(errno);
595 throw BESSyntaxUserError(
"TailLog lines attribute bad value: " + err.str(), __FILE__, __LINE__);
598 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:BesLog") < 0)
601 BESDEBUG(
"besdaemon",
602 "DaemonCommandHandler::execute_command() - TailLog: log file:" << d_log_file_name <<
", lines: " << num_lines << endl);
604 char *content = get_bes_log_lines(d_log_file_name, num_lines);
606 BESDEBUG(
"besdaemon_verbose",
"DaemonCommandHandler::execute_command() - Returned lines: " << content << endl);
607 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*)
"\n") < 0)
610 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*) content) < 0)
622 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
628 case HAI_GET_LOG_CONTEXTS: {
629 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received GetLogContexts" << endl);
631 BESDEBUG(
"besdaemon",
632 "DaemonCommandHandler::execute_command() - There are " << BESDebug::debug_map().size() <<
" Contexts" << endl);
633 if (BESDebug::debug_map().size()) {
634 BESDebug::debug_citer i = BESDebug::debug_map().begin();
635 while (i != BESDebug::debug_map().end()) {
636 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:LogContext") < 0)
640 if (xmlTextWriterWriteAttribute(writer.get_writer(), (
const xmlChar*)
"name",
641 (
const xmlChar*) (*i).first.c_str()) < 0)
644 string state = (*i).second ?
"on" :
"off";
645 if (xmlTextWriterWriteAttribute(writer.get_writer(), (
const xmlChar*)
"state",
646 (
const xmlChar*) state.c_str()) < 0)
649 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
660 case HAI_SET_LOG_CONTEXT: {
661 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetLogContext" << endl);
663 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"name");
664 if (!xml_char_module) {
667 string name = (
const char *) xml_char_module;
668 xmlFree(xml_char_module);
670 xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"state");
671 if (!xml_char_module) {
674 bool state = strcmp((
const char *) xml_char_module,
"on") == 0;
675 xmlFree(xml_char_module);
677 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Before setting " << name <<
" to " << state << endl);
685 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - After setting " << name <<
" to " << state << endl);
687 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
689 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
700 current_node = current_node->next;
715 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:BESError") < 0)
720 if (xmlTextWriterWriteElement(writer.get_writer(), (
const xmlChar*)
"hai:Type", (
const xmlChar*) oss.str().c_str())
723 if (xmlTextWriterWriteElement(writer.get_writer(), (
const xmlChar*)
"hai:Message",
727 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
741 map<string, string> extensions;
746 done = c->receive(extensions, &ss);
748 if (extensions[
"status"] == c->exit()) {
752 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Received PPT_EXIT_NOW in an extension chunk." << endl);
756 int descript = c->getSocket()->getSocketDescriptor();
757 unsigned int bufsize = c->getSendChunkSize();
760 std::streambuf *holder;
761 holder = cout.rdbuf();
767 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - cmd: " << ss.str() << endl);
769 execute_command(ss.str(), writer);
770 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Transmitting response." << endl);
772 cout << writer.get_doc() << endl;
783 map<string, string> extensions;
784 extensions[
"status"] =
"error";
787 case BES_INTERNAL_ERROR:
788 case BES_INTERNAL_FATAL_ERROR:
789 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Internal/Fatal ERROR: " << e.
get_message() << endl);
790 extensions[
"exit"] =
"true";
791 c->sendExtensions(extensions);
792 send_bes_error(writer, e);
795 case BES_SYNTAX_USER_ERROR:
796 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Syntax ERROR: " << e.
get_message() << endl);
797 c->sendExtensions(extensions);
798 send_bes_error(writer, e);
802 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - ERROR (unknown command): " << ss.str() << endl);
803 extensions[
"exit"] =
"true";
804 c->sendExtensions(extensions);
805 send_bes_error(writer, e);
810 cout << writer.get_doc() << endl;
820 c->closeConnection();
822 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Command Processing completed. " << endl);
833 strm << BESIndent::LMarg <<
"DaemonCommandHandler::dump - (" << (
void *)
this <<
")" << endl;
static bool IsSet(const std::string &flagName)
see if the debug context flagName is set to true
static void Set(const std::string &flagName, bool value)
set the debug context to the specified value
Abstract exception class for the BES with basic string message.
virtual int get_bes_error_type()
Return the return code for this error class.
virtual std::string get_message()
get the error message for this exception
exception thrown if internal error encountered
exception thrown if an internal error is found and is fatal to the BES
error thrown if there is a user syntax error in the request or any other user error
static void GetNodeInfo(xmlNode *node, std::string &name, std::string &value, std::map< std::string, std::string > &props)
get the name, value if any, and any properties for the specified node
static void XMLErrorFunc(void *context, const char *msg,...)
error function used by libxml2 to report errors
virtual void handle(Connection *c)
virtual void dump(std::ostream &strm) const
dumps information about this object
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.