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;
96 static volatile int master_beslistener_pid = -1;
100 static string debug_sink =
"";
108 static volatile sig_atomic_t sigchild = 0;
109 static volatile sig_atomic_t sigterm = 0;
110 static volatile sig_atomic_t sighup = 0;
112 static string errno_str(
const string &msg)
115 oss << daemon_name << msg;
116 const char *perror_string = strerror(errno);
118 oss << perror_string;
131 static int pr_exit(
int status)
133 if (WIFEXITED( status )) {
134 switch (WEXITSTATUS( status )) {
139 cerr << daemon_name <<
": server cannot start, exited with status " << WEXITSTATUS( status ) << endl;
140 cerr <<
"Please check all error messages " <<
"and adjust server installation" << endl;
144 cerr << daemon_name <<
": abnormal server termination, exited with status " << WEXITSTATUS( status ) << endl;
148 cerr << daemon_name <<
": server has been requested to re-start." << endl;
155 else if (WIFSIGNALED( status )) {
156 cerr << daemon_name <<
": abnormal server termination, signaled with signal number " << WTERMSIG( status ) << endl;
158 if (WCOREDUMP( status )) {
159 cerr << daemon_name <<
": server dumped core." << endl;
165 else if (WIFSTOPPED( status )) {
166 cerr << daemon_name <<
": abnormal server termination, stopped with signal number " << WSTOPSIG( status ) << endl;
181 sigaddset(&set, SIGCHLD);
182 sigaddset(&set, SIGHUP);
183 sigaddset(&set, SIGTERM);
185 if (sigprocmask(SIG_BLOCK, &set, 0) < 0) {
186 cerr << errno_str(
": sigprocmask error, blocking signals in stop_all_beslisteners ");
195 sigaddset(&set, SIGCHLD);
196 sigaddset(&set, SIGHUP);
197 sigaddset(&set, SIGTERM);
199 if (sigprocmask(SIG_UNBLOCK, &set, 0) < 0) {
200 cerr << errno_str(
": sigprocmask error unblocking signals in stop_all_beslisteners ");
219 BESDEBUG(
"besdaemon",
"besdaemon: stopping listeners" << endl);
223 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid " << master_beslistener_pid << endl);
226 int status = killpg(master_beslistener_pid, sig);
229 cerr <<
"The sig argument is not a valid signal number." << endl;
233 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;
237 cerr <<
"No process can be found in the process group specified by the process group (" << master_beslistener_pid <<
")." << endl;
244 bool mbes_status_caught =
false;
246 while ((pid = wait(&status)) > 0) {
247 BESDEBUG(
"besdaemon",
"besdaemon: caught listener: " << pid <<
" raw status: " << status << endl);
248 if (pid == master_beslistener_pid) {
250 mbes_status_caught =
true;
255 BESDEBUG(
"besdaemon",
"besdaemon: done catching listeners (last pid:" << pid <<
")" << endl);
258 BESDEBUG(
"besdaemon",
"besdaemon: unblocking signals " << endl);
259 return mbes_status_caught;
271 char **arguments =
new char*[global_args.size() * 2 + 1];
275 arguments[0] = strdup(global_args[
"beslistener"].c_str());
278 arg_map::iterator it;
279 for (it = global_args.begin() ; it != global_args.end(); ++it) {
280 BESDEBUG(
"besdaemon",
"besdaemon; global_args " << (*it).first <<
" => " << (*it).second << endl);
284 if ((*it).first ==
"-d") {
285 arguments[i++] = strdup(
"-d");
290 arguments[i++] = strdup(debug_opts.c_str());
292 else if ((*it).first !=
"beslistener") {
293 arguments[i++] = strdup((*it).first.c_str());
294 arguments[i++] = strdup((*it).second.c_str());
319 if (pipe(pipefd) < 0) {
320 cerr << errno_str(
": pipe error ");
325 if ((pid = fork()) < 0) {
326 cerr << errno_str(
": fork error ");
341 cerr << errno_str(
": dup2 error ");
349 BESDEBUG(
"besdaemon",
"Starting: " << arguments[0] << endl);
358 execvp(arguments[0], arguments);
361 cerr << errno_str(
": mounting listener, subprocess failed: ");
372 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener pid: " << pid << endl);
375 int beslistener_start_status;
376 int status = read(pipefd[0], &beslistener_start_status,
sizeof(beslistener_start_status));
379 cerr <<
"Could not read master beslistener status; the master pid was not changed." << endl;
384 cerr <<
"The beslistener status is not 'BESLISTENER_RUNNING' (it is '" << beslistener_start_status <<
"') the master pid was not changed." << endl;
389 BESDEBUG(
"besdaemon",
"besdaemon: master beslistener start status: " << beslistener_start_status << endl);
392 master_beslistener_pid = pid;
403 static void cleanup_resources()
405 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
406 (void)
remove(file_for_daemon_pid.c_str());
413 static void CatchSigChild(
int signal)
415 if (signal == SIGCHLD) {
420 static void CatchSigHup(
int signal)
422 if (signal == SIGHUP) {
427 static void CatchSigTerm(
int signal)
429 if (signal == SIGTERM) {
434 static void process_signals()
444 int pid = wait(&status);
472 cerr <<
"Could not restart the master beslistener." << endl;
510 BESDEBUG(
"besdaemon",
"besdaemon: Starting command processor." << endl);
521 port = strtol(port_str.c_str(), &ptr, 10);
523 cerr <<
"Invalid port number for daemon command interface: " << port_str << endl;
529 BESDEBUG(
"besdaemon",
"besdaemon: listening on port: " << port << endl);
531 listener.
listen(my_socket);
538 if (!usock_str.empty()) {
539 BESDEBUG(
"besdaemon",
"besdaemon: listening on unix socket: " << usock_str << endl);
541 listener.
listen(unix_socket);
544 if (!port_found && !usock_found) {
545 BESDEBUG(
"besdaemon",
"Neither a port nor a unix socket was set for the daemon command interface." << endl);
549 BESDEBUG(
"besdaemon",
"besdaemon: starting command interface on port: " << port << endl);
550 command_server =
new PPTServer(&handler, &listener,
false);
562 delete command_server;
584 delete command_server;
598 cerr <<
"daemon: " <<
"caught unknown exception" << endl;
600 delete command_server;
614 delete command_server;
637 static void register_signal_handlers()
639 struct sigaction act;
642 sigemptyset(&act.sa_mask);
643 sigaddset(&act.sa_mask, SIGCHLD);
644 sigaddset(&act.sa_mask, SIGTERM);
645 sigaddset(&act.sa_mask, SIGHUP);
648 BESDEBUG(
"besdaemon" ,
"besdaemon: setting restart for sigchld." << endl);
649 act.sa_flags |= SA_RESTART;
652 act.sa_handler = CatchSigChild;
653 if (sigaction(SIGCHLD, &act, 0)) {
654 cerr <<
"Could not register a handler to catch beslistener status." << endl;
658 act.sa_handler = CatchSigTerm;
659 if (sigaction(SIGTERM, &act, 0) < 0) {
660 cerr <<
"Could not register a handler to catch the terminate signal." << endl;
664 act.sa_handler = CatchSigHup;
665 if (sigaction(SIGHUP, &act, 0) < 0) {
666 cerr <<
"Could not register a handler to catch the hang-up signal." << endl;
677 static int daemon_init()
680 if ((pid = fork()) < 0)
694 static void store_daemon_id(
int pid)
696 ofstream f(file_for_daemon_pid.c_str());
698 cerr << errno_str(
": unable to create pid file " + file_for_daemon_pid +
": ");
701 f <<
"PID: " << pid <<
" UID: " << getuid() << endl;
703 mode_t new_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
704 (void) chmod(file_for_daemon_pid.c_str(), new_mode);
716 static bool load_names(
const string &install_dir,
const string &pid_dir)
718 string bindir =
"/bin";
719 if (!pid_dir.empty()) {
720 file_for_daemon_pid = pid_dir;
723 if (!install_dir.empty()) {
724 beslistener_path = install_dir;
725 beslistener_path += bindir;
726 if (file_for_daemon_pid.empty()) {
729 file_for_daemon_pid = install_dir +
"/var/run/bes";
734 string prog = daemon_name;
735 string::size_type slash = prog.find_last_of(
'/');
736 if (slash != string::npos) {
737 beslistener_path = prog.substr(0, slash);
738 slash = prog.find_last_of(
'/');
739 if (slash != string::npos) {
740 string root = prog.substr(0, slash);
741 if (file_for_daemon_pid.empty()) {
744 file_for_daemon_pid = root +
"/var/run/bes";
748 if (file_for_daemon_pid.empty()) {
749 file_for_daemon_pid = beslistener_path;
755 if (beslistener_path ==
"") {
756 beslistener_path =
".";
757 if (file_for_daemon_pid.empty()) {
758 file_for_daemon_pid =
"./run/bes";
765 if (access(beslistener_path.c_str(), F_OK) != 0) {
766 cerr << daemon_name <<
": cannot find " << beslistener_path << endl <<
"Please either pass -i <install_dir> on the command line." << endl;
771 global_args[
"beslistener"] = beslistener_path;
776 static void set_group_id() {
777 #if !defined(OS2) && !defined(TPF)
783 BESDEBUG(
"server",
"beslistener: Setting group id ... " << endl );
785 string key =
"BES.Group";
790 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
797 if (!found || group_str.empty()) {
798 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
799 string err =
"FAILED: Group not specified in BES configuration file";
804 BESDEBUG(
"server",
"to " << group_str <<
" ... " << endl );
807 if (group_str[0] ==
'#') {
809 const char *group_c = group_str.c_str();
811 new_gid = atoi(group_c);
816 ent = getgrnam(group_str.c_str());
818 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
819 string err = (string)
"FAILED: Group " + group_str +
" does not exist";
824 new_gid = ent->gr_gid;
828 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
830 err <<
"FAILED: Group id " << new_gid <<
" not a valid group id for BES";
831 cerr << err.str() << endl;
836 BESDEBUG(
"server",
"to id " << new_gid <<
" ... " << endl );
837 if (setgid(new_gid) == -1) {
838 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
840 err <<
"FAILED: unable to set the group id to " << new_gid;
841 cerr << err.str() << endl;
848 BESDEBUG(
"server",
"beslistener: Groups not supported in this OS" << endl );
852 static void set_user_id() {
853 BESDEBUG(
"server",
"beslistener: Setting user id ... " << endl );
860 string key =
"BES.User";
865 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
866 string err = (string)
"FAILED: " + e.
get_message();
872 if (!found || user_str.empty()) {
873 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
874 string err = (string)
"FAILED: User not specified in BES config file";
879 BESDEBUG(
"server",
"to " << user_str <<
" ... " << endl );
882 if (user_str[0] ==
'#') {
883 const char *user_str_c = user_str.c_str();
885 new_id = atoi(user_str_c);
889 ent = getpwnam(user_str.c_str());
891 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
892 string err = (string)
"FAILED: Bad user name specified: " + user_str;
897 new_id = ent->pw_uid;
902 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
903 string err = (string)
"FAILED: BES cannot run as root";
909 BESDEBUG(
"server",
"to " << new_id <<
" ... " << endl );
910 if (setuid(new_id) == -1) {
911 BESDEBUG(
"server",
"beslistener: FAILED" << endl );
913 err <<
"FAILED: Unable to set user id to " << new_id;
914 cerr << err.str() << endl;
923 int main(
int argc,
char *argv[])
925 uid_t curr_euid = geteuid();
927 #ifndef BES_DEVELOPER
930 cerr <<
"FAILED: Must be root to run BES" << endl;
934 cerr <<
"Developer Mode: Not testing if BES is run by root" << endl;
938 daemon_name = argv[0];
942 daemon_name =
"besdaemon";
957 string config_file =
"";
959 unsigned short num_args = 1;
963 while ((c = getopt(argc, argv,
"hvsd:c:p:u:i:r:")) != EOF) {
973 install_dir = optarg;
975 cout <<
"The specified install directory (-i option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
978 global_args[
"-i"] = install_dir;
982 global_args[
"-s"] =
"";
988 cout <<
"The specified state directory (-r option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
991 global_args[
"-r"] = pid_dir;
995 config_file = optarg;
997 cout <<
"The specified configuration file (-c option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
1000 global_args[
"-c"] = config_file;
1005 string check_path = optarg;
1007 cout <<
"The specified unix socket (-u option) " <<
"is incorrectly formatted. Must be less than " <<
"255 characters and include the characters " <<
"[0-9A-z_./-]" << endl;
1010 global_args[
"-u"] = check_path;
1016 string port_num = optarg;
1017 for (
unsigned int i = 0; i < port_num.length(); i++) {
1018 if (!isdigit(port_num[i])) {
1019 cout <<
"The specified port contains non-digit " <<
"characters: " << port_num << endl;
1023 global_args[
"-p"] = port_num;
1029 string check_arg = optarg;
1031 cout <<
"The specified debug options \"" << check_arg <<
"\" contains invalid characters" << endl;
1035 global_args[
"-d"] = check_arg;
1036 debug_sink = check_arg.substr(0, check_arg.find(
','));
1049 if (argc > num_args) {
1050 cout << daemon_name <<
": too many arguments passed to the BES";
1054 if (pid_dir.empty()) {
1055 pid_dir = install_dir;
1059 if (!config_file.empty()) {
1066 if (install_dir.empty() && !install_dir.empty()) {
1067 if (install_dir[install_dir.length() - 1] !=
'/') {
1070 string conf_file = install_dir +
"etc/bes/bes.conf";
1075 if (!load_names(install_dir, pid_dir))
1078 if (!access(file_for_daemon_pid.c_str(), F_OK)) {
1079 ifstream temp(file_for_daemon_pid.c_str());
1080 cout << daemon_name <<
": there seems to be a BES daemon already running at ";
1082 temp.getline(buf, 500);
1083 cout << buf << endl;
1090 store_daemon_id(getpid());
1092 register_signal_handlers();
1099 cerr <<
"Could not initialize the modules to get the log contexts." << endl;
1110 #ifdef BES_DEVELOPER
1111 cerr <<
"Developer Mode: Running as root - setting group and user ids"
1119 cerr <<
"Developer Mode: Not setting group or user ids" << endl;
1130 if (global_args.count(
"-d") == 0)
1163 if (master_beslistener_pid == 0) {
1164 cerr << daemon_name <<
": server cannot mount at first try (core dump). " <<
"Please correct problems on the process manager " << beslistener_path << endl;
1165 return master_beslistener_pid;
1169 store_daemon_id(getpid());
1172 BESDEBUG(
"besdaemon",
"besdaemon: master_beslistener_pid: " << master_beslistener_pid << endl);
1178 int status = start_command_processor(handler);
1202 BESDEBUG(
"besdaemon",
"besdaemon: past the command processor start" << endl);
1204 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...
volatile int master_beslistener_status
#define SERVER_EXIT_FATAL_CANNOT_START
#define DAEMON_UNIX_SOCK_STR
static void SetUp(const string &values)
Sets up debugging for the bes.
#define BESLISTENER_RUNNING
void unblock_signals()
See block_signals()
#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...
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)
void block_signals()
For code that must use signals to stop and start the master listener, block signals being delivered t...
volatile int num_children
#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