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/xthread.h>
29#include <support/xunistd.h>
30
31static char *tmpdir;
32static long int namemax;
33
34static void
35do_prepare (int argc, char *argv[])
36{
37 tmpdir = support_create_temp_directory (base: "tst-system-");
38 /* Include the last '/0'. */
39 namemax = pathconf (path: tmpdir, _PC_NAME_MAX) + 1;
40 TEST_VERIFY_EXIT (namemax != -1);
41}
42#define PREPARE do_prepare
43
44struct args
45{
46 const char *command;
47 int exit_status;
48 int term_sig;
49 const char *path;
50};
51
52static void
53call_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 (command: 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
75static void *
76sleep_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
89static int
90do_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 (callback: call_system,
101 closure: &(struct args) {
102 cmd, 127, 0, tmpdir
103 });
104 support_capture_subprocess_check (&result, context: "system", status_or_signal: 0, allowed: sc_allow_stderr);
105
106 char *returnerr = xasprintf (format: "%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 (ptr: 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 (callback: call_system,
120 closure: &(struct args) {
121 cmd, 127, 0, tmpdir
122 });
123 support_capture_subprocess_check (&result, context: "system", status_or_signal: 0, allowed: sc_allow_stderr);
124
125 char *returnerr = xasprintf (format: "%s: execing %s failed: "
126 "File name too long",
127 basename(_PATH_BSHELL), cmd);
128 TEST_COMPARE_STRING (result.err.buffer, returnerr);
129 free (ptr: returnerr);
130 }
131
132 {
133 struct support_capture_subprocess result;
134 result = support_capture_subprocess (callback: call_system,
135 closure: &(struct args) {
136 "kill $$", 0, SIGTERM
137 });
138 support_capture_subprocess_check (&result, context: "system", status_or_signal: 0, allowed: sc_allow_none);
139 }
140
141 {
142 struct support_capture_subprocess result;
143 result = support_capture_subprocess (callback: call_system,
144 closure: &(struct args) { "echo ...", 0 });
145 support_capture_subprocess_check (&result, context: "system", status_or_signal: 0, allowed: sc_allow_stdout);
146 TEST_COMPARE_STRING (result.out.buffer, "...\n");
147 }
148
149 {
150 struct support_capture_subprocess result;
151 result = support_capture_subprocess (callback: call_system,
152 closure: &(struct args) { "exit 1", 1 });
153 support_capture_subprocess_check (&result, context: "system", status_or_signal: 0, allowed: sc_allow_none);
154 }
155
156 {
157 struct stat64 st;
158 xstat (_PATH_BSHELL, &st);
159 mode_t mode = st.st_mode;
160 xchmod (_PATH_BSHELL, mode: mode & ~(S_IXUSR | S_IXGRP | S_IXOTH));
161
162 struct support_capture_subprocess result;
163 result = support_capture_subprocess (callback: call_system,
164 closure: &(struct args) {
165 "exit 1", 127, 0
166 });
167 support_capture_subprocess_check (&result, context: "system", status_or_signal: 0, allowed: sc_allow_none);
168
169 xchmod (_PATH_BSHELL, mode: st.st_mode);
170 }
171
172 {
173 pthread_t long_sleep_thread = xpthread_create (NULL,
174 thread_func: sleep_and_check_sigchld,
175 closure: &(double) { 0.2 });
176 pthread_t short_sleep_thread = xpthread_create (NULL,
177 thread_func: sleep_and_check_sigchld,
178 closure: &(double) { 0.1 });
179 xpthread_join (thr: short_sleep_thread);
180 xpthread_join (thr: long_sleep_thread);
181 }
182
183 TEST_COMPARE (system (""), 0);
184
185 return 0;
186}
187
188#include <support/test-driver.c>
189

source code of glibc/stdlib/tst-system.c