Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/atf/atf-c/check.c
39481 views
1
/* Copyright (c) 2008 The NetBSD Foundation, Inc.
2
* All rights reserved.
3
*
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
6
* are met:
7
* 1. Redistributions of source code must retain the above copyright
8
* notice, this list of conditions and the following disclaimer.
9
* 2. Redistributions in binary form must reproduce the above copyright
10
* notice, this list of conditions and the following disclaimer in the
11
* documentation and/or other materials provided with the distribution.
12
*
13
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
14
* CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
15
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17
* IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
18
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
20
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
22
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
24
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
25
26
#include "atf-c/check.h"
27
28
#include <sys/wait.h>
29
30
#include <errno.h>
31
#include <fcntl.h>
32
#include <stdint.h>
33
#include <stdio.h>
34
#include <stdlib.h>
35
#include <string.h>
36
#include <unistd.h>
37
38
#include "atf-c/build.h"
39
#include "atf-c/defs.h"
40
#include "atf-c/detail/dynstr.h"
41
#include "atf-c/detail/env.h"
42
#include "atf-c/detail/fs.h"
43
#include "atf-c/detail/list.h"
44
#include "atf-c/detail/process.h"
45
#include "atf-c/detail/sanity.h"
46
#include "atf-c/error.h"
47
#include "atf-c/utils.h"
48
49
/* ---------------------------------------------------------------------
50
* Auxiliary functions.
51
* --------------------------------------------------------------------- */
52
53
static
54
atf_error_t
55
create_tmpdir(atf_fs_path_t *dir)
56
{
57
atf_error_t err;
58
59
err = atf_fs_path_init_fmt(dir, "%s/check.XXXXXX",
60
atf_env_get_with_default("TMPDIR", "/tmp"));
61
if (atf_is_error(err))
62
goto out;
63
64
err = atf_fs_mkdtemp(dir);
65
if (atf_is_error(err)) {
66
atf_fs_path_fini(dir);
67
goto out;
68
}
69
70
INV(!atf_is_error(err));
71
out:
72
return err;
73
}
74
75
static
76
void
77
cleanup_tmpdir(const atf_fs_path_t *dir, const atf_fs_path_t *outfile,
78
const atf_fs_path_t *errfile)
79
{
80
{
81
atf_error_t err = atf_fs_unlink(outfile);
82
if (atf_is_error(err)) {
83
INV(atf_error_is(err, "libc") &&
84
atf_libc_error_code(err) == ENOENT);
85
atf_error_free(err);
86
} else
87
INV(!atf_is_error(err));
88
}
89
90
{
91
atf_error_t err = atf_fs_unlink(errfile);
92
if (atf_is_error(err)) {
93
INV(atf_error_is(err, "libc") &&
94
atf_libc_error_code(err) == ENOENT);
95
atf_error_free(err);
96
} else
97
INV(!atf_is_error(err));
98
}
99
100
{
101
atf_error_t err = atf_fs_rmdir(dir);
102
INV(!atf_is_error(err));
103
}
104
}
105
106
static
107
int
108
const_execvp(const char *file, const char *const *argv)
109
{
110
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
111
return execvp(file, UNCONST(argv));
112
#undef UNCONST
113
}
114
115
static
116
atf_error_t
117
init_sb(const atf_fs_path_t *path, atf_process_stream_t *sb)
118
{
119
atf_error_t err;
120
121
if (path == NULL)
122
err = atf_process_stream_init_inherit(sb);
123
else
124
err = atf_process_stream_init_redirect_path(sb, path);
125
126
return err;
127
}
128
129
static
130
atf_error_t
131
init_sbs(const atf_fs_path_t *outfile, atf_process_stream_t *outsb,
132
const atf_fs_path_t *errfile, atf_process_stream_t *errsb)
133
{
134
atf_error_t err;
135
136
err = init_sb(outfile, outsb);
137
if (atf_is_error(err))
138
goto out;
139
140
err = init_sb(errfile, errsb);
141
if (atf_is_error(err)) {
142
atf_process_stream_fini(outsb);
143
goto out;
144
}
145
146
out:
147
return err;
148
}
149
150
struct exec_data {
151
const char *const *m_argv;
152
};
153
154
static void exec_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
155
156
static
157
void
158
exec_child(void *v)
159
{
160
struct exec_data *ea = v;
161
162
const_execvp(ea->m_argv[0], ea->m_argv);
163
fprintf(stderr, "execvp(%s) failed: %s\n", ea->m_argv[0], strerror(errno));
164
exit(127);
165
}
166
167
static
168
atf_error_t
169
fork_and_wait(const char *const *argv, const atf_fs_path_t *outfile,
170
const atf_fs_path_t *errfile, atf_process_status_t *status)
171
{
172
atf_error_t err;
173
atf_process_child_t child;
174
atf_process_stream_t outsb, errsb;
175
struct exec_data ea = { argv };
176
177
err = init_sbs(outfile, &outsb, errfile, &errsb);
178
if (atf_is_error(err))
179
goto out;
180
181
err = atf_process_fork(&child, exec_child, &outsb, &errsb, &ea);
182
if (atf_is_error(err))
183
goto out_sbs;
184
185
err = atf_process_child_wait(&child, status);
186
187
out_sbs:
188
atf_process_stream_fini(&errsb);
189
atf_process_stream_fini(&outsb);
190
out:
191
return err;
192
}
193
194
static
195
void
196
update_success_from_status(const char *progname,
197
const atf_process_status_t *status, bool *success)
198
{
199
bool s = atf_process_status_exited(status) &&
200
atf_process_status_exitstatus(status) == EXIT_SUCCESS;
201
202
if (atf_process_status_exited(status)) {
203
if (atf_process_status_exitstatus(status) == EXIT_SUCCESS)
204
INV(s);
205
else {
206
INV(!s);
207
fprintf(stderr, "%s failed with exit code %d\n", progname,
208
atf_process_status_exitstatus(status));
209
}
210
} else if (atf_process_status_signaled(status)) {
211
INV(!s);
212
fprintf(stderr, "%s failed due to signal %d%s\n", progname,
213
atf_process_status_termsig(status),
214
atf_process_status_coredump(status) ? " (core dumped)" : "");
215
} else {
216
INV(!s);
217
fprintf(stderr, "%s failed due to unknown reason\n", progname);
218
}
219
220
*success = s;
221
}
222
223
static
224
atf_error_t
225
array_to_list(const char *const *a, atf_list_t *l)
226
{
227
atf_error_t err;
228
229
err = atf_list_init(l);
230
if (atf_is_error(err))
231
goto out;
232
233
while (*a != NULL) {
234
char *item = strdup(*a);
235
if (item == NULL) {
236
err = atf_no_memory_error();
237
goto out;
238
}
239
240
err = atf_list_append(l, item, true);
241
if (atf_is_error(err))
242
goto out;
243
244
a++;
245
}
246
247
out:
248
return err;
249
}
250
251
static void
252
print_array(const char *const *array, const char *pfx)
253
{
254
const char *const *ptr;
255
256
printf("%s", pfx);
257
for (ptr = array; *ptr != NULL; ptr++)
258
printf(" %s", *ptr);
259
printf("\n");
260
}
261
262
static
263
atf_error_t
264
check_build_run(const char *const *argv, bool *success)
265
{
266
atf_error_t err;
267
atf_process_status_t status;
268
269
print_array(argv, ">");
270
271
err = fork_and_wait(argv, NULL, NULL, &status);
272
if (atf_is_error(err))
273
goto out;
274
275
update_success_from_status(argv[0], &status, success);
276
atf_process_status_fini(&status);
277
278
INV(!atf_is_error(err));
279
out:
280
return err;
281
}
282
283
/* ---------------------------------------------------------------------
284
* The "atf_check_result" type.
285
* --------------------------------------------------------------------- */
286
287
struct atf_check_result_impl {
288
atf_list_t m_argv;
289
atf_fs_path_t m_dir;
290
atf_fs_path_t m_stdout;
291
atf_fs_path_t m_stderr;
292
atf_process_status_t m_status;
293
};
294
295
static
296
atf_error_t
297
atf_check_result_init(atf_check_result_t *r, const char *const *argv,
298
const atf_fs_path_t *dir)
299
{
300
atf_error_t err;
301
302
r->pimpl = malloc(sizeof(struct atf_check_result_impl));
303
if (r->pimpl == NULL)
304
return atf_no_memory_error();
305
306
err = array_to_list(argv, &r->pimpl->m_argv);
307
if (atf_is_error(err))
308
goto out;
309
310
err = atf_fs_path_copy(&r->pimpl->m_dir, dir);
311
if (atf_is_error(err))
312
goto err_argv;
313
314
err = atf_fs_path_init_fmt(&r->pimpl->m_stdout, "%s/stdout",
315
atf_fs_path_cstring(dir));
316
if (atf_is_error(err))
317
goto err_dir;
318
319
err = atf_fs_path_init_fmt(&r->pimpl->m_stderr, "%s/stderr",
320
atf_fs_path_cstring(dir));
321
if (atf_is_error(err))
322
goto err_stdout;
323
324
INV(!atf_is_error(err));
325
goto out;
326
327
err_stdout:
328
atf_fs_path_fini(&r->pimpl->m_stdout);
329
err_dir:
330
atf_fs_path_fini(&r->pimpl->m_dir);
331
err_argv:
332
atf_list_fini(&r->pimpl->m_argv);
333
out:
334
return err;
335
}
336
337
void
338
atf_check_result_fini(atf_check_result_t *r)
339
{
340
atf_process_status_fini(&r->pimpl->m_status);
341
342
cleanup_tmpdir(&r->pimpl->m_dir, &r->pimpl->m_stdout,
343
&r->pimpl->m_stderr);
344
atf_fs_path_fini(&r->pimpl->m_stdout);
345
atf_fs_path_fini(&r->pimpl->m_stderr);
346
atf_fs_path_fini(&r->pimpl->m_dir);
347
348
atf_list_fini(&r->pimpl->m_argv);
349
350
free(r->pimpl);
351
}
352
353
const char *
354
atf_check_result_stdout(const atf_check_result_t *r)
355
{
356
return atf_fs_path_cstring(&r->pimpl->m_stdout);
357
}
358
359
const char *
360
atf_check_result_stderr(const atf_check_result_t *r)
361
{
362
return atf_fs_path_cstring(&r->pimpl->m_stderr);
363
}
364
365
bool
366
atf_check_result_exited(const atf_check_result_t *r)
367
{
368
return atf_process_status_exited(&r->pimpl->m_status);
369
}
370
371
int
372
atf_check_result_exitcode(const atf_check_result_t *r)
373
{
374
return atf_process_status_exitstatus(&r->pimpl->m_status);
375
}
376
377
bool
378
atf_check_result_signaled(const atf_check_result_t *r)
379
{
380
return atf_process_status_signaled(&r->pimpl->m_status);
381
}
382
383
int
384
atf_check_result_termsig(const atf_check_result_t *r)
385
{
386
return atf_process_status_termsig(&r->pimpl->m_status);
387
}
388
389
/* ---------------------------------------------------------------------
390
* Free functions.
391
* --------------------------------------------------------------------- */
392
393
/* XXX: This function shouldn't be in this module. It messes with stdout
394
* and stderr, and it provides a very high-end interface. This belongs,
395
* probably, somewhere related to test cases (such as in the tc module). */
396
atf_error_t
397
atf_check_build_c_o(const char *sfile,
398
const char *ofile,
399
const char *const optargs[],
400
bool *success)
401
{
402
atf_error_t err;
403
char **argv;
404
405
err = atf_build_c_o(sfile, ofile, optargs, &argv);
406
if (atf_is_error(err))
407
goto out;
408
409
err = check_build_run((const char *const *)argv, success);
410
411
atf_utils_free_charpp(argv);
412
out:
413
return err;
414
}
415
416
atf_error_t
417
atf_check_build_cpp(const char *sfile,
418
const char *ofile,
419
const char *const optargs[],
420
bool *success)
421
{
422
atf_error_t err;
423
char **argv;
424
425
err = atf_build_cpp(sfile, ofile, optargs, &argv);
426
if (atf_is_error(err))
427
goto out;
428
429
err = check_build_run((const char *const *)argv, success);
430
431
atf_utils_free_charpp(argv);
432
out:
433
return err;
434
}
435
436
atf_error_t
437
atf_check_build_cxx_o(const char *sfile,
438
const char *ofile,
439
const char *const optargs[],
440
bool *success)
441
{
442
atf_error_t err;
443
char **argv;
444
445
err = atf_build_cxx_o(sfile, ofile, optargs, &argv);
446
if (atf_is_error(err))
447
goto out;
448
449
err = check_build_run((const char *const *)argv, success);
450
451
atf_utils_free_charpp(argv);
452
out:
453
return err;
454
}
455
456
atf_error_t
457
atf_check_exec_array(const char *const *argv, atf_check_result_t *r)
458
{
459
atf_error_t err;
460
atf_fs_path_t dir;
461
462
err = create_tmpdir(&dir);
463
if (atf_is_error(err))
464
goto out;
465
466
err = atf_check_result_init(r, argv, &dir);
467
if (atf_is_error(err)) {
468
atf_error_t err2 = atf_fs_rmdir(&dir);
469
INV(!atf_is_error(err2));
470
goto out;
471
}
472
473
err = fork_and_wait(argv, &r->pimpl->m_stdout, &r->pimpl->m_stderr,
474
&r->pimpl->m_status);
475
if (atf_is_error(err)) {
476
atf_check_result_fini(r);
477
goto out;
478
}
479
480
INV(!atf_is_error(err));
481
482
atf_fs_path_fini(&dir);
483
out:
484
return err;
485
}
486
487