summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNate Straz <nstraz@redhat.com>2005-08-24 23:12:22 +0000
committerNate Straz <nstraz@redhat.com>2005-08-24 23:12:22 +0000
commit468d9d0d5dd436b6280639850449a38f48715894 (patch)
tree11097eec4886099a81ad9d478e5ea85e7d66209d
parente48b3f4d5002deced980f5ef8e1c4fe3eb884fbc (diff)
downloadqarsh-468d9d0d5dd436b6280639850449a38f48715894.tar.gz
qarsh-468d9d0d5dd436b6280639850449a38f48715894.tar.xz
qarsh-468d9d0d5dd436b6280639850449a38f48715894.zip
Initial pass at signal propogation. Only SIGINT is passed along at this point.
-rw-r--r--qarsh/qarsh.c56
-rw-r--r--qarsh/qarsh_packet.c48
-rw-r--r--qarsh/qarsh_packet.h10
-rw-r--r--qarsh/qarshd.c48
4 files changed, 144 insertions, 18 deletions
diff --git a/qarsh/qarsh.c b/qarsh/qarsh.c
index 0b91f5d..2c709c7 100644
--- a/qarsh/qarsh.c
+++ b/qarsh/qarsh.c
@@ -5,6 +5,7 @@
*
*/
+#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
@@ -28,6 +29,7 @@
/* Globals */
int qarsh_fd = -1; /* The control connection to qarshd */
+int signal_to_send = 0;
void
usage()
@@ -60,6 +62,12 @@ copyargs(char **argv)
}
void
+sig_handler(int sig)
+{
+ signal_to_send = sig;
+}
+
+void
set_remote_user(char *user, char *group)
{
struct qa_packet *qp;
@@ -90,6 +98,8 @@ run_remote_cmd(char *cmdline)
int l_in, l_out, l_err; /* listening sockets */
int c_in, c_out, c_err; /* client sockets */
fd_set readfds, testfds;
+ sigset_t sigmask, orig_sigmask;
+ struct sigaction sa;
int nset;
struct sockaddr_in caddr;
socklen_t clen;
@@ -160,9 +170,19 @@ run_remote_cmd(char *cmdline)
FD_SET(c_out, &readfds);
FD_SET(c_err, &readfds);
FD_SET(fileno(stdin), &readfds);
+ /* Setup signal handling stuff so we can propogate signals */
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGINT);
+ sigprocmask(SIG_BLOCK, &sigmask, &orig_sigmask);
+ sa.sa_handler = sig_handler;
+ sa.sa_mask = sigmask;
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGINT, &sa, NULL);
if (fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) != 0) {
- fprintf(stderr, "fcntl stdin O_NONBLOCK failed, %d: %s\n", errno, strerror(errno));
+ fprintf(stderr,
+ "fcntl stdin O_NONBLOCK failed, %d: %s\n",
+ errno, strerror(errno));
}
buf = malloc(1024);
memset(buf, 0, 1024);
@@ -171,47 +191,65 @@ run_remote_cmd(char *cmdline)
testfds = readfds;
memset(buf, 0, 1024);
- nset = select(FD_SETSIZE, &testfds, NULL, NULL, NULL);
- if (FD_ISSET(fileno(stdin), &testfds)) {
+ nset = pselect(FD_SETSIZE, &testfds, NULL, NULL, NULL,
+ &orig_sigmask);
+ if (nset == -1 && errno == EINTR) {
+ nset = 0;
+ }
+
+ if (signal_to_send) {
+ qp = make_qp_kill(signal_to_send);
+ send_packet(qarsh_fd, qp);
+ qpfree(qp);
+ signal_to_send = 0;
+ }
+ if (nset && FD_ISSET(fileno(stdin), &testfds)) {
do {
bufsize = read(fileno(stdin), buf, 1024);
- write(c_in, buf, bufsize);
+ if (bufsize > 0)
+ write(c_in, buf, bufsize);
} while (bufsize == 1024);
if (bufsize == 0) {
FD_CLR(fileno(stdin), &readfds);
close(c_in);
c_in = 0;
}
+ nset--;
}
- if (c_out && FD_ISSET(c_out, &testfds)) {
+ if (nset && c_out && FD_ISSET(c_out, &testfds)) {
do {
bufsize = read(c_out, buf, 1024);
- write(fileno(stdout), buf, bufsize);
+ if (bufsize > 0)
+ write(fileno(stdout), buf, bufsize);
} while (bufsize == 1024);
if (bufsize == 0) {
FD_CLR(c_out, &readfds);
close(c_out);
c_out = 0;
}
+ nset--;
}
- if (c_err && FD_ISSET(c_err, &testfds)) {
+ if (nset && c_err && FD_ISSET(c_err, &testfds)) {
do {
bufsize = read(c_err, buf, 1024);
- write(fileno(stderr), buf, bufsize);
+ if (bufsize > 0)
+ write(fileno(stderr), buf, bufsize);
} while (bufsize == 1024);
if (bufsize == 0) {
FD_CLR(c_err, &readfds);
close(c_err);
c_err = 0;
}
+ nset--;
}
- if (FD_ISSET(qarsh_fd, &testfds)) {
+ if (nset && FD_ISSET(qarsh_fd, &testfds)) {
qp = recv_packet(qarsh_fd);
/* dump_qp(qp); */
if (qp && qp->qp_type == QP_CMDEXIT) {
break;
}
+ nset--;
}
}
diff --git a/qarsh/qarsh_packet.c b/qarsh/qarsh_packet.c
index cc4f082..bad614f 100644
--- a/qarsh/qarsh_packet.c
+++ b/qarsh/qarsh_packet.c
@@ -17,6 +17,7 @@ int parse_qp_ack(xmlXPathContextPtr ctxt, struct qa_packet *qp);
int parse_qp_runcmd(xmlXPathContextPtr ctxt, struct qa_packet *qp);
int parse_qp_cmdexit(xmlXPathContextPtr ctxt, struct qa_packet *qp);
int parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp);
+int parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp);
void string_qp_hello(xmlNodePtr node, struct qa_packet *qp);
void string_qp_returncode(xmlNodePtr node, struct qa_packet *qp);
@@ -24,6 +25,7 @@ void string_qp_runcmd(xmlNodePtr node, struct qa_packet *qp);
void string_qp_ack(xmlNodePtr node, struct qa_packet *qp);
void string_qp_cmdexit(xmlNodePtr node, struct qa_packet *qp);
void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp);
+void string_qp_kill(xmlNodePtr node, struct qa_packet *qp);
void free_qp_hello(struct qa_packet *qp);
void free_qp_returncode(struct qa_packet *qp);
@@ -35,6 +37,7 @@ void dump_qp_runcmd(struct qa_packet *qp);
void dump_qp_returncode(struct qa_packet *qp);
void dump_qp_cmdexit(struct qa_packet *qp);
void dump_qp_setuser(struct qa_packet *qp);
+void dump_qp_kill(struct qa_packet *qp);
struct packet_internals {
@@ -86,6 +89,12 @@ struct packet_internals {
.pi_string = string_qp_setuser,
.pi_free = free_qp_setuser,
.pi_dump = dump_qp_setuser
+ }, {
+ .pi_name = "kill",
+ .pi_parse = parse_qp_kill,
+ .pi_string = string_qp_kill,
+ .pi_free = NULL,
+ .pi_dump = dump_qp_kill
}
};
@@ -196,6 +205,17 @@ parse_qp_setuser(xmlXPathContextPtr ctxt, struct qa_packet *qp)
return 0;
}
+int
+parse_qp_kill(xmlXPathContextPtr ctxt, struct qa_packet *qp)
+{
+ char *s;
+
+ s = get_xpath_string(ctxt, "param[@name='signal']");
+ qp->qp_kill.qp_sig = atoi(s);
+ free(s);
+ return 0;
+}
+
struct qa_packet *
parse_packet(xmlXPathContextPtr ctxt)
{
@@ -349,6 +369,14 @@ void string_qp_setuser(xmlNodePtr node, struct qa_packet *qp)
}
}
+void string_qp_kill(xmlNodePtr node, struct qa_packet *qp)
+{
+ char tmpstr[32];
+
+ snprintf(tmpstr, 32, "%d", qp->qp_kill.qp_sig);
+ xmlAddChild(node, make_param("signal", tmpstr));
+}
+
/* Must pass in a pointer, but not a malloc'ed pointer */
char *
qptostr(struct qa_packet *qp, char **qpstr, int *qpsize)
@@ -476,6 +504,20 @@ make_qp_setuser(char *user, char *group)
return qp;
}
+struct qa_packet *
+make_qp_kill(int sig)
+{
+ struct qa_packet *qp;
+ qp = malloc(sizeof *qp);
+ assert(qp);
+ memset(qp, 0, sizeof *qp);
+
+ qp->qp_type = QP_KILL;
+ qp->qp_kill.qp_sig = sig;
+
+ return qp;
+}
+
/*
* Packet deallocation functions
*/
@@ -560,6 +602,12 @@ dump_qp_setuser(struct qa_packet *qp)
}
void
+dump_qp_kill(struct qa_packet *qp)
+{
+ printf("\tsig: %d\n", qp->qp_kill.qp_sig);
+}
+
+void
dump_qp(struct qa_packet *qp)
{
printf("%s #%d\n", QP_NAME(qp->qp_type), qp->qp_seq);
diff --git a/qarsh/qarsh_packet.h b/qarsh/qarsh_packet.h
index b6d821b..64b2b2a 100644
--- a/qarsh/qarsh_packet.h
+++ b/qarsh/qarsh_packet.h
@@ -12,7 +12,8 @@ enum qa_packet_type {
QP_RUNCMD = 3,
QP_ACK = 4,
QP_CMDEXIT = 5,
- QP_SETUSER = 6
+ QP_SETUSER = 6,
+ QP_KILL = 7
};
struct qp_hello_pkt {
@@ -48,6 +49,10 @@ struct qp_setuser_pkt {
char *qp_group;
};
+struct qp_kill_pkt {
+ int qp_sig;
+};
+
#define QP_VERSION 1
struct qa_packet {
@@ -60,6 +65,7 @@ struct qa_packet {
struct qp_ack_pkt ack;
struct qp_cmdexit_pkt cmdexit;
struct qp_setuser_pkt setuser;
+ struct qp_kill_pkt kill;
} qp_u;
};
@@ -69,6 +75,7 @@ struct qa_packet {
#define qp_ack qp_u.ack
#define qp_cmdexit qp_u.cmdexit
#define qp_setuser qp_u.setuser
+#define qp_kill qp_u.kill
/* Prototypes */
char *qp_packet_type(enum qa_packet_type t);
@@ -79,6 +86,7 @@ struct qa_packet *make_qp_ack(enum qa_packet_type t, int i);
struct qa_packet *make_qp_runcmd(char *cmdline, int p_in, int p_out, int p_err);
struct qa_packet *make_qp_cmdexit(pid_t pid, int status);
struct qa_packet *make_qp_setuser(char *user, char *group);
+struct qa_packet *make_qp_kill(int sig);
char *qptostr(struct qa_packet *qp, char **qpstr, int *qpsize);
void qpfree(struct qa_packet *qp);
void dump_qp(struct qa_packet *qp);
diff --git a/qarsh/qarshd.c b/qarsh/qarshd.c
index d443704..bf8353b 100644
--- a/qarsh/qarshd.c
+++ b/qarsh/qarshd.c
@@ -1,4 +1,5 @@
+#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
@@ -25,6 +26,7 @@
/* Globals */
struct sockaddr_in peername;
+int child_exitted = 0;
int
setup_user(char *user, char *group)
@@ -49,6 +51,12 @@ setup_user(char *user, char *group)
return 1;
}
+void
+sig_handler(int sig)
+{
+ if (sig == SIGCHLD) child_exitted++;
+}
+
pid_t
run_cmd(const char *cmd, int p_in, int p_out, int p_err)
{
@@ -113,20 +121,40 @@ handle_packets(int infd)
{
fd_set rfds;
int nfd;
- struct timeval timeout;
+ struct timespec timeout;
struct qa_packet *qp = NULL, *rp = NULL;
+ sigset_t sigmask, orig_sigmask;
+ struct sigaction sa;
pid_t child_pid = 0;
int child_status;
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &sigmask, &orig_sigmask);
+ sa.sa_handler = sig_handler;
+ sa.sa_mask = sigmask;
+ sa.sa_flags = SA_RESTART;
+ sigaction(SIGCHLD, &sa, NULL);
+
for (;;) {
FD_SET(infd, &rfds);
timeout.tv_sec = 5;
- timeout.tv_usec = 0;
- nfd = select(infd+1, &rfds, NULL, NULL, &timeout);
+ nfd = pselect(infd+1, &rfds, NULL, NULL, &timeout,
+ &orig_sigmask);
if (nfd < 0) {
- syslog(LOG_ERR, "select errno %d, %s\n", errno, strerror(errno));
+ if (errno == EINTR) {
+ /* Handle signals here */
+ if (child_exitted) {
+ waitpid(child_pid, &child_status, 0);
+ rp = make_qp_cmdexit(child_pid, child_status);
+ send_packet(fileno(stdout), rp);
+ qpfree(rp);
+ }
+ } else {
+ syslog(LOG_ERR, "select errno %d, %s\n", errno, strerror(errno));
+ }
} else if (nfd > 0) {
qp = recv_packet(infd);
if (qp == NULL) {
@@ -134,6 +162,14 @@ handle_packets(int infd)
break;
}
switch (qp->qp_type) {
+ case QP_KILL:
+ if (child_pid) {
+
+ syslog(LOG_INFO, "Sending child %d signal %d",
+ child_pid, qp->qp_kill.qp_sig);
+ kill(child_pid, qp->qp_kill.qp_sig);
+ }
+ break;
case QP_SETUSER:
if (setup_user(qp->qp_setuser.qp_user,
qp->qp_setuser.qp_group) == 0) {
@@ -149,10 +185,6 @@ handle_packets(int infd)
qp->qp_runcmd.qp_stdin_port,
qp->qp_runcmd.qp_stdout_port,
qp->qp_runcmd.qp_stderr_port);
- waitpid(child_pid, &child_status, 0);
- rp = make_qp_cmdexit(child_pid, child_status);
- send_packet(fileno(stdout), rp);
- qpfree(rp);
break;
default:
syslog(LOG_WARNING,