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