(root)/
m4-1.4.19/
tests/
test-posix_spawn-chdir.c
       1  /* Test of posix_spawn() function with 'chdir' action.
       2     Copyright (C) 2008-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 of the License, or
       7     (at your option) 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  /* Written by Bruno Haible <bruno@clisp.org>, 2018.  */
      18  
      19  #include <config.h>
      20  
      21  #include <spawn.h>
      22  
      23  #include <errno.h>
      24  #include <fcntl.h>
      25  #include <signal.h>
      26  #include <stdbool.h>
      27  #include <stdio.h>
      28  #include <stdlib.h>
      29  #include <string.h>
      30  #include <unistd.h>
      31  #include <sys/types.h>
      32  #include <sys/wait.h>
      33  
      34  #include "findprog.h"
      35  
      36  static int
      37  fd_safer (int fd)
      38  {
      39    if (0 <= fd && fd <= 2)
      40      {
      41        int f = fd_safer (dup (fd));
      42        int e = errno;
      43        close (fd);
      44        errno = e;
      45        fd = f;
      46      }
      47  
      48    return fd;
      49  }
      50  
      51  static void
      52  test (const char *pwd_prog)
      53  {
      54    char *argv[2] = { (char *) "pwd", NULL };
      55    int ifd[2];
      56    sigset_t blocked_signals;
      57    sigset_t fatal_signal_set;
      58    posix_spawn_file_actions_t actions;
      59    bool actions_allocated;
      60    posix_spawnattr_t attrs;
      61    bool attrs_allocated;
      62    int err;
      63    pid_t child;
      64    int fd;
      65    FILE *fp;
      66    char line[80];
      67    int line_len;
      68    int status;
      69    int exitstatus;
      70  
      71    if (pipe (ifd) < 0 || (ifd[0] = fd_safer (ifd[0])) < 0)
      72      {
      73        perror ("cannot create pipe");
      74        exit (1);
      75      }
      76    sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
      77    sigemptyset (&fatal_signal_set);
      78    sigaddset (&fatal_signal_set, SIGINT);
      79    sigaddset (&fatal_signal_set, SIGTERM);
      80    #ifdef SIGHUP
      81    sigaddset (&fatal_signal_set, SIGHUP);
      82    #endif
      83    #ifdef SIGPIPE
      84    sigaddset (&fatal_signal_set, SIGPIPE);
      85    #endif
      86    sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
      87    actions_allocated = false;
      88    attrs_allocated = false;
      89    if ((err = posix_spawn_file_actions_init (&actions)) != 0
      90        || (actions_allocated = true,
      91            (err = posix_spawn_file_actions_adddup2 (&actions, ifd[1], STDOUT_FILENO)) != 0
      92            || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
      93            || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
      94            || (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, "/dev/null", O_RDONLY, 0)) != 0
      95            || (err = posix_spawn_file_actions_addchdir (&actions, "/")) != 0
      96            || (err = posix_spawnattr_init (&attrs)) != 0
      97            || (attrs_allocated = true,
      98                #if defined _WIN32 && !defined __CYGWIN__
      99                0
     100                #else
     101                (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
     102                || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0
     103                #endif
     104               )
     105            || (err = posix_spawnp (&child, pwd_prog, &actions, &attrs, argv, environ)) != 0))
     106      {
     107        if (actions_allocated)
     108          posix_spawn_file_actions_destroy (&actions);
     109        if (attrs_allocated)
     110          posix_spawnattr_destroy (&attrs);
     111        sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
     112        errno = err;
     113        perror ("subprocess failed");
     114        exit (1);
     115      }
     116    posix_spawn_file_actions_destroy (&actions);
     117    posix_spawnattr_destroy (&attrs);
     118    sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
     119    close (ifd[1]);
     120    fd = ifd[0];
     121    fp = fdopen (fd, "rb");
     122    if (fp == NULL)
     123      {
     124        fprintf (stderr, "fdopen() failed\n");
     125        exit (1);
     126      }
     127    line_len = fread (line, 1, 80, fp);
     128    if (line_len < 2)
     129      {
     130        fprintf (stderr, "could not read expected output\n");
     131        exit (1);
     132      }
     133    if (!(line_len == 2 && memcmp (line, "/\n", 2) == 0))
     134  #if defined _WIN32 && !defined __CYGWIN__
     135      /* If the pwd program is Cygwin's pwd, its output in the root directory is
     136         "/cygdrive/N", where N is a lowercase letter.  */
     137      if (!(line_len > 11
     138            && memcmp (line, "/cygdrive/", 10) == 0
     139            && line[10] >= 'a' && line[10] <= 'z'
     140            && ((line_len == 12 && line[11] == '\n')
     141                || (line_len == 13 && line[11] == '\r' && line[12] == '\n'))))
     142  #endif
     143        {
     144          fprintf (stderr, "read output is not the expected output\n");
     145          exit (1);
     146        }
     147    fclose (fp);
     148    status = 0;
     149    while (waitpid (child, &status, 0) != child)
     150      ;
     151    if (!WIFEXITED (status))
     152      {
     153        fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
     154        exit (1);
     155      }
     156    exitstatus = WEXITSTATUS (status);
     157    if (exitstatus != 0)
     158      {
     159        fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
     160        exit (1);
     161      }
     162  }
     163  
     164  int
     165  main ()
     166  {
     167    test ("pwd");
     168  
     169    /* Verify that if a program is given as a relative file name with at least one
     170       slash, it is interpreted w.r.t. the current directory after chdir has been
     171       executed.  */
     172    {
     173      const char *abs_pwd_prog = find_in_path ("pwd");
     174  
     175      if (abs_pwd_prog != NULL
     176          && abs_pwd_prog[0] == '/'
     177          && abs_pwd_prog[1] != '0' && abs_pwd_prog[1] != '/')
     178        test (&abs_pwd_prog[1]);
     179    }
     180  
     181    return 0;
     182  }