check.c revision 1.1 1 1.1 jmmv /*
2 1.1 jmmv * Automated Testing Framework (atf)
3 1.1 jmmv *
4 1.1 jmmv * Copyright (c) 2008 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/wait.h>
31 1.1 jmmv
32 1.1 jmmv #include <errno.h>
33 1.1 jmmv #include <stdio.h>
34 1.1 jmmv #include <stdlib.h>
35 1.1 jmmv #include <string.h>
36 1.1 jmmv #include <unistd.h>
37 1.1 jmmv
38 1.1 jmmv #include "atf-c/check.h"
39 1.1 jmmv #include "atf-c/config.h"
40 1.1 jmmv #include "atf-c/dynstr.h"
41 1.1 jmmv #include "atf-c/error.h"
42 1.1 jmmv #include "atf-c/fs.h"
43 1.1 jmmv #include "atf-c/process.h"
44 1.1 jmmv #include "atf-c/sanity.h"
45 1.1 jmmv
46 1.1 jmmv /* Only needed for testing, so not in the public header. */
47 1.1 jmmv atf_error_t atf_check_result_init(atf_check_result_t *);
48 1.1 jmmv
49 1.1 jmmv /* ---------------------------------------------------------------------
50 1.1 jmmv * Auxiliary functions.
51 1.1 jmmv * --------------------------------------------------------------------- */
52 1.1 jmmv
53 1.1 jmmv static
54 1.1 jmmv atf_error_t
55 1.1 jmmv create_files(atf_check_result_t *r, int *fdout, int *fderr)
56 1.1 jmmv {
57 1.1 jmmv atf_error_t err;
58 1.1 jmmv
59 1.1 jmmv err = atf_fs_mkstemp(&r->m_stdout, fdout);
60 1.1 jmmv if (atf_is_error(err))
61 1.1 jmmv goto out;
62 1.1 jmmv
63 1.1 jmmv err = atf_fs_mkstemp(&r->m_stderr, fderr);
64 1.1 jmmv if (atf_is_error(err))
65 1.1 jmmv goto err_fdout;
66 1.1 jmmv
67 1.1 jmmv INV(!atf_is_error(err));
68 1.1 jmmv goto out;
69 1.1 jmmv
70 1.1 jmmv err_fdout:
71 1.1 jmmv close(*fdout);
72 1.1 jmmv atf_fs_unlink(&r->m_stdout);
73 1.1 jmmv out:
74 1.1 jmmv return err;
75 1.1 jmmv }
76 1.1 jmmv
77 1.1 jmmv static
78 1.1 jmmv void
79 1.1 jmmv cleanup_files(const atf_check_result_t *r, int fdout, int fderr)
80 1.1 jmmv {
81 1.1 jmmv int ret;
82 1.1 jmmv
83 1.1 jmmv ret = close(fdout);
84 1.1 jmmv INV(ret == 0);
85 1.1 jmmv ret = close(fderr);
86 1.1 jmmv INV(ret == 0);
87 1.1 jmmv
88 1.1 jmmv atf_fs_unlink(&r->m_stdout);
89 1.1 jmmv atf_fs_unlink(&r->m_stderr);
90 1.1 jmmv }
91 1.1 jmmv
92 1.1 jmmv static
93 1.1 jmmv atf_error_t
94 1.1 jmmv fork_and_wait(char *const *argv, int fdout, int fderr, int *estatus)
95 1.1 jmmv {
96 1.1 jmmv atf_error_t err;
97 1.1 jmmv int status;
98 1.1 jmmv pid_t pid;
99 1.1 jmmv
100 1.1 jmmv err = atf_process_fork(&pid);
101 1.1 jmmv if (atf_is_error(err))
102 1.1 jmmv goto out;
103 1.1 jmmv
104 1.1 jmmv if (pid == 0) {
105 1.1 jmmv atf_disable_exit_checks();
106 1.1 jmmv /* XXX No error handling at all? */
107 1.1 jmmv dup2(fdout, STDOUT_FILENO);
108 1.1 jmmv dup2(fderr, STDERR_FILENO);
109 1.1 jmmv execvp(argv[0], argv);
110 1.1 jmmv fprintf(stderr, "execvp(%s) failed: %s", argv[0], strerror(errno));
111 1.1 jmmv exit(127);
112 1.1 jmmv UNREACHABLE;
113 1.1 jmmv } else {
114 1.1 jmmv if (waitpid(pid, &status, 0) == -1) {
115 1.1 jmmv err = atf_libc_error(errno, "Error waiting for "
116 1.1 jmmv "child process: %d", pid);
117 1.1 jmmv } else {
118 1.1 jmmv *estatus = status;
119 1.1 jmmv }
120 1.1 jmmv }
121 1.1 jmmv
122 1.1 jmmv out:
123 1.1 jmmv return err;
124 1.1 jmmv }
125 1.1 jmmv
126 1.1 jmmv /* ---------------------------------------------------------------------
127 1.1 jmmv * The "atf_check_result" type.
128 1.1 jmmv * --------------------------------------------------------------------- */
129 1.1 jmmv
130 1.1 jmmv atf_error_t
131 1.1 jmmv atf_check_result_init(atf_check_result_t *r)
132 1.1 jmmv {
133 1.1 jmmv atf_error_t err;
134 1.1 jmmv const char *workdir;
135 1.1 jmmv
136 1.1 jmmv atf_object_init(&r->m_object);
137 1.1 jmmv
138 1.1 jmmv workdir = atf_config_get("atf_workdir");
139 1.1 jmmv
140 1.1 jmmv err = atf_fs_path_init_fmt(&r->m_stdout, "%s/%s",
141 1.1 jmmv workdir, "stdout.XXXXXX");
142 1.1 jmmv if (atf_is_error(err))
143 1.1 jmmv goto out;
144 1.1 jmmv
145 1.1 jmmv err = atf_fs_path_init_fmt(&r->m_stderr, "%s/%s",
146 1.1 jmmv workdir, "stderr.XXXXXX");
147 1.1 jmmv if (atf_is_error(err))
148 1.1 jmmv goto err_stdout;
149 1.1 jmmv
150 1.1 jmmv INV(!atf_is_error(err));
151 1.1 jmmv goto out;
152 1.1 jmmv
153 1.1 jmmv err_stdout:
154 1.1 jmmv atf_fs_path_fini(&r->m_stdout);
155 1.1 jmmv out:
156 1.1 jmmv return err;
157 1.1 jmmv }
158 1.1 jmmv
159 1.1 jmmv void
160 1.1 jmmv atf_check_result_fini(atf_check_result_t *r)
161 1.1 jmmv {
162 1.1 jmmv atf_fs_unlink(&r->m_stdout);
163 1.1 jmmv atf_fs_path_fini(&r->m_stdout);
164 1.1 jmmv
165 1.1 jmmv atf_fs_unlink(&r->m_stderr);
166 1.1 jmmv atf_fs_path_fini(&r->m_stderr);
167 1.1 jmmv
168 1.1 jmmv atf_object_fini(&r->m_object);
169 1.1 jmmv }
170 1.1 jmmv
171 1.1 jmmv const atf_fs_path_t *
172 1.1 jmmv atf_check_result_stdout(const atf_check_result_t *r)
173 1.1 jmmv {
174 1.1 jmmv return &r->m_stdout;
175 1.1 jmmv }
176 1.1 jmmv
177 1.1 jmmv const atf_fs_path_t *
178 1.1 jmmv atf_check_result_stderr(const atf_check_result_t *r)
179 1.1 jmmv {
180 1.1 jmmv return &r->m_stderr;
181 1.1 jmmv }
182 1.1 jmmv
183 1.1 jmmv bool
184 1.1 jmmv atf_check_result_exited(const atf_check_result_t *r)
185 1.1 jmmv {
186 1.1 jmmv int estatus = r->m_estatus;
187 1.1 jmmv return WIFEXITED(estatus);
188 1.1 jmmv }
189 1.1 jmmv
190 1.1 jmmv int
191 1.1 jmmv atf_check_result_exitcode(const atf_check_result_t *r)
192 1.1 jmmv {
193 1.1 jmmv int estatus = r->m_estatus;
194 1.1 jmmv return WEXITSTATUS(estatus);
195 1.1 jmmv }
196 1.1 jmmv
197 1.1 jmmv /* ---------------------------------------------------------------------
198 1.1 jmmv * Free functions.
199 1.1 jmmv * --------------------------------------------------------------------- */
200 1.1 jmmv
201 1.1 jmmv atf_error_t
202 1.1 jmmv atf_check_exec(char *const *argv, atf_check_result_t *r)
203 1.1 jmmv {
204 1.1 jmmv atf_error_t err;
205 1.1 jmmv int fdout, fderr;
206 1.1 jmmv
207 1.1 jmmv err = atf_check_result_init(r);
208 1.1 jmmv if (atf_is_error(err))
209 1.1 jmmv goto out;
210 1.1 jmmv
211 1.1 jmmv err = create_files(r, &fdout, &fderr);
212 1.1 jmmv if (atf_is_error(err))
213 1.1 jmmv goto err_r;
214 1.1 jmmv
215 1.1 jmmv err = fork_and_wait(argv, fdout, fderr, &r->m_estatus);
216 1.1 jmmv if (atf_is_error(err))
217 1.1 jmmv goto err_files;
218 1.1 jmmv
219 1.1 jmmv INV(!atf_is_error(err));
220 1.1 jmmv goto out;
221 1.1 jmmv
222 1.1 jmmv err_files:
223 1.1 jmmv cleanup_files(r, fdout, fderr);
224 1.1 jmmv err_r:
225 1.1 jmmv atf_check_result_fini(r);
226 1.1 jmmv out:
227 1.1 jmmv return err;
228 1.1 jmmv }
229