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;