Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3153872
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rB Booth
Attached
Detach File
Event Timeline
Log In to Comment