39 #include <sys/types.h>
62 using std::ostringstream;
66 #include "ServerExitConditions.h"
67 #include "SocketListener.h"
68 #include "TcpSocket.h"
69 #include "UnixSocket.h"
70 #include "PPTServer.h"
71 #include "BESModuleApp.h"
72 #include "DaemonCommandHandler.h"
73 #include "BESServerUtils.h"
77 #include "TheBESKeys.h"
79 #include "BESDaemonConstants.h"
81 #define BES_SERVER "/beslistener"
82 #define BES_SERVER_PID "/bes.pid"
83 #define DAEMON_PORT_STR "BES.DaemonPort"
84 #define DAEMON_UNIX_SOCK_STR "BES.DaemonUnixSocket"
87 extern "C" int set_sups(
const int target_sups_size,
const gid_t*
const target_sups_list);
91 void unblock_signals();
92 int start_master_beslistener();
93 bool stop_all_beslisteners(
int sig);
95 static string daemon_name;
98 static string beslistener_path;
99 static string file_for_daemon_pid;
102 volatile int master_beslistener_status = BESLISTENER_STOPPED;
103 volatile int num_children = 0;
104 static volatile int master_beslistener_pid = -1;
106 typedef map<string, string> arg_map;
107 static arg_map global_args;
108 static string debug_sink =
"";
116 static volatile sig_atomic_t sigchild = 0;
117 static volatile sig_atomic_t sigterm = 0;
118 static volatile sig_atomic_t sighup = 0;
120 static string errno_str(
const string &msg)
123 oss << daemon_name << msg;
124 const char *perror_string = strerror(errno);
125 if (perror_string) oss << perror_string;
138 static int pr_exit(
int status)
140 if (WIFEXITED(status)) {
141 switch (WEXITSTATUS(status)) {
142 case SERVER_EXIT_NORMAL_SHUTDOWN:
145 case SERVER_EXIT_FATAL_CANNOT_START:
146 cerr << daemon_name <<
": server cannot start, exited with status " << WEXITSTATUS(status) << endl;
147 cerr <<
"Please check all error messages " <<
"and adjust server installation" << endl;
150 case SERVER_EXIT_ABNORMAL_TERMINATION:
151 cerr << daemon_name <<
": abnormal server termination, exited with status " << WEXITSTATUS(status) << endl;
154 case SERVER_EXIT_RESTART:
155 cerr << daemon_name <<
": server has been requested to re-start." << endl;
156 return SERVER_EXIT_RESTART;
162 else if (WIFSIGNALED(status)) {
163 cerr << daemon_name <<
": abnormal server termination, signaled with signal number " << WTERMSIG(status)
166 if (WCOREDUMP(status)) {
167 cerr << daemon_name <<
": server dumped core." << endl;
173 else if (WIFSTOPPED(status)) {
174 cerr << daemon_name <<
": abnormal server termination, stopped with signal number " << WSTOPSIG(status) << endl;
189 sigaddset(&set, SIGCHLD);
190 sigaddset(&set, SIGHUP);
191 sigaddset(&set, SIGTERM);
193 if (sigprocmask(SIG_BLOCK, &set, 0) < 0) {
194 cerr << errno_str(
": sigprocmask error, blocking signals in stop_all_beslisteners ");
199 void unblock_signals()
203 sigaddset(&set, SIGCHLD);
204 sigaddset(&set, SIGHUP);
205 sigaddset(&set, SIGTERM);
207 if (sigprocmask(SIG_UNBLOCK, &set, 0) < 0) {
208 cerr << errno_str(
": sigprocmask error unblocking signals in stop_all_beslisteners ");
225 bool stop_all_beslisteners(
int sig)
227 BESDEBUG(
"besdaemon",
"besdaemon: stopping listeners" << endl);
231 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid " << master_beslistener_pid << endl);
234 int status = killpg(master_beslistener_pid, sig);
237 cerr <<
"The sig argument is not a valid signal number." << endl;
242 <<
"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."
247 cerr <<
"No process can be found in the process group specified by the process group ("
248 << master_beslistener_pid <<
")." << endl;
255 bool mbes_status_caught =
false;
257 while ((pid = wait(&status)) > 0) {
258 BESDEBUG(
"besdaemon",
"besdaemon: caught listener: " << pid <<
" raw status: " << status << endl);
259 if (pid == master_beslistener_pid) {
260 master_beslistener_status = pr_exit(status);
261 mbes_status_caught =
true;
262 BESDEBUG(
"besdaemon",
263 "besdaemon: caught master beslistener: " << pid <<
" status: " << master_beslistener_status << endl);
267 BESDEBUG(
"besdaemon",
"besdaemon: done catching listeners (last pid:" << pid <<
")" << endl);
270 BESDEBUG(
"besdaemon",
"besdaemon: unblocking signals " << endl);
271 return mbes_status_caught;
281 char **update_beslistener_args()
283 char **arguments =
new char*[global_args.size() * 2 + 1];
287 arguments[0] = strdup(global_args[
"beslistener"].c_str());
290 arg_map::iterator it;
291 for (it = global_args.begin(); it != global_args.end(); ++it) {
292 BESDEBUG(
"besdaemon",
"besdaemon; global_args " << (*it).first <<
" => " << (*it).second << endl);
296 if ((*it).first ==
"-d") {
297 arguments[i++] = strdup(
"-d");
302 arguments[i++] = strdup(debug_opts.c_str());
304 else if ((*it).first !=
"beslistener") {
305 arguments[i++] = strdup((*it).first.c_str());
306 arguments[i++] = strdup((*it).second.c_str());
326 int start_master_beslistener()
331 if (pipe(pipefd) < 0) {
332 cerr << errno_str(
": pipe error ");
337 if ((pid = fork()) < 0) {
338 cerr << errno_str(
": fork error ");
352 if (dup2(pipefd[1], BESLISTENER_PIPE_FD) != BESLISTENER_PIPE_FD) {
353 cerr << errno_str(
": dup2 error ");
359 char **arguments = update_beslistener_args();
361 BESDEBUG(
"besdaemon",
"Starting: " << arguments[0] << endl);
366 if (command_server) command_server->closeConnection();
369 execvp(arguments[0], arguments);
372 cerr << errno_str(
": mounting listener, subprocess failed: ");
383 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener pid: " << pid << endl);
386 int beslistener_start_status;
387 int status = read(pipefd[0], &beslistener_start_status,
sizeof(beslistener_start_status));
390 cerr <<
"Could not read master beslistener status; the master pid was not changed." << endl;
394 else if (beslistener_start_status != BESLISTENER_RUNNING) {
395 cerr <<
"The beslistener status is not 'BESLISTENER_RUNNING' (it is '" << beslistener_start_status
396 <<
"') the master pid was not changed." << endl;
401 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener start status: " << beslistener_start_status << endl);
404 master_beslistener_pid = pid;
405 master_beslistener_status = BESLISTENER_RUNNING;
415 static void cleanup_resources()
421 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
422 (void) remove(file_for_daemon_pid.c_str());
426 (void) remove(file_for_daemon_pid.c_str());
432 static void CatchSigChild(
int signal)
434 if (signal == SIGCHLD) {
439 static void CatchSigHup(
int signal)
441 if (signal == SIGHUP) {
446 static void CatchSigTerm(
int signal)
448 if (signal == SIGTERM) {
453 static void process_signals()
463 int pid = wait(&status);
470 if (pid == master_beslistener_pid) master_beslistener_status = pr_exit(status);
487 stop_all_beslisteners(SIGHUP);
490 if (start_master_beslistener() == 0) {
491 cerr <<
"Could not restart the master beslistener." << endl;
492 stop_all_beslisteners(SIGTERM);
505 stop_all_beslisteners(SIGTERM);
529 BESDEBUG(
"besdaemon",
"besdaemon: Starting command processor." << endl);
540 port = strtol(port_str.c_str(), &ptr, 10);
542 cerr <<
"Invalid port number for daemon command interface: " << port_str << endl;
548 BESDEBUG(
"besdaemon",
"besdaemon: listening on port: " << port << endl);
550 listener.listen(my_socket);
557 if (!usock_str.empty()) {
558 BESDEBUG(
"besdaemon",
"besdaemon: listening on unix socket: " << usock_str << endl);
560 listener.listen(unix_socket);
563 if (!port_found && !usock_found) {
564 BESDEBUG(
"besdaemon",
"Neither a port nor a unix socket was set for the daemon command interface." << endl);
568 BESDEBUG(
"besdaemon",
"besdaemon: starting command interface on port: " << port << endl);
569 command_server =
new PPTServer(&handler, &listener,
false);
579 command_server->closeConnection();
585 cerr <<
"daemon: " <<
"caught unknown exception" << endl;
588 delete command_server;
598 stop_all_beslisteners(SIGTERM);
611 static void register_signal_handlers()
613 struct sigaction act;
616 sigemptyset(&act.sa_mask);
617 sigaddset(&act.sa_mask, SIGCHLD);
618 sigaddset(&act.sa_mask, SIGTERM);
619 sigaddset(&act.sa_mask, SIGHUP);
622 BESDEBUG(
"besdaemon",
"besdaemon: setting restart for sigchld." << endl);
623 act.sa_flags |= SA_RESTART;
626 act.sa_handler = CatchSigChild;
627 if (sigaction(SIGCHLD, &act, 0)) {
628 cerr <<
"Could not register a handler to catch beslistener status." << endl;
632 act.sa_handler = CatchSigTerm;
633 if (sigaction(SIGTERM, &act, 0) < 0) {
634 cerr <<
"Could not register a handler to catch the terminate signal." << endl;
638 act.sa_handler = CatchSigHup;
639 if (sigaction(SIGHUP, &act, 0) < 0) {
640 cerr <<
"Could not register a handler to catch the hang-up signal." << endl;
651 static int daemon_init()
654 if ((pid = fork()) < 0)
668 static void store_daemon_id(
int pid)
670 ofstream f(file_for_daemon_pid.c_str());
672 cerr << errno_str(
": unable to create pid file " + file_for_daemon_pid +
": ");
680 mode_t new_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
681 (void) chmod(file_for_daemon_pid.c_str(), new_mode);
693 static bool load_names(
const string &install_dir,
const string &pid_dir)
695 string bindir =
"/bin";
696 if (!pid_dir.empty()) {
697 file_for_daemon_pid = pid_dir;
700 if (!install_dir.empty()) {
701 beslistener_path = install_dir;
702 beslistener_path += bindir;
703 if (file_for_daemon_pid.empty()) {
704 file_for_daemon_pid = install_dir +
"/var/run";
713 string prog = daemon_name;
714 string::size_type slash = prog.find_last_of(
'/');
715 if (slash != string::npos) {
716 beslistener_path = prog.substr(0, slash);
717 slash = prog.find_last_of(
'/');
718 if (slash != string::npos) {
719 string root = prog.substr(0, slash);
720 if (file_for_daemon_pid.empty()) {
721 file_for_daemon_pid = root +
"/var/run";
727 if (file_for_daemon_pid.empty()) {
728 file_for_daemon_pid = beslistener_path;
734 if (beslistener_path ==
"") {
735 beslistener_path =
".";
736 if (file_for_daemon_pid.empty()) {
737 file_for_daemon_pid =
"./run";
741 beslistener_path += BES_SERVER;
742 file_for_daemon_pid += BES_SERVER_PID;
744 if (access(beslistener_path.c_str(), F_OK) != 0) {
745 cerr << daemon_name <<
": cannot find " << beslistener_path << endl
746 <<
"Please either pass -i <install_dir> on the command line." << endl;
751 global_args[
"beslistener"] = beslistener_path;
756 static void set_group_id()
758 #if !defined(OS2) && !defined(TPF)
764 BESDEBUG(
"server",
"beslistener: Setting group id ... " << endl);
766 string key =
"BES.Group";
772 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
776 exit(SERVER_EXIT_FATAL_CANNOT_START);
779 if (!found || group_str.empty()) {
780 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
781 string err =
"FAILED: Group not specified in BES configuration file";
784 exit(SERVER_EXIT_FATAL_CANNOT_START);
786 BESDEBUG(
"server",
"to " << group_str <<
" ... " << endl);
789 if (group_str[0] ==
'#') {
791 const char *group_c = group_str.c_str();
793 new_gid = atoi(group_c);
798 ent = getgrnam(group_str.c_str());
800 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
801 string err = (string)
"FAILED: Group " + group_str +
" does not exist";
804 exit(SERVER_EXIT_FATAL_CANNOT_START);
806 new_gid = ent->gr_gid;
810 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
812 err <<
"FAILED: Group id " << new_gid <<
" not a valid group id for BES";
813 cerr << err.str() << endl;
814 LOG(err.str() << endl);
815 exit(SERVER_EXIT_FATAL_CANNOT_START);
818 BESDEBUG(
"server",
"to id " << new_gid <<
" ... " << endl);
819 if (setgid(new_gid) == -1) {
820 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
822 err <<
"FAILED: unable to set the group id to " << new_gid;
823 cerr << err.str() << endl;
824 LOG(err.str() << endl);
825 exit(SERVER_EXIT_FATAL_CANNOT_START);
828 BESDEBUG(
"server",
"OK" << endl);
830 BESDEBUG(
"server",
"beslistener: Groups not supported in this OS" << endl );
834 static void set_user_id()
836 BESDEBUG(
"server",
"beslistener: Setting user id ... " << endl);
843 string key =
"BES.User";
849 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
850 string err = (string)
"FAILED: " + e.
get_message();
853 exit(SERVER_EXIT_FATAL_CANNOT_START);
856 if (!found || user_str.empty()) {
857 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
858 string err = (string)
"FAILED: User not specified in BES config file";
861 exit(SERVER_EXIT_FATAL_CANNOT_START);
863 BESDEBUG(
"server",
"to " << user_str <<
" ... " << endl);
866 if (user_str[0] ==
'#') {
867 const char *user_str_c = user_str.c_str();
869 new_id = atoi(user_str_c);
873 ent = getpwnam(user_str.c_str());
875 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
876 string err = (string)
"FAILED: Bad user name specified: " + user_str;
879 exit(SERVER_EXIT_FATAL_CANNOT_START);
881 new_id = ent->pw_uid;
886 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
887 string err = (string)
"FAILED: BES cannot run as root";
890 exit(SERVER_EXIT_FATAL_CANNOT_START);
895 vector<gid_t> groups(1);
896 groups.at(0) = getegid();
897 if (set_sups(groups.size(), &groups[0]) == -1) {
898 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
900 err <<
"FAILED: Unable to relinquish supplementary groups (" << new_id <<
")";
901 cerr << err.str() << endl;
902 LOG(err.str() << endl);
903 exit(SERVER_EXIT_FATAL_CANNOT_START);
906 BESDEBUG(
"server",
"to " << new_id <<
" ... " << endl);
907 if (setuid(new_id) == -1) {
908 BESDEBUG(
"server",
"beslistener: FAILED" << endl);
910 err <<
"FAILED: Unable to set user id to " << new_id;
911 cerr << err.str() << endl;
912 LOG(err.str() << endl);
913 exit(SERVER_EXIT_FATAL_CANNOT_START);
916 BESDEBUG(
"server",
"OK" << endl);
922 int main(
int argc,
char *argv[])
924 uid_t curr_euid = geteuid();
926 #ifndef BES_DEVELOPER
929 cerr <<
"FAILED: Must be root to run BES" << endl;
930 exit(SERVER_EXIT_FATAL_CANNOT_START);
933 cerr <<
"Developer Mode: Not testing if BES is run by root" << endl;
936 daemon_name =
"besdaemon";
941 bool become_daemon =
true;
947 BESServerUtils::show_usage(daemon_name);
953 string config_file =
"";
955 unsigned short num_args = 1;
960 while ((c = getopt(argc, argv,
"hvsd:c:p:u:i:r:n")) != -1) {
963 BESServerUtils::show_version(daemon_name);
967 BESServerUtils::show_usage(daemon_name);
971 cerr <<
"Running in foreground!" << endl;
975 install_dir = optarg;
977 cout <<
"The specified install directory (-i option) "
978 <<
"is incorrectly formatted. Must be less than "
979 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
982 global_args[
"-i"] = install_dir;
986 global_args[
"-s"] =
"";
992 cout <<
"The specified state directory (-r option) "
993 <<
"is incorrectly formatted. Must be less than "
994 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
997 global_args[
"-r"] = pid_dir;
1001 config_file = optarg;
1003 cout <<
"The specified configuration file (-c option) "
1004 <<
"is incorrectly formatted. Must be less than "
1005 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
1008 global_args[
"-c"] = config_file;
1013 string check_path = optarg;
1015 cout <<
"The specified unix socket (-u option) " <<
"is incorrectly formatted. Must be less than "
1016 <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
1019 global_args[
"-u"] = check_path;
1025 string port_num = optarg;
1026 for (
unsigned int i = 0; i < port_num.length(); i++) {
1027 if (!isdigit(port_num[i])) {
1028 cout <<
"The specified port contains non-digit " <<
"characters: " << port_num << endl;
1032 global_args[
"-p"] = port_num;
1038 string check_arg = optarg;
1040 cout <<
"The specified debug options \"" << check_arg <<
"\" contains invalid characters" << endl;
1044 global_args[
"-d"] = check_arg;
1045 debug_sink = check_arg.substr(0, check_arg.find(
','));
1050 BESServerUtils::show_usage(daemon_name);
1058 if (argc > num_args) {
1059 cout << daemon_name <<
": too many arguments passed to the BES";
1060 BESServerUtils::show_usage(daemon_name);
1063 if (pid_dir.empty()) {
1064 pid_dir = install_dir;
1068 if (!config_file.empty()) {
1075 if (config_file.empty() && !install_dir.empty()) {
1076 if (install_dir[install_dir.length() - 1] !=
'/') {
1079 string conf_file = install_dir +
"etc/bes/bes.conf";
1086 cerr <<
"Caught BES Error while processing the daemon's options: " << e.
get_message() << endl;
1089 catch (std::exception &e) {
1090 cerr <<
"Caught C++ error while processing the daemon's options: " << e.what() << endl;
1094 cerr <<
"Caught unknown error while processing the daemon's options." << endl;
1100 if (!load_names(install_dir, pid_dir))
return 1;
1102 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
1103 ifstream temp(file_for_daemon_pid.c_str());
1104 cout << daemon_name <<
": there seems to be a BES daemon already running at ";
1106 temp.getline(buf, 500);
1107 cout << buf << endl;
1116 store_daemon_id(getpid());
1118 register_signal_handlers();
1125 cerr <<
"Could not initialize the modules to get the log contexts." << endl;
1134 if (curr_euid == 0) {
1135 #ifdef BES_DEVELOPER
1136 cerr <<
"Developer Mode: Running as root - setting group and user ids" << endl;
1142 cerr <<
"Developer Mode: Not setting group or user ids" << endl;
1153 if (global_args.count(
"-d") == 0) {
1181 master_beslistener_pid = start_master_beslistener();
1182 if (master_beslistener_pid == 0) {
1183 cerr << daemon_name <<
": server cannot mount at first try (core dump). "
1184 <<
"Please correct problems on the process manager " << beslistener_path << endl;
1185 return master_beslistener_pid;
1188 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid: " << master_beslistener_pid << endl);
1193 cerr <<
"Caught BES Error during initialization: " << e.
get_message() << endl;
1196 catch (std::exception &e) {
1197 cerr <<
"Caught C++ error during initialization: " << e.what() << endl;
1201 cerr <<
"Caught unknown error during initialization." << endl;
1211 status = start_command_processor(handler);
1222 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_status: " << master_beslistener_status << endl);
1223 if (master_beslistener_status == BESLISTENER_RESTART) {
1224 master_beslistener_status = BESLISTENER_STOPPED;
1226 start_master_beslistener();
1229 else if (master_beslistener_status != BESLISTENER_RUNNING) {
1239 cerr <<
"Caught BES Error while starting the command handler: " << e.
get_message() << endl;
1241 catch (std::exception &e) {
1243 cerr <<
"Caught C++ error while starting the command handler: " << e.what() << endl;
1247 cerr <<
"Caught unknown error while starting the command handler." << endl;
1250 BESDEBUG(
"besdaemon",
"besdaemon: past the command processor start" << endl);
1252 cleanup_resources();