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