xref: /minix3/external/bsd/atf/dist/atf-c/utils.c (revision 11be35a165022172ed3cea20f2b5df0307540b0e)
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