Home | History | Annotate | Download | only in testsuite
      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