tc.c revision 1.5 1 1.1 jmmv /*
2 1.1 jmmv * Automated Testing Framework (atf)
3 1.1 jmmv *
4 1.4 jmmv * Copyright (c) 2008, 2009, 2010 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.3 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/tc.h"
53 1.1 jmmv #include "atf-c/tcr.h"
54 1.1 jmmv #include "atf-c/text.h"
55 1.1 jmmv #include "atf-c/user.h"
56 1.1 jmmv
57 1.1 jmmv /* ---------------------------------------------------------------------
58 1.1 jmmv * Auxiliary types and functions.
59 1.1 jmmv * --------------------------------------------------------------------- */
60 1.1 jmmv
61 1.1 jmmv static atf_error_t check_prog(const char *, void *);
62 1.1 jmmv static atf_error_t check_prog_in_dir(const char *, void *);
63 1.1 jmmv static void fail_internal(const char *, int, const char *, const char *,
64 1.1 jmmv const char *, va_list,
65 1.3 jmmv void (*)(atf_dynstr_t *),
66 1.1 jmmv void (*)(const char *, ...));
67 1.3 jmmv static void tc_fail(atf_dynstr_t *) ATF_DEFS_ATTRIBUTE_NORETURN;
68 1.3 jmmv static void tc_fail_nonfatal(atf_dynstr_t *);
69 1.1 jmmv
70 1.1 jmmv /* ---------------------------------------------------------------------
71 1.1 jmmv * The "atf_tc" type.
72 1.1 jmmv * --------------------------------------------------------------------- */
73 1.1 jmmv
74 1.1 jmmv /*
75 1.1 jmmv * Constructors/destructors.
76 1.1 jmmv */
77 1.1 jmmv
78 1.1 jmmv atf_error_t
79 1.1 jmmv atf_tc_init(atf_tc_t *tc, const char *ident, atf_tc_head_t head,
80 1.1 jmmv atf_tc_body_t body, atf_tc_cleanup_t cleanup,
81 1.1 jmmv const atf_map_t *config)
82 1.1 jmmv {
83 1.1 jmmv atf_error_t err;
84 1.1 jmmv
85 1.1 jmmv tc->m_ident = ident;
86 1.1 jmmv tc->m_head = head;
87 1.1 jmmv tc->m_body = body;
88 1.1 jmmv tc->m_cleanup = cleanup;
89 1.1 jmmv tc->m_config = config;
90 1.1 jmmv
91 1.1 jmmv err = atf_map_init(&tc->m_vars);
92 1.1 jmmv if (atf_is_error(err))
93 1.5 jmmv goto err;
94 1.1 jmmv
95 1.1 jmmv err = atf_tc_set_md_var(tc, "ident", ident);
96 1.1 jmmv if (atf_is_error(err))
97 1.1 jmmv goto err_map;
98 1.1 jmmv
99 1.1 jmmv /* XXX Should the head be able to return error codes? */
100 1.5 jmmv if (tc->m_head != NULL)
101 1.5 jmmv tc->m_head(tc);
102 1.1 jmmv
103 1.1 jmmv if (strcmp(atf_tc_get_md_var(tc, "ident"), ident) != 0)
104 1.1 jmmv atf_tc_fail("Test case head modified the read-only 'ident' "
105 1.1 jmmv "property");
106 1.1 jmmv
107 1.1 jmmv INV(!atf_is_error(err));
108 1.1 jmmv return err;
109 1.1 jmmv
110 1.1 jmmv err_map:
111 1.1 jmmv atf_map_fini(&tc->m_vars);
112 1.5 jmmv err:
113 1.1 jmmv return err;
114 1.1 jmmv }
115 1.1 jmmv
116 1.1 jmmv atf_error_t
117 1.1 jmmv atf_tc_init_pack(atf_tc_t *tc, const atf_tc_pack_t *pack,
118 1.1 jmmv const atf_map_t *config)
119 1.1 jmmv {
120 1.1 jmmv return atf_tc_init(tc, pack->m_ident, pack->m_head, pack->m_body,
121 1.1 jmmv pack->m_cleanup, config);
122 1.1 jmmv }
123 1.1 jmmv
124 1.1 jmmv void
125 1.1 jmmv atf_tc_fini(atf_tc_t *tc)
126 1.1 jmmv {
127 1.1 jmmv atf_map_fini(&tc->m_vars);
128 1.1 jmmv }
129 1.1 jmmv
130 1.1 jmmv /*
131 1.1 jmmv * Getters.
132 1.1 jmmv */
133 1.1 jmmv
134 1.1 jmmv const char *
135 1.1 jmmv atf_tc_get_ident(const atf_tc_t *tc)
136 1.1 jmmv {
137 1.1 jmmv return tc->m_ident;
138 1.1 jmmv }
139 1.1 jmmv
140 1.1 jmmv const char *
141 1.1 jmmv atf_tc_get_config_var(const atf_tc_t *tc, const char *name)
142 1.1 jmmv {
143 1.1 jmmv const char *val;
144 1.1 jmmv atf_map_citer_t iter;
145 1.1 jmmv
146 1.1 jmmv PRE(atf_tc_has_config_var(tc, name));
147 1.1 jmmv iter = atf_map_find_c(tc->m_config, name);
148 1.1 jmmv val = atf_map_citer_data(iter);
149 1.1 jmmv INV(val != NULL);
150 1.1 jmmv
151 1.1 jmmv return val;
152 1.1 jmmv }
153 1.1 jmmv
154 1.1 jmmv const char *
155 1.1 jmmv atf_tc_get_config_var_wd(const atf_tc_t *tc, const char *name,
156 1.1 jmmv const char *defval)
157 1.1 jmmv {
158 1.1 jmmv const char *val;
159 1.1 jmmv
160 1.1 jmmv if (!atf_tc_has_config_var(tc, name))
161 1.1 jmmv val = defval;
162 1.1 jmmv else
163 1.1 jmmv val = atf_tc_get_config_var(tc, name);
164 1.1 jmmv
165 1.1 jmmv return val;
166 1.1 jmmv }
167 1.1 jmmv
168 1.1 jmmv const char *
169 1.1 jmmv atf_tc_get_md_var(const atf_tc_t *tc, const char *name)
170 1.1 jmmv {
171 1.1 jmmv const char *val;
172 1.1 jmmv atf_map_citer_t iter;
173 1.1 jmmv
174 1.1 jmmv PRE(atf_tc_has_md_var(tc, name));
175 1.1 jmmv iter = atf_map_find_c(&tc->m_vars, name);
176 1.1 jmmv val = atf_map_citer_data(iter);
177 1.1 jmmv INV(val != NULL);
178 1.1 jmmv
179 1.1 jmmv return val;
180 1.1 jmmv }
181 1.1 jmmv
182 1.4 jmmv const atf_map_t *
183 1.4 jmmv atf_tc_get_md_vars(const atf_tc_t *tc)
184 1.4 jmmv {
185 1.4 jmmv return &tc->m_vars;
186 1.4 jmmv }
187 1.4 jmmv
188 1.1 jmmv bool
189 1.1 jmmv atf_tc_has_config_var(const atf_tc_t *tc, const char *name)
190 1.1 jmmv {
191 1.1 jmmv bool found;
192 1.1 jmmv atf_map_citer_t end, iter;
193 1.1 jmmv
194 1.1 jmmv if (tc->m_config == NULL)
195 1.1 jmmv found = false;
196 1.1 jmmv else {
197 1.1 jmmv iter = atf_map_find_c(tc->m_config, name);
198 1.1 jmmv end = atf_map_end_c(tc->m_config);
199 1.1 jmmv found = !atf_equal_map_citer_map_citer(iter, end);
200 1.1 jmmv }
201 1.1 jmmv
202 1.1 jmmv return found;
203 1.1 jmmv }
204 1.1 jmmv
205 1.1 jmmv bool
206 1.1 jmmv atf_tc_has_md_var(const atf_tc_t *tc, const char *name)
207 1.1 jmmv {
208 1.1 jmmv atf_map_citer_t end, iter;
209 1.1 jmmv
210 1.1 jmmv iter = atf_map_find_c(&tc->m_vars, name);
211 1.1 jmmv end = atf_map_end_c(&tc->m_vars);
212 1.1 jmmv return !atf_equal_map_citer_map_citer(iter, end);
213 1.1 jmmv }
214 1.1 jmmv
215 1.1 jmmv /*
216 1.1 jmmv * Modifiers.
217 1.1 jmmv */
218 1.1 jmmv
219 1.1 jmmv atf_error_t
220 1.1 jmmv atf_tc_set_md_var(atf_tc_t *tc, const char *name, const char *fmt, ...)
221 1.1 jmmv {
222 1.1 jmmv atf_error_t err;
223 1.1 jmmv char *value;
224 1.1 jmmv va_list ap;
225 1.1 jmmv
226 1.1 jmmv va_start(ap, fmt);
227 1.1 jmmv err = atf_text_format_ap(&value, fmt, ap);
228 1.1 jmmv va_end(ap);
229 1.1 jmmv
230 1.1 jmmv if (!atf_is_error(err))
231 1.1 jmmv err = atf_map_insert(&tc->m_vars, name, value, true);
232 1.1 jmmv else
233 1.1 jmmv free(value);
234 1.1 jmmv
235 1.1 jmmv return err;
236 1.1 jmmv }
237 1.1 jmmv
238 1.1 jmmv /* ---------------------------------------------------------------------
239 1.1 jmmv * Free functions.
240 1.1 jmmv * --------------------------------------------------------------------- */
241 1.1 jmmv
242 1.1 jmmv static const atf_tc_t *current_tc = NULL;
243 1.4 jmmv static const atf_fs_path_t *current_resfile = NULL;
244 1.1 jmmv static size_t current_tc_fail_count = 0;
245 1.1 jmmv
246 1.1 jmmv atf_error_t
247 1.4 jmmv atf_tc_run(const atf_tc_t *tc, const atf_fs_path_t *resfile)
248 1.1 jmmv {
249 1.4 jmmv current_tc = tc;
250 1.4 jmmv current_resfile = resfile;
251 1.1 jmmv current_tc_fail_count = 0;
252 1.1 jmmv
253 1.4 jmmv tc->m_body(tc);
254 1.1 jmmv
255 1.1 jmmv if (current_tc_fail_count == 0)
256 1.1 jmmv atf_tc_pass();
257 1.1 jmmv else
258 1.1 jmmv atf_tc_fail("%d checks failed; see output for more details",
259 1.1 jmmv current_tc_fail_count);
260 1.1 jmmv
261 1.4 jmmv current_tc = NULL;
262 1.4 jmmv current_resfile = NULL;
263 1.4 jmmv current_tc_fail_count = 0;
264 1.1 jmmv
265 1.1 jmmv return atf_no_error();
266 1.1 jmmv }
267 1.1 jmmv
268 1.1 jmmv atf_error_t
269 1.4 jmmv atf_tc_cleanup(const atf_tc_t *tc)
270 1.1 jmmv {
271 1.4 jmmv if (tc->m_cleanup != NULL)
272 1.4 jmmv tc->m_cleanup(tc);
273 1.4 jmmv return atf_no_error(); /* XXX */
274 1.1 jmmv }
275 1.1 jmmv
276 1.1 jmmv struct prog_found_pair {
277 1.1 jmmv const char *prog;
278 1.1 jmmv bool found;
279 1.1 jmmv };
280 1.1 jmmv
281 1.1 jmmv static
282 1.1 jmmv atf_error_t
283 1.1 jmmv check_prog(const char *prog, void *data)
284 1.1 jmmv {
285 1.1 jmmv atf_error_t err;
286 1.1 jmmv atf_fs_path_t p;
287 1.1 jmmv
288 1.1 jmmv err = atf_fs_path_init_fmt(&p, "%s", prog);
289 1.1 jmmv if (atf_is_error(err))
290 1.1 jmmv goto out;
291 1.1 jmmv
292 1.1 jmmv if (atf_fs_path_is_absolute(&p)) {
293 1.3 jmmv err = atf_fs_eaccess(&p, atf_fs_access_x);
294 1.3 jmmv if (atf_is_error(err)) {
295 1.3 jmmv atf_error_free(err);
296 1.3 jmmv atf_fs_path_fini(&p);
297 1.1 jmmv atf_tc_skip("The required program %s could not be found", prog);
298 1.3 jmmv }
299 1.1 jmmv } else {
300 1.1 jmmv const char *path = atf_env_get("PATH");
301 1.1 jmmv struct prog_found_pair pf;
302 1.1 jmmv atf_fs_path_t bp;
303 1.1 jmmv
304 1.1 jmmv err = atf_fs_path_branch_path(&p, &bp);
305 1.1 jmmv if (atf_is_error(err))
306 1.1 jmmv goto out_p;
307 1.1 jmmv
308 1.3 jmmv if (strcmp(atf_fs_path_cstring(&bp), ".") != 0) {
309 1.3 jmmv atf_fs_path_fini(&bp);
310 1.3 jmmv atf_fs_path_fini(&p);
311 1.1 jmmv atf_tc_fail("Relative paths are not allowed when searching for "
312 1.1 jmmv "a program (%s)", prog);
313 1.3 jmmv }
314 1.1 jmmv
315 1.1 jmmv pf.prog = prog;
316 1.1 jmmv pf.found = false;
317 1.1 jmmv err = atf_text_for_each_word(path, ":", check_prog_in_dir, &pf);
318 1.1 jmmv if (atf_is_error(err))
319 1.1 jmmv goto out_bp;
320 1.1 jmmv
321 1.3 jmmv if (!pf.found) {
322 1.3 jmmv atf_fs_path_fini(&bp);
323 1.3 jmmv atf_fs_path_fini(&p);
324 1.1 jmmv atf_tc_skip("The required program %s could not be found in "
325 1.1 jmmv "the PATH", prog);
326 1.3 jmmv }
327 1.1 jmmv
328 1.1 jmmv out_bp:
329 1.1 jmmv atf_fs_path_fini(&bp);
330 1.1 jmmv }
331 1.1 jmmv
332 1.1 jmmv out_p:
333 1.1 jmmv atf_fs_path_fini(&p);
334 1.1 jmmv out:
335 1.1 jmmv return err;
336 1.1 jmmv }
337 1.1 jmmv
338 1.1 jmmv static
339 1.1 jmmv atf_error_t
340 1.1 jmmv check_prog_in_dir(const char *dir, void *data)
341 1.1 jmmv {
342 1.1 jmmv struct prog_found_pair *pf = data;
343 1.1 jmmv atf_error_t err;
344 1.1 jmmv
345 1.1 jmmv if (pf->found)
346 1.1 jmmv err = atf_no_error();
347 1.1 jmmv else {
348 1.1 jmmv atf_fs_path_t p;
349 1.1 jmmv
350 1.1 jmmv err = atf_fs_path_init_fmt(&p, "%s/%s", dir, pf->prog);
351 1.1 jmmv if (atf_is_error(err))
352 1.1 jmmv goto out_p;
353 1.1 jmmv
354 1.3 jmmv err = atf_fs_eaccess(&p, atf_fs_access_x);
355 1.3 jmmv if (!atf_is_error(err))
356 1.1 jmmv pf->found = true;
357 1.3 jmmv else {
358 1.3 jmmv atf_error_free(err);
359 1.3 jmmv INV(!pf->found);
360 1.3 jmmv err = atf_no_error();
361 1.3 jmmv }
362 1.1 jmmv
363 1.1 jmmv out_p:
364 1.1 jmmv atf_fs_path_fini(&p);
365 1.1 jmmv }
366 1.1 jmmv
367 1.1 jmmv return err;
368 1.1 jmmv }
369 1.1 jmmv
370 1.1 jmmv static
371 1.3 jmmv void
372 1.3 jmmv tc_fail(atf_dynstr_t *msg)
373 1.3 jmmv {
374 1.3 jmmv atf_tcr_t tcr;
375 1.3 jmmv atf_error_t err;
376 1.3 jmmv
377 1.3 jmmv PRE(current_tc != NULL);
378 1.3 jmmv
379 1.3 jmmv err = atf_tcr_init_reason_fmt(&tcr, atf_tcr_failed_state, "%s",
380 1.3 jmmv atf_dynstr_cstring(msg));
381 1.3 jmmv if (atf_is_error(err))
382 1.3 jmmv abort();
383 1.3 jmmv
384 1.4 jmmv atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
385 1.3 jmmv
386 1.3 jmmv atf_tcr_fini(&tcr);
387 1.3 jmmv atf_dynstr_fini(msg);
388 1.3 jmmv
389 1.4 jmmv exit(EXIT_FAILURE);
390 1.3 jmmv }
391 1.3 jmmv
392 1.3 jmmv static
393 1.3 jmmv void
394 1.3 jmmv tc_fail_nonfatal(atf_dynstr_t *msg)
395 1.3 jmmv {
396 1.3 jmmv fprintf(stderr, "%s\n", atf_dynstr_cstring(msg));
397 1.3 jmmv atf_dynstr_fini(msg);
398 1.3 jmmv
399 1.3 jmmv current_tc_fail_count++;
400 1.1 jmmv }
401 1.1 jmmv
402 1.1 jmmv void
403 1.1 jmmv atf_tc_fail(const char *fmt, ...)
404 1.1 jmmv {
405 1.1 jmmv va_list ap;
406 1.1 jmmv atf_tcr_t tcr;
407 1.1 jmmv atf_error_t err;
408 1.1 jmmv
409 1.1 jmmv PRE(current_tc != NULL);
410 1.1 jmmv
411 1.1 jmmv va_start(ap, fmt);
412 1.1 jmmv err = atf_tcr_init_reason_ap(&tcr, atf_tcr_failed_state, fmt, ap);
413 1.1 jmmv va_end(ap);
414 1.1 jmmv if (atf_is_error(err))
415 1.1 jmmv abort();
416 1.1 jmmv
417 1.4 jmmv atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
418 1.1 jmmv
419 1.1 jmmv atf_tcr_fini(&tcr);
420 1.1 jmmv
421 1.4 jmmv exit(EXIT_FAILURE);
422 1.1 jmmv }
423 1.1 jmmv
424 1.1 jmmv void
425 1.1 jmmv atf_tc_fail_nonfatal(const char *fmt, ...)
426 1.1 jmmv {
427 1.1 jmmv va_list ap;
428 1.1 jmmv
429 1.1 jmmv va_start(ap, fmt);
430 1.1 jmmv vfprintf(stderr, fmt, ap);
431 1.1 jmmv va_end(ap);
432 1.1 jmmv fprintf(stderr, "\n");
433 1.1 jmmv
434 1.1 jmmv current_tc_fail_count++;
435 1.1 jmmv }
436 1.1 jmmv
437 1.1 jmmv void
438 1.1 jmmv atf_tc_fail_check(const char *file, int line, const char *fmt, ...)
439 1.1 jmmv {
440 1.1 jmmv va_list ap;
441 1.1 jmmv
442 1.1 jmmv va_start(ap, fmt);
443 1.1 jmmv fail_internal(file, line, "Check failed", "*** ", fmt, ap,
444 1.3 jmmv tc_fail_nonfatal, atf_tc_fail_nonfatal);
445 1.1 jmmv va_end(ap);
446 1.1 jmmv }
447 1.1 jmmv
448 1.1 jmmv void
449 1.1 jmmv atf_tc_fail_requirement(const char *file, int line, const char *fmt, ...)
450 1.1 jmmv {
451 1.1 jmmv va_list ap;
452 1.1 jmmv
453 1.1 jmmv va_start(ap, fmt);
454 1.1 jmmv fail_internal(file, line, "Requirement failed", "", fmt, ap,
455 1.3 jmmv tc_fail, atf_tc_fail);
456 1.1 jmmv va_end(ap);
457 1.1 jmmv
458 1.1 jmmv UNREACHABLE;
459 1.1 jmmv abort();
460 1.1 jmmv }
461 1.1 jmmv
462 1.1 jmmv static
463 1.1 jmmv void
464 1.1 jmmv fail_internal(const char *file, int line, const char *reason,
465 1.1 jmmv const char *prefix, const char *fmt, va_list ap,
466 1.3 jmmv void (*failfunc)(atf_dynstr_t *),
467 1.3 jmmv void (*backupfunc)(const char *, ...))
468 1.1 jmmv {
469 1.1 jmmv va_list ap2;
470 1.1 jmmv atf_error_t err;
471 1.1 jmmv atf_dynstr_t msg;
472 1.1 jmmv
473 1.1 jmmv err = atf_dynstr_init_fmt(&msg, "%s%s:%d: %s: ", prefix, file, line,
474 1.1 jmmv reason);
475 1.1 jmmv if (atf_is_error(err))
476 1.1 jmmv goto backup;
477 1.1 jmmv
478 1.1 jmmv va_copy(ap2, ap);
479 1.1 jmmv err = atf_dynstr_append_ap(&msg, fmt, ap2);
480 1.1 jmmv va_end(ap2);
481 1.1 jmmv if (atf_is_error(err)) {
482 1.1 jmmv atf_dynstr_fini(&msg);
483 1.1 jmmv goto backup;
484 1.1 jmmv }
485 1.1 jmmv
486 1.1 jmmv va_copy(ap2, ap);
487 1.3 jmmv failfunc(&msg);
488 1.1 jmmv return;
489 1.1 jmmv
490 1.1 jmmv backup:
491 1.3 jmmv atf_error_free(err);
492 1.1 jmmv va_copy(ap2, ap);
493 1.3 jmmv backupfunc(fmt, ap2);
494 1.1 jmmv va_end(ap2);
495 1.1 jmmv }
496 1.1 jmmv
497 1.1 jmmv void
498 1.1 jmmv atf_tc_pass(void)
499 1.1 jmmv {
500 1.1 jmmv atf_tcr_t tcr;
501 1.1 jmmv atf_error_t err;
502 1.1 jmmv
503 1.1 jmmv PRE(current_tc != NULL);
504 1.1 jmmv
505 1.1 jmmv err = atf_tcr_init(&tcr, atf_tcr_passed_state);
506 1.1 jmmv if (atf_is_error(err))
507 1.1 jmmv abort();
508 1.1 jmmv
509 1.4 jmmv atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
510 1.1 jmmv
511 1.1 jmmv atf_tcr_fini(&tcr);
512 1.1 jmmv
513 1.1 jmmv exit(EXIT_SUCCESS);
514 1.1 jmmv }
515 1.1 jmmv
516 1.1 jmmv void
517 1.1 jmmv atf_tc_require_prog(const char *prog)
518 1.1 jmmv {
519 1.1 jmmv atf_error_t err;
520 1.1 jmmv
521 1.1 jmmv err = check_prog(prog, NULL);
522 1.3 jmmv if (atf_is_error(err)) {
523 1.3 jmmv atf_error_free(err);
524 1.1 jmmv atf_tc_fail("atf_tc_require_prog failed"); /* XXX Correct? */
525 1.3 jmmv }
526 1.1 jmmv }
527 1.1 jmmv
528 1.1 jmmv void
529 1.1 jmmv atf_tc_skip(const char *fmt, ...)
530 1.1 jmmv {
531 1.1 jmmv va_list ap;
532 1.1 jmmv atf_tcr_t tcr;
533 1.1 jmmv atf_error_t err;
534 1.1 jmmv
535 1.1 jmmv PRE(current_tc != NULL);
536 1.1 jmmv
537 1.1 jmmv va_start(ap, fmt);
538 1.1 jmmv err = atf_tcr_init_reason_ap(&tcr, atf_tcr_skipped_state, fmt, ap);
539 1.1 jmmv va_end(ap);
540 1.1 jmmv if (atf_is_error(err))
541 1.1 jmmv abort();
542 1.1 jmmv
543 1.4 jmmv atf_tcr_write(&tcr, current_resfile); /* XXX Handle errors. */
544 1.1 jmmv
545 1.1 jmmv atf_tcr_fini(&tcr);
546 1.1 jmmv
547 1.1 jmmv exit(EXIT_SUCCESS);
548 1.1 jmmv }
549