(root)/
glibc-2.38/
stdlib/
tst-system.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library 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 GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <stdlib.h>
      19  #include <unistd.h>
      20  #include <string.h>
      21  #include <signal.h>
      22  #include <paths.h>
      23  
      24  #include <support/capture_subprocess.h>
      25  #include <support/check.h>
      26  #include <support/temp_file.h>
      27  #include <support/support.h>
      28  #include <support/xthread.h>
      29  #include <support/xunistd.h>
      30  
      31  static char *tmpdir;
      32  static long int namemax;
      33  
      34  static void
      35  do_prepare (int argc, char *argv[])
      36  {
      37    tmpdir = support_create_temp_directory ("tst-system-");
      38    /* Include the last '/0'.  */
      39    namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1;
      40    TEST_VERIFY_EXIT (namemax != -1);
      41  }
      42  #define PREPARE do_prepare
      43  
      44  struct args
      45  {
      46    const char *command;
      47    int exit_status;
      48    int term_sig;
      49    const char *path;
      50  };
      51  
      52  static void
      53  call_system (void *closure)
      54  {
      55    struct args *args = (struct args *) closure;
      56    int ret;
      57  
      58    if (args->path != NULL)
      59      TEST_COMPARE (setenv ("PATH", args->path, 1), 0);
      60    ret = system (args->command);
      61    if (args->term_sig == 0)
      62      {
      63        /* Expect regular termination.  */
      64        TEST_VERIFY (WIFEXITED (ret) != 0);
      65        TEST_COMPARE (WEXITSTATUS (ret), args->exit_status);
      66      }
      67    else
      68      {
      69        /* status_or_signal < 0.  Expect termination by signal.  */
      70        TEST_VERIFY (WIFSIGNALED (ret) != 0);
      71        TEST_COMPARE (WTERMSIG (ret), args->term_sig);
      72      }
      73  }
      74  
      75  static void *
      76  sleep_and_check_sigchld (void *closure)
      77  {
      78    double *seconds = (double *) closure;
      79    char cmd[namemax];
      80    sprintf (cmd, "sleep %lf" , *seconds);
      81    TEST_COMPARE (system (cmd), 0);
      82  
      83    sigset_t blocked = {0};
      84    TEST_COMPARE (sigprocmask (SIG_BLOCK, NULL, &blocked), 0);
      85    TEST_COMPARE (sigismember (&blocked, SIGCHLD), 0);
      86    return NULL;
      87  }
      88  
      89  static int
      90  do_test (void)
      91  {
      92    TEST_VERIFY (system (NULL) != 0);
      93  
      94    {
      95      char cmd[namemax];
      96      memset (cmd, 'a', sizeof(cmd));
      97      cmd[sizeof(cmd) - 1] = '\0';
      98  
      99      struct support_capture_subprocess result;
     100      result = support_capture_subprocess (call_system,
     101  					 &(struct args) {
     102  					   cmd, 127, 0, tmpdir
     103  					 });
     104      support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
     105  
     106      char *returnerr = xasprintf ("%s: execing %s failed: "
     107  				 "No such file or directory",
     108  				 basename(_PATH_BSHELL), cmd);
     109      TEST_COMPARE_STRING (result.err.buffer, returnerr);
     110      free (returnerr);
     111    }
     112  
     113    {
     114      char cmd[namemax + 1];
     115      memset (cmd, 'a', sizeof(cmd));
     116      cmd[sizeof(cmd) - 1] = '\0';
     117  
     118      struct support_capture_subprocess result;
     119      result = support_capture_subprocess (call_system,
     120  					 &(struct args) {
     121  					   cmd, 127, 0, tmpdir
     122  					 });
     123      support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
     124  
     125      char *returnerr = xasprintf ("%s: execing %s failed: "
     126  				 "File name too long",
     127  				 basename(_PATH_BSHELL), cmd);
     128      TEST_COMPARE_STRING (result.err.buffer, returnerr);
     129      free (returnerr);
     130    }
     131  
     132    {
     133      struct support_capture_subprocess result;
     134      result = support_capture_subprocess (call_system,
     135  					 &(struct args) {
     136  					   "kill $$", 0, SIGTERM
     137  					 });
     138      support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
     139    }
     140  
     141    {
     142      struct support_capture_subprocess result;
     143      result = support_capture_subprocess (call_system,
     144  					 &(struct args) { "echo ...", 0 });
     145      support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout);
     146      TEST_COMPARE_STRING (result.out.buffer, "...\n");
     147    }
     148  
     149    {
     150      struct support_capture_subprocess result;
     151      const char *cmd = "-echo";
     152      result = support_capture_subprocess (call_system,
     153  					 &(struct args) { cmd, 127 });
     154      support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr |
     155  			sc_allow_stdout);
     156      char *returnerr = xasprintf ("%s: execing -echo failed: "
     157  				 "No such file or directory",
     158  				 basename(_PATH_BSHELL));
     159      TEST_COMPARE_STRING (result.err.buffer, returnerr);
     160      free (returnerr);
     161    }
     162  
     163    {
     164      struct support_capture_subprocess result;
     165      result = support_capture_subprocess (call_system,
     166  					 &(struct args) { "exit 1", 1 });
     167      support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
     168    }
     169  
     170    {
     171      struct stat64 st;
     172      xstat (_PATH_BSHELL, &st);
     173      mode_t mode = st.st_mode;
     174      xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH));
     175  
     176      struct support_capture_subprocess result;
     177      result = support_capture_subprocess (call_system,
     178  					 &(struct args) {
     179  					   "exit 1", 127, 0
     180  					 });
     181      support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
     182  
     183      xchmod (_PATH_BSHELL, st.st_mode);
     184    }
     185  
     186    {
     187      pthread_t long_sleep_thread = xpthread_create (NULL,
     188                                                     sleep_and_check_sigchld,
     189                                                     &(double) { 0.2 });
     190      pthread_t short_sleep_thread = xpthread_create (NULL,
     191                                                      sleep_and_check_sigchld,
     192                                                      &(double) { 0.1 });
     193      xpthread_join (short_sleep_thread);
     194      xpthread_join (long_sleep_thread);
     195    }
     196  
     197    TEST_COMPARE (system (""), 0);
     198  
     199    return 0;
     200  }
     201  
     202  #include <support/test-driver.c>