summaryrefslogtreecommitdiffstats
path: root/qarsh/qarshd.c
diff options
context:
space:
mode:
Diffstat (limited to 'qarsh/qarshd.c')
-rw-r--r--qarsh/qarshd.c48
1 files changed, 40 insertions, 8 deletions
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,