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