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