34#include <sys/socket.h>
47#include "DaemonCommandHandler.h"
48#include "Connection.h"
50#include "PPTStreamBuf.h"
51#include "PPTProtocolNames.h"
52#include "BESXMLUtils.h"
53#include "BESInternalFatalError.h"
54#include "BESInternalError.h"
55#include "BESSyntaxUserError.h"
59#include "TheBESKeys.h"
61#include "BESXMLWriter.h"
62#include "BESDaemonConstants.h"
66extern void unblock_signals();
67extern int start_master_beslistener();
68extern bool stop_all_beslisteners(
int);
69extern int master_beslistener_status;
71void DaemonCommandHandler::load_include_files(vector<string> &files,
const string &keys_file_name)
73 vector<string>::iterator i = files.begin();
74 while (i != files.end())
75 load_include_file(*i++, keys_file_name);
87void DaemonCommandHandler::load_include_file(
const string &files,
const string &keys_file_name)
90 BESFSFile allfiles(files);
94 if (!files.empty() && files[0] ==
'/') {
95 newdir = allfiles.getDirName();
100 BESFSFile currfile(keys_file_name);
101 string currdir = currfile.getDirName();
103 string alldir = allfiles.getDirName();
105 if ((currdir ==
"./" || currdir ==
".") && (alldir ==
"./" || alldir ==
".")) {
109 if (alldir ==
"./" || alldir ==
".") {
113 newdir = currdir +
"/" + alldir;
120 BESFSDir fsd(newdir, allfiles.getFileName());
121 BESFSDir::fileIterator i = fsd.beginOfFileList();
122 BESFSDir::fileIterator e = fsd.endOfFileList();
123 for (; i != e; i++) {
124 d_pathnames.insert(make_pair((*i).getFileName(), (*i).getFullPath()));
128DaemonCommandHandler::DaemonCommandHandler(
const string &config) :
132 string d_bes_name = d_bes_conf.substr(d_bes_conf.find_last_of(
'/') + 1);
133 d_pathnames.insert(make_pair(d_bes_name, d_bes_conf));
140 BESDEBUG(
"besdaemon",
"DaemonCommandHandler() - Found BES.Include: " << found << endl);
144 load_include_files(vals, config);
150 while (i != d_pathnames.end()) {
151 BESDEBUG(
"besdaemon",
152 "DaemonCommandHandler() - d_pathnames: [" << (*i).first <<
"]: " << d_pathnames[(*i).first] << endl);
160 if (!found) d_log_file_name =
"";
169DaemonCommandHandler::hai_command DaemonCommandHandler::lookup_command(
const string &command)
171 if (command ==
"StopNow")
173 else if (command ==
"Start")
175 else if (command ==
"Exit")
177 else if (command ==
"GetConfig")
178 return HAI_GET_CONFIG;
179 else if (command ==
"SetConfig")
180 return HAI_SET_CONFIG;
181 else if (command ==
"TailLog")
183 else if (command ==
"GetLogContexts")
184 return HAI_GET_LOG_CONTEXTS;
185 else if (command ==
"SetLogContext")
186 return HAI_SET_LOG_CONTEXT;
196static char *read_file(
const string &name)
199 ifstream::pos_type size;
201 ifstream file(name.c_str(), ios::in | ios::binary | ios::ate);
202 if (file.is_open()) {
204 memblock =
new char[((
unsigned long) size) + 1];
205 file.seekg(0, ios::beg);
206 file.read(memblock, size);
209 memblock[size] =
'\0';
214 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
227static void write_file(
const string &name,
const string &buffer)
230 string tmp_name = name +
".tmp";
231 ofstream outfile(tmp_name.c_str(), std::ios_base::out);
232 if (outfile.is_open()) {
234 outfile.write(buffer.data(), buffer.size());
239 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
245 ostringstream backup_name;
246 backup_name << name <<
"." << getpid();
247 if (access(backup_name.str().c_str(), F_OK) == -1) {
248 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - No backup file yet" << endl);
250 if (rename(name.c_str(), backup_name.str().c_str()) == -1) {
251 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - : Could not backup file " << name <<
" to " << backup_name.str() << endl);
253 err <<
"(" << errno <<
") " << strerror(errno);
254 throw BESInternalError(
"Could not backup config file: " + name +
": " + err.str(), __FILE__, __LINE__);
259 if (rename(tmp_name.c_str(), name.c_str()) == -1) {
260 BESDEBUG(
"besdaemon",
"DaemonCommandHandler()::write_file() - : Could not complete write " << name <<
" to " << backup_name.str() << endl);
262 err <<
"(" << errno <<
") " << strerror(errno);
263 throw BESInternalError(
"Could not write config file:" + name +
": " + err.str(), __FILE__, __LINE__);
270static unsigned long move_forward_lines(ifstream &infile,
unsigned long lines)
272 unsigned long count = 0;
273 while (count < lines && !infile.eof() && !infile.fail()) {
274 infile.ignore(1024,
'\n');
284static unsigned long count_lines(ifstream &infile, ifstream::pos_type pos)
286 infile.seekg(pos, ios::beg);
287 unsigned long count = 0;
288 while (!infile.eof() && !infile.fail()) {
289 infile.ignore(1024,
'\n');
300static char *read_file_data(ifstream &infile)
303 ifstream::pos_type start_pos = infile.tellg();
304 infile.seekg(0, ios::end);
305 ifstream::pos_type end_pos = infile.tellg();
307 unsigned long size = (end_pos > start_pos) ? end_pos - start_pos : 0;
308 char *memblock =
new char[size + 1];
310 infile.seekg(start_pos, ios::beg);
311 infile.read(memblock, size);
314 memblock[size] =
'\0';
320static ifstream::pos_type last_start_pos = 0;
321static unsigned long last_start_line = 0;
330static char *get_bes_log_lines(
const string &log_file_name,
unsigned long num_lines)
332 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
333 if (!infile.is_open())
334 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
336 if (num_lines == 0) {
338 infile.seekg(0, ios::beg);
339 return read_file_data(infile);
343 unsigned long count = count_lines(infile, last_start_pos) + last_start_line;
347 unsigned long new_start_line = (count >= num_lines) ? count - num_lines + 1 : 0;
350 infile.seekg(last_start_pos, ios::beg);
352 count = move_forward_lines(infile, new_start_line - last_start_line);
355 last_start_line = new_start_line;
356 last_start_pos = infile.tellg();
358 return read_file_data(infile);
368void DaemonCommandHandler::execute_command(
const string &command,
BESXMLWriter &writer)
371 xmlNode *root_element = NULL;
372 xmlNode *current_node = NULL;
376 vector<string> parseerrors;
382 doc = xmlParseDoc((
const xmlChar*) command.c_str());
387 vector<string>::const_iterator i = parseerrors.begin();
388 vector<string>::const_iterator e = parseerrors.end();
389 for (; i != e; i++) {
390 if (!isfirst && (*i).compare(0, 6,
"Entity") == 0) {
397 throw BESSyntaxUserError(err, __FILE__, __LINE__);
401 root_element = xmlDocGetRootElement(doc);
403 throw BESSyntaxUserError(
"There is no root element in the xml document", __FILE__, __LINE__);
408 map<string, string> props;
410 if (root_name !=
"BesAdminCmd") {
411 string err = (string)
"The root element should be a BesAdminCmd element, name is "
412 + (
char *) root_element->name;
413 throw BESSyntaxUserError(err, __FILE__, __LINE__);
415 if (root_val !=
"") {
416 string err = (string)
"The BesAdminCmd element must not contain a value, " + root_val;
417 throw BESSyntaxUserError(err, __FILE__, __LINE__);
422 current_node = root_element->children;
424 while (current_node) {
425 if (current_node->type == XML_ELEMENT_NODE) {
426 string node_name = (
char *) current_node->name;
427 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Looking for command " << node_name << endl);
435 switch (lookup_command(node_name)) {
437 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received StopNow" << endl);
439 if (stop_all_beslisteners(SIGTERM) ==
false) {
440 if (master_beslistener_status == BESLISTENER_RUNNING) {
441 throw BESInternalFatalError(
"Could not stop the master beslistener", __FILE__, __LINE__);
444 throw BESSyntaxUserError(
445 "Received Stop command but the master beslistener was likely already stopped",
450 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
451 throw BESInternalFatalError(
"Could not write <hai:OK> element ", __FILE__, __LINE__);
452 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
453 throw BESInternalFatalError(
"Could not end <hai:OK> element ", __FILE__, __LINE__);
458 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received Start" << endl);
462 if (master_beslistener_status == BESLISTENER_RUNNING) {
463 throw BESSyntaxUserError(
"Received Start command but the master beslistener is already running",
467 if (start_master_beslistener() == 0) {
468 BESDEBUG(
"besdaemon",
469 "DaemonCommandHandler::execute_command() - Error starting; master_beslistener_status = " << master_beslistener_status << endl);
470 if (master_beslistener_status == BESLISTENER_RUNNING) {
471 throw BESSyntaxUserError(
472 "Received Start command but the master beslistener is already running", __FILE__,
476 throw BESInternalFatalError(
"Could not start the master beslistener", __FILE__, __LINE__);
486 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
487 throw BESInternalFatalError(
"Could not write <hai:OK> element ", __FILE__, __LINE__);
488 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
489 throw BESInternalFatalError(
"Could not end <hai:OK> element ", __FILE__, __LINE__);
495 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received Exit" << endl);
496 stop_all_beslisteners(SIGTERM);
501 case HAI_GET_CONFIG: {
502 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received GetConfig" << endl);
504 if (d_pathnames.empty()) {
505 throw BESInternalFatalError(
"There are no known configuration files for this BES!", __FILE__,
511 map<string, string>::iterator i = d_pathnames.begin();
512 while (i != d_pathnames.end()) {
513 BESDEBUG(
"besdaemon",
514 "DaemonCommandHandler::execute_command() - Retrieving " << (*i).first <<
": " << d_pathnames[(*i).first] << endl);
516 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:BesConfig") < 0)
517 throw BESInternalFatalError(
"Could not write <hai:Config> element ", __FILE__, __LINE__);
519 if (xmlTextWriterWriteAttribute(writer.get_writer(), (
const xmlChar*)
"module",
520 (
const xmlChar*) (*i).first.c_str()) < 0)
521 throw BESInternalFatalError(
"Could not write fileName attribute ", __FILE__, __LINE__);
523 char *content = read_file(d_pathnames[(*i).first]);
525 BESDEBUG(
"besdaemon_verbose",
"DaemonCommandHandler::execute_command() - content: " << content << endl);
526 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*)
"\n") < 0)
527 throw BESInternalFatalError(
"Could not write newline", __FILE__, __LINE__);
529 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*) content) < 0)
530 throw BESInternalFatalError(
"Could not write line", __FILE__, __LINE__);
541 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
542 throw BESInternalFatalError(
"Could not end <hai:BesConfig> element ", __FILE__, __LINE__);
549 case HAI_SET_CONFIG: {
550 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetConfig" << endl);
551 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"module");
552 if (!xml_char_module) {
553 throw BESSyntaxUserError(
"SetConfig missing module ", __FILE__, __LINE__);
555 string module = (
const char *) xml_char_module;
556 xmlFree(xml_char_module);
558 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetConfig; module: " << module << endl);
560 xmlChar *file_content = xmlNodeListGetString(doc, current_node->children,
true);
562 throw BESInternalFatalError(
"SetConfig missing content, no changes made ", __FILE__, __LINE__);
564 string content = (
const char *) file_content;
565 xmlFree(file_content);
566 BESDEBUG(
"besdaemon_verbose",
567 "DaemonCommandHandler::execute_command() - Received SetConfig; content: " << endl << content << endl);
569 write_file(d_pathnames[module], content);
571 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
572 throw BESInternalFatalError(
"Could not write <hai:OK> element ", __FILE__, __LINE__);
574 if (xmlTextWriterWriteString(writer.get_writer(),
575 (
const xmlChar*)
"\nPlease restart the server for these changes to take affect.\n") < 0)
576 throw BESInternalFatalError(
"Could not write newline", __FILE__, __LINE__);
578 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
579 throw BESInternalFatalError(
"Could not end <hai:OK> element ", __FILE__, __LINE__);
585 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received TailLog" << endl);
587 xmlChar *xml_char_lines = xmlGetProp(current_node, (
const xmlChar*)
"lines");
588 if (!xml_char_lines) {
589 throw BESSyntaxUserError(
"TailLog missing lines attribute ", __FILE__, __LINE__);
593 long num_lines = strtol((
const char *) xml_char_lines, &endptr, 10 );
594 if (num_lines == 0 && endptr == (
const char *) xml_char_lines) {
596 err <<
"(" << errno <<
") " << strerror(errno);
597 throw BESSyntaxUserError(
"TailLog lines attribute bad value: " + err.str(), __FILE__, __LINE__);
600 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:BesLog") < 0)
601 throw BESInternalFatalError(
"Could not write <hai:BesLog> element ", __FILE__, __LINE__);
603 BESDEBUG(
"besdaemon",
604 "DaemonCommandHandler::execute_command() - TailLog: log file:" << d_log_file_name <<
", lines: " << num_lines << endl);
606 char *content = get_bes_log_lines(d_log_file_name, num_lines);
608 BESDEBUG(
"besdaemon_verbose",
"DaemonCommandHandler::execute_command() - Returned lines: " << content << endl);
609 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*)
"\n") < 0)
610 throw BESInternalFatalError(
"Could not write newline", __FILE__, __LINE__);
612 if (xmlTextWriterWriteString(writer.get_writer(), (
const xmlChar*) content) < 0)
613 throw BESInternalFatalError(
"Could not write line", __FILE__, __LINE__);
624 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
625 throw BESInternalFatalError(
"Could not end <hai:BesLog> element ", __FILE__, __LINE__);
630 case HAI_GET_LOG_CONTEXTS: {
631 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received GetLogContexts" << endl);
633 BESDEBUG(
"besdaemon",
634 "DaemonCommandHandler::execute_command() - There are " << BESDebug::debug_map().size() <<
" Contexts" << endl);
635 if (BESDebug::debug_map().size()) {
636 auto i = BESDebug::debug_map().begin();
637 while (i != BESDebug::debug_map().end()) {
638 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:LogContext") < 0)
639 throw BESInternalFatalError(
"Could not write <hai:LogContext> element ", __FILE__,
642 if (xmlTextWriterWriteAttribute(writer.get_writer(), (
const xmlChar*)
"name",
643 (
const xmlChar*) (*i).first.c_str()) < 0)
644 throw BESInternalFatalError(
"Could not write 'name' attribute ", __FILE__, __LINE__);
646 string state = (*i).second ?
"on" :
"off";
647 if (xmlTextWriterWriteAttribute(writer.get_writer(), (
const xmlChar*)
"state",
648 (
const xmlChar*) state.c_str()) < 0)
649 throw BESInternalFatalError(
"Could not write 'state' attribute ", __FILE__, __LINE__);
651 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
652 throw BESInternalFatalError(
"Could not end <hai:LogContext> element ", __FILE__,
662 case HAI_SET_LOG_CONTEXT: {
663 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Received SetLogContext" << endl);
665 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"name");
666 if (!xml_char_module) {
667 throw BESSyntaxUserError(
"SetLogContext missing name ", __FILE__, __LINE__);
669 string name = (
const char *) xml_char_module;
670 xmlFree(xml_char_module);
672 xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"state");
673 if (!xml_char_module) {
674 throw BESSyntaxUserError(
"SetLogContext missing state ", __FILE__, __LINE__);
676 bool state = strcmp((
const char *) xml_char_module,
"on") == 0;
677 xmlFree(xml_char_module);
679 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - Before setting " << name <<
" to " << state << endl);
687 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::execute_command() - After setting " << name <<
" to " << state << endl);
689 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:OK") < 0)
690 throw BESInternalFatalError(
"Could not write <hai:OK> element ", __FILE__, __LINE__);
691 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
692 throw BESInternalFatalError(
"Could not end <hai:OK> element ", __FILE__, __LINE__);
698 throw BESSyntaxUserError(
"Command " + node_name +
" unknown.", __FILE__, __LINE__);
702 current_node = current_node->next;
717 if (xmlTextWriterStartElement(writer.get_writer(), (
const xmlChar*)
"hai:BESError") < 0)
722 if (xmlTextWriterWriteElement(writer.get_writer(), (
const xmlChar*)
"hai:Type", (
const xmlChar*) oss.str().c_str())
725 if (xmlTextWriterWriteElement(writer.get_writer(), (
const xmlChar*)
"hai:Message",
729 if (xmlTextWriterEndElement(writer.get_writer()) < 0)
743 map<string, string> extensions;
748 done = c->receive(extensions, &ss);
750 if (extensions[
"status"] == c->exit()) {
754 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Received PPT_EXIT_NOW in an extension chunk." << endl);
758 int descript = c->getSocket()->getSocketDescriptor();
759 unsigned int bufsize = c->getSendChunkSize();
762 std::streambuf *holder;
763 holder = cout.rdbuf();
769 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - cmd: " << ss.str() << endl);
771 execute_command(ss.str(), writer);
772 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Transmitting response." << endl);
774 cout << writer.get_doc() << endl;
785 map<string, string> extensions;
786 extensions[
"status"] =
"error";
789 case BES_INTERNAL_ERROR:
790 case BES_INTERNAL_FATAL_ERROR:
791 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Internal/Fatal ERROR: " << e.
get_message() << endl);
792 extensions[
"exit"] =
"true";
793 c->sendExtensions(extensions);
794 send_bes_error(writer, e);
797 case BES_SYNTAX_USER_ERROR:
798 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Syntax ERROR: " << e.
get_message() << endl);
799 c->sendExtensions(extensions);
800 send_bes_error(writer, e);
804 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - ERROR (unknown command): " << ss.str() << endl);
805 extensions[
"exit"] =
"true";
806 c->sendExtensions(extensions);
807 send_bes_error(writer, e);
812 cout << writer.get_doc() << endl;
822 c->closeConnection();
824 BESDEBUG(
"besdaemon",
"DaemonCommandHandler::handle() - Command Processing completed. " << endl);
835 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
Base exception class for the BES with basic string message.
unsigned int get_bes_error_type() const
Return the return code for this error class.
std::string get_message() const
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
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
void dump(std::ostream &strm) const override
dumps information about this object
void handle(Connection *c) override
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
static TheBESKeys * TheKeys()
Access to the singleton.
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.