2 * Automated Testing Framework (atf)
4 * Copyright (c) 2007, 2008, 2009 The NetBSD Foundation, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
17 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #if defined(HAVE_CONFIG_H)
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/mount.h>
49 #include "atf-c/error.h"
51 #include "atf-c/process.h"
52 #include "atf-c/sanity.h"
53 #include "atf-c/text.h"
54 #include "atf-c/user.h"
56 /* ---------------------------------------------------------------------
57 * Prototypes for auxiliary functions.
58 * --------------------------------------------------------------------- */
60 static bool check_umask(const mode_t
, const mode_t
);
61 static atf_error_t
cleanup_aux(const atf_fs_path_t
*, dev_t
, bool);
62 static atf_error_t
cleanup_aux_dir(const char *, const atf_fs_stat_t
*, bool);
63 static atf_error_t
copy_contents(const atf_fs_path_t
*, char **);
64 static mode_t
current_umask(void);
65 static atf_error_t
do_mkdtemp(char *);
66 static atf_error_t
do_unmount(const atf_fs_path_t
*);
67 static atf_error_t
normalize(atf_dynstr_t
*, char *);
68 static atf_error_t
normalize_ap(atf_dynstr_t
*, const char *, va_list);
69 static void replace_contents(atf_fs_path_t
*, const char *);
70 static const char *stat_type_to_string(const int);
72 /* ---------------------------------------------------------------------
73 * The "invalid_umask" error type.
74 * --------------------------------------------------------------------- */
76 struct invalid_umask_error_data
{
77 /* One of atf_fs_stat_*_type. */
80 /* The original path causing the error. */
81 /* XXX: Ideally this would be an atf_fs_path_t, but if we create it
82 * from the error constructor, we cannot delete the path later on.
83 * Can't remember why atf_error_new does not take a hook for
87 /* The umask that caused the error. */
90 typedef struct invalid_umask_error_data invalid_umask_error_data_t
;
94 invalid_umask_format(const atf_error_t err
, char *buf
, size_t buflen
)
96 const invalid_umask_error_data_t
*data
;
98 PRE(atf_error_is(err
, "invalid_umask"));
100 data
= atf_error_data(err
);
101 snprintf(buf
, buflen
, "Could not create the temporary %s %s because "
102 "it will not have enough access rights due to the current "
103 "umask %05o", stat_type_to_string(data
->m_type
),
104 data
->m_path
, (unsigned int)data
->m_umask
);
109 invalid_umask_error(const atf_fs_path_t
*path
, const int type
,
110 const mode_t failing_mask
)
113 invalid_umask_error_data_t data
;
117 strncpy(data
.m_path
, atf_fs_path_cstring(path
), sizeof(data
.m_path
));
118 data
.m_path
[sizeof(data
.m_path
) - 1] = '\0';
120 data
.m_umask
= failing_mask
;
122 err
= atf_error_new("invalid_umask", &data
, sizeof(data
),
123 invalid_umask_format
);
128 /* ---------------------------------------------------------------------
129 * The "unknown_file_type" error type.
130 * --------------------------------------------------------------------- */
132 struct unknown_type_error_data
{
136 typedef struct unknown_type_error_data unknown_type_error_data_t
;
140 unknown_type_format(const atf_error_t err
, char *buf
, size_t buflen
)
142 const unknown_type_error_data_t
*data
;
144 PRE(atf_error_is(err
, "unknown_type"));
146 data
= atf_error_data(err
);
147 snprintf(buf
, buflen
, "Unknown file type %d of %s", data
->m_type
,
153 unknown_type_error(const char *path
, int type
)
156 unknown_type_error_data_t data
;
161 err
= atf_error_new("unknown_type", &data
, sizeof(data
),
162 unknown_type_format
);
167 /* ---------------------------------------------------------------------
168 * Auxiliary functions.
169 * --------------------------------------------------------------------- */
173 check_umask(const mode_t exp_mode
, const mode_t min_mode
)
175 const mode_t actual_mode
= (~current_umask() & exp_mode
);
176 return (actual_mode
& min_mode
) == min_mode
;
179 /* The erase parameter in this routine is to control nested mount points.
180 * We want to descend into a mount point to unmount anything that is
181 * mounted under it, but we do not want to delete any files while doing
182 * this traversal. In other words, we erase files until we cross the
183 * first mount point, and after that point we only scan and unmount. */
186 cleanup_aux(const atf_fs_path_t
*p
, dev_t parent_device
, bool erase
)
188 const char *pstr
= atf_fs_path_cstring(p
);
192 err
= atf_fs_stat_init(&st
, p
);
193 if (atf_is_error(err
))
196 if (atf_fs_stat_get_type(&st
) == atf_fs_stat_dir_type
) {
197 err
= cleanup_aux_dir(pstr
, &st
,
198 atf_fs_stat_get_device(&st
) == parent_device
);
199 if (atf_is_error(err
))
203 if (atf_fs_stat_get_device(&st
) != parent_device
) {
205 if (atf_is_error(err
))
210 if (atf_fs_stat_get_type(&st
) == atf_fs_stat_dir_type
) {
211 err
= atf_fs_rmdir(p
);
213 if (unlink(pstr
) == -1)
214 err
= atf_libc_error(errno
, "Cannot remove file %s", pstr
);
216 INV(!atf_is_error(err
));
221 atf_fs_stat_fini(&st
);
228 cleanup_aux_dir(const char *pstr
, const atf_fs_stat_t
*st
, bool erase
)
234 if (erase
&& !(atf_fs_stat_get_mode(st
) & S_IWUSR
)) {
235 if (chmod(pstr
, atf_fs_stat_get_mode(st
) | S_IWUSR
) == -1) {
236 err
= atf_libc_error(errno
, "Cannot grant write permissions "
244 err
= atf_libc_error(errno
, "Cannot open directory %s", pstr
);
248 err
= atf_no_error();
249 while (!atf_is_error(err
) && (de
= readdir(d
)) != NULL
) {
252 err
= atf_fs_path_init_fmt(&p
, "%s/%s", pstr
, de
->d_name
);
253 if (!atf_is_error(err
)) {
254 if (strcmp(de
->d_name
, ".") != 0 &&
255 strcmp(de
->d_name
, "..") != 0)
256 err
= cleanup_aux(&p
, atf_fs_stat_get_device(st
), erase
);
258 atf_fs_path_fini(&p
);
270 copy_contents(const atf_fs_path_t
*p
, char **buf
)
275 str
= (char *)malloc(atf_dynstr_length(&p
->m_data
) + 1);
277 err
= atf_no_memory_error();
279 strcpy(str
, atf_dynstr_cstring(&p
->m_data
));
281 err
= atf_no_error();
291 const mode_t current
= umask(0);
292 (void)umask(current
);
298 do_mkdtemp(char *tmpl
)
302 PRE(strstr(tmpl
, "XXXXXX") != NULL
);
304 if (mkdtemp(tmpl
) == NULL
)
305 err
= atf_libc_error(errno
, "Cannot create temporary directory "
306 "with template '%s'", tmpl
);
308 err
= atf_no_error();
315 do_mkstemp(char *tmpl
, int *fdout
)
319 PRE(strstr(tmpl
, "XXXXXX") != NULL
);
321 *fdout
= mkstemp(tmpl
);
323 err
= atf_libc_error(errno
, "Cannot create temporary file "
324 "with template '%s'", tmpl
);
327 err
= atf_no_error();
334 do_unmount(const atf_fs_path_t
*p
)
340 /* At least, FreeBSD's unmount(2) requires the path to be absolute.
341 * Let's make it absolute in all cases just to be safe that this does
342 * not affect other systems. */
344 if (!atf_fs_path_is_absolute(p
))
345 err
= atf_fs_path_to_absolute(p
, &pa
);
347 err
= atf_fs_path_copy(&pa
, p
);
348 if (atf_is_error(err
))
350 pastr
= atf_fs_path_cstring(&pa
);
352 #if defined(HAVE_UNMOUNT)
353 if (unmount(pastr
, 0) == -1)
354 err
= atf_libc_error(errno
, "Cannot unmount %s", pastr
);
356 err
= atf_no_error();
359 /* We could use umount(2) instead if it was available... but
360 * trying to do so under, e.g. Linux, is a nightmare because we
361 * also have to update /etc/mtab to match what we did. It is
362 * simpler to just leave the system-specific umount(8) tool deal
363 * with it, at least for now. */
366 /* TODO: Should have an atf_fs_find_in_path function or similar to
367 * avoid relying on the automatic path lookup of exec, which I'd
368 * like to get rid of. */
369 err
= atf_fs_path_init_fmt(&prog
, "umount");
370 if (!atf_is_error(err
)) {
371 atf_process_status_t status
;
372 const char *argv
[3] = { "unmount", pastr
, NULL
};
374 err
= atf_process_exec_array(&status
, &prog
, argv
, NULL
, NULL
);
375 if (!atf_is_error(err
)) {
376 if (!atf_process_status_exited(&status
) ||
377 atf_process_status_exitstatus(&status
) != EXIT_SUCCESS
) {
378 /* XXX: This is the wrong error type. */
379 err
= atf_libc_error(EINVAL
, "Failed to exec unmount");
382 atf_process_status_fini(&status
);
385 atf_fs_path_fini(&prog
);
390 atf_fs_path_fini(&pa
);
397 normalize(atf_dynstr_t
*d
, char *p
)
405 PRE(atf_dynstr_length(d
) == 0);
408 err
= atf_dynstr_append_fmt(d
, "/");
410 err
= atf_no_error();
413 last
= NULL
; /* Silence GCC warning. */
414 ptr
= strtok_r(p
, "/", &last
);
415 while (!atf_is_error(err
) && ptr
!= NULL
) {
416 if (strlen(ptr
) > 0) {
417 err
= atf_dynstr_append_fmt(d
, "%s%s", first
? "" : "/", ptr
);
421 ptr
= strtok_r(NULL
, "/", &last
);
429 normalize_ap(atf_dynstr_t
*d
, const char *p
, va_list ap
)
435 err
= atf_dynstr_init(d
);
436 if (atf_is_error(err
))
440 err
= atf_text_format_ap(&str
, p
, ap2
);
442 if (atf_is_error(err
))
445 err
= normalize(d
, str
);
455 replace_contents(atf_fs_path_t
*p
, const char *buf
)
459 PRE(atf_dynstr_length(&p
->m_data
) == strlen(buf
));
461 atf_dynstr_clear(&p
->m_data
);
462 err
= atf_dynstr_append_fmt(&p
->m_data
, "%s", buf
);
464 INV(!atf_is_error(err
));
469 stat_type_to_string(const int type
)
473 if (type
== atf_fs_stat_blk_type
)
474 str
= "block device";
475 else if (type
== atf_fs_stat_chr_type
)
476 str
= "character device";
477 else if (type
== atf_fs_stat_dir_type
)
479 else if (type
== atf_fs_stat_fifo_type
)
481 else if (type
== atf_fs_stat_lnk_type
)
482 str
= "symbolic link";
483 else if (type
== atf_fs_stat_reg_type
)
484 str
= "regular file";
485 else if (type
== atf_fs_stat_sock_type
)
487 else if (type
== atf_fs_stat_wht_type
)
497 /* ---------------------------------------------------------------------
498 * The "atf_fs_path" type.
499 * --------------------------------------------------------------------- */
502 * Constructors/destructors.
506 atf_fs_path_init_ap(atf_fs_path_t
*p
, const char *fmt
, va_list ap
)
511 atf_object_init(&p
->m_object
);
514 err
= normalize_ap(&p
->m_data
, fmt
, ap2
);
521 atf_fs_path_init_fmt(atf_fs_path_t
*p
, const char *fmt
, ...)
527 err
= atf_fs_path_init_ap(p
, fmt
, ap
);
534 atf_fs_path_copy(atf_fs_path_t
*dest
, const atf_fs_path_t
*src
)
536 atf_object_copy(&dest
->m_object
, &src
->m_object
);
538 return atf_dynstr_copy(&dest
->m_data
, &src
->m_data
);
542 atf_fs_path_fini(atf_fs_path_t
*p
)
544 atf_dynstr_fini(&p
->m_data
);
546 atf_object_fini(&p
->m_object
);
554 atf_fs_path_branch_path(const atf_fs_path_t
*p
, atf_fs_path_t
*bp
)
556 const size_t endpos
= atf_dynstr_rfind_ch(&p
->m_data
, '/');
559 if (endpos
== atf_dynstr_npos
)
560 err
= atf_fs_path_init_fmt(bp
, ".");
561 else if (endpos
== 0)
562 err
= atf_fs_path_init_fmt(bp
, "/");
564 atf_object_init(&bp
->m_object
);
565 err
= atf_dynstr_init_substr(&bp
->m_data
, &p
->m_data
, 0, endpos
);
568 #if defined(HAVE_CONST_DIRNAME)
569 INV(atf_equal_dynstr_cstring(&bp
->m_data
,
570 dirname(atf_dynstr_cstring(&p
->m_data
))));
571 #endif /* defined(HAVE_CONST_DIRNAME) */
577 atf_fs_path_cstring(const atf_fs_path_t
*p
)
579 return atf_dynstr_cstring(&p
->m_data
);
583 atf_fs_path_leaf_name(const atf_fs_path_t
*p
, atf_dynstr_t
*ln
)
585 size_t begpos
= atf_dynstr_rfind_ch(&p
->m_data
, '/');
588 if (begpos
== atf_dynstr_npos
)
593 err
= atf_dynstr_init_substr(ln
, &p
->m_data
, begpos
, atf_dynstr_npos
);
595 #if defined(HAVE_CONST_BASENAME)
596 INV(atf_equal_dynstr_cstring(ln
,
597 basename(atf_dynstr_cstring(&p
->m_data
))));
598 #endif /* defined(HAVE_CONST_BASENAME) */
604 atf_fs_path_is_absolute(const atf_fs_path_t
*p
)
606 return atf_dynstr_cstring(&p
->m_data
)[0] == '/';
610 atf_fs_path_is_root(const atf_fs_path_t
*p
)
612 return atf_equal_dynstr_cstring(&p
->m_data
, "/");
620 atf_fs_path_append_ap(atf_fs_path_t
*p
, const char *fmt
, va_list ap
)
627 err
= normalize_ap(&aux
, fmt
, ap2
);
629 if (!atf_is_error(err
)) {
630 const char *auxstr
= atf_dynstr_cstring(&aux
);
631 const bool needslash
= auxstr
[0] != '/';
633 err
= atf_dynstr_append_fmt(&p
->m_data
, "%s%s",
634 needslash
? "/" : "", auxstr
);
636 atf_dynstr_fini(&aux
);
643 atf_fs_path_append_fmt(atf_fs_path_t
*p
, const char *fmt
, ...)
649 err
= atf_fs_path_append_ap(p
, fmt
, ap
);
656 atf_fs_path_append_path(atf_fs_path_t
*p
, const atf_fs_path_t
*p2
)
658 return atf_fs_path_append_fmt(p
, "%s", atf_dynstr_cstring(&p2
->m_data
));
662 atf_fs_path_to_absolute(const atf_fs_path_t
*p
, atf_fs_path_t
*pa
)
666 PRE(!atf_fs_path_is_absolute(p
));
668 err
= atf_fs_getcwd(pa
);
669 if (atf_is_error(err
))
672 err
= atf_fs_path_append_path(pa
, p
);
673 if (atf_is_error(err
))
674 atf_fs_path_fini(pa
);
684 bool atf_equal_fs_path_fs_path(const atf_fs_path_t
*p1
,
685 const atf_fs_path_t
*p2
)
687 return atf_equal_dynstr_dynstr(&p1
->m_data
, &p2
->m_data
);
690 /* ---------------------------------------------------------------------
691 * The "atf_fs_path" type.
692 * --------------------------------------------------------------------- */
698 const int atf_fs_stat_blk_type
= 1;
699 const int atf_fs_stat_chr_type
= 2;
700 const int atf_fs_stat_dir_type
= 3;
701 const int atf_fs_stat_fifo_type
= 4;
702 const int atf_fs_stat_lnk_type
= 5;
703 const int atf_fs_stat_reg_type
= 6;
704 const int atf_fs_stat_sock_type
= 7;
705 const int atf_fs_stat_wht_type
= 8;
708 * Constructors/destructors.
712 atf_fs_stat_init(atf_fs_stat_t
*st
, const atf_fs_path_t
*p
)
715 const char *pstr
= atf_fs_path_cstring(p
);
717 if (lstat(pstr
, &st
->m_sb
) == -1) {
718 err
= atf_libc_error(errno
, "Cannot get information of %s; "
719 "lstat(2) failed", pstr
);
721 int type
= st
->m_sb
.st_mode
& S_IFMT
;
722 err
= atf_no_error();
724 case S_IFBLK
: st
->m_type
= atf_fs_stat_blk_type
; break;
725 case S_IFCHR
: st
->m_type
= atf_fs_stat_chr_type
; break;
726 case S_IFDIR
: st
->m_type
= atf_fs_stat_dir_type
; break;
727 case S_IFIFO
: st
->m_type
= atf_fs_stat_fifo_type
; break;
728 case S_IFLNK
: st
->m_type
= atf_fs_stat_lnk_type
; break;
729 case S_IFREG
: st
->m_type
= atf_fs_stat_reg_type
; break;
730 case S_IFSOCK
: st
->m_type
= atf_fs_stat_sock_type
; break;
732 case S_IFWHT
: st
->m_type
= atf_fs_stat_wht_type
; break;
735 err
= unknown_type_error(pstr
, type
);
739 if (!atf_is_error(err
))
740 atf_object_init(&st
->m_object
);
746 atf_fs_stat_copy(atf_fs_stat_t
*dest
, const atf_fs_stat_t
*src
)
748 atf_object_copy(&dest
->m_object
, &src
->m_object
);
750 dest
->m_type
= src
->m_type
;
751 dest
->m_sb
= src
->m_sb
;
755 atf_fs_stat_fini(atf_fs_stat_t
*st
)
757 atf_object_fini(&st
->m_object
);
765 atf_fs_stat_get_device(const atf_fs_stat_t
*st
)
767 return st
->m_sb
.st_dev
;
771 atf_fs_stat_get_inode(const atf_fs_stat_t
*st
)
773 return st
->m_sb
.st_ino
;
777 atf_fs_stat_get_mode(const atf_fs_stat_t
*st
)
779 return st
->m_sb
.st_mode
& ~S_IFMT
;
783 atf_fs_stat_get_size(const atf_fs_stat_t
*st
)
785 return st
->m_sb
.st_size
;
789 atf_fs_stat_get_type(const atf_fs_stat_t
*st
)
795 atf_fs_stat_is_owner_readable(const atf_fs_stat_t
*st
)
797 return st
->m_sb
.st_mode
& S_IRUSR
;
801 atf_fs_stat_is_owner_writable(const atf_fs_stat_t
*st
)
803 return st
->m_sb
.st_mode
& S_IWUSR
;
807 atf_fs_stat_is_owner_executable(const atf_fs_stat_t
*st
)
809 return st
->m_sb
.st_mode
& S_IXUSR
;
813 atf_fs_stat_is_group_readable(const atf_fs_stat_t
*st
)
815 return st
->m_sb
.st_mode
& S_IRGRP
;
819 atf_fs_stat_is_group_writable(const atf_fs_stat_t
*st
)
821 return st
->m_sb
.st_mode
& S_IWGRP
;
825 atf_fs_stat_is_group_executable(const atf_fs_stat_t
*st
)
827 return st
->m_sb
.st_mode
& S_IXGRP
;
831 atf_fs_stat_is_other_readable(const atf_fs_stat_t
*st
)
833 return st
->m_sb
.st_mode
& S_IROTH
;
837 atf_fs_stat_is_other_writable(const atf_fs_stat_t
*st
)
839 return st
->m_sb
.st_mode
& S_IWOTH
;
843 atf_fs_stat_is_other_executable(const atf_fs_stat_t
*st
)
845 return st
->m_sb
.st_mode
& S_IXOTH
;
848 /* ---------------------------------------------------------------------
850 * --------------------------------------------------------------------- */
852 const int atf_fs_access_f
= 1 << 0;
853 const int atf_fs_access_r
= 1 << 1;
854 const int atf_fs_access_w
= 1 << 2;
855 const int atf_fs_access_x
= 1 << 3;
858 atf_fs_cleanup(const atf_fs_path_t
*p
)
863 err
= atf_fs_stat_init(&info
, p
);
864 if (atf_is_error(err
))
867 err
= cleanup_aux(p
, atf_fs_stat_get_device(&info
), true);
869 atf_fs_stat_fini(&info
);
875 * An implementation of access(2) but using the effective user value
876 * instead of the real one. Also avoids false positives for root when
877 * asking for execute permissions, which appear in SunOS.
880 atf_fs_eaccess(const atf_fs_path_t
*p
, int mode
)
886 PRE(mode
& atf_fs_access_f
|| mode
& atf_fs_access_r
||
887 mode
& atf_fs_access_w
|| mode
& atf_fs_access_x
);
889 if (lstat(atf_fs_path_cstring(p
), &st
) == -1) {
890 err
= atf_libc_error(errno
, "Cannot get information from file %s",
891 atf_fs_path_cstring(p
));
895 err
= atf_no_error();
897 /* Early return if we are only checking for existence and the file
898 * exists (stat call returned). */
899 if (mode
& atf_fs_access_f
)
903 if (atf_user_is_root()) {
904 if (!ok
&& !(mode
& atf_fs_access_x
)) {
905 /* Allow root to read/write any file. */
909 if (!ok
&& (st
.st_mode
& (S_IXUSR
| S_IXGRP
| S_IXOTH
))) {
910 /* Allow root to execute the file if any of its execution bits
915 if (!ok
&& (atf_user_euid() == st
.st_uid
)) {
916 ok
= ((mode
& atf_fs_access_r
) && (st
.st_mode
& S_IRUSR
)) ||
917 ((mode
& atf_fs_access_w
) && (st
.st_mode
& S_IWUSR
)) ||
918 ((mode
& atf_fs_access_x
) && (st
.st_mode
& S_IXUSR
));
920 if (!ok
&& atf_user_is_member_of_group(st
.st_gid
)) {
921 ok
= ((mode
& atf_fs_access_r
) && (st
.st_mode
& S_IRGRP
)) ||
922 ((mode
& atf_fs_access_w
) && (st
.st_mode
& S_IWGRP
)) ||
923 ((mode
& atf_fs_access_x
) && (st
.st_mode
& S_IXGRP
));
925 if (!ok
&& ((atf_user_euid() != st
.st_uid
) &&
926 !atf_user_is_member_of_group(st
.st_gid
))) {
927 ok
= ((mode
& atf_fs_access_r
) && (st
.st_mode
& S_IROTH
)) ||
928 ((mode
& atf_fs_access_w
) && (st
.st_mode
& S_IWOTH
)) ||
929 ((mode
& atf_fs_access_x
) && (st
.st_mode
& S_IXOTH
));
934 err
= atf_libc_error(EACCES
, "Access check failed");
941 atf_fs_exists(const atf_fs_path_t
*p
, bool *b
)
945 err
= atf_fs_eaccess(p
, atf_fs_access_f
);
946 if (atf_is_error(err
)) {
947 if (atf_error_is(err
, "libc") && atf_libc_error_code(err
) == ENOENT
) {
949 err
= atf_no_error();
959 atf_fs_getcwd(atf_fs_path_t
*p
)
964 #if defined(HAVE_GETCWD_DYN)
965 cwd
= getcwd(NULL
, 0);
967 cwd
= getcwd(NULL
, MAXPATHLEN
);
970 err
= atf_libc_error(errno
, "Cannot determine current directory");
974 err
= atf_fs_path_init_fmt(p
, "%s", cwd
);
982 atf_fs_mkdtemp(atf_fs_path_t
*p
)
987 if (!check_umask(S_IRWXU
, S_IRWXU
)) {
988 err
= invalid_umask_error(p
, atf_fs_stat_dir_type
, current_umask());
992 err
= copy_contents(p
, &buf
);
993 if (atf_is_error(err
))
996 err
= do_mkdtemp(buf
);
997 if (atf_is_error(err
))
1000 replace_contents(p
, buf
);
1002 INV(!atf_is_error(err
));
1010 atf_fs_mkstemp(atf_fs_path_t
*p
, int *fdout
)
1016 if (!check_umask(S_IRWXU
, S_IRWXU
)) {
1017 err
= invalid_umask_error(p
, atf_fs_stat_reg_type
, current_umask());
1021 err
= copy_contents(p
, &buf
);
1022 if (atf_is_error(err
))
1025 err
= do_mkstemp(buf
, &fd
);
1026 if (atf_is_error(err
))
1029 replace_contents(p
, buf
);
1032 INV(!atf_is_error(err
));
1040 atf_fs_rmdir(const atf_fs_path_t
*p
)
1044 if (rmdir(atf_fs_path_cstring(p
))) {
1045 if (errno
== EEXIST
) {
1046 /* Some operating systems (e.g. OpenSolaris 200906) return
1047 * EEXIST instead of ENOTEMPTY for non-empty directories.
1048 * Homogenize the return value so that callers don't need
1049 * to bother about differences in operating systems. */
1052 err
= atf_libc_error(errno
, "Cannot remove directory");
1054 err
= atf_no_error();
1060 atf_fs_unlink(const atf_fs_path_t
*p
)
1065 path
= atf_fs_path_cstring(p
);
1067 if (unlink(path
) != 0)
1068 err
= atf_libc_error(errno
, "Cannot unlink file: '%s'", path
);
1070 err
= atf_no_error();