1 /* 2 * Copyright (C) 2012-2013 ProFUSION embedded systems 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <assert.h> 19 #include <dirent.h> 20 #include <dlfcn.h> 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <limits.h> 24 #include <stdarg.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 #include <sys/stat.h> 30 #include <sys/types.h> 31 32 #include <shared/util.h> 33 34 #include "testsuite.h" 35 36 static void *nextlib; 37 static const char *rootpath; 38 static size_t rootpathlen; 39 40 static inline bool need_trap(const char *path) 41 { 42 return path != NULL && path[0] == '/' 43 && !strstartswith(path, ABS_TOP_BUILDDIR); 44 } 45 46 static const char *trap_path(const char *path, char buf[PATH_MAX * 2]) 47 { 48 size_t len; 49 50 if (!need_trap(path)) 51 return path; 52 53 len = strlen(path); 54 55 if (len + rootpathlen > PATH_MAX * 2) { 56 errno = ENAMETOOLONG; 57 return NULL; 58 } 59 60 memcpy(buf, rootpath, rootpathlen); 61 strcpy(buf + rootpathlen, path); 62 return buf; 63 } 64 65 static bool get_rootpath(const char *f) 66 { 67 if (rootpath != NULL) 68 return true; 69 70 rootpath = getenv(S_TC_ROOTFS); 71 if (rootpath == NULL) { 72 ERR("TRAP %s(): missing export %s?\n", f, S_TC_ROOTFS); 73 errno = ENOENT; 74 return false; 75 } 76 77 rootpathlen = strlen(rootpath); 78 79 return true; 80 } 81 82 static void *get_libc_func(const char *f) 83 { 84 void *fp; 85 86 if (nextlib == NULL) { 87 #ifdef RTLD_NEXT 88 nextlib = RTLD_NEXT; 89 #else 90 nextlib = dlopen("libc.so.6", RTLD_LAZY); 91 #endif 92 } 93 94 fp = dlsym(nextlib, f); 95 assert(fp); 96 97 return fp; 98 } 99 100 /* wrapper template for a function with one "const char* path" argument */ 101 #define WRAP_1ARG(rettype, failret, name) \ 102 TS_EXPORT rettype name(const char *path) \ 103 { \ 104 const char *p; \ 105 char buf[PATH_MAX * 2]; \ 106 static rettype (*_fn)(const char*); \ 107 \ 108 if (!get_rootpath(__func__)) \ 109 return failret; \ 110 _fn = get_libc_func(#name); \ 111 p = trap_path(path, buf); \ 112 if (p == NULL) \ 113 return failret; \ 114 return (*_fn)(p); \ 115 } 116 117 /* wrapper template for a function with "const char* path" and another argument */ 118 #define WRAP_2ARGS(rettype, failret, name, arg2t) \ 119 TS_EXPORT rettype name(const char *path, arg2t arg2) \ 120 { \ 121 const char *p; \ 122 char buf[PATH_MAX * 2]; \ 123 static rettype (*_fn)(const char*, arg2t arg2); \ 124 \ 125 if (!get_rootpath(__func__)) \ 126 return failret; \ 127 _fn = get_libc_func(#name); \ 128 p = trap_path(path, buf); \ 129 if (p == NULL) \ 130 return failret; \ 131 return (*_fn)(p, arg2); \ 132 } 133 134 /* wrapper template for open family */ 135 #define WRAP_OPEN(suffix) \ 136 TS_EXPORT int open ## suffix (const char *path, int flags, ...) \ 137 { \ 138 const char *p; \ 139 char buf[PATH_MAX * 2]; \ 140 static int (*_fn)(const char *path, int flags, ...); \ 141 \ 142 if (!get_rootpath(__func__)) \ 143 return -1; \ 144 _fn = get_libc_func("open" #suffix); \ 145 p = trap_path(path, buf); \ 146 if (p == NULL) \ 147 return -1; \ 148 \ 149 if (flags & O_CREAT) { \ 150 mode_t mode; \ 151 va_list ap; \ 152 \ 153 va_start(ap, flags); \ 154 mode = va_arg(ap, mode_t); \ 155 va_end(ap); \ 156 return _fn(p, flags, mode); \ 157 } \ 158 \ 159 return _fn(p, flags); \ 160 } 161 162 /* wrapper template for __xstat family */ 163 #define WRAP_VERSTAT(prefix, suffix) \ 164 TS_EXPORT int prefix ## stat ## suffix (int ver, \ 165 const char *path, \ 166 struct stat ## suffix *st) \ 167 { \ 168 const char *p; \ 169 char buf[PATH_MAX * 2]; \ 170 static int (*_fn)(int ver, const char *path, \ 171 struct stat ## suffix *); \ 172 _fn = get_libc_func(#prefix "stat" #suffix); \ 173 \ 174 if (!get_rootpath(__func__)) \ 175 return -1; \ 176 p = trap_path(path, buf); \ 177 if (p == NULL) \ 178 return -1; \ 179 \ 180 return _fn(ver, p, st); \ 181 } 182 183 WRAP_1ARG(DIR*, NULL, opendir); 184 185 WRAP_2ARGS(FILE*, NULL, fopen, const char*); 186 WRAP_2ARGS(int, -1, mkdir, mode_t); 187 WRAP_2ARGS(int, -1, access, int); 188 WRAP_2ARGS(int, -1, stat, struct stat*); 189 WRAP_2ARGS(int, -1, lstat, struct stat*); 190 #ifndef _FILE_OFFSET_BITS 191 WRAP_2ARGS(int, -1, stat64, struct stat64*); 192 WRAP_2ARGS(int, -1, lstat64, struct stat64*); 193 WRAP_OPEN(64); 194 #endif 195 196 WRAP_OPEN(); 197 198 #ifdef HAVE___XSTAT 199 WRAP_VERSTAT(__x,); 200 WRAP_VERSTAT(__lx,); 201 #ifndef _FILE_OFFSET_BITS 202 WRAP_VERSTAT(__x,64); 203 WRAP_VERSTAT(__lx,64); 204 #endif 205 #endif 206