| /* |
| * Copyright (C) 2012-2013 ProFUSION embedded systems |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <assert.h> |
| #include <dirent.h> |
| #include <dlfcn.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <stdarg.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| |
| #include "testsuite.h" |
| |
| static void *nextlib; |
| static const char *rootpath; |
| static size_t rootpathlen; |
| |
| static inline bool need_trap(const char *path) |
| { |
| return path != NULL && path[0] == '/'; |
| } |
| |
| static const char *trap_path(const char *path, char buf[PATH_MAX * 2]) |
| { |
| size_t len; |
| |
| if (!need_trap(path)) |
| return path; |
| |
| len = strlen(path); |
| |
| if (len + rootpathlen > PATH_MAX * 2) { |
| errno = ENAMETOOLONG; |
| return NULL; |
| } |
| |
| memcpy(buf, rootpath, rootpathlen); |
| strcpy(buf + rootpathlen, path); |
| return buf; |
| } |
| |
| static bool get_rootpath(const char *f) |
| { |
| if (rootpath != NULL) |
| return true; |
| |
| rootpath = getenv(S_TC_ROOTFS); |
| if (rootpath == NULL) { |
| ERR("TRAP %s(): missing export %s?\n", f, S_TC_ROOTFS); |
| errno = ENOENT; |
| return false; |
| } |
| |
| rootpathlen = strlen(rootpath); |
| |
| return true; |
| } |
| |
| static void *get_libc_func(const char *f) |
| { |
| void *fp; |
| |
| if (nextlib == NULL) { |
| #ifdef RTLD_NEXT |
| nextlib = RTLD_NEXT; |
| #else |
| nextlib = dlopen("libc.so.6", RTLD_LAZY); |
| #endif |
| } |
| |
| fp = dlsym(nextlib, f); |
| assert(fp); |
| |
| return fp; |
| } |
| |
| /* wrapper template for a function with one "const char* path" argument */ |
| #define WRAP_1ARG(rettype, failret, name) \ |
| TS_EXPORT rettype name(const char *path) \ |
| { \ |
| const char *p; \ |
| char buf[PATH_MAX * 2]; \ |
| static rettype (*_fn)(const char*); \ |
| \ |
| if (!get_rootpath(__func__)) \ |
| return failret; \ |
| _fn = get_libc_func(#name); \ |
| p = trap_path(path, buf); \ |
| if (p == NULL) \ |
| return failret; \ |
| return (*_fn)(p); \ |
| } |
| |
| /* wrapper template for a function with "const char* path" and another argument */ |
| #define WRAP_2ARGS(rettype, failret, name, arg2t) \ |
| TS_EXPORT rettype name(const char *path, arg2t arg2) \ |
| { \ |
| const char *p; \ |
| char buf[PATH_MAX * 2]; \ |
| static rettype (*_fn)(const char*, arg2t arg2); \ |
| \ |
| if (!get_rootpath(__func__)) \ |
| return failret; \ |
| _fn = get_libc_func(#name); \ |
| p = trap_path(path, buf); \ |
| if (p == NULL) \ |
| return failret; \ |
| return (*_fn)(p, arg2); \ |
| } |
| |
| /* wrapper template for open family */ |
| #define WRAP_OPEN(suffix) \ |
| TS_EXPORT int open ## suffix (const char *path, int flags, ...) \ |
| { \ |
| const char *p; \ |
| char buf[PATH_MAX * 2]; \ |
| static int (*_fn)(const char *path, int flags, ...); \ |
| \ |
| if (!get_rootpath(__func__)) \ |
| return -1; \ |
| _fn = get_libc_func("open" #suffix); \ |
| p = trap_path(path, buf); \ |
| if (p == NULL) \ |
| return -1; \ |
| \ |
| if (flags & O_CREAT) { \ |
| mode_t mode; \ |
| va_list ap; \ |
| \ |
| va_start(ap, flags); \ |
| mode = va_arg(ap, mode_t); \ |
| va_end(ap); \ |
| return _fn(p, flags, mode); \ |
| } \ |
| \ |
| return _fn(p, flags); \ |
| } |
| |
| /* wrapper template for __xstat family */ |
| #define WRAP_VERSTAT(prefix, suffix) \ |
| TS_EXPORT int prefix ## stat ## suffix (int ver, \ |
| const char *path, \ |
| struct stat ## suffix *st) \ |
| { \ |
| const char *p; \ |
| char buf[PATH_MAX * 2]; \ |
| static int (*_fn)(int ver, const char *path, \ |
| struct stat ## suffix *); \ |
| _fn = get_libc_func(#prefix "stat" #suffix); \ |
| \ |
| if (!get_rootpath(__func__)) \ |
| return -1; \ |
| p = trap_path(path, buf); \ |
| if (p == NULL) \ |
| return -1; \ |
| \ |
| return _fn(ver, p, st); \ |
| } |
| |
| WRAP_1ARG(DIR*, NULL, opendir); |
| |
| WRAP_2ARGS(FILE*, NULL, fopen, const char*); |
| WRAP_2ARGS(int, -1, mkdir, mode_t); |
| WRAP_2ARGS(int, -1, access, int); |
| WRAP_2ARGS(int, -1, stat, struct stat*); |
| WRAP_2ARGS(int, -1, lstat, struct stat*); |
| #ifndef _FILE_OFFSET_BITS |
| WRAP_2ARGS(int, -1, stat64, struct stat64*); |
| WRAP_2ARGS(int, -1, lstat64, struct stat64*); |
| WRAP_OPEN(64); |
| #endif |
| |
| WRAP_OPEN(); |
| |
| #ifdef HAVE___XSTAT |
| WRAP_VERSTAT(__x,); |
| WRAP_VERSTAT(__lx,); |
| #ifndef _FILE_OFFSET_BITS |
| WRAP_VERSTAT(__x,64); |
| WRAP_VERSTAT(__lx,64); |
| #endif |
| #endif |