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