1 /* Copyright (C) 2002-2022 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/xunistd.h>
29 
30 static char *tmpdir;
31 static long int namemax;
32 
33 static void
do_prepare(int argc,char * argv[])34 do_prepare (int argc, char *argv[])
35 {
36   tmpdir = support_create_temp_directory ("tst-system-");
37   /* Include the last '/0'.  */
38   namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1;
39   TEST_VERIFY_EXIT (namemax != -1);
40 }
41 #define PREPARE do_prepare
42 
43 struct args
44 {
45   const char *command;
46   int exit_status;
47   int term_sig;
48   const char *path;
49 };
50 
51 static void
call_system(void * closure)52 call_system (void *closure)
53 {
54   struct args *args = (struct args *) closure;
55   int ret;
56 
57   if (args->path != NULL)
58     TEST_COMPARE (setenv ("PATH", args->path, 1), 0);
59   ret = system (args->command);
60   if (args->term_sig == 0)
61     {
62       /* Expect regular termination.  */
63       TEST_VERIFY (WIFEXITED (ret) != 0);
64       TEST_COMPARE (WEXITSTATUS (ret), args->exit_status);
65     }
66   else
67     {
68       /* status_or_signal < 0.  Expect termination by signal.  */
69       TEST_VERIFY (WIFSIGNALED (ret) != 0);
70       TEST_COMPARE (WTERMSIG (ret), args->term_sig);
71     }
72 }
73 
74 static int
do_test(void)75 do_test (void)
76 {
77   TEST_VERIFY (system (NULL) != 0);
78 
79   {
80     char cmd[namemax];
81     memset (cmd, 'a', sizeof(cmd));
82     cmd[sizeof(cmd) - 1] = '\0';
83 
84     struct support_capture_subprocess result;
85     result = support_capture_subprocess (call_system,
86 					 &(struct args) {
87 					   cmd, 127, 0, tmpdir
88 					 });
89     support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
90 
91     char *returnerr = xasprintf ("%s: execing %s failed: "
92 				 "No such file or directory",
93 				 basename(_PATH_BSHELL), cmd);
94     TEST_COMPARE_STRING (result.err.buffer, returnerr);
95     free (returnerr);
96   }
97 
98   {
99     char cmd[namemax + 1];
100     memset (cmd, 'a', sizeof(cmd));
101     cmd[sizeof(cmd) - 1] = '\0';
102 
103     struct support_capture_subprocess result;
104     result = support_capture_subprocess (call_system,
105 					 &(struct args) {
106 					   cmd, 127, 0, tmpdir
107 					 });
108     support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
109 
110     char *returnerr = xasprintf ("%s: execing %s failed: "
111 				 "File name too long",
112 				 basename(_PATH_BSHELL), cmd);
113     TEST_COMPARE_STRING (result.err.buffer, returnerr);
114     free (returnerr);
115   }
116 
117   {
118     struct support_capture_subprocess result;
119     result = support_capture_subprocess (call_system,
120 					 &(struct args) {
121 					   "kill $$", 0, SIGTERM
122 					 });
123     support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
124   }
125 
126   {
127     struct support_capture_subprocess result;
128     result = support_capture_subprocess (call_system,
129 					 &(struct args) { "echo ...", 0 });
130     support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout);
131     TEST_COMPARE_STRING (result.out.buffer, "...\n");
132   }
133 
134   {
135     struct support_capture_subprocess result;
136     result = support_capture_subprocess (call_system,
137 					 &(struct args) { "exit 1", 1 });
138     support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
139   }
140 
141   {
142     struct stat64 st;
143     xstat (_PATH_BSHELL, &st);
144     mode_t mode = st.st_mode;
145     xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH));
146 
147     struct support_capture_subprocess result;
148     result = support_capture_subprocess (call_system,
149 					 &(struct args) {
150 					   "exit 1", 127, 0
151 					 });
152     support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
153 
154     xchmod (_PATH_BSHELL, st.st_mode);
155   }
156 
157   TEST_COMPARE (system (""), 0);
158 
159   return 0;
160 }
161 
162 #include <support/test-driver.c>
163