From 115f4e5c3e3677af1d5bc3c5bb7043fc211c1e8e Mon Sep 17 00:00:00 2001 From: Pawel Jakub Dawidek Date: Mon, 24 Jan 2011 15:04:15 +0000 Subject: [PATCH] Don't open configuration file from worker process. Handle SIGHUP in the master process only and pass changes to the worker processes over control socket. This removes access to global namespace in preparation for capsicum sandboxing. MFC after: 2 weeks --- sbin/hastd/control.c | 13 +++++++- sbin/hastd/control.h | 1 + sbin/hastd/hastd.c | 48 +++++++++++++++++++++++---- sbin/hastd/hastd.h | 2 ++ sbin/hastd/primary.c | 77 ++++++++++++++++---------------------------- 5 files changed, 83 insertions(+), 58 deletions(-) diff --git a/sbin/hastd/control.c b/sbin/hastd/control.c index eab7a9e1d57b..87fa42abbf82 100644 --- a/sbin/hastd/control.c +++ b/sbin/hastd/control.c @@ -411,7 +411,6 @@ ctrl_thread(void *arg) nv_free(nvin); continue; } - nv_free(nvin); nvout = nv_alloc(); switch (cmd) { case HASTCTL_STATUS: @@ -433,11 +432,23 @@ ctrl_thread(void *arg) nv_add_uint32(nvout, (uint32_t)0, "keepdirty"); nv_add_uint64(nvout, (uint64_t)0, "dirty"); } + nv_add_int16(nvout, 0, "error"); + break; + case HASTCTL_RELOAD: + /* + * When parent receives SIGHUP and discovers that + * something related to us has changes, it sends reload + * message to us. + */ + assert(res->hr_role == HAST_ROLE_PRIMARY); + primary_config_reload(res, nvin); + nv_add_int16(nvout, 0, "error"); break; default: nv_add_int16(nvout, EINVAL, "error"); break; } + nv_free(nvin); if (nv_error(nvout) != 0) { pjdlog_error("Unable to create answer on control message."); nv_free(nvout); diff --git a/sbin/hastd/control.h b/sbin/hastd/control.h index 582617d21e18..ed8e4ffdfb05 100644 --- a/sbin/hastd/control.h +++ b/sbin/hastd/control.h @@ -34,6 +34,7 @@ #define HASTCTL_SET_ROLE 1 #define HASTCTL_STATUS 2 +#define HASTCTL_RELOAD 3 struct hastd_config; struct hast_resource; diff --git a/sbin/hastd/hastd.c b/sbin/hastd/hastd.c index ea9821e1ab5d..30478cad60ab 100644 --- a/sbin/hastd/hastd.c +++ b/sbin/hastd/hastd.c @@ -204,6 +204,45 @@ resource_needs_reload(const struct hast_resource *res0, return (false); } +static void +resource_reload(const struct hast_resource *res) +{ + struct nv *nvin, *nvout; + int error; + + assert(res->hr_role == HAST_ROLE_PRIMARY); + + nvout = nv_alloc(); + nv_add_uint8(nvout, HASTCTL_RELOAD, "cmd"); + nv_add_string(nvout, res->hr_remoteaddr, "remoteaddr"); + nv_add_int32(nvout, (int32_t)res->hr_replication, "replication"); + nv_add_int32(nvout, (int32_t)res->hr_timeout, "timeout"); + nv_add_string(nvout, res->hr_exec, "exec"); + if (nv_error(nvout) != 0) { + nv_free(nvout); + pjdlog_error("Unable to allocate header for reload message."); + return; + } + if (hast_proto_send(res, res->hr_ctrl, nvout, NULL, 0) < 0) { + pjdlog_errno(LOG_ERR, "Unable to send reload message"); + nv_free(nvout); + return; + } + nv_free(nvout); + + /* Receive response. */ + if (hast_proto_recv_hdr(res->hr_ctrl, &nvin) < 0) { + pjdlog_errno(LOG_ERR, "Unable to receive reload reply"); + return; + } + error = nv_get_int16(nvin, "error"); + nv_free(nvin); + if (error != 0) { + pjdlog_common(LOG_ERR, 0, error, "Reload failed"); + return; + } +} + static void hastd_reload(void) { @@ -338,13 +377,8 @@ hastd_reload(void) cres->hr_timeout = nres->hr_timeout; strlcpy(cres->hr_exec, nres->hr_exec, sizeof(cres->hr_exec)); - if (cres->hr_workerpid != 0) { - if (kill(cres->hr_workerpid, SIGHUP) < 0) { - pjdlog_errno(LOG_WARNING, - "Unable to send SIGHUP to worker process %u", - (unsigned int)cres->hr_workerpid); - } - } + if (cres->hr_workerpid != 0) + resource_reload(cres); } } diff --git a/sbin/hastd/hastd.h b/sbin/hastd/hastd.h index 0186e81e0e8e..1157f926e8d9 100644 --- a/sbin/hastd/hastd.h +++ b/sbin/hastd/hastd.h @@ -46,4 +46,6 @@ extern struct pidfh *pfh; void hastd_primary(struct hast_resource *res); void hastd_secondary(struct hast_resource *res, struct nv *nvin); +void primary_config_reload(struct hast_resource *res, struct nv *nv); + #endif /* !_HASTD_H_ */ diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c index e1083975379b..a4cd1725537c 100644 --- a/sbin/hastd/primary.c +++ b/sbin/hastd/primary.c @@ -836,6 +836,7 @@ hastd_primary(struct hast_resource *res) init_local(res); init_ggate(res); init_environment(res); + /* * Create the guard thread first, so we can handle signals from the * very begining. @@ -1844,47 +1845,32 @@ sync_thread(void *arg __unused) return (NULL); } -static void -config_reload(void) +void +primary_config_reload(struct hast_resource *res, struct nv *nv) { - struct hastd_config *newcfg; - struct hast_resource *res; unsigned int ii, ncomps; - int modified; + int modified, vint; + const char *vstr; pjdlog_info("Reloading configuration..."); + assert(res->hr_role == HAST_ROLE_PRIMARY); + assert(gres == res); + nv_assert(nv, "remoteaddr"); + nv_assert(nv, "replication"); + nv_assert(nv, "timeout"); + nv_assert(nv, "exec"); + ncomps = HAST_NCOMPONENTS; - newcfg = yy_config_parse(cfgpath, false); - if (newcfg == NULL) - goto failed; - - TAILQ_FOREACH(res, &newcfg->hc_resources, hr_next) { - if (strcmp(res->hr_name, gres->hr_name) == 0) - break; - } - /* - * If resource was removed from the configuration file, resource - * name, provider name or path to local component was modified we - * shouldn't be here. This means that someone modified configuration - * file and send SIGHUP to us instead of main hastd process. - * Log advice and ignore the signal. - */ - if (res == NULL || strcmp(gres->hr_name, res->hr_name) != 0 || - strcmp(gres->hr_provname, res->hr_provname) != 0 || - strcmp(gres->hr_localpath, res->hr_localpath) != 0) { - pjdlog_warning("To reload configuration send SIGHUP to the main hastd process (pid %u).", - (unsigned int)getppid()); - goto failed; - } - #define MODIFIED_REMOTEADDR 0x1 #define MODIFIED_REPLICATION 0x2 #define MODIFIED_TIMEOUT 0x4 #define MODIFIED_EXEC 0x8 modified = 0; - if (strcmp(gres->hr_remoteaddr, res->hr_remoteaddr) != 0) { + + vstr = nv_get_string(nv, "remoteaddr"); + if (strcmp(gres->hr_remoteaddr, vstr) != 0) { /* * Don't copy res->hr_remoteaddr to gres just yet. * We want remote_close() to log disconnect from the old @@ -1892,18 +1878,22 @@ config_reload(void) */ modified |= MODIFIED_REMOTEADDR; } - if (gres->hr_replication != res->hr_replication) { - gres->hr_replication = res->hr_replication; + vint = nv_get_int32(nv, "replication"); + if (gres->hr_replication != vint) { + gres->hr_replication = vint; modified |= MODIFIED_REPLICATION; } - if (gres->hr_timeout != res->hr_timeout) { - gres->hr_timeout = res->hr_timeout; + vint = nv_get_int32(nv, "timeout"); + if (gres->hr_timeout != vint) { + gres->hr_timeout = vint; modified |= MODIFIED_TIMEOUT; } - if (strcmp(gres->hr_exec, res->hr_exec) != 0) { - strlcpy(gres->hr_exec, res->hr_exec, sizeof(gres->hr_exec)); + vstr = nv_get_string(nv, "exec"); + if (strcmp(gres->hr_exec, vstr) != 0) { + strlcpy(gres->hr_exec, vstr, sizeof(gres->hr_exec)); modified |= MODIFIED_EXEC; } + /* * If only timeout was modified we only need to change it without * reconnecting. @@ -1937,7 +1927,8 @@ config_reload(void) remote_close(gres, ii); } if (modified & MODIFIED_REMOTEADDR) { - strlcpy(gres->hr_remoteaddr, res->hr_remoteaddr, + vstr = nv_get_string(nv, "remoteaddr"); + strlcpy(gres->hr_remoteaddr, vstr, sizeof(gres->hr_remoteaddr)); } } @@ -1947,16 +1938,6 @@ config_reload(void) #undef MODIFIED_EXEC pjdlog_info("Configuration reloaded successfully."); - return; -failed: - if (newcfg != NULL) { - if (newcfg->hc_controlconn != NULL) - proto_close(newcfg->hc_controlconn); - if (newcfg->hc_listenconn != NULL) - proto_close(newcfg->hc_listenconn); - yy_config_free(newcfg); - } - pjdlog_warning("Configuration not reloaded."); } static void @@ -2032,7 +2013,6 @@ guard_thread(void *arg) lastcheck = time(NULL); PJDLOG_VERIFY(sigemptyset(&mask) == 0); - PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0); @@ -2042,9 +2022,6 @@ guard_thread(void *arg) for (;;) { switch (signo) { - case SIGHUP: - config_reload(); - break; case SIGINT: case SIGTERM: sigexit_received = true;