root/maint/gnulib/tests/test-posix_spawn-fchdir.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 'fchdir' 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 #include "qemu.h"
  36 
  37 static bool is_qemu;
  38 
  39 static int
  40 fd_safer (int fd)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42   if (0 <= fd && fd <= 2)
  43     {
  44       int f = fd_safer (dup (fd));
  45       int e = errno;
  46       close (fd);
  47       errno = e;
  48       fd = f;
  49     }
  50 
  51   return fd;
  52 }
  53 
  54 static void
  55 test (const char *pwd_prog)
     /* [previous][next][first][last][top][bottom][index][help] */
  56 {
  57   char *argv[2] = { (char *) "pwd", NULL };
  58   int rootfd;
  59   int ifd[2];
  60   sigset_t blocked_signals;
  61   sigset_t fatal_signal_set;
  62   posix_spawn_file_actions_t actions;
  63   bool actions_allocated;
  64   posix_spawnattr_t attrs;
  65   bool attrs_allocated;
  66   int err;
  67   pid_t child;
  68   int fd;
  69   FILE *fp;
  70   char line[80];
  71   int status;
  72   int exitstatus;
  73 
  74   rootfd = open ("/", O_RDONLY);
  75   if (rootfd < 0)
  76     {
  77       perror ("cannot open directory");
  78       exit (1);
  79     }
  80   if (pipe (ifd) < 0 || (ifd[0] = fd_safer (ifd[0])) < 0)
  81     {
  82       perror ("cannot create pipe");
  83       exit (1);
  84     }
  85   sigprocmask (SIG_SETMASK, NULL, &blocked_signals);
  86   sigemptyset (&fatal_signal_set);
  87   sigaddset (&fatal_signal_set, SIGINT);
  88   sigaddset (&fatal_signal_set, SIGTERM);
  89   #ifdef SIGHUP
  90   sigaddset (&fatal_signal_set, SIGHUP);
  91   #endif
  92   #ifdef SIGPIPE
  93   sigaddset (&fatal_signal_set, SIGPIPE);
  94   #endif
  95   sigprocmask (SIG_BLOCK, &fatal_signal_set, NULL);
  96   actions_allocated = false;
  97   attrs_allocated = false;
  98   if ((err = posix_spawn_file_actions_init (&actions)) != 0
  99       || (actions_allocated = true,
 100           (err = posix_spawn_file_actions_adddup2 (&actions, ifd[1], STDOUT_FILENO)) != 0
 101           || (err = posix_spawn_file_actions_addclose (&actions, ifd[1])) != 0
 102           || (err = posix_spawn_file_actions_addclose (&actions, ifd[0])) != 0
 103           || (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, "/dev/null", O_RDONLY, 0)) != 0
 104           || (err = posix_spawn_file_actions_addfchdir (&actions, rootfd)) != 0
 105           || (err = posix_spawnattr_init (&attrs)) != 0
 106           || (attrs_allocated = true,
 107               #if defined _WIN32 && !defined __CYGWIN__
 108               0
 109               #else
 110               (err = posix_spawnattr_setsigmask (&attrs, &blocked_signals)) != 0
 111               || (err = posix_spawnattr_setflags (&attrs, POSIX_SPAWN_SETSIGMASK)) != 0
 112               #endif
 113              )
 114           || (err = posix_spawnp (&child, pwd_prog, &actions, &attrs, argv, environ)) != 0))
 115     {
 116       if (actions_allocated)
 117         posix_spawn_file_actions_destroy (&actions);
 118       if (attrs_allocated)
 119         posix_spawnattr_destroy (&attrs);
 120       sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
 121       errno = err;
 122       perror ("subprocess failed");
 123       exit (1);
 124     }
 125   posix_spawn_file_actions_destroy (&actions);
 126   posix_spawnattr_destroy (&attrs);
 127   sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL);
 128   close (ifd[1]);
 129   fd = ifd[0];
 130   fp = fdopen (fd, "r");
 131   if (fp == NULL)
 132     {
 133       fprintf (stderr, "fdopen() failed\n");
 134       exit (1);
 135     }
 136   if (fread (line, 1, 80, fp) < 2)
 137     {
 138       fprintf (stderr, "could not read expected output\n");
 139       exit (1);
 140     }
 141   /* For a process running under QEMU user-mode, rootfd points to the directory
 142      that is the value of the QEMU_LD_PREFIX environment variable or of the -L
 143      command-line option, and the line produced by 'pwd' is that directory, not
 144      "/".  */
 145   if (!is_qemu)
 146     {
 147       if (memcmp (line, "/\n", 2) != 0)
 148         {
 149           fprintf (stderr, "read output is not the expected output\n");
 150           exit (1);
 151         }
 152     }
 153   fclose (fp);
 154   status = 0;
 155   while (waitpid (child, &status, 0) != child)
 156     ;
 157   if (!WIFEXITED (status))
 158     {
 159       fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
 160       exit (1);
 161     }
 162   exitstatus = WEXITSTATUS (status);
 163   if (exitstatus != 0)
 164     {
 165       fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
 166       exit (1);
 167     }
 168 }
 169 
 170 int
 171 main ()
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173   is_qemu = is_running_under_qemu_user ();
 174 
 175   test ("pwd");
 176 
 177   /* Verify that if a program is given as a relative file name with at least one
 178      slash, it is interpreted w.r.t. the current directory after fchdir has been
 179      executed.  */
 180   if (!is_qemu)
 181     {
 182       const char *abs_pwd_prog = find_in_path ("pwd");
 183 
 184       if (abs_pwd_prog != NULL
 185           && abs_pwd_prog[0] == '/'
 186           && abs_pwd_prog[1] != '0' && abs_pwd_prog[1] != '/')
 187         test (&abs_pwd_prog[1]);
 188     }
 189 
 190   return 0;
 191 }

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