1*11be35a1SLionel Sambuc /*
2*11be35a1SLionel Sambuc * Automated Testing Framework (atf)
3*11be35a1SLionel Sambuc *
4*11be35a1SLionel Sambuc * Copyright (c) 2010 The NetBSD Foundation, Inc.
5*11be35a1SLionel Sambuc * All rights reserved.
6*11be35a1SLionel Sambuc *
7*11be35a1SLionel Sambuc * Redistribution and use in source and binary forms, with or without
8*11be35a1SLionel Sambuc * modification, are permitted provided that the following conditions
9*11be35a1SLionel Sambuc * are met:
10*11be35a1SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
11*11be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer.
12*11be35a1SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
13*11be35a1SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
14*11be35a1SLionel Sambuc * documentation and/or other materials provided with the distribution.
15*11be35a1SLionel Sambuc *
16*11be35a1SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*11be35a1SLionel Sambuc * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*11be35a1SLionel Sambuc * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*11be35a1SLionel Sambuc * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*11be35a1SLionel Sambuc * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*11be35a1SLionel Sambuc * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*11be35a1SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*11be35a1SLionel Sambuc * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*11be35a1SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*11be35a1SLionel Sambuc * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*11be35a1SLionel Sambuc * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*11be35a1SLionel Sambuc * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*11be35a1SLionel Sambuc */
29*11be35a1SLionel Sambuc
30*11be35a1SLionel Sambuc #include "atf-c/utils.h"
31*11be35a1SLionel Sambuc
32*11be35a1SLionel Sambuc #include <sys/stat.h>
33*11be35a1SLionel Sambuc #include <sys/wait.h>
34*11be35a1SLionel Sambuc
35*11be35a1SLionel Sambuc #include <err.h>
36*11be35a1SLionel Sambuc #include <errno.h>
37*11be35a1SLionel Sambuc #include <fcntl.h>
38*11be35a1SLionel Sambuc #include <regex.h>
39*11be35a1SLionel Sambuc #include <stdio.h>
40*11be35a1SLionel Sambuc #include <stdlib.h>
41*11be35a1SLionel Sambuc #include <string.h>
42*11be35a1SLionel Sambuc #include <unistd.h>
43*11be35a1SLionel Sambuc
44*11be35a1SLionel Sambuc #include <atf-c.h>
45*11be35a1SLionel Sambuc
46*11be35a1SLionel Sambuc #include "detail/dynstr.h"
47*11be35a1SLionel Sambuc
48*11be35a1SLionel Sambuc /** Searches for a regexp in a string.
49*11be35a1SLionel Sambuc *
50*11be35a1SLionel Sambuc * \param regex The regexp to look for.
51*11be35a1SLionel Sambuc * \param str The string in which to look for the expression.
52*11be35a1SLionel Sambuc *
53*11be35a1SLionel Sambuc * \return True if there is a match; false otherwise. */
54*11be35a1SLionel Sambuc static
55*11be35a1SLionel Sambuc bool
grep_string(const char * regex,const char * str)56*11be35a1SLionel Sambuc grep_string(const char *regex, const char *str)
57*11be35a1SLionel Sambuc {
58*11be35a1SLionel Sambuc int res;
59*11be35a1SLionel Sambuc regex_t preg;
60*11be35a1SLionel Sambuc
61*11be35a1SLionel Sambuc printf("Looking for '%s' in '%s'\n", regex, str);
62*11be35a1SLionel Sambuc ATF_REQUIRE(regcomp(&preg, regex, REG_EXTENDED) == 0);
63*11be35a1SLionel Sambuc
64*11be35a1SLionel Sambuc res = regexec(&preg, str, 0, NULL, 0);
65*11be35a1SLionel Sambuc ATF_REQUIRE(res == 0 || res == REG_NOMATCH);
66*11be35a1SLionel Sambuc
67*11be35a1SLionel Sambuc regfree(&preg);
68*11be35a1SLionel Sambuc
69*11be35a1SLionel Sambuc return res == 0;
70*11be35a1SLionel Sambuc }
71*11be35a1SLionel Sambuc
72*11be35a1SLionel Sambuc /** Prints the contents of a file to stdout.
73*11be35a1SLionel Sambuc *
74*11be35a1SLionel Sambuc * \param name The name of the file to be printed.
75*11be35a1SLionel Sambuc * \param prefix An string to be prepended to every line of the printed
76*11be35a1SLionel Sambuc * file. */
77*11be35a1SLionel Sambuc void
atf_utils_cat_file(const char * name,const char * prefix)78*11be35a1SLionel Sambuc atf_utils_cat_file(const char *name, const char *prefix)
79*11be35a1SLionel Sambuc {
80*11be35a1SLionel Sambuc const int fd = open(name, O_RDONLY);
81*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", name);
82*11be35a1SLionel Sambuc
83*11be35a1SLionel Sambuc char buffer[1024];
84*11be35a1SLionel Sambuc ssize_t count;
85*11be35a1SLionel Sambuc bool continued = false;
86*11be35a1SLionel Sambuc while ((count = read(fd, buffer, sizeof(buffer) - 1)) > 0) {
87*11be35a1SLionel Sambuc buffer[count] = '\0';
88*11be35a1SLionel Sambuc
89*11be35a1SLionel Sambuc if (!continued)
90*11be35a1SLionel Sambuc printf("%s", prefix);
91*11be35a1SLionel Sambuc
92*11be35a1SLionel Sambuc char *iter = buffer;
93*11be35a1SLionel Sambuc char *end;
94*11be35a1SLionel Sambuc while ((end = strchr(iter, '\n')) != NULL) {
95*11be35a1SLionel Sambuc *end = '\0';
96*11be35a1SLionel Sambuc printf("%s\n", iter);
97*11be35a1SLionel Sambuc
98*11be35a1SLionel Sambuc iter = end + 1;
99*11be35a1SLionel Sambuc if (iter != buffer + count)
100*11be35a1SLionel Sambuc printf("%s", prefix);
101*11be35a1SLionel Sambuc else
102*11be35a1SLionel Sambuc continued = false;
103*11be35a1SLionel Sambuc }
104*11be35a1SLionel Sambuc if (iter < buffer + count) {
105*11be35a1SLionel Sambuc printf("%s", iter);
106*11be35a1SLionel Sambuc continued = true;
107*11be35a1SLionel Sambuc }
108*11be35a1SLionel Sambuc }
109*11be35a1SLionel Sambuc ATF_REQUIRE(count == 0);
110*11be35a1SLionel Sambuc }
111*11be35a1SLionel Sambuc
112*11be35a1SLionel Sambuc /** Compares a file against the given golden contents.
113*11be35a1SLionel Sambuc *
114*11be35a1SLionel Sambuc * \param name Name of the file to be compared.
115*11be35a1SLionel Sambuc * \param contents Expected contents of the file.
116*11be35a1SLionel Sambuc *
117*11be35a1SLionel Sambuc * \return True if the file matches the contents; false otherwise. */
118*11be35a1SLionel Sambuc bool
atf_utils_compare_file(const char * name,const char * contents)119*11be35a1SLionel Sambuc atf_utils_compare_file(const char *name, const char *contents)
120*11be35a1SLionel Sambuc {
121*11be35a1SLionel Sambuc const int fd = open(name, O_RDONLY);
122*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(fd != -1, "Cannot open %s", name);
123*11be35a1SLionel Sambuc
124*11be35a1SLionel Sambuc const char *pos = contents;
125*11be35a1SLionel Sambuc ssize_t remaining = strlen(contents);
126*11be35a1SLionel Sambuc
127*11be35a1SLionel Sambuc char buffer[1024];
128*11be35a1SLionel Sambuc ssize_t count;
129*11be35a1SLionel Sambuc while ((count = read(fd, buffer, sizeof(buffer))) > 0 &&
130*11be35a1SLionel Sambuc count <= remaining) {
131*11be35a1SLionel Sambuc if (memcmp(pos, buffer, count) != 0) {
132*11be35a1SLionel Sambuc close(fd);
133*11be35a1SLionel Sambuc return false;
134*11be35a1SLionel Sambuc }
135*11be35a1SLionel Sambuc remaining -= count;
136*11be35a1SLionel Sambuc pos += count;
137*11be35a1SLionel Sambuc }
138*11be35a1SLionel Sambuc close(fd);
139*11be35a1SLionel Sambuc return count == 0 && remaining == 0;
140*11be35a1SLionel Sambuc }
141*11be35a1SLionel Sambuc
142*11be35a1SLionel Sambuc /** Copies a file.
143*11be35a1SLionel Sambuc *
144*11be35a1SLionel Sambuc * \param source Path to the source file.
145*11be35a1SLionel Sambuc * \param destination Path to the destination file. */
146*11be35a1SLionel Sambuc void
atf_utils_copy_file(const char * source,const char * destination)147*11be35a1SLionel Sambuc atf_utils_copy_file(const char *source, const char *destination)
148*11be35a1SLionel Sambuc {
149*11be35a1SLionel Sambuc const int input = open(source, O_RDONLY);
150*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(input != -1, "Failed to open source file during "
151*11be35a1SLionel Sambuc "copy (%s)", source);
152*11be35a1SLionel Sambuc
153*11be35a1SLionel Sambuc const int output = open(destination, O_WRONLY | O_CREAT | O_TRUNC, 0777);
154*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(output != -1, "Failed to open destination file during "
155*11be35a1SLionel Sambuc "copy (%s)", destination);
156*11be35a1SLionel Sambuc
157*11be35a1SLionel Sambuc char buffer[1024];
158*11be35a1SLionel Sambuc ssize_t length;
159*11be35a1SLionel Sambuc while ((length = read(input, buffer, sizeof(buffer))) > 0)
160*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(write(output, buffer, length) == length,
161*11be35a1SLionel Sambuc "Failed to write to %s during copy", destination);
162*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(length != -1, "Failed to read from %s during copy", source);
163*11be35a1SLionel Sambuc
164*11be35a1SLionel Sambuc struct stat sb;
165*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(fstat(input, &sb) != -1,
166*11be35a1SLionel Sambuc "Failed to stat source file %s during copy", source);
167*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(fchmod(output, sb.st_mode) != -1,
168*11be35a1SLionel Sambuc "Failed to chmod destination file %s during copy",
169*11be35a1SLionel Sambuc destination);
170*11be35a1SLionel Sambuc
171*11be35a1SLionel Sambuc close(output);
172*11be35a1SLionel Sambuc close(input);
173*11be35a1SLionel Sambuc }
174*11be35a1SLionel Sambuc
175*11be35a1SLionel Sambuc /** Creates a file.
176*11be35a1SLionel Sambuc *
177*11be35a1SLionel Sambuc * \param name Name of the file to create.
178*11be35a1SLionel Sambuc * \param contents Text to write into the created file.
179*11be35a1SLionel Sambuc * \param ... Positional parameters to the contents. */
180*11be35a1SLionel Sambuc void
atf_utils_create_file(const char * name,const char * contents,...)181*11be35a1SLionel Sambuc atf_utils_create_file(const char *name, const char *contents, ...)
182*11be35a1SLionel Sambuc {
183*11be35a1SLionel Sambuc va_list ap;
184*11be35a1SLionel Sambuc atf_dynstr_t formatted;
185*11be35a1SLionel Sambuc atf_error_t error;
186*11be35a1SLionel Sambuc
187*11be35a1SLionel Sambuc va_start(ap, contents);
188*11be35a1SLionel Sambuc error = atf_dynstr_init_ap(&formatted, contents, ap);
189*11be35a1SLionel Sambuc va_end(ap);
190*11be35a1SLionel Sambuc ATF_REQUIRE(!atf_is_error(error));
191*11be35a1SLionel Sambuc
192*11be35a1SLionel Sambuc const int fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
193*11be35a1SLionel Sambuc ATF_REQUIRE_MSG(fd != -1, "Cannot create file %s", name);
194*11be35a1SLionel Sambuc ATF_REQUIRE(write(fd, atf_dynstr_cstring(&formatted),
195*11be35a1SLionel Sambuc atf_dynstr_length(&formatted)) != -1);
196*11be35a1SLionel Sambuc close(fd);
197*11be35a1SLionel Sambuc
198*11be35a1SLionel Sambuc atf_dynstr_fini(&formatted);
199*11be35a1SLionel Sambuc }
200*11be35a1SLionel Sambuc
201*11be35a1SLionel Sambuc /** Checks if a file exists.
202*11be35a1SLionel Sambuc *
203*11be35a1SLionel Sambuc * \param path Location of the file to check for.
204*11be35a1SLionel Sambuc *
205*11be35a1SLionel Sambuc * \return True if the file exists, false otherwise. */
206*11be35a1SLionel Sambuc bool
atf_utils_file_exists(const char * path)207*11be35a1SLionel Sambuc atf_utils_file_exists(const char *path)
208*11be35a1SLionel Sambuc {
209*11be35a1SLionel Sambuc const int ret = access(path, F_OK);
210*11be35a1SLionel Sambuc if (ret == -1) {
211*11be35a1SLionel Sambuc if (errno != ENOENT)
212*11be35a1SLionel Sambuc atf_tc_fail("Failed to check the existence of %s: %s", path,
213*11be35a1SLionel Sambuc strerror(errno));
214*11be35a1SLionel Sambuc else
215*11be35a1SLionel Sambuc return false;
216*11be35a1SLionel Sambuc } else
217*11be35a1SLionel Sambuc return true;
218*11be35a1SLionel Sambuc }
219*11be35a1SLionel Sambuc
220*11be35a1SLionel Sambuc /** Spawns a subprocess and redirects its output to files.
221*11be35a1SLionel Sambuc *
222*11be35a1SLionel Sambuc * Use the atf_utils_wait() function to wait for the completion of the spawned
223*11be35a1SLionel Sambuc * subprocess and validate its exit conditions.
224*11be35a1SLionel Sambuc *
225*11be35a1SLionel Sambuc * \return 0 in the new child; the PID of the new child in the parent. Does
226*11be35a1SLionel Sambuc * not return in error conditions. */
227*11be35a1SLionel Sambuc pid_t
atf_utils_fork(void)228*11be35a1SLionel Sambuc atf_utils_fork(void)
229*11be35a1SLionel Sambuc {
230*11be35a1SLionel Sambuc const pid_t pid = fork();
231*11be35a1SLionel Sambuc if (pid == -1)
232*11be35a1SLionel Sambuc atf_tc_fail("fork failed");
233*11be35a1SLionel Sambuc
234*11be35a1SLionel Sambuc if (pid == 0) {
235*11be35a1SLionel Sambuc atf_utils_redirect(STDOUT_FILENO, "atf_utils_fork_out.txt");
236*11be35a1SLionel Sambuc atf_utils_redirect(STDERR_FILENO, "atf_utils_fork_err.txt");
237*11be35a1SLionel Sambuc }
238*11be35a1SLionel Sambuc return pid;
239*11be35a1SLionel Sambuc }
240*11be35a1SLionel Sambuc
241*11be35a1SLionel Sambuc /** Frees an dynamically-allocated "argv" array.
242*11be35a1SLionel Sambuc *
243*11be35a1SLionel Sambuc * \param argv A dynamically-allocated array of dynamically-allocated
244*11be35a1SLionel Sambuc * strings. */
245*11be35a1SLionel Sambuc void
atf_utils_free_charpp(char ** argv)246*11be35a1SLionel Sambuc atf_utils_free_charpp(char **argv)
247*11be35a1SLionel Sambuc {
248*11be35a1SLionel Sambuc char **ptr;
249*11be35a1SLionel Sambuc
250*11be35a1SLionel Sambuc for (ptr = argv; *ptr != NULL; ptr++)
251*11be35a1SLionel Sambuc free(*ptr);
252*11be35a1SLionel Sambuc
253*11be35a1SLionel Sambuc free(argv);
254*11be35a1SLionel Sambuc }
255*11be35a1SLionel Sambuc
256*11be35a1SLionel Sambuc /** Searches for a regexp in a file.
257*11be35a1SLionel Sambuc *
258*11be35a1SLionel Sambuc * \param regex The regexp to look for.
259*11be35a1SLionel Sambuc * \param file The file in which to look for the expression.
260*11be35a1SLionel Sambuc * \param ... Positional parameters to the regex.
261*11be35a1SLionel Sambuc *
262*11be35a1SLionel Sambuc * \return True if there is a match; false otherwise. */
263*11be35a1SLionel Sambuc bool
atf_utils_grep_file(const char * regex,const char * file,...)264*11be35a1SLionel Sambuc atf_utils_grep_file(const char *regex, const char *file, ...)
265*11be35a1SLionel Sambuc {
266*11be35a1SLionel Sambuc int fd;
267*11be35a1SLionel Sambuc va_list ap;
268*11be35a1SLionel Sambuc atf_dynstr_t formatted;
269*11be35a1SLionel Sambuc atf_error_t error;
270*11be35a1SLionel Sambuc
271*11be35a1SLionel Sambuc va_start(ap, file);
272*11be35a1SLionel Sambuc error = atf_dynstr_init_ap(&formatted, regex, ap);
273*11be35a1SLionel Sambuc va_end(ap);
274*11be35a1SLionel Sambuc ATF_REQUIRE(!atf_is_error(error));
275*11be35a1SLionel Sambuc
276*11be35a1SLionel Sambuc ATF_REQUIRE((fd = open(file, O_RDONLY)) != -1);
277*11be35a1SLionel Sambuc bool found = false;
278*11be35a1SLionel Sambuc char *line = NULL;
279*11be35a1SLionel Sambuc while (!found && (line = atf_utils_readline(fd)) != NULL) {
280*11be35a1SLionel Sambuc found = grep_string(atf_dynstr_cstring(&formatted), line);
281*11be35a1SLionel Sambuc free(line);
282*11be35a1SLionel Sambuc }
283*11be35a1SLionel Sambuc close(fd);
284*11be35a1SLionel Sambuc
285*11be35a1SLionel Sambuc atf_dynstr_fini(&formatted);
286*11be35a1SLionel Sambuc
287*11be35a1SLionel Sambuc return found;
288*11be35a1SLionel Sambuc }
289*11be35a1SLionel Sambuc
290*11be35a1SLionel Sambuc /** Searches for a regexp in a string.
291*11be35a1SLionel Sambuc *
292*11be35a1SLionel Sambuc * \param regex The regexp to look for.
293*11be35a1SLionel Sambuc * \param str The string in which to look for the expression.
294*11be35a1SLionel Sambuc * \param ... Positional parameters to the regex.
295*11be35a1SLionel Sambuc *
296*11be35a1SLionel Sambuc * \return True if there is a match; false otherwise. */
297*11be35a1SLionel Sambuc bool
atf_utils_grep_string(const char * regex,const char * str,...)298*11be35a1SLionel Sambuc atf_utils_grep_string(const char *regex, const char *str, ...)
299*11be35a1SLionel Sambuc {
300*11be35a1SLionel Sambuc bool res;
301*11be35a1SLionel Sambuc va_list ap;
302*11be35a1SLionel Sambuc atf_dynstr_t formatted;
303*11be35a1SLionel Sambuc atf_error_t error;
304*11be35a1SLionel Sambuc
305*11be35a1SLionel Sambuc va_start(ap, str);
306*11be35a1SLionel Sambuc error = atf_dynstr_init_ap(&formatted, regex, ap);
307*11be35a1SLionel Sambuc va_end(ap);
308*11be35a1SLionel Sambuc ATF_REQUIRE(!atf_is_error(error));
309*11be35a1SLionel Sambuc
310*11be35a1SLionel Sambuc res = grep_string(atf_dynstr_cstring(&formatted), str);
311*11be35a1SLionel Sambuc
312*11be35a1SLionel Sambuc atf_dynstr_fini(&formatted);
313*11be35a1SLionel Sambuc
314*11be35a1SLionel Sambuc return res;
315*11be35a1SLionel Sambuc }
316*11be35a1SLionel Sambuc
317*11be35a1SLionel Sambuc /** Reads a line of arbitrary length.
318*11be35a1SLionel Sambuc *
319*11be35a1SLionel Sambuc * \param fd The descriptor from which to read the line.
320*11be35a1SLionel Sambuc *
321*11be35a1SLionel Sambuc * \return A pointer to the read line, which must be released with free(), or
322*11be35a1SLionel Sambuc * NULL if there was nothing to read from the file. */
323*11be35a1SLionel Sambuc char *
atf_utils_readline(const int fd)324*11be35a1SLionel Sambuc atf_utils_readline(const int fd)
325*11be35a1SLionel Sambuc {
326*11be35a1SLionel Sambuc char ch;
327*11be35a1SLionel Sambuc ssize_t cnt;
328*11be35a1SLionel Sambuc atf_dynstr_t temp;
329*11be35a1SLionel Sambuc atf_error_t error;
330*11be35a1SLionel Sambuc
331*11be35a1SLionel Sambuc error = atf_dynstr_init(&temp);
332*11be35a1SLionel Sambuc ATF_REQUIRE(!atf_is_error(error));
333*11be35a1SLionel Sambuc
334*11be35a1SLionel Sambuc while ((cnt = read(fd, &ch, sizeof(ch))) == sizeof(ch) &&
335*11be35a1SLionel Sambuc ch != '\n') {
336*11be35a1SLionel Sambuc error = atf_dynstr_append_fmt(&temp, "%c", ch);
337*11be35a1SLionel Sambuc ATF_REQUIRE(!atf_is_error(error));
338*11be35a1SLionel Sambuc }
339*11be35a1SLionel Sambuc ATF_REQUIRE(cnt != -1);
340*11be35a1SLionel Sambuc
341*11be35a1SLionel Sambuc if (cnt == 0 && atf_dynstr_length(&temp) == 0) {
342*11be35a1SLionel Sambuc atf_dynstr_fini(&temp);
343*11be35a1SLionel Sambuc return NULL;
344*11be35a1SLionel Sambuc } else
345*11be35a1SLionel Sambuc return atf_dynstr_fini_disown(&temp);
346*11be35a1SLionel Sambuc }
347*11be35a1SLionel Sambuc
348*11be35a1SLionel Sambuc /** Redirects a file descriptor to a file.
349*11be35a1SLionel Sambuc *
350*11be35a1SLionel Sambuc * \param target_fd The file descriptor to be replaced.
351*11be35a1SLionel Sambuc * \param name The name of the file to direct the descriptor to.
352*11be35a1SLionel Sambuc *
353*11be35a1SLionel Sambuc * \pre Should only be called from the process spawned by fork_for_testing
354*11be35a1SLionel Sambuc * because this exits uncontrolledly.
355*11be35a1SLionel Sambuc * \post Terminates execution if the redirection fails. */
356*11be35a1SLionel Sambuc void
atf_utils_redirect(const int target_fd,const char * name)357*11be35a1SLionel Sambuc atf_utils_redirect(const int target_fd, const char *name)
358*11be35a1SLionel Sambuc {
359*11be35a1SLionel Sambuc if (target_fd == STDOUT_FILENO)
360*11be35a1SLionel Sambuc fflush(stdout);
361*11be35a1SLionel Sambuc else if (target_fd == STDERR_FILENO)
362*11be35a1SLionel Sambuc fflush(stderr);
363*11be35a1SLionel Sambuc
364*11be35a1SLionel Sambuc const int new_fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
365*11be35a1SLionel Sambuc if (new_fd == -1)
366*11be35a1SLionel Sambuc err(EXIT_FAILURE, "Cannot create %s", name);
367*11be35a1SLionel Sambuc if (new_fd != target_fd) {
368*11be35a1SLionel Sambuc if (dup2(new_fd, target_fd) == -1)
369*11be35a1SLionel Sambuc err(EXIT_FAILURE, "Cannot redirect to fd %d", target_fd);
370*11be35a1SLionel Sambuc }
371*11be35a1SLionel Sambuc close(new_fd);
372*11be35a1SLionel Sambuc }
373*11be35a1SLionel Sambuc
374*11be35a1SLionel Sambuc /** Waits for a subprocess and validates its exit condition.
375*11be35a1SLionel Sambuc *
376*11be35a1SLionel Sambuc * \param pid The process to be waited for. Must have been started by
377*11be35a1SLionel Sambuc * testutils_fork().
378*11be35a1SLionel Sambuc * \param exitstatus Expected exit status.
379*11be35a1SLionel Sambuc * \param expout Expected contents of stdout.
380*11be35a1SLionel Sambuc * \param experr Expected contents of stderr. */
381*11be35a1SLionel Sambuc void
atf_utils_wait(const pid_t pid,const int exitstatus,const char * expout,const char * experr)382*11be35a1SLionel Sambuc atf_utils_wait(const pid_t pid, const int exitstatus, const char *expout,
383*11be35a1SLionel Sambuc const char *experr)
384*11be35a1SLionel Sambuc {
385*11be35a1SLionel Sambuc int status;
386*11be35a1SLionel Sambuc ATF_REQUIRE(waitpid(pid, &status, 0) != -1);
387*11be35a1SLionel Sambuc
388*11be35a1SLionel Sambuc atf_utils_cat_file("atf_utils_fork_out.txt", "subprocess stdout: ");
389*11be35a1SLionel Sambuc atf_utils_cat_file("atf_utils_fork_err.txt", "subprocess stderr: ");
390*11be35a1SLionel Sambuc
391*11be35a1SLionel Sambuc ATF_REQUIRE(WIFEXITED(status));
392*11be35a1SLionel Sambuc ATF_REQUIRE_EQ(exitstatus, WEXITSTATUS(status));
393*11be35a1SLionel Sambuc
394*11be35a1SLionel Sambuc const char *save_prefix = "save:";
395*11be35a1SLionel Sambuc const size_t save_prefix_length = strlen(save_prefix);
396*11be35a1SLionel Sambuc
397*11be35a1SLionel Sambuc if (strlen(expout) > save_prefix_length &&
398*11be35a1SLionel Sambuc strncmp(expout, save_prefix, save_prefix_length) == 0) {
399*11be35a1SLionel Sambuc atf_utils_copy_file("atf_utils_fork_out.txt",
400*11be35a1SLionel Sambuc expout + save_prefix_length);
401*11be35a1SLionel Sambuc } else {
402*11be35a1SLionel Sambuc ATF_REQUIRE(atf_utils_compare_file("atf_utils_fork_out.txt", expout));
403*11be35a1SLionel Sambuc }
404*11be35a1SLionel Sambuc
405*11be35a1SLionel Sambuc if (strlen(experr) > save_prefix_length &&
406*11be35a1SLionel Sambuc strncmp(experr, save_prefix, save_prefix_length) == 0) {
407*11be35a1SLionel Sambuc atf_utils_copy_file("atf_utils_fork_err.txt",
408*11be35a1SLionel Sambuc experr + save_prefix_length);
409*11be35a1SLionel Sambuc } else {
410*11be35a1SLionel Sambuc ATF_REQUIRE(atf_utils_compare_file("atf_utils_fork_err.txt", experr));
411*11be35a1SLionel Sambuc }
412*11be35a1SLionel Sambuc
413*11be35a1SLionel Sambuc ATF_REQUIRE(unlink("atf_utils_fork_out.txt") != -1);
414*11be35a1SLionel Sambuc ATF_REQUIRE(unlink("atf_utils_fork_err.txt") != -1);
415*11be35a1SLionel Sambuc }
416