mirror of
https://github.com/openbsd/src.git
synced 2024-12-22 07:27:59 -08:00
19a6b45e5e
previous attempt at running a check script has finished yet, so we can avoid building up a backlog of check requests. ok dlg@ tb@ giovanni@
182 lines
4.3 KiB
C
182 lines
4.3 KiB
C
/* $OpenBSD: check_script.c,v 1.22 2021/02/22 01:24:59 jmatthew Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2007 - 2014 Reyk Floeter <reyk@openbsd.org>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/wait.h>
|
|
#include <sys/time.h>
|
|
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <signal.h>
|
|
#include <pwd.h>
|
|
|
|
#include "relayd.h"
|
|
|
|
void script_sig_alarm(int);
|
|
|
|
pid_t child = -1;
|
|
|
|
void
|
|
check_script(struct relayd *env, struct host *host)
|
|
{
|
|
struct ctl_script scr;
|
|
struct table *table;
|
|
|
|
if ((host->flags & (F_CHECK_SENT|F_CHECK_DONE)) == F_CHECK_SENT)
|
|
return;
|
|
|
|
if ((table = table_find(env, host->conf.tableid)) == NULL)
|
|
fatalx("%s: invalid table id", __func__);
|
|
|
|
host->last_up = host->up;
|
|
host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
|
|
|
|
scr.host = host->conf.id;
|
|
if ((strlcpy(scr.name, host->conf.name,sizeof(scr.name)) >=
|
|
sizeof(scr.name)) ||
|
|
(strlcpy(scr.path, table->conf.path, sizeof(scr.path)) >=
|
|
sizeof(scr.path)))
|
|
fatalx("invalid script path");
|
|
memcpy(&scr.timeout, &table->conf.timeout, sizeof(scr.timeout));
|
|
|
|
if (proc_compose(env->sc_ps, PROC_PARENT, IMSG_SCRIPT, &scr,
|
|
sizeof(scr)) == 0)
|
|
host->flags |= F_CHECK_SENT;
|
|
}
|
|
|
|
void
|
|
script_done(struct relayd *env, struct ctl_script *scr)
|
|
{
|
|
struct host *host;
|
|
|
|
if ((host = host_find(env, scr->host)) == NULL)
|
|
fatalx("%s: invalid host id", __func__);
|
|
|
|
if (scr->retval < 0)
|
|
host->up = HOST_UNKNOWN;
|
|
else if (scr->retval == 0)
|
|
host->up = HOST_DOWN;
|
|
else
|
|
host->up = HOST_UP;
|
|
host->flags |= F_CHECK_DONE;
|
|
|
|
hce_notify_done(host, host->up == HOST_UP ?
|
|
HCE_SCRIPT_OK : HCE_SCRIPT_FAIL);
|
|
}
|
|
|
|
void
|
|
script_sig_alarm(int sig)
|
|
{
|
|
int save_errno = errno;
|
|
|
|
if (child != -1)
|
|
kill(child, SIGKILL);
|
|
errno = save_errno;
|
|
}
|
|
|
|
int
|
|
script_exec(struct relayd *env, struct ctl_script *scr)
|
|
{
|
|
int status = 0, ret = 0;
|
|
sig_t save_quit, save_int, save_chld;
|
|
struct itimerval it;
|
|
struct timeval *tv;
|
|
const char *file, *arg;
|
|
struct passwd *pw;
|
|
|
|
if ((env->sc_conf.flags & F_SCRIPT) == 0) {
|
|
log_warnx("%s: script disabled", __func__);
|
|
return (-1);
|
|
}
|
|
|
|
DPRINTF("%s: running script %s, host %s",
|
|
__func__, scr->path, scr->name);
|
|
|
|
arg = scr->name;
|
|
file = scr->path;
|
|
tv = &scr->timeout;
|
|
|
|
save_quit = signal(SIGQUIT, SIG_IGN);
|
|
save_int = signal(SIGINT, SIG_IGN);
|
|
save_chld = signal(SIGCHLD, SIG_DFL);
|
|
|
|
switch (child = fork()) {
|
|
case -1:
|
|
ret = -1;
|
|
goto done;
|
|
case 0:
|
|
signal(SIGQUIT, SIG_DFL);
|
|
signal(SIGINT, SIG_DFL);
|
|
signal(SIGCHLD, SIG_DFL);
|
|
|
|
if ((pw = getpwnam(RELAYD_USER)) == NULL)
|
|
fatal("%s: getpwnam", __func__);
|
|
if (chdir("/") == -1)
|
|
fatal("%s: chdir(\"/\")", __func__);
|
|
if (setgroups(1, &pw->pw_gid) ||
|
|
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
|
|
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
|
|
fatal("%s: can't drop privileges", __func__);
|
|
|
|
/*
|
|
* close fds before executing an external program, to
|
|
* prevent access to internal fds, eg. IMSG connections
|
|
* of internal processes.
|
|
*/
|
|
closefrom(STDERR_FILENO + 1);
|
|
|
|
execlp(file, file, arg, (char *)NULL);
|
|
_exit(0);
|
|
break;
|
|
default:
|
|
/* Kill the process after a timeout */
|
|
signal(SIGALRM, script_sig_alarm);
|
|
bzero(&it, sizeof(it));
|
|
bcopy(tv, &it.it_value, sizeof(it.it_value));
|
|
setitimer(ITIMER_REAL, &it, NULL);
|
|
|
|
waitpid(child, &status, 0);
|
|
break;
|
|
}
|
|
|
|
switch (ret) {
|
|
case -1:
|
|
ret = -1;
|
|
break;
|
|
default:
|
|
if (WIFEXITED(status))
|
|
ret = WEXITSTATUS(status);
|
|
else
|
|
ret = 0;
|
|
}
|
|
|
|
done:
|
|
/* Disable the process timeout timer */
|
|
bzero(&it, sizeof(it));
|
|
setitimer(ITIMER_REAL, &it, NULL);
|
|
child = -1;
|
|
|
|
signal(SIGQUIT, save_quit);
|
|
signal(SIGINT, save_int);
|
|
signal(SIGCHLD, save_chld);
|
|
signal(SIGALRM, SIG_DFL);
|
|
|
|
return (ret);
|
|
}
|