예제 #1
0
static bool check_with_child(struct ptr_valid_batch *batch,
                             const void *p, size_t size, bool is_write)
{
    char ret;

    if (!child_alive(batch)) {
        if (!create_child(batch))
            return false;
    }

    if (write(batch->to_child, &p, sizeof(p))
            + write(batch->to_child, &size, sizeof(size))
            + write(batch->to_child, &is_write, sizeof(is_write))
            != sizeof(p) + sizeof(size) + sizeof(is_write)) {
        finish_child(batch);
        errno = EFAULT;
        return false;
    }

    if (read(batch->from_child, &ret, sizeof(ret)) != sizeof(ret)) {
        finish_child(batch);
        errno = EFAULT;
        return false;
    }
    return true;
}
예제 #2
0
파일: ptr_valid.c 프로젝트: mvanga/worlds
void ptr_valid_batch_end(struct ptr_valid_batch *batch)
{
	if (child_alive(batch))
		finish_child(batch);
	free(batch->maps);
}
예제 #3
0
파일: cthelper.c 프로젝트: Chaz6/futty
int
main(int argc, char *const *argv)
{
  int
    c,      /* control descriptor (stdin) */
    s;      /* socket descriptor (PuTTY) */
  Buffer
    cbuf,   /* control buffer */
    pbuf,   /* pty buffer */
    sbuf;   /* socket buffer */

  DBUG_INIT_ENV("main",argv[0],"DBUG_OPTS");

#ifndef DBUG_OFF
  setvbuf(DBUG_FILE, 0, _IONBF, 0);
#endif

  /* General steps:
    1. connect to cygterm backend
    2. create pty
    3. fork child process (/bin/bash)
    4. select on pty, cygterm backend forwarding pty data and messages
  */

  if (argc < 4) {
    DBUG_PRINT("error", ("Too few arguments"));
    DBUG_RETURN(CthelperInvalidUsage);
  }

  DBUG_PRINT("startup", ("isatty: (%d,%d,%d)",
    isatty(STDIN_FILENO), isatty(STDOUT_FILENO), isatty(STDERR_FILENO)));
  DBUG_PRINT("startup", (
    "cmdline: [%s] %s %s %s ...", argv[0], argv[1], argv[2], argv[3]));
  {
    extern char **environ;
    char **envp;
    for (envp = environ; *envp; envp++)
      DBUG_PRINT("startup", ("%s", *envp));
  }

  /* It is not necessary to close all open descriptors.  There are no
   * files inherited from the PuTTY process except standard input.
   */
#ifndef DEBUG
  close(STDERR_FILENO);
#endif

  /* Duplicate c and open /dev/null as 0 so that 0 can mean "closed". */
  c = dup(STDIN_FILENO); close(STDIN_FILENO);
  open("/dev/null", O_RDWR);

  /* Command line:
   * argv[1] =  port number
   * argv[2] =  terminal name
   * argv[3] =  terminal characteristics string
   * Any remaining arguments are the command to execute.  If there are no
   * other arguments, use the user's default login shell with a - prefix
   * for its argv[0].
   */
/*
cthelper command line parameters:

cthelper PORT TERM ATTRS [COMMAND [ARGS]]

    PORT
        port number for PuTTY pty input data socket
    TERM
        name of terminal (set TERM environment variable)
    ATTRS
    a colon-separated list of terminal attributes
    See init_pty() for details.
    COMMAND
        Runs COMMAND with ARGS as child process.  If COMMAND is not
        supplied, cthelper will run the user's login shell as specified in
        /etc/passwd specifying "-" for its argv[0] as typical.
*/


  /* connect to cygterm */
  {
    int ct_port = strtol(argv[1], 0, 0);
#ifdef DEBUG
    if (ct_port == 0) {
      /* For debugging purposes, make the tty we are started
       * in the "socket". This allows to test cthelper without
       * putty.exe */
      assert(isatty(STDOUT_FILENO));
      raw();
      atexit(restore);
      c = open("/dev/null", O_RDONLY);
      s = dup(STDOUT_FILENO);
    }
    else 
#endif
    if (ct_port <= 0) {
      DBUG_PRINT("startup", ("invalid port"));
      DBUG_RETURN(CthelperInvalidPort);
    }
    DBUG_PRINT("startup", ("connect cygterm"));
    if (0 > (s = connect_cygterm(ct_port))) {
      DBUG_PRINT("startup", ("connect_cygterm: bad"));
      DBUG_RETURN(CthelperConnectFailed);
    }
    DBUG_PRINT("startup", ("OK"));
  }

  /* initialize buffers */
  DBUG_PRINT("startup", ("initialize buffers"));
  BUFFER_ALLOCA(cbuf, CTLBUF);
  BUFFER_ALLOCA(pbuf, PTOBUF);
  BUFFER_ALLOCA(sbuf, PTIBUF);

  /* set up signal handling */
  signal(SIGCHLD, handle_sigchld);

  /* start child process */
  if (0 > (t = setup_child(&child, argv[2], argv[3], argv + 4))) {
    DBUG_PRINT("startup", ("setup_child failed: %s", strerror(-t)));
    DBUG_RETURN(CthelperPtyforkFailure);
  }

  /*  To explain what is happening here:
   *  's' is the socket between PuTTY and cthelper; it is read to get
   *  input for the tty and written to display output from the pty.
   *  't' is the pseudo terminal; it is read to get pty input which is sent to
   *  PuTTY and written to pass input from PuTTY to the pty.
   *  'c' is standard input, which is a one-way anonymous pipe from PuTTY.
   *  It is read to receive special messages from PuTTY such as
   *  terminal resize events.
   *
   *  This is the flow of data through the buffers:
   *      s => sbuf => t
   *      t => pbuf => s
   *      c => cbuf => process_message()
   *
   *  When 't' is closed, we close(s) to signal PuTTY we are done.
   *  When 's' is closed, we kill(child, HUP) to kill the child process.
   */

  setnonblock(c);
  setnonblock(s);
  setnonblock(t);

  DBUG_PRINT("info", ("c==%d, s==%d, t==%d", c, s, t));
  /* allow easy select() and FD_ISSET() stuff */
  assert(0 < c && c < s && s < t);
  DBUG_PRINT("startup", ("starting select loop"));
  while (s || t) {
    int n = 0;
    fd_set r, w;
    DBUG_ENTER("select");
    FD_ZERO(&r); FD_ZERO(&w);
    if (c && !buffer_isfull(cbuf)) { FD_SET(c, &r); n = c; }
    if (s && !buffer_isfull(sbuf)) { FD_SET(s, &r); n = s; }
    if (s && !buffer_isempty(pbuf)) { FD_SET(s, &w); n = s; }
    if (t && !buffer_isfull(pbuf)) { FD_SET(t, &r); n = t; }
    if (t && !buffer_isempty(sbuf)) { FD_SET(t, &w); n = t; }
    switch (n = select(n + 1, &r, &w, 0, 0)) {
    case -1:
      DBUG_PRINT("error", ("%s", strerror(errno)));
      if (errno != EINTR) {
        /* Something bad happened */
        close(c); c = 0;
        close(s); s = 0;
        close(t); t = 0;
      }
      break;
    case 0:
      DBUG_PRINT("info", ("select timeout"));
      break;
    default:
      DBUG_PRINT("info", ("%d ready descriptors [[r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w));
      if (FD_ISSET(c, &r)) {
        DBUG_ENTER("c=>cbuf");
        switch (buffer_read(cbuf, c)) {
        case -1:
          DBUG_PRINT("error", ("error reading c: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the message pipe */
          DBUG_PRINT("io", ("c closed"));
          close(c); c = 0;
          break;
        default:
          DBUG_PRINT("io", ("cbuf => process_message()"));
          process_message(cbuf, t);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(s, &r)) {
        DBUG_ENTER("s=>sbuf");
        switch (buffer_read(sbuf, s)) {
        case -1:
          DBUG_PRINT("error", ("error reading s: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the socket */
          DBUG_PRINT("io", ("s closed"));
          close(s); s = 0;
          break;
        default:
          FD_SET(t, &w);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(t, &r)) {
        DBUG_ENTER("t=>pbuf");
        switch (buffer_read(pbuf, t)) {
        case -1:
          DBUG_PRINT("error", ("error reading t: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* pty closed */
          DBUG_PRINT("io", ("t closed"));
          if (!FD_ISSET(t, &w)) {
            close(t); t = 0;
          }
          break;
        default:
          FD_SET(s, &w);
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(t, &w)) {
        DBUG_ENTER("sbuf=>t");
        switch (buffer_write(sbuf, t)) {
        case -1:
          DBUG_PRINT("error", ("error writing t: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* pty closed */
          DBUG_PRINT("io", ("t closed"));
          close(t); t = 0;
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      if (FD_ISSET(s, &w)) {
        DBUG_ENTER("pbuf=>s");
        switch (buffer_write(pbuf, s)) {
        case -1:
          DBUG_PRINT("error", ("error writing s: %s", strerror(errno)));
          if (errno == EINTR || errno == EWOULDBLOCK) break;
          /*FALLTHRU*/
        case 0:
          /* PuTTY closed the socket */
          DBUG_PRINT("io", ("s closed"));
          close(s); s = 0;
          break;
        }
        DBUG_LEAVE;
        if (!--n) break;
      }
      DBUG_PRINT("info", ("[[n==%d,r==%lx,w==%lx]]", n, *(unsigned long *)&r, *(unsigned long *)&w));
      assert(n == 0);
      break;
    }

    if (child_signalled) check_child();

    if (!t && buffer_isempty(pbuf)) {
      DBUG_PRINT("info", ("shutdown socket"));
      shutdown(s, SHUT_WR);
    }

    if (!s && buffer_isempty(sbuf) && child_alive()) {
      DBUG_PRINT("sig", ("kill child"));
      kill(child, SIGHUP);
      /* handle_sigchld() will close(t) */
    }
    DBUG_LEAVE;
  }
  DBUG_PRINT("info", ("end of select loop"));

  /* ensure child process killed */
  /* XXX I'm not sure if all of this is necessary, but it probably won't
   * hurt anything. */
  if (child_alive() && sleep(1) == 0) {
    DBUG_PRINT("sig", ("waiting for child"));
    waitpid(child, 0, WNOHANG);
  }

  DBUG_PRINT("info", ("goodbye"));
  if (exit_status == 111)
    DBUG_RETURN(CthelperExecFailure);
  DBUG_RETURN(EXIT_SUCCESS);
}