31 #include <sys/types.h>
32 #include <sys/socket.h>
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] ==
'/')
94 newdir = allfiles.getDirName();
101 string currdir = currfile.getDirName();
103 string alldir = allfiles.getDirName();
105 if ((currdir ==
"./" || currdir ==
".") && (alldir ==
"./" || alldir ==
"."))
111 if (alldir ==
"./" || alldir ==
".")
117 newdir = currdir +
"/" + alldir;
124 BESFSDir fsd(newdir, allfiles.getFileName());
129 d_pathnames.insert(make_pair((*i).getFileName(), (*i).getFullPath()));
137 string d_bes_name = d_bes_conf.substr(d_bes_conf.find_last_of(
'/') + 1);
138 d_pathnames.insert(make_pair(d_bes_name, d_bes_conf));
145 BESDEBUG(
"besdaemon",
"besdaemon: found BES.Include: " << found << endl);
150 load_include_files(vals, config);
156 map<string, string>::iterator i = d_pathnames.begin();
157 while (i != d_pathnames.end())
159 BESDEBUG(
"besdaemon",
"besdaemon: d_pathnames: [" << (*i).first <<
"]: " << d_pathnames[(*i).first] << endl);
168 d_log_file_name =
"";
177 DaemonCommandHandler::hai_command DaemonCommandHandler::lookup_command(
const string &command)
179 if (command ==
"StopNow")
181 else if (command ==
"Start")
183 else if (command ==
"Exit")
185 else if (command ==
"GetConfig")
186 return HAI_GET_CONFIG;
187 else if (command ==
"SetConfig")
188 return HAI_SET_CONFIG;
189 else if (command ==
"TailLog")
191 else if (command ==
"GetLogContexts")
192 return HAI_GET_LOG_CONTEXTS;
193 else if (command ==
"SetLogContext")
194 return HAI_SET_LOG_CONTEXT;
204 static char *read_file(
const string &name)
207 ifstream::pos_type size;
209 ifstream file(name.c_str(), ios::in | ios::binary | ios::ate);
213 memblock =
new char[((
unsigned long)size) + 1];
214 file.seekg(0, ios::beg);
215 file.read(memblock, size);
218 memblock[size] =
'\0';
224 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
237 static void write_file(
const string &name,
const string &buffer)
240 string tmp_name = name +
".tmp";
241 ofstream outfile(tmp_name.c_str(), std::ios_base::out);
242 if (outfile.is_open()) {
244 outfile.write(buffer.data(), buffer.length());
249 throw BESInternalError(
"Could not open config file:" + name, __FILE__, __LINE__);
255 ostringstream backup_name;
256 backup_name << name <<
"." << getpid();
257 if (access(backup_name.str().c_str(), F_OK) == -1) {
258 BESDEBUG(
"besdaemon",
"besdaemon: No backup file yet" << endl);
260 if (rename(name.c_str(), backup_name.str().c_str()) == -1) {
261 BESDEBUG(
"besdaemon",
"besdaemon: Could not backup file " << name <<
" to " << backup_name.str() << endl);
263 err <<
"(" << errno <<
") " << strerror(errno);
264 throw BESInternalError(
"Could not backup config file: " + name +
": " + err.str(), __FILE__, __LINE__);
269 if (rename(tmp_name.c_str(), name.c_str()) == -1) {
270 BESDEBUG(
"besdaemon",
"besdaemon: Could not complete write " << name <<
" to " << backup_name.str() << endl);
272 err <<
"(" << errno <<
") " << strerror(errno);
273 throw BESInternalError(
"Could not write config file:" + name +
": " + err.str(), __FILE__, __LINE__);
291 #define BES_LOG_CHARS_EST_PER_LINE 126
293 static char *get_bes_log_lines(
const string &log_file_name,
long num_lines)
295 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
296 if (!infile.is_open())
297 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
300 static ifstream::pos_type prev_end_pos = 0;
303 ifstream::pos_type start_from_pos = 0;
309 infile.seekg(0, ios::end);
310 ifstream::pos_type end_pos = infile.tellg();
311 long est_num_lines = end_pos / BES_LOG_CHARS_EST_PER_LINE;
312 if (num_lines >= est_num_lines)
313 infile.seekg(0, ios::beg);
315 infile.seekg((est_num_lines - num_lines) * BES_LOG_CHARS_EST_PER_LINE, ios::beg);
316 ifstream::pos_type start_from_pos = infile.tellg();
318 BESDEBUG(
"besdaemon",
"beadaemon: end_pos: " << end_pos <<
" start_from_pos: " << start_from_pos << endl);
324 while (!infile.eof() && !infile.fail())
326 infile.ignore(1024,
'\n');
334 if (count < num_lines) {
335 BESDEBUG(
"besdaemon",
"besdaemon: Retrying; Log length (count)" << count <<
", num_lines " << num_lines << endl);
337 long size = start_from_pos;
338 size -= ((num_lines - count + 10) * BES_LOG_CHARS_EST_PER_LINE);
339 infile.seekg(size, ios::beg);
340 start_from_pos = infile.tellg();
344 infile.seekg(start_from_pos, ios::beg);
346 BESDEBUG(
"besdaemon",
"besdaemon: Log length (count)" << count << endl);
348 if (count > num_lines)
351 long skip = count - num_lines;
352 while (skip > 0 && !infile.eof() && !infile.fail())
354 infile.ignore(1024,
'\n');
363 ifstream::pos_type start_pos = infile.tellg();
364 infile.seekg(0, ios::end);
365 ifstream::pos_type end_pos = infile.tellg();
367 unsigned long size = end_pos - start_pos;
368 char *memblock =
new char[size + 1];
370 infile.seekg(start_pos, ios::beg);
371 infile.read(memblock, size);
374 memblock[size] =
'\0';
388 static char *get_bes_log_lines(
const string &log_file_name,
long num_lines)
390 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
391 if (!infile.is_open())
392 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
395 static ifstream::pos_type prev_end_pos = 0;
396 static long prev_line_count = 0;
398 BESDEBUG(
"besdaemon",
"besdaemon: prev_line_count: " << prev_line_count << endl);
403 infile.seekg(prev_end_pos, ios::beg);
404 long count = prev_line_count;
405 while (!infile.eof() && !infile.fail())
407 infile.ignore(1024,
'\n');
413 prev_end_pos = infile.tellg();
414 prev_line_count = count - 1;
416 infile.seekg(0, ios::beg);
418 BESDEBUG(
"besdaemon",
"besdaemon: Log length " << count << endl);
420 if (count > num_lines)
423 long skip = count - num_lines;
426 infile.ignore(1024,
'\n');
428 }
while (skip > 0 && !infile.eof() && !infile.fail());
435 ifstream::pos_type start_pos = infile.tellg();
436 infile.seekg(0, ios::end);
437 ifstream::pos_type end_pos = infile.tellg();
439 unsigned long size = end_pos - start_pos;
440 char *memblock =
new char[size + 1];
442 infile.seekg(start_pos, ios::beg);
443 infile.read(memblock, size);
446 memblock[size] =
'\0';
456 static unsigned long move_forward_lines(ifstream &infile,
unsigned long lines)
458 unsigned long count = 0;
459 while (count < lines && !infile.eof() && !infile.fail()) {
460 infile.ignore(1024,
'\n');
470 static unsigned long count_lines(ifstream &infile, ifstream::pos_type pos)
472 infile.seekg(pos, ios::beg);
473 unsigned long count = 0;
474 while (!infile.eof() && !infile.fail()) {
475 infile.ignore(1024,
'\n');
486 static char *read_file_data(ifstream &infile)
489 ifstream::pos_type start_pos = infile.tellg();
490 infile.seekg(0, ios::end);
491 ifstream::pos_type end_pos = infile.tellg();
493 unsigned long size = (end_pos > start_pos) ? end_pos - start_pos : 0;
494 char *memblock =
new char[size + 1];
496 infile.seekg(start_pos, ios::beg);
497 infile.read(memblock, size);
500 memblock[size] =
'\0';
506 static ifstream::pos_type last_start_pos = 0;
507 static unsigned long last_start_line = 0;
516 static char *get_bes_log_lines(
const string &log_file_name,
unsigned long num_lines)
518 ifstream infile(log_file_name.c_str(), ios::in | ios::binary);
519 if (!infile.is_open())
520 throw BESInternalError(
"Could not open file for reading (" + log_file_name +
")", __FILE__, __LINE__);
523 static ifstream::pos_type last_start_pos = 0;
524 static unsigned long last_start_line = 0;
526 BESDEBUG(
"besdaemon",
"besdaemon: last_start_line " << last_start_line << endl);
527 if (num_lines == 0) {
529 infile.seekg(0, ios::beg);
530 return read_file_data(infile);
534 unsigned long count = count_lines(infile, last_start_pos) + last_start_line;
535 BESDEBUG(
"besdaemon",
"besdaemon: Log length " << count <<
" (started at " << last_start_line <<
")" << endl);
538 unsigned long new_start_line = (count >= num_lines) ? count - num_lines + 1: 0;
540 infile.seekg(last_start_pos, ios::beg);
542 count = move_forward_lines(infile, new_start_line - last_start_line);
543 BESDEBUG(
"besdaemon",
"besdaemon: count forward " << count <<
" lines." << endl);
545 last_start_line = new_start_line;
546 last_start_pos = infile.tellg();
548 return read_file_data(infile);
559 void DaemonCommandHandler::execute_command(
const string &command,
BESXMLWriter &writer)
564 xmlNode *root_element = NULL;
565 xmlNode *current_node = NULL;
569 vector<string> parseerrors;
574 doc = xmlParseDoc((
const xmlChar*) command.c_str());
576 doc = xmlParseDoc((xmlChar*) command.c_str());
581 vector<string>::const_iterator i = parseerrors.begin();
582 vector<string>::const_iterator e = parseerrors.end();
583 for (; i != e; i++) {
584 if (!isfirst && (*i).compare(0, 6,
"Entity") == 0) {
595 root_element = xmlDocGetRootElement(doc);
597 throw BESSyntaxUserError(
"There is no root element in the xml document", __FILE__, __LINE__);
602 map<string, string> props;
604 if (root_name !=
"BesAdminCmd") {
605 string err = (string)
"The root element should be a BesAdminCmd element, name is " + (
char *) root_element->name;
608 if (root_val !=
"") {
609 string err = (string)
"The BesAdminCmd element must not contain a value, " + root_val;
615 current_node = root_element->children;
617 while (current_node) {
618 if (current_node->type == XML_ELEMENT_NODE) {
619 string node_name = (
char *) current_node->name;
620 BESDEBUG(
"besdaemon",
"besdaemon: looking for command " << node_name << endl);
628 switch (lookup_command(node_name)) {
630 BESDEBUG(
"besdaemon",
"besdaemon: Received StopNow" << endl);
637 throw BESSyntaxUserError(
"Received Stop command but the master beslistener was likely already stopped", __FILE__, __LINE__);
641 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
643 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
649 BESDEBUG(
"besdaemon",
"besdaemon: Received Start" << endl);
654 throw BESSyntaxUserError(
"Received Start command but the master beslistener is already running", __FILE__, __LINE__);
660 throw BESSyntaxUserError(
"Received Start command but the master beslistener is already running", __FILE__, __LINE__);
673 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
675 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
682 BESDEBUG(
"besdaemon",
"besdaemon: Received Exit" << endl);
688 case HAI_GET_CONFIG: {
689 BESDEBUG(
"besdaemon",
"besdaemon: Received GetConfig" << endl);
691 if (d_pathnames.empty()) {
692 throw BESInternalFatalError(
"There are no known configuration files for this BES!", __FILE__, __LINE__);
697 map<string, string>::iterator i = d_pathnames.begin();
698 while (i != d_pathnames.end()) {
699 BESDEBUG(
"besdaemon",
"besdaemon: d_pathnames: [" << (*i).first <<
"]: " << d_pathnames[(*i).first] << endl);
701 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:BesConfig") < 0)
704 if (xmlTextWriterWriteAttribute(writer.
get_writer(), (
const xmlChar*)
"module", (
const xmlChar*) (*i).first.c_str()) < 0)
707 char *content = read_file(d_pathnames[(*i).first]);
709 BESDEBUG(
"besdaemon_verbose",
"besdaemon: content: " << content << endl);
710 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)
"\n") < 0)
713 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)content) < 0)
716 delete [] content; content = 0;
719 delete [] content; content = 0;
723 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
731 case HAI_SET_CONFIG: {
732 BESDEBUG(
"besdaemon",
"besdaemon: Received SetConfig" << endl);
733 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"module");
734 if (!xml_char_module) {
737 string module = (
const char *) xml_char_module;
738 xmlFree(xml_char_module);
740 BESDEBUG(
"besdaemon",
"besdaemon: Received SetConfig; module: " << module << endl);
742 xmlChar *file_content = xmlNodeListGetString(doc, current_node->children,
true);
746 string content = (
const char *) file_content;
747 xmlFree(file_content);
748 BESDEBUG(
"besdaemon_verbose",
"besdaemon: Received SetConfig; content: " << endl << content << endl);
750 write_file(d_pathnames[module], content);
752 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
755 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)
"\nPlease restart the server for these changes to take affect.\n") < 0)
758 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
765 BESDEBUG(
"besdaemon",
"besdaemon: Received TailLog" << endl);
767 xmlChar *xml_char_lines = xmlGetProp(current_node, (
const xmlChar*)
"lines");
768 if (!xml_char_lines) {
773 long num_lines = strtol((
const char *) xml_char_lines, &endptr, 10 );
774 if (num_lines == 0 && endptr == (
const char *) xml_char_lines) {
776 err <<
"(" << errno <<
") " << strerror(errno);
777 throw BESSyntaxUserError(
"TailLog lines attribute bad value: " + err.str(), __FILE__, __LINE__);
780 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:BesLog") < 0)
783 BESDEBUG(
"besdaemon",
"besdaemon: TailLog: log file:" << d_log_file_name <<
", lines: " << num_lines << endl);
785 char *content = get_bes_log_lines(d_log_file_name, num_lines);
787 BESDEBUG(
"besdaemon_verbose",
"besdaemon: Returned lines: " << content << endl);
788 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)
"\n") < 0)
791 if (xmlTextWriterWriteString(writer.
get_writer(), (
const xmlChar*)content) < 0)
794 delete [] content; content = 0;
797 delete [] content; content = 0;
801 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
807 case HAI_GET_LOG_CONTEXTS: {
808 BESDEBUG(
"besdaemon",
"besdaemon: Received GetLogContexts" << endl);
814 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:LogContext") < 0)
817 if (xmlTextWriterWriteAttribute(writer.
get_writer(), (
const xmlChar*)
"name", (
const xmlChar*) (*i).first.c_str()) < 0)
820 string state = (*i).second ?
"on" :
"off";
821 if (xmlTextWriterWriteAttribute(writer.
get_writer(), (
const xmlChar*)
"state", (
const xmlChar*) state.c_str()) < 0)
824 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
834 case HAI_SET_LOG_CONTEXT: {
835 BESDEBUG(
"besdaemon",
"besdaemon: Received SetLogContext" << endl);
837 xmlChar *xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"name");
838 if (!xml_char_module) {
841 string name = (
const char *)xml_char_module;
842 xmlFree(xml_char_module);
844 xml_char_module = xmlGetProp(current_node, (
const xmlChar*)
"state");
845 if (!xml_char_module) {
848 bool state = strcmp((
const char *)xml_char_module,
"on") == 0;
849 xmlFree(xml_char_module);
851 BESDEBUG(
"besdaemon",
"besdaemon: before setting " << name <<
" to " << state << endl);
861 BESDEBUG(
"besdaemon",
"besdaemon: after setting " << name <<
" to " << state << endl);
863 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:OK") < 0)
865 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
878 current_node = current_node->next;
895 if (xmlTextWriterStartElement(writer.
get_writer(), (
const xmlChar*)
"hai:BESError") < 0)
900 if (xmlTextWriterWriteElement(writer.
get_writer(), (
const xmlChar*)
"hai:Type", (
const xmlChar*) oss.str().c_str()) < 0)
903 if (xmlTextWriterWriteElement(writer.
get_writer(), (
const xmlChar*)
"hai:Message", (
const xmlChar*) e.
get_message().c_str()) < 0)
906 if (xmlTextWriterEndElement(writer.
get_writer()) < 0)
917 string from = strm.str();
919 map<string, string> extensions;
924 done = c->
receive(extensions, &ss);
926 if (extensions[
"status"] == c->
exit()) {
937 std::streambuf *holder;
938 holder = cout.rdbuf();
944 BESDEBUG(
"besdaemon",
"besdaemon: cmd: " << ss.str() << endl);
946 execute_command(ss.str(), writer);
948 cout << writer.
get_doc() << endl;
959 map<string, string> extensions;
960 extensions[
"status"] =
"error";
966 extensions[
"exit"] =
"true";
968 send_bes_error(writer, e);
973 cout << writer.
get_doc() << endl;
985 send_bes_error(writer, e);
989 BESDEBUG(
"besdaemon",
"besdaemon: Error (unknown command): " << ss.str() << endl);
990 extensions[
"exit"] =
"true";
993 send_bes_error(writer, e);
998 cout << writer.
get_doc() << endl;
1012 strm <<
BESIndent::LMarg <<
"DaemonCommandHandler::dump - (" << (
void *)
this <<
")" << endl;