(root)/
glibc-2.38/
posix/
tst-vfork3.c
       1  /* Test for vfork functions.
       2     Copyright (C) 2007-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 <errno.h>
      20  #include <fcntl.h>
      21  #include <mcheck.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  #include <unistd.h>
      25  #include <sys/stat.h>
      26  #include <sys/wait.h>
      27  
      28  static int do_test (void);
      29  static void do_prepare (void);
      30  char *tmpdirname;
      31  
      32  #define TEST_FUNCTION do_test ()
      33  #define PREPARE(argc, argv) do_prepare ()
      34  #include "../test-skeleton.c"
      35  
      36  static void
      37  run_script (const char *script, char *const argv[])
      38  {
      39    for (size_t i = 0; i < 5; i++)
      40      {
      41        pid_t pid = vfork ();
      42        if (pid < 0)
      43  	FAIL_EXIT1 ("vfork failed: %m");
      44        else if (pid == 0)
      45  	{
      46  	  execvp (script, argv);
      47  	  _exit (errno);
      48  	}
      49  
      50        int status;
      51        if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
      52  	FAIL_EXIT1 ("waitpid failed");
      53        else if (status != 0)
      54  	{
      55  	  if (WIFEXITED (status))
      56  	    FAIL_EXIT1 ("%s failed with status %d\n", script,
      57  			WEXITSTATUS (status));
      58  	  else
      59  	    FAIL_EXIT1 ("%s killed by signal %d\n", script,
      60  			WTERMSIG (status));
      61  	}
      62      }
      63  }
      64  
      65  static int
      66  do_test (void)
      67  {
      68    mtrace ();
      69  
      70    const char *path = getenv ("PATH");
      71    if (path == NULL)
      72      path = "/bin";
      73    char pathbuf[strlen (tmpdirname) + 1 + strlen (path) + 1];
      74    strcpy (stpcpy (stpcpy (pathbuf, tmpdirname), ":"), path);
      75    if (setenv ("PATH", pathbuf, 1) < 0)
      76      {
      77        puts ("setenv failed");
      78        return 1;
      79      }
      80  
      81    /* Although manual states first argument should be the script name itself,
      82       current execv{p,e} implementation allows it.  */
      83    char *argv00[] = { NULL };
      84    run_script ("script0.sh", argv00);
      85  
      86    char *argv01[] = { (char*) "script0.sh", NULL };
      87    run_script ("script0.sh", argv01);
      88  
      89    char *argv1[] = { (char *) "script1.sh", (char *) "1", NULL };
      90    run_script ("script1.sh", argv1);
      91  
      92    char *argv2[] = { (char *) "script2.sh", (char *) "2", NULL };
      93    run_script ("script2.sh", argv2);
      94  
      95    /* Same as before but with execlp.  */
      96    for (size_t i = 0; i < 5; i++)
      97      {
      98        pid_t pid = vfork ();
      99        if (pid < 0)
     100  	{
     101  	  printf ("vfork failed: %m\n");
     102  	  return 1;
     103  	}
     104        else if (pid == 0)
     105  	{
     106  	  execlp ("script2.sh", "script2.sh", "3", NULL);
     107  	  _exit (errno);
     108  	}
     109        int status;
     110        if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
     111  	{
     112  	  puts ("waitpid failed");
     113  	  return 1;
     114  	}
     115        else if (status != 0)
     116  	{
     117  	  printf ("script2.sh failed with status %d\n", status);
     118  	  return 1;
     119  	}
     120      }
     121  
     122    unsetenv ("PATH");
     123    char *argv4[] = { (char *) "echo", (char *) "script 4", NULL };
     124    run_script ("echo", argv4);
     125  
     126    return 0;
     127  }
     128  
     129  static void
     130  create_script (const char *script, const char *contents, size_t size)
     131  {
     132    int fd = open (script, O_WRONLY | O_CREAT, 0700);
     133    if (fd < 0
     134        || TEMP_FAILURE_RETRY (write (fd, contents, size)) != size
     135        || fchmod (fd, S_IRUSR | S_IXUSR) < 0)
     136      FAIL_EXIT1 ("could not write %s\n", script);
     137    close (fd);
     138  }
     139  
     140  static void
     141  do_prepare (void)
     142  {
     143    size_t len = strlen (test_dir) + sizeof ("/tst-vfork3.XXXXXX");
     144    tmpdirname = malloc (len);
     145    if (tmpdirname == NULL)
     146      FAIL_EXIT1 ("out of memory");
     147    strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX");
     148  
     149    tmpdirname = mkdtemp (tmpdirname);
     150    if (tmpdirname == NULL)
     151      FAIL_EXIT1 ("could not create temporary directory");
     152  
     153    char script0[len + sizeof "/script0.sh"];
     154    char script1[len + sizeof "/script1.sh"];
     155    char script2[len + sizeof "/script2.sh"];
     156  
     157    strcpy (stpcpy (script0, tmpdirname), "/script0.sh");
     158    strcpy (stpcpy (script1, tmpdirname), "/script1.sh");
     159    strcpy (stpcpy (script2, tmpdirname), "/script2.sh");
     160  
     161    add_temp_file (tmpdirname);
     162    add_temp_file (script0);
     163    add_temp_file (script1);
     164    add_temp_file (script2);
     165  
     166    const char content0[] = "#!/bin/sh\necho empty\n";
     167    create_script (script0, content0, sizeof content0);
     168  
     169    const char content1[] = "#!/bin/sh\necho script $1\n";
     170    create_script (script1, content1, sizeof content1);
     171  
     172    const char content2[] = "echo script $1\n";
     173    create_script (script2, content2, sizeof content2);
     174  }