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