diff --git a/src/common/errcode.c b/src/common/errcode.c index 681f96eac726b39e5183f319affe49eade6bec6d..c03b47321be38dd3957501f011b2c5582a35b748 100644 --- a/src/common/errcode.c +++ b/src/common/errcode.c @@ -74,6 +74,10 @@ const error_table_t knot_error_msgs[] = { { KNOT_ENOTSIG, "expected a TSIG or SIG(0)" }, { KNOT_ELIMIT, "Exceeded response rate limit." }, + /* Control states. */ + { KNOT_CTL_STOP, "Stopping server." }, + { KNOT_CTL_RESTART, "Restarting server." }, + /* Network errors. */ { KNOT_NET_EADDR, "Bad address or host name." }, { KNOT_NET_ESOCKET, "Can't create socket." }, diff --git a/src/common/errcode.h b/src/common/errcode.h index 3a653c5566afe1038ace603ec653ff20de2eee0e..400a10e07a4e43c4e5222dbf5db02ccc15e32259 100644 --- a/src/common/errcode.h +++ b/src/common/errcode.h @@ -87,6 +87,10 @@ enum knot_error { KNOT_ENOTSIG, /*!< Expected a TSIG or SIG(0). */ KNOT_ELIMIT, /*!< Exceeded response rate limit. */ + /* Control states. */ + KNOT_CTL_STOP, /*!< Stop requested. */ + KNOT_CTL_RESTART, /*!< Restart requested. */ + /* Network errors. */ KNOT_NET_EADDR, KNOT_NET_ESOCKET, diff --git a/src/knot/ctl/knotc_main.c b/src/knot/ctl/knotc_main.c index 3f6517a48c7eee33f86b47a054f25bbc95fc969a..e81feefb95a193061865c2201b9b2f6c9b2f456d 100644 --- a/src/knot/ctl/knotc_main.c +++ b/src/knot/ctl/knotc_main.c @@ -45,11 +45,6 @@ #include "libknot/packet/response.h" #include "knot/zone/zone-load.h" -/*! \brief Controller constants. */ -enum knotc_constants_t { - WAITPID_TIMEOUT = 120 /*!< \brief Timeout for waiting for process. */ -}; - /*! \brief Controller flags. */ enum knotc_flag_t { F_NULL = 0 << 0, @@ -82,7 +77,6 @@ typedef struct knot_cmd { } knot_cmd_t; /* Forward decls. */ -static int cmd_start(int argc, char *argv[], unsigned flags); static int cmd_stop(int argc, char *argv[], unsigned flags); static int cmd_restart(int argc, char *argv[], unsigned flags); static int cmd_reload(int argc, char *argv[], unsigned flags); @@ -95,9 +89,8 @@ static int cmd_checkzone(int argc, char *argv[], unsigned flags); /*! \brief Table of remote commands. */ knot_cmd_t knot_cmd_tbl[] = { - {&cmd_start, 1, "start", "", "\t\tStart server (if not running)."}, - {&cmd_stop, 1, "stop", "", "\t\tStop server."}, - {&cmd_restart, 1, "restart", "", "\tRestart server."}, + {&cmd_stop, 0, "stop", "", "\t\tStop server."}, + {&cmd_restart, 0, "restart", "", "\tRestart server."}, {&cmd_reload, 0, "reload", "", "\tReload configuration and changed zones."}, {&cmd_refresh, 0, "refresh", "[zone]", "\tRefresh slave zone (all if not specified)."}, {&cmd_flush, 0, "flush", "", "\t\tFlush journal and update zone files."}, @@ -122,7 +115,6 @@ void help(void) " -f, --force \tForce operation - override some checks.\n" " -v, --verbose \tVerbose mode - additional runtime information.\n" " -V, --version \tPrint %s server version.\n" - " -w, --wait \tWait for the server to finish start/stop operations.\n" " -i, --interactive \tInteractive mode (do not daemonize).\n" " -h, --help \tPrint help and usage.\n", "127.0.0.1", REMOTE_DPORT, PACKAGE_NAME); @@ -570,167 +562,22 @@ exit: return rc; } -static int cmd_start(int argc, char *argv[], unsigned flags) -{ - /* Check config. */ - if (has_flag(flags, F_NOCONF)) { - log_server_error("Couldn't parse config file, refusing to " - "continue.\n"); - return 1; - } - - /* Fetch PID. */ - char *pidfile = pid_filename(); - pid_t pid = pid_read(pidfile); - log_server_info("Starting server...\n"); - - /* Prevent concurrent daemon launch. */ - int rc = 0; - struct stat st; - int is_pidf = 0; - - /* Check PID. */ - if (pid > 0 && pid_running(pid)) { - log_server_error("Server PID found, already running.\n"); - is_pidf = 1; - } else if (stat(pidfile, &st) == 0) { - log_server_warning("PID file '%s' exists, another process " - "is starting or PID file is stale.\n", - pidfile); - is_pidf = 1; - } - if (is_pidf) { - if (!has_flag(flags, F_FORCE)) { - free(pidfile); - return 1; - } else { - log_server_info("Forcing server start.\n"); - pid_remove(pidfile); - } - } - - /* Prepare command */ - const char *cfg = conf()->filename; - size_t args_c = 6; - const char *args[] = { - PROJECT_EXEC, - has_flag(flags, F_INTERACTIVE) ? "" : "-d", - cfg ? "-c" : "", - cfg ? cfg : "", - has_flag(flags, F_VERBOSE) ? "-v" : "", - argc > 0 ? argv[0] : "" - }; - - /* Execute command */ - if (has_flag(flags, F_INTERACTIVE)) { - log_server_info("Running in interactive mode.\n"); - } else { - log_server_info("Starting as daemon, 'stdout' and 'stderr' log " - "sinks will be closed.\n"); - } - fflush(stderr); - fflush(stdout); - - if ((rc = cmd_exec(args, args_c)) < 0) { - rc = 1; - } - fflush(stderr); - fflush(stdout); - - /* Wait for finish */ - if (has_flag(flags, F_WAIT) && !has_flag(flags, F_INTERACTIVE)) { - if (has_flag(flags, F_VERBOSE)) { - log_server_info("Waiting for server to load.\n"); - } - - /* Periodically read pidfile and wait for valid result. */ - pid = 0; - while (pid == 0 || !pid_running(pid)) { - pid = pid_read(pidfile); - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500 * 1000; - select(0, 0, 0, 0, &tv); - } - } - - free(pidfile); - return rc; -} - static int cmd_stop(int argc, char *argv[], unsigned flags) { UNUSED(argc); UNUSED(argv); + UNUSED(flags); - /* Check config. */ - if (has_flag(flags, F_NOCONF)) { - log_server_error("Couldn't parse config file, refusing to " - "continue.\n"); - return 1; - } - - /* Fetch PID. */ - char *pidfile = pid_filename(); - pid_t pid = pid_read(pidfile); - int rc = 0; - struct stat st; - - /* Check for non-existent PID file. */ - int has_pidf = (stat(pidfile, &st) == 0); - if(has_pidf && pid <= 0) { - log_server_warning("Empty PID file '%s' exists, daemon process " - "is starting or PID file is stale.\n", - pidfile); - free(pidfile); - return 1; - } else if (pid <= 0 || !pid_running(pid)) { - log_server_warning("Server PID not found, " - "probably not running.\n"); - if (!has_flag(flags, F_FORCE)) { - free(pidfile); - return 1; - } else { - log_server_info("Forcing server stop.\n"); - } - } - - /* Stop */ - log_server_info("Stopping server...\n"); - if (kill(pid, SIGTERM) < 0) { - pid_remove(pidfile); - rc = 1; - } - - - /* Wait for finish */ - if (rc == 0 && has_flag(flags, F_WAIT)) { - log_server_info("Waiting for server to finish.\n"); - while (pid_running(pid)) { - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 500 * 1000; - select(0, 0, 0, 0, &tv); - pid = pid_read(pidfile); /* Update */ - } - } - - return rc; + return cmd_remote("stop", KNOT_RRTYPE_TXT, 0, NULL); } static int cmd_restart(int argc, char *argv[], unsigned flags) { - /* Check config. */ - if (has_flag(flags, F_NOCONF)) { - log_server_error("Couldn't parse config file, refusing to " - "continue.\n"); - return 1; - } + UNUSED(argc); + UNUSED(argv); + UNUSED(flags); - int rc = 0; - rc |= cmd_stop(argc, argv, flags | F_WAIT); - rc |= cmd_start(argc, argv, flags); - return rc; + return cmd_remote("restart", KNOT_RRTYPE_TXT, 0, NULL); } static int cmd_reload(int argc, char *argv[], unsigned flags) diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c index cf558772d91f882f5bfe50159f5ec4475ac9d7d5..c0358cfedc6fd7357d1f54b37d99b96970ee2f9c 100644 --- a/src/knot/ctl/process.c +++ b/src/knot/ctl/process.c @@ -176,63 +176,3 @@ int proc_update_privileges(int uid, int gid) free(lfile); return ret; } - -pid_t pid_wait(pid_t proc, int *rc) -{ - /* Wait for finish. */ - sigset_t newset; - sigfillset(&newset); - sigprocmask(SIG_BLOCK, &newset, 0); - proc = waitpid(proc, rc, 0); - sigprocmask(SIG_UNBLOCK, &newset, 0); - return proc; -} - - -pid_t pid_start(const char *argv[], int argc, int drop_privs) -{ - pid_t chproc = fork(); - if (chproc == 0) { - - /* Alter privileges. */ - if (drop_privs) { - proc_update_privileges(conf()->uid, conf()->gid); - } - - /* Duplicate, it doesn't run from stack address anyway. */ - char **args = malloc((argc + 1) * sizeof(char*)); - memset(args, 0, (argc + 1) * sizeof(char*)); - int ci = 0; - for (int i = 0; i < argc; ++i) { - if (strlen(argv[i]) > 0) { - args[ci++] = strdup(argv[i]); - } - } - args[ci] = 0; - - /* Execute command. */ - fflush(stdout); - fflush(stderr); - execvp(args[0], args); - - /* Execute failed. */ - log_server_error("Failed to run executable '%s'\n", args[0]); - for (int i = 0; i < argc; ++i) { - free(args[i]); - } - free(args); - - exit(1); - return -1; - } - - return chproc; -} - -int cmd_exec(const char *argv[], int argc) -{ - int ret = 0; - pid_t proc = pid_start(argv, argc, 0); - pid_wait(proc, &ret); - return ret; -} diff --git a/src/knot/ctl/process.h b/src/knot/ctl/process.h index d5aa191db4b04e92cb9fd80b5b350169dac7ded8..1257417b1b41b6654632719ebc6f15451cdc12a3 100644 --- a/src/knot/ctl/process.h +++ b/src/knot/ctl/process.h @@ -94,39 +94,6 @@ int pid_running(pid_t pid); */ int proc_update_privileges(int uid, int gid); -/*! - * \brief Wait for process to finish. - * - * \param proc Process ID. - * \param rc Destination for return code. - * - * \return PID of finished process. - */ -pid_t pid_wait(pid_t proc, int *rc); - -/*! - * \brief Start command with given parameters. - * - * Set drop_privs = 1 to change privileges according to conf(). - * - * \param argv Parameter list. - * \param argc Parameter count. - * \param drop_privs Set to 1 to alter privileges. - * - * \return PID of started process. - */ -pid_t pid_start(const char *argv[], int argc, int drop_privs); - -/*! - * \brief Execute command and wait for finish. - * - * \param argv Parameter list. - * \param argc Parameter count. - * - * \return Return code. - */ -int cmd_exec(const char *argv[], int argc); - #endif // _KNOTD_PROCESS_H_ /*! @} */ diff --git a/src/knot/ctl/remote.c b/src/knot/ctl/remote.c index bc7698f4bb14b41db36ab87347821c34f1883598..0f273729b5e669b0cd53b6bfff0d248284b8a3d7 100644 --- a/src/knot/ctl/remote.c +++ b/src/knot/ctl/remote.c @@ -58,6 +58,8 @@ typedef struct remote_cmd_t { } remote_cmd_t; /* Forward decls. */ +static int remote_c_stop(server_t *s, remote_cmdargs_t* a); +static int remote_c_restart(server_t *s, remote_cmdargs_t* a); static int remote_c_reload(server_t *s, remote_cmdargs_t* a); static int remote_c_refresh(server_t *s, remote_cmdargs_t* a); static int remote_c_status(server_t *s, remote_cmdargs_t* a); @@ -66,6 +68,8 @@ static int remote_c_flush(server_t *s, remote_cmdargs_t* a); /*! \brief Table of remote commands. */ struct remote_cmd_t remote_cmd_tbl[] = { + { "stop", &remote_c_stop }, + { "restart", &remote_c_restart }, { "reload", &remote_c_reload }, { "refresh", &remote_c_refresh }, { "status", &remote_c_status }, @@ -159,6 +163,31 @@ static int remote_zone_flush(server_t *s, const knot_zone_t *z) return KNOT_EOK; } +/*! + * \brief Remote command 'stop' handler. + * + * QNAME: stop + * DATA: NULL + */ +static int remote_c_stop(server_t *s, remote_cmdargs_t* a) +{ + UNUSED(a); + UNUSED(s); + return KNOT_CTL_STOP; +} + +/*! + * \brief Remote command 'restart' handler. + * + * QNAME: restart + * DATA: NULL + */ +static int remote_c_restart(server_t *s, remote_cmdargs_t* a) +{ + UNUSED(a); + return KNOT_CTL_RESTART; +} + /*! * \brief Remote command 'reload' handler. * @@ -646,7 +675,7 @@ int remote_process(server_t *s, int r, uint8_t* buf, size_t buflen) } /* Answer packet. */ - remote_answer(c, s, pkt, buf, buflen); + ret = remote_answer(c, s, pkt, buf, buflen); } knot_packet_free(&pkt); diff --git a/src/knot/main.c b/src/knot/main.c index c06c6990cd02a60c8a78e017290353c2503a844d..10d6ec3906c73a2b67e278f766326e9c9bde816e 100644 --- a/src/knot/main.c +++ b/src/knot/main.c @@ -40,6 +40,7 @@ /* Signal flags. */ static volatile short sig_req_stop = 0; +static volatile short sig_req_rst = 0; static volatile short sig_req_reload = 0; static volatile short sig_req_refresh = 0; static volatile short sig_stopping = 0; @@ -371,6 +372,20 @@ int main(int argc, char **argv) int ret = remote_poll(remote); pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL); + /* Events. */ + if (ret > 0) { + ret = remote_process(server, remote, buf, buflen); + switch(ret) { + case KNOT_CTL_RESTART: + sig_req_rst = 1; /* Fall through */ + case KNOT_CTL_STOP: + sig_req_stop = 1; + break; + default: + break; + } + } + /* Interrupts. */ if (sig_req_stop) { sig_req_stop = 0; @@ -392,11 +407,6 @@ int main(int argc, char **argv) } } - - /* Events. */ - if (ret > 0) { - remote_process(server, remote, buf, buflen); - } } pthread_sigmask(SIG_UNBLOCK, &sa.sa_mask, NULL); @@ -434,6 +444,10 @@ int main(int argc, char **argv) fflush(stderr); } + /* Restart hook. */ + if (sig_req_rst) + return execvp(argv[0], argv); + return res; }