1240116Smarcel/*
2240116Smarcel * Automated Testing Framework (atf)
3240116Smarcel *
4240116Smarcel * Copyright (c) 2007 The NetBSD Foundation, Inc.
5240116Smarcel * All rights reserved.
6240116Smarcel *
7240116Smarcel * Redistribution and use in source and binary forms, with or without
8240116Smarcel * modification, are permitted provided that the following conditions
9240116Smarcel * are met:
10240116Smarcel * 1. Redistributions of source code must retain the above copyright
11240116Smarcel *    notice, this list of conditions and the following disclaimer.
12240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
13240116Smarcel *    notice, this list of conditions and the following disclaimer in the
14240116Smarcel *    documentation and/or other materials provided with the distribution.
15240116Smarcel *
16240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27240116Smarcel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28240116Smarcel */
29240116Smarcel
30240116Smarcel#if defined(HAVE_CONFIG_H)
31240116Smarcel#include "bconfig.h"
32240116Smarcel#endif
33240116Smarcel
34240116Smarcel#include <sys/types.h>
35240116Smarcel#include <sys/param.h>
36240116Smarcel#include <sys/mount.h>
37240116Smarcel#include <sys/stat.h>
38240116Smarcel#include <sys/wait.h>
39240116Smarcel
40240116Smarcel#include <dirent.h>
41240116Smarcel#include <errno.h>
42240116Smarcel#include <libgen.h>
43240116Smarcel#include <stdarg.h>
44240116Smarcel#include <stdio.h>
45240116Smarcel#include <stdlib.h>
46240116Smarcel#include <string.h>
47240116Smarcel#include <unistd.h>
48240116Smarcel
49240116Smarcel#include "atf-c/defs.h"
50240116Smarcel#include "atf-c/error.h"
51240116Smarcel
52240116Smarcel#include "fs.h"
53240116Smarcel#include "sanity.h"
54240116Smarcel#include "text.h"
55240116Smarcel#include "user.h"
56240116Smarcel
57240116Smarcel/* ---------------------------------------------------------------------
58240116Smarcel * Prototypes for auxiliary functions.
59240116Smarcel * --------------------------------------------------------------------- */
60240116Smarcel
61240116Smarcelstatic bool check_umask(const mode_t, const mode_t);
62240116Smarcelstatic atf_error_t copy_contents(const atf_fs_path_t *, char **);
63240116Smarcelstatic mode_t current_umask(void);
64240116Smarcelstatic atf_error_t do_mkdtemp(char *);
65240116Smarcelstatic atf_error_t normalize(atf_dynstr_t *, char *);
66240116Smarcelstatic atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list);
67240116Smarcelstatic void replace_contents(atf_fs_path_t *, const char *);
68240116Smarcelstatic const char *stat_type_to_string(const int);
69240116Smarcel
70240116Smarcel/* ---------------------------------------------------------------------
71240116Smarcel * The "invalid_umask" error type.
72240116Smarcel * --------------------------------------------------------------------- */
73240116Smarcel
74240116Smarcelstruct invalid_umask_error_data {
75240116Smarcel    /* One of atf_fs_stat_*_type. */
76240116Smarcel    int m_type;
77240116Smarcel
78240116Smarcel    /* The original path causing the error. */
79240116Smarcel    /* XXX: Ideally this would be an atf_fs_path_t, but if we create it
80240116Smarcel     * from the error constructor, we cannot delete the path later on.
81240116Smarcel     * Can't remember why atf_error_new does not take a hook for
82240116Smarcel     * deletion. */
83240116Smarcel    char m_path[1024];
84240116Smarcel
85240116Smarcel    /* The umask that caused the error. */
86240116Smarcel    mode_t m_umask;
87240116Smarcel};
88240116Smarceltypedef struct invalid_umask_error_data invalid_umask_error_data_t;
89240116Smarcel
90240116Smarcelstatic
91240116Smarcelvoid
92240116Smarcelinvalid_umask_format(const atf_error_t err, char *buf, size_t buflen)
93240116Smarcel{
94240116Smarcel    const invalid_umask_error_data_t *data;
95240116Smarcel
96240116Smarcel    PRE(atf_error_is(err, "invalid_umask"));
97240116Smarcel
98240116Smarcel    data = atf_error_data(err);
99240116Smarcel    snprintf(buf, buflen, "Could not create the temporary %s %s because "
100240116Smarcel             "it will not have enough access rights due to the current "
101240116Smarcel             "umask %05o", stat_type_to_string(data->m_type),
102240116Smarcel             data->m_path, (unsigned int)data->m_umask);
103240116Smarcel}
104240116Smarcel
105240116Smarcelstatic
106240116Smarcelatf_error_t
107240116Smarcelinvalid_umask_error(const atf_fs_path_t *path, const int type,
108240116Smarcel                    const mode_t failing_mask)
109240116Smarcel{
110240116Smarcel    atf_error_t err;
111240116Smarcel    invalid_umask_error_data_t data;
112240116Smarcel
113240116Smarcel    data.m_type = type;
114240116Smarcel
115240116Smarcel    strncpy(data.m_path, atf_fs_path_cstring(path), sizeof(data.m_path));
116240116Smarcel    data.m_path[sizeof(data.m_path) - 1] = '\0';
117240116Smarcel
118240116Smarcel    data.m_umask = failing_mask;
119240116Smarcel
120240116Smarcel    err = atf_error_new("invalid_umask", &data, sizeof(data),
121240116Smarcel                        invalid_umask_format);
122240116Smarcel
123240116Smarcel    return err;
124240116Smarcel}
125240116Smarcel
126240116Smarcel/* ---------------------------------------------------------------------
127240116Smarcel * The "unknown_file_type" error type.
128240116Smarcel * --------------------------------------------------------------------- */
129240116Smarcel
130240116Smarcelstruct unknown_type_error_data {
131240116Smarcel    const char *m_path;
132240116Smarcel    int m_type;
133240116Smarcel};
134240116Smarceltypedef struct unknown_type_error_data unknown_type_error_data_t;
135240116Smarcel
136240116Smarcelstatic
137240116Smarcelvoid
138240116Smarcelunknown_type_format(const atf_error_t err, char *buf, size_t buflen)
139240116Smarcel{
140240116Smarcel    const unknown_type_error_data_t *data;
141240116Smarcel
142240116Smarcel    PRE(atf_error_is(err, "unknown_type"));
143240116Smarcel
144240116Smarcel    data = atf_error_data(err);
145240116Smarcel    snprintf(buf, buflen, "Unknown file type %d of %s", data->m_type,
146240116Smarcel             data->m_path);
147240116Smarcel}
148240116Smarcel
149240116Smarcelstatic
150240116Smarcelatf_error_t
151240116Smarcelunknown_type_error(const char *path, int type)
152240116Smarcel{
153240116Smarcel    atf_error_t err;
154240116Smarcel    unknown_type_error_data_t data;
155240116Smarcel
156240116Smarcel    data.m_path = path;
157240116Smarcel    data.m_type = type;
158240116Smarcel
159240116Smarcel    err = atf_error_new("unknown_type", &data, sizeof(data),
160240116Smarcel                        unknown_type_format);
161240116Smarcel
162240116Smarcel    return err;
163240116Smarcel}
164240116Smarcel
165240116Smarcel/* ---------------------------------------------------------------------
166240116Smarcel * Auxiliary functions.
167240116Smarcel * --------------------------------------------------------------------- */
168240116Smarcel
169240116Smarcelstatic
170240116Smarcelbool
171240116Smarcelcheck_umask(const mode_t exp_mode, const mode_t min_mode)
172240116Smarcel{
173240116Smarcel    const mode_t actual_mode = (~current_umask() & exp_mode);
174240116Smarcel    return (actual_mode & min_mode) == min_mode;
175240116Smarcel}
176240116Smarcel
177240116Smarcelstatic
178240116Smarcelatf_error_t
179240116Smarcelcopy_contents(const atf_fs_path_t *p, char **buf)
180240116Smarcel{
181240116Smarcel    atf_error_t err;
182240116Smarcel    char *str;
183240116Smarcel
184240116Smarcel    str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1);
185240116Smarcel    if (str == NULL)
186240116Smarcel        err = atf_no_memory_error();
187240116Smarcel    else {
188240116Smarcel        strcpy(str, atf_dynstr_cstring(&p->m_data));
189240116Smarcel        *buf = str;
190240116Smarcel        err = atf_no_error();
191240116Smarcel    }
192240116Smarcel
193240116Smarcel    return err;
194240116Smarcel}
195240116Smarcel
196240116Smarcelstatic
197240116Smarcelmode_t
198240116Smarcelcurrent_umask(void)
199240116Smarcel{
200240116Smarcel    const mode_t current = umask(0);
201240116Smarcel    (void)umask(current);
202240116Smarcel    return current;
203240116Smarcel}
204240116Smarcel
205240116Smarcelstatic
206240116Smarcelatf_error_t
207240116Smarceldo_mkdtemp(char *tmpl)
208240116Smarcel{
209240116Smarcel    atf_error_t err;
210240116Smarcel
211240116Smarcel    PRE(strstr(tmpl, "XXXXXX") != NULL);
212240116Smarcel
213240116Smarcel    if (mkdtemp(tmpl) == NULL)
214240116Smarcel        err = atf_libc_error(errno, "Cannot create temporary directory "
215240116Smarcel                             "with template '%s'", tmpl);
216240116Smarcel    else
217240116Smarcel        err = atf_no_error();
218240116Smarcel
219240116Smarcel    return err;
220240116Smarcel}
221240116Smarcel
222240116Smarcelstatic
223240116Smarcelatf_error_t
224240116Smarceldo_mkstemp(char *tmpl, int *fdout)
225240116Smarcel{
226240116Smarcel    atf_error_t err;
227240116Smarcel
228240116Smarcel    PRE(strstr(tmpl, "XXXXXX") != NULL);
229240116Smarcel
230240116Smarcel    *fdout = mkstemp(tmpl);
231240116Smarcel    if (*fdout == -1)
232240116Smarcel        err = atf_libc_error(errno, "Cannot create temporary file "
233240116Smarcel                             "with template '%s'", tmpl);
234240116Smarcel
235240116Smarcel    else
236240116Smarcel        err = atf_no_error();
237240116Smarcel
238240116Smarcel    return err;
239240116Smarcel}
240240116Smarcel
241240116Smarcelstatic
242240116Smarcelatf_error_t
243240116Smarcelnormalize(atf_dynstr_t *d, char *p)
244240116Smarcel{
245240116Smarcel    const char *ptr;
246240116Smarcel    char *last;
247240116Smarcel    atf_error_t err;
248240116Smarcel    bool first;
249240116Smarcel
250240116Smarcel    PRE(strlen(p) > 0);
251240116Smarcel    PRE(atf_dynstr_length(d) == 0);
252240116Smarcel
253240116Smarcel    if (p[0] == '/')
254240116Smarcel        err = atf_dynstr_append_fmt(d, "/");
255240116Smarcel    else
256240116Smarcel        err = atf_no_error();
257240116Smarcel
258240116Smarcel    first = true;
259240116Smarcel    last = NULL; /* Silence GCC warning. */
260240116Smarcel    ptr = strtok_r(p, "/", &last);
261240116Smarcel    while (!atf_is_error(err) && ptr != NULL) {
262240116Smarcel        if (strlen(ptr) > 0) {
263240116Smarcel            err = atf_dynstr_append_fmt(d, "%s%s", first ? "" : "/", ptr);
264240116Smarcel            first = false;
265240116Smarcel        }
266240116Smarcel
267240116Smarcel        ptr = strtok_r(NULL, "/", &last);
268240116Smarcel    }
269240116Smarcel
270240116Smarcel    return err;
271240116Smarcel}
272240116Smarcel
273240116Smarcelstatic
274240116Smarcelatf_error_t
275240116Smarcelnormalize_ap(atf_dynstr_t *d, const char *p, va_list ap)
276240116Smarcel{
277240116Smarcel    char *str;
278240116Smarcel    atf_error_t err;
279240116Smarcel    va_list ap2;
280240116Smarcel
281240116Smarcel    err = atf_dynstr_init(d);
282240116Smarcel    if (atf_is_error(err))
283240116Smarcel        goto out;
284240116Smarcel
285240116Smarcel    va_copy(ap2, ap);
286240116Smarcel    err = atf_text_format_ap(&str, p, ap2);
287240116Smarcel    va_end(ap2);
288240116Smarcel    if (atf_is_error(err))
289240116Smarcel        atf_dynstr_fini(d);
290240116Smarcel    else {
291240116Smarcel        err = normalize(d, str);
292240116Smarcel        free(str);
293240116Smarcel    }
294240116Smarcel
295240116Smarcelout:
296240116Smarcel    return err;
297240116Smarcel}
298240116Smarcel
299240116Smarcelstatic
300240116Smarcelvoid
301240116Smarcelreplace_contents(atf_fs_path_t *p, const char *buf)
302240116Smarcel{
303240116Smarcel    atf_error_t err;
304240116Smarcel
305240116Smarcel    PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
306240116Smarcel
307240116Smarcel    atf_dynstr_clear(&p->m_data);
308240116Smarcel    err = atf_dynstr_append_fmt(&p->m_data, "%s", buf);
309240116Smarcel
310240116Smarcel    INV(!atf_is_error(err));
311240116Smarcel}
312240116Smarcel
313240116Smarcelstatic
314240116Smarcelconst char *
315240116Smarcelstat_type_to_string(const int type)
316240116Smarcel{
317240116Smarcel    const char *str;
318240116Smarcel
319240116Smarcel    if (type == atf_fs_stat_blk_type)
320240116Smarcel        str = "block device";
321240116Smarcel    else if (type == atf_fs_stat_chr_type)
322240116Smarcel        str = "character device";
323240116Smarcel    else if (type == atf_fs_stat_dir_type)
324240116Smarcel        str = "directory";
325240116Smarcel    else if (type == atf_fs_stat_fifo_type)
326240116Smarcel        str = "named pipe";
327240116Smarcel    else if (type == atf_fs_stat_lnk_type)
328240116Smarcel        str = "symbolic link";
329240116Smarcel    else if (type == atf_fs_stat_reg_type)
330240116Smarcel        str = "regular file";
331240116Smarcel    else if (type == atf_fs_stat_sock_type)
332240116Smarcel        str = "socket";
333240116Smarcel    else if (type == atf_fs_stat_wht_type)
334240116Smarcel        str = "whiteout";
335240116Smarcel    else {
336240116Smarcel        UNREACHABLE;
337240116Smarcel        str = NULL;
338240116Smarcel    }
339240116Smarcel
340240116Smarcel    return str;
341240116Smarcel}
342240116Smarcel
343240116Smarcel/* ---------------------------------------------------------------------
344240116Smarcel * The "atf_fs_path" type.
345240116Smarcel * --------------------------------------------------------------------- */
346240116Smarcel
347240116Smarcel/*
348240116Smarcel * Constructors/destructors.
349240116Smarcel */
350240116Smarcel
351240116Smarcelatf_error_t
352240116Smarcelatf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
353240116Smarcel{
354240116Smarcel    atf_error_t err;
355240116Smarcel    va_list ap2;
356240116Smarcel
357240116Smarcel    va_copy(ap2, ap);
358240116Smarcel    err = normalize_ap(&p->m_data, fmt, ap2);
359240116Smarcel    va_end(ap2);
360240116Smarcel
361240116Smarcel    return err;
362240116Smarcel}
363240116Smarcel
364240116Smarcelatf_error_t
365240116Smarcelatf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
366240116Smarcel{
367240116Smarcel    va_list ap;
368240116Smarcel    atf_error_t err;
369240116Smarcel
370240116Smarcel    va_start(ap, fmt);
371240116Smarcel    err = atf_fs_path_init_ap(p, fmt, ap);
372240116Smarcel    va_end(ap);
373240116Smarcel
374240116Smarcel    return err;
375240116Smarcel}
376240116Smarcel
377240116Smarcelatf_error_t
378240116Smarcelatf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
379240116Smarcel{
380240116Smarcel    return atf_dynstr_copy(&dest->m_data, &src->m_data);
381240116Smarcel}
382240116Smarcel
383240116Smarcelvoid
384240116Smarcelatf_fs_path_fini(atf_fs_path_t *p)
385240116Smarcel{
386240116Smarcel    atf_dynstr_fini(&p->m_data);
387240116Smarcel}
388240116Smarcel
389240116Smarcel/*
390240116Smarcel * Getters.
391240116Smarcel */
392240116Smarcel
393240116Smarcelatf_error_t
394240116Smarcelatf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
395240116Smarcel{
396240116Smarcel    const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
397240116Smarcel    atf_error_t err;
398240116Smarcel
399240116Smarcel    if (endpos == atf_dynstr_npos)
400240116Smarcel        err = atf_fs_path_init_fmt(bp, ".");
401240116Smarcel    else if (endpos == 0)
402240116Smarcel        err = atf_fs_path_init_fmt(bp, "/");
403240116Smarcel    else
404240116Smarcel        err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
405240116Smarcel
406240116Smarcel#if defined(HAVE_CONST_DIRNAME)
407240116Smarcel    INV(atf_equal_dynstr_cstring(&bp->m_data,
408240116Smarcel                                 dirname(atf_dynstr_cstring(&p->m_data))));
409240116Smarcel#endif /* defined(HAVE_CONST_DIRNAME) */
410240116Smarcel
411240116Smarcel    return err;
412240116Smarcel}
413240116Smarcel
414240116Smarcelconst char *
415240116Smarcelatf_fs_path_cstring(const atf_fs_path_t *p)
416240116Smarcel{
417240116Smarcel    return atf_dynstr_cstring(&p->m_data);
418240116Smarcel}
419240116Smarcel
420240116Smarcelatf_error_t
421240116Smarcelatf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
422240116Smarcel{
423240116Smarcel    size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
424240116Smarcel    atf_error_t err;
425240116Smarcel
426240116Smarcel    if (begpos == atf_dynstr_npos)
427240116Smarcel        begpos = 0;
428240116Smarcel    else
429240116Smarcel        begpos++;
430240116Smarcel
431240116Smarcel    err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
432240116Smarcel
433240116Smarcel#if defined(HAVE_CONST_BASENAME)
434240116Smarcel    INV(atf_equal_dynstr_cstring(ln,
435240116Smarcel                                 basename(atf_dynstr_cstring(&p->m_data))));
436240116Smarcel#endif /* defined(HAVE_CONST_BASENAME) */
437240116Smarcel
438240116Smarcel    return err;
439240116Smarcel}
440240116Smarcel
441240116Smarcelbool
442240116Smarcelatf_fs_path_is_absolute(const atf_fs_path_t *p)
443240116Smarcel{
444240116Smarcel    return atf_dynstr_cstring(&p->m_data)[0] == '/';
445240116Smarcel}
446240116Smarcel
447240116Smarcelbool
448240116Smarcelatf_fs_path_is_root(const atf_fs_path_t *p)
449240116Smarcel{
450240116Smarcel    return atf_equal_dynstr_cstring(&p->m_data, "/");
451240116Smarcel}
452240116Smarcel
453240116Smarcel/*
454240116Smarcel * Modifiers.
455240116Smarcel */
456240116Smarcel
457240116Smarcelatf_error_t
458240116Smarcelatf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
459240116Smarcel{
460240116Smarcel    atf_dynstr_t aux;
461240116Smarcel    atf_error_t err;
462240116Smarcel    va_list ap2;
463240116Smarcel
464240116Smarcel    va_copy(ap2, ap);
465240116Smarcel    err = normalize_ap(&aux, fmt, ap2);
466240116Smarcel    va_end(ap2);
467240116Smarcel    if (!atf_is_error(err)) {
468240116Smarcel        const char *auxstr = atf_dynstr_cstring(&aux);
469240116Smarcel        const bool needslash = auxstr[0] != '/';
470240116Smarcel
471240116Smarcel        err = atf_dynstr_append_fmt(&p->m_data, "%s%s",
472240116Smarcel                                    needslash ? "/" : "", auxstr);
473240116Smarcel
474240116Smarcel        atf_dynstr_fini(&aux);
475240116Smarcel    }
476240116Smarcel
477240116Smarcel    return err;
478240116Smarcel}
479240116Smarcel
480240116Smarcelatf_error_t
481240116Smarcelatf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
482240116Smarcel{
483240116Smarcel    va_list ap;
484240116Smarcel    atf_error_t err;
485240116Smarcel
486240116Smarcel    va_start(ap, fmt);
487240116Smarcel    err = atf_fs_path_append_ap(p, fmt, ap);
488240116Smarcel    va_end(ap);
489240116Smarcel
490240116Smarcel    return err;
491240116Smarcel}
492240116Smarcel
493240116Smarcelatf_error_t
494240116Smarcelatf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
495240116Smarcel{
496240116Smarcel    return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
497240116Smarcel}
498240116Smarcel
499240116Smarcelatf_error_t
500240116Smarcelatf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
501240116Smarcel{
502240116Smarcel    atf_error_t err;
503240116Smarcel
504240116Smarcel    PRE(!atf_fs_path_is_absolute(p));
505240116Smarcel
506240116Smarcel    err = atf_fs_getcwd(pa);
507240116Smarcel    if (atf_is_error(err))
508240116Smarcel        goto out;
509240116Smarcel
510240116Smarcel    err = atf_fs_path_append_path(pa, p);
511240116Smarcel    if (atf_is_error(err))
512240116Smarcel        atf_fs_path_fini(pa);
513240116Smarcel
514240116Smarcelout:
515240116Smarcel    return err;
516240116Smarcel}
517240116Smarcel
518240116Smarcel/*
519240116Smarcel * Operators.
520240116Smarcel */
521240116Smarcel
522240116Smarcelbool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
523240116Smarcel                               const atf_fs_path_t *p2)
524240116Smarcel{
525240116Smarcel    return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
526240116Smarcel}
527240116Smarcel
528240116Smarcel/* ---------------------------------------------------------------------
529240116Smarcel * The "atf_fs_path" type.
530240116Smarcel * --------------------------------------------------------------------- */
531240116Smarcel
532240116Smarcel/*
533240116Smarcel * Constants.
534240116Smarcel */
535240116Smarcel
536240116Smarcelconst int atf_fs_stat_blk_type  = 1;
537240116Smarcelconst int atf_fs_stat_chr_type  = 2;
538240116Smarcelconst int atf_fs_stat_dir_type  = 3;
539240116Smarcelconst int atf_fs_stat_fifo_type = 4;
540240116Smarcelconst int atf_fs_stat_lnk_type  = 5;
541240116Smarcelconst int atf_fs_stat_reg_type  = 6;
542240116Smarcelconst int atf_fs_stat_sock_type = 7;
543240116Smarcelconst int atf_fs_stat_wht_type  = 8;
544240116Smarcel
545240116Smarcel/*
546240116Smarcel * Constructors/destructors.
547240116Smarcel */
548240116Smarcel
549240116Smarcelatf_error_t
550240116Smarcelatf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
551240116Smarcel{
552240116Smarcel    atf_error_t err;
553240116Smarcel    const char *pstr = atf_fs_path_cstring(p);
554240116Smarcel
555240116Smarcel    if (lstat(pstr, &st->m_sb) == -1) {
556240116Smarcel        err = atf_libc_error(errno, "Cannot get information of %s; "
557240116Smarcel                             "lstat(2) failed", pstr);
558240116Smarcel    } else {
559240116Smarcel        int type = st->m_sb.st_mode & S_IFMT;
560240116Smarcel        err = atf_no_error();
561240116Smarcel        switch (type) {
562240116Smarcel            case S_IFBLK:  st->m_type = atf_fs_stat_blk_type;  break;
563240116Smarcel            case S_IFCHR:  st->m_type = atf_fs_stat_chr_type;  break;
564240116Smarcel            case S_IFDIR:  st->m_type = atf_fs_stat_dir_type;  break;
565240116Smarcel            case S_IFIFO:  st->m_type = atf_fs_stat_fifo_type; break;
566240116Smarcel            case S_IFLNK:  st->m_type = atf_fs_stat_lnk_type;  break;
567240116Smarcel            case S_IFREG:  st->m_type = atf_fs_stat_reg_type;  break;
568240116Smarcel            case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
569240116Smarcel#if defined(S_IFWHT)
570240116Smarcel            case S_IFWHT:  st->m_type = atf_fs_stat_wht_type;  break;
571240116Smarcel#endif
572240116Smarcel            default:
573240116Smarcel                err = unknown_type_error(pstr, type);
574240116Smarcel        }
575240116Smarcel    }
576240116Smarcel
577240116Smarcel    return err;
578240116Smarcel}
579240116Smarcel
580240116Smarcelvoid
581240116Smarcelatf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
582240116Smarcel{
583240116Smarcel    dest->m_type = src->m_type;
584240116Smarcel    dest->m_sb = src->m_sb;
585240116Smarcel}
586240116Smarcel
587240116Smarcelvoid
588240116Smarcelatf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
589240116Smarcel{
590240116Smarcel}
591240116Smarcel
592240116Smarcel/*
593240116Smarcel * Getters.
594240116Smarcel */
595240116Smarcel
596240116Smarceldev_t
597240116Smarcelatf_fs_stat_get_device(const atf_fs_stat_t *st)
598240116Smarcel{
599240116Smarcel    return st->m_sb.st_dev;
600240116Smarcel}
601240116Smarcel
602240116Smarcelino_t
603240116Smarcelatf_fs_stat_get_inode(const atf_fs_stat_t *st)
604240116Smarcel{
605240116Smarcel    return st->m_sb.st_ino;
606240116Smarcel}
607240116Smarcel
608240116Smarcelmode_t
609240116Smarcelatf_fs_stat_get_mode(const atf_fs_stat_t *st)
610240116Smarcel{
611240116Smarcel    return st->m_sb.st_mode & ~S_IFMT;
612240116Smarcel}
613240116Smarcel
614240116Smarceloff_t
615240116Smarcelatf_fs_stat_get_size(const atf_fs_stat_t *st)
616240116Smarcel{
617240116Smarcel    return st->m_sb.st_size;
618240116Smarcel}
619240116Smarcel
620240116Smarcelint
621240116Smarcelatf_fs_stat_get_type(const atf_fs_stat_t *st)
622240116Smarcel{
623240116Smarcel    return st->m_type;
624240116Smarcel}
625240116Smarcel
626240116Smarcelbool
627240116Smarcelatf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
628240116Smarcel{
629240116Smarcel    return st->m_sb.st_mode & S_IRUSR;
630240116Smarcel}
631240116Smarcel
632240116Smarcelbool
633240116Smarcelatf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
634240116Smarcel{
635240116Smarcel    return st->m_sb.st_mode & S_IWUSR;
636240116Smarcel}
637240116Smarcel
638240116Smarcelbool
639240116Smarcelatf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
640240116Smarcel{
641240116Smarcel    return st->m_sb.st_mode & S_IXUSR;
642240116Smarcel}
643240116Smarcel
644240116Smarcelbool
645240116Smarcelatf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
646240116Smarcel{
647240116Smarcel    return st->m_sb.st_mode & S_IRGRP;
648240116Smarcel}
649240116Smarcel
650240116Smarcelbool
651240116Smarcelatf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
652240116Smarcel{
653240116Smarcel    return st->m_sb.st_mode & S_IWGRP;
654240116Smarcel}
655240116Smarcel
656240116Smarcelbool
657240116Smarcelatf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
658240116Smarcel{
659240116Smarcel    return st->m_sb.st_mode & S_IXGRP;
660240116Smarcel}
661240116Smarcel
662240116Smarcelbool
663240116Smarcelatf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
664240116Smarcel{
665240116Smarcel    return st->m_sb.st_mode & S_IROTH;
666240116Smarcel}
667240116Smarcel
668240116Smarcelbool
669240116Smarcelatf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
670240116Smarcel{
671240116Smarcel    return st->m_sb.st_mode & S_IWOTH;
672240116Smarcel}
673240116Smarcel
674240116Smarcelbool
675240116Smarcelatf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
676240116Smarcel{
677240116Smarcel    return st->m_sb.st_mode & S_IXOTH;
678240116Smarcel}
679240116Smarcel
680240116Smarcel/* ---------------------------------------------------------------------
681240116Smarcel * Free functions.
682240116Smarcel * --------------------------------------------------------------------- */
683240116Smarcel
684240116Smarcelconst int atf_fs_access_f = 1 << 0;
685240116Smarcelconst int atf_fs_access_r = 1 << 1;
686240116Smarcelconst int atf_fs_access_w = 1 << 2;
687240116Smarcelconst int atf_fs_access_x = 1 << 3;
688240116Smarcel
689240116Smarcel/*
690240116Smarcel * An implementation of access(2) but using the effective user value
691240116Smarcel * instead of the real one.  Also avoids false positives for root when
692240116Smarcel * asking for execute permissions, which appear in SunOS.
693240116Smarcel */
694240116Smarcelatf_error_t
695240116Smarcelatf_fs_eaccess(const atf_fs_path_t *p, int mode)
696240116Smarcel{
697240116Smarcel    atf_error_t err;
698240116Smarcel    struct stat st;
699240116Smarcel    bool ok;
700240116Smarcel
701240116Smarcel    PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
702240116Smarcel        mode & atf_fs_access_w || mode & atf_fs_access_x);
703240116Smarcel
704240116Smarcel    if (lstat(atf_fs_path_cstring(p), &st) == -1) {
705240116Smarcel        err = atf_libc_error(errno, "Cannot get information from file %s",
706240116Smarcel                             atf_fs_path_cstring(p));
707240116Smarcel        goto out;
708240116Smarcel    }
709240116Smarcel
710240116Smarcel    err = atf_no_error();
711240116Smarcel
712240116Smarcel    /* Early return if we are only checking for existence and the file
713240116Smarcel     * exists (stat call returned). */
714240116Smarcel    if (mode & atf_fs_access_f)
715240116Smarcel        goto out;
716240116Smarcel
717240116Smarcel    ok = false;
718240116Smarcel    if (atf_user_is_root()) {
719240116Smarcel        if (!ok && !(mode & atf_fs_access_x)) {
720240116Smarcel            /* Allow root to read/write any file. */
721240116Smarcel            ok = true;
722240116Smarcel        }
723240116Smarcel
724240116Smarcel        if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
725240116Smarcel            /* Allow root to execute the file if any of its execution bits
726240116Smarcel             * are set. */
727240116Smarcel            ok = true;
728240116Smarcel        }
729240116Smarcel    } else {
730240116Smarcel        if (!ok && (atf_user_euid() == st.st_uid)) {
731240116Smarcel            ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
732240116Smarcel                 ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
733240116Smarcel                 ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
734240116Smarcel        }
735240116Smarcel        if (!ok && atf_user_is_member_of_group(st.st_gid)) {
736240116Smarcel            ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
737240116Smarcel                 ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
738240116Smarcel                 ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
739240116Smarcel        }
740240116Smarcel        if (!ok && ((atf_user_euid() != st.st_uid) &&
741240116Smarcel                    !atf_user_is_member_of_group(st.st_gid))) {
742240116Smarcel            ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
743240116Smarcel                 ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
744240116Smarcel                 ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
745240116Smarcel        }
746240116Smarcel    }
747240116Smarcel
748240116Smarcel    if (!ok)
749240116Smarcel        err = atf_libc_error(EACCES, "Access check failed");
750240116Smarcel
751240116Smarcelout:
752240116Smarcel    return err;
753240116Smarcel}
754240116Smarcel
755240116Smarcelatf_error_t
756240116Smarcelatf_fs_exists(const atf_fs_path_t *p, bool *b)
757240116Smarcel{
758240116Smarcel    atf_error_t err;
759240116Smarcel
760240116Smarcel    err = atf_fs_eaccess(p, atf_fs_access_f);
761240116Smarcel    if (atf_is_error(err)) {
762240116Smarcel        if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
763240116Smarcel            atf_error_free(err);
764240116Smarcel            err = atf_no_error();
765240116Smarcel            *b = false;
766240116Smarcel        }
767240116Smarcel    } else
768240116Smarcel        *b = true;
769240116Smarcel
770240116Smarcel    return err;
771240116Smarcel}
772240116Smarcel
773240116Smarcelatf_error_t
774240116Smarcelatf_fs_getcwd(atf_fs_path_t *p)
775240116Smarcel{
776240116Smarcel    atf_error_t err;
777240116Smarcel    char *cwd;
778240116Smarcel
779240116Smarcel#if defined(HAVE_GETCWD_DYN)
780240116Smarcel    cwd = getcwd(NULL, 0);
781240116Smarcel#else
782240116Smarcel    cwd = getcwd(NULL, MAXPATHLEN);
783240116Smarcel#endif
784240116Smarcel    if (cwd == NULL) {
785240116Smarcel        err = atf_libc_error(errno, "Cannot determine current directory");
786240116Smarcel        goto out;
787240116Smarcel    }
788240116Smarcel
789240116Smarcel    err = atf_fs_path_init_fmt(p, "%s", cwd);
790240116Smarcel    free(cwd);
791240116Smarcel
792240116Smarcelout:
793240116Smarcel    return err;
794240116Smarcel}
795240116Smarcel
796240116Smarcelatf_error_t
797240116Smarcelatf_fs_mkdtemp(atf_fs_path_t *p)
798240116Smarcel{
799240116Smarcel    atf_error_t err;
800240116Smarcel    char *buf;
801240116Smarcel
802240116Smarcel    if (!check_umask(S_IRWXU, S_IRWXU)) {
803240116Smarcel        err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
804240116Smarcel        goto out;
805240116Smarcel    }
806240116Smarcel
807240116Smarcel    err = copy_contents(p, &buf);
808240116Smarcel    if (atf_is_error(err))
809240116Smarcel        goto out;
810240116Smarcel
811240116Smarcel    err = do_mkdtemp(buf);
812240116Smarcel    if (atf_is_error(err))
813240116Smarcel        goto out_buf;
814240116Smarcel
815240116Smarcel    replace_contents(p, buf);
816240116Smarcel
817240116Smarcel    INV(!atf_is_error(err));
818240116Smarcelout_buf:
819240116Smarcel    free(buf);
820240116Smarcelout:
821240116Smarcel    return err;
822240116Smarcel}
823240116Smarcel
824240116Smarcelatf_error_t
825240116Smarcelatf_fs_mkstemp(atf_fs_path_t *p, int *fdout)
826240116Smarcel{
827240116Smarcel    atf_error_t err;
828240116Smarcel    char *buf;
829240116Smarcel    int fd;
830240116Smarcel
831240116Smarcel    if (!check_umask(S_IRWXU, S_IRWXU)) {
832240116Smarcel        err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
833240116Smarcel        goto out;
834240116Smarcel    }
835240116Smarcel
836240116Smarcel    err = copy_contents(p, &buf);
837240116Smarcel    if (atf_is_error(err))
838240116Smarcel        goto out;
839240116Smarcel
840240116Smarcel    err = do_mkstemp(buf, &fd);
841240116Smarcel    if (atf_is_error(err))
842240116Smarcel        goto out_buf;
843240116Smarcel
844240116Smarcel    replace_contents(p, buf);
845240116Smarcel    *fdout = fd;
846240116Smarcel
847240116Smarcel    INV(!atf_is_error(err));
848240116Smarcelout_buf:
849240116Smarcel    free(buf);
850240116Smarcelout:
851240116Smarcel    return err;
852240116Smarcel}
853240116Smarcel
854240116Smarcelatf_error_t
855240116Smarcelatf_fs_rmdir(const atf_fs_path_t *p)
856240116Smarcel{
857240116Smarcel    atf_error_t err;
858240116Smarcel
859240116Smarcel    if (rmdir(atf_fs_path_cstring(p))) {
860240116Smarcel        if (errno == EEXIST) {
861240116Smarcel            /* Some operating systems (e.g. OpenSolaris 200906) return
862240116Smarcel             * EEXIST instead of ENOTEMPTY for non-empty directories.
863240116Smarcel             * Homogenize the return value so that callers don't need
864240116Smarcel             * to bother about differences in operating systems. */
865240116Smarcel            errno = ENOTEMPTY;
866240116Smarcel        }
867240116Smarcel        err = atf_libc_error(errno, "Cannot remove directory");
868240116Smarcel    } else
869240116Smarcel        err = atf_no_error();
870240116Smarcel
871240116Smarcel    return err;
872240116Smarcel}
873240116Smarcel
874240116Smarcelatf_error_t
875240116Smarcelatf_fs_unlink(const atf_fs_path_t *p)
876240116Smarcel{
877240116Smarcel    atf_error_t err;
878240116Smarcel    const char *path;
879240116Smarcel
880240116Smarcel    path = atf_fs_path_cstring(p);
881240116Smarcel
882240116Smarcel    if (unlink(path) != 0)
883240116Smarcel        err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);
884240116Smarcel    else
885240116Smarcel        err = atf_no_error();
886240116Smarcel
887240116Smarcel    return err;
888240116Smarcel}
889