diff options
author | Nate Straz <nstraz@redhat.com> | 2005-08-24 16:07:46 +0000 |
---|---|---|
committer | Nate Straz <nstraz@redhat.com> | 2005-08-24 16:07:46 +0000 |
commit | 35ffc8bdc7ec6b166c0799f49d475803e6f285ff (patch) | |
tree | 4df7017959442635f3d5b1703849fd20db6a1c87 /qarsh/qarsh.c | |
download | qarsh-35ffc8bdc7ec6b166c0799f49d475803e6f285ff.tar.gz qarsh-35ffc8bdc7ec6b166c0799f49d475803e6f285ff.tar.xz qarsh-35ffc8bdc7ec6b166c0799f49d475803e6f285ff.zip |
Add initial working version of the QA Remote SHell.
Diffstat (limited to 'qarsh/qarsh.c')
-rw-r--r-- | qarsh/qarsh.c | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/qarsh/qarsh.c b/qarsh/qarsh.c new file mode 100644 index 0000000..fcfda10 --- /dev/null +++ b/qarsh/qarsh.c @@ -0,0 +1,255 @@ +/* + * QA Remote Shell - client side + * + * Run a command on the server with lots of wizz-bang options + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <netinet/in.h> +#include <netdb.h> +#include <syslog.h> + + +#include "sockutil.h" +#include "qarsh_packet.h" + +#define QARSH_MINPORT 5010 + +/* Globals */ +int qarsh_fd = -1; /* The control connection to qarshd */ + + +char * +copyargs(char **argv) +{ + int cc; + char **ap, *p; + char *args; + + cc = 0; + for (ap = argv; *ap; ++ap) + cc += strlen(*ap) + 1; + args = malloc(cc); + if (!args) { + perror("qarsh: malloc failed in copyargs"); + exit(1); + } + for (p = args, ap = argv; *ap; ++ap) { + for (p = strcpy(p, *ap); *p; ++p); + if (ap[1]) + *p++ = ' '; + } + return(args); +} + + +int +run_remote_cmd(char *cmdline) +{ + struct qa_packet *qp; + char *packetbuf; + int packetsize; + int rc; + int p_in, p_out, p_err; /* Port numbers */ + int l_in, l_out, l_err; /* listening sockets */ + int c_in, c_out, c_err; /* client sockets */ + fd_set readfds, testfds; + int nset; + struct sockaddr_in caddr; + socklen_t clen; + + l_in = bind_any(QARSH_MINPORT); + p_in = getsockport(l_in); + l_out = bind_any(QARSH_MINPORT); + p_out = getsockport(l_out); + l_err = bind_any(QARSH_MINPORT); + p_err = getsockport(l_err); + + qp = make_qp_runcmd(cmdline, p_in, p_out, p_err); + qp->qp_seq = 1; + packetbuf = qptostr(qp, &packetbuf, &packetsize); + qpfree(qp); + write(qarsh_fd, packetbuf, packetsize); + free(packetbuf); + + /* Get the stdin, stdout, and stderr connections up before we do work */ + FD_ZERO(&readfds); + FD_SET(l_in, &readfds); + FD_SET(l_out, &readfds); + FD_SET(l_err, &readfds); + c_in = c_out = c_err = 0; + + do { + testfds = readfds; + nset = select(FD_SETSIZE, &testfds, NULL, NULL, NULL); + + if (FD_ISSET(l_in, &testfds)) { + clen = sizeof caddr; + c_in = accept(l_in, (struct sockaddr *)&caddr, &clen); + if (c_in == -1) { + fprintf(stderr, + "accept of l_in failed, %d: %s\n", + errno, strerror(errno)); + continue; + } + } + if (FD_ISSET(l_out, &testfds)) { + clen = sizeof caddr; + c_out = accept(l_out, (struct sockaddr *)&caddr, &clen); + if (c_out == -1) { + fprintf(stderr, + "accept of l_out failed, %d: %s\n", + errno, strerror(errno)); + continue; + } + } + if (FD_ISSET(l_err, &testfds)) { + clen = sizeof caddr; + c_err = accept(l_err, (struct sockaddr *)&caddr, &clen); + if (c_err == -1) { + fprintf(stderr, + "accept of l_err failed, %d: %s\n", + errno, strerror(errno)); + continue; + } + } + } while (c_in == 0 || c_out == 0 || c_err == 0); + close(l_in); + close(l_out); + close(l_err); + l_in = l_out = l_err = -1; + + /* Now we can start doing some real work */ + + FD_ZERO(&readfds); + FD_SET(qarsh_fd, &readfds); + FD_SET(c_out, &readfds); + FD_SET(c_err, &readfds); + FD_SET(fileno(stdin), &readfds); + + if (fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) != 0) { + fprintf(stderr, "fcntl stdin O_NONBLOCK failed, %d: %s\n", errno, strerror(errno)); + } + packetbuf = malloc(1024); + memset(packetbuf, 0, 1024); + + for (;;) { + testfds = readfds; + memset(packetbuf, 0, 1024); + + nset = select(FD_SETSIZE, &testfds, NULL, NULL, NULL); + if (FD_ISSET(fileno(stdin), &testfds)) { + do { + packetsize = read(fileno(stdin), packetbuf, 1024); + write(c_in, packetbuf, packetsize); + } while (packetsize == 1024); + if (packetsize == 0) { + FD_CLR(fileno(stdin), &readfds); + close(c_in); + c_in = 0; + } + } + if (c_out && FD_ISSET(c_out, &testfds)) { + do { + packetsize = read(c_out, packetbuf, 1024); + write(fileno(stdout), packetbuf, packetsize); + } while (packetsize == 1024); + if (packetsize == 0) { + FD_CLR(c_out, &readfds); + close(c_out); + c_out = 0; + } + } + if (c_err && FD_ISSET(c_err, &testfds)) { + do { + packetsize = read(c_err, packetbuf, 1024); + write(fileno(stderr), packetbuf, packetsize); + } while (packetsize == 1024); + if (packetsize == 0) { + FD_CLR(c_err, &readfds); + close(c_err); + c_err = 0; + } + } + if (FD_ISSET(qarsh_fd, &testfds)) { + packetsize = read(qarsh_fd, packetbuf, 1024); + if (packetsize == 0) { + qp = NULL; + break; + } + qp = parse_packets(packetbuf, packetsize); + + /* dump_qp(qp); */ + if (qp && qp->qp_type == QP_CMDEXIT) { + break; + } + } + + } + if (c_out) close(c_out); + if (c_err) close(c_err); + if (qp == NULL) { + fprintf(stderr, "Remote command exited with unknown state\n"); + free(packetbuf); + return 127; + } + if (WIFSIGNALED(qp->qp_cmdexit.qp_status)) { + rc = 128 + WTERMSIG(qp->qp_cmdexit.qp_status); + } else { + rc = WEXITSTATUS(qp->qp_cmdexit.qp_status); + } + qpfree(qp); + free(packetbuf); + return rc; +} + +int +main(int argc, char *argv[]) +{ + + int c; + int port = 5008; + char *host; + char *args; + int ret; + + openlog("qarsh", LOG_PID, LOG_DAEMON); + + while ((c = getopt(argc, argv, "+p:")) != -1) { + switch (c) { + case 'p': + port = atoi(optarg); + break; + case '?': + default: + printf("Unknown option %c\n", (char)c); + } } + + host = argv[optind++]; + + argc -= optind; + argv += optind; + args = copyargs(argv); + + qarsh_fd = connect_to_host(host, port); + if (qarsh_fd == -1) { + fprintf(stderr, "Could not connect to %s:%d, %d: %s\n", + host, port, errno, strerror(errno)); + return 127; + } + + ret = run_remote_cmd(args); + close(qarsh_fd); + free(args); + return ret; +} |