tc.c revision 1.1.1.2 1 1.1 jmmv /*
2 1.1 jmmv * Automated Testing Framework (atf)
3 1.1 jmmv *
4 1.1.1.2 jmmv * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5 1.1 jmmv * All rights reserved.
6 1.1 jmmv *
7 1.1 jmmv * Redistribution and use in source and binary forms, with or without
8 1.1 jmmv * modification, are permitted provided that the following conditions
9 1.1 jmmv * are met:
10 1.1 jmmv * 1. Redistributions of source code must retain the above copyright
11 1.1 jmmv * notice, this list of conditions and the following disclaimer.
12 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jmmv * notice, this list of conditions and the following disclaimer in the
14 1.1 jmmv * documentation and/or other materials provided with the distribution.
15 1.1 jmmv *
16 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 1.1 jmmv * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 1.1 jmmv * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 1.1 jmmv * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 1.1 jmmv * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 1.1 jmmv * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.1 jmmv * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 1.1 jmmv * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 1.1 jmmv * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 1.1 jmmv * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 1.1 jmmv * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 1.1 jmmv */
29 1.1 jmmv
30 1.1 jmmv #include <sys/types.h>
31 1.1 jmmv #include <sys/time.h>
32 1.1 jmmv #include <sys/stat.h>
33 1.1 jmmv #include <sys/wait.h>
34 1.1 jmmv
35 1.1 jmmv #include <errno.h>
36 1.1 jmmv #include <fcntl.h>
37 1.1 jmmv #include <limits.h>
38 1.1 jmmv #include <stdarg.h>
39 1.1 jmmv #include <stdbool.h>
40 1.1 jmmv #include <stdio.h>
41 1.1 jmmv #include <stdlib.h>
42 1.1 jmmv #include <string.h>
43 1.1 jmmv #include <unistd.h>
44 1.1 jmmv
45 1.1 jmmv #include "atf-c/config.h"
46 1.1.1.2 jmmv #include "atf-c/defs.h"
47 1.1 jmmv #include "atf-c/env.h"
48 1.1 jmmv #include "atf-c/error.h"
49 1.1 jmmv #include "atf-c/fs.h"
50 1.1 jmmv #include "atf-c/process.h"
51 1.1 jmmv #include "atf-c/sanity.h"
52 1.1 jmmv #include "atf-c/signals.h"
53 1.1 jmmv #include "atf-c/tc.h"
54 1.1 jmmv #include "atf-c/tcr.h"
55 1.1 jmmv #include "atf-c/text.h"
56 1.1 jmmv #include "atf-c/user.h"
57 1.1 jmmv
58 1.1 jmmv /* ---------------------------------------------------------------------
59 1.1 jmmv * Auxiliary types and functions.
60 1.1 jmmv * --------------------------------------------------------------------- */
61 1.1 jmmv
62 1.1.1.2 jmmv struct child_data {
63 1.1.1.2 jmmv const atf_tc_t *tc;
64 1.1.1.2 jmmv const atf_fs_path_t *workdir;
65 1.1.1.2 jmmv };
66 1.1.1.2 jmmv
67 1.1 jmmv /* Parent-only stuff. */
68 1.1 jmmv struct timeout_data;
69 1.1 jmmv static atf_error_t body_parent(const atf_tc_t *, const atf_fs_path_t *,
70 1.1.1.2 jmmv atf_process_child_t *, atf_tcr_t *);
71 1.1.1.2 jmmv static atf_error_t cleanup_parent(const atf_tc_t *, atf_process_child_t *);
72 1.1.1.2 jmmv static atf_error_t fork_body(const atf_tc_t *, int, int,
73 1.1.1.2 jmmv const atf_fs_path_t *, atf_tcr_t *);
74 1.1.1.2 jmmv static atf_error_t fork_cleanup(const atf_tc_t *, int, int,
75 1.1.1.2 jmmv const atf_fs_path_t *);
76 1.1 jmmv static atf_error_t get_tc_result(const atf_fs_path_t *, atf_tcr_t *);
77 1.1.1.2 jmmv static atf_error_t program_timeout(const atf_process_child_t *,
78 1.1.1.2 jmmv const atf_tc_t *, struct timeout_data *);
79 1.1 jmmv static void unprogram_timeout(struct timeout_data *);
80 1.1 jmmv static void sigalrm_handler(int);
81 1.1 jmmv
82 1.1 jmmv /* Child-only stuff. */
83 1.1.1.2 jmmv static void body_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
84 1.1 jmmv static atf_error_t check_arch(const char *, void *);
85 1.1 jmmv static atf_error_t check_config(const char *, void *);
86 1.1 jmmv static atf_error_t check_machine(const char *, void *);
87 1.1 jmmv static atf_error_t check_prog(const char *, void *);
88 1.1 jmmv static atf_error_t check_prog_in_dir(const char *, void *);
89 1.1 jmmv static atf_error_t check_requirements(const atf_tc_t *);
90 1.1.1.2 jmmv static void cleanup_child(void *) ATF_DEFS_ATTRIBUTE_NORETURN;
91 1.1 jmmv static void fail_internal(const char *, int, const char *, const char *,
92 1.1 jmmv const char *, va_list,
93 1.1.1.2 jmmv void (*)(atf_dynstr_t *),
94 1.1 jmmv void (*)(const char *, ...));
95 1.1 jmmv static void fatal_atf_error(const char *, atf_error_t)
96 1.1 jmmv ATF_DEFS_ATTRIBUTE_NORETURN;
97 1.1 jmmv static void fatal_libc_error(const char *, int)
98 1.1 jmmv ATF_DEFS_ATTRIBUTE_NORETURN;
99 1.1.1.2 jmmv static atf_error_t prepare_child(const struct child_data *);
100 1.1.1.2 jmmv static void tc_fail(atf_dynstr_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
101 1.1.1.2 jmmv static void tc_fail_nonfatal(atf_dynstr_t *);
102 1.1 jmmv static void write_tcr(const atf_tcr_t *);
103 1.1 jmmv
104 1.1 jmmv /* ---------------------------------------------------------------------
105 1.1 jmmv * The "atf_tc" type.
106 1.1 jmmv * --------------------------------------------------------------------- */
107 1.1 jmmv
108 1.1 jmmv /*
109 1.1 jmmv * Constructors/destructors.
110 1.1 jmmv */
111 1.1 jmmv
112 1.1 jmmv atf_error_t
113 1.1 jmmv atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
114 1.1 jmmv atf_tc_body_t body, atf_tc_cleanup_t cleanup,
115 1.1 jmmv const atf_map_t *config)
116 1.1 jmmv {
117 1.1 jmmv atf_error_t err;
118 1.1 jmmv
119 1.1 jmmv atf_object_init(&tc->m_object);
120 1.1 jmmv
121 1.1 jmmv tc->m_ident = ident;
122 1.1 jmmv tc->m_head = head;
123 1.1 jmmv tc->m_body = body;
124 1.1 jmmv tc->m_cleanup = cleanup;
125 1.1 jmmv tc->m_config = config;
126 1.1 jmmv
127 1.1 jmmv err = atf_map_init(&tc->m_vars);
128 1.1 jmmv if (atf_is_error(err))
129 1.1 jmmv goto err_object;
130 1.1 jmmv
131 1.1 jmmv err = atf_tc_set_md_var(tc, "ident", ident);
132 1.1 jmmv if (atf_is_error(err))
133 1.1 jmmv goto err_map;
134 1.1 jmmv
135 1.1 jmmv err = atf_tc_set_md_var(tc, "timeout", "300");
136 1.1 jmmv if (atf_is_error(err))
137 1.1 jmmv goto err_map;
138 1.1 jmmv
139 1.1 jmmv /* XXX Should the head be able to return error codes? */
140 1.1 jmmv tc->m_head(tc);
141 1.1 jmmv
142 1.1 jmmv if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0)
143 1.1 jmmv atf_tc_fail("Test case head modified the read-only 'ident' "
144 1.1 jmmv "property");
145 1.1 jmmv
146 1.1 jmmv INV(!atf_is_error(err));
147 1.1 jmmv return err;
148 1.1 jmmv
149 1.1 jmmv err_map:
150 1.1 jmmv atf_map_fini(&tc->m_vars);
151 1.1 jmmv err_object:
152 1.1 jmmv atf_object_fini(&tc->m_object);
153 1.1 jmmv
154 1.1 jmmv return err;
155 1.1 jmmv }
156 1.1 jmmv
157 1.1 jmmv atf_error_t
158 1.1 jmmv atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
159 1.1 jmmv const atf_map_t *config)
160 1.1 jmmv {
161 1.1 jmmv return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
162 1.1 jmmv pack->m_cleanup, config);
163 1.1 jmmv }
164 1.1 jmmv
165 1.1 jmmv void
166 1.1 jmmv atf_tc_fini(atf_tc_t *tc)
167 1.1 jmmv {
168 1.1 jmmv atf_map_fini(&tc->m_vars);
169 1.1 jmmv
170 1.1 jmmv atf_object_fini(&tc->m_object);
171 1.1 jmmv }
172 1.1 jmmv
173 1.1 jmmv /*
174 1.1 jmmv * Getters.
175 1.1 jmmv */
176 1.1 jmmv
177 1.1 jmmv const char *
178 1.1 jmmv atf_tc_get_ident(const atf_tc_t *tc)
179 1.1 jmmv {
180 1.1 jmmv return tc->m_ident;
181 1.1 jmmv }
182 1.1 jmmv
183 1.1 jmmv const char *
184 1.1 jmmv atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
185 1.1 jmmv {
186 1.1 jmmv const char *val;
187 1.1 jmmv atf_map_citer_t iter;
188 1.1 jmmv
189 1.1 jmmv PRE(atf_tc_has_config_var(tc, name));
190 1.1 jmmv iter = atf_map_find_c(tc->m_config, name);
191 1.1 jmmv val = atf_map_citer_data(iter);
192 1.1 jmmv INV(val != NULL);
193 1.1 jmmv
194 1.1 jmmv return val;
195 1.1 jmmv }
196 1.1 jmmv
197 1.1 jmmv const char *
198 1.1 jmmv atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
199 1.1 jmmv const char *defval)
200 1.1 jmmv {
201 1.1 jmmv const char *val;
202 1.1 jmmv
203 1.1 jmmv if (!atf_tc_has_config_var(tc, name))
204 1.1 jmmv val = defval;
205 1.1 jmmv else
206 1.1 jmmv val = atf_tc_get_config_var(tc, name);
207 1.1 jmmv
208 1.1 jmmv return val;
209 1.1 jmmv }
210 1.1 jmmv
211 1.1 jmmv const char *
212 1.1 jmmv atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
213 1.1 jmmv {
214 1.1 jmmv const char *val;
215 1.1 jmmv atf_map_citer_t iter;
216 1.1 jmmv
217 1.1 jmmv PRE(atf_tc_has_md_var(tc, name));
218 1.1 jmmv iter = atf_map_find_c(&tc->m_vars, name);
219 1.1 jmmv val = atf_map_citer_data(iter);
220 1.1 jmmv INV(val != NULL);
221 1.1 jmmv
222 1.1 jmmv return val;
223 1.1 jmmv }
224 1.1 jmmv
225 1.1 jmmv bool
226 1.1 jmmv atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
227 1.1 jmmv {
228 1.1 jmmv bool found;
229 1.1 jmmv atf_map_citer_t end, iter;
230 1.1 jmmv
231 1.1 jmmv if (tc->m_config == NULL)
232 1.1 jmmv found = false;
233 1.1 jmmv else {
234 1.1 jmmv iter = atf_map_find_c(tc->m_config, name);
235 1.1 jmmv end = atf_map_end_c(tc->m_config);
236 1.1 jmmv found = !atf_equal_map_citer_map_citer(iter, end);
237 1.1 jmmv }
238 1.1 jmmv
239 1.1 jmmv return found;
240 1.1 jmmv }
241 1.1 jmmv
242 1.1 jmmv bool
243 1.1 jmmv atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
244 1.1 jmmv {
245 1.1 jmmv atf_map_citer_t end, iter;
246 1.1 jmmv
247 1.1 jmmv iter = atf_map_find_c(&tc->m_vars, name);
248 1.1 jmmv end = atf_map_end_c(&tc->m_vars);
249 1.1 jmmv return !atf_equal_map_citer_map_citer(iter, end);
250 1.1 jmmv }
251 1.1 jmmv
252 1.1 jmmv /*
253 1.1 jmmv * Modifiers.
254 1.1 jmmv */
255 1.1 jmmv
256 1.1 jmmv atf_error_t
257 1.1 jmmv atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
258 1.1 jmmv {
259 1.1 jmmv atf_error_t err;
260 1.1 jmmv char *value;
261 1.1 jmmv va_list ap;
262 1.1 jmmv
263 1.1 jmmv va_start(ap, fmt);
264 1.1 jmmv err = atf_text_format_ap(&value, fmt, ap);
265 1.1 jmmv va_end(ap);
266 1.1 jmmv
267 1.1 jmmv if (!atf_is_error(err))
268 1.1 jmmv err = atf_map_insert(&tc->m_vars, name, value, true);
269 1.1 jmmv else
270 1.1 jmmv free(value);
271 1.1 jmmv
272 1.1 jmmv return err;
273 1.1 jmmv }
274 1.1 jmmv
275 1.1 jmmv /* ---------------------------------------------------------------------
276 1.1 jmmv * Free functions.
277 1.1 jmmv * --------------------------------------------------------------------- */
278 1.1 jmmv
279 1.1 jmmv atf_error_t
280 1.1.1.2 jmmv atf_tc_run(const atf_tc_t *tc, atf_tcr_t *tcr, int fdout, int fderr,
281 1.1 jmmv const atf_fs_path_t *workdirbase)
282 1.1 jmmv {
283 1.1 jmmv atf_error_t err, cleanuperr;
284 1.1 jmmv atf_fs_path_t workdir;
285 1.1 jmmv
286 1.1 jmmv err = atf_fs_path_copy(&workdir, workdirbase);
287 1.1 jmmv if (atf_is_error(err))
288 1.1 jmmv goto out;
289 1.1 jmmv
290 1.1 jmmv err = atf_fs_path_append_fmt(&workdir, "atf.XXXXXX");
291 1.1 jmmv if (atf_is_error(err))
292 1.1 jmmv goto out_workdir;
293 1.1 jmmv
294 1.1 jmmv err = atf_fs_mkdtemp(&workdir);
295 1.1 jmmv if (atf_is_error(err))
296 1.1 jmmv goto out_workdir;
297 1.1 jmmv
298 1.1.1.2 jmmv err = fork_body(tc, fdout, fderr, &workdir, tcr);
299 1.1.1.2 jmmv cleanuperr = fork_cleanup(tc, fdout, fderr, &workdir);
300 1.1 jmmv if (!atf_is_error(cleanuperr))
301 1.1 jmmv (void)atf_fs_cleanup(&workdir);
302 1.1 jmmv if (!atf_is_error(err))
303 1.1 jmmv err = cleanuperr;
304 1.1 jmmv else if (atf_is_error(cleanuperr))
305 1.1 jmmv atf_error_free(cleanuperr);
306 1.1 jmmv
307 1.1 jmmv out_workdir:
308 1.1 jmmv atf_fs_path_fini(&workdir);
309 1.1 jmmv out:
310 1.1 jmmv return err;
311 1.1 jmmv }
312 1.1 jmmv
313 1.1 jmmv /*
314 1.1 jmmv * Parent-only stuff.
315 1.1 jmmv */
316 1.1 jmmv
317 1.1 jmmv static bool sigalrm_killed = false;
318 1.1 jmmv static pid_t sigalrm_pid = -1;
319 1.1 jmmv
320 1.1 jmmv static
321 1.1 jmmv void
322 1.1 jmmv sigalrm_handler(int signo)
323 1.1 jmmv {
324 1.1 jmmv INV(signo == SIGALRM);
325 1.1 jmmv
326 1.1 jmmv if (sigalrm_pid != -1) {
327 1.1 jmmv killpg(sigalrm_pid, SIGTERM);
328 1.1 jmmv sigalrm_killed = true;
329 1.1 jmmv }
330 1.1 jmmv }
331 1.1 jmmv
332 1.1 jmmv struct timeout_data {
333 1.1 jmmv bool m_programmed;
334 1.1 jmmv atf_signal_programmer_t m_sigalrm;
335 1.1 jmmv };
336 1.1 jmmv
337 1.1 jmmv static
338 1.1 jmmv atf_error_t
339 1.1.1.2 jmmv program_timeout(const atf_process_child_t *child, const atf_tc_t *tc,
340 1.1.1.2 jmmv struct timeout_data *td)
341 1.1 jmmv {
342 1.1 jmmv atf_error_t err;
343 1.1 jmmv long timeout;
344 1.1 jmmv
345 1.1 jmmv err = atf_text_to_long(atf_tc_get_md_var(tc, "timeout"), &timeout);
346 1.1 jmmv if (atf_is_error(err))
347 1.1 jmmv goto out;
348 1.1 jmmv
349 1.1 jmmv if (timeout != 0) {
350 1.1.1.2 jmmv sigalrm_pid = atf_process_child_pid(child);
351 1.1 jmmv sigalrm_killed = false;
352 1.1 jmmv
353 1.1 jmmv err = atf_signal_programmer_init(&td->m_sigalrm, SIGALRM,
354 1.1 jmmv sigalrm_handler);
355 1.1 jmmv if (atf_is_error(err))
356 1.1 jmmv goto out;
357 1.1 jmmv
358 1.1 jmmv struct itimerval itv;
359 1.1 jmmv timerclear(&itv.it_interval);
360 1.1 jmmv timerclear(&itv.it_value);
361 1.1 jmmv itv.it_value.tv_sec = timeout;
362 1.1 jmmv if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
363 1.1 jmmv atf_signal_programmer_fini(&td->m_sigalrm);
364 1.1 jmmv err = atf_libc_error(errno, "Failed to program timeout "
365 1.1 jmmv "with %ld seconds", timeout);
366 1.1 jmmv }
367 1.1 jmmv
368 1.1 jmmv td->m_programmed = !atf_is_error(err);
369 1.1 jmmv } else
370 1.1 jmmv td->m_programmed = false;
371 1.1 jmmv
372 1.1 jmmv out:
373 1.1 jmmv return err;
374 1.1 jmmv }
375 1.1 jmmv
376 1.1 jmmv static
377 1.1 jmmv void
378 1.1 jmmv unprogram_timeout(struct timeout_data *td)
379 1.1 jmmv {
380 1.1 jmmv if (td->m_programmed) {
381 1.1 jmmv atf_signal_programmer_fini(&td->m_sigalrm);
382 1.1 jmmv sigalrm_pid = -1;
383 1.1 jmmv sigalrm_killed = false;
384 1.1 jmmv }
385 1.1 jmmv }
386 1.1 jmmv
387 1.1 jmmv static
388 1.1 jmmv atf_error_t
389 1.1.1.2 jmmv body_parent(const atf_tc_t *tc, const atf_fs_path_t *workdir,
390 1.1.1.2 jmmv atf_process_child_t *child, atf_tcr_t *tcr)
391 1.1 jmmv {
392 1.1 jmmv atf_error_t err;
393 1.1.1.2 jmmv atf_process_status_t status;
394 1.1 jmmv struct timeout_data td;
395 1.1 jmmv
396 1.1.1.2 jmmv err = program_timeout(child, tc, &td);
397 1.1 jmmv if (atf_is_error(err)) {
398 1.1 jmmv char buf[4096];
399 1.1 jmmv
400 1.1 jmmv atf_error_format(err, buf, sizeof(buf));
401 1.1 jmmv fprintf(stderr, "Error programming test case's timeout: %s", buf);
402 1.1 jmmv atf_error_free(err);
403 1.1.1.2 jmmv killpg(atf_process_child_pid(child), SIGKILL);
404 1.1 jmmv }
405 1.1 jmmv
406 1.1.1.2 jmmv again:
407 1.1.1.2 jmmv err = atf_process_child_wait(child, &status);
408 1.1.1.2 jmmv if (atf_is_error(err)) {
409 1.1.1.2 jmmv if (atf_error_is(err, "libc") && atf_libc_error_code(err) == EINTR) {
410 1.1.1.2 jmmv atf_error_free(err);
411 1.1.1.2 jmmv goto again;
412 1.1.1.2 jmmv } else {
413 1.1.1.2 jmmv /* Propagate err */
414 1.1.1.2 jmmv }
415 1.1.1.2 jmmv } else {
416 1.1.1.2 jmmv if (sigalrm_killed)
417 1.1 jmmv err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
418 1.1 jmmv "Test case timed out after %s "
419 1.1 jmmv "seconds",
420 1.1 jmmv atf_tc_get_md_var(tc, "timeout"));
421 1.1.1.2 jmmv else {
422 1.1.1.2 jmmv if (atf_process_status_exited(&status)) {
423 1.1.1.2 jmmv const int exitstatus = atf_process_status_exitstatus(&status);
424 1.1.1.2 jmmv if (exitstatus == EXIT_SUCCESS)
425 1.1.1.2 jmmv err = get_tc_result(workdir, tcr);
426 1.1.1.2 jmmv else
427 1.1.1.2 jmmv err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
428 1.1.1.2 jmmv "Test case exited with "
429 1.1.1.2 jmmv "status %d", exitstatus);
430 1.1.1.2 jmmv } else if (atf_process_status_signaled(&status)) {
431 1.1.1.2 jmmv const int sig = atf_process_status_termsig(&status);
432 1.1.1.2 jmmv const bool wcore = atf_process_status_coredump(&status);
433 1.1.1.2 jmmv err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
434 1.1.1.2 jmmv "Test case was signaled by "
435 1.1.1.2 jmmv "signal %d%s", sig,
436 1.1.1.2 jmmv wcore ? " (core dumped)" : "");
437 1.1.1.2 jmmv } else {
438 1.1.1.2 jmmv err = atf_tcr_init_reason_fmt(tcr, atf_tcr_failed_state,
439 1.1.1.2 jmmv "Test case exited due to an "
440 1.1.1.2 jmmv "unexpected condition");
441 1.1.1.2 jmmv }
442 1.1.1.2 jmmv }
443 1.1.1.2 jmmv
444 1.1.1.2 jmmv atf_process_status_fini(&status);
445 1.1 jmmv }
446 1.1 jmmv
447 1.1 jmmv unprogram_timeout(&td);
448 1.1 jmmv
449 1.1 jmmv return err;
450 1.1 jmmv }
451 1.1 jmmv
452 1.1 jmmv static
453 1.1 jmmv atf_error_t
454 1.1.1.2 jmmv cleanup_parent(const atf_tc_t *tc, atf_process_child_t *child)
455 1.1 jmmv {
456 1.1 jmmv atf_error_t err;
457 1.1.1.2 jmmv atf_process_status_t status;
458 1.1 jmmv
459 1.1.1.2 jmmv err = atf_process_child_wait(child, &status);
460 1.1.1.2 jmmv if (atf_is_error(err))
461 1.1 jmmv goto out;
462 1.1 jmmv
463 1.1.1.2 jmmv if (!atf_process_status_exited(&status) ||
464 1.1.1.2 jmmv atf_process_status_exitstatus(&status) != EXIT_SUCCESS) {
465 1.1 jmmv /* XXX Not really a libc error. */
466 1.1 jmmv err = atf_libc_error(EINVAL, "Child process did not exit cleanly");
467 1.1.1.2 jmmv } else
468 1.1 jmmv err = atf_no_error();
469 1.1 jmmv
470 1.1.1.2 jmmv atf_process_status_fini(&status);
471 1.1 jmmv out:
472 1.1 jmmv return err;
473 1.1 jmmv }
474 1.1 jmmv
475 1.1 jmmv static
476 1.1 jmmv atf_error_t
477 1.1.1.2 jmmv fork_body(const atf_tc_t *tc, int fdout, int fderr,
478 1.1.1.2 jmmv const atf_fs_path_t *workdir, atf_tcr_t *tcr)
479 1.1 jmmv {
480 1.1 jmmv atf_error_t err;
481 1.1.1.2 jmmv atf_process_stream_t outsb, errsb;
482 1.1.1.2 jmmv atf_process_child_t child;
483 1.1.1.2 jmmv struct child_data data = {
484 1.1.1.2 jmmv tc,
485 1.1.1.2 jmmv workdir,
486 1.1.1.2 jmmv };
487 1.1 jmmv
488 1.1.1.2 jmmv err = atf_process_stream_init_redirect_fd(&outsb, fdout);
489 1.1 jmmv if (atf_is_error(err))
490 1.1 jmmv goto out;
491 1.1 jmmv
492 1.1.1.2 jmmv err = atf_process_stream_init_redirect_fd(&errsb, fderr);
493 1.1.1.2 jmmv if (atf_is_error(err))
494 1.1.1.2 jmmv goto out_outsb;
495 1.1.1.2 jmmv
496 1.1.1.2 jmmv err = atf_process_fork(&child, body_child, &outsb, &errsb, &data);
497 1.1.1.2 jmmv if (atf_is_error(err))
498 1.1.1.2 jmmv goto out_errsb;
499 1.1 jmmv
500 1.1.1.2 jmmv err = body_parent(tc, workdir, &child, tcr);
501 1.1.1.2 jmmv
502 1.1.1.2 jmmv out_errsb:
503 1.1.1.2 jmmv atf_process_stream_fini(&errsb);
504 1.1.1.2 jmmv out_outsb:
505 1.1.1.2 jmmv atf_process_stream_fini(&outsb);
506 1.1 jmmv out:
507 1.1 jmmv return err;
508 1.1 jmmv }
509 1.1 jmmv
510 1.1 jmmv static
511 1.1 jmmv atf_error_t
512 1.1.1.2 jmmv fork_cleanup(const atf_tc_t *tc, int fdout, int fderr,
513 1.1.1.2 jmmv const atf_fs_path_t *workdir)
514 1.1 jmmv {
515 1.1 jmmv atf_error_t err;
516 1.1 jmmv
517 1.1 jmmv if (tc->m_cleanup == NULL)
518 1.1 jmmv err = atf_no_error();
519 1.1 jmmv else {
520 1.1.1.2 jmmv atf_process_stream_t outsb, errsb;
521 1.1.1.2 jmmv atf_process_child_t child;
522 1.1.1.2 jmmv struct child_data data = {
523 1.1.1.2 jmmv tc,
524 1.1.1.2 jmmv workdir,
525 1.1.1.2 jmmv };
526 1.1.1.2 jmmv
527 1.1.1.2 jmmv err = atf_process_stream_init_redirect_fd(&outsb, fdout);
528 1.1 jmmv if (atf_is_error(err))
529 1.1 jmmv goto out;
530 1.1 jmmv
531 1.1.1.2 jmmv err = atf_process_stream_init_redirect_fd(&errsb, fderr);
532 1.1.1.2 jmmv if (atf_is_error(err))
533 1.1.1.2 jmmv goto out_outsb;
534 1.1.1.2 jmmv
535 1.1.1.2 jmmv err = atf_process_fork(&child, cleanup_child, &outsb, &errsb, &data);
536 1.1.1.2 jmmv if (atf_is_error(err))
537 1.1.1.2 jmmv goto out_errsb;
538 1.1.1.2 jmmv
539 1.1.1.2 jmmv err = cleanup_parent(tc, &child);
540 1.1.1.2 jmmv
541 1.1.1.2 jmmv out_errsb:
542 1.1.1.2 jmmv atf_process_stream_fini(&errsb);
543 1.1.1.2 jmmv out_outsb:
544 1.1.1.2 jmmv atf_process_stream_fini(&outsb);
545 1.1 jmmv }
546 1.1 jmmv
547 1.1 jmmv out:
548 1.1 jmmv return err;
549 1.1 jmmv }
550 1.1 jmmv
551 1.1 jmmv static
552 1.1 jmmv atf_error_t
553 1.1 jmmv get_tc_result(const atf_fs_path_t *workdir, atf_tcr_t *tcr)
554 1.1 jmmv {
555 1.1 jmmv atf_error_t err;
556 1.1 jmmv int fd;
557 1.1 jmmv atf_fs_path_t tcrfile;
558 1.1 jmmv
559 1.1 jmmv err = atf_fs_path_copy(&tcrfile, workdir);
560 1.1 jmmv if (atf_is_error(err))
561 1.1 jmmv goto out;
562 1.1 jmmv
563 1.1 jmmv err = atf_fs_path_append_fmt(&tcrfile, "tc-result");
564 1.1 jmmv if (atf_is_error(err))
565 1.1 jmmv goto out_tcrfile;
566 1.1 jmmv
567 1.1 jmmv fd = open(atf_fs_path_cstring(&tcrfile), O_RDONLY);
568 1.1 jmmv if (fd == -1) {
569 1.1 jmmv err = atf_libc_error(errno, "Cannot retrieve test case result");
570 1.1 jmmv goto out_tcrfile;
571 1.1 jmmv }
572 1.1 jmmv
573 1.1 jmmv err = atf_tcr_deserialize(tcr, fd);
574 1.1 jmmv
575 1.1 jmmv close(fd);
576 1.1 jmmv out_tcrfile:
577 1.1 jmmv atf_fs_path_fini(&tcrfile);
578 1.1 jmmv out:
579 1.1 jmmv return err;
580 1.1 jmmv }
581 1.1 jmmv
582 1.1 jmmv /*
583 1.1 jmmv * Child-only stuff.
584 1.1 jmmv */
585 1.1 jmmv
586 1.1 jmmv static const atf_tc_t *current_tc = NULL;
587 1.1 jmmv static const atf_fs_path_t *current_workdir = NULL;
588 1.1 jmmv static size_t current_tc_fail_count = 0;
589 1.1 jmmv
590 1.1 jmmv static
591 1.1 jmmv atf_error_t
592 1.1.1.2 jmmv prepare_child(const struct child_data *cd)
593 1.1 jmmv {
594 1.1 jmmv atf_error_t err;
595 1.1 jmmv int i, ret;
596 1.1 jmmv
597 1.1.1.2 jmmv current_tc = cd->tc;
598 1.1.1.2 jmmv current_workdir = cd->workdir;
599 1.1 jmmv current_tc_fail_count = 0;
600 1.1 jmmv
601 1.1 jmmv ret = setpgid(getpid(), 0);
602 1.1 jmmv INV(ret != -1);
603 1.1 jmmv
604 1.1 jmmv umask(S_IWGRP | S_IWOTH);
605 1.1 jmmv
606 1.1 jmmv for (i = 1; i <= atf_signals_last_signo; i++)
607 1.1 jmmv atf_signal_reset(i);
608 1.1 jmmv
609 1.1.1.2 jmmv err = atf_env_set("HOME", atf_fs_path_cstring(cd->workdir));
610 1.1 jmmv if (atf_is_error(err))
611 1.1 jmmv goto out;
612 1.1 jmmv
613 1.1 jmmv err = atf_env_unset("LANG");
614 1.1 jmmv if (atf_is_error(err))
615 1.1 jmmv goto out;
616 1.1 jmmv
617 1.1 jmmv err = atf_env_unset("LC_ALL");
618 1.1 jmmv if (atf_is_error(err))
619 1.1 jmmv goto out;
620 1.1 jmmv
621 1.1 jmmv err = atf_env_unset("LC_COLLATE");
622 1.1 jmmv if (atf_is_error(err))
623 1.1 jmmv goto out;
624 1.1 jmmv
625 1.1 jmmv err = atf_env_unset("LC_CTYPE");
626 1.1 jmmv if (atf_is_error(err))
627 1.1 jmmv goto out;
628 1.1 jmmv
629 1.1 jmmv err = atf_env_unset("LC_MESSAGES");
630 1.1 jmmv if (atf_is_error(err))
631 1.1 jmmv goto out;
632 1.1 jmmv
633 1.1 jmmv err = atf_env_unset("LC_MONETARY");
634 1.1 jmmv if (atf_is_error(err))
635 1.1 jmmv goto out;
636 1.1 jmmv
637 1.1 jmmv err = atf_env_unset("LC_NUMERIC");
638 1.1 jmmv if (atf_is_error(err))
639 1.1 jmmv goto out;
640 1.1 jmmv
641 1.1 jmmv err = atf_env_unset("LC_TIME");
642 1.1 jmmv if (atf_is_error(err))
643 1.1 jmmv goto out;
644 1.1 jmmv
645 1.1 jmmv err = atf_env_unset("TZ");
646 1.1 jmmv if (atf_is_error(err))
647 1.1 jmmv goto out;
648 1.1 jmmv
649 1.1.1.2 jmmv if (chdir(atf_fs_path_cstring(cd->workdir)) == -1) {
650 1.1 jmmv err = atf_libc_error(errno, "Cannot enter work directory '%s'",
651 1.1.1.2 jmmv atf_fs_path_cstring(cd->workdir));
652 1.1 jmmv goto out;
653 1.1 jmmv }
654 1.1 jmmv
655 1.1 jmmv err = atf_no_error();
656 1.1 jmmv
657 1.1 jmmv out:
658 1.1 jmmv return err;
659 1.1 jmmv }
660 1.1 jmmv
661 1.1 jmmv static
662 1.1 jmmv void
663 1.1.1.2 jmmv body_child(void *v)
664 1.1 jmmv {
665 1.1.1.2 jmmv const struct child_data *cd = v;
666 1.1 jmmv atf_error_t err;
667 1.1 jmmv
668 1.1.1.2 jmmv atf_reset_exit_checks();
669 1.1 jmmv
670 1.1.1.2 jmmv err = prepare_child(cd);
671 1.1 jmmv if (atf_is_error(err))
672 1.1 jmmv goto print_err;
673 1.1.1.2 jmmv err = check_requirements(cd->tc);
674 1.1 jmmv if (atf_is_error(err))
675 1.1 jmmv goto print_err;
676 1.1.1.2 jmmv
677 1.1.1.2 jmmv cd->tc->m_body(cd->tc);
678 1.1 jmmv
679 1.1 jmmv if (current_tc_fail_count == 0)
680 1.1 jmmv atf_tc_pass();
681 1.1 jmmv else
682 1.1 jmmv atf_tc_fail("%d checks failed; see output for more details",
683 1.1 jmmv current_tc_fail_count);
684 1.1 jmmv
685 1.1 jmmv UNREACHABLE;
686 1.1 jmmv
687 1.1 jmmv print_err:
688 1.1 jmmv INV(atf_is_error(err));
689 1.1 jmmv {
690 1.1 jmmv char buf[4096];
691 1.1 jmmv
692 1.1 jmmv atf_error_format(err, buf, sizeof(buf));
693 1.1 jmmv atf_error_free(err);
694 1.1 jmmv
695 1.1 jmmv atf_tc_fail("Error while preparing child process: %s", buf);
696 1.1 jmmv }
697 1.1 jmmv
698 1.1 jmmv UNREACHABLE;
699 1.1 jmmv }
700 1.1 jmmv
701 1.1 jmmv static
702 1.1 jmmv atf_error_t
703 1.1 jmmv check_arch(const char *arch, void *data)
704 1.1 jmmv {
705 1.1 jmmv bool *found = data;
706 1.1 jmmv
707 1.1 jmmv if (strcmp(arch, atf_config_get("atf_arch")) == 0)
708 1.1 jmmv *found = true;
709 1.1 jmmv
710 1.1 jmmv return atf_no_error();
711 1.1 jmmv }
712 1.1 jmmv
713 1.1 jmmv static
714 1.1 jmmv atf_error_t
715 1.1 jmmv check_config(const char *var, void *data)
716 1.1 jmmv {
717 1.1 jmmv if (!atf_tc_has_config_var(current_tc, var))
718 1.1 jmmv atf_tc_skip("Required configuration variable %s not defined", var);
719 1.1 jmmv
720 1.1 jmmv return atf_no_error();
721 1.1 jmmv }
722 1.1 jmmv
723 1.1 jmmv static
724 1.1 jmmv atf_error_t
725 1.1 jmmv check_machine(const char *machine, void *data)
726 1.1 jmmv {
727 1.1 jmmv bool *found = data;
728 1.1 jmmv
729 1.1 jmmv if (strcmp(machine, atf_config_get("atf_machine")) == 0)
730 1.1 jmmv *found = true;
731 1.1 jmmv
732 1.1 jmmv return atf_no_error();
733 1.1 jmmv }
734 1.1 jmmv
735 1.1 jmmv struct prog_found_pair {
736 1.1 jmmv const char *prog;
737 1.1 jmmv bool found;
738 1.1 jmmv };
739 1.1 jmmv
740 1.1 jmmv static
741 1.1 jmmv atf_error_t
742 1.1 jmmv check_prog(const char *prog, void *data)
743 1.1 jmmv {
744 1.1 jmmv atf_error_t err;
745 1.1 jmmv atf_fs_path_t p;
746 1.1 jmmv
747 1.1 jmmv err = atf_fs_path_init_fmt(&p, "%s", prog);
748 1.1 jmmv if (atf_is_error(err))
749 1.1 jmmv goto out;
750 1.1 jmmv
751 1.1 jmmv if (atf_fs_path_is_absolute(&p)) {
752 1.1.1.2 jmmv err = atf_fs_eaccess(&p, atf_fs_access_x);
753 1.1.1.2 jmmv if (atf_is_error(err)) {
754 1.1.1.2 jmmv atf_error_free(err);
755 1.1.1.2 jmmv atf_fs_path_fini(&p);
756 1.1 jmmv atf_tc_skip("The required program %s could not be found", prog);
757 1.1.1.2 jmmv }
758 1.1 jmmv } else {
759 1.1 jmmv const char *path = atf_env_get("PATH");
760 1.1 jmmv struct prog_found_pair pf;
761 1.1 jmmv atf_fs_path_t bp;
762 1.1 jmmv
763 1.1 jmmv err = atf_fs_path_branch_path(&p, &bp);
764 1.1 jmmv if (atf_is_error(err))
765 1.1 jmmv goto out_p;
766 1.1 jmmv
767 1.1.1.2 jmmv if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
768 1.1.1.2 jmmv atf_fs_path_fini(&bp);
769 1.1.1.2 jmmv atf_fs_path_fini(&p);
770 1.1 jmmv atf_tc_fail("Relative paths are not allowed when searching for "
771 1.1 jmmv "a program (%s)", prog);
772 1.1.1.2 jmmv }
773 1.1 jmmv
774 1.1 jmmv pf.prog = prog;
775 1.1 jmmv pf.found = false;
776 1.1 jmmv err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
777 1.1 jmmv if (atf_is_error(err))
778 1.1 jmmv goto out_bp;
779 1.1 jmmv
780 1.1.1.2 jmmv if (!pf.found) {
781 1.1.1.2 jmmv atf_fs_path_fini(&bp);
782 1.1.1.2 jmmv atf_fs_path_fini(&p);
783 1.1 jmmv atf_tc_skip("The required program %s could not be found in "
784 1.1 jmmv "the PATH", prog);
785 1.1.1.2 jmmv }
786 1.1 jmmv
787 1.1 jmmv out_bp:
788 1.1 jmmv atf_fs_path_fini(&bp);
789 1.1 jmmv }
790 1.1 jmmv
791 1.1 jmmv out_p:
792 1.1 jmmv atf_fs_path_fini(&p);
793 1.1 jmmv out:
794 1.1 jmmv return err;
795 1.1 jmmv }
796 1.1 jmmv
797 1.1 jmmv static
798 1.1 jmmv atf_error_t
799 1.1 jmmv check_prog_in_dir(const char *dir, void *data)
800 1.1 jmmv {
801 1.1 jmmv struct prog_found_pair *pf = data;
802 1.1 jmmv atf_error_t err;
803 1.1 jmmv
804 1.1 jmmv if (pf->found)
805 1.1 jmmv err = atf_no_error();
806 1.1 jmmv else {
807 1.1 jmmv atf_fs_path_t p;
808 1.1 jmmv
809 1.1 jmmv err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
810 1.1 jmmv if (atf_is_error(err))
811 1.1 jmmv goto out_p;
812 1.1 jmmv
813 1.1.1.2 jmmv err = atf_fs_eaccess(&p, atf_fs_access_x);
814 1.1.1.2 jmmv if (!atf_is_error(err))
815 1.1 jmmv pf->found = true;
816 1.1.1.2 jmmv else {
817 1.1.1.2 jmmv atf_error_free(err);
818 1.1.1.2 jmmv INV(!pf->found);
819 1.1.1.2 jmmv err = atf_no_error();
820 1.1.1.2 jmmv }
821 1.1 jmmv
822 1.1 jmmv out_p:
823 1.1 jmmv atf_fs_path_fini(&p);
824 1.1 jmmv }
825 1.1 jmmv
826 1.1 jmmv return err;
827 1.1 jmmv }
828 1.1 jmmv
829 1.1 jmmv static
830 1.1 jmmv atf_error_t
831 1.1 jmmv check_requirements(const atf_tc_t *tc)
832 1.1 jmmv {
833 1.1 jmmv atf_error_t err;
834 1.1 jmmv
835 1.1 jmmv err = atf_no_error();
836 1.1 jmmv
837 1.1 jmmv if (atf_tc_has_md_var(tc, "require.arch")) {
838 1.1 jmmv const char *arches = atf_tc_get_md_var(tc, "require.arch");
839 1.1 jmmv bool found = false;
840 1.1 jmmv
841 1.1 jmmv if (strlen(arches) == 0)
842 1.1 jmmv atf_tc_fail("Invalid value in the require.arch property");
843 1.1 jmmv else {
844 1.1 jmmv err = atf_text_for_each_word(arches, " ", check_arch, &found);
845 1.1 jmmv if (atf_is_error(err))
846 1.1 jmmv goto out;
847 1.1 jmmv
848 1.1 jmmv if (!found)
849 1.1 jmmv atf_tc_skip("Requires one of the '%s' architectures",
850 1.1 jmmv arches);
851 1.1 jmmv }
852 1.1 jmmv }
853 1.1 jmmv
854 1.1 jmmv if (atf_tc_has_md_var(tc, "require.config")) {
855 1.1 jmmv const char *vars = atf_tc_get_md_var(tc, "require.config");
856 1.1 jmmv
857 1.1 jmmv if (strlen(vars) == 0)
858 1.1 jmmv atf_tc_fail("Invalid value in the require.config property");
859 1.1 jmmv else {
860 1.1 jmmv err = atf_text_for_each_word(vars, " ", check_config, NULL);
861 1.1 jmmv if (atf_is_error(err))
862 1.1 jmmv goto out;
863 1.1 jmmv }
864 1.1 jmmv }
865 1.1 jmmv
866 1.1 jmmv if (atf_tc_has_md_var(tc, "require.machine")) {
867 1.1 jmmv const char *machines = atf_tc_get_md_var(tc, "require.machine");
868 1.1 jmmv bool found = false;
869 1.1 jmmv
870 1.1 jmmv if (strlen(machines) == 0)
871 1.1 jmmv atf_tc_fail("Invalid value in the require.machine property");
872 1.1 jmmv else {
873 1.1 jmmv err = atf_text_for_each_word(machines, " ", check_machine,
874 1.1 jmmv &found);
875 1.1 jmmv if (atf_is_error(err))
876 1.1 jmmv goto out;
877 1.1 jmmv
878 1.1 jmmv if (!found)
879 1.1 jmmv atf_tc_skip("Requires one of the '%s' machine types",
880 1.1 jmmv machines);
881 1.1 jmmv }
882 1.1 jmmv }
883 1.1 jmmv
884 1.1 jmmv if (atf_tc_has_md_var(tc, "require.progs")) {
885 1.1 jmmv const char *progs = atf_tc_get_md_var(tc, "require.progs");
886 1.1 jmmv
887 1.1 jmmv if (strlen(progs) == 0)
888 1.1 jmmv atf_tc_fail("Invalid value in the require.progs property");
889 1.1 jmmv else {
890 1.1 jmmv err = atf_text_for_each_word(progs, " ", check_prog, NULL);
891 1.1 jmmv if (atf_is_error(err))
892 1.1 jmmv goto out;
893 1.1 jmmv }
894 1.1 jmmv }
895 1.1 jmmv
896 1.1 jmmv if (atf_tc_has_md_var(tc, "require.user")) {
897 1.1 jmmv const char *u = atf_tc_get_md_var(tc, "require.user");
898 1.1 jmmv
899 1.1 jmmv if (strcmp(u, "root") == 0) {
900 1.1 jmmv if (!atf_user_is_root())
901 1.1 jmmv atf_tc_skip("Requires root privileges");
902 1.1 jmmv } else if (strcmp(u, "unprivileged") == 0) {
903 1.1 jmmv if (atf_user_is_root())
904 1.1 jmmv atf_tc_skip("Requires an unprivileged user");
905 1.1 jmmv } else
906 1.1 jmmv atf_tc_fail("Invalid value in the require.user property");
907 1.1 jmmv }
908 1.1 jmmv
909 1.1 jmmv INV(!atf_is_error(err));
910 1.1 jmmv out:
911 1.1 jmmv return err;
912 1.1 jmmv }
913 1.1 jmmv
914 1.1 jmmv static
915 1.1 jmmv void
916 1.1.1.2 jmmv cleanup_child(void *v)
917 1.1 jmmv {
918 1.1.1.2 jmmv const struct child_data *cd = v;
919 1.1 jmmv atf_error_t err;
920 1.1 jmmv
921 1.1.1.2 jmmv err = prepare_child(cd);
922 1.1.1.2 jmmv if (atf_is_error(err)) {
923 1.1.1.2 jmmv atf_reset_exit_checks();
924 1.1 jmmv exit(EXIT_FAILURE);
925 1.1.1.2 jmmv } else {
926 1.1.1.2 jmmv atf_reset_exit_checks();
927 1.1.1.2 jmmv cd->tc->m_cleanup(cd->tc);
928 1.1 jmmv exit(EXIT_SUCCESS);
929 1.1 jmmv }
930 1.1 jmmv
931 1.1 jmmv UNREACHABLE;
932 1.1 jmmv }
933 1.1 jmmv
934 1.1 jmmv static
935 1.1 jmmv void
936 1.1 jmmv fatal_atf_error(const char *prefix, atf_error_t err)
937 1.1 jmmv {
938 1.1 jmmv char buf[1024];
939 1.1 jmmv
940 1.1 jmmv INV(atf_is_error(err));
941 1.1 jmmv
942 1.1 jmmv atf_error_format(err, buf, sizeof(buf));
943 1.1 jmmv atf_error_free(err);
944 1.1 jmmv
945 1.1 jmmv fprintf(stderr, "%s: %s", prefix, buf);
946 1.1 jmmv
947 1.1 jmmv abort();
948 1.1 jmmv }
949 1.1 jmmv
950 1.1 jmmv static
951 1.1 jmmv void
952 1.1 jmmv fatal_libc_error(const char *prefix, int err)
953 1.1 jmmv {
954 1.1 jmmv fprintf(stderr, "%s: %s", prefix, strerror(err));
955 1.1 jmmv
956 1.1 jmmv abort();
957 1.1 jmmv }
958 1.1 jmmv
959 1.1 jmmv static
960 1.1 jmmv void
961 1.1 jmmv write_tcr(const atf_tcr_t *tcr)
962 1.1 jmmv {
963 1.1 jmmv atf_error_t err;
964 1.1 jmmv int fd;
965 1.1 jmmv atf_fs_path_t tcrfile;
966 1.1 jmmv
967 1.1 jmmv err = atf_fs_path_copy(&tcrfile, current_workdir);
968 1.1 jmmv if (atf_is_error(err))
969 1.1 jmmv fatal_atf_error("Cannot write test case results", err);
970 1.1 jmmv
971 1.1 jmmv err = atf_fs_path_append_fmt(&tcrfile, "tc-result");
972 1.1 jmmv if (atf_is_error(err))
973 1.1 jmmv fatal_atf_error("Cannot write test case results", err);
974 1.1 jmmv
975 1.1 jmmv fd = open(atf_fs_path_cstring(&tcrfile),
976 1.1 jmmv O_WRONLY | O_CREAT | O_TRUNC, 0755);
977 1.1 jmmv if (fd == -1)
978 1.1 jmmv fatal_libc_error("Cannot write test case results", errno);
979 1.1 jmmv
980 1.1 jmmv err = atf_tcr_serialize(tcr, fd);
981 1.1 jmmv if (atf_is_error(err))
982 1.1 jmmv fatal_atf_error("Cannot write test case results", err);
983 1.1 jmmv
984 1.1 jmmv close(fd);
985 1.1.1.2 jmmv atf_fs_path_fini(&tcrfile);
986 1.1.1.2 jmmv }
987 1.1.1.2 jmmv
988 1.1.1.2 jmmv static
989 1.1.1.2 jmmv void
990 1.1.1.2 jmmv tc_fail(atf_dynstr_t *msg)
991 1.1.1.2 jmmv {
992 1.1.1.2 jmmv atf_tcr_t tcr;
993 1.1.1.2 jmmv atf_error_t err;
994 1.1.1.2 jmmv
995 1.1.1.2 jmmv PRE(current_tc != NULL);
996 1.1.1.2 jmmv
997 1.1.1.2 jmmv err = atf_tcr_init_reason_fmt(&tcr, atf_tcr_failed_state, "%s",
998 1.1.1.2 jmmv atf_dynstr_cstring(msg));
999 1.1.1.2 jmmv if (atf_is_error(err))
1000 1.1.1.2 jmmv abort();
1001 1.1.1.2 jmmv
1002 1.1.1.2 jmmv write_tcr(&tcr);
1003 1.1.1.2 jmmv
1004 1.1.1.2 jmmv atf_tcr_fini(&tcr);
1005 1.1.1.2 jmmv atf_dynstr_fini(msg);
1006 1.1.1.2 jmmv
1007 1.1.1.2 jmmv exit(EXIT_SUCCESS);
1008 1.1.1.2 jmmv }
1009 1.1.1.2 jmmv
1010 1.1.1.2 jmmv static
1011 1.1.1.2 jmmv void
1012 1.1.1.2 jmmv tc_fail_nonfatal(atf_dynstr_t *msg)
1013 1.1.1.2 jmmv {
1014 1.1.1.2 jmmv fprintf(stderr, "%s\n", atf_dynstr_cstring(msg));
1015 1.1.1.2 jmmv atf_dynstr_fini(msg);
1016 1.1.1.2 jmmv
1017 1.1.1.2 jmmv current_tc_fail_count++;
1018 1.1 jmmv }
1019 1.1 jmmv
1020 1.1 jmmv void
1021 1.1 jmmv atf_tc_fail(const char *fmt, ...)
1022 1.1 jmmv {
1023 1.1 jmmv va_list ap;
1024 1.1 jmmv atf_tcr_t tcr;
1025 1.1 jmmv atf_error_t err;
1026 1.1 jmmv
1027 1.1 jmmv PRE(current_tc != NULL);
1028 1.1 jmmv
1029 1.1 jmmv va_start(ap, fmt);
1030 1.1 jmmv err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap);
1031 1.1 jmmv va_end(ap);
1032 1.1 jmmv if (atf_is_error(err))
1033 1.1 jmmv abort();
1034 1.1 jmmv
1035 1.1 jmmv write_tcr(&tcr);
1036 1.1 jmmv
1037 1.1 jmmv atf_tcr_fini(&tcr);
1038 1.1 jmmv
1039 1.1 jmmv exit(EXIT_SUCCESS);
1040 1.1 jmmv }
1041 1.1 jmmv
1042 1.1 jmmv void
1043 1.1 jmmv atf_tc_fail_nonfatal(const char *fmt, ...)
1044 1.1 jmmv {
1045 1.1 jmmv va_list ap;
1046 1.1 jmmv
1047 1.1 jmmv va_start(ap, fmt);
1048 1.1 jmmv vfprintf(stderr, fmt, ap);
1049 1.1 jmmv va_end(ap);
1050 1.1 jmmv fprintf(stderr, "\n");
1051 1.1 jmmv
1052 1.1 jmmv current_tc_fail_count++;
1053 1.1 jmmv }
1054 1.1 jmmv
1055 1.1 jmmv void
1056 1.1 jmmv atf_tc_fail_check(const char *file, int line, const char *fmt, ...)
1057 1.1 jmmv {
1058 1.1 jmmv va_list ap;
1059 1.1 jmmv
1060 1.1 jmmv va_start(ap, fmt);
1061 1.1 jmmv fail_internal(file, line, "Check failed", "*** ", fmt, ap,
1062 1.1.1.2 jmmv tc_fail_nonfatal, atf_tc_fail_nonfatal);
1063 1.1 jmmv va_end(ap);
1064 1.1 jmmv }
1065 1.1 jmmv
1066 1.1 jmmv void
1067 1.1 jmmv atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...)
1068 1.1 jmmv {
1069 1.1 jmmv va_list ap;
1070 1.1 jmmv
1071 1.1.1.2 jmmv atf_reset_exit_checks();
1072 1.1.1.2 jmmv
1073 1.1 jmmv va_start(ap, fmt);
1074 1.1 jmmv fail_internal(file, line, "Requirement failed", "", fmt, ap,
1075 1.1.1.2 jmmv tc_fail, atf_tc_fail);
1076 1.1 jmmv va_end(ap);
1077 1.1 jmmv
1078 1.1 jmmv UNREACHABLE;
1079 1.1 jmmv abort();
1080 1.1 jmmv }
1081 1.1 jmmv
1082 1.1 jmmv static
1083 1.1 jmmv void
1084 1.1 jmmv fail_internal(const char *file, int line, const char *reason,
1085 1.1 jmmv const char *prefix, const char *fmt, va_list ap,
1086 1.1.1.2 jmmv void (*failfunc)(atf_dynstr_t *),
1087 1.1.1.2 jmmv void (*backupfunc)(const char *, ...))
1088 1.1 jmmv {
1089 1.1 jmmv va_list ap2;
1090 1.1 jmmv atf_error_t err;
1091 1.1 jmmv atf_dynstr_t msg;
1092 1.1 jmmv
1093 1.1 jmmv err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line,
1094 1.1 jmmv reason);
1095 1.1 jmmv if (atf_is_error(err))
1096 1.1 jmmv goto backup;
1097 1.1 jmmv
1098 1.1 jmmv va_copy(ap2, ap);
1099 1.1 jmmv err = atf_dynstr_append_ap(&msg, fmt, ap2);
1100 1.1 jmmv va_end(ap2);
1101 1.1 jmmv if (atf_is_error(err)) {
1102 1.1 jmmv atf_dynstr_fini(&msg);
1103 1.1 jmmv goto backup;
1104 1.1 jmmv }
1105 1.1 jmmv
1106 1.1 jmmv va_copy(ap2, ap);
1107 1.1.1.2 jmmv failfunc(&msg);
1108 1.1 jmmv return;
1109 1.1 jmmv
1110 1.1 jmmv backup:
1111 1.1.1.2 jmmv atf_error_free(err);
1112 1.1 jmmv va_copy(ap2, ap);
1113 1.1.1.2 jmmv backupfunc(fmt, ap2);
1114 1.1 jmmv va_end(ap2);
1115 1.1 jmmv }
1116 1.1 jmmv
1117 1.1 jmmv void
1118 1.1 jmmv atf_tc_pass(void)
1119 1.1 jmmv {
1120 1.1 jmmv atf_tcr_t tcr;
1121 1.1 jmmv atf_error_t err;
1122 1.1 jmmv
1123 1.1 jmmv PRE(current_tc != NULL);
1124 1.1 jmmv
1125 1.1 jmmv err = atf_tcr_init(&tcr, atf_tcr_passed_state);
1126 1.1 jmmv if (atf_is_error(err))
1127 1.1 jmmv abort();
1128 1.1 jmmv
1129 1.1 jmmv write_tcr(&tcr);
1130 1.1 jmmv
1131 1.1 jmmv atf_tcr_fini(&tcr);
1132 1.1 jmmv
1133 1.1 jmmv exit(EXIT_SUCCESS);
1134 1.1 jmmv }
1135 1.1 jmmv
1136 1.1 jmmv void
1137 1.1 jmmv atf_tc_require_prog(const char *prog)
1138 1.1 jmmv {
1139 1.1 jmmv atf_error_t err;
1140 1.1 jmmv
1141 1.1 jmmv err = check_prog(prog, NULL);
1142 1.1.1.2 jmmv if (atf_is_error(err)) {
1143 1.1.1.2 jmmv atf_error_free(err);
1144 1.1 jmmv atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */
1145 1.1.1.2 jmmv }
1146 1.1 jmmv }
1147 1.1 jmmv
1148 1.1 jmmv void
1149 1.1 jmmv atf_tc_skip(const char *fmt, ...)
1150 1.1 jmmv {
1151 1.1 jmmv va_list ap;
1152 1.1 jmmv atf_tcr_t tcr;
1153 1.1 jmmv atf_error_t err;
1154 1.1 jmmv
1155 1.1 jmmv PRE(current_tc != NULL);
1156 1.1 jmmv
1157 1.1 jmmv va_start(ap, fmt);
1158 1.1 jmmv err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap);
1159 1.1 jmmv va_end(ap);
1160 1.1 jmmv if (atf_is_error(err))
1161 1.1 jmmv abort();
1162 1.1 jmmv
1163 1.1 jmmv write_tcr(&tcr);
1164 1.1 jmmv
1165 1.1 jmmv atf_tcr_fini(&tcr);
1166 1.1 jmmv
1167 1.1 jmmv exit(EXIT_SUCCESS);
1168 1.1 jmmv }
1169