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 #if !defined(NDEBUG) && defined(__minix)
305 atf_error_t err;
306
307 PRE(atf_dynstr_length(&p->m_data) == strlen(buf));
308
309 #endif /* !defined(NDEBUG) && defined(__minix) */
310 atf_dynstr_clear(&p->m_data);
311 #if !defined(NDEBUG) && defined(__minix)
312 err =
313 #endif /* !defined(NDEBUG) && defined(__minix) */
314 atf_dynstr_append_fmt(&p->m_data, "%s", buf);
315
316 #if !defined(NDEBUG) && defined(__minix)
317 INV(!atf_is_error(err));
318 #endif /* !defined(NDEBUG) && defined(__minix) */
319 }
320
321 static
322 const char *
stat_type_to_string(const int type)323 stat_type_to_string(const int type)
324 {
325 const char *str;
326
327 if (type == atf_fs_stat_blk_type)
328 str = "block device";
329 else if (type == atf_fs_stat_chr_type)
330 str = "character device";
331 else if (type == atf_fs_stat_dir_type)
332 str = "directory";
333 else if (type == atf_fs_stat_fifo_type)
334 str = "named pipe";
335 else if (type == atf_fs_stat_lnk_type)
336 str = "symbolic link";
337 else if (type == atf_fs_stat_reg_type)
338 str = "regular file";
339 else if (type == atf_fs_stat_sock_type)
340 str = "socket";
341 else if (type == atf_fs_stat_wht_type)
342 str = "whiteout";
343 else {
344 UNREACHABLE;
345 str = NULL;
346 }
347
348 return str;
349 }
350
351 /* ---------------------------------------------------------------------
352 * The "atf_fs_path" type.
353 * --------------------------------------------------------------------- */
354
355 /*
356 * Constructors/destructors.
357 */
358
359 atf_error_t
atf_fs_path_init_ap(atf_fs_path_t * p,const char * fmt,va_list ap)360 atf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
361 {
362 atf_error_t err;
363 va_list ap2;
364
365 va_copy(ap2, ap);
366 err = normalize_ap(&p->m_data, fmt, ap2);
367 va_end(ap2);
368
369 return err;
370 }
371
372 atf_error_t
atf_fs_path_init_fmt(atf_fs_path_t * p,const char * fmt,...)373 atf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...)
374 {
375 va_list ap;
376 atf_error_t err;
377
378 va_start(ap, fmt);
379 err = atf_fs_path_init_ap(p, fmt, ap);
380 va_end(ap);
381
382 return err;
383 }
384
385 atf_error_t
atf_fs_path_copy(atf_fs_path_t * dest,const atf_fs_path_t * src)386 atf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src)
387 {
388 return atf_dynstr_copy(&dest->m_data, &src->m_data);
389 }
390
391 void
atf_fs_path_fini(atf_fs_path_t * p)392 atf_fs_path_fini(atf_fs_path_t *p)
393 {
394 atf_dynstr_fini(&p->m_data);
395 }
396
397 /*
398 * Getters.
399 */
400
401 atf_error_t
atf_fs_path_branch_path(const atf_fs_path_t * p,atf_fs_path_t * bp)402 atf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp)
403 {
404 const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/');
405 atf_error_t err;
406
407 if (endpos == atf_dynstr_npos)
408 err = atf_fs_path_init_fmt(bp, ".");
409 else if (endpos == 0)
410 err = atf_fs_path_init_fmt(bp, "/");
411 else
412 err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos);
413
414 #if defined(HAVE_CONST_DIRNAME)
415 INV(atf_equal_dynstr_cstring(&bp->m_data,
416 dirname(atf_dynstr_cstring(&p->m_data))));
417 #endif /* defined(HAVE_CONST_DIRNAME) */
418
419 return err;
420 }
421
422 const char *
atf_fs_path_cstring(const atf_fs_path_t * p)423 atf_fs_path_cstring(const atf_fs_path_t *p)
424 {
425 return atf_dynstr_cstring(&p->m_data);
426 }
427
428 atf_error_t
atf_fs_path_leaf_name(const atf_fs_path_t * p,atf_dynstr_t * ln)429 atf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln)
430 {
431 size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/');
432 atf_error_t err;
433
434 if (begpos == atf_dynstr_npos)
435 begpos = 0;
436 else
437 begpos++;
438
439 err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos);
440
441 #if defined(HAVE_CONST_BASENAME)
442 INV(atf_equal_dynstr_cstring(ln,
443 basename(atf_dynstr_cstring(&p->m_data))));
444 #endif /* defined(HAVE_CONST_BASENAME) */
445
446 return err;
447 }
448
449 bool
atf_fs_path_is_absolute(const atf_fs_path_t * p)450 atf_fs_path_is_absolute(const atf_fs_path_t *p)
451 {
452 return atf_dynstr_cstring(&p->m_data)[0] == '/';
453 }
454
455 bool
atf_fs_path_is_root(const atf_fs_path_t * p)456 atf_fs_path_is_root(const atf_fs_path_t *p)
457 {
458 return atf_equal_dynstr_cstring(&p->m_data, "/");
459 }
460
461 /*
462 * Modifiers.
463 */
464
465 atf_error_t
atf_fs_path_append_ap(atf_fs_path_t * p,const char * fmt,va_list ap)466 atf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap)
467 {
468 atf_dynstr_t aux;
469 atf_error_t err;
470 va_list ap2;
471
472 va_copy(ap2, ap);
473 err = normalize_ap(&aux, fmt, ap2);
474 va_end(ap2);
475 if (!atf_is_error(err)) {
476 const char *auxstr = atf_dynstr_cstring(&aux);
477 const bool needslash = auxstr[0] != '/';
478
479 err = atf_dynstr_append_fmt(&p->m_data, "%s%s",
480 needslash ? "/" : "", auxstr);
481
482 atf_dynstr_fini(&aux);
483 }
484
485 return err;
486 }
487
488 atf_error_t
atf_fs_path_append_fmt(atf_fs_path_t * p,const char * fmt,...)489 atf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...)
490 {
491 va_list ap;
492 atf_error_t err;
493
494 va_start(ap, fmt);
495 err = atf_fs_path_append_ap(p, fmt, ap);
496 va_end(ap);
497
498 return err;
499 }
500
501 atf_error_t
atf_fs_path_append_path(atf_fs_path_t * p,const atf_fs_path_t * p2)502 atf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2)
503 {
504 return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data));
505 }
506
507 atf_error_t
atf_fs_path_to_absolute(const atf_fs_path_t * p,atf_fs_path_t * pa)508 atf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa)
509 {
510 atf_error_t err;
511
512 PRE(!atf_fs_path_is_absolute(p));
513
514 err = atf_fs_getcwd(pa);
515 if (atf_is_error(err))
516 goto out;
517
518 err = atf_fs_path_append_path(pa, p);
519 if (atf_is_error(err))
520 atf_fs_path_fini(pa);
521
522 out:
523 return err;
524 }
525
526 /*
527 * Operators.
528 */
529
atf_equal_fs_path_fs_path(const atf_fs_path_t * p1,const atf_fs_path_t * p2)530 bool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1,
531 const atf_fs_path_t *p2)
532 {
533 return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data);
534 }
535
536 /* ---------------------------------------------------------------------
537 * The "atf_fs_path" type.
538 * --------------------------------------------------------------------- */
539
540 /*
541 * Constants.
542 */
543
544 const int atf_fs_stat_blk_type = 1;
545 const int atf_fs_stat_chr_type = 2;
546 const int atf_fs_stat_dir_type = 3;
547 const int atf_fs_stat_fifo_type = 4;
548 const int atf_fs_stat_lnk_type = 5;
549 const int atf_fs_stat_reg_type = 6;
550 const int atf_fs_stat_sock_type = 7;
551 const int atf_fs_stat_wht_type = 8;
552
553 /*
554 * Constructors/destructors.
555 */
556
557 atf_error_t
atf_fs_stat_init(atf_fs_stat_t * st,const atf_fs_path_t * p)558 atf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p)
559 {
560 atf_error_t err;
561 const char *pstr = atf_fs_path_cstring(p);
562
563 if (lstat(pstr, &st->m_sb) == -1) {
564 err = atf_libc_error(errno, "Cannot get information of %s; "
565 "lstat(2) failed", pstr);
566 } else {
567 int type = st->m_sb.st_mode & S_IFMT;
568 err = atf_no_error();
569 switch (type) {
570 case S_IFBLK: st->m_type = atf_fs_stat_blk_type; break;
571 case S_IFCHR: st->m_type = atf_fs_stat_chr_type; break;
572 case S_IFDIR: st->m_type = atf_fs_stat_dir_type; break;
573 case S_IFIFO: st->m_type = atf_fs_stat_fifo_type; break;
574 case S_IFLNK: st->m_type = atf_fs_stat_lnk_type; break;
575 case S_IFREG: st->m_type = atf_fs_stat_reg_type; break;
576 case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break;
577 #if defined(S_IFWHT)
578 case S_IFWHT: st->m_type = atf_fs_stat_wht_type; break;
579 #endif
580 default:
581 err = unknown_type_error(pstr, type);
582 }
583 }
584
585 return err;
586 }
587
588 void
atf_fs_stat_copy(atf_fs_stat_t * dest,const atf_fs_stat_t * src)589 atf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src)
590 {
591 dest->m_type = src->m_type;
592 dest->m_sb = src->m_sb;
593 }
594
595 void
atf_fs_stat_fini(atf_fs_stat_t * st ATF_DEFS_ATTRIBUTE_UNUSED)596 atf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED)
597 {
598 }
599
600 /*
601 * Getters.
602 */
603
604 dev_t
atf_fs_stat_get_device(const atf_fs_stat_t * st)605 atf_fs_stat_get_device(const atf_fs_stat_t *st)
606 {
607 return st->m_sb.st_dev;
608 }
609
610 ino_t
atf_fs_stat_get_inode(const atf_fs_stat_t * st)611 atf_fs_stat_get_inode(const atf_fs_stat_t *st)
612 {
613 return st->m_sb.st_ino;
614 }
615
616 mode_t
atf_fs_stat_get_mode(const atf_fs_stat_t * st)617 atf_fs_stat_get_mode(const atf_fs_stat_t *st)
618 {
619 return st->m_sb.st_mode & ~S_IFMT;
620 }
621
622 off_t
atf_fs_stat_get_size(const atf_fs_stat_t * st)623 atf_fs_stat_get_size(const atf_fs_stat_t *st)
624 {
625 return st->m_sb.st_size;
626 }
627
628 int
atf_fs_stat_get_type(const atf_fs_stat_t * st)629 atf_fs_stat_get_type(const atf_fs_stat_t *st)
630 {
631 return st->m_type;
632 }
633
634 bool
atf_fs_stat_is_owner_readable(const atf_fs_stat_t * st)635 atf_fs_stat_is_owner_readable(const atf_fs_stat_t *st)
636 {
637 return st->m_sb.st_mode & S_IRUSR;
638 }
639
640 bool
atf_fs_stat_is_owner_writable(const atf_fs_stat_t * st)641 atf_fs_stat_is_owner_writable(const atf_fs_stat_t *st)
642 {
643 return st->m_sb.st_mode & S_IWUSR;
644 }
645
646 bool
atf_fs_stat_is_owner_executable(const atf_fs_stat_t * st)647 atf_fs_stat_is_owner_executable(const atf_fs_stat_t *st)
648 {
649 return st->m_sb.st_mode & S_IXUSR;
650 }
651
652 bool
atf_fs_stat_is_group_readable(const atf_fs_stat_t * st)653 atf_fs_stat_is_group_readable(const atf_fs_stat_t *st)
654 {
655 return st->m_sb.st_mode & S_IRGRP;
656 }
657
658 bool
atf_fs_stat_is_group_writable(const atf_fs_stat_t * st)659 atf_fs_stat_is_group_writable(const atf_fs_stat_t *st)
660 {
661 return st->m_sb.st_mode & S_IWGRP;
662 }
663
664 bool
atf_fs_stat_is_group_executable(const atf_fs_stat_t * st)665 atf_fs_stat_is_group_executable(const atf_fs_stat_t *st)
666 {
667 return st->m_sb.st_mode & S_IXGRP;
668 }
669
670 bool
atf_fs_stat_is_other_readable(const atf_fs_stat_t * st)671 atf_fs_stat_is_other_readable(const atf_fs_stat_t *st)
672 {
673 return st->m_sb.st_mode & S_IROTH;
674 }
675
676 bool
atf_fs_stat_is_other_writable(const atf_fs_stat_t * st)677 atf_fs_stat_is_other_writable(const atf_fs_stat_t *st)
678 {
679 return st->m_sb.st_mode & S_IWOTH;
680 }
681
682 bool
atf_fs_stat_is_other_executable(const atf_fs_stat_t * st)683 atf_fs_stat_is_other_executable(const atf_fs_stat_t *st)
684 {
685 return st->m_sb.st_mode & S_IXOTH;
686 }
687
688 /* ---------------------------------------------------------------------
689 * Free functions.
690 * --------------------------------------------------------------------- */
691
692 const int atf_fs_access_f = 1 << 0;
693 const int atf_fs_access_r = 1 << 1;
694 const int atf_fs_access_w = 1 << 2;
695 const int atf_fs_access_x = 1 << 3;
696
697 /*
698 * An implementation of access(2) but using the effective user value
699 * instead of the real one. Also avoids false positives for root when
700 * asking for execute permissions, which appear in SunOS.
701 */
702 atf_error_t
atf_fs_eaccess(const atf_fs_path_t * p,int mode)703 atf_fs_eaccess(const atf_fs_path_t *p, int mode)
704 {
705 atf_error_t err;
706 struct stat st;
707 bool ok;
708
709 PRE(mode & atf_fs_access_f || mode & atf_fs_access_r ||
710 mode & atf_fs_access_w || mode & atf_fs_access_x);
711
712 if (lstat(atf_fs_path_cstring(p), &st) == -1) {
713 err = atf_libc_error(errno, "Cannot get information from file %s",
714 atf_fs_path_cstring(p));
715 goto out;
716 }
717
718 err = atf_no_error();
719
720 /* Early return if we are only checking for existence and the file
721 * exists (stat call returned). */
722 if (mode & atf_fs_access_f)
723 goto out;
724
725 ok = false;
726 if (atf_user_is_root()) {
727 if (!ok && !(mode & atf_fs_access_x)) {
728 /* Allow root to read/write any file. */
729 ok = true;
730 }
731
732 if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
733 /* Allow root to execute the file if any of its execution bits
734 * are set. */
735 ok = true;
736 }
737 } else {
738 if (!ok && (atf_user_euid() == st.st_uid)) {
739 ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) ||
740 ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) ||
741 ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR));
742 }
743 if (!ok && atf_user_is_member_of_group(st.st_gid)) {
744 ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) ||
745 ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) ||
746 ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP));
747 }
748 if (!ok && ((atf_user_euid() != st.st_uid) &&
749 !atf_user_is_member_of_group(st.st_gid))) {
750 ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) ||
751 ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) ||
752 ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH));
753 }
754 }
755
756 if (!ok)
757 err = atf_libc_error(EACCES, "Access check failed");
758
759 out:
760 return err;
761 }
762
763 atf_error_t
atf_fs_exists(const atf_fs_path_t * p,bool * b)764 atf_fs_exists(const atf_fs_path_t *p, bool *b)
765 {
766 atf_error_t err;
767
768 err = atf_fs_eaccess(p, atf_fs_access_f);
769 if (atf_is_error(err)) {
770 if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) {
771 atf_error_free(err);
772 err = atf_no_error();
773 *b = false;
774 }
775 } else
776 *b = true;
777
778 return err;
779 }
780
781 atf_error_t
atf_fs_getcwd(atf_fs_path_t * p)782 atf_fs_getcwd(atf_fs_path_t *p)
783 {
784 atf_error_t err;
785 char *cwd;
786
787 #if defined(HAVE_GETCWD_DYN)
788 cwd = getcwd(NULL, 0);
789 #else
790 cwd = getcwd(NULL, MAXPATHLEN);
791 #endif
792 if (cwd == NULL) {
793 err = atf_libc_error(errno, "Cannot determine current directory");
794 goto out;
795 }
796
797 err = atf_fs_path_init_fmt(p, "%s", cwd);
798 free(cwd);
799
800 out:
801 return err;
802 }
803
804 atf_error_t
atf_fs_mkdtemp(atf_fs_path_t * p)805 atf_fs_mkdtemp(atf_fs_path_t *p)
806 {
807 atf_error_t err;
808 char *buf = NULL; /* MINIX: Complain in -O3 */
809
810 if (!check_umask(S_IRWXU, S_IRWXU)) {
811 err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask());
812 goto out;
813 }
814
815 err = copy_contents(p, &buf);
816 if (atf_is_error(err))
817 goto out;
818
819 err = do_mkdtemp(buf);
820 if (atf_is_error(err))
821 goto out_buf;
822
823 replace_contents(p, buf);
824
825 INV(!atf_is_error(err));
826 out_buf:
827 free(buf);
828 out:
829 return err;
830 }
831
832 atf_error_t
atf_fs_mkstemp(atf_fs_path_t * p,int * fdout)833 atf_fs_mkstemp(atf_fs_path_t *p, int *fdout)
834 {
835 atf_error_t err;
836 char *buf = NULL; /* MINIX: Complain in -O3 */
837 int fd;
838
839 if (!check_umask(S_IRWXU, S_IRWXU)) {
840 err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask());
841 goto out;
842 }
843
844 err = copy_contents(p, &buf);
845 if (atf_is_error(err))
846 goto out;
847
848 err = do_mkstemp(buf, &fd);
849 if (atf_is_error(err))
850 goto out_buf;
851
852 replace_contents(p, buf);
853 *fdout = fd;
854
855 INV(!atf_is_error(err));
856 out_buf:
857 free(buf);
858 out:
859 return err;
860 }
861
862 atf_error_t
atf_fs_rmdir(const atf_fs_path_t * p)863 atf_fs_rmdir(const atf_fs_path_t *p)
864 {
865 atf_error_t err;
866
867 if (rmdir(atf_fs_path_cstring(p))) {
868 if (errno == EEXIST) {
869 /* Some operating systems (e.g. OpenSolaris 200906) return
870 * EEXIST instead of ENOTEMPTY for non-empty directories.
871 * Homogenize the return value so that callers don't need
872 * to bother about differences in operating systems. */
873 errno = ENOTEMPTY;
874 }
875 err = atf_libc_error(errno, "Cannot remove directory");
876 } else
877 err = atf_no_error();
878
879 return err;
880 }
881
882 atf_error_t
atf_fs_unlink(const atf_fs_path_t * p)883 atf_fs_unlink(const atf_fs_path_t *p)
884 {
885 atf_error_t err;
886 const char *path;
887
888 path = atf_fs_path_cstring(p);
889
890 if (unlink(path) != 0)
891 err = atf_libc_error(errno, "Cannot unlink file: '%s'", path);
892 else
893 err = atf_no_error();
894
895 return err;
896 }
897