root/maint/gnulib/tests/test-posix_spawn-chdir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fd_safer
  2. test
  3. main

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 ()
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }

/* [previous][next][first][last][top][bottom][index][help] */