| // SPDX-License-Identifier: GPL-2.0-or-later |
| /* |
| * Copyright (c) Linux Test Project, 2010-2020 |
| */ |
| |
| #define _GNU_SOURCE |
| #include <sys/types.h> |
| #include <sys/mman.h> |
| #include <sys/resource.h> |
| #include <sys/stat.h> |
| #include <sys/wait.h> |
| #include <sys/mount.h> |
| #include <sys/xattr.h> |
| #include <sys/sysinfo.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <libgen.h> |
| #include <limits.h> |
| #include <pwd.h> |
| #include <stdarg.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <malloc.h> |
| #include "test.h" |
| #include "safe_macros.h" |
| |
| char *safe_basename(const char *file, const int lineno, |
| void (*cleanup_fn) (void), char *path) |
| { |
| char *rval; |
| |
| rval = basename(path); |
| |
| if (rval == NULL) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "basename(%s) failed", path); |
| } |
| |
| return rval; |
| } |
| |
| int |
| safe_chdir(const char *file, const int lineno, void (*cleanup_fn) (void), |
| const char *path) |
| { |
| int rval; |
| |
| rval = chdir(path); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "chdir(%s) failed", path); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid chdir(%s) return value %d", path, rval); |
| } |
| |
| return rval; |
| } |
| |
| int |
| safe_close(const char *file, const int lineno, void (*cleanup_fn) (void), |
| int fildes) |
| { |
| int rval; |
| |
| rval = close(fildes); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "close(%d) failed", fildes); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid close(%d) return value %d", fildes, rval); |
| } |
| |
| return rval; |
| } |
| |
| int |
| safe_creat(const char *file, const int lineno, void (*cleanup_fn) (void), |
| const char *pathname, mode_t mode) |
| { |
| int rval; |
| |
| rval = creat(pathname, mode); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "creat(%s,%04o) failed", pathname, mode); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid creat(%s,%04o) return value %d", pathname, |
| mode, rval); |
| } |
| |
| return rval; |
| } |
| |
| char *safe_dirname(const char *file, const int lineno, |
| void (*cleanup_fn) (void), char *path) |
| { |
| char *rval; |
| |
| rval = dirname(path); |
| |
| if (rval == NULL) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "dirname(%s) failed", path); |
| } |
| |
| return rval; |
| } |
| |
| char *safe_getcwd(const char *file, const int lineno, void (*cleanup_fn) (void), |
| char *buf, size_t size) |
| { |
| char *rval; |
| |
| rval = getcwd(buf, size); |
| |
| if (rval == NULL) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "getcwd(%p,%zu) failed", buf, size); |
| } |
| |
| return rval; |
| } |
| |
| struct passwd *safe_getpwnam(const char *file, const int lineno, |
| void (*cleanup_fn) (void), const char *name) |
| { |
| struct passwd *rval; |
| |
| rval = getpwnam(name); |
| |
| if (rval == NULL) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "getpwnam(%s) failed", name); |
| } |
| |
| return rval; |
| } |
| |
| int |
| safe_getrusage(const char *file, const int lineno, void (*cleanup_fn) (void), |
| int who, struct rusage *usage) |
| { |
| int rval; |
| |
| rval = getrusage(who, usage); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "getrusage(%d,%p) failed", who, usage); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid getrusage(%d,%p) return value %d", who, |
| usage, rval); |
| } |
| |
| return rval; |
| } |
| |
| void *safe_malloc(const char *file, const int lineno, void (*cleanup_fn) (void), |
| size_t size) |
| { |
| void *rval; |
| |
| rval = malloc(size); |
| |
| if (rval == NULL) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "malloc(%zu) failed", size); |
| } |
| |
| return rval; |
| } |
| |
| int safe_mkdir(const char *file, const int lineno, void (*cleanup_fn) (void), |
| const char *pathname, mode_t mode) |
| { |
| int rval; |
| |
| rval = mkdir(pathname, mode); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "mkdir(%s, %04o) failed", pathname, mode); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid mkdir(%s, %04o) return value %d", pathname, |
| mode, rval); |
| } |
| |
| return (rval); |
| } |
| |
| int safe_rmdir(const char *file, const int lineno, void (*cleanup_fn) (void), |
| const char *pathname) |
| { |
| int rval; |
| |
| rval = rmdir(pathname); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "rmdir(%s) failed", pathname); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid rmdir(%s) return value %d", pathname, rval); |
| } |
| |
| return (rval); |
| } |
| |
| int safe_munmap(const char *file, const int lineno, void (*cleanup_fn) (void), |
| void *addr, size_t length) |
| { |
| int rval; |
| |
| rval = munmap(addr, length); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "munmap(%p,%zu) failed", addr, length); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid munmap(%p,%zu) return value %d", addr, |
| length, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_open(const char *file, const int lineno, void (*cleanup_fn) (void), |
| const char *pathname, int oflags, ...) |
| { |
| va_list ap; |
| int rval; |
| mode_t mode; |
| |
| va_start(ap, oflags); |
| |
| /* Android's NDK's mode_t is smaller than an int, which results in |
| * SIGILL here when passing the mode_t type. |
| */ |
| mode = va_arg(ap, int); |
| |
| va_end(ap); |
| |
| rval = open(pathname, oflags, mode); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "open(%s,%d,%04o) failed", pathname, oflags, mode); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid open(%s,%d,%04o) return value %d", pathname, |
| oflags, mode, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_pipe(const char *file, const int lineno, void (*cleanup_fn) (void), |
| int fildes[2]) |
| { |
| int rval; |
| |
| rval = pipe(fildes); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "pipe({%d,%d}) failed", fildes[0], fildes[1]); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid pipe({%d,%d}) return value %d", fildes[0], |
| fildes[1], rval); |
| } |
| |
| return rval; |
| } |
| |
| ssize_t safe_read(const char *file, const int lineno, void (*cleanup_fn) (void), |
| char len_strict, int fildes, void *buf, size_t nbyte) |
| { |
| ssize_t rval; |
| |
| rval = read(fildes, buf, nbyte); |
| |
| if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "read(%d,%p,%zu) failed, returned %zd", fildes, buf, |
| nbyte, rval); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid read(%d,%p,%zu) return value %zd", fildes, |
| buf, nbyte, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_setegid(const char *file, const int lineno, void (*cleanup_fn) (void), |
| gid_t egid) |
| { |
| int rval; |
| |
| rval = setegid(egid); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "setegid(%u) failed", (unsigned int)egid); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid setegid(%u) return value %d", |
| (unsigned int)egid, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_seteuid(const char *file, const int lineno, void (*cleanup_fn) (void), |
| uid_t euid) |
| { |
| int rval; |
| |
| rval = seteuid(euid); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "seteuid(%u) failed", (unsigned int)euid); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid seteuid(%u) return value %d", |
| (unsigned int)euid, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_setgid(const char *file, const int lineno, void (*cleanup_fn) (void), |
| gid_t gid) |
| { |
| int rval; |
| |
| rval = setgid(gid); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "setgid(%u) failed", (unsigned int)gid); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid setgid(%u) return value %d", |
| (unsigned int)gid, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_setuid(const char *file, const int lineno, void (*cleanup_fn) (void), |
| uid_t uid) |
| { |
| int rval; |
| |
| rval = setuid(uid); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "setuid(%u) failed", (unsigned int)uid); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid setuid(%u) return value %d", |
| (unsigned int)uid, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_getresuid(const char *file, const int lineno, void (*cleanup_fn)(void), |
| uid_t *ruid, uid_t *euid, uid_t *suid) |
| { |
| int rval; |
| |
| rval = getresuid(ruid, euid, suid); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "getresuid(%p, %p, %p) failed", ruid, euid, suid); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid getresuid(%p, %p, %p) return value %d", ruid, |
| euid, suid, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_getresgid(const char *file, const int lineno, void (*cleanup_fn)(void), |
| gid_t *rgid, gid_t *egid, gid_t *sgid) |
| { |
| int rval; |
| |
| rval = getresgid(rgid, egid, sgid); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "getresgid(%p, %p, %p) failed", rgid, egid, sgid); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid getresgid(%p, %p, %p) return value %d", rgid, |
| egid, sgid, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_unlink(const char *file, const int lineno, void (*cleanup_fn) (void), |
| const char *pathname) |
| { |
| int rval; |
| |
| rval = unlink(pathname); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "unlink(%s) failed", pathname); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid unlink(%s) return value %d", pathname, rval); |
| } |
| |
| return rval; |
| } |
| |
| |
| int safe_link(const char *file, const int lineno, |
| void (cleanup_fn)(void), const char *oldpath, |
| const char *newpath) |
| { |
| int rval; |
| |
| rval = link(oldpath, newpath); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "link(%s,%s) failed", oldpath, newpath); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid link(%s,%s) return value %d", oldpath, |
| newpath, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_linkat(const char *file, const int lineno, |
| void (cleanup_fn)(void), int olddirfd, const char *oldpath, |
| int newdirfd, const char *newpath, int flags) |
| { |
| int rval; |
| |
| rval = linkat(olddirfd, oldpath, newdirfd, newpath, flags); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "linkat(%d,%s,%d,%s,%d) failed", olddirfd, oldpath, |
| newdirfd, newpath, flags); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid linkat(%d,%s,%d,%s,%d) return value %d", |
| olddirfd, oldpath, newdirfd, newpath, flags, rval); |
| } |
| |
| return rval; |
| } |
| |
| ssize_t safe_readlink(const char *file, const int lineno, |
| void (cleanup_fn)(void), const char *path, |
| char *buf, size_t bufsize) |
| { |
| ssize_t rval; |
| |
| rval = readlink(path, buf, bufsize); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "readlink(%s,%p,%zu) failed", path, buf, bufsize); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid readlink(%s,%p,%zu) return value %zd", path, |
| buf, bufsize, rval); |
| } else { |
| /* readlink does not append a NUL byte to the buffer. |
| * Add it now. */ |
| if ((size_t) rval < bufsize) |
| buf[rval] = '\0'; |
| else |
| buf[bufsize-1] = '\0'; |
| } |
| |
| return rval; |
| } |
| |
| int safe_symlink(const char *file, const int lineno, |
| void (cleanup_fn)(void), const char *oldpath, |
| const char *newpath) |
| { |
| int rval; |
| |
| rval = symlink(oldpath, newpath); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "symlink(%s,%s) failed", oldpath, newpath); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid symlink(%s,%s) return value %d", oldpath, |
| newpath, rval); |
| } |
| |
| return rval; |
| } |
| |
| ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void), |
| char len_strict, int fildes, const void *buf, size_t nbyte) |
| { |
| ssize_t rval; |
| |
| rval = write(fildes, buf, nbyte); |
| |
| if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "write(%d,%p,%zu) failed", fildes, buf, nbyte); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid write(%d,%p,%zu) return value %zd", fildes, |
| buf, nbyte, rval); |
| } |
| |
| return rval; |
| } |
| |
| long safe_strtol(const char *file, const int lineno, |
| void (cleanup_fn) (void), char *str, long min, long max) |
| { |
| long rval; |
| char *endptr; |
| |
| errno = 0; |
| rval = strtol(str, &endptr, 10); |
| |
| if ((errno == ERANGE && (rval == LONG_MAX || rval == LONG_MIN)) |
| || (errno != 0 && rval == 0)) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "strtol(%s) failed", str); |
| return rval; |
| } |
| |
| if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { |
| tst_brkm_(file, lineno, TBROK, cleanup_fn, |
| "strtol(%s): Invalid value", str); |
| return 0; |
| } |
| |
| if (rval > max || rval < min) { |
| tst_brkm_(file, lineno, TBROK, cleanup_fn, |
| "strtol(%s): %ld is out of range %ld - %ld", |
| str, rval, min, max); |
| return 0; |
| } |
| |
| return rval; |
| } |
| |
| unsigned long safe_strtoul(const char *file, const int lineno, |
| void (cleanup_fn) (void), char *str, |
| unsigned long min, unsigned long max) |
| { |
| unsigned long rval; |
| char *endptr; |
| |
| errno = 0; |
| rval = strtoul(str, &endptr, 10); |
| |
| if ((errno == ERANGE && rval == ULONG_MAX) |
| || (errno != 0 && rval == 0)) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "strtoul(%s) failed", str); |
| return rval; |
| } |
| |
| if (rval > max || rval < min) { |
| tst_brkm_(file, lineno, TBROK, cleanup_fn, |
| "strtoul(%s): %lu is out of range %lu - %lu", |
| str, rval, min, max); |
| return 0; |
| } |
| |
| if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { |
| tst_brkm_(file, lineno, TBROK, cleanup_fn, |
| "Invalid value: '%s'", str); |
| return 0; |
| } |
| |
| return rval; |
| } |
| |
| long safe_sysconf(const char *file, const int lineno, |
| void (cleanup_fn) (void), int name) |
| { |
| long rval; |
| |
| errno = 0; |
| rval = sysconf(name); |
| |
| if (rval == -1) { |
| if (errno) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "sysconf(%d) failed", name); |
| } else { |
| tst_resm_(file, lineno, TINFO, |
| "sysconf(%d): queried option is not available or there is no definite limit", |
| name); |
| } |
| } |
| |
| return rval; |
| } |
| |
| int safe_chmod(const char *file, const int lineno, |
| void (cleanup_fn)(void), const char *path, mode_t mode) |
| { |
| int rval; |
| |
| rval = chmod(path, mode); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "chmod(%s,%04o) failed", path, mode); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid chmod(%s,%04o) return value %d", path, mode, |
| rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_fchmod(const char *file, const int lineno, |
| void (cleanup_fn)(void), int fd, mode_t mode) |
| { |
| int rval; |
| |
| rval = fchmod(fd, mode); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "fchmod(%d,%04o) failed", fd, mode); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid fchmod(%d,%04o) return value %d", fd, mode, |
| rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_chown(const char *file, const int lineno, void (cleanup_fn)(void), |
| const char *path, uid_t owner, gid_t group) |
| { |
| int rval; |
| |
| rval = chown(path, owner, group); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "chown(%s,%d,%d) failed", path, owner, group); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid chown(%s,%d,%d) return value %d", path, |
| owner, group, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_fchown(const char *file, const int lineno, void (cleanup_fn)(void), |
| int fd, uid_t owner, gid_t group) |
| { |
| int rval; |
| |
| rval = fchown(fd, owner, group); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "fchown(%d,%d,%d) failed", fd, owner, group); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid fchown(%d,%d,%d) return value %d", fd, |
| owner, group, rval); |
| } |
| |
| return rval; |
| } |
| |
| pid_t safe_wait(const char *file, const int lineno, void (cleanup_fn)(void), |
| int *status) |
| { |
| pid_t rval; |
| |
| rval = wait(status); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "wait(%p) failed", status); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid wait(%p) return value %d", status, rval); |
| } |
| |
| return rval; |
| } |
| |
| pid_t safe_waitpid(const char *file, const int lineno, void (cleanup_fn)(void), |
| pid_t pid, int *status, int opts) |
| { |
| pid_t rval; |
| |
| rval = waitpid(pid, status, opts); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "waitpid(%d,%p,%d) failed", pid, status, opts); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid waitpid(%d,%p,%d) return value %d", pid, |
| status, opts, rval); |
| } |
| |
| return rval; |
| } |
| |
| void *safe_memalign(const char *file, const int lineno, |
| void (*cleanup_fn) (void), size_t alignment, size_t size) |
| { |
| void *rval; |
| |
| rval = memalign(alignment, size); |
| |
| if (rval == NULL) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "memalign() failed"); |
| } |
| |
| return rval; |
| } |
| |
| int safe_kill(const char *file, const int lineno, void (cleanup_fn)(void), |
| pid_t pid, int sig) |
| { |
| int rval; |
| |
| rval = kill(pid, sig); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "kill(%d,%s) failed", pid, tst_strsig(sig)); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid kill(%d,%s) return value %d", pid, |
| tst_strsig(sig), rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_mkfifo(const char *file, const int lineno, |
| void (*cleanup_fn)(void), const char *pathname, mode_t mode) |
| { |
| int rval; |
| |
| rval = mkfifo(pathname, mode); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "mkfifo(%s, %04o) failed", pathname, mode); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid mkfifo(%s, %04o) return value %d", pathname, |
| mode, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_rename(const char *file, const int lineno, void (*cleanup_fn)(void), |
| const char *oldpath, const char *newpath) |
| { |
| int rval; |
| |
| rval = rename(oldpath, newpath); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "rename(%s, %s) failed", oldpath, newpath); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid rename(%s, %s) return value %d", oldpath, |
| newpath, rval); |
| } |
| |
| return rval; |
| } |
| |
| static const char *const fuse_fs_types[] = { |
| "exfat", |
| "ntfs", |
| }; |
| |
| static int possibly_fuse(const char *fs_type) |
| { |
| unsigned int i; |
| |
| if (!fs_type) |
| return 0; |
| |
| for (i = 0; i < ARRAY_SIZE(fuse_fs_types); i++) { |
| if (!strcmp(fuse_fs_types[i], fs_type)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void), |
| const char *source, const char *target, |
| const char *filesystemtype, unsigned long mountflags, |
| const void *data) |
| { |
| int rval = -1; |
| |
| /* |
| * Don't try using the kernel's NTFS driver when mounting NTFS, since |
| * the kernel's NTFS driver doesn't have proper write support. |
| */ |
| if (!filesystemtype || strcmp(filesystemtype, "ntfs")) { |
| rval = mount(source, target, filesystemtype, mountflags, data); |
| if (!rval) |
| return 0; |
| } |
| |
| /* |
| * The FUSE filesystem executes mount.fuse helper, which tries to |
| * execute corresponding binary name which is encoded at the start of |
| * the source string and separated by # from the device name. |
| * |
| * The mount helpers are called mount.$fs_type. |
| */ |
| if (possibly_fuse(filesystemtype)) { |
| char buf[1024]; |
| |
| tst_resm_(file, lineno, TINFO, "Trying FUSE..."); |
| snprintf(buf, sizeof(buf), "mount.%s '%s' '%s'", |
| filesystemtype, source, target); |
| |
| rval = tst_system(buf); |
| if (WIFEXITED(rval) && WEXITSTATUS(rval) == 0) |
| return 0; |
| |
| tst_brkm_(file, lineno, TBROK, cleanup_fn, |
| "mount.%s failed with %i", filesystemtype, rval); |
| return -1; |
| } else if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "mount(%s, %s, %s, %lu, %p) failed", source, target, |
| filesystemtype, mountflags, data); |
| } else { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid mount(%s, %s, %s, %lu, %p) return value %d", |
| source, target, filesystemtype, mountflags, data, |
| rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void), |
| const char *target) |
| { |
| int rval; |
| |
| rval = tst_umount(target); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "umount(%s) failed", target); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid umount(%s) return value %d", target, rval); |
| } |
| |
| return rval; |
| } |
| |
| DIR* safe_opendir(const char *file, const int lineno, void (cleanup_fn)(void), |
| const char *name) |
| { |
| DIR *rval; |
| |
| rval = opendir(name); |
| |
| if (!rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "opendir(%s) failed", name); |
| } |
| |
| return rval; |
| } |
| |
| int safe_closedir(const char *file, const int lineno, void (cleanup_fn)(void), |
| DIR *dirp) |
| { |
| int rval; |
| |
| rval = closedir(dirp); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "closedir(%p) failed", dirp); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "Invalid closedir(%p) return value %d", dirp, rval); |
| } |
| |
| return rval; |
| } |
| |
| struct dirent *safe_readdir(const char *file, const int lineno, void (cleanup_fn)(void), |
| DIR *dirp) |
| { |
| struct dirent *rval; |
| int err = errno; |
| |
| errno = 0; |
| rval = readdir(dirp); |
| |
| if (!rval && errno) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, |
| "readdir(%p) failed", dirp); |
| } |
| |
| errno = err; |
| return rval; |
| } |
| |
| int safe_getpriority(const char *file, const int lineno, int which, id_t who) |
| { |
| int rval, err = errno; |
| |
| errno = 0; |
| rval = getpriority(which, who); |
| |
| if (rval == -1 && errno) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "getpriority(%i, %i) failed", which, who); |
| } else if (errno) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "getpriority(%i, %i) failed with return value %d", |
| which, who, rval); |
| } |
| |
| errno = err; |
| return rval; |
| } |
| |
| ssize_t safe_getxattr(const char *file, const int lineno, const char *path, |
| const char *name, void *value, size_t size) |
| { |
| ssize_t rval; |
| |
| rval = getxattr(path, name, value, size); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "getxattr(%s, %s, %p, %zu) failed", |
| path, name, value, size); |
| } else if (rval < 0) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid getxattr(%s, %s, %p, %zu) return value %zd", |
| path, name, value, size, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_setxattr(const char *file, const int lineno, const char *path, |
| const char *name, const void *value, size_t size, int flags) |
| { |
| int rval; |
| |
| rval = setxattr(path, name, value, size, flags); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "setxattr(%s, %s, %p, %zu) failed", |
| path, name, value, size); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid setxattr(%s, %s, %p, %zu) return value %d", |
| path, name, value, size, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_lsetxattr(const char *file, const int lineno, const char *path, |
| const char *name, const void *value, size_t size, int flags) |
| { |
| int rval; |
| |
| rval = lsetxattr(path, name, value, size, flags); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "lsetxattr(%s, %s, %p, %zu, %i) failed", |
| path, name, value, size, flags); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid lsetxattr(%s, %s, %p, %zu, %i) return value %d", |
| path, name, value, size, flags, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name, |
| const void *value, size_t size, int flags) |
| { |
| int rval; |
| |
| rval = fsetxattr(fd, name, value, size, flags); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "fsetxattr(%i, %s, %p, %zu, %i) failed", |
| fd, name, value, size, flags); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid fsetxattr(%i, %s, %p, %zu, %i) return value %d", |
| fd, name, value, size, flags, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_removexattr(const char *file, const int lineno, const char *path, |
| const char *name) |
| { |
| int rval; |
| |
| rval = removexattr(path, name); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "removexattr(%s, %s) failed", path, name); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid removexattr(%s, %s) return value %d", path, |
| name, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_lremovexattr(const char *file, const int lineno, const char *path, |
| const char *name) |
| { |
| int rval; |
| |
| rval = lremovexattr(path, name); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "lremovexattr(%s, %s) failed", path, name); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid lremovexattr(%s, %s) return value %d", path, |
| name, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_fremovexattr(const char *file, const int lineno, int fd, |
| const char *name) |
| { |
| int rval; |
| |
| rval = fremovexattr(fd, name); |
| |
| if (rval == -1) { |
| if (errno == ENOTSUP) { |
| tst_brkm_(file, lineno, TCONF, NULL, |
| "no xattr support in fs or mounted without user_xattr option"); |
| return rval; |
| } |
| |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "fremovexattr(%i, %s) failed", fd, name); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid fremovexattr(%i, %s) return value %d", fd, |
| name, rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_fsync(const char *file, const int lineno, int fd) |
| { |
| int rval; |
| |
| rval = fsync(fd); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "fsync(%i) failed", fd); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid fsync(%i) return value %d", fd, rval); |
| } |
| |
| return rval; |
| } |
| |
| pid_t safe_setsid(const char *file, const int lineno) |
| { |
| pid_t rval; |
| |
| rval = setsid(); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "setsid() failed"); |
| } |
| |
| return rval; |
| } |
| |
| int safe_mknod(const char *file, const int lineno, const char *pathname, |
| mode_t mode, dev_t dev) |
| { |
| int rval; |
| |
| rval = mknod(pathname, mode, dev); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "mknod() failed"); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid mknod() return value %d", rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_mlock(const char *file, const int lineno, const void *addr, |
| size_t len) |
| { |
| int rval; |
| |
| rval = mlock(addr, len); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "mlock() failed"); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid mlock() return value %d", rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_munlock(const char *file, const int lineno, const void *addr, |
| size_t len) |
| { |
| int rval; |
| |
| rval = munlock(addr, len); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "munlock() failed"); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid munlock() return value %d", rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_mincore(const char *file, const int lineno, void *start, |
| size_t length, unsigned char *vec) |
| { |
| int rval; |
| |
| rval = mincore(start, length, vec); |
| |
| if (rval == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "mincore() failed"); |
| } else if (rval) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid mincore() return value %d", rval); |
| } |
| |
| return rval; |
| } |
| |
| int safe_sysinfo(const char *file, const int lineno, struct sysinfo *info) |
| { |
| int ret; |
| |
| errno = 0; |
| ret = sysinfo(info); |
| |
| if (ret == -1) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "sysinfo() failed"); |
| } else if (ret) { |
| tst_brkm_(file, lineno, TBROK | TERRNO, NULL, |
| "Invalid sysinfo() return value %d", ret); |
| } |
| |
| return ret; |
| } |