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();
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...
#define DAEMON_UNIX_SOCK_STR
static void SetUp(const string &values)
Sets up debugging for the bes.
#define BESLISTENER_RUNNING
#define SERVER_EXIT_NORMAL_SHUTDOWN
int main(int argc, char *argv[])
Run the daemon.
#define BESLISTENER_RESTART
static bool command_line_arg_ok(const string &arg)
sanitize command line arguments
#define BESLISTENER_PIPE_FD
static void show_usage(const string &app_name)
char ** update_beslistener_args()
Update the arguments passed to the master beslistener so that changes in the debug/log contexts set i...
virtual string get_message()
get the error message for this exception
#define SERVER_EXIT_ABNORMAL_TERMINATION
bool stop_all_beslisteners(int sig)
Stop all of the listeners (both the master listener and all of the child listeners that actually proc...
virtual void initConnection()
Using the info passed into the SocketLister, wait for an inbound request (see SocketListener::accept(...
Abstract exception class for the BES with basic string message.
map< string, string > arg_map
virtual void closeConnection()
static string GetOptionsString()
This method looks at the current setting of the BESDebug object and builds a string that...
#define SERVER_EXIT_FATAL_CAN_NOT_START
int start_master_beslistener()
Start the 'master beslistener' and return its PID.
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 show_version(const string &app_name)
int master_beslistener_status
#define BESLISTENER_STOPPED
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
#define SERVER_EXIT_RESTART
virtual void listen(Socket *s)
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