diff --git a/sbin/hastd/hast.h b/sbin/hastd/hast.h index 1f3b3860ed77..71379178e767 100644 --- a/sbin/hastd/hast.h +++ b/sbin/hastd/hast.h @@ -127,6 +127,8 @@ struct hast_resource { int hr_extentsize; /* Maximum number of extents that are kept dirty. */ int hr_keepdirty; + /* Path to a program to execute on various events. */ + char hr_exec[PATH_MAX]; /* Path to local component. */ char hr_localpath[PATH_MAX]; diff --git a/sbin/hastd/hastd.c b/sbin/hastd/hastd.c index 31fc3bf22cc4..c5eebf4a5b4c 100644 --- a/sbin/hastd/hastd.c +++ b/sbin/hastd/hastd.c @@ -62,7 +62,7 @@ const char *cfgpath = HAST_CONFIG; /* Hastd configuration. */ static struct hastd_config *cfg; /* Was SIGCHLD signal received? */ -static bool sigchld_received = false; +bool sigchld_received = false; /* Was SIGHUP signal received? */ bool sighup_received = false; /* Was SIGINT or SIGTERM signal received? */ @@ -189,6 +189,8 @@ resource_needs_restart(const struct hast_resource *res0, return (true); if (res0->hr_timeout != res1->hr_timeout) return (true); + if (strcmp(res0->hr_exec, res1->hr_exec) != 0) + return (true); } return (false); } @@ -211,6 +213,8 @@ resource_needs_reload(const struct hast_resource *res0, return (true); if (res0->hr_timeout != res1->hr_timeout) return (true); + if (strcmp(res0->hr_exec, res1->hr_exec) != 0) + return (true); return (false); } diff --git a/sbin/hastd/hastd.h b/sbin/hastd/hastd.h index 12b384de6ed9..a32e512411ea 100644 --- a/sbin/hastd/hastd.h +++ b/sbin/hastd/hastd.h @@ -40,7 +40,7 @@ #include "hast.h" extern const char *cfgpath; -extern bool sigexit_received, sighup_received; +extern bool sigchld_received, sigexit_received, sighup_received; extern struct pidfh *pfh; void hastd_primary(struct hast_resource *res); diff --git a/sbin/hastd/parse.y b/sbin/hastd/parse.y index 5b4f3e5ac087..ca575cf1238b 100644 --- a/sbin/hastd/parse.y +++ b/sbin/hastd/parse.y @@ -61,6 +61,7 @@ static char depth0_control[HAST_ADDRSIZE]; static char depth0_listen[HAST_ADDRSIZE]; static int depth0_replication; static int depth0_timeout; +static char depth0_exec[PATH_MAX]; static char depth1_provname[PATH_MAX]; static char depth1_localpath[PATH_MAX]; @@ -130,6 +131,7 @@ yy_config_parse(const char *config, bool exitonerror) depth0_replication = HAST_REPLICATION_MEMSYNC; strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control)); strlcpy(depth0_listen, HASTD_LISTEN, sizeof(depth0_listen)); + depth0_exec[0] = '\0'; lconfig = calloc(1, sizeof(*lconfig)); if (lconfig == NULL) { @@ -190,6 +192,14 @@ yy_config_parse(const char *config, bool exitonerror) */ curres->hr_timeout = depth0_timeout; } + if (curres->hr_exec[0] == '\0') { + /* + * Exec is not set at resource-level. + * Use global or default setting. + */ + strlcpy(curres->hr_exec, depth0_exec, + sizeof(curres->hr_exec)); + } } return (lconfig); @@ -208,7 +218,7 @@ yy_config_free(struct hastd_config *config) } %} -%token CONTROL LISTEN PORT REPLICATION TIMEOUT EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON +%token CONTROL LISTEN PORT REPLICATION TIMEOUT EXEC EXTENTSIZE RESOURCE NAME LOCAL REMOTE ON %token FULLSYNC MEMSYNC ASYNC %token NUM STR OB CB @@ -239,6 +249,8 @@ statement: | timeout_statement | + exec_statement + | node_statement | resource_statement @@ -338,6 +350,32 @@ timeout_statement: TIMEOUT NUM } ; +exec_statement: EXEC STR + { + switch (depth) { + case 0: + if (strlcpy(depth0_exec, $2, sizeof(depth0_exec)) >= + sizeof(depth0_exec)) { + pjdlog_error("Exec path is too long."); + return (1); + } + break; + case 1: + if (curres == NULL) + break; + if (strlcpy(curres->hr_exec, $2, + sizeof(curres->hr_exec)) >= + sizeof(curres->hr_exec)) { + pjdlog_error("Exec path is too long."); + return (1); + } + break; + default: + assert(!"exec at wrong depth level"); + } + } + ; + node_statement: ON node_start OB node_entries CB { mynode = false; @@ -456,6 +494,7 @@ resource_start: STR curres->hr_previous_role = HAST_ROLE_INIT; curres->hr_replication = -1; curres->hr_timeout = -1; + curres->hr_exec[0] = '\0'; curres->hr_provname[0] = '\0'; curres->hr_localpath[0] = '\0'; curres->hr_localfd = -1; @@ -474,6 +513,8 @@ resource_entry: | timeout_statement | + exec_statement + | name_statement | local_statement diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c index dd26f4affb14..bc91266f2c84 100644 --- a/sbin/hastd/primary.c +++ b/sbin/hastd/primary.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include "hast.h" #include "hast_proto.h" #include "hastd.h" +#include "hooks.h" #include "metadata.h" #include "proto.h" #include "pjdlog.h" @@ -433,6 +434,7 @@ init_environment(struct hast_resource *res __unused) signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGHUP, sighandler); + signal(SIGCHLD, sighandler); } static void @@ -791,6 +793,7 @@ hastd_primary(struct hast_resource *res) signal(SIGHUP, SIG_DFL); signal(SIGCHLD, SIG_DFL); + hook_init(); init_local(res); if (real_remote(res) && init_remote(res, NULL, NULL)) sync_start(); @@ -1737,6 +1740,9 @@ sighandler(int sig) case SIGHUP: sighup_received = true; break; + case SIGCHLD: + sigchld_received = true; + break; default: assert(!"invalid condition"); } @@ -1788,6 +1794,7 @@ config_reload(void) #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) { /* @@ -1805,6 +1812,10 @@ config_reload(void) gres->hr_timeout = res->hr_timeout; modified |= MODIFIED_TIMEOUT; } + if (strcmp(gres->hr_exec, res->hr_exec) != 0) { + strlcpy(gres->hr_exec, res->hr_exec, sizeof(gres->hr_exec)); + modified |= MODIFIED_EXEC; + } /* * If only timeout was modified we only need to change it without * reconnecting. @@ -1830,7 +1841,8 @@ config_reload(void) "Unable to set connection timeout"); } } - } else { + } else if ((modified & + (MODIFIED_REMOTEADDR | MODIFIED_REPLICATION)) != 0) { for (ii = 0; ii < ncomps; ii++) { if (!ISREMOTE(ii)) continue; @@ -1844,6 +1856,7 @@ config_reload(void) #undef MODIFIED_REMOTEADDR #undef MODIFIED_REPLICATION #undef MODIFIED_TIMEOUT +#undef MODIFIED_EXEC pjdlog_info("Configuration reloaded successfully."); return; @@ -1907,6 +1920,9 @@ guard_thread(void *arg) sighup_received = false; config_reload(); } + hook_check(sigchld_received); + if (sigchld_received) + sigchld_received = false; timeout = KEEPALIVE_SLEEP; pjdlog_debug(2, "remote_guard: Checking connections."); diff --git a/sbin/hastd/token.l b/sbin/hastd/token.l index e5d4ca10df21..05d600c6ef10 100644 --- a/sbin/hastd/token.l +++ b/sbin/hastd/token.l @@ -49,6 +49,7 @@ listen { DP; return LISTEN; } port { DP; return PORT; } replication { DP; return REPLICATION; } timeout { DP; return TIMEOUT; } +exec { DP; return EXEC; } resource { DP; return RESOURCE; } name { DP; return NAME; } local { DP; return LOCAL; }