(root)/
glibc-2.38/
posix/
tst-spawn3.c
       1  /* Check posix_spawn add file actions.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <stdio.h>
      20  #include <spawn.h>
      21  #include <error.h>
      22  #include <errno.h>
      23  #include <stdlib.h>
      24  #include <string.h>
      25  #include <unistd.h>
      26  #include <sys/wait.h>
      27  #include <sys/resource.h>
      28  #include <fcntl.h>
      29  #include <paths.h>
      30  
      31  #include <support/check.h>
      32  #include <support/temp_file.h>
      33  
      34  static int
      35  do_test (void)
      36  {
      37    /* The test checks if posix_spawn open file action close the file descriptor
      38       before opening a new one in case the input file descriptor is already
      39       opened.  It does by exhausting all file descriptors on the process before
      40       issue posix_spawn.  It then issues a posix_spawn for '/bin/sh echo $$'
      41       and add two rules:
      42  
      43       1. Redirect stdout to a temporary filepath
      44       2. Redirect stderr to stdout
      45  
      46       If the implementation does not close the file 1. will fail with
      47       EMFILE.  */
      48  
      49    struct rlimit rl;
      50    int max_fd = 24;
      51    int ret;
      52  
      53    /* Set maximum number of file descriptor to a low value to avoid open
      54       too many files in environments where RLIMIT_NOFILE is large and to
      55       limit the array size to track the opened file descriptors.  */
      56  
      57    if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
      58      FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
      59  
      60    max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
      61    rl.rlim_cur = max_fd;
      62  
      63    if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
      64      FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
      65  
      66    /* Exhauste the file descriptor limit with temporary files.  */
      67    int files[max_fd];
      68    int nfiles = 0;
      69    for (;;)
      70      {
      71        int fd = create_temp_file ("tst-spawn3.", NULL);
      72        if (fd == -1)
      73  	{
      74  	  if (errno != EMFILE)
      75  	    FAIL_EXIT1 ("create_temp_file: %m");
      76  	  break;
      77  	}
      78        files[nfiles++] = fd;
      79      }
      80  
      81    posix_spawn_file_actions_t a;
      82    if (posix_spawn_file_actions_init (&a) != 0)
      83      FAIL_EXIT1 ("posix_spawn_file_actions_init");
      84  
      85    /* Executes a /bin/sh echo $$ 2>&1 > ${objpfx}tst-spawn3.pid .  */
      86    const char pidfile[] = OBJPFX "tst-spawn3.pid";
      87    if (posix_spawn_file_actions_addopen (&a, STDOUT_FILENO, pidfile, O_WRONLY
      88  					| O_CREAT | O_TRUNC, 0644) != 0)
      89      FAIL_EXIT1 ("posix_spawn_file_actions_addopen");
      90  
      91    if (posix_spawn_file_actions_adddup2 (&a, STDOUT_FILENO, STDERR_FILENO) != 0)
      92      FAIL_EXIT1 ("posix_spawn_file_actions_adddup2");
      93  
      94    /* Since execve (called by posix_spawn) might require to open files to
      95       actually execute the shell script, setup to close the temporary file
      96       descriptors.  */
      97    for (int i=0; i<nfiles; i++)
      98      {
      99        if (posix_spawn_file_actions_addclose (&a, files[i]))
     100  	FAIL_EXIT1 ("posix_spawn_file_actions_addclose");
     101      }
     102  
     103    char *spawn_argv[] = { (char *) _PATH_BSHELL, (char *) "-c",
     104  			 (char *) "echo $$", NULL };
     105    pid_t pid;
     106    if ((ret = posix_spawn (&pid, _PATH_BSHELL, &a, NULL, spawn_argv, NULL))
     107         != 0)
     108      {
     109        errno = ret;
     110        FAIL_EXIT1 ("posix_spawn: %m");
     111      }
     112  
     113    int status;
     114    int err = waitpid (pid, &status, 0);
     115    if (err != pid)
     116      FAIL_EXIT1 ("waitpid: %m");
     117  
     118    /* Close the temporary files descriptor so it can check posix_spawn
     119       output.  */
     120    for (int i=0; i<nfiles; i++)
     121      {
     122        if (close (files[i]))
     123  	FAIL_EXIT1 ("close: %m");
     124      }
     125  
     126    int pidfd = open (pidfile, O_RDONLY);
     127    if (pidfd == -1)
     128      FAIL_EXIT1 ("open: %m");
     129  
     130    char buf[64];
     131    ssize_t n;
     132    if ((n = read (pidfd, buf, sizeof (buf))) < 0)
     133      FAIL_EXIT1 ("read: %m");
     134  
     135    unlink (pidfile);
     136  
     137    /* We only expect to read the PID.  */
     138    char *endp;
     139    long int rpid = strtol (buf, &endp, 10);
     140    if (*endp != '\n')
     141      FAIL_EXIT1 ("*endp != \'n\'");
     142    if (endp == buf)
     143      FAIL_EXIT1 ("read empty line");
     144  
     145    if (rpid != pid)
     146      FAIL_EXIT1 ("found \"%s\", expected pid %ld\n", buf, (long int) pid);
     147  
     148    return 0;
     149  }
     150  
     151  #include <support/test-driver.c>