Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/stdlib/system_test.c
178586 views
1
/*-
2
* Copyright (c) 2026 Klara, Inc.
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*/
6
7
#include <sys/wait.h>
8
9
#include <errno.h>
10
#include <fcntl.h>
11
#include <pthread.h>
12
#include <signal.h>
13
#include <stdio.h>
14
#include <stdlib.h>
15
#include <unistd.h>
16
17
#include <atf-c.h>
18
19
ATF_TC(system_true);
20
ATF_TC_HEAD(system_true, tc)
21
{
22
atf_tc_set_md_var(tc, "descr", "system(\"true\")");
23
}
24
ATF_TC_BODY(system_true, tc)
25
{
26
ATF_REQUIRE_EQ(W_EXITCODE(0, 0), system("true"));
27
}
28
29
ATF_TC(system_false);
30
ATF_TC_HEAD(system_false, tc)
31
{
32
atf_tc_set_md_var(tc, "descr", "system(\"false\")");
33
}
34
ATF_TC_BODY(system_false, tc)
35
{
36
ATF_REQUIRE_EQ(W_EXITCODE(1, 0), system("false"));
37
}
38
39
ATF_TC(system_touch);
40
ATF_TC_HEAD(system_touch, tc)
41
{
42
atf_tc_set_md_var(tc, "descr", "system(\"touch file\")");
43
}
44
ATF_TC_BODY(system_touch, tc)
45
{
46
/* The file does not exist */
47
ATF_CHECK_ERRNO(ENOENT, unlink("file"));
48
49
/* Run a command that creates it */
50
ATF_REQUIRE_EQ(W_EXITCODE(0, 0), system("touch file"));
51
52
/* Now the file exists */
53
ATF_CHECK_EQ(0, unlink("file"));
54
}
55
56
ATF_TC(system_null);
57
ATF_TC_HEAD(system_null, tc)
58
{
59
atf_tc_set_md_var(tc, "descr", "system(NULL)");
60
atf_tc_set_md_var(tc, "require.user", "root");
61
}
62
ATF_TC_BODY(system_null, tc)
63
{
64
/* First, test in a normal environment */
65
ATF_REQUIRE_EQ(1, system(NULL));
66
67
/* Now enter an empty chroot */
68
ATF_REQUIRE_EQ(0, chroot("."));
69
ATF_REQUIRE_EQ(0, chdir("/"));
70
71
/* Test again with no shell available */
72
ATF_REQUIRE_EQ(0, system(NULL));
73
ATF_REQUIRE_EQ(W_EXITCODE(127, 0), system("true"));
74
}
75
76
/*
77
* Define PROCMASK_IS_THREADMASK if sigprocmask() gets / sets the thread
78
* mask in multithreaded programs, which makes it impossible to verify
79
* that system(3) correctly blocks and unblocks SIGCHLD.
80
*/
81
#ifdef __FreeBSD__
82
#define PROCMASK_IS_THREADMASK 1
83
#endif
84
85
static void *
86
system_thread(void *arg)
87
{
88
char cmd[64];
89
int i = (int)(intptr_t)arg;
90
91
snprintf(cmd, sizeof(cmd), "rm flag%d ; lockf -ns lock%d true", i, i);
92
return ((void *)(intptr_t)system(cmd));
93
}
94
95
static inline int
96
sigcmpset(const sigset_t *a, const sigset_t *b)
97
{
98
return (memcmp(a, b, sizeof(sigset_t)));
99
}
100
101
ATF_TC(system_concurrent);
102
ATF_TC_HEAD(system_concurrent, tc)
103
{
104
atf_tc_set_md_var(tc, "descr", "Concurrent calls");
105
}
106
ATF_TC_BODY(system_concurrent, tc)
107
{
108
enum { N = 3 };
109
struct sigaction sigint, sigquit, sigact;
110
sigset_t normset, sigset;
111
pthread_t thr[N];
112
char fn[8];
113
int fd[N];
114
void *arg, *ret;
115
116
/* Create and lock the locks */
117
for (int i = 0; i < N; i++) {
118
snprintf(fn, sizeof(fn), "lock%d", i);
119
fd[i] = open(fn, O_CREAT|O_EXCL|O_EXLOCK|O_CLOEXEC, 0644);
120
ATF_REQUIRE_MSG(fd[i] >= 0, "%s: %m", fn);
121
}
122
123
/* Create the flags */
124
for (int i = 0; i < N; i++) {
125
snprintf(fn, sizeof(fn), "flag%d", i);
126
ATF_REQUIRE_EQ(0, symlink(fn, fn));
127
}
128
129
/* Save the current signal dispositions */
130
ATF_REQUIRE_EQ(0, sigaction(SIGINT, NULL, &sigint));
131
ATF_REQUIRE_EQ(0, sigaction(SIGQUIT, NULL, &sigquit));
132
ATF_REQUIRE_EQ(0, sigprocmask(0, NULL, &normset));
133
134
/* Spawn threads which block on these files */
135
for (int i = 0; i < N; i++) {
136
arg = (void *)(intptr_t)i;
137
ATF_REQUIRE_INTEQ(0,
138
pthread_create(&thr[i], NULL, system_thread, arg));
139
}
140
141
/* Wait until the flags are gone */
142
for (int i = 0; i < N; i++) {
143
snprintf(fn, sizeof(fn), "flag%d", i);
144
while (readlink(fn, fn, sizeof(fn)) > 0)
145
usleep(10000);
146
ATF_REQUIRE_EQ(ENOENT, errno);
147
}
148
149
/* Release the locks */
150
for (int i = 0; i < N; i++) {
151
/* Check the signal dispositions */
152
ATF_REQUIRE_EQ(0, sigaction(SIGINT, NULL, &sigact));
153
ATF_CHECK_EQ(SIG_IGN, sigact.sa_handler);
154
ATF_REQUIRE_EQ(0, sigaction(SIGQUIT, NULL, &sigact));
155
ATF_CHECK_EQ(SIG_IGN, sigact.sa_handler);
156
#ifndef PROCMASK_IS_THREADMASK
157
ATF_REQUIRE_EQ(0, sigprocmask(0, NULL, &sigset));
158
ATF_CHECK(sigismember(&sigset, SIGCHLD));
159
#endif
160
161
/* Close the file, releasing the lock */
162
ATF_REQUIRE_INTEQ(0, close(fd[i]));
163
164
/* Join the thread and check the return value */
165
ATF_CHECK_INTEQ(0, pthread_join(thr[i], &ret));
166
ATF_CHECK_INTEQ(W_EXITCODE(0, 0), (int)(intptr_t)ret);
167
}
168
169
/* Check the signal dispositions */
170
ATF_REQUIRE_EQ(0, sigaction(SIGINT, NULL, &sigact));
171
ATF_CHECK_EQ(sigint.sa_handler, sigact.sa_handler);
172
ATF_CHECK_EQ(sigint.sa_flags, sigact.sa_flags);
173
ATF_CHECK_EQ(0, sigcmpset(&sigint.sa_mask, &sigact.sa_mask));
174
ATF_REQUIRE_EQ(0, sigaction(SIGQUIT, NULL, &sigact));
175
ATF_CHECK_EQ(sigquit.sa_handler, sigact.sa_handler);
176
ATF_CHECK_EQ(sigquit.sa_flags, sigact.sa_flags);
177
ATF_CHECK_EQ(0, sigcmpset(&sigquit.sa_mask, &sigact.sa_mask));
178
ATF_REQUIRE_EQ(0, sigprocmask(0, NULL, &sigset));
179
ATF_CHECK_EQ(0, sigcmpset(&sigset, &normset));
180
}
181
182
ATF_TP_ADD_TCS(tp)
183
{
184
ATF_TP_ADD_TC(tp, system_true);
185
ATF_TP_ADD_TC(tp, system_false);
186
ATF_TP_ADD_TC(tp, system_touch);
187
ATF_TP_ADD_TC(tp, system_null);
188
ATF_TP_ADD_TC(tp, system_concurrent);
189
return (atf_no_error());
190
}
191
192