Advertisement
Guest User

cmdctl.c

a guest
Mar 18th, 2014
303
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.11 KB | None | 0 0
  1. /*-
  2.  * Copyright (c) 2014 Unknown
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24.  * SUCH DAMAGE.
  25.  */
  26.  
  27. #include <sys/prctl.h>
  28. #include <sys/wait.h>
  29. #include <poll.h>
  30.  
  31. struct cmdctl {
  32.     pid_t       pid;
  33.     pthread_t   tp;
  34.     int     fds[6];
  35.     const char  *prefix;
  36. };
  37. static struct cmdctl *cmdctl;
  38.  
  39. static int
  40. CMD_nonblocking(int sock)
  41. {
  42.         int i, j;
  43.  
  44.         i = 1;
  45.         j = ioctl(sock, FIONBIO, &i);
  46.     assert(j == 0);
  47.         return (j);
  48. }
  49.  
  50. static void *
  51. CMD_thread(void *priv)
  52. {
  53.     struct cmdctl *v;
  54.     struct pollfd *fds, fd;
  55.     char buf[8 * 1024];
  56.     int i;
  57.  
  58.     v = priv;
  59.     CMD_nonblocking(v->fds[0]);
  60.     while (1) {
  61.         fds = &fd;
  62.         memset(fds, 0, sizeof *fds);
  63.         fds->fd = v->fds[0];
  64.         fds->events = POLLIN;
  65.         i = poll(fds, 1, 1000);
  66.         if (i == 0)
  67.             continue;
  68.         if (fds->revents & (POLLERR|POLLHUP))
  69.             break;
  70.         i = read(v->fds[0], buf, sizeof buf - 1);
  71.         if (i <= 0)
  72.             break;
  73.         buf[i] = '\0';
  74.         printf("%s%s", v->prefix, buf);
  75.     }
  76.     return (NULL);
  77. }
  78.  
  79. static void
  80. CMD_RunChild(void)
  81. {
  82.     struct pollfd *fds, fd;
  83.     int error, i, l, offset = 0;
  84.     char buf[8 * 1024], *p, *q;
  85.     char msg[1024];
  86.  
  87.     error = prctl(PR_SET_PDEATHSIG, SIGHUP);
  88.     if (error != 0)
  89.         printf("prctl(2) failed: %d %s.", errno,
  90.             strerror(errno));
  91.  
  92.     assert(dup2(cmdctl->fds[0], 0) == 0);
  93.     assert(dup2(cmdctl->fds[3], 1) == 1);
  94.     assert(dup2(1, 2) == 2);
  95.     assert(dup2(cmdctl->fds[4], 3) == 3);
  96.     AZ(close(cmdctl->fds[0]));
  97.     AZ(close(cmdctl->fds[1]));
  98.     AZ(close(cmdctl->fds[2]));
  99.     AZ(close(cmdctl->fds[3]));
  100.     setbuf(stdout, NULL);
  101.     setbuf(stderr, NULL);
  102.     CMD_nonblocking(cmdctl->fds[4]);
  103.         while (1) {
  104.                 fds = &fd;
  105.                 memset(fds, 0, sizeof *fds);
  106.                 fds->fd = cmdctl->fds[4];
  107.                 fds->events = POLLIN;
  108.                 i = poll(fds, 1, 1000);
  109.                 if (i == 0)
  110.                         continue;
  111.                 if (fds->revents & (POLLERR|POLLHUP))
  112.                         break;
  113.                 i = read(cmdctl->fds[4], buf + offset, sizeof buf - 1 - offset);
  114.                 if (i <= 0)
  115.                         break;
  116.                 buf[i] = '\0';
  117.         p = buf;
  118.         while (1) {
  119.             q = strchr(p, '\n');
  120.             if (q == NULL) {
  121.                 offset = &buf[i] - p;
  122.                 memmove(buf, p, offset);
  123.                 break;
  124.             }
  125.             offset = 0;
  126.             *q = '\0';
  127.             {
  128.                 struct cmdctl _v, *v = &_v;
  129.                 void *pp;
  130.                 int status, r;
  131.  
  132.                 AZ(pipe(&v->fds[0]));
  133.                 AZ(pipe(&v->fds[2]));
  134.                 v->prefix = "";
  135.                 v->pid = fork();
  136.                 assert(v->pid >= 0);
  137.                 if (v->pid == 0) {
  138.                     assert(dup2(v->fds[0], 0) == 0);
  139.                     assert(dup2(v->fds[3], 1) == 1);
  140.                     assert(dup2(1, 2) == 2);
  141.                     AZ(close(v->fds[0]));
  142.                     AZ(close(v->fds[1]));
  143.                     AZ(close(v->fds[2]));
  144.                     AZ(close(v->fds[3]));
  145.                     for (i = 3; i <getdtablesize(); i++)
  146.                         (void)close(i);
  147.                     printf("Executing %s\n", p);
  148.                     AZ(execl("/bin/sh", "/bin/sh", "-c",
  149.                         p, NULL));
  150.                     exit(1);
  151.                 }
  152.                 AZ(close(v->fds[0]));
  153.                 AZ(close(v->fds[3]));
  154.                 v->fds[0] = v->fds[2];
  155.                 v->fds[2] = v->fds[3] = -1;
  156.                 AZ(pthread_create(&v->tp, NULL, CMD_thread, v));
  157.  
  158.                 /* May already have been closed */
  159.                 (void)close(v->fds[1]);
  160.                 AZ(pthread_join(v->tp, &pp));
  161.                 AZ(close(v->fds[0]));
  162.                 r = wait4(v->pid, &status, 0, NULL);
  163.                 v->pid = 0;
  164.                 l = snprintf(msg, sizeof(msg),
  165.                     "R %d Status: %04x", r, status);
  166.                 if (!WIFEXITED(status) ||
  167.                     WEXITSTATUS(status) != 0) {
  168.                     l += snprintf(msg + l, sizeof(msg) - l,
  169.                         " Bad exit code: %04x sig %x"
  170.                         " exit %x",
  171.                         status, WTERMSIG(status),
  172.                         WEXITSTATUS(status));
  173.                 }
  174.                 l += snprintf(msg + l, sizeof(msg) - l, "\n");
  175.                 printf("%s", msg);
  176.             }
  177.             p = q + 1;
  178.         }
  179.         }
  180.     printf("Command controller exited.\n");
  181.     exit(1);
  182. }
  183.  
  184. void
  185. CMD_Execute(const char *fmt, ...)
  186. {
  187.     va_list ap;
  188.     ssize_t l;
  189.     int buflen;
  190.     char buf[BUFSIZ];
  191.  
  192.     va_start(ap, fmt);
  193.     buflen = vsnprintf(buf, sizeof(buf), fmt, ap);
  194.     va_end(ap);
  195.     assert(buflen < sizeof(buf));
  196.  
  197.     l = write(cmdctl->fds[5], buf, buflen);
  198.     if (l == -1) {
  199.         printf(
  200.             "write(2) error for command \"%s\": %d %s\n", buf,
  201.             errno, strerror(errno));
  202.         return;
  203.     }
  204.     /* XXX no wait until it finishes? */
  205. }
  206.  
  207. static void
  208. CMD_Run(void)
  209. {
  210.  
  211.     cmdctl = calloc(1, sizeof(*cmdctl));
  212.     AN(cmdctl);
  213.     cmdctl->prefix = "Child said: ";
  214.     AZ(pipe(&cmdctl->fds[0]));
  215.     AZ(pipe(&cmdctl->fds[2]));
  216.     AZ(pipe(&cmdctl->fds[4]));
  217.     cmdctl->pid = fork();
  218.     assert(cmdctl->pid >= 0);
  219.     if (cmdctl->pid == 0)
  220.         CMD_RunChild();
  221.     AZ(close(cmdctl->fds[0]));
  222.     AZ(close(cmdctl->fds[3]));
  223.     AZ(close(cmdctl->fds[4]));
  224.     cmdctl->fds[0] = cmdctl->fds[2];
  225.     cmdctl->fds[2] = cmdctl->fds[3] = -1;
  226.     AZ(pthread_create(&cmdctl->tp, NULL, CMD_thread, cmdctl));
  227. }
  228.  
  229. static void
  230. CMD_Fini(void)
  231. {
  232.  
  233.     if (cmdctl->pid >= 0)
  234.         kill(cmdctl->pid, SIGTERM);
  235. }
  236.  
  237. #ifdef TEST
  238. int
  239. main(void)
  240. {
  241.     CMD_Run();
  242.     CMD_Execute("blah");
  243.     CMD_Fini();
  244. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement