#include #include #include #include #include /* the following works ok on OpenBSD and Linux. __USE_GNU is required on linux, otherwise RTLD_NEXT is undefined. */ #define __USE_GNU #include #include #include /* On both OpenBSD and Linux, fcntl.h declares: int open( const char*, int, ...); - which makes it difficult to write our wrapper. So we temporarily #define open to something else.*/ #define open open_yabs_bad #include #undef open static int raw_open( const char* path, int flags, mode_t mode) { static int (*real_open)( const char*, int, mode_t) = NULL; if ( !real_open) { real_open = dlsym( RTLD_NEXT, "open"); } return real_open( path, flags, mode); } static int printf_log( const char* format, ...) { int ret; va_list ap; int f; FILE* ff; const char* varname = "YABS_AUTODEPS_FILENAME"; static const char* log_filename; log_filename = getenv( varname); if ( 0) { va_start( ap, format); vfprintf( stderr, format, ap); va_end( ap); } if ( !log_filename) { fprintf( stderr, "getenv returned NULL: %s\n", varname); return 1; } f = raw_open( log_filename, O_WRONLY|O_APPEND|O_CREAT, 0777); if ( f<0) { fprintf( stderr, "Couldn't raw_open %s, error=%i\n", log_filename, f); return 1; } ff = fdopen( f, "a"); if ( !ff) { fprintf( stderr, "Couldn't fdopen %i\n", f); close( f); return 1; } va_start( ap, format); ret = vfprintf( ff, format, ap); fclose( ff); close( f); va_end( ap); return 0; } #ifdef USE_PTHREADS static void wrap( int e) { if ( e) abort(); } static pthread_mutex_t global_lock0 = PTHREAD_MUTEX_INITIALIZER; static int global_lock_initialised = 0; static pthread_mutex_t global_lock; #endif int open( const char* path, int flags, mode_t mode) { /* we sometimes call getcwd(), which can recurse into open(), so we protect against being reentered. this is not exactly thread-safe... */ static int nesting = 0; int ret; int ret_errno; #ifdef USE_PTHREADS wrap( pthread_mutex_lock( &global_lock0)); if ( !global_lock_initialised) { pthread_mutexattr_t ma; wrap( pthread_mutexattr_init( &ma)); wrap( pthread_mutexattr_settype( &ma, PTHREAD_MUTEX_RECURSIVE)); wrap( pthread_mutex_init( &global_lock, &ma)); } wrap( pthread_mutex_unlock( &global_lock0)); wrap( pthread_mutex_lock( &global_lock)); #endif ++nesting; /*fprintf( stderr, "open: %s\n", path);*/ ret = raw_open( path, flags, mode); ret_errno = errno; if ( nesting>1) goto end; /* we store filenames even if they did not open succesfully.*/ /*if ( ret>=0)*/ { int accmode = flags & O_ACCMODE; if ( ( accmode==O_RDONLY || accmode==O_RDWR) && 0!=strncmp( path, "/tmp/", 5) && 0!=strcmp( path, "/dev/null")) { char path2[ MAXPATHLEN]; int e; if ( !realpath( path, path2)) { /*fprintf( stderr, "yabs autodeps.so: realpath failed for: %s\n", path); */ goto end; } if ( ret>=0) e = printf_log( "+%s\n", path2); else e = printf_log( "-%s\n", path2); if ( e) { fprintf( stderr, "printf_log failed\n"); } } } end: --nesting; #ifdef USE_PTHREADS wrap( pthread_mutex_unlock( &global_lock)); #endif errno = ret_errno; /* make sure error info is correct, even after we've called realpath() etc. */ return ret; }