xref: /freebsd/contrib/atf/atf-c/detail/fs.c (revision c243e4902be8df1e643c76b5f18b68bb77cc5268)
1*c243e490SMarcel Moolenaar /*
2*c243e490SMarcel Moolenaar  * Automated Testing Framework (atf)
3*c243e490SMarcel Moolenaar  *
4*c243e490SMarcel Moolenaar  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5*c243e490SMarcel Moolenaar  * All rights reserved.
6*c243e490SMarcel Moolenaar  *
7*c243e490SMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
8*c243e490SMarcel Moolenaar  * modification, are permitted provided that the following conditions
9*c243e490SMarcel Moolenaar  * are met:
10*c243e490SMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
11*c243e490SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
12*c243e490SMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
13*c243e490SMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
14*c243e490SMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
15*c243e490SMarcel Moolenaar  *
16*c243e490SMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17*c243e490SMarcel Moolenaar  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18*c243e490SMarcel Moolenaar  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19*c243e490SMarcel Moolenaar  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20*c243e490SMarcel Moolenaar  * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21*c243e490SMarcel Moolenaar  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*c243e490SMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*c243e490SMarcel Moolenaar  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*c243e490SMarcel Moolenaar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*c243e490SMarcel Moolenaar  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*c243e490SMarcel Moolenaar  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*c243e490SMarcel Moolenaar  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*c243e490SMarcel Moolenaar  */
29*c243e490SMarcel Moolenaar 
30*c243e490SMarcel Moolenaar #if defined(HAVE_CONFIG_H)
31*c243e490SMarcel Moolenaar #include "bconfig.h"
32*c243e490SMarcel Moolenaar #endif
33*c243e490SMarcel Moolenaar 
34*c243e490SMarcel Moolenaar #include <sys/types.h>
35*c243e490SMarcel Moolenaar #include <sys/param.h>
36*c243e490SMarcel Moolenaar #include <sys/mount.h>
37*c243e490SMarcel Moolenaar #include <sys/stat.h>
38*c243e490SMarcel Moolenaar #include <sys/wait.h>
39*c243e490SMarcel Moolenaar 
40*c243e490SMarcel Moolenaar #include <dirent.h>
41*c243e490SMarcel Moolenaar #include <errno.h>
42*c243e490SMarcel Moolenaar #include <libgen.h>
43*c243e490SMarcel Moolenaar #include <stdarg.h>
44*c243e490SMarcel Moolenaar #include <stdio.h>
45*c243e490SMarcel Moolenaar #include <stdlib.h>
46*c243e490SMarcel Moolenaar #include <string.h>
47*c243e490SMarcel Moolenaar #include <unistd.h>
48*c243e490SMarcel Moolenaar 
49*c243e490SMarcel Moolenaar #include "atf-c/defs.h"
50*c243e490SMarcel Moolenaar #include "atf-c/error.h"
51*c243e490SMarcel Moolenaar 
52*c243e490SMarcel Moolenaar #include "fs.h"
53*c243e490SMarcel Moolenaar #include "sanity.h"
54*c243e490SMarcel Moolenaar #include "text.h"
55*c243e490SMarcel Moolenaar #include "user.h"
56*c243e490SMarcel Moolenaar 
57*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
58*c243e490SMarcel Moolenaar  * Prototypes for auxiliary functions.
59*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
60*c243e490SMarcel Moolenaar 
61*c243e490SMarcel Moolenaar static bool check_umask(const mode_t, const mode_t);
62*c243e490SMarcel Moolenaar static atf_error_t copy_contents(const atf_fs_path_t *, char **);
63*c243e490SMarcel Moolenaar static mode_t current_umask(void);
64*c243e490SMarcel Moolenaar static atf_error_t do_mkdtemp(char *);
65*c243e490SMarcel Moolenaar static atf_error_t normalize(atf_dynstr_t *, char *);
66*c243e490SMarcel Moolenaar static atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list);
67*c243e490SMarcel Moolenaar static void replace_contents(atf_fs_path_t *, const char *);
68*c243e490SMarcel Moolenaar static const char *stat_type_to_string(const int);
69*c243e490SMarcel Moolenaar 
70*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
71*c243e490SMarcel Moolenaar  * The "invalid_umask" error type.
72*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
73*c243e490SMarcel Moolenaar 
74*c243e490SMarcel Moolenaar struct invalid_umask_error_data {
75*c243e490SMarcel Moolenaar     /* One of atf_fs_stat_*_type. */
76*c243e490SMarcel Moolenaar     int m_type;
77*c243e490SMarcel Moolenaar 
78*c243e490SMarcel Moolenaar     /* The original path causing the error. */
79*c243e490SMarcel Moolenaar     /* XXX: Ideally this would be an atf_fs_path_t, but if we create it
80*c243e490SMarcel Moolenaar      * from the error constructor, we cannot delete the path later on.
81*c243e490SMarcel Moolenaar      * Can't remember why atf_error_new does not take a hook for
82*c243e490SMarcel Moolenaar      * deletion. */
83*c243e490SMarcel Moolenaar     char m_path[1024];
84*c243e490SMarcel Moolenaar 
85*c243e490SMarcel Moolenaar     /* The umask that caused the error. */
86*c243e490SMarcel Moolenaar     mode_t m_umask;
87*c243e490SMarcel Moolenaar };
88*c243e490SMarcel Moolenaar typedef struct invalid_umask_error_data invalid_umask_error_data_t;
89*c243e490SMarcel Moolenaar 
90*c243e490SMarcel Moolenaar static
91*c243e490SMarcel Moolenaar void
92*c243e490SMarcel Moolenaar invalid_umask_format(const atf_error_t err, char *buf, size_t buflen)
93*c243e490SMarcel Moolenaar {
94*c243e490SMarcel Moolenaar     const invalid_umask_error_data_t *data;
95*c243e490SMarcel Moolenaar 
96*c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "invalid_umask"));
97*c243e490SMarcel Moolenaar 
98*c243e490SMarcel Moolenaar     data = atf_error_data(err);
99*c243e490SMarcel Moolenaar     snprintf(buf, buflen, "Could not create the temporary %s %s because "
100*c243e490SMarcel Moolenaar              "it will not have enough access rights due to the current "
101*c243e490SMarcel Moolenaar              "umask %05o", stat_type_to_string(data->m_type),
102*c243e490SMarcel Moolenaar              data->m_path, (unsigned int)data->m_umask);
103*c243e490SMarcel Moolenaar }
104*c243e490SMarcel Moolenaar 
105*c243e490SMarcel Moolenaar static
106*c243e490SMarcel Moolenaar atf_error_t
107*c243e490SMarcel Moolenaar invalid_umask_error(const atf_fs_path_t *path, const int type,
108*c243e490SMarcel Moolenaar                     const mode_t failing_mask)
109*c243e490SMarcel Moolenaar {
110*c243e490SMarcel Moolenaar     atf_error_t err;
111*c243e490SMarcel Moolenaar     invalid_umask_error_data_t data;
112*c243e490SMarcel Moolenaar 
113*c243e490SMarcel Moolenaar     data.m_type = type;
114*c243e490SMarcel Moolenaar 
115*c243e490SMarcel Moolenaar     strncpy(data.m_path, atf_fs_path_cstring(path), sizeof(data.m_path));
116*c243e490SMarcel Moolenaar     data.m_path[sizeof(data.m_path) - 1] = '\0';
117*c243e490SMarcel Moolenaar 
118*c243e490SMarcel Moolenaar     data.m_umask = failing_mask;
119*c243e490SMarcel Moolenaar 
120*c243e490SMarcel Moolenaar     err = atf_error_new("invalid_umask", &data, sizeof(data),
121*c243e490SMarcel Moolenaar                         invalid_umask_format);
122*c243e490SMarcel Moolenaar 
123*c243e490SMarcel Moolenaar     return err;
124*c243e490SMarcel Moolenaar }
125*c243e490SMarcel Moolenaar 
126*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
127*c243e490SMarcel Moolenaar  * The "unknown_file_type" error type.
128*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
129*c243e490SMarcel Moolenaar 
130*c243e490SMarcel Moolenaar struct unknown_type_error_data {
131*c243e490SMarcel Moolenaar     const char *m_path;
132*c243e490SMarcel Moolenaar     int m_type;
133*c243e490SMarcel Moolenaar };
134*c243e490SMarcel Moolenaar typedef struct unknown_type_error_data unknown_type_error_data_t;
135*c243e490SMarcel Moolenaar 
136*c243e490SMarcel Moolenaar static
137*c243e490SMarcel Moolenaar void
138*c243e490SMarcel Moolenaar unknown_type_format(const atf_error_t err, char *buf, size_t buflen)
139*c243e490SMarcel Moolenaar {
140*c243e490SMarcel Moolenaar     const unknown_type_error_data_t *data;
141*c243e490SMarcel Moolenaar 
142*c243e490SMarcel Moolenaar     PRE(atf_error_is(err, "unknown_type"));
143*c243e490SMarcel Moolenaar 
144*c243e490SMarcel Moolenaar     data = atf_error_data(err);
145*c243e490SMarcel Moolenaar     snprintf(buf, buflen, "Unknown file type %d of %s", data->m_type,
146*c243e490SMarcel Moolenaar              data->m_path);
147*c243e490SMarcel Moolenaar }
148*c243e490SMarcel Moolenaar 
149*c243e490SMarcel Moolenaar static
150*c243e490SMarcel Moolenaar atf_error_t
151*c243e490SMarcel Moolenaar unknown_type_error(const char *path, int type)
152*c243e490SMarcel Moolenaar {
153*c243e490SMarcel Moolenaar     atf_error_t err;
154*c243e490SMarcel Moolenaar     unknown_type_error_data_t data;
155*c243e490SMarcel Moolenaar 
156*c243e490SMarcel Moolenaar     data.m_path = path;
157*c243e490SMarcel Moolenaar     data.m_type = type;
158*c243e490SMarcel Moolenaar 
159*c243e490SMarcel Moolenaar     err = atf_error_new("unknown_type", &data, sizeof(data),
160*c243e490SMarcel Moolenaar                         unknown_type_format);
161*c243e490SMarcel Moolenaar 
162*c243e490SMarcel Moolenaar     return err;
163*c243e490SMarcel Moolenaar }
164*c243e490SMarcel Moolenaar 
165*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
166*c243e490SMarcel Moolenaar  * Auxiliary functions.
167*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
168*c243e490SMarcel Moolenaar 
169*c243e490SMarcel Moolenaar static
170*c243e490SMarcel Moolenaar bool
171*c243e490SMarcel Moolenaar check_umask(const mode_t exp_mode, const mode_t min_mode)
172*c243e490SMarcel Moolenaar {
173*c243e490SMarcel Moolenaar     const mode_t actual_mode = (~current_umask() & exp_mode);
174*c243e490SMarcel Moolenaar     return (actual_mode & min_mode) == min_mode;
175*c243e490SMarcel Moolenaar }
176*c243e490SMarcel Moolenaar 
177*c243e490SMarcel Moolenaar static
178*c243e490SMarcel Moolenaar atf_error_t
179*c243e490SMarcel Moolenaar copy_contents(const atf_fs_path_t *p, char **buf)
180*c243e490SMarcel Moolenaar {
181*c243e490SMarcel Moolenaar     atf_error_t err;
182*c243e490SMarcel Moolenaar     char *str;
183*c243e490SMarcel Moolenaar 
184*c243e490SMarcel Moolenaar     str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1);
185*c243e490SMarcel Moolenaar     if (str == NULL)
186*c243e490SMarcel Moolenaar         err = atf_no_memory_error();
187*c243e490SMarcel Moolenaar     else {
188*c243e490SMarcel Moolenaar         strcpy(str, atf_dynstr_cstring(&p->m_data));
189*c243e490SMarcel Moolenaar         *buf = str;
190*c243e490SMarcel Moolenaar         err = atf_no_error();
191*c243e490SMarcel Moolenaar     }
192*c243e490SMarcel Moolenaar 
193*c243e490SMarcel Moolenaar     return err;
194*c243e490SMarcel Moolenaar }
195*c243e490SMarcel Moolenaar 
196*c243e490SMarcel Moolenaar static
197*c243e490SMarcel Moolenaar mode_t
198*c243e490SMarcel Moolenaar current_umask(void)
199*c243e490SMarcel Moolenaar {
200*c243e490SMarcel Moolenaar     const mode_t current = umask(0);
201*c243e490SMarcel Moolenaar     (void)umask(current);
202*c243e490SMarcel Moolenaar     return current;
203*c243e490SMarcel Moolenaar }
204*c243e490SMarcel Moolenaar 
205*c243e490SMarcel Moolenaar static
206*c243e490SMarcel Moolenaar atf_error_t
207*c243e490SMarcel Moolenaar do_mkdtemp(char *tmpl)
208*c243e490SMarcel Moolenaar {
209*c243e490SMarcel Moolenaar     atf_error_t err;
210*c243e490SMarcel Moolenaar 
211*c243e490SMarcel Moolenaar     PRE(strstr(tmpl, "XXXXXX") != NULL);
212*c243e490SMarcel Moolenaar 
213*c243e490SMarcel Moolenaar     if (mkdtemp(tmpl) == NULL)
214*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot create temporary directory "
215*c243e490SMarcel Moolenaar                              "with template '%s'", tmpl);
216*c243e490SMarcel Moolenaar     else
217*c243e490SMarcel Moolenaar         err = atf_no_error();
218*c243e490SMarcel Moolenaar 
219*c243e490SMarcel Moolenaar     return err;
220*c243e490SMarcel Moolenaar }
221*c243e490SMarcel Moolenaar 
222*c243e490SMarcel Moolenaar static
223*c243e490SMarcel Moolenaar atf_error_t
224*c243e490SMarcel Moolenaar do_mkstemp(char *tmpl, int *fdout)
225*c243e490SMarcel Moolenaar {
226*c243e490SMarcel Moolenaar     atf_error_t err;
227*c243e490SMarcel Moolenaar 
228*c243e490SMarcel Moolenaar     PRE(strstr(tmpl, "XXXXXX") != NULL);
229*c243e490SMarcel Moolenaar 
230*c243e490SMarcel Moolenaar     *fdout = mkstemp(tmpl);
231*c243e490SMarcel Moolenaar     if (*fdout == -1)
232*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot create temporary file "
233*c243e490SMarcel Moolenaar                              "with template '%s'", tmpl);
234*c243e490SMarcel Moolenaar 
235*c243e490SMarcel Moolenaar     else
236*c243e490SMarcel Moolenaar         err = atf_no_error();
237*c243e490SMarcel Moolenaar 
238*c243e490SMarcel Moolenaar     return err;
239*c243e490SMarcel Moolenaar }
240*c243e490SMarcel Moolenaar 
241*c243e490SMarcel Moolenaar static
242*c243e490SMarcel Moolenaar atf_error_t
243*c243e490SMarcel Moolenaar normalize(atf_dynstr_t *d, char *p)
244*c243e490SMarcel Moolenaar {
245*c243e490SMarcel Moolenaar     const char *ptr;
246*c243e490SMarcel Moolenaar     char *last;
247*c243e490SMarcel Moolenaar     atf_error_t err;
248*c243e490SMarcel Moolenaar     bool first;
249*c243e490SMarcel Moolenaar 
250*c243e490SMarcel Moolenaar     PRE(strlen(p) > 0);
251*c243e490SMarcel Moolenaar     PRE(atf_dynstr_length(d) == 0);
252*c243e490SMarcel Moolenaar 
253*c243e490SMarcel Moolenaar     if (p[0] == '/')
254*c243e490SMarcel Moolenaar         err = atf_dynstr_append_fmt(d, "/");
255*c243e490SMarcel Moolenaar     else
256*c243e490SMarcel Moolenaar         err = atf_no_error();
257*c243e490SMarcel Moolenaar 
258*c243e490SMarcel Moolenaar     first = true;
259*c243e490SMarcel Moolenaar     last = NULL; /* Silence GCC warning. */
260*c243e490SMarcel Moolenaar     ptr = strtok_r(p, "/", &last);
261*c243e490SMarcel Moolenaar     while (!atf_is_error(err) && ptr != NULL) {
262*c243e490SMarcel Moolenaar         if (strlen(ptr) > 0) {
263*c243e490SMarcel Moolenaar             err = atf_dynstr_append_fmt(d, "%s%s", first ? "" : "/", ptr);
264*c243e490SMarcel Moolenaar             first = false;
265*c243e490SMarcel Moolenaar         }
266*c243e490SMarcel Moolenaar 
267*c243e490SMarcel Moolenaar         ptr = strtok_r(NULL, "/", &last);
268*c243e490SMarcel Moolenaar     }
269*c243e490SMarcel Moolenaar 
270*c243e490SMarcel Moolenaar     return err;
271*c243e490SMarcel Moolenaar }
272*c243e490SMarcel Moolenaar 
273*c243e490SMarcel Moolenaar static
274*c243e490SMarcel Moolenaar atf_error_t
275*c243e490SMarcel Moolenaar normalize_ap(atf_dynstr_t *d, const char *p, va_list ap)
276*c243e490SMarcel Moolenaar {
277*c243e490SMarcel Moolenaar     char *str;
278*c243e490SMarcel Moolenaar     atf_error_t err;
279*c243e490SMarcel Moolenaar     va_list ap2;
280*c243e490SMarcel Moolenaar 
281*c243e490SMarcel Moolenaar     err = atf_dynstr_init(d);
282*c243e490SMarcel Moolenaar     if (atf_is_error(err))
283*c243e490SMarcel Moolenaar         goto out;
284*c243e490SMarcel Moolenaar 
285*c243e490SMarcel Moolenaar     va_copy(ap2, ap);
286*c243e490SMarcel Moolenaar     err = atf_text_format_ap(&str, p, ap2);
287*c243e490SMarcel Moolenaar     va_end(ap2);
288*c243e490SMarcel Moolenaar     if (atf_is_error(err))
289*c243e490SMarcel Moolenaar         atf_dynstr_fini(d);
290*c243e490SMarcel Moolenaar     else {
291*c243e490SMarcel Moolenaar         err = normalize(d, str);
292*c243e490SMarcel Moolenaar         free(str);
293*c243e490SMarcel Moolenaar     }
294*c243e490SMarcel Moolenaar 
295*c243e490SMarcel Moolenaar out:
296*c243e490SMarcel Moolenaar     return err;
297*c243e490SMarcel Moolenaar }
298*c243e490SMarcel Moolenaar 
299*c243e490SMarcel Moolenaar static
300*c243e490SMarcel Moolenaar void
301*c243e490SMarcel Moolenaar replace_contents(atf_fs_path_t *p, const char *buf)
302*c243e490SMarcel Moolenaar {
303*c243e490SMarcel Moolenaar     atf_error_t err;
304*c243e490SMarcel Moolenaar 
305*c243e490SMarcel Moolenaar     PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
306*c243e490SMarcel Moolenaar 
307*c243e490SMarcel Moolenaar     atf_dynstr_clear(&p->m_data);
308*c243e490SMarcel Moolenaar     err = atf_dynstr_append_fmt(&p->m_data, "%s", buf);
309*c243e490SMarcel Moolenaar 
310*c243e490SMarcel Moolenaar     INV(!atf_is_error(err));
311*c243e490SMarcel Moolenaar }
312*c243e490SMarcel Moolenaar 
313*c243e490SMarcel Moolenaar static
314*c243e490SMarcel Moolenaar const char *
315*c243e490SMarcel Moolenaar stat_type_to_string(const int type)
316*c243e490SMarcel Moolenaar {
317*c243e490SMarcel Moolenaar     const char *str;
318*c243e490SMarcel Moolenaar 
319*c243e490SMarcel Moolenaar     if (type == atf_fs_stat_blk_type)
320*c243e490SMarcel Moolenaar         str = "block device";
321*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_chr_type)
322*c243e490SMarcel Moolenaar         str = "character device";
323*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_dir_type)
324*c243e490SMarcel Moolenaar         str = "directory";
325*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_fifo_type)
326*c243e490SMarcel Moolenaar         str = "named pipe";
327*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_lnk_type)
328*c243e490SMarcel Moolenaar         str = "symbolic link";
329*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_reg_type)
330*c243e490SMarcel Moolenaar         str = "regular file";
331*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_sock_type)
332*c243e490SMarcel Moolenaar         str = "socket";
333*c243e490SMarcel Moolenaar     else if (type == atf_fs_stat_wht_type)
334*c243e490SMarcel Moolenaar         str = "whiteout";
335*c243e490SMarcel Moolenaar     else {
336*c243e490SMarcel Moolenaar         UNREACHABLE;
337*c243e490SMarcel Moolenaar         str = NULL;
338*c243e490SMarcel Moolenaar     }
339*c243e490SMarcel Moolenaar 
340*c243e490SMarcel Moolenaar     return str;
341*c243e490SMarcel Moolenaar }
342*c243e490SMarcel Moolenaar 
343*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
344*c243e490SMarcel Moolenaar  * The "atf_fs_path" type.
345*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
346*c243e490SMarcel Moolenaar 
347*c243e490SMarcel Moolenaar /*
348*c243e490SMarcel Moolenaar  * Constructors/destructors.
349*c243e490SMarcel Moolenaar  */
350*c243e490SMarcel Moolenaar 
351*c243e490SMarcel Moolenaar atf_error_t
352*c243e490SMarcel Moolenaar atf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
353*c243e490SMarcel Moolenaar {
354*c243e490SMarcel Moolenaar     atf_error_t err;
355*c243e490SMarcel Moolenaar     va_list ap2;
356*c243e490SMarcel Moolenaar 
357*c243e490SMarcel Moolenaar     va_copy(ap2, ap);
358*c243e490SMarcel Moolenaar     err = normalize_ap(&p->m_data, fmt, ap2);
359*c243e490SMarcel Moolenaar     va_end(ap2);
360*c243e490SMarcel Moolenaar 
361*c243e490SMarcel Moolenaar     return err;
362*c243e490SMarcel Moolenaar }
363*c243e490SMarcel Moolenaar 
364*c243e490SMarcel Moolenaar atf_error_t
365*c243e490SMarcel Moolenaar atf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
366*c243e490SMarcel Moolenaar {
367*c243e490SMarcel Moolenaar     va_list ap;
368*c243e490SMarcel Moolenaar     atf_error_t err;
369*c243e490SMarcel Moolenaar 
370*c243e490SMarcel Moolenaar     va_start(ap, fmt);
371*c243e490SMarcel Moolenaar     err = atf_fs_path_init_ap(p, fmt, ap);
372*c243e490SMarcel Moolenaar     va_end(ap);
373*c243e490SMarcel Moolenaar 
374*c243e490SMarcel Moolenaar     return err;
375*c243e490SMarcel Moolenaar }
376*c243e490SMarcel Moolenaar 
377*c243e490SMarcel Moolenaar atf_error_t
378*c243e490SMarcel Moolenaar atf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
379*c243e490SMarcel Moolenaar {
380*c243e490SMarcel Moolenaar     return atf_dynstr_copy(&dest->m_data, &src->m_data);
381*c243e490SMarcel Moolenaar }
382*c243e490SMarcel Moolenaar 
383*c243e490SMarcel Moolenaar void
384*c243e490SMarcel Moolenaar atf_fs_path_fini(atf_fs_path_t *p)
385*c243e490SMarcel Moolenaar {
386*c243e490SMarcel Moolenaar     atf_dynstr_fini(&p->m_data);
387*c243e490SMarcel Moolenaar }
388*c243e490SMarcel Moolenaar 
389*c243e490SMarcel Moolenaar /*
390*c243e490SMarcel Moolenaar  * Getters.
391*c243e490SMarcel Moolenaar  */
392*c243e490SMarcel Moolenaar 
393*c243e490SMarcel Moolenaar atf_error_t
394*c243e490SMarcel Moolenaar atf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
395*c243e490SMarcel Moolenaar {
396*c243e490SMarcel Moolenaar     const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
397*c243e490SMarcel Moolenaar     atf_error_t err;
398*c243e490SMarcel Moolenaar 
399*c243e490SMarcel Moolenaar     if (endpos == atf_dynstr_npos)
400*c243e490SMarcel Moolenaar         err = atf_fs_path_init_fmt(bp, ".");
401*c243e490SMarcel Moolenaar     else if (endpos == 0)
402*c243e490SMarcel Moolenaar         err = atf_fs_path_init_fmt(bp, "/");
403*c243e490SMarcel Moolenaar     else
404*c243e490SMarcel Moolenaar         err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
405*c243e490SMarcel Moolenaar 
406*c243e490SMarcel Moolenaar #if defined(HAVE_CONST_DIRNAME)
407*c243e490SMarcel Moolenaar     INV(atf_equal_dynstr_cstring(&bp->m_data,
408*c243e490SMarcel Moolenaar                                  dirname(atf_dynstr_cstring(&p->m_data))));
409*c243e490SMarcel Moolenaar #endif /* defined(HAVE_CONST_DIRNAME) */
410*c243e490SMarcel Moolenaar 
411*c243e490SMarcel Moolenaar     return err;
412*c243e490SMarcel Moolenaar }
413*c243e490SMarcel Moolenaar 
414*c243e490SMarcel Moolenaar const char *
415*c243e490SMarcel Moolenaar atf_fs_path_cstring(const atf_fs_path_t *p)
416*c243e490SMarcel Moolenaar {
417*c243e490SMarcel Moolenaar     return atf_dynstr_cstring(&p->m_data);
418*c243e490SMarcel Moolenaar }
419*c243e490SMarcel Moolenaar 
420*c243e490SMarcel Moolenaar atf_error_t
421*c243e490SMarcel Moolenaar atf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
422*c243e490SMarcel Moolenaar {
423*c243e490SMarcel Moolenaar     size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
424*c243e490SMarcel Moolenaar     atf_error_t err;
425*c243e490SMarcel Moolenaar 
426*c243e490SMarcel Moolenaar     if (begpos == atf_dynstr_npos)
427*c243e490SMarcel Moolenaar         begpos = 0;
428*c243e490SMarcel Moolenaar     else
429*c243e490SMarcel Moolenaar         begpos++;
430*c243e490SMarcel Moolenaar 
431*c243e490SMarcel Moolenaar     err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
432*c243e490SMarcel Moolenaar 
433*c243e490SMarcel Moolenaar #if defined(HAVE_CONST_BASENAME)
434*c243e490SMarcel Moolenaar     INV(atf_equal_dynstr_cstring(ln,
435*c243e490SMarcel Moolenaar                                  basename(atf_dynstr_cstring(&p->m_data))));
436*c243e490SMarcel Moolenaar #endif /* defined(HAVE_CONST_BASENAME) */
437*c243e490SMarcel Moolenaar 
438*c243e490SMarcel Moolenaar     return err;
439*c243e490SMarcel Moolenaar }
440*c243e490SMarcel Moolenaar 
441*c243e490SMarcel Moolenaar bool
442*c243e490SMarcel Moolenaar atf_fs_path_is_absolute(const atf_fs_path_t *p)
443*c243e490SMarcel Moolenaar {
444*c243e490SMarcel Moolenaar     return atf_dynstr_cstring(&p->m_data)[0] == '/';
445*c243e490SMarcel Moolenaar }
446*c243e490SMarcel Moolenaar 
447*c243e490SMarcel Moolenaar bool
448*c243e490SMarcel Moolenaar atf_fs_path_is_root(const atf_fs_path_t *p)
449*c243e490SMarcel Moolenaar {
450*c243e490SMarcel Moolenaar     return atf_equal_dynstr_cstring(&p->m_data, "/");
451*c243e490SMarcel Moolenaar }
452*c243e490SMarcel Moolenaar 
453*c243e490SMarcel Moolenaar /*
454*c243e490SMarcel Moolenaar  * Modifiers.
455*c243e490SMarcel Moolenaar  */
456*c243e490SMarcel Moolenaar 
457*c243e490SMarcel Moolenaar atf_error_t
458*c243e490SMarcel Moolenaar atf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
459*c243e490SMarcel Moolenaar {
460*c243e490SMarcel Moolenaar     atf_dynstr_t aux;
461*c243e490SMarcel Moolenaar     atf_error_t err;
462*c243e490SMarcel Moolenaar     va_list ap2;
463*c243e490SMarcel Moolenaar 
464*c243e490SMarcel Moolenaar     va_copy(ap2, ap);
465*c243e490SMarcel Moolenaar     err = normalize_ap(&aux, fmt, ap2);
466*c243e490SMarcel Moolenaar     va_end(ap2);
467*c243e490SMarcel Moolenaar     if (!atf_is_error(err)) {
468*c243e490SMarcel Moolenaar         const char *auxstr = atf_dynstr_cstring(&aux);
469*c243e490SMarcel Moolenaar         const bool needslash = auxstr[0] != '/';
470*c243e490SMarcel Moolenaar 
471*c243e490SMarcel Moolenaar         err = atf_dynstr_append_fmt(&p->m_data, "%s%s",
472*c243e490SMarcel Moolenaar                                     needslash ? "/" : "", auxstr);
473*c243e490SMarcel Moolenaar 
474*c243e490SMarcel Moolenaar         atf_dynstr_fini(&aux);
475*c243e490SMarcel Moolenaar     }
476*c243e490SMarcel Moolenaar 
477*c243e490SMarcel Moolenaar     return err;
478*c243e490SMarcel Moolenaar }
479*c243e490SMarcel Moolenaar 
480*c243e490SMarcel Moolenaar atf_error_t
481*c243e490SMarcel Moolenaar atf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
482*c243e490SMarcel Moolenaar {
483*c243e490SMarcel Moolenaar     va_list ap;
484*c243e490SMarcel Moolenaar     atf_error_t err;
485*c243e490SMarcel Moolenaar 
486*c243e490SMarcel Moolenaar     va_start(ap, fmt);
487*c243e490SMarcel Moolenaar     err = atf_fs_path_append_ap(p, fmt, ap);
488*c243e490SMarcel Moolenaar     va_end(ap);
489*c243e490SMarcel Moolenaar 
490*c243e490SMarcel Moolenaar     return err;
491*c243e490SMarcel Moolenaar }
492*c243e490SMarcel Moolenaar 
493*c243e490SMarcel Moolenaar atf_error_t
494*c243e490SMarcel Moolenaar atf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
495*c243e490SMarcel Moolenaar {
496*c243e490SMarcel Moolenaar     return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
497*c243e490SMarcel Moolenaar }
498*c243e490SMarcel Moolenaar 
499*c243e490SMarcel Moolenaar atf_error_t
500*c243e490SMarcel Moolenaar atf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
501*c243e490SMarcel Moolenaar {
502*c243e490SMarcel Moolenaar     atf_error_t err;
503*c243e490SMarcel Moolenaar 
504*c243e490SMarcel Moolenaar     PRE(!atf_fs_path_is_absolute(p));
505*c243e490SMarcel Moolenaar 
506*c243e490SMarcel Moolenaar     err = atf_fs_getcwd(pa);
507*c243e490SMarcel Moolenaar     if (atf_is_error(err))
508*c243e490SMarcel Moolenaar         goto out;
509*c243e490SMarcel Moolenaar 
510*c243e490SMarcel Moolenaar     err = atf_fs_path_append_path(pa, p);
511*c243e490SMarcel Moolenaar     if (atf_is_error(err))
512*c243e490SMarcel Moolenaar         atf_fs_path_fini(pa);
513*c243e490SMarcel Moolenaar 
514*c243e490SMarcel Moolenaar out:
515*c243e490SMarcel Moolenaar     return err;
516*c243e490SMarcel Moolenaar }
517*c243e490SMarcel Moolenaar 
518*c243e490SMarcel Moolenaar /*
519*c243e490SMarcel Moolenaar  * Operators.
520*c243e490SMarcel Moolenaar  */
521*c243e490SMarcel Moolenaar 
522*c243e490SMarcel Moolenaar bool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
523*c243e490SMarcel Moolenaar                                const atf_fs_path_t *p2)
524*c243e490SMarcel Moolenaar {
525*c243e490SMarcel Moolenaar     return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
526*c243e490SMarcel Moolenaar }
527*c243e490SMarcel Moolenaar 
528*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
529*c243e490SMarcel Moolenaar  * The "atf_fs_path" type.
530*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
531*c243e490SMarcel Moolenaar 
532*c243e490SMarcel Moolenaar /*
533*c243e490SMarcel Moolenaar  * Constants.
534*c243e490SMarcel Moolenaar  */
535*c243e490SMarcel Moolenaar 
536*c243e490SMarcel Moolenaar const int atf_fs_stat_blk_type  = 1;
537*c243e490SMarcel Moolenaar const int atf_fs_stat_chr_type  = 2;
538*c243e490SMarcel Moolenaar const int atf_fs_stat_dir_type  = 3;
539*c243e490SMarcel Moolenaar const int atf_fs_stat_fifo_type = 4;
540*c243e490SMarcel Moolenaar const int atf_fs_stat_lnk_type  = 5;
541*c243e490SMarcel Moolenaar const int atf_fs_stat_reg_type  = 6;
542*c243e490SMarcel Moolenaar const int atf_fs_stat_sock_type = 7;
543*c243e490SMarcel Moolenaar const int atf_fs_stat_wht_type  = 8;
544*c243e490SMarcel Moolenaar 
545*c243e490SMarcel Moolenaar /*
546*c243e490SMarcel Moolenaar  * Constructors/destructors.
547*c243e490SMarcel Moolenaar  */
548*c243e490SMarcel Moolenaar 
549*c243e490SMarcel Moolenaar atf_error_t
550*c243e490SMarcel Moolenaar atf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
551*c243e490SMarcel Moolenaar {
552*c243e490SMarcel Moolenaar     atf_error_t err;
553*c243e490SMarcel Moolenaar     const char *pstr = atf_fs_path_cstring(p);
554*c243e490SMarcel Moolenaar 
555*c243e490SMarcel Moolenaar     if (lstat(pstr, &st->m_sb) == -1) {
556*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot get information of %s; "
557*c243e490SMarcel Moolenaar                              "lstat(2) failed", pstr);
558*c243e490SMarcel Moolenaar     } else {
559*c243e490SMarcel Moolenaar         int type = st->m_sb.st_mode & S_IFMT;
560*c243e490SMarcel Moolenaar         err = atf_no_error();
561*c243e490SMarcel Moolenaar         switch (type) {
562*c243e490SMarcel Moolenaar             case S_IFBLK:  st->m_type = atf_fs_stat_blk_type;  break;
563*c243e490SMarcel Moolenaar             case S_IFCHR:  st->m_type = atf_fs_stat_chr_type;  break;
564*c243e490SMarcel Moolenaar             case S_IFDIR:  st->m_type = atf_fs_stat_dir_type;  break;
565*c243e490SMarcel Moolenaar             case S_IFIFO:  st->m_type = atf_fs_stat_fifo_type; break;
566*c243e490SMarcel Moolenaar             case S_IFLNK:  st->m_type = atf_fs_stat_lnk_type;  break;
567*c243e490SMarcel Moolenaar             case S_IFREG:  st->m_type = atf_fs_stat_reg_type;  break;
568*c243e490SMarcel Moolenaar             case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
569*c243e490SMarcel Moolenaar #if defined(S_IFWHT)
570*c243e490SMarcel Moolenaar             case S_IFWHT:  st->m_type = atf_fs_stat_wht_type;  break;
571*c243e490SMarcel Moolenaar #endif
572*c243e490SMarcel Moolenaar             default:
573*c243e490SMarcel Moolenaar                 err = unknown_type_error(pstr, type);
574*c243e490SMarcel Moolenaar         }
575*c243e490SMarcel Moolenaar     }
576*c243e490SMarcel Moolenaar 
577*c243e490SMarcel Moolenaar     return err;
578*c243e490SMarcel Moolenaar }
579*c243e490SMarcel Moolenaar 
580*c243e490SMarcel Moolenaar void
581*c243e490SMarcel Moolenaar atf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
582*c243e490SMarcel Moolenaar {
583*c243e490SMarcel Moolenaar     dest->m_type = src->m_type;
584*c243e490SMarcel Moolenaar     dest->m_sb = src->m_sb;
585*c243e490SMarcel Moolenaar }
586*c243e490SMarcel Moolenaar 
587*c243e490SMarcel Moolenaar void
588*c243e490SMarcel Moolenaar atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
589*c243e490SMarcel Moolenaar {
590*c243e490SMarcel Moolenaar }
591*c243e490SMarcel Moolenaar 
592*c243e490SMarcel Moolenaar /*
593*c243e490SMarcel Moolenaar  * Getters.
594*c243e490SMarcel Moolenaar  */
595*c243e490SMarcel Moolenaar 
596*c243e490SMarcel Moolenaar dev_t
597*c243e490SMarcel Moolenaar atf_fs_stat_get_device(const atf_fs_stat_t *st)
598*c243e490SMarcel Moolenaar {
599*c243e490SMarcel Moolenaar     return st->m_sb.st_dev;
600*c243e490SMarcel Moolenaar }
601*c243e490SMarcel Moolenaar 
602*c243e490SMarcel Moolenaar ino_t
603*c243e490SMarcel Moolenaar atf_fs_stat_get_inode(const atf_fs_stat_t *st)
604*c243e490SMarcel Moolenaar {
605*c243e490SMarcel Moolenaar     return st->m_sb.st_ino;
606*c243e490SMarcel Moolenaar }
607*c243e490SMarcel Moolenaar 
608*c243e490SMarcel Moolenaar mode_t
609*c243e490SMarcel Moolenaar atf_fs_stat_get_mode(const atf_fs_stat_t *st)
610*c243e490SMarcel Moolenaar {
611*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & ~S_IFMT;
612*c243e490SMarcel Moolenaar }
613*c243e490SMarcel Moolenaar 
614*c243e490SMarcel Moolenaar off_t
615*c243e490SMarcel Moolenaar atf_fs_stat_get_size(const atf_fs_stat_t *st)
616*c243e490SMarcel Moolenaar {
617*c243e490SMarcel Moolenaar     return st->m_sb.st_size;
618*c243e490SMarcel Moolenaar }
619*c243e490SMarcel Moolenaar 
620*c243e490SMarcel Moolenaar int
621*c243e490SMarcel Moolenaar atf_fs_stat_get_type(const atf_fs_stat_t *st)
622*c243e490SMarcel Moolenaar {
623*c243e490SMarcel Moolenaar     return st->m_type;
624*c243e490SMarcel Moolenaar }
625*c243e490SMarcel Moolenaar 
626*c243e490SMarcel Moolenaar bool
627*c243e490SMarcel Moolenaar atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
628*c243e490SMarcel Moolenaar {
629*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IRUSR;
630*c243e490SMarcel Moolenaar }
631*c243e490SMarcel Moolenaar 
632*c243e490SMarcel Moolenaar bool
633*c243e490SMarcel Moolenaar atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
634*c243e490SMarcel Moolenaar {
635*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IWUSR;
636*c243e490SMarcel Moolenaar }
637*c243e490SMarcel Moolenaar 
638*c243e490SMarcel Moolenaar bool
639*c243e490SMarcel Moolenaar atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
640*c243e490SMarcel Moolenaar {
641*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IXUSR;
642*c243e490SMarcel Moolenaar }
643*c243e490SMarcel Moolenaar 
644*c243e490SMarcel Moolenaar bool
645*c243e490SMarcel Moolenaar atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
646*c243e490SMarcel Moolenaar {
647*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IRGRP;
648*c243e490SMarcel Moolenaar }
649*c243e490SMarcel Moolenaar 
650*c243e490SMarcel Moolenaar bool
651*c243e490SMarcel Moolenaar atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
652*c243e490SMarcel Moolenaar {
653*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IWGRP;
654*c243e490SMarcel Moolenaar }
655*c243e490SMarcel Moolenaar 
656*c243e490SMarcel Moolenaar bool
657*c243e490SMarcel Moolenaar atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
658*c243e490SMarcel Moolenaar {
659*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IXGRP;
660*c243e490SMarcel Moolenaar }
661*c243e490SMarcel Moolenaar 
662*c243e490SMarcel Moolenaar bool
663*c243e490SMarcel Moolenaar atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
664*c243e490SMarcel Moolenaar {
665*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IROTH;
666*c243e490SMarcel Moolenaar }
667*c243e490SMarcel Moolenaar 
668*c243e490SMarcel Moolenaar bool
669*c243e490SMarcel Moolenaar atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
670*c243e490SMarcel Moolenaar {
671*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IWOTH;
672*c243e490SMarcel Moolenaar }
673*c243e490SMarcel Moolenaar 
674*c243e490SMarcel Moolenaar bool
675*c243e490SMarcel Moolenaar atf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
676*c243e490SMarcel Moolenaar {
677*c243e490SMarcel Moolenaar     return st->m_sb.st_mode & S_IXOTH;
678*c243e490SMarcel Moolenaar }
679*c243e490SMarcel Moolenaar 
680*c243e490SMarcel Moolenaar /* ---------------------------------------------------------------------
681*c243e490SMarcel Moolenaar  * Free functions.
682*c243e490SMarcel Moolenaar  * --------------------------------------------------------------------- */
683*c243e490SMarcel Moolenaar 
684*c243e490SMarcel Moolenaar const int atf_fs_access_f = 1 << 0;
685*c243e490SMarcel Moolenaar const int atf_fs_access_r = 1 << 1;
686*c243e490SMarcel Moolenaar const int atf_fs_access_w = 1 << 2;
687*c243e490SMarcel Moolenaar const int atf_fs_access_x = 1 << 3;
688*c243e490SMarcel Moolenaar 
689*c243e490SMarcel Moolenaar /*
690*c243e490SMarcel Moolenaar  * An implementation of access(2) but using the effective user value
691*c243e490SMarcel Moolenaar  * instead of the real one.  Also avoids false positives for root when
692*c243e490SMarcel Moolenaar  * asking for execute permissions, which appear in SunOS.
693*c243e490SMarcel Moolenaar  */
694*c243e490SMarcel Moolenaar atf_error_t
695*c243e490SMarcel Moolenaar atf_fs_eaccess(const atf_fs_path_t *p, int mode)
696*c243e490SMarcel Moolenaar {
697*c243e490SMarcel Moolenaar     atf_error_t err;
698*c243e490SMarcel Moolenaar     struct stat st;
699*c243e490SMarcel Moolenaar     bool ok;
700*c243e490SMarcel Moolenaar 
701*c243e490SMarcel Moolenaar     PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
702*c243e490SMarcel Moolenaar         mode & atf_fs_access_w || mode & atf_fs_access_x);
703*c243e490SMarcel Moolenaar 
704*c243e490SMarcel Moolenaar     if (lstat(atf_fs_path_cstring(p), &st) == -1) {
705*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot get information from file %s",
706*c243e490SMarcel Moolenaar                              atf_fs_path_cstring(p));
707*c243e490SMarcel Moolenaar         goto out;
708*c243e490SMarcel Moolenaar     }
709*c243e490SMarcel Moolenaar 
710*c243e490SMarcel Moolenaar     err = atf_no_error();
711*c243e490SMarcel Moolenaar 
712*c243e490SMarcel Moolenaar     /* Early return if we are only checking for existence and the file
713*c243e490SMarcel Moolenaar      * exists (stat call returned). */
714*c243e490SMarcel Moolenaar     if (mode & atf_fs_access_f)
715*c243e490SMarcel Moolenaar         goto out;
716*c243e490SMarcel Moolenaar 
717*c243e490SMarcel Moolenaar     ok = false;
718*c243e490SMarcel Moolenaar     if (atf_user_is_root()) {
719*c243e490SMarcel Moolenaar         if (!ok && !(mode & atf_fs_access_x)) {
720*c243e490SMarcel Moolenaar             /* Allow root to read/write any file. */
721*c243e490SMarcel Moolenaar             ok = true;
722*c243e490SMarcel Moolenaar         }
723*c243e490SMarcel Moolenaar 
724*c243e490SMarcel Moolenaar         if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
725*c243e490SMarcel Moolenaar             /* Allow root to execute the file if any of its execution bits
726*c243e490SMarcel Moolenaar              * are set. */
727*c243e490SMarcel Moolenaar             ok = true;
728*c243e490SMarcel Moolenaar         }
729*c243e490SMarcel Moolenaar     } else {
730*c243e490SMarcel Moolenaar         if (!ok && (atf_user_euid() == st.st_uid)) {
731*c243e490SMarcel Moolenaar             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
732*c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
733*c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
734*c243e490SMarcel Moolenaar         }
735*c243e490SMarcel Moolenaar         if (!ok && atf_user_is_member_of_group(st.st_gid)) {
736*c243e490SMarcel Moolenaar             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
737*c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
738*c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
739*c243e490SMarcel Moolenaar         }
740*c243e490SMarcel Moolenaar         if (!ok && ((atf_user_euid() != st.st_uid) &&
741*c243e490SMarcel Moolenaar                     !atf_user_is_member_of_group(st.st_gid))) {
742*c243e490SMarcel Moolenaar             ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
743*c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
744*c243e490SMarcel Moolenaar                  ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
745*c243e490SMarcel Moolenaar         }
746*c243e490SMarcel Moolenaar     }
747*c243e490SMarcel Moolenaar 
748*c243e490SMarcel Moolenaar     if (!ok)
749*c243e490SMarcel Moolenaar         err = atf_libc_error(EACCES, "Access check failed");
750*c243e490SMarcel Moolenaar 
751*c243e490SMarcel Moolenaar out:
752*c243e490SMarcel Moolenaar     return err;
753*c243e490SMarcel Moolenaar }
754*c243e490SMarcel Moolenaar 
755*c243e490SMarcel Moolenaar atf_error_t
756*c243e490SMarcel Moolenaar atf_fs_exists(const atf_fs_path_t *p, bool *b)
757*c243e490SMarcel Moolenaar {
758*c243e490SMarcel Moolenaar     atf_error_t err;
759*c243e490SMarcel Moolenaar 
760*c243e490SMarcel Moolenaar     err = atf_fs_eaccess(p, atf_fs_access_f);
761*c243e490SMarcel Moolenaar     if (atf_is_error(err)) {
762*c243e490SMarcel Moolenaar         if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
763*c243e490SMarcel Moolenaar             atf_error_free(err);
764*c243e490SMarcel Moolenaar             err = atf_no_error();
765*c243e490SMarcel Moolenaar             *b = false;
766*c243e490SMarcel Moolenaar         }
767*c243e490SMarcel Moolenaar     } else
768*c243e490SMarcel Moolenaar         *b = true;
769*c243e490SMarcel Moolenaar 
770*c243e490SMarcel Moolenaar     return err;
771*c243e490SMarcel Moolenaar }
772*c243e490SMarcel Moolenaar 
773*c243e490SMarcel Moolenaar atf_error_t
774*c243e490SMarcel Moolenaar atf_fs_getcwd(atf_fs_path_t *p)
775*c243e490SMarcel Moolenaar {
776*c243e490SMarcel Moolenaar     atf_error_t err;
777*c243e490SMarcel Moolenaar     char *cwd;
778*c243e490SMarcel Moolenaar 
779*c243e490SMarcel Moolenaar #if defined(HAVE_GETCWD_DYN)
780*c243e490SMarcel Moolenaar     cwd = getcwd(NULL, 0);
781*c243e490SMarcel Moolenaar #else
782*c243e490SMarcel Moolenaar     cwd = getcwd(NULL, MAXPATHLEN);
783*c243e490SMarcel Moolenaar #endif
784*c243e490SMarcel Moolenaar     if (cwd == NULL) {
785*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot determine current directory");
786*c243e490SMarcel Moolenaar         goto out;
787*c243e490SMarcel Moolenaar     }
788*c243e490SMarcel Moolenaar 
789*c243e490SMarcel Moolenaar     err = atf_fs_path_init_fmt(p, "%s", cwd);
790*c243e490SMarcel Moolenaar     free(cwd);
791*c243e490SMarcel Moolenaar 
792*c243e490SMarcel Moolenaar out:
793*c243e490SMarcel Moolenaar     return err;
794*c243e490SMarcel Moolenaar }
795*c243e490SMarcel Moolenaar 
796*c243e490SMarcel Moolenaar atf_error_t
797*c243e490SMarcel Moolenaar atf_fs_mkdtemp(atf_fs_path_t *p)
798*c243e490SMarcel Moolenaar {
799*c243e490SMarcel Moolenaar     atf_error_t err;
800*c243e490SMarcel Moolenaar     char *buf;
801*c243e490SMarcel Moolenaar 
802*c243e490SMarcel Moolenaar     if (!check_umask(S_IRWXU, S_IRWXU)) {
803*c243e490SMarcel Moolenaar         err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
804*c243e490SMarcel Moolenaar         goto out;
805*c243e490SMarcel Moolenaar     }
806*c243e490SMarcel Moolenaar 
807*c243e490SMarcel Moolenaar     err = copy_contents(p, &buf);
808*c243e490SMarcel Moolenaar     if (atf_is_error(err))
809*c243e490SMarcel Moolenaar         goto out;
810*c243e490SMarcel Moolenaar 
811*c243e490SMarcel Moolenaar     err = do_mkdtemp(buf);
812*c243e490SMarcel Moolenaar     if (atf_is_error(err))
813*c243e490SMarcel Moolenaar         goto out_buf;
814*c243e490SMarcel Moolenaar 
815*c243e490SMarcel Moolenaar     replace_contents(p, buf);
816*c243e490SMarcel Moolenaar 
817*c243e490SMarcel Moolenaar     INV(!atf_is_error(err));
818*c243e490SMarcel Moolenaar out_buf:
819*c243e490SMarcel Moolenaar     free(buf);
820*c243e490SMarcel Moolenaar out:
821*c243e490SMarcel Moolenaar     return err;
822*c243e490SMarcel Moolenaar }
823*c243e490SMarcel Moolenaar 
824*c243e490SMarcel Moolenaar atf_error_t
825*c243e490SMarcel Moolenaar atf_fs_mkstemp(atf_fs_path_t *p, int *fdout)
826*c243e490SMarcel Moolenaar {
827*c243e490SMarcel Moolenaar     atf_error_t err;
828*c243e490SMarcel Moolenaar     char *buf;
829*c243e490SMarcel Moolenaar     int fd;
830*c243e490SMarcel Moolenaar 
831*c243e490SMarcel Moolenaar     if (!check_umask(S_IRWXU, S_IRWXU)) {
832*c243e490SMarcel Moolenaar         err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
833*c243e490SMarcel Moolenaar         goto out;
834*c243e490SMarcel Moolenaar     }
835*c243e490SMarcel Moolenaar 
836*c243e490SMarcel Moolenaar     err = copy_contents(p, &buf);
837*c243e490SMarcel Moolenaar     if (atf_is_error(err))
838*c243e490SMarcel Moolenaar         goto out;
839*c243e490SMarcel Moolenaar 
840*c243e490SMarcel Moolenaar     err = do_mkstemp(buf, &fd);
841*c243e490SMarcel Moolenaar     if (atf_is_error(err))
842*c243e490SMarcel Moolenaar         goto out_buf;
843*c243e490SMarcel Moolenaar 
844*c243e490SMarcel Moolenaar     replace_contents(p, buf);
845*c243e490SMarcel Moolenaar     *fdout = fd;
846*c243e490SMarcel Moolenaar 
847*c243e490SMarcel Moolenaar     INV(!atf_is_error(err));
848*c243e490SMarcel Moolenaar out_buf:
849*c243e490SMarcel Moolenaar     free(buf);
850*c243e490SMarcel Moolenaar out:
851*c243e490SMarcel Moolenaar     return err;
852*c243e490SMarcel Moolenaar }
853*c243e490SMarcel Moolenaar 
854*c243e490SMarcel Moolenaar atf_error_t
855*c243e490SMarcel Moolenaar atf_fs_rmdir(const atf_fs_path_t *p)
856*c243e490SMarcel Moolenaar {
857*c243e490SMarcel Moolenaar     atf_error_t err;
858*c243e490SMarcel Moolenaar 
859*c243e490SMarcel Moolenaar     if (rmdir(atf_fs_path_cstring(p))) {
860*c243e490SMarcel Moolenaar         if (errno == EEXIST) {
861*c243e490SMarcel Moolenaar             /* Some operating systems (e.g. OpenSolaris 200906) return
862*c243e490SMarcel Moolenaar              * EEXIST instead of ENOTEMPTY for non-empty directories.
863*c243e490SMarcel Moolenaar              * Homogenize the return value so that callers don't need
864*c243e490SMarcel Moolenaar              * to bother about differences in operating systems. */
865*c243e490SMarcel Moolenaar             errno = ENOTEMPTY;
866*c243e490SMarcel Moolenaar         }
867*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot remove directory");
868*c243e490SMarcel Moolenaar     } else
869*c243e490SMarcel Moolenaar         err = atf_no_error();
870*c243e490SMarcel Moolenaar 
871*c243e490SMarcel Moolenaar     return err;
872*c243e490SMarcel Moolenaar }
873*c243e490SMarcel Moolenaar 
874*c243e490SMarcel Moolenaar atf_error_t
875*c243e490SMarcel Moolenaar atf_fs_unlink(const atf_fs_path_t *p)
876*c243e490SMarcel Moolenaar {
877*c243e490SMarcel Moolenaar     atf_error_t err;
878*c243e490SMarcel Moolenaar     const char *path;
879*c243e490SMarcel Moolenaar 
880*c243e490SMarcel Moolenaar     path = atf_fs_path_cstring(p);
881*c243e490SMarcel Moolenaar 
882*c243e490SMarcel Moolenaar     if (unlink(path) != 0)
883*c243e490SMarcel Moolenaar         err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);
884*c243e490SMarcel Moolenaar     else
885*c243e490SMarcel Moolenaar         err = atf_no_error();
886*c243e490SMarcel Moolenaar 
887*c243e490SMarcel Moolenaar     return err;
888*c243e490SMarcel Moolenaar }
889