(root)/
m4-1.4.19/
tests/
test-posix_spawnp-script.c
       1  /* Test of posix_spawnp() function.
       2     Copyright (C) 2020-2021 Free Software Foundation, Inc.
       3  
       4     This program is free software; you can redistribute it and/or modify
       5     it under the terms of the GNU General Public License as published by
       6     the Free Software Foundation; either version 3, or (at your option)
       7     any later version.
       8  
       9     This program is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU General Public License for more details.
      13  
      14     You should have received a copy of the GNU General Public License
      15     along with this program; if not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  #include <spawn.h>
      20  
      21  #include <errno.h>
      22  #include <fcntl.h>
      23  #include <stdio.h>
      24  #include <string.h>
      25  #include <unistd.h>
      26  #include <sys/types.h>
      27  #include <sys/wait.h>
      28  
      29  #include "macros.h"
      30  
      31  #define DATA_FILENAME "test-posix_spawn-script.tmp"
      32  
      33  int
      34  main ()
      35  {
      36    unlink (DATA_FILENAME);
      37  
      38    /* Check an invocation of an executable script.
      39       This should only be supported if the script has a '#!' marker; otherwise
      40       it is unsecure: <https://sourceware.org/bugzilla/show_bug.cgi?id=13134>.
      41       POSIX says that the execlp() and execvp() functions support executing
      42       shell scripts
      43       <https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html>,
      44       but this is considered an antiquated feature.  */
      45    pid_t child;
      46  
      47    posix_spawn_file_actions_t actions;
      48    ASSERT (posix_spawn_file_actions_init (&actions) == 0);
      49    ASSERT (posix_spawn_file_actions_addopen (&actions, STDOUT_FILENO,
      50                                              DATA_FILENAME,
      51                                              O_RDWR | O_CREAT | O_TRUNC, 0600)
      52            == 0);
      53  
      54    {
      55      size_t i;
      56  
      57      for (i = 0; i < 2; i++)
      58        {
      59          const char *prog_path =
      60            (i == 0 ? SRCDIR "executable-script" : SRCDIR "executable-script.sh");
      61          const char *prog_argv[2] = { prog_path, NULL };
      62  
      63          int err = posix_spawnp (&child, prog_path, &actions, NULL,
      64                                  (char **) prog_argv, environ);
      65          if (err != ENOEXEC)
      66            {
      67              if (err != 0)
      68                {
      69                  errno = err;
      70                  perror ("posix_spawn");
      71                  return 1;
      72                }
      73  
      74              /* Wait for child.  */
      75              int status = 0;
      76              while (waitpid (child, &status, 0) != child)
      77                ;
      78              if (!WIFEXITED (status))
      79                {
      80                  fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
      81                  return 1;
      82                }
      83              int exitstatus = WEXITSTATUS (status);
      84              if (exitstatus != 127)
      85                {
      86                  fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
      87                  return 1;
      88                }
      89            }
      90        }
      91    }
      92  
      93  #if defined _WIN32 && !defined __CYGWIN__
      94    /* On native Windows, scripts - even with '#!' marker - are not executable.
      95       Only .bat and .cmd files are.  */
      96    fprintf (stderr, "Skipping test: scripts are not executable on this platform.\n");
      97    return 77;
      98  #else
      99    {
     100      const char *prog_path = SRCDIR "executable-shell-script";
     101      const char *prog_argv[2] = { prog_path, NULL };
     102  
     103      int err = posix_spawnp (&child, prog_path, &actions, NULL,
     104                              (char **) prog_argv, environ);
     105      if (err != 0)
     106        {
     107          errno = err;
     108          perror ("posix_spawn");
     109          return 1;
     110        }
     111  
     112      posix_spawn_file_actions_destroy (&actions);
     113  
     114      /* Wait for child.  */
     115      int status = 0;
     116      while (waitpid (child, &status, 0) != child)
     117        ;
     118      if (!WIFEXITED (status))
     119        {
     120          fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
     121          return 1;
     122        }
     123      int exitstatus = WEXITSTATUS (status);
     124      if (exitstatus != 0)
     125        {
     126          fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
     127          return 1;
     128        }
     129  
     130      /* Check the contents of the data file.  */
     131      FILE *fp = fopen (DATA_FILENAME, "rb");
     132      if (fp == NULL)
     133        {
     134          perror ("cannot open data file");
     135          return 1;
     136        }
     137      char buf[1024];
     138      int nread = fread (buf, 1, sizeof (buf), fp);
     139      if (!(nread == 11 && memcmp (buf, "Halle Potta", 11) == 0))
     140        {
     141          fprintf (stderr, "data file wrong: has %d bytes, expected %d bytes\n", nread, 11);
     142          return 1;
     143        }
     144      if (fclose (fp))
     145        {
     146          perror ("cannot close data file");
     147          return 1;
     148        }
     149    }
     150  #endif
     151  
     152    /* Clean up data file.  */
     153    unlink (DATA_FILENAME);
     154  
     155    return 0;
     156  }