39 #include <sys/types.h> 61 #include "ServerExitConditions.h" 62 #include "SocketListener.h" 63 #include "TcpSocket.h" 64 #include "UnixSocket.h" 65 #include "PPTServer.h" 66 #include "BESModuleApp.h" 67 #include "DaemonCommandHandler.h" 68 #include "BESServerUtils.h" 72 #include "TheBESKeys.h" 74 #include "BESDaemonConstants.h" 76 #define BES_SERVER "/beslistener" 77 #define BES_SERVER_PID "/bes.pid" 78 #define DAEMON_PORT_STR "BES.DaemonPort" 79 #define DAEMON_UNIX_SOCK_STR "BES.DaemonUnixSocket" 82 extern "C" int set_sups(
const int target_sups_size,
const gid_t*
const target_sups_list);
86 void unblock_signals();
87 int start_master_beslistener();
88 bool stop_all_beslisteners(
int sig);
90 static string daemon_name;
93 static string beslistener_path;
94 static string file_for_daemon_pid;
97 volatile int master_beslistener_status = BESLISTENER_STOPPED;
98 volatile int num_children = 0;
99 static volatile int master_beslistener_pid = -1;
101 typedef map<string, string> arg_map;
102 static arg_map global_args;
103 static string debug_sink =
"";
111 static volatile sig_atomic_t sigchild = 0;
112 static volatile sig_atomic_t sigterm = 0;
113 static volatile sig_atomic_t sighup = 0;
115 static string errno_str(
const string &msg)
118 oss << daemon_name << msg;
119 const char *perror_string = strerror(errno);
120 if (perror_string) oss << perror_string;
133 static int pr_exit(
int status)
135 if (WIFEXITED(status)) {
136 switch (WEXITSTATUS(status)) {
137 case SERVER_EXIT_NORMAL_SHUTDOWN:
140 case SERVER_EXIT_FATAL_CANNOT_START:
141 cerr << daemon_name <<
": server cannot start, exited with status " << WEXITSTATUS(status) << endl;
142 cerr <<
"Please check all error messages " <<
"and adjust server installation" << endl;
145 case SERVER_EXIT_ABNORMAL_TERMINATION:
146 cerr << daemon_name <<
": abnormal server termination, exited with status " << WEXITSTATUS(status) << endl;
149 case SERVER_EXIT_RESTART:
150 cerr << daemon_name <<
": server has been requested to re-start." << endl;
151 return SERVER_EXIT_RESTART;
157 else if (WIFSIGNALED(status)) {
158 cerr << daemon_name <<
": abnormal server termination, signaled with signal number " << WTERMSIG(status)
161 if (WCOREDUMP(status)) {
162 cerr << daemon_name <<
": server dumped core." << endl;
168 else if (WIFSTOPPED(status)) {
169 cerr << daemon_name <<
": abnormal server termination, stopped with signal number " << WSTOPSIG(status) << endl;
184 sigaddset(&
set, SIGCHLD);
185 sigaddset(&
set, SIGHUP);
186 sigaddset(&
set, SIGTERM);
188 if (sigprocmask(SIG_BLOCK, &
set, 0) < 0) {
189 cerr << errno_str(
": sigprocmask error, blocking signals in stop_all_beslisteners ");
194 void unblock_signals()
198 sigaddset(&
set, SIGCHLD);
199 sigaddset(&
set, SIGHUP);
200 sigaddset(&
set, SIGTERM);
202 if (sigprocmask(SIG_UNBLOCK, &
set, 0) < 0) {
203 cerr << errno_str(
": sigprocmask error unblocking signals in stop_all_beslisteners ");
220 bool stop_all_beslisteners(
int sig)
222 BESDEBUG(
"besdaemon",
"besdaemon: stopping listeners" << endl);
226 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid " << master_beslistener_pid << endl);
229 int status = killpg(master_beslistener_pid, sig);
232 cerr <<
"The sig argument is not a valid signal number." << endl;
237 <<
"The sending process is not the super-user and one or more of the target processes has an effective user ID different from that of the sending process." 242 cerr <<
"No process can be found in the process group specified by the process group (" 243 << master_beslistener_pid <<
")." << endl;
250 bool mbes_status_caught =
false;
252 while ((pid = wait(&status)) > 0) {
253 BESDEBUG(
"besdaemon",
"besdaemon: caught listener: " << pid <<
" raw status: " << status << endl);
254 if (pid == master_beslistener_pid) {
255 master_beslistener_status = pr_exit(status);
256 mbes_status_caught =
true;
257 BESDEBUG(
"besdaemon",
258 "besdaemon: caught master beslistener: " << pid <<
" status: " << master_beslistener_status << endl);
262 BESDEBUG(
"besdaemon",
"besdaemon: done catching listeners (last pid:" << pid <<
")" << endl);
265 BESDEBUG(
"besdaemon",
"besdaemon: unblocking signals " << endl);
266 return mbes_status_caught;
276 char **update_beslistener_args()
278 char **arguments =
new char*[global_args.size() * 2 + 1];
282 arguments[0] = strdup(global_args[
"beslistener"].c_str());
285 arg_map::iterator it;
286 for (it = global_args.begin(); it != global_args.end(); ++it) {
287 BESDEBUG(
"besdaemon",
"besdaemon; global_args " << (*it).first <<
" => " << (*it).second << endl);
291 if ((*it).first ==
"-d") {
292 arguments[i++] = strdup(
"-d");
297 arguments[i++] = strdup(debug_opts.c_str());
299 else if ((*it).first !=
"beslistener") {
300 arguments[i++] = strdup((*it).first.c_str());
301 arguments[i++] = strdup((*it).second.c_str());
321 int start_master_beslistener()
326 if (pipe(pipefd) < 0) {
327 cerr << errno_str(
": pipe error ");
332 if ((pid = fork()) < 0) {
333 cerr << errno_str(
": fork error ");
347 if (dup2(pipefd[1], BESLISTENER_PIPE_FD) != BESLISTENER_PIPE_FD) {
348 cerr << errno_str(
": dup2 error ");
354 char **arguments = update_beslistener_args();
356 BESDEBUG(
"besdaemon",
"Starting: " << arguments[0] << endl);
361 if (command_server) command_server->closeConnection();
364 execvp(arguments[0], arguments);
367 cerr << errno_str(
": mounting listener, subprocess failed: ");
378 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener pid: " << pid << endl);
381 int beslistener_start_status;
382 int status = read(pipefd[0], &beslistener_start_status,
sizeof(beslistener_start_status));
385 cerr <<
"Could not read master beslistener status; the master pid was not changed." << endl;
389 else if (beslistener_start_status != BESLISTENER_RUNNING) {
390 cerr <<
"The beslistener status is not 'BESLISTENER_RUNNING' (it is '" << beslistener_start_status
391 <<
"') the master pid was not changed." << endl;
396 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener start status: " << beslistener_start_status << endl);
399 master_beslistener_pid = pid;
400 master_beslistener_status = BESLISTENER_RUNNING;
410 static void cleanup_resources()
416 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
417 (void)
remove(file_for_daemon_pid.c_str());
421 (void)
remove(file_for_daemon_pid.c_str());
427 static void CatchSigChild(
int signal)
429 if (signal == SIGCHLD) {
434 static void CatchSigHup(
int signal)
436 if (signal == SIGHUP) {
441 static void CatchSigTerm(
int signal)
443 if (signal == SIGTERM) {
448 static void process_signals()
458 int pid = wait(&status);
465 if (pid == master_beslistener_pid) master_beslistener_status = pr_exit(status);
482 stop_all_beslisteners(SIGHUP);
485 if (start_master_beslistener() == 0) {
486 cerr <<
"Could not restart the master beslistener." << endl;
487 stop_all_beslisteners(SIGTERM);
500 stop_all_beslisteners(SIGTERM);
524 BESDEBUG(
"besdaemon",
"besdaemon: Starting command processor." << endl);
535 port = strtol(port_str.c_str(), &ptr, 10);
537 cerr <<
"Invalid port number for daemon command interface: " << port_str << endl;
543 BESDEBUG(
"besdaemon",
"besdaemon: listening on port: " << port << endl);
545 listener.listen(my_socket);
552 if (!usock_str.empty()) {
553 BESDEBUG(
"besdaemon",
"besdaemon: listening on unix socket: " << usock_str << endl);
555 listener.listen(unix_socket);
558 if (!port_found && !usock_found) {
559 BESDEBUG(
"besdaemon",
"Neither a port nor a unix socket was set for the daemon command interface." << endl);
563 BESDEBUG(
"besdaemon",
"besdaemon: starting command interface on port: " << port << endl);
564 command_server =
new PPTServer(&handler, &listener,
false);
574 command_server->closeConnection();
580 cerr <<
"daemon: " <<
"caught unknown exception" << endl;
583 delete command_server;
593 stop_all_beslisteners(SIGTERM);
606 static void register_signal_handlers()
608 struct sigaction act;
611 sigemptyset(&act.sa_mask);
612 sigaddset(&act.sa_mask, SIGCHLD);
613 sigaddset(&act.sa_mask, SIGTERM);
614 sigaddset(&act.sa_mask, SIGHUP);
617 BESDEBUG(
"besdaemon",
"besdaemon: setting restart for sigchld." << endl);
618 act.sa_flags |= SA_RESTART;
621 act.sa_handler = CatchSigChild;
622 if (sigaction(SIGCHLD, &act, 0)) {
623 cerr <<
"Could not register a handler to catch beslistener status." << endl;
627 act.sa_handler = CatchSigTerm;
628 if (sigaction(SIGTERM, &act, 0) < 0) {
629 cerr <<
"Could not register a handler to catch the terminate signal." << endl;
633 act.sa_handler = CatchSigHup;
634 if (sigaction(SIGHUP, &act, 0) < 0) {
635 cerr <<
"Could not register a handler to catch the hang-up signal." << endl;
646 static int daemon_init()
649 if ((pid = fork()) < 0)
663 static void store_daemon_id(
int pid)
665 ofstream f(file_for_daemon_pid.c_str());
667 cerr << errno_str(
": unable to create pid file " + file_for_daemon_pid +
": ");
670 f <<
"PID: " << pid <<
" UID: " << getuid() << endl;
672 mode_t new_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
673 (void) chmod(file_for_daemon_pid.c_str(), new_mode);
685 static bool load_names(
const string &install_dir,
const string &pid_dir)
687 string bindir =
"/bin";
688 if (!pid_dir.empty()) {
689 file_for_daemon_pid = pid_dir;
692 if (!install_dir.empty()) {
693 beslistener_path = install_dir;
694 beslistener_path += bindir;
695 if (file_for_daemon_pid.empty()) {
698 file_for_daemon_pid = install_dir +
"/var/run/bes";
703 string prog = daemon_name;
704 string::size_type slash = prog.find_last_of(
'/');
705 if (slash != string::npos) {
706 beslistener_path = prog.substr(0, slash);
707 slash = prog.find_last_of(
'/');
708 if (slash != string::npos) {
709 string root = prog.substr(0, slash);
710 if (file_for_daemon_pid.empty()) {
713 file_for_daemon_pid = root +
"/var/run/bes";
717 if (file_for_daemon_pid.empty()) {
718 file_for_daemon_pid = beslistener_path;
724 if (beslistener_path ==
"") {
725 beslistener_path =
".";
726 if (file_for_daemon_pid.empty()) {
727 file_for_daemon_pid =
"./run/bes";
731 beslistener_path += BES_SERVER;
732 file_for_daemon_pid += BES_SERVER_PID;
734 if (access(beslistener_path.c_str(), F_OK) != 0) {
735 cerr << daemon_name <<
": cannot find " << beslistener_path << endl
736 <<
"Please either pass -i <install_dir> on the command line." << endl;
741 global_args[
"beslistener"] = beslistener_path;
746 static void set_group_id()
748 #if !defined(OS2) && !defined(TPF) 754 BESDEBUG(
"server",
"beslistener: Setting group id ... " << endl);
756 string key =
"BES.Group";
762 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
765 (*BESLog::TheLog()) << err << endl;
766 exit(SERVER_EXIT_FATAL_CANNOT_START);
769 if (!found || group_str.empty()) {
770 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
771 string err =
"FAILED: Group not specified in BES configuration file";
773 (*BESLog::TheLog()) << err << endl;
774 exit(SERVER_EXIT_FATAL_CANNOT_START);
776 BESDEBUG(
"server",
"to " << group_str <<
" ... " << endl);
779 if (group_str[0] ==
'#') {
781 const char *group_c = group_str.c_str();
783 new_gid = atoi(group_c);
788 ent = getgrnam(group_str.c_str());
790 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
791 string err = (string)
"FAILED: Group " + group_str +
" does not exist";
793 (*BESLog::TheLog()) << err << endl;
794 exit(SERVER_EXIT_FATAL_CANNOT_START);
796 new_gid = ent->gr_gid;
800 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
802 err <<
"FAILED: Group id " << new_gid <<
" not a valid group id for BES";
803 cerr << err.str() << endl;
804 (*BESLog::TheLog()) << err.str() << endl;
805 exit(SERVER_EXIT_FATAL_CANNOT_START);
808 BESDEBUG(
"server",
"to id " << new_gid <<
" ... " << endl);
809 if (setgid(new_gid) == -1) {
810 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
812 err <<
"FAILED: unable to set the group id to " << new_gid;
813 cerr << err.str() << endl;
814 (*BESLog::TheLog()) << err.str() << endl;
815 exit(SERVER_EXIT_FATAL_CANNOT_START);
818 BESDEBUG(
"server",
"OK" << endl);
820 BESDEBUG(
"server",
"beslistener: Groups not supported in this OS" << endl );
824 static void set_user_id()
826 BESDEBUG(
"server",
"beslistener: Setting user id ... " << endl);
833 string key =
"BES.User";
839 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
840 string err = (string)
"FAILED: " + e.
get_message();
842 (*BESLog::TheLog()) << err << endl;
843 exit(SERVER_EXIT_FATAL_CANNOT_START);
846 if (!found || user_str.empty()) {
847 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
848 string err = (string)
"FAILED: User not specified in BES config file";
850 (*BESLog::TheLog()) << err << endl;
851 exit(SERVER_EXIT_FATAL_CANNOT_START);
853 BESDEBUG(
"server",
"to " << user_str <<
" ... " << endl);
856 if (user_str[0] ==
'#') {
857 const char *user_str_c = user_str.c_str();
859 new_id = atoi(user_str_c);
863 ent = getpwnam(user_str.c_str());
865 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
866 string err = (string)
"FAILED: Bad user name specified: " + user_str;
868 (*BESLog::TheLog()) << err << endl;
869 exit(SERVER_EXIT_FATAL_CANNOT_START);
871 new_id = ent->pw_uid;
876 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
877 string err = (string)
"FAILED: BES cannot run as root";
879 (*BESLog::TheLog()) << err << endl;
880 exit(SERVER_EXIT_FATAL_CANNOT_START);
885 vector<gid_t> groups(1);
886 groups.at(0) = getegid();
887 if (set_sups(groups.size(), &groups[0]) == -1) {
888 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
890 err <<
"FAILED: Unable to relinquish supplementary groups (" << new_id <<
")";
891 cerr << err.str() << endl;
892 (*BESLog::TheLog()) << err.str() << endl;
893 exit(SERVER_EXIT_FATAL_CANNOT_START);
896 BESDEBUG(
"server",
"to " << new_id <<
" ... " << endl);
897 if (setuid(new_id) == -1) {
898 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
900 err <<
"FAILED: Unable to set user id to " << new_id;
901 cerr << err.str() << endl;
902 (*BESLog::TheLog()) << err.str() << endl;
903 exit(SERVER_EXIT_FATAL_CANNOT_START);
906 BESDEBUG(
"server",
"OK" << endl);
912 int main(
int argc,
char *argv[])
914 uid_t curr_euid = geteuid();
916 #ifndef BES_DEVELOPER 919 cerr <<
"FAILED: Must be root to run BES" << endl;
920 exit(SERVER_EXIT_FATAL_CANNOT_START);
923 cerr <<
"Developer Mode: Not testing if BES is run by root" << endl;
926 daemon_name =
"besdaemon";
935 BESServerUtils::show_usage(daemon_name);
941 string config_file =
"";
943 unsigned short num_args = 1;
948 while ((c = getopt(argc, argv,
"hvsd:c:p:u:i:r:")) != -1) {
951 BESServerUtils::show_version(daemon_name);
955 BESServerUtils::show_usage(daemon_name);
958 install_dir = optarg;
960 cout <<
"The specified install directory (-i option) " 961 <<
"is incorrectly formatted. Must be less than " 962 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
965 global_args[
"-i"] = install_dir;
969 global_args[
"-s"] =
"";
975 cout <<
"The specified state directory (-r option) " 976 <<
"is incorrectly formatted. Must be less than " 977 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
980 global_args[
"-r"] = pid_dir;
984 config_file = optarg;
986 cout <<
"The specified configuration file (-c option) " 987 <<
"is incorrectly formatted. Must be less than " 988 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
991 global_args[
"-c"] = config_file;
996 string check_path = optarg;
998 cout <<
"The specified unix socket (-u option) " <<
"is incorrectly formatted. Must be less than " 999 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
1002 global_args[
"-u"] = check_path;
1008 string port_num = optarg;
1009 for (
unsigned int i = 0; i < port_num.length(); i++) {
1010 if (!isdigit(port_num[i])) {
1011 cout <<
"The specified port contains non-digit " <<
"characters: " << port_num << endl;
1015 global_args[
"-p"] = port_num;
1021 string check_arg = optarg;
1023 cout <<
"The specified debug options \"" << check_arg <<
"\" contains invalid characters" << endl;
1027 global_args[
"-d"] = check_arg;
1028 debug_sink = check_arg.substr(0, check_arg.find(
','));
1033 BESServerUtils::show_usage(daemon_name);
1041 if (argc > num_args) {
1042 cout << daemon_name <<
": too many arguments passed to the BES";
1043 BESServerUtils::show_usage(daemon_name);
1046 if (pid_dir.empty()) {
1047 pid_dir = install_dir;
1051 if (!config_file.empty()) {
1058 if (install_dir.empty() && !install_dir.empty()) {
1059 if (install_dir[install_dir.length() - 1] !=
'/') {
1062 string conf_file = install_dir +
"etc/bes/bes.conf";
1069 cerr <<
"Caught BES Error while processing the daemon's options: " << e.
get_message() << endl;
1072 catch (std::exception &e) {
1073 cerr <<
"Caught C++ error while processing the daemon's options: " << e.what() << endl;
1077 cerr <<
"Caught unknown error while processing the daemon's options." << endl;
1083 if (!load_names(install_dir, pid_dir))
return 1;
1085 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
1086 ifstream temp(file_for_daemon_pid.c_str());
1087 cout << daemon_name <<
": there seems to be a BES daemon already running at ";
1089 temp.getline(buf, 500);
1090 cout << buf << endl;
1097 store_daemon_id(getpid());
1099 register_signal_handlers();
1106 cerr <<
"Could not initialize the modules to get the log contexts." << endl;
1115 if (curr_euid == 0) {
1116 #ifdef BES_DEVELOPER 1117 cerr <<
"Developer Mode: Running as root - setting group and user ids" << endl;
1123 cerr <<
"Developer Mode: Not setting group or user ids" << endl;
1134 if (global_args.count(
"-d") == 0) {
1162 master_beslistener_pid = start_master_beslistener();
1163 if (master_beslistener_pid == 0) {
1164 cerr << daemon_name <<
": server cannot mount at first try (core dump). " 1165 <<
"Please correct problems on the process manager " << beslistener_path << endl;
1166 return master_beslistener_pid;
1169 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid: " << master_beslistener_pid << endl);
1174 cerr <<
"Caught BES Error during initialization: " << e.
get_message() << endl;
1177 catch (std::exception &e) {
1178 cerr <<
"Caught C++ error during initialization: " << e.what() << endl;
1182 cerr <<
"Caught unknown error during initialization." << endl;
1192 status = start_command_processor(handler);
1203 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_status: " << master_beslistener_status << endl);
1204 if (master_beslistener_status == BESLISTENER_RESTART) {
1205 master_beslistener_status = BESLISTENER_STOPPED;
1207 start_master_beslistener();
1210 else if (master_beslistener_status != BESLISTENER_RUNNING) {
1220 cerr <<
"Caught BES Error while starting the command handler: " << e.
get_message() << endl;
1222 catch (std::exception &e) {
1224 cerr <<
"Caught C++ error while starting the command handler: " << e.what() << endl;
1228 cerr <<
"Caught unknown error while starting the command handler." << endl;
1231 BESDEBUG(
"besdaemon",
"besdaemon: past the command processor start" << endl);
1233 cleanup_resources();
static bool pathname_ok(const string &path, bool strict)
Does the string name a potentailly valid pathname? Test the given pathname to verfiy that it is a val...
static void SetUp(const string &values)
Sets up debugging for the bes.
virtual std::string get_message()
get the error message for this exception
static bool command_line_arg_ok(const string &arg)
sanitize command line arguments
virtual void initConnection()
Abstract exception class for the BES with basic string message.
static string GetOptionsString()
Base application object for all BES applications.
virtual int initialize(int argC, char **argV)
Load and initialize any BES modules.
void get_value(const string &s, string &val, bool &found)
Retrieve the value of a given key, if set.
static void SetStrm(ostream *strm, bool created)
set the debug output stream to the specified stream
static BESKeys * TheKeys()
static void Register(const string &flagName)
register the specified debug flag