Page MenuHomeClusterLabs Projects

No OneTemporary

diff --git a/src/handler.c b/src/handler.c
index 8f2208c..b315138 100644
--- a/src/handler.c
+++ b/src/handler.c
@@ -1,271 +1,271 @@
/*
* Copyright (C) 2014 Philipp Marek <philipp.marek@linbit.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <inttypes.h>
#include <dirent.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include "ticket.h"
#include "config.h"
#include "inline-fn.h"
#include "log.h"
#include "pacemaker.h"
#include "booth.h"
#include "handler.h"
static int set_booth_env(struct ticket_config *tk)
{
int rv;
char expires[16];
sprintf(expires, "%" PRId64, (int64_t)wall_ts(&tk->term_expires));
rv = setenv("BOOTH_TICKET", tk->name, 1) ||
setenv("BOOTH_LOCAL", local->addr_string, 1) ||
setenv("BOOTH_CONF_NAME", booth_conf->name, 1) ||
setenv("BOOTH_CONF_PATH", cl.configfile, 1) ||
setenv("BOOTH_TICKET_EXPIRES", expires, 1);
if (rv) {
log_error("Cannot set environment: %s", strerror(errno));
}
return rv;
}
static void
closefiles(void)
{
int fd;
/* close all descriptors except stdin/out/err */
for (fd = getdtablesize() - 1; fd > STDERR_FILENO; fd--) {
close(fd);
}
}
static void
run_ext_prog(struct ticket_config *tk, char *prog)
{
if (set_booth_env(tk)) {
_exit(1);
}
closefiles(); /* don't leak open files */
tk_log_debug("running handler %s", prog);
execv(prog, tk_test.argv);
tk_log_error("%s: execv failed (%s)", prog, strerror(errno));
_exit(1);
}
static int
prog_filter(const struct dirent *dp)
{
return (*dp->d_name != '.');
}
static pid_t curr_pid;
static int ignore_status;
static int
test_exit_status(struct ticket_config *tk, char *prog, int status, int log_msg)
{
int rv = -1;
if (WIFEXITED(status)) {
rv = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
rv = 128 + WTERMSIG(status);
}
if (rv) {
if (log_msg) {
tk_log_warn("handler \"%s\" failed: %s",
prog, interpret_rv(status));
tk_log_warn("we are not allowed to acquire ticket");
}
} else {
tk_log_debug("handler \"%s\" exited with success",
prog);
}
return rv;
}
static void
reset_test_state(struct ticket_config *tk)
{
tk_test.pid = 0;
tk_test.progstate = EXTPROG_IDLE;
}
int tk_test_exit_status(struct ticket_config *tk)
{
int rv;
rv = test_exit_status(tk, tk_test.path, tk_test.status, !tk_test.is_dir);
reset_test_state(tk);
return rv;
}
void wait_child(int sig)
{
int i, status;
struct ticket_config *tk;
/* use waitpid(2) and not wait(2) in order not to interfear
* with popen(2)/pclose(2) and system(2) used in pacemaker.c
*/
foreach_ticket(i, tk) {
- if (tk_test.path && tk_test.pid >= 0 &&
+ if (tk_test.path && tk_test.pid > 0 &&
(tk_test.progstate == EXTPROG_RUNNING ||
tk_test.progstate == EXTPROG_IGNORE) &&
waitpid(tk_test.pid, &status, WNOHANG) == tk_test.pid) {
if (tk_test.progstate == EXTPROG_IGNORE) {
/* not interested in the outcome */
reset_test_state(tk);
} else {
tk_test.status = status;
tk_test.progstate = EXTPROG_EXITED;
}
}
}
}
/* the parent may want to have us stop processing scripts, say
* when the ticket gets revoked
*/
static void ignore_rest(int sig)
{
signal(SIGTERM, SIG_IGN);
log_info("external programs handler caught TERM, ignoring status of external test programs");
ignore_status = 1;
if (curr_pid > 0) {
(void)kill(curr_pid, SIGTERM);
}
}
void ext_prog_timeout(struct ticket_config *tk)
{
tk_log_warn("handler timed out");
}
int is_ext_prog_running(struct ticket_config *tk)
{
if (!tk_test.path)
return 0;
return (tk_test.pid > 0 && tk_test.progstate == EXTPROG_RUNNING);
}
void ignore_ext_test(struct ticket_config *tk)
{
if (is_ext_prog_running(tk)) {
(void)kill(tk_test.pid, SIGTERM);
tk_test.progstate = EXTPROG_IGNORE;
}
}
static void
process_ext_dir(struct ticket_config *tk)
{
char prog[FILENAME_MAX+1];
int rv, n_progs, i, status;
struct dirent **proglist, *dp;
signal(SIGTERM, (__sighandler_t)ignore_rest);
signal(SIGCHLD, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
signal(SIGINT, SIG_DFL);
tk_log_debug("running programs in directory %s", tk_test.path);
n_progs = scandir(tk_test.path, &proglist, prog_filter, alphasort);
if (n_progs == -1) {
tk_log_error("%s: scandir failed (%s)", tk_test.path, strerror(errno));
_exit(1);
}
for (i = 0; i < n_progs; i++) {
if (ignore_status)
break;
dp = proglist[i];
if (strlen(dp->d_name) + strlen(tk_test.path) + 1 > FILENAME_MAX) {
tk_log_error("%s: name exceeds max length (%s)",
tk_test.path, dp->d_name);
_exit(1);
}
strcpy(prog, tk_test.path);
strcat(prog, "/");
strcat(prog, dp->d_name);
switch(curr_pid=fork()) {
case -1:
log_error("fork: %s", strerror(errno));
_exit(1);
case 0: /* child */
run_ext_prog(tk, prog);
default: /* parent */
while (waitpid(curr_pid, &status, 0) != curr_pid)
;
curr_pid = 0;
if (!ignore_status) {
rv = test_exit_status(tk, prog, status, 1);
if (rv)
_exit(rv);
}
}
}
_exit(0);
}
/* run some external program
* return codes:
* RUNCMD_ERR: executing program failed (or some other failure)
* RUNCMD_MORE: program forked, results later
*/
int run_handler(struct ticket_config *tk)
{
int rv = 0;
pid_t pid;
struct stat stbuf;
if (!tk_test.path)
return 0;
if (stat(tk_test.path, &stbuf)) {
tk_log_error("%s: stat failed (%s)", tk_test.path, strerror(errno));
return RUNCMD_ERR;
}
tk_test.is_dir = (stbuf.st_mode & S_IFDIR);
switch(pid=fork()) {
case -1:
log_error("fork: %s", strerror(errno));
return RUNCMD_ERR;
case 0: /* child */
if (tk_test.is_dir) {
process_ext_dir(tk);
} else {
run_ext_prog(tk, tk_test.path);
}
default: /* parent */
tk_test.pid = pid;
tk_test.progstate = EXTPROG_RUNNING;
rv = RUNCMD_MORE; /* program runs */
}
return rv;
}

File Metadata

Mime Type
text/x-diff
Expires
Wed, Feb 26, 3:12 AM (23 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1462967
Default Alt Text
(6 KB)

Event Timeline