From a3c885e41bc188051f8918f090be998469018bca Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Fri, 20 Sep 2013 12:23:02 -0700 Subject: Use the One Makefile to build them all This changes the names of the built binaries: login-server -> tmwa-login char-server -> tmwa-char map-server -> tmwa-map ladmin -> tmwa-admin eathena-monitor -> tmwa-monitor It also gets rid of the 'deps.make' file. --- src/monitor/GNUmakefile | 7 ++ src/monitor/main.cpp | 217 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) create mode 100644 src/monitor/GNUmakefile create mode 100644 src/monitor/main.cpp (limited to 'src/monitor') diff --git a/src/monitor/GNUmakefile b/src/monitor/GNUmakefile new file mode 100644 index 0000000..42efa8b --- /dev/null +++ b/src/monitor/GNUmakefile @@ -0,0 +1,7 @@ +.SUFFIXES: +bin/tmwa-monitor: + ${MAKE} -C ../.. bin/tmwa-monitor +clean: + rm -r ../../obj/monitor/ +%:: + ${MAKE} -C ../.. obj/monitor/$@ diff --git a/src/monitor/main.cpp b/src/monitor/main.cpp new file mode 100644 index 0000000..f6e8271 --- /dev/null +++ b/src/monitor/main.cpp @@ -0,0 +1,217 @@ +/** + * Name: eAthena processes monitor + * Original Author: Bartosz Waszak + * Rewrite Author: Ben Longbons + * License: GPL + * Compilation: + * gcc -o eathena-monitor eathena-monitor.c + */ + +#include + +#include +#include + +#include + +#include + +#include "../common/cxxstdio.hpp" +#include "../common/io.hpp" +#include "../common/utils.hpp" + +#include "../poison.hpp" + +#define LOGIN_SERVER "./login-server" +#define MAP_SERVER "./map-server" +#define CHAR_SERVER "./char-server" +#define CONFIG "conf/eathena-monitor.conf" + + +// initialiized to $HOME/tmwserver +static +FString workdir; +//the rest are relative to workdir +static +FString login_server = LOGIN_SERVER; +static +FString map_server = MAP_SERVER; +static +FString char_server = CHAR_SERVER; + +static +pid_t pid_login, pid_map, pid_char; + +static +FString make_path(XString base, XString path) +{ + MString m; + m += base; + m += '/'; + m += path; + return FString(m); +} + +static +void parse_option(XString name, ZString value) +{ + if (name == "login_server") + login_server = value; + else if (name == "map_server") + map_server = value; + else if (name == "char_server") + char_server = value; + else if (name == "workdir") + workdir = value; + else + { + FString name_ = name; + FPRINTF(stderr, "WARNING: ingnoring invalid option '%s' : '%s'\n", + name_, value); + } +} + +static +void read_config(ZString filename) +{ + std::ifstream in(filename.c_str()); + if (!in.is_open()) + { + FPRINTF(stderr, "Monitor config file not found: %s\n", filename); + exit(1); + } + + FString line; + while (io::getline(in, line)) + { + SString name; + TString value; + if (!split_key_value(line, &name, &value)) + continue; + + parse_option(name, value); + } +} + +static +pid_t start_process(ZString exec) +{ + const char *args[2] = {exec.c_str(), NULL}; + pid_t pid = fork(); + if (pid == -1) + { + FPRINTF(stderr, "Failed to fork"); + return 0; + } + if (pid == 0) + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" + execv(exec.c_str(), const_cast(args)); +#pragma GCC diagnostic pop + perror("Failed to exec"); + kill(getppid(), SIGABRT); + exit(1); + } + return pid; +} + +// Kill all children with the same signal we got, then ourself. +static +void stop_process(int sig) +{ + if (pid_map) + kill(pid_map, sig); + if (pid_login) + kill(pid_login, sig); + if (pid_char) + kill(pid_char, sig); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wold-style-cast" + signal(sig, SIG_DFL); +#pragma GCC diagnostic pop + raise(sig); +} + +int main(int argc, char *argv[]) +{ + // These are all the signals we are likely to get + // The shell handles stop/cont + signal(SIGTERM, stop_process); + signal(SIGINT, stop_process); + signal(SIGQUIT, stop_process); + signal(SIGABRT, stop_process); + + workdir = make_path(ZString(ZString::really_construct_from_a_pointer, getenv("HOME"), nullptr), "tmwserver"); + + ZString config = CONFIG; + if (argc > 1) + config = ZString(ZString::really_construct_from_a_pointer, argv[1], nullptr); + read_config(config); + + if (chdir(workdir.c_str()) < 0) + { + perror("Failed to change directory"); + exit(1); + } + + PRINTF("Starting:\n"); + PRINTF("* workdir: %s\n", workdir); + PRINTF("* login_server: %s\n", login_server); + PRINTF("* map_server: %s\n", map_server); + PRINTF("* char_server: %s\n", char_server); + { + //make sure all possible file descriptors are free for use by the servers + //if there are file descriptors higher than the max open from before the limit dropped, that's not our problem + int fd = sysconf(_SC_OPEN_MAX); + while (--fd > 2) + if (close(fd) == 0) + FPRINTF(stderr, "close fd %d\n", fd); + fd = open("/dev/null", O_RDWR); + if (fd < 0) + { + perror("open /dev/null"); + exit(1); + } + dup2(fd, 0); + dup2(fd, 1); + close(fd); + } + while (1) + { + // write stuff to stderr + timestamp_seconds_buffer timestamp; + stamp_time(timestamp); + + if (!pid_login) + { + pid_login = start_process(login_server); + FPRINTF(stderr, "[%s] forked login server: %lu\n", + timestamp, static_cast(pid_login)); + } + if (!pid_char) + { + pid_char = start_process(char_server); + FPRINTF(stderr, "[%s] forked char server: %lu\n", + timestamp, static_cast(pid_char)); + } + if (!pid_map) + { + pid_map = start_process(map_server); + FPRINTF(stderr, "[%s] forked map server: %lu\n", + timestamp, static_cast(pid_map)); + } + pid_t dead = wait(NULL); + if (dead == -1) + { + perror("Failed to wait for child"); + exit(1); + } + if (pid_login == dead) + pid_login = 0; + if (pid_char == dead) + pid_char = 0; + if (pid_map == dead) + pid_map = 0; + } +} -- cgit v1.2.3-60-g2f50