Beispiel #1
0
/*
 * Signal that we are now inside a directory pointed to by dir_fd.
 * The caller can't tell if this is the first time this happens, so
 * we have to be careful not to call dup() more than once
 */
static void
inside_dir (int dir_fd)
{
  if (ftsoptions & FTS_CWDFD)
    {
      assert (dir_fd == AT_FDCWD || dir_fd >= 0);

      state.cwd_dir_fd = dir_fd;
      if (curr_fd < 0)
	{
	  if (AT_FDCWD == dir_fd)
	    {
	      curr_fd = AT_FDCWD;
	    }
	  else if (dir_fd >= 0)
	    {
	      curr_fd = dup_cloexec (dir_fd);
	    }
	  else
	    {
	      /* curr_fd is invalid, but dir_fd is also invalid.
	       * This should not have happened.
	       */
	      assert (curr_fd >= 0 || dir_fd >= 0);
	    }
	}
    }
  else
    {
      /* FTS_CWDFD is not in use.  We can always assume that
       * AT_FDCWD refers to the directory we are currentl searching.
       *
       * Therefore there is nothing to do.
       */
    }
}
int
main (void)
{
  const char *file = "test-dup2.tmp";
  char buffer[1];
  int fd = open (file, O_CREAT | O_TRUNC | O_RDWR, 0600);

  /* Assume std descriptors were provided by invoker.  */
  ASSERT (STDERR_FILENO < fd);
  ASSERT (is_open (fd));
  /* Ignore any other fd's leaked into this process.  */
  close (fd + 1);
  close (fd + 2);
  ASSERT (!is_open (fd + 1));
  ASSERT (!is_open (fd + 2));

  /* Assigning to self must be a no-op.  */
  ASSERT (dup2 (fd, fd) == fd);
  ASSERT (is_open (fd));

  /* The source must be valid.  */
  errno = 0;
  ASSERT (dup2 (-1, fd) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup2 (99, fd) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup2 (AT_FDCWD, fd) == -1);
  ASSERT (errno == EBADF);
  ASSERT (is_open (fd));

  /* If the source is not open, then the destination is unaffected.  */
  errno = 0;
  ASSERT (dup2 (fd + 1, fd + 1) == -1);
  ASSERT (errno == EBADF);
  ASSERT (!is_open (fd + 1));
  errno = 0;
  ASSERT (dup2 (fd + 1, fd) == -1);
  ASSERT (errno == EBADF);
  ASSERT (is_open (fd));

  /* The destination must be valid.  */
  errno = 0;
  ASSERT (dup2 (fd, -2) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup2 (fd, 10000000) == -1);
  ASSERT (errno == EBADF);

  /* Using dup2 can skip fds.  */
  ASSERT (dup2 (fd, fd + 2) == fd + 2);
  ASSERT (is_open (fd));
  ASSERT (!is_open (fd + 1));
  ASSERT (is_open (fd + 2));

  /* Verify that dup2 closes the previous occupant of a fd.  */
  ASSERT (open ("/dev/null", O_WRONLY, 0600) == fd + 1);
  ASSERT (dup2 (fd + 1, fd) == fd);
  ASSERT (close (fd + 1) == 0);
  ASSERT (write (fd, "1", 1) == 1);
  ASSERT (dup2 (fd + 2, fd) == fd);
  ASSERT (lseek (fd, 0, SEEK_END) == 0);
  ASSERT (write (fd + 2, "2", 1) == 1);
  ASSERT (lseek (fd, 0, SEEK_SET) == 0);
  ASSERT (read (fd, buffer, 1) == 1);
  ASSERT (*buffer == '2');

#if GNULIB_TEST_CLOEXEC
  /* Any new fd created by dup2 must not be cloexec.  */
  ASSERT (close (fd + 2) == 0);
  ASSERT (dup_cloexec (fd) == fd + 1);
  ASSERT (!is_inheritable (fd + 1));
  ASSERT (dup2 (fd + 1, fd + 1) == fd + 1);
  ASSERT (!is_inheritable (fd + 1));
  ASSERT (dup2 (fd + 1, fd + 2) == fd + 2);
  ASSERT (!is_inheritable (fd + 1));
  ASSERT (is_inheritable (fd + 2));
  errno = 0;
  ASSERT (dup2 (fd + 1, -1) == -1);
  ASSERT (errno == EBADF);
  ASSERT (!is_inheritable (fd + 1));
#endif

  /* On systems that distinguish between text and binary mode, dup2
     reuses the mode of the source.  */
  setmode (fd, O_BINARY);
  ASSERT (is_mode (fd, O_BINARY));
  ASSERT (dup2 (fd, fd + 1) == fd + 1);
  ASSERT (is_mode (fd + 1, O_BINARY));
  setmode (fd, O_TEXT);
  ASSERT (is_mode (fd, O_TEXT));
  ASSERT (dup2 (fd, fd + 1) == fd + 1);
  ASSERT (is_mode (fd + 1, O_TEXT));

  /* Clean up.  */
  ASSERT (close (fd + 2) == 0);
  ASSERT (close (fd + 1) == 0);
  ASSERT (close (fd) == 0);
  ASSERT (unlink (file) == 0);

  return 0;
}
Beispiel #3
0
/* 'fd_cwd' is a file descriptor pointing to an open directory.
 * 'name' is the path element to search for.  'is_end' is a flag
 * indicating if this is the last path element.
 *
 * We search the directory looking for a path element that case
 * insensitively matches 'name', returning the actual name in '*name_ret'.
 *
 * If this is successful, return 0.  If it fails, reply with an error
 * and return -1.
 */
static int
find_path_element (int fd_cwd, int is_end, const char *name, char **name_ret)
{
  int fd2;
  DIR *dir;
  struct dirent *d;

  fd2 = dup_cloexec (fd_cwd); /* because closedir will close it */
  if (fd2 == -1) {
    reply_with_perror ("dup");
    return -1;
  }
  dir = fdopendir (fd2);
  if (dir == NULL) {
    reply_with_perror ("opendir");
    close (fd2);
    return -1;
  }

  for (;;) {
    errno = 0;
    d = readdir (dir);
    if (d == NULL)
      break;
    if (STRCASEEQ (d->d_name, name))
      break;
  }

  if (d == NULL && errno != 0) {
    reply_with_perror ("readdir");
    closedir (dir);
    return -1;
  }

  if (d == NULL && is_end) {
    /* Last path element: return it as-is, assuming that the user will
     * create a new file or directory (RHBZ#840115).
     */
    closedir (dir);
    *name_ret = strdup (name);
    if (*name_ret == NULL) {
      reply_with_perror ("strdup");
      return -1;
    }
    return 0;
  }

  if (d == NULL) {
    reply_with_error ("%s: no file or directory found with this name", name);
    closedir (dir);
    return -1;
  }

  *name_ret = strdup (d->d_name);
  if (*name_ret == NULL) {
    reply_with_perror ("strdup");
    closedir (dir);
    return -1;
  }

  /* NB: closedir frees the structure associated with 'd', so we must
   * do this last.
   */
  if (closedir (dir) == -1) {
    reply_with_perror ("closedir");
    return -1;
  }

  return 0;
}
Beispiel #4
0
int
main (void)
{
  const char *file = "test-cloexec.tmp";
  int fd = creat (file, 0600);
  int fd2;

  /* Assume std descriptors were provided by invoker.  */
  ASSERT (STDERR_FILENO < fd);
  ASSERT (is_inheritable (fd));

  /* Normal use of set_cloexec_flag.  */
  ASSERT (set_cloexec_flag (fd, true) == 0);
#if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
  ASSERT (!is_inheritable (fd));
#endif
  ASSERT (set_cloexec_flag (fd, false) == 0);
  ASSERT (is_inheritable (fd));

  /* Normal use of dup_cloexec.  */
  fd2 = dup_cloexec (fd);
  ASSERT (fd < fd2);
  ASSERT (!is_inheritable (fd2));
  ASSERT (close (fd) == 0);
  ASSERT (dup_cloexec (fd2) == fd);
  ASSERT (!is_inheritable (fd));
  ASSERT (close (fd2) == 0);

  /* On systems that distinguish between text and binary mode,
     dup_cloexec reuses the mode of the source.  */
  setmode (fd, O_BINARY);
  ASSERT (is_mode (fd, O_BINARY));
  fd2 = dup_cloexec (fd);
  ASSERT (fd < fd2);
  ASSERT (is_mode (fd2, O_BINARY));
  ASSERT (close (fd2) == 0);
  setmode (fd, O_TEXT);
  ASSERT (is_mode (fd, O_TEXT));
  fd2 = dup_cloexec (fd);
  ASSERT (fd < fd2);
  ASSERT (is_mode (fd2, O_TEXT));
  ASSERT (close (fd2) == 0);

  /* Test error handling.  */
  errno = 0;
  ASSERT (set_cloexec_flag (-1, false) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (set_cloexec_flag (10000000, false) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (set_cloexec_flag (fd2, false) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup_cloexec (-1) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup_cloexec (10000000) == -1);
  ASSERT (errno == EBADF);
  errno = 0;
  ASSERT (dup_cloexec (fd2) == -1);
  ASSERT (errno == EBADF);

  /* Clean up.  */
  ASSERT (close (fd) == 0);
  ASSERT (unlink (file) == 0);

  return 0;
}
Beispiel #5
0
int
main (void)
{
  int i;
  int fd;

  /* We close fd 2 later, so save it in fd 10.  */
  if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
      || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
    return 2;

  /* Create file for later checks.  */
  fd = creat (witness, 0600);
  ASSERT (STDERR_FILENO < fd);

  /* Four iterations, with progressively more standard descriptors
     closed.  */
  for (i = -1; i <= STDERR_FILENO; i++)
    {
      if (0 <= i)
        ASSERT (close (i) == 0);

      /* Detect errors.  */
      errno = 0;
      ASSERT (dup (-1) == -1);
      ASSERT (errno == EBADF);
      errno = 0;
      ASSERT (dup (10000000) == -1);
      ASSERT (errno == EBADF);
      close (fd + 1);
      errno = 0;
      ASSERT (dup (fd + 1) == -1);
      ASSERT (errno == EBADF);

      /* Preserve text vs. binary.  */
      setmode (fd, O_BINARY);
      ASSERT (dup (fd) == fd + 1);
      ASSERT (is_open (fd + 1));
      ASSERT (is_inheritable (fd + 1));
      ASSERT (is_mode (fd + 1, O_BINARY));

      ASSERT (close (fd + 1) == 0);
      setmode (fd, O_TEXT);
      ASSERT (dup (fd) == fd + 1);
      ASSERT (is_open (fd + 1));
      ASSERT (is_inheritable (fd + 1));
      ASSERT (is_mode (fd + 1, O_TEXT));

      /* Create cloexec copy.  */
      ASSERT (close (fd + 1) == 0);
      ASSERT (fd_safer_flag (dup_cloexec (fd), O_CLOEXEC) == fd + 1);
      ASSERT (set_cloexec_flag (fd + 1, true) == 0);
      ASSERT (is_open (fd + 1));
      ASSERT (!is_inheritable (fd + 1));
      ASSERT (close (fd) == 0);

      /* dup always creates inheritable copies.  Also, check that
         earliest slot past std fds is used.  */
      ASSERT (dup (fd + 1) == fd);
      ASSERT (is_open (fd));
      ASSERT (is_inheritable (fd));
      ASSERT (close (fd + 1) == 0);
    }

  /* Cleanup.  */
  ASSERT (close (fd) == 0);
  ASSERT (unlink (witness) == 0);

  return 0;
}
Beispiel #6
0
static void run_helper(libxl__egc *egc, libxl__save_helper_state *shs,
                       const char *mode_arg,
                       int stream_fd, int back_channel_fd,
                       const int *preserve_fds, int num_preserve_fds,
                       const unsigned long *argnums, int num_argnums)
{
    STATE_AO_GC(shs->ao);
    const char *args[HELPER_NR_ARGS + num_argnums];
    const char **arg = args;
    int i, rc;

    /* Resources we must free */
    libxl__carefd *childs_pipes[2] = { 0,0 };

    /* Convenience aliases */
    const uint32_t domid = shs->domid;

    shs->rc = 0;
    shs->completed = 0;
    shs->pipes[0] = shs->pipes[1] = 0;
    libxl__save_helper_init(shs);

    shs->abrt.ao = shs->ao;
    shs->abrt.callback = helper_stop;
    rc = libxl__ao_abortable_register(&shs->abrt);
    if (rc) goto out;

    shs->stdin_what = GCSPRINTF("domain %"PRIu32" save/restore helper"
                                " stdin pipe", domid);
    shs->stdout_what = GCSPRINTF("domain %"PRIu32" save/restore helper"
                                 " stdout pipe", domid);

    *arg++ = getenv("LIBXL_SAVE_HELPER") ?: LIBEXEC_BIN "/" "libxl-save-helper";
    *arg++ = mode_arg;
    const char **stream_fd_arg = arg++;
    const char **back_channel_fd_arg = arg++;
    for (i=0; i<num_argnums; i++)
        *arg++ = GCSPRINTF("%lu", argnums[i]);
    *arg++ = 0;
    assert(arg == args + ARRAY_SIZE(args));

    libxl__carefd_begin();
    int childfd;
    for (childfd=0; childfd<2; childfd++) {
        /* Setting up the pipe for the child's fd childfd */
        int fds[2];
        if (libxl_pipe(CTX,fds)) {
            rc = ERROR_FAIL;
            libxl__carefd_unlock();
            goto out;
        }
        int childs_end = childfd==0 ? 0 /*read*/  : 1 /*write*/;
        int our_end    = childfd==0 ? 1 /*write*/ : 0 /*read*/;
        childs_pipes[childfd] = libxl__carefd_record(CTX, fds[childs_end]);
        shs->pipes[childfd] =   libxl__carefd_record(CTX, fds[our_end]);
    }
    libxl__carefd_unlock();

    pid_t pid = libxl__ev_child_fork(gc, &shs->child, helper_exited);
    if (!pid) {
        stream_fd = dup_cloexec(gc, stream_fd, "migration stream fd");
        *stream_fd_arg = GCSPRINTF("%d", stream_fd);

        if (back_channel_fd >= 0)
            back_channel_fd = dup_cloexec(gc, back_channel_fd,
                                          "migration back channel fd");
        *back_channel_fd_arg = GCSPRINTF("%d", back_channel_fd);

        for (i=0; i<num_preserve_fds; i++)
            if (preserve_fds[i] >= 0) {
                assert(preserve_fds[i] > 2);
                libxl_fd_set_cloexec(CTX, preserve_fds[i], 0);
            }

        libxl__exec(gc,
                    libxl__carefd_fd(childs_pipes[0]),
                    libxl__carefd_fd(childs_pipes[1]),
                    -1,
                    args[0], (char**)args, 0);
    }

    libxl__carefd_close(childs_pipes[0]);
    libxl__carefd_close(childs_pipes[1]);

    rc = libxl__ev_fd_register(gc, &shs->readable, helper_stdout_readable,
                               libxl__carefd_fd(shs->pipes[1]), POLLIN|POLLPRI);
    if (rc) goto out;
    return;

 out:
    libxl__carefd_close(childs_pipes[0]);
    libxl__carefd_close(childs_pipes[1]);
    helper_failed(egc, shs, rc);;
}