Blame posix/tst-spawn3.c

Packit Service 82fcde
/* Check posix_spawn add file actions.
Packit Service 82fcde
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <spawn.h>
Packit Service 82fcde
#include <error.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/wait.h>
Packit Service 82fcde
#include <sys/resource.h>
Packit Service 82fcde
#include <fcntl.h>
Packit Service 82fcde
#include <paths.h>
Packit Service 82fcde
Packit Service 82fcde
#include <support/check.h>
Packit Service 82fcde
#include <support/temp_file.h>
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  /* The test checks if posix_spawn open file action close the file descriptor
Packit Service 82fcde
     before opening a new one in case the input file descriptor is already
Packit Service 82fcde
     opened.  It does by exhausting all file descriptors on the process before
Packit Service 82fcde
     issue posix_spawn.  It then issues a posix_spawn for '/bin/sh echo $$'
Packit Service 82fcde
     and add two rules:
Packit Service 82fcde
Packit Service 82fcde
     1. Redirect stdout to a temporary filepath
Packit Service 82fcde
     2. Redirect stderr to stdout
Packit Service 82fcde
Packit Service 82fcde
     If the implementation does not close the file 1. will fail with
Packit Service 82fcde
     EMFILE.  */
Packit Service 82fcde
Packit Service 82fcde
  struct rlimit rl;
Packit Service 82fcde
  int max_fd = 24;
Packit Service 82fcde
  int ret;
Packit Service 82fcde
Packit Service 82fcde
  /* Set maximum number of file descriptor to a low value to avoid open
Packit Service 82fcde
     too many files in environments where RLIMIT_NOFILE is large and to
Packit Service 82fcde
     limit the array size to track the opened file descriptors.  */
Packit Service 82fcde
Packit Service 82fcde
  if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
Packit Service 82fcde
    FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
Packit Service 82fcde
Packit Service 82fcde
  max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
Packit Service 82fcde
  rl.rlim_cur = max_fd;
Packit Service 82fcde
Packit Service 82fcde
  if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
Packit Service 82fcde
    FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
Packit Service 82fcde
Packit Service 82fcde
  /* Exhauste the file descriptor limit with temporary files.  */
Packit Service 82fcde
  int files[max_fd];
Packit Service 82fcde
  int nfiles = 0;
Packit Service 82fcde
  for (;;)
Packit Service 82fcde
    {
Packit Service 82fcde
      int fd = create_temp_file ("tst-spawn3.", NULL);
Packit Service 82fcde
      if (fd == -1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  if (errno != EMFILE)
Packit Service 82fcde
	    FAIL_EXIT1 ("create_temp_file: %m");
Packit Service 82fcde
	  break;
Packit Service 82fcde
	}
Packit Service 82fcde
      files[nfiles++] = fd;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  posix_spawn_file_actions_t a;
Packit Service 82fcde
  if (posix_spawn_file_actions_init (&a) != 0)
Packit Service 82fcde
    FAIL_EXIT1 ("posix_spawn_file_actions_init");
Packit Service 82fcde
Packit Service 82fcde
  /* Executes a /bin/sh echo $$ 2>&1 > ${objpfx}tst-spawn3.pid .  */
Packit Service 82fcde
  const char pidfile[] = OBJPFX "tst-spawn3.pid";
Packit Service 82fcde
  if (posix_spawn_file_actions_addopen (&a, STDOUT_FILENO, pidfile, O_WRONLY |
Packit Service 82fcde
					O_CREAT | O_TRUNC, 0644) != 0)
Packit Service 82fcde
    FAIL_EXIT1 ("posix_spawn_file_actions_addopen");
Packit Service 82fcde
Packit Service 82fcde
  if (posix_spawn_file_actions_adddup2 (&a, STDOUT_FILENO, STDERR_FILENO) != 0)
Packit Service 82fcde
    FAIL_EXIT1 ("posix_spawn_file_actions_adddup2");
Packit Service 82fcde
Packit Service 82fcde
  /* Since execve (called by posix_spawn) might require to open files to
Packit Service 82fcde
     actually execute the shell script, setup to close the temporary file
Packit Service 82fcde
     descriptors.  */
Packit Service 82fcde
  for (int i=0; i
Packit Service 82fcde
    {
Packit Service 82fcde
      if (posix_spawn_file_actions_addclose (&a, files[i]))
Packit Service 82fcde
	FAIL_EXIT1 ("posix_spawn_file_actions_addclose");
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  char *spawn_argv[] = { (char *) _PATH_BSHELL, (char *) "-c",
Packit Service 82fcde
			 (char *) "echo $$", NULL };
Packit Service 82fcde
  pid_t pid;
Packit Service 82fcde
  if ((ret = posix_spawn (&pid, _PATH_BSHELL, &a, NULL, spawn_argv, NULL))
Packit Service 82fcde
       != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      errno = ret;
Packit Service 82fcde
      FAIL_EXIT1 ("posix_spawn: %m");
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  int status;
Packit Service 82fcde
  int err = waitpid (pid, &status, 0);
Packit Service 82fcde
  if (err != pid)
Packit Service 82fcde
    FAIL_EXIT1 ("waitpid: %m");
Packit Service 82fcde
Packit Service 82fcde
  /* Close the temporary files descriptor so it can check posix_spawn
Packit Service 82fcde
     output.  */
Packit Service 82fcde
  for (int i=0; i
Packit Service 82fcde
    {
Packit Service 82fcde
      if (close (files[i]))
Packit Service 82fcde
	FAIL_EXIT1 ("close: %m");
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  int pidfd = open (pidfile, O_RDONLY);
Packit Service 82fcde
  if (pidfd == -1)
Packit Service 82fcde
    FAIL_EXIT1 ("open: %m");
Packit Service 82fcde
Packit Service 82fcde
  char buf[64];
Packit Service 82fcde
  ssize_t n;
Packit Service 82fcde
  if ((n = read (pidfd, buf, sizeof (buf))) < 0)
Packit Service 82fcde
    FAIL_EXIT1 ("read: %m");
Packit Service 82fcde
Packit Service 82fcde
  unlink (pidfile);
Packit Service 82fcde
Packit Service 82fcde
  /* We only expect to read the PID.  */
Packit Service 82fcde
  char *endp;
Packit Service 82fcde
  long int rpid = strtol (buf, &endp, 10);
Packit Service 82fcde
  if (*endp != '\n')
Packit Service 82fcde
    FAIL_EXIT1 ("*endp != \'n\'");
Packit Service 82fcde
  if (endp == buf)
Packit Service 82fcde
    FAIL_EXIT1 ("read empty line");
Packit Service 82fcde
Packit Service 82fcde
  if (rpid != pid)
Packit Service 82fcde
    FAIL_EXIT1 ("found \"%s\", expected pid %ld\n", buf, (long int) pid);
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#include <support/test-driver.c>