(root)/
gettext-0.22.4/
gettext-tools/
gnulib-tests/
test-posix_spawn-open1.c
       1  /* Test of posix_spawn() function with 'open' action.
       2     Copyright (C) 2008-2023 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>, 2008.  */
      18  
      19  /* Test whether posix_spawn_file_actions_addopen supports filename arguments
      20     that contain special characters such as '*'.  */
      21  
      22  #include <config.h>
      23  
      24  #include <spawn.h>
      25  
      26  #include "signature.h"
      27  SIGNATURE_CHECK (posix_spawn, int, (pid_t *, char const *,
      28                                      posix_spawn_file_actions_t const *,
      29                                      posix_spawnattr_t const *,
      30                                      char *const[], char *const[]));
      31  #include <errno.h>
      32  #include <fcntl.h>
      33  #include <signal.h>
      34  #include <stdio.h>
      35  #include <string.h>
      36  #include <unistd.h>
      37  #include <sys/types.h>
      38  #include <sys/wait.h>
      39  
      40  #define CHILD_PROGRAM_FILENAME "test-posix_spawn-open1" EXEEXT
      41  #define DATA_FILENAME "t!#$%&'()*+,-;=?@[\\]^_`{|}~.tmp"
      42  /* On Windows (including Cygwin), '*' '?' '\\' '|' cannot be used in file
      43     names.  */
      44  #if defined _WIN32 || defined __CYGWIN__
      45  # undef DATA_FILENAME
      46  # define DATA_FILENAME "t!#$%&'()+,-;=@[]^_`{}~.tmp"
      47  #endif
      48  
      49  static int
      50  parent_main (void)
      51  {
      52    FILE *fp;
      53    char *argv[3] = { CHILD_PROGRAM_FILENAME, "-child", NULL };
      54    posix_spawn_file_actions_t actions;
      55    bool actions_allocated;
      56    int err;
      57    pid_t child;
      58    int status;
      59    int exitstatus;
      60  
      61    /* Create a data file with specific contents.  */
      62    fp = fopen (DATA_FILENAME, "wb");
      63    if (fp == NULL)
      64      {
      65        perror ("cannot create data file");
      66        return 1;
      67      }
      68    fwrite ("Halle Potta", 1, 11, fp);
      69    if (fflush (fp) || fclose (fp))
      70      {
      71        perror ("cannot prepare data file");
      72        return 1;
      73      }
      74  
      75    /* Avoid reading from our stdin, as it could block.  */
      76    if (freopen ("/dev/null", "rb", stdin) == NULL)
      77      {
      78        perror ("cannot redirect stdin");
      79        return 1;
      80      }
      81  
      82    /* Test whether posix_spawn_file_actions_addopen with this file name
      83       actually works, by spawning a child that reads from this file.  */
      84    actions_allocated = false;
      85    if ((err = posix_spawn_file_actions_init (&actions)) != 0
      86        || (actions_allocated = true,
      87            (err = posix_spawn_file_actions_addopen (&actions, STDIN_FILENO, DATA_FILENAME, O_RDONLY, 0600)) != 0
      88            || (err = posix_spawn (&child, CHILD_PROGRAM_FILENAME, &actions, NULL, argv, environ)) != 0))
      89      {
      90        if (actions_allocated)
      91          posix_spawn_file_actions_destroy (&actions);
      92        errno = err;
      93        perror ("subprocess failed");
      94        return 1;
      95      }
      96    posix_spawn_file_actions_destroy (&actions);
      97    status = 0;
      98    while (waitpid (child, &status, 0) != child)
      99      ;
     100    if (!WIFEXITED (status))
     101      {
     102        fprintf (stderr, "subprocess terminated with unexpected wait status %d\n", status);
     103        return 1;
     104      }
     105    exitstatus = WEXITSTATUS (status);
     106    if (exitstatus != 0)
     107      {
     108        fprintf (stderr, "subprocess terminated with unexpected exit status %d\n", exitstatus);
     109        return 1;
     110      }
     111    return 0;
     112  }
     113  
     114  static int
     115  child_main (void)
     116  {
     117    char buf[1024];
     118  
     119    /* See if reading from STDIN_FILENO yields the expected contents.  */
     120    if (fread (buf, 1, sizeof (buf), stdin) == 11
     121        && memcmp (buf, "Halle Potta", 11) == 0)
     122      return 0;
     123    else
     124      return 2;
     125  }
     126  
     127  static void
     128  cleanup_then_die (int sig)
     129  {
     130    /* Clean up data file.  */
     131    unlink (DATA_FILENAME);
     132  
     133    /* Re-raise the signal and die from it.  */
     134    signal (sig, SIG_DFL);
     135    raise (sig);
     136  }
     137  
     138  int
     139  main (int argc, char *argv[])
     140  {
     141    int exitstatus;
     142  
     143    if (!(argc > 1 && strcmp (argv[1], "-child") == 0))
     144      {
     145        /* This is the parent process.  */
     146        signal (SIGINT, cleanup_then_die);
     147        signal (SIGTERM, cleanup_then_die);
     148        #ifdef SIGHUP
     149        signal (SIGHUP, cleanup_then_die);
     150        #endif
     151  
     152        exitstatus = parent_main ();
     153      }
     154    else
     155      {
     156        /* This is the child process.  */
     157  
     158        exitstatus = child_main ();
     159      }
     160    unlink (DATA_FILENAME);
     161    return exitstatus;
     162  }