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