39 #include <sys/types.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"
87 static string daemon_name;
90 static string beslistener_path;
91 static string file_for_daemon_pid;
95 static int master_beslistener_pid = -1;
99 static string debug_sink =
"";
105 static string errno_str(
const string &msg)
108 oss << daemon_name << msg;
109 const char *perror_string = strerror(errno);
111 oss << perror_string;
124 static int pr_exit(
int status)
126 if (WIFEXITED( status )) {
127 switch (WEXITSTATUS( status )) {
132 cerr << daemon_name <<
": server cannot start, exited with status " << WEXITSTATUS( status ) << endl;
133 cerr <<
"Please check all error messages " <<
"and adjust server installation" << endl;
137 cerr << daemon_name <<
": abnormal server termination, exited with status " << WEXITSTATUS( status ) << endl;
141 cerr << daemon_name <<
": server has been requested to re-start." << endl;
148 else if (WIFSIGNALED( status )) {
149 cerr << daemon_name <<
": abnormal server termination, signaled with signal number " << WTERMSIG( status ) << endl;
151 if (WCOREDUMP( status )) {
152 cerr << daemon_name <<
": server dumped core." << endl;
158 else if (WIFSTOPPED( status )) {
159 cerr << daemon_name <<
": abnormal server termination, stopped with signal number " << WSTOPSIG( status ) << endl;
170 sigaddset(&set, SIGCHLD);
171 sigaddset(&set, SIGHUP);
172 sigaddset(&set, SIGTERM);
174 if (sigprocmask(SIG_BLOCK, &set, 0) < 0) {
175 cerr << errno_str(
": sigprocmask error, blocking signals in stop_all_beslisteners ");
183 sigaddset(&set, SIGCHLD);
184 sigaddset(&set, SIGHUP);
185 sigaddset(&set, SIGTERM);
187 if (sigprocmask(SIG_UNBLOCK, &set, 0) < 0) {
188 cerr << errno_str(
": sigprocmask error unblocking signals in stop_all_beslisteners ");
206 BESDEBUG(
"besdaemon",
"besdaemon: stopping listeners" << endl);
209 BESDEBUG(
"besdaemon",
"besdaemon: blocking signals " << endl);
211 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid " << master_beslistener_pid << endl);
214 int status = killpg(master_beslistener_pid, sig);
217 cerr <<
"The sig argument is not a valid signal number." << endl;
221 cerr <<
"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." << endl;
225 cerr <<
"No process can be found in the process group specified by the process group (" << master_beslistener_pid <<
")." << endl;
232 bool mbes_status_caught =
false;
234 while ((pid = wait(&status)) > 0) {
235 BESDEBUG(
"besdaemon",
"besdaemon: caught listener: " << pid <<
" raw status: " << status << endl);
236 if (pid == master_beslistener_pid) {
238 mbes_status_caught =
true;
243 BESDEBUG(
"besdaemon",
"besdaemon: done catching listeners (last pid:" << pid <<
")" << endl);
246 BESDEBUG(
"besdaemon",
"besdaemon: unblocking signals " << endl);
247 return mbes_status_caught;
259 char **arguments =
new char*[global_args.size() * 2 + 1];
263 arguments[0] = strdup(global_args[
"beslistener"].c_str());
266 arg_map::iterator it;
267 for (it = global_args.begin() ; it != global_args.end(); ++it) {
268 BESDEBUG(
"besdaemon",
"besdaemon; global_args " << (*it).first <<
" => " << (*it).second << endl);
272 if ((*it).first ==
"-d") {
273 arguments[i++] = strdup(
"-d");
278 arguments[i++] = strdup(debug_opts.c_str());
280 else if ((*it).first !=
"beslistener") {
281 arguments[i++] = strdup((*it).first.c_str());
282 arguments[i++] = strdup((*it).second.c_str());
307 if (pipe(pipefd) < 0) {
308 cerr << errno_str(
": pipe error ");
313 if ((pid = fork()) < 0) {
314 cerr << errno_str(
": fork error ");
329 cerr << errno_str(
": dup2 error ");
337 BESDEBUG(
"besdaemon",
"Starting: " << arguments[0] << endl);
346 execvp(arguments[0], arguments);
349 cerr << errno_str(
": mounting listener, subprocess failed: ");
360 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener pid: " << pid << endl);
363 int beslistener_start_status;
364 int status = read(pipefd[0], &beslistener_start_status,
sizeof(beslistener_start_status));
368 cerr <<
"Could not read master beslistener status; the master pid was not changed." << endl;
373 cerr <<
"The beslistener status is not 'BESLISTENER_RUNNING' (it is '" << beslistener_start_status <<
"') the master pid was not changed." << endl;
378 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener start status: " << beslistener_start_status << endl);
381 master_beslistener_pid = pid;
392 static void cleanup_resources()
394 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
395 (void)
remove(file_for_daemon_pid.c_str());
406 static void CatchSigChild(
int signal)
408 if (signal == SIGCHLD) {
410 int pid = wait(&status);
412 BESDEBUG(
"besdaemon",
"besdaemon: SIGCHLD: caught master beslistener (" << pid <<
") status: " << pr_exit(status) << endl);
419 if (pid == master_beslistener_pid)
436 static void CatchSigHup(
int signal)
438 if (signal == SIGHUP) {
439 BESDEBUG(
"besdaemon",
"besdaemon: caught SIGHUP in besdaemon." << endl);
440 BESDEBUG(
"besdaemon",
"besdaemon: sending SIGHUP to the process group: " << master_beslistener_pid << endl);
446 cerr <<
"Could not restart the master beslistener." << endl;
459 static void CatchSigTerm(
int signal)
461 if (signal == SIGTERM) {
462 BESDEBUG(
"besdaemon",
"besdaemon: caught SIGTERM." << endl);
463 BESDEBUG(
"besdaemon",
"besdaemon: sending SIGTERM to the process group: " << master_beslistener_pid << endl);
488 BESDEBUG(
"besdaemon",
"besdaemon: Starting command processor." << endl);
499 port = strtol(port_str.c_str(), &ptr, 10);
501 cerr <<
"Invalid port number for daemon command interface: " << port_str << endl;
507 BESDEBUG(
"besdaemon",
"besdaemon: listening on port: " << port << endl);
509 listener.
listen(my_socket);
516 if (!usock_str.empty()) {
517 BESDEBUG(
"besdaemon",
"besdaemon: listening on unix socket: " << usock_str << endl);
519 listener.
listen(unix_socket);
522 if (!port_found && !usock_found) {
523 BESDEBUG(
"besdaemon",
"Neither a port nor a unix socket was set for the daemon command interface." << endl);
527 BESDEBUG(
"besdaemon",
"besdaemon: starting command interface on port: " << port << endl);
528 command_server =
new PPTServer(&handler, &listener,
false);
535 delete command_server;
553 delete command_server;
566 cerr <<
"daemon: " <<
"caught unknown exception" << endl;
567 delete command_server;
589 static void register_signal_handlers()
591 struct sigaction act;
594 sigemptyset(&act.sa_mask);
595 sigaddset(&act.sa_mask, SIGCHLD);
596 sigaddset(&act.sa_mask, SIGTERM);
597 sigaddset(&act.sa_mask, SIGHUP);
600 BESDEBUG(
"besdaemon" ,
"besdaemon: setting restart for sigchld." << endl);
601 act.sa_flags |= SA_RESTART;
604 act.sa_handler = CatchSigChild;
605 if (sigaction(SIGCHLD, &act, 0)) {
606 cerr <<
"Could not register a handler to catch beslistener status." << endl;
610 act.sa_handler = CatchSigTerm;
611 if (sigaction(SIGTERM, &act, 0) < 0) {
612 cerr <<
"Could not register a handler to catch the terminate signal." << endl;
616 act.sa_handler = CatchSigHup;
617 if (sigaction(SIGHUP, &act, 0) < 0) {
618 cerr <<
"Could not register a handler to catch the hang-up signal." << endl;
629 static int daemon_init()
632 if ((pid = fork()) < 0)
646 static void store_daemon_id(
int pid)
648 ofstream f(file_for_daemon_pid.c_str());
650 cerr << errno_str(
": unable to create pid file " + file_for_daemon_pid +
": ");
653 f <<
"PID: " << pid <<
" UID: " << getuid() << endl;
655 mode_t new_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
656 (void) chmod(file_for_daemon_pid.c_str(), new_mode);
668 static bool load_names(
const string &install_dir,
const string &pid_dir)
670 string bindir =
"/bin";
671 if (!pid_dir.empty()) {
672 file_for_daemon_pid = pid_dir;
675 if (!install_dir.empty()) {
676 beslistener_path = install_dir;
677 beslistener_path += bindir;
678 if (file_for_daemon_pid.empty()) {
681 file_for_daemon_pid = install_dir +
"/var/run/bes";
686 string prog = daemon_name;
687 string::size_type slash = prog.find_last_of(
'/');
688 if (slash != string::npos) {
689 beslistener_path = prog.substr(0, slash);
690 slash = prog.find_last_of(
'/');
691 if (slash != string::npos) {
692 string root = prog.substr(0, slash);
693 if (file_for_daemon_pid.empty()) {
696 file_for_daemon_pid = root +
"/var/run/bes";
700 if (file_for_daemon_pid.empty()) {
701 file_for_daemon_pid = beslistener_path;
707 if (beslistener_path ==
"") {
708 beslistener_path =
".";
709 if (file_for_daemon_pid.empty()) {
710 file_for_daemon_pid =
"./run/bes";
717 if (access(beslistener_path.c_str(), F_OK) != 0) {
718 cerr << daemon_name <<
": cannot find " << beslistener_path << endl <<
"Please either pass -i <install_dir> on the command line." << endl;
723 global_args[
"beslistener"] = beslistener_path;
728 static void set_group_id() {
729 #if !defined(OS2) && !defined(TPF)
735 BESDEBUG(
"server",
"beslisterner: Setting group id ... " << endl );
737 string key =
"BES.Group";
742 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
749 if (!found || group_str.empty()) {
750 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
751 string err =
"FAILED: Group not specified in BES configuration file";
756 BESDEBUG(
"server",
"to " << group_str <<
" ... " << endl );
759 if (group_str[0] ==
'#') {
761 const char *group_c = group_str.c_str();
763 new_gid = atoi(group_c);
768 ent = getgrnam(group_str.c_str());
770 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
771 string err = (string)
"FAILED: Group " + group_str +
" does not exist";
776 new_gid = ent->gr_gid;
780 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
782 err <<
"FAILED: Group id " << new_gid <<
" not a valid group id for BES";
783 cerr << err.str() << endl;
788 BESDEBUG(
"server",
"to id " << new_gid <<
" ... " << endl );
789 if (setgid(new_gid) == -1) {
790 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
792 err <<
"FAILED: unable to set the group id to " << new_gid;
793 cerr << err.str() << endl;
800 BESDEBUG(
"server",
"beslisterner: Groups not supported in this OS" << endl );
804 static void set_user_id() {
805 BESDEBUG(
"server",
"beslisterner: Setting user id ... " << endl );
812 string key =
"BES.User";
817 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
818 string err = (string)
"FAILED: " + e.
get_message();
824 if (!found || user_str.empty()) {
825 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
826 string err = (string)
"FAILED: User not specified in BES config file";
831 BESDEBUG(
"server",
"to " << user_str <<
" ... " << endl );
834 if (user_str[0] ==
'#') {
835 const char *user_str_c = user_str.c_str();
837 new_id = atoi(user_str_c);
841 ent = getpwnam(user_str.c_str());
843 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
844 string err = (string)
"FAILED: Bad user name specified: " + user_str;
849 new_id = ent->pw_uid;
854 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
855 string err = (string)
"FAILED: BES cannot run as root";
861 BESDEBUG(
"server",
"to " << new_id <<
" ... " << endl );
862 if (setuid(new_id) == -1) {
863 BESDEBUG(
"server",
"beslisterner: FAILED" << endl );
865 err <<
"FAILED: Unable to set user id to " << new_id;
866 cerr << err.str() << endl;
875 int main(
int argc,
char *argv[])
877 uid_t curr_euid = geteuid();
879 #ifndef BES_DEVELOPER
882 cerr <<
"FAILED: Must be root to run BES" << endl;
886 cerr <<
"Developer Mode: Not testing if BES is run by root" << endl;
889 daemon_name = argv[0];
903 string config_file =
"";
905 unsigned short num_args = 1;
909 while ((c = getopt(argc, argv,
"hvsd:c:p:u:i:r:")) != EOF) {
919 install_dir = optarg;
921 cout <<
"The specified install directory (-i option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
924 global_args[
"-i"] = install_dir;
928 global_args[
"-s"] =
"";
934 cout <<
"The specified state directory (-r option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
937 global_args[
"-r"] = pid_dir;
941 config_file = optarg;
943 cout <<
"The specified configuration file (-c option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
946 global_args[
"-c"] = config_file;
951 string check_path = optarg;
953 cout <<
"The specified unix socket (-u option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
956 global_args[
"-u"] = check_path;
962 string port_num = optarg;
963 for (
unsigned int i = 0; i < port_num.length(); i++) {
964 if (!isdigit(port_num[i])) {
965 cout <<
"The specified port contains non-digit " <<
"characters: " << port_num << endl;
969 global_args[
"-p"] = port_num;
975 string check_arg = optarg;
977 cout <<
"The specified debug options \"" << check_arg <<
"\" contains invalid characters" << endl;
981 global_args[
"-d"] = check_arg;
982 debug_sink = check_arg.substr(0, check_arg.find(
','));
995 if (argc > num_args) {
996 cout << daemon_name <<
": too many arguments passed to the BES";
1000 if (pid_dir.empty()) {
1001 pid_dir = install_dir;
1005 if (!config_file.empty()) {
1012 if (install_dir.empty() && !install_dir.empty()) {
1013 if (install_dir[install_dir.length() - 1] !=
'/') {
1016 string conf_file = install_dir +
"etc/bes/bes.conf";
1021 if (!load_names(install_dir, pid_dir))
1024 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
1025 ifstream temp(file_for_daemon_pid.c_str());
1026 cout << daemon_name <<
": there seems to be a BES daemon already running at ";
1028 temp.getline(buf, 500);
1029 cout << buf << endl;
1036 store_daemon_id(getpid());
1038 register_signal_handlers();
1045 cerr <<
"Could not initialize the modules to get the log contexts." << endl;
1056 #ifdef BES_DEVELOPER
1057 cerr <<
"Developer Mode: Running as root - setting group and user ids"
1065 cerr <<
"Developer Mode: Not setting group or user ids" << endl;
1076 if (global_args.count(
"-d") == 0)
1109 if (master_beslistener_pid == 0) {
1110 cerr << daemon_name <<
": server cannot mount at first try (core dump). " <<
"Please correct problems on the process manager " << beslistener_path << endl;
1111 return master_beslistener_pid;
1115 store_daemon_id(getpid());
1118 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid: " << master_beslistener_pid << endl);
1124 int status = start_command_processor(handler);
1145 BESDEBUG(
"besdaemon",
"besdaemon: past the command processor start" << endl);
1147 cleanup_resources();