xref: /netbsd-src/external/bsd/atf/dist/atf-c/check.c (revision de4fa6c51a9708fc05f88b618fa6fad87c9508ec)
1 /*
2  * Automated Testing Framework (atf)
3  *
4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <sys/wait.h>
31 
32 #include <errno.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 #include "atf-c/check.h"
39 #include "atf-c/config.h"
40 #include "atf-c/dynstr.h"
41 #include "atf-c/error.h"
42 #include "atf-c/fs.h"
43 #include "atf-c/process.h"
44 #include "atf-c/sanity.h"
45 
46 /* Only needed for testing, so not in the public header. */
47 atf_error_t atf_check_result_init(atf_check_result_t *);
48 
49 /* ---------------------------------------------------------------------
50  * Auxiliary functions.
51  * --------------------------------------------------------------------- */
52 
53 static
54 atf_error_t
55 create_files(atf_check_result_t *r, int *fdout, int *fderr)
56 {
57     atf_error_t err;
58 
59     err = atf_fs_mkstemp(&r->m_stdout, fdout);
60     if (atf_is_error(err))
61         goto out;
62 
63     err = atf_fs_mkstemp(&r->m_stderr, fderr);
64     if (atf_is_error(err))
65         goto err_fdout;
66 
67     INV(!atf_is_error(err));
68     goto out;
69 
70 err_fdout:
71     close(*fdout);
72     atf_fs_unlink(&r->m_stdout);
73 out:
74     return err;
75 }
76 
77 static
78 void
79 cleanup_files(const atf_check_result_t *r, int fdout, int fderr)
80 {
81     int ret;
82 
83     ret = close(fdout);
84     INV(ret == 0);
85     ret = close(fderr);
86     INV(ret == 0);
87 
88     atf_fs_unlink(&r->m_stdout);
89     atf_fs_unlink(&r->m_stderr);
90 }
91 
92 static
93 atf_error_t
94 fork_and_wait(char *const *argv, int fdout, int fderr, int *estatus)
95 {
96     atf_error_t err;
97     int status;
98     pid_t pid;
99 
100     err = atf_process_fork(&pid);
101     if (atf_is_error(err))
102         goto out;
103 
104     if (pid == 0) {
105         atf_disable_exit_checks();
106         /* XXX No error handling at all? */
107         dup2(fdout, STDOUT_FILENO);
108         dup2(fderr, STDERR_FILENO);
109         execvp(argv[0], argv);
110         fprintf(stderr, "execvp(%s) failed: %s", argv[0], strerror(errno));
111         exit(127);
112         UNREACHABLE;
113     } else {
114         if (waitpid(pid, &status, 0) == -1) {
115             err = atf_libc_error(errno, "Error waiting for "
116                                  "child process: %d", pid);
117         } else {
118             *estatus = status;
119         }
120     }
121 
122 out:
123     return err;
124 }
125 
126 /* ---------------------------------------------------------------------
127  * The "atf_check_result" type.
128  * --------------------------------------------------------------------- */
129 
130 atf_error_t
131 atf_check_result_init(atf_check_result_t *r)
132 {
133     atf_error_t err;
134     const char *workdir;
135 
136     atf_object_init(&r->m_object);
137 
138     workdir = atf_config_get("atf_workdir");
139 
140     err = atf_fs_path_init_fmt(&r->m_stdout, "%s/%s",
141                                workdir, "stdout.XXXXXX");
142     if (atf_is_error(err))
143         goto out;
144 
145     err = atf_fs_path_init_fmt(&r->m_stderr, "%s/%s",
146                                workdir, "stderr.XXXXXX");
147     if (atf_is_error(err))
148         goto err_stdout;
149 
150     INV(!atf_is_error(err));
151     goto out;
152 
153 err_stdout:
154     atf_fs_path_fini(&r->m_stdout);
155 out:
156     return err;
157 }
158 
159 void
160 atf_check_result_fini(atf_check_result_t *r)
161 {
162     atf_fs_unlink(&r->m_stdout);
163     atf_fs_path_fini(&r->m_stdout);
164 
165     atf_fs_unlink(&r->m_stderr);
166     atf_fs_path_fini(&r->m_stderr);
167 
168     atf_object_fini(&r->m_object);
169 }
170 
171 const atf_fs_path_t *
172 atf_check_result_stdout(const atf_check_result_t *r)
173 {
174     return &r->m_stdout;
175 }
176 
177 const atf_fs_path_t *
178 atf_check_result_stderr(const atf_check_result_t *r)
179 {
180     return &r->m_stderr;
181 }
182 
183 bool
184 atf_check_result_exited(const atf_check_result_t *r)
185 {
186     int estatus = r->m_estatus;
187     return WIFEXITED(estatus);
188 }
189 
190 int
191 atf_check_result_exitcode(const atf_check_result_t *r)
192 {
193     int estatus = r->m_estatus;
194     return WEXITSTATUS(estatus);
195 }
196 
197 /* ---------------------------------------------------------------------
198  * Free functions.
199  * --------------------------------------------------------------------- */
200 
201 atf_error_t
202 atf_check_exec(char *const *argv, atf_check_result_t *r)
203 {
204     atf_error_t err;
205     int fdout, fderr;
206 
207     err = atf_check_result_init(r);
208     if (atf_is_error(err))
209         goto out;
210 
211     err = create_files(r, &fdout, &fderr);
212     if (atf_is_error(err))
213         goto err_r;
214 
215     err = fork_and_wait(argv, fdout, fderr, &r->m_estatus);
216     if (atf_is_error(err))
217         goto err_files;
218 
219     INV(!atf_is_error(err));
220     goto out;
221 
222 err_files:
223     cleanup_files(r, fdout, fderr);
224 err_r:
225     atf_check_result_fini(r);
226 out:
227     return err;
228 }
229