1240116Smarcel/* 2240116Smarcel * Automated Testing Framework (atf) 3240116Smarcel * 4240116Smarcel * Copyright (c) 2007 The NetBSD Foundation, Inc. 5240116Smarcel * All rights reserved. 6240116Smarcel * 7240116Smarcel * Redistribution and use in source and binary forms, with or without 8240116Smarcel * modification, are permitted provided that the following conditions 9240116Smarcel * are met: 10240116Smarcel * 1. Redistributions of source code must retain the above copyright 11240116Smarcel * notice, this list of conditions and the following disclaimer. 12240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13240116Smarcel * notice, this list of conditions and the following disclaimer in the 14240116Smarcel * documentation and/or other materials provided with the distribution. 15240116Smarcel * 16240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND 17240116Smarcel * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 18240116Smarcel * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19240116Smarcel * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20240116Smarcel * IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY 21240116Smarcel * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22240116Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 23240116Smarcel * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24240116Smarcel * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25240116Smarcel * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26240116Smarcel * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27240116Smarcel * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28240116Smarcel */ 29240116Smarcel 30240116Smarcel#if defined(HAVE_CONFIG_H) 31240116Smarcel#include "bconfig.h" 32240116Smarcel#endif 33240116Smarcel 34240116Smarcel#include <sys/types.h> 35240116Smarcel#include <sys/param.h> 36240116Smarcel#include <sys/mount.h> 37240116Smarcel#include <sys/stat.h> 38240116Smarcel#include <sys/wait.h> 39240116Smarcel 40240116Smarcel#include <dirent.h> 41240116Smarcel#include <errno.h> 42240116Smarcel#include <libgen.h> 43240116Smarcel#include <stdarg.h> 44240116Smarcel#include <stdio.h> 45240116Smarcel#include <stdlib.h> 46240116Smarcel#include <string.h> 47240116Smarcel#include <unistd.h> 48240116Smarcel 49240116Smarcel#include "atf-c/defs.h" 50240116Smarcel#include "atf-c/error.h" 51240116Smarcel 52240116Smarcel#include "fs.h" 53240116Smarcel#include "sanity.h" 54240116Smarcel#include "text.h" 55240116Smarcel#include "user.h" 56240116Smarcel 57240116Smarcel/* --------------------------------------------------------------------- 58240116Smarcel * Prototypes for auxiliary functions. 59240116Smarcel * --------------------------------------------------------------------- */ 60240116Smarcel 61240116Smarcelstatic bool check_umask(const mode_t, const mode_t); 62240116Smarcelstatic atf_error_t copy_contents(const atf_fs_path_t *, char **); 63240116Smarcelstatic mode_t current_umask(void); 64240116Smarcelstatic atf_error_t do_mkdtemp(char *); 65240116Smarcelstatic atf_error_t normalize(atf_dynstr_t *, char *); 66240116Smarcelstatic atf_error_t normalize_ap(atf_dynstr_t *, const char *, va_list); 67240116Smarcelstatic void replace_contents(atf_fs_path_t *, const char *); 68240116Smarcelstatic const char *stat_type_to_string(const int); 69240116Smarcel 70240116Smarcel/* --------------------------------------------------------------------- 71240116Smarcel * The "invalid_umask" error type. 72240116Smarcel * --------------------------------------------------------------------- */ 73240116Smarcel 74240116Smarcelstruct invalid_umask_error_data { 75240116Smarcel /* One of atf_fs_stat_*_type. */ 76240116Smarcel int m_type; 77240116Smarcel 78240116Smarcel /* The original path causing the error. */ 79240116Smarcel /* XXX: Ideally this would be an atf_fs_path_t, but if we create it 80240116Smarcel * from the error constructor, we cannot delete the path later on. 81240116Smarcel * Can't remember why atf_error_new does not take a hook for 82240116Smarcel * deletion. */ 83240116Smarcel char m_path[1024]; 84240116Smarcel 85240116Smarcel /* The umask that caused the error. */ 86240116Smarcel mode_t m_umask; 87240116Smarcel}; 88240116Smarceltypedef struct invalid_umask_error_data invalid_umask_error_data_t; 89240116Smarcel 90240116Smarcelstatic 91240116Smarcelvoid 92240116Smarcelinvalid_umask_format(const atf_error_t err, char *buf, size_t buflen) 93240116Smarcel{ 94240116Smarcel const invalid_umask_error_data_t *data; 95240116Smarcel 96240116Smarcel PRE(atf_error_is(err, "invalid_umask")); 97240116Smarcel 98240116Smarcel data = atf_error_data(err); 99240116Smarcel snprintf(buf, buflen, "Could not create the temporary %s %s because " 100240116Smarcel "it will not have enough access rights due to the current " 101240116Smarcel "umask %05o", stat_type_to_string(data->m_type), 102240116Smarcel data->m_path, (unsigned int)data->m_umask); 103240116Smarcel} 104240116Smarcel 105240116Smarcelstatic 106240116Smarcelatf_error_t 107240116Smarcelinvalid_umask_error(const atf_fs_path_t *path, const int type, 108240116Smarcel const mode_t failing_mask) 109240116Smarcel{ 110240116Smarcel atf_error_t err; 111240116Smarcel invalid_umask_error_data_t data; 112240116Smarcel 113240116Smarcel data.m_type = type; 114240116Smarcel 115240116Smarcel strncpy(data.m_path, atf_fs_path_cstring(path), sizeof(data.m_path)); 116240116Smarcel data.m_path[sizeof(data.m_path) - 1] = '\0'; 117240116Smarcel 118240116Smarcel data.m_umask = failing_mask; 119240116Smarcel 120240116Smarcel err = atf_error_new("invalid_umask", &data, sizeof(data), 121240116Smarcel invalid_umask_format); 122240116Smarcel 123240116Smarcel return err; 124240116Smarcel} 125240116Smarcel 126240116Smarcel/* --------------------------------------------------------------------- 127240116Smarcel * The "unknown_file_type" error type. 128240116Smarcel * --------------------------------------------------------------------- */ 129240116Smarcel 130240116Smarcelstruct unknown_type_error_data { 131240116Smarcel const char *m_path; 132240116Smarcel int m_type; 133240116Smarcel}; 134240116Smarceltypedef struct unknown_type_error_data unknown_type_error_data_t; 135240116Smarcel 136240116Smarcelstatic 137240116Smarcelvoid 138240116Smarcelunknown_type_format(const atf_error_t err, char *buf, size_t buflen) 139240116Smarcel{ 140240116Smarcel const unknown_type_error_data_t *data; 141240116Smarcel 142240116Smarcel PRE(atf_error_is(err, "unknown_type")); 143240116Smarcel 144240116Smarcel data = atf_error_data(err); 145240116Smarcel snprintf(buf, buflen, "Unknown file type %d of %s", data->m_type, 146240116Smarcel data->m_path); 147240116Smarcel} 148240116Smarcel 149240116Smarcelstatic 150240116Smarcelatf_error_t 151240116Smarcelunknown_type_error(const char *path, int type) 152240116Smarcel{ 153240116Smarcel atf_error_t err; 154240116Smarcel unknown_type_error_data_t data; 155240116Smarcel 156240116Smarcel data.m_path = path; 157240116Smarcel data.m_type = type; 158240116Smarcel 159240116Smarcel err = atf_error_new("unknown_type", &data, sizeof(data), 160240116Smarcel unknown_type_format); 161240116Smarcel 162240116Smarcel return err; 163240116Smarcel} 164240116Smarcel 165240116Smarcel/* --------------------------------------------------------------------- 166240116Smarcel * Auxiliary functions. 167240116Smarcel * --------------------------------------------------------------------- */ 168240116Smarcel 169240116Smarcelstatic 170240116Smarcelbool 171240116Smarcelcheck_umask(const mode_t exp_mode, const mode_t min_mode) 172240116Smarcel{ 173240116Smarcel const mode_t actual_mode = (~current_umask() & exp_mode); 174240116Smarcel return (actual_mode & min_mode) == min_mode; 175240116Smarcel} 176240116Smarcel 177240116Smarcelstatic 178240116Smarcelatf_error_t 179240116Smarcelcopy_contents(const atf_fs_path_t *p, char **buf) 180240116Smarcel{ 181240116Smarcel atf_error_t err; 182240116Smarcel char *str; 183240116Smarcel 184240116Smarcel str = (char *)malloc(atf_dynstr_length(&p->m_data) + 1); 185240116Smarcel if (str == NULL) 186240116Smarcel err = atf_no_memory_error(); 187240116Smarcel else { 188240116Smarcel strcpy(str, atf_dynstr_cstring(&p->m_data)); 189240116Smarcel *buf = str; 190240116Smarcel err = atf_no_error(); 191240116Smarcel } 192240116Smarcel 193240116Smarcel return err; 194240116Smarcel} 195240116Smarcel 196240116Smarcelstatic 197240116Smarcelmode_t 198240116Smarcelcurrent_umask(void) 199240116Smarcel{ 200240116Smarcel const mode_t current = umask(0); 201240116Smarcel (void)umask(current); 202240116Smarcel return current; 203240116Smarcel} 204240116Smarcel 205240116Smarcelstatic 206240116Smarcelatf_error_t 207240116Smarceldo_mkdtemp(char *tmpl) 208240116Smarcel{ 209240116Smarcel atf_error_t err; 210240116Smarcel 211240116Smarcel PRE(strstr(tmpl, "XXXXXX") != NULL); 212240116Smarcel 213240116Smarcel if (mkdtemp(tmpl) == NULL) 214240116Smarcel err = atf_libc_error(errno, "Cannot create temporary directory " 215240116Smarcel "with template '%s'", tmpl); 216240116Smarcel else 217240116Smarcel err = atf_no_error(); 218240116Smarcel 219240116Smarcel return err; 220240116Smarcel} 221240116Smarcel 222240116Smarcelstatic 223240116Smarcelatf_error_t 224240116Smarceldo_mkstemp(char *tmpl, int *fdout) 225240116Smarcel{ 226240116Smarcel atf_error_t err; 227240116Smarcel 228240116Smarcel PRE(strstr(tmpl, "XXXXXX") != NULL); 229240116Smarcel 230240116Smarcel *fdout = mkstemp(tmpl); 231240116Smarcel if (*fdout == -1) 232240116Smarcel err = atf_libc_error(errno, "Cannot create temporary file " 233240116Smarcel "with template '%s'", tmpl); 234240116Smarcel 235240116Smarcel else 236240116Smarcel err = atf_no_error(); 237240116Smarcel 238240116Smarcel return err; 239240116Smarcel} 240240116Smarcel 241240116Smarcelstatic 242240116Smarcelatf_error_t 243240116Smarcelnormalize(atf_dynstr_t *d, char *p) 244240116Smarcel{ 245240116Smarcel const char *ptr; 246240116Smarcel char *last; 247240116Smarcel atf_error_t err; 248240116Smarcel bool first; 249240116Smarcel 250240116Smarcel PRE(strlen(p) > 0); 251240116Smarcel PRE(atf_dynstr_length(d) == 0); 252240116Smarcel 253240116Smarcel if (p[0] == '/') 254240116Smarcel err = atf_dynstr_append_fmt(d, "/"); 255240116Smarcel else 256240116Smarcel err = atf_no_error(); 257240116Smarcel 258240116Smarcel first = true; 259240116Smarcel last = NULL; /* Silence GCC warning. */ 260240116Smarcel ptr = strtok_r(p, "/", &last); 261240116Smarcel while (!atf_is_error(err) && ptr != NULL) { 262240116Smarcel if (strlen(ptr) > 0) { 263240116Smarcel err = atf_dynstr_append_fmt(d, "%s%s", first ? "" : "/", ptr); 264240116Smarcel first = false; 265240116Smarcel } 266240116Smarcel 267240116Smarcel ptr = strtok_r(NULL, "/", &last); 268240116Smarcel } 269240116Smarcel 270240116Smarcel return err; 271240116Smarcel} 272240116Smarcel 273240116Smarcelstatic 274240116Smarcelatf_error_t 275240116Smarcelnormalize_ap(atf_dynstr_t *d, const char *p, va_list ap) 276240116Smarcel{ 277240116Smarcel char *str; 278240116Smarcel atf_error_t err; 279240116Smarcel va_list ap2; 280240116Smarcel 281240116Smarcel err = atf_dynstr_init(d); 282240116Smarcel if (atf_is_error(err)) 283240116Smarcel goto out; 284240116Smarcel 285240116Smarcel va_copy(ap2, ap); 286240116Smarcel err = atf_text_format_ap(&str, p, ap2); 287240116Smarcel va_end(ap2); 288240116Smarcel if (atf_is_error(err)) 289240116Smarcel atf_dynstr_fini(d); 290240116Smarcel else { 291240116Smarcel err = normalize(d, str); 292240116Smarcel free(str); 293240116Smarcel } 294240116Smarcel 295240116Smarcelout: 296240116Smarcel return err; 297240116Smarcel} 298240116Smarcel 299240116Smarcelstatic 300240116Smarcelvoid 301240116Smarcelreplace_contents(atf_fs_path_t *p, const char *buf) 302240116Smarcel{ 303240116Smarcel atf_error_t err; 304240116Smarcel 305240116Smarcel PRE(atf_dynstr_length(&p->m_data) == strlen(buf)); 306240116Smarcel 307240116Smarcel atf_dynstr_clear(&p->m_data); 308240116Smarcel err = atf_dynstr_append_fmt(&p->m_data, "%s", buf); 309240116Smarcel 310240116Smarcel INV(!atf_is_error(err)); 311240116Smarcel} 312240116Smarcel 313240116Smarcelstatic 314240116Smarcelconst char * 315240116Smarcelstat_type_to_string(const int type) 316240116Smarcel{ 317240116Smarcel const char *str; 318240116Smarcel 319240116Smarcel if (type == atf_fs_stat_blk_type) 320240116Smarcel str = "block device"; 321240116Smarcel else if (type == atf_fs_stat_chr_type) 322240116Smarcel str = "character device"; 323240116Smarcel else if (type == atf_fs_stat_dir_type) 324240116Smarcel str = "directory"; 325240116Smarcel else if (type == atf_fs_stat_fifo_type) 326240116Smarcel str = "named pipe"; 327240116Smarcel else if (type == atf_fs_stat_lnk_type) 328240116Smarcel str = "symbolic link"; 329240116Smarcel else if (type == atf_fs_stat_reg_type) 330240116Smarcel str = "regular file"; 331240116Smarcel else if (type == atf_fs_stat_sock_type) 332240116Smarcel str = "socket"; 333240116Smarcel else if (type == atf_fs_stat_wht_type) 334240116Smarcel str = "whiteout"; 335240116Smarcel else { 336240116Smarcel UNREACHABLE; 337240116Smarcel str = NULL; 338240116Smarcel } 339240116Smarcel 340240116Smarcel return str; 341240116Smarcel} 342240116Smarcel 343240116Smarcel/* --------------------------------------------------------------------- 344240116Smarcel * The "atf_fs_path" type. 345240116Smarcel * --------------------------------------------------------------------- */ 346240116Smarcel 347240116Smarcel/* 348240116Smarcel * Constructors/destructors. 349240116Smarcel */ 350240116Smarcel 351240116Smarcelatf_error_t 352240116Smarcelatf_fs_path_init_ap(atf_fs_path_t *p, const char *fmt, va_list ap) 353240116Smarcel{ 354240116Smarcel atf_error_t err; 355240116Smarcel va_list ap2; 356240116Smarcel 357240116Smarcel va_copy(ap2, ap); 358240116Smarcel err = normalize_ap(&p->m_data, fmt, ap2); 359240116Smarcel va_end(ap2); 360240116Smarcel 361240116Smarcel return err; 362240116Smarcel} 363240116Smarcel 364240116Smarcelatf_error_t 365240116Smarcelatf_fs_path_init_fmt(atf_fs_path_t *p, const char *fmt, ...) 366240116Smarcel{ 367240116Smarcel va_list ap; 368240116Smarcel atf_error_t err; 369240116Smarcel 370240116Smarcel va_start(ap, fmt); 371240116Smarcel err = atf_fs_path_init_ap(p, fmt, ap); 372240116Smarcel va_end(ap); 373240116Smarcel 374240116Smarcel return err; 375240116Smarcel} 376240116Smarcel 377240116Smarcelatf_error_t 378240116Smarcelatf_fs_path_copy(atf_fs_path_t *dest, const atf_fs_path_t *src) 379240116Smarcel{ 380240116Smarcel return atf_dynstr_copy(&dest->m_data, &src->m_data); 381240116Smarcel} 382240116Smarcel 383240116Smarcelvoid 384240116Smarcelatf_fs_path_fini(atf_fs_path_t *p) 385240116Smarcel{ 386240116Smarcel atf_dynstr_fini(&p->m_data); 387240116Smarcel} 388240116Smarcel 389240116Smarcel/* 390240116Smarcel * Getters. 391240116Smarcel */ 392240116Smarcel 393240116Smarcelatf_error_t 394240116Smarcelatf_fs_path_branch_path(const atf_fs_path_t *p, atf_fs_path_t *bp) 395240116Smarcel{ 396240116Smarcel const size_t endpos = atf_dynstr_rfind_ch(&p->m_data, '/'); 397240116Smarcel atf_error_t err; 398240116Smarcel 399240116Smarcel if (endpos == atf_dynstr_npos) 400240116Smarcel err = atf_fs_path_init_fmt(bp, "."); 401240116Smarcel else if (endpos == 0) 402240116Smarcel err = atf_fs_path_init_fmt(bp, "/"); 403240116Smarcel else 404240116Smarcel err = atf_dynstr_init_substr(&bp->m_data, &p->m_data, 0, endpos); 405240116Smarcel 406240116Smarcel#if defined(HAVE_CONST_DIRNAME) 407240116Smarcel INV(atf_equal_dynstr_cstring(&bp->m_data, 408240116Smarcel dirname(atf_dynstr_cstring(&p->m_data)))); 409240116Smarcel#endif /* defined(HAVE_CONST_DIRNAME) */ 410240116Smarcel 411240116Smarcel return err; 412240116Smarcel} 413240116Smarcel 414240116Smarcelconst char * 415240116Smarcelatf_fs_path_cstring(const atf_fs_path_t *p) 416240116Smarcel{ 417240116Smarcel return atf_dynstr_cstring(&p->m_data); 418240116Smarcel} 419240116Smarcel 420240116Smarcelatf_error_t 421240116Smarcelatf_fs_path_leaf_name(const atf_fs_path_t *p, atf_dynstr_t *ln) 422240116Smarcel{ 423240116Smarcel size_t begpos = atf_dynstr_rfind_ch(&p->m_data, '/'); 424240116Smarcel atf_error_t err; 425240116Smarcel 426240116Smarcel if (begpos == atf_dynstr_npos) 427240116Smarcel begpos = 0; 428240116Smarcel else 429240116Smarcel begpos++; 430240116Smarcel 431240116Smarcel err = atf_dynstr_init_substr(ln, &p->m_data, begpos, atf_dynstr_npos); 432240116Smarcel 433240116Smarcel#if defined(HAVE_CONST_BASENAME) 434240116Smarcel INV(atf_equal_dynstr_cstring(ln, 435240116Smarcel basename(atf_dynstr_cstring(&p->m_data)))); 436240116Smarcel#endif /* defined(HAVE_CONST_BASENAME) */ 437240116Smarcel 438240116Smarcel return err; 439240116Smarcel} 440240116Smarcel 441240116Smarcelbool 442240116Smarcelatf_fs_path_is_absolute(const atf_fs_path_t *p) 443240116Smarcel{ 444240116Smarcel return atf_dynstr_cstring(&p->m_data)[0] == '/'; 445240116Smarcel} 446240116Smarcel 447240116Smarcelbool 448240116Smarcelatf_fs_path_is_root(const atf_fs_path_t *p) 449240116Smarcel{ 450240116Smarcel return atf_equal_dynstr_cstring(&p->m_data, "/"); 451240116Smarcel} 452240116Smarcel 453240116Smarcel/* 454240116Smarcel * Modifiers. 455240116Smarcel */ 456240116Smarcel 457240116Smarcelatf_error_t 458240116Smarcelatf_fs_path_append_ap(atf_fs_path_t *p, const char *fmt, va_list ap) 459240116Smarcel{ 460240116Smarcel atf_dynstr_t aux; 461240116Smarcel atf_error_t err; 462240116Smarcel va_list ap2; 463240116Smarcel 464240116Smarcel va_copy(ap2, ap); 465240116Smarcel err = normalize_ap(&aux, fmt, ap2); 466240116Smarcel va_end(ap2); 467240116Smarcel if (!atf_is_error(err)) { 468240116Smarcel const char *auxstr = atf_dynstr_cstring(&aux); 469240116Smarcel const bool needslash = auxstr[0] != '/'; 470240116Smarcel 471240116Smarcel err = atf_dynstr_append_fmt(&p->m_data, "%s%s", 472240116Smarcel needslash ? "/" : "", auxstr); 473240116Smarcel 474240116Smarcel atf_dynstr_fini(&aux); 475240116Smarcel } 476240116Smarcel 477240116Smarcel return err; 478240116Smarcel} 479240116Smarcel 480240116Smarcelatf_error_t 481240116Smarcelatf_fs_path_append_fmt(atf_fs_path_t *p, const char *fmt, ...) 482240116Smarcel{ 483240116Smarcel va_list ap; 484240116Smarcel atf_error_t err; 485240116Smarcel 486240116Smarcel va_start(ap, fmt); 487240116Smarcel err = atf_fs_path_append_ap(p, fmt, ap); 488240116Smarcel va_end(ap); 489240116Smarcel 490240116Smarcel return err; 491240116Smarcel} 492240116Smarcel 493240116Smarcelatf_error_t 494240116Smarcelatf_fs_path_append_path(atf_fs_path_t *p, const atf_fs_path_t *p2) 495240116Smarcel{ 496240116Smarcel return atf_fs_path_append_fmt(p, "%s", atf_dynstr_cstring(&p2->m_data)); 497240116Smarcel} 498240116Smarcel 499240116Smarcelatf_error_t 500240116Smarcelatf_fs_path_to_absolute(const atf_fs_path_t *p, atf_fs_path_t *pa) 501240116Smarcel{ 502240116Smarcel atf_error_t err; 503240116Smarcel 504240116Smarcel PRE(!atf_fs_path_is_absolute(p)); 505240116Smarcel 506240116Smarcel err = atf_fs_getcwd(pa); 507240116Smarcel if (atf_is_error(err)) 508240116Smarcel goto out; 509240116Smarcel 510240116Smarcel err = atf_fs_path_append_path(pa, p); 511240116Smarcel if (atf_is_error(err)) 512240116Smarcel atf_fs_path_fini(pa); 513240116Smarcel 514240116Smarcelout: 515240116Smarcel return err; 516240116Smarcel} 517240116Smarcel 518240116Smarcel/* 519240116Smarcel * Operators. 520240116Smarcel */ 521240116Smarcel 522240116Smarcelbool atf_equal_fs_path_fs_path(const atf_fs_path_t *p1, 523240116Smarcel const atf_fs_path_t *p2) 524240116Smarcel{ 525240116Smarcel return atf_equal_dynstr_dynstr(&p1->m_data, &p2->m_data); 526240116Smarcel} 527240116Smarcel 528240116Smarcel/* --------------------------------------------------------------------- 529240116Smarcel * The "atf_fs_path" type. 530240116Smarcel * --------------------------------------------------------------------- */ 531240116Smarcel 532240116Smarcel/* 533240116Smarcel * Constants. 534240116Smarcel */ 535240116Smarcel 536240116Smarcelconst int atf_fs_stat_blk_type = 1; 537240116Smarcelconst int atf_fs_stat_chr_type = 2; 538240116Smarcelconst int atf_fs_stat_dir_type = 3; 539240116Smarcelconst int atf_fs_stat_fifo_type = 4; 540240116Smarcelconst int atf_fs_stat_lnk_type = 5; 541240116Smarcelconst int atf_fs_stat_reg_type = 6; 542240116Smarcelconst int atf_fs_stat_sock_type = 7; 543240116Smarcelconst int atf_fs_stat_wht_type = 8; 544240116Smarcel 545240116Smarcel/* 546240116Smarcel * Constructors/destructors. 547240116Smarcel */ 548240116Smarcel 549240116Smarcelatf_error_t 550240116Smarcelatf_fs_stat_init(atf_fs_stat_t *st, const atf_fs_path_t *p) 551240116Smarcel{ 552240116Smarcel atf_error_t err; 553240116Smarcel const char *pstr = atf_fs_path_cstring(p); 554240116Smarcel 555240116Smarcel if (lstat(pstr, &st->m_sb) == -1) { 556240116Smarcel err = atf_libc_error(errno, "Cannot get information of %s; " 557240116Smarcel "lstat(2) failed", pstr); 558240116Smarcel } else { 559240116Smarcel int type = st->m_sb.st_mode & S_IFMT; 560240116Smarcel err = atf_no_error(); 561240116Smarcel switch (type) { 562240116Smarcel case S_IFBLK: st->m_type = atf_fs_stat_blk_type; break; 563240116Smarcel case S_IFCHR: st->m_type = atf_fs_stat_chr_type; break; 564240116Smarcel case S_IFDIR: st->m_type = atf_fs_stat_dir_type; break; 565240116Smarcel case S_IFIFO: st->m_type = atf_fs_stat_fifo_type; break; 566240116Smarcel case S_IFLNK: st->m_type = atf_fs_stat_lnk_type; break; 567240116Smarcel case S_IFREG: st->m_type = atf_fs_stat_reg_type; break; 568240116Smarcel case S_IFSOCK: st->m_type = atf_fs_stat_sock_type; break; 569240116Smarcel#if defined(S_IFWHT) 570240116Smarcel case S_IFWHT: st->m_type = atf_fs_stat_wht_type; break; 571240116Smarcel#endif 572240116Smarcel default: 573240116Smarcel err = unknown_type_error(pstr, type); 574240116Smarcel } 575240116Smarcel } 576240116Smarcel 577240116Smarcel return err; 578240116Smarcel} 579240116Smarcel 580240116Smarcelvoid 581240116Smarcelatf_fs_stat_copy(atf_fs_stat_t *dest, const atf_fs_stat_t *src) 582240116Smarcel{ 583240116Smarcel dest->m_type = src->m_type; 584240116Smarcel dest->m_sb = src->m_sb; 585240116Smarcel} 586240116Smarcel 587240116Smarcelvoid 588240116Smarcelatf_fs_stat_fini(atf_fs_stat_t *st ATF_DEFS_ATTRIBUTE_UNUSED) 589240116Smarcel{ 590240116Smarcel} 591240116Smarcel 592240116Smarcel/* 593240116Smarcel * Getters. 594240116Smarcel */ 595240116Smarcel 596240116Smarceldev_t 597240116Smarcelatf_fs_stat_get_device(const atf_fs_stat_t *st) 598240116Smarcel{ 599240116Smarcel return st->m_sb.st_dev; 600240116Smarcel} 601240116Smarcel 602240116Smarcelino_t 603240116Smarcelatf_fs_stat_get_inode(const atf_fs_stat_t *st) 604240116Smarcel{ 605240116Smarcel return st->m_sb.st_ino; 606240116Smarcel} 607240116Smarcel 608240116Smarcelmode_t 609240116Smarcelatf_fs_stat_get_mode(const atf_fs_stat_t *st) 610240116Smarcel{ 611240116Smarcel return st->m_sb.st_mode & ~S_IFMT; 612240116Smarcel} 613240116Smarcel 614240116Smarceloff_t 615240116Smarcelatf_fs_stat_get_size(const atf_fs_stat_t *st) 616240116Smarcel{ 617240116Smarcel return st->m_sb.st_size; 618240116Smarcel} 619240116Smarcel 620240116Smarcelint 621240116Smarcelatf_fs_stat_get_type(const atf_fs_stat_t *st) 622240116Smarcel{ 623240116Smarcel return st->m_type; 624240116Smarcel} 625240116Smarcel 626240116Smarcelbool 627240116Smarcelatf_fs_stat_is_owner_readable(const atf_fs_stat_t *st) 628240116Smarcel{ 629240116Smarcel return st->m_sb.st_mode & S_IRUSR; 630240116Smarcel} 631240116Smarcel 632240116Smarcelbool 633240116Smarcelatf_fs_stat_is_owner_writable(const atf_fs_stat_t *st) 634240116Smarcel{ 635240116Smarcel return st->m_sb.st_mode & S_IWUSR; 636240116Smarcel} 637240116Smarcel 638240116Smarcelbool 639240116Smarcelatf_fs_stat_is_owner_executable(const atf_fs_stat_t *st) 640240116Smarcel{ 641240116Smarcel return st->m_sb.st_mode & S_IXUSR; 642240116Smarcel} 643240116Smarcel 644240116Smarcelbool 645240116Smarcelatf_fs_stat_is_group_readable(const atf_fs_stat_t *st) 646240116Smarcel{ 647240116Smarcel return st->m_sb.st_mode & S_IRGRP; 648240116Smarcel} 649240116Smarcel 650240116Smarcelbool 651240116Smarcelatf_fs_stat_is_group_writable(const atf_fs_stat_t *st) 652240116Smarcel{ 653240116Smarcel return st->m_sb.st_mode & S_IWGRP; 654240116Smarcel} 655240116Smarcel 656240116Smarcelbool 657240116Smarcelatf_fs_stat_is_group_executable(const atf_fs_stat_t *st) 658240116Smarcel{ 659240116Smarcel return st->m_sb.st_mode & S_IXGRP; 660240116Smarcel} 661240116Smarcel 662240116Smarcelbool 663240116Smarcelatf_fs_stat_is_other_readable(const atf_fs_stat_t *st) 664240116Smarcel{ 665240116Smarcel return st->m_sb.st_mode & S_IROTH; 666240116Smarcel} 667240116Smarcel 668240116Smarcelbool 669240116Smarcelatf_fs_stat_is_other_writable(const atf_fs_stat_t *st) 670240116Smarcel{ 671240116Smarcel return st->m_sb.st_mode & S_IWOTH; 672240116Smarcel} 673240116Smarcel 674240116Smarcelbool 675240116Smarcelatf_fs_stat_is_other_executable(const atf_fs_stat_t *st) 676240116Smarcel{ 677240116Smarcel return st->m_sb.st_mode & S_IXOTH; 678240116Smarcel} 679240116Smarcel 680240116Smarcel/* --------------------------------------------------------------------- 681240116Smarcel * Free functions. 682240116Smarcel * --------------------------------------------------------------------- */ 683240116Smarcel 684240116Smarcelconst int atf_fs_access_f = 1 << 0; 685240116Smarcelconst int atf_fs_access_r = 1 << 1; 686240116Smarcelconst int atf_fs_access_w = 1 << 2; 687240116Smarcelconst int atf_fs_access_x = 1 << 3; 688240116Smarcel 689240116Smarcel/* 690240116Smarcel * An implementation of access(2) but using the effective user value 691240116Smarcel * instead of the real one. Also avoids false positives for root when 692240116Smarcel * asking for execute permissions, which appear in SunOS. 693240116Smarcel */ 694240116Smarcelatf_error_t 695240116Smarcelatf_fs_eaccess(const atf_fs_path_t *p, int mode) 696240116Smarcel{ 697240116Smarcel atf_error_t err; 698240116Smarcel struct stat st; 699240116Smarcel bool ok; 700240116Smarcel 701240116Smarcel PRE(mode & atf_fs_access_f || mode & atf_fs_access_r || 702240116Smarcel mode & atf_fs_access_w || mode & atf_fs_access_x); 703240116Smarcel 704240116Smarcel if (lstat(atf_fs_path_cstring(p), &st) == -1) { 705240116Smarcel err = atf_libc_error(errno, "Cannot get information from file %s", 706240116Smarcel atf_fs_path_cstring(p)); 707240116Smarcel goto out; 708240116Smarcel } 709240116Smarcel 710240116Smarcel err = atf_no_error(); 711240116Smarcel 712240116Smarcel /* Early return if we are only checking for existence and the file 713240116Smarcel * exists (stat call returned). */ 714240116Smarcel if (mode & atf_fs_access_f) 715240116Smarcel goto out; 716240116Smarcel 717240116Smarcel ok = false; 718240116Smarcel if (atf_user_is_root()) { 719240116Smarcel if (!ok && !(mode & atf_fs_access_x)) { 720240116Smarcel /* Allow root to read/write any file. */ 721240116Smarcel ok = true; 722240116Smarcel } 723240116Smarcel 724240116Smarcel if (!ok && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) { 725240116Smarcel /* Allow root to execute the file if any of its execution bits 726240116Smarcel * are set. */ 727240116Smarcel ok = true; 728240116Smarcel } 729240116Smarcel } else { 730240116Smarcel if (!ok && (atf_user_euid() == st.st_uid)) { 731240116Smarcel ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRUSR)) || 732240116Smarcel ((mode & atf_fs_access_w) && (st.st_mode & S_IWUSR)) || 733240116Smarcel ((mode & atf_fs_access_x) && (st.st_mode & S_IXUSR)); 734240116Smarcel } 735240116Smarcel if (!ok && atf_user_is_member_of_group(st.st_gid)) { 736240116Smarcel ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IRGRP)) || 737240116Smarcel ((mode & atf_fs_access_w) && (st.st_mode & S_IWGRP)) || 738240116Smarcel ((mode & atf_fs_access_x) && (st.st_mode & S_IXGRP)); 739240116Smarcel } 740240116Smarcel if (!ok && ((atf_user_euid() != st.st_uid) && 741240116Smarcel !atf_user_is_member_of_group(st.st_gid))) { 742240116Smarcel ok = ((mode & atf_fs_access_r) && (st.st_mode & S_IROTH)) || 743240116Smarcel ((mode & atf_fs_access_w) && (st.st_mode & S_IWOTH)) || 744240116Smarcel ((mode & atf_fs_access_x) && (st.st_mode & S_IXOTH)); 745240116Smarcel } 746240116Smarcel } 747240116Smarcel 748240116Smarcel if (!ok) 749240116Smarcel err = atf_libc_error(EACCES, "Access check failed"); 750240116Smarcel 751240116Smarcelout: 752240116Smarcel return err; 753240116Smarcel} 754240116Smarcel 755240116Smarcelatf_error_t 756240116Smarcelatf_fs_exists(const atf_fs_path_t *p, bool *b) 757240116Smarcel{ 758240116Smarcel atf_error_t err; 759240116Smarcel 760240116Smarcel err = atf_fs_eaccess(p, atf_fs_access_f); 761240116Smarcel if (atf_is_error(err)) { 762240116Smarcel if (atf_error_is(err, "libc") && atf_libc_error_code(err) == ENOENT) { 763240116Smarcel atf_error_free(err); 764240116Smarcel err = atf_no_error(); 765240116Smarcel *b = false; 766240116Smarcel } 767240116Smarcel } else 768240116Smarcel *b = true; 769240116Smarcel 770240116Smarcel return err; 771240116Smarcel} 772240116Smarcel 773240116Smarcelatf_error_t 774240116Smarcelatf_fs_getcwd(atf_fs_path_t *p) 775240116Smarcel{ 776240116Smarcel atf_error_t err; 777240116Smarcel char *cwd; 778240116Smarcel 779240116Smarcel#if defined(HAVE_GETCWD_DYN) 780240116Smarcel cwd = getcwd(NULL, 0); 781240116Smarcel#else 782240116Smarcel cwd = getcwd(NULL, MAXPATHLEN); 783240116Smarcel#endif 784240116Smarcel if (cwd == NULL) { 785240116Smarcel err = atf_libc_error(errno, "Cannot determine current directory"); 786240116Smarcel goto out; 787240116Smarcel } 788240116Smarcel 789240116Smarcel err = atf_fs_path_init_fmt(p, "%s", cwd); 790240116Smarcel free(cwd); 791240116Smarcel 792240116Smarcelout: 793240116Smarcel return err; 794240116Smarcel} 795240116Smarcel 796240116Smarcelatf_error_t 797240116Smarcelatf_fs_mkdtemp(atf_fs_path_t *p) 798240116Smarcel{ 799240116Smarcel atf_error_t err; 800240116Smarcel char *buf; 801240116Smarcel 802240116Smarcel if (!check_umask(S_IRWXU, S_IRWXU)) { 803240116Smarcel err = invalid_umask_error(p, atf_fs_stat_dir_type, current_umask()); 804240116Smarcel goto out; 805240116Smarcel } 806240116Smarcel 807240116Smarcel err = copy_contents(p, &buf); 808240116Smarcel if (atf_is_error(err)) 809240116Smarcel goto out; 810240116Smarcel 811240116Smarcel err = do_mkdtemp(buf); 812240116Smarcel if (atf_is_error(err)) 813240116Smarcel goto out_buf; 814240116Smarcel 815240116Smarcel replace_contents(p, buf); 816240116Smarcel 817240116Smarcel INV(!atf_is_error(err)); 818240116Smarcelout_buf: 819240116Smarcel free(buf); 820240116Smarcelout: 821240116Smarcel return err; 822240116Smarcel} 823240116Smarcel 824240116Smarcelatf_error_t 825240116Smarcelatf_fs_mkstemp(atf_fs_path_t *p, int *fdout) 826240116Smarcel{ 827240116Smarcel atf_error_t err; 828240116Smarcel char *buf; 829240116Smarcel int fd; 830240116Smarcel 831240116Smarcel if (!check_umask(S_IRWXU, S_IRWXU)) { 832240116Smarcel err = invalid_umask_error(p, atf_fs_stat_reg_type, current_umask()); 833240116Smarcel goto out; 834240116Smarcel } 835240116Smarcel 836240116Smarcel err = copy_contents(p, &buf); 837240116Smarcel if (atf_is_error(err)) 838240116Smarcel goto out; 839240116Smarcel 840240116Smarcel err = do_mkstemp(buf, &fd); 841240116Smarcel if (atf_is_error(err)) 842240116Smarcel goto out_buf; 843240116Smarcel 844240116Smarcel replace_contents(p, buf); 845240116Smarcel *fdout = fd; 846240116Smarcel 847240116Smarcel INV(!atf_is_error(err)); 848240116Smarcelout_buf: 849240116Smarcel free(buf); 850240116Smarcelout: 851240116Smarcel return err; 852240116Smarcel} 853240116Smarcel 854240116Smarcelatf_error_t 855240116Smarcelatf_fs_rmdir(const atf_fs_path_t *p) 856240116Smarcel{ 857240116Smarcel atf_error_t err; 858240116Smarcel 859240116Smarcel if (rmdir(atf_fs_path_cstring(p))) { 860240116Smarcel if (errno == EEXIST) { 861240116Smarcel /* Some operating systems (e.g. OpenSolaris 200906) return 862240116Smarcel * EEXIST instead of ENOTEMPTY for non-empty directories. 863240116Smarcel * Homogenize the return value so that callers don't need 864240116Smarcel * to bother about differences in operating systems. */ 865240116Smarcel errno = ENOTEMPTY; 866240116Smarcel } 867240116Smarcel err = atf_libc_error(errno, "Cannot remove directory"); 868240116Smarcel } else 869240116Smarcel err = atf_no_error(); 870240116Smarcel 871240116Smarcel return err; 872240116Smarcel} 873240116Smarcel 874240116Smarcelatf_error_t 875240116Smarcelatf_fs_unlink(const atf_fs_path_t *p) 876240116Smarcel{ 877240116Smarcel atf_error_t err; 878240116Smarcel const char *path; 879240116Smarcel 880240116Smarcel path = atf_fs_path_cstring(p); 881240116Smarcel 882240116Smarcel if (unlink(path) != 0) 883240116Smarcel err = atf_libc_error(errno, "Cannot unlink file: '%s'", path); 884240116Smarcel else 885240116Smarcel err = atf_no_error(); 886240116Smarcel 887240116Smarcel return err; 888240116Smarcel} 889