From 57bf98ae37ae7a72672651d3531509e054198a86 Mon Sep 17 00:00:00 2001 From: Ralph Ronnquist Date: Mon, 29 Mar 2021 12:53:36 +1100 Subject: [PATCH 1/1] creation --- Makefile | 47 +++++ README.md | 12 ++ debian/changelog | 4 + debian/compat | 1 + debian/copyright | 22 +++ debian/rules | 8 + debian/source/format | 1 + libpathmap.8.adoc | 62 +++++++ libpathmap.c | 421 +++++++++++++++++++++++++++++++++++++++++++ libtarmap.8.adoc | 62 +++++++ libtarmap.c | 174 ++++++++++++++++++ tarmap.c | 61 +++++++ 12 files changed, 875 insertions(+) create mode 100644 Makefile create mode 100644 README.md create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/copyright create mode 100644 debian/rules create mode 100644 debian/source/format create mode 100644 libpathmap.8.adoc create mode 100644 libpathmap.c create mode 100644 libtarmap.8.adoc create mode 100644 libtarmap.c create mode 100644 tarmap.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a1f3982 --- /dev/null +++ b/Makefile @@ -0,0 +1,47 @@ +LIBDIR= $(DESTDIR)/usr/lib +SBINDIR = $(DESTDIR)/usr/local/sbin +MAN8DIR = $(DESTDIR)/usr/local/share/man/man8 + +SBINFILES = tarmap +LIBFILES = libtarmap.so libpathmap.so +MAN8FILES = $(addsuffix .8,$(LIBFILES) $(SBINFILES)) +HTMLDOC = $(addsuffix .html,$(MAN8FILES)) +GENFILES = $(LIBFILES) $(SBINFILES) + +default: $(GENFILES) + +# Generic rule to compile an html file from an adoc file +%.html: %.adoc + asciidoc -bhtml $^ + +# Generic rule to compile a man page from an adoc file +%: %.adoc + a2x -d manpage -f manpage $^ + +# Generic rule for making a dynamic library form a same named .c file +%.so: %.c + gcc -Wall -fPIC -Wl,-init,so_init -shared -o $$@ $$^ -ldl + +# Generic rule for making a binary from a same named .c file +%: %.c + gcc -Wall -fPIC -o $@ $^ -ldl + +clean: + rm -f $(GENFILES) + +# Installation targets + +INSTALLTARGETS = $(addprefix $(SBINDIR)/,$(SBINFILES)) +INSTALLTARGETS = $(addprefix $(LIBDIR)/,$(LIBFILES)) +INSTALLTARGETS += $(addprefix $(MAN8DIR)/,$(MAN8FILES)) + +# Generic rule to install bmo the install command without renaming +$(LIBDIR)/% $(SBINDIR)/% $(MAN8DIR)/%: % + install -D -T $< $@ + +install: $(INSTALLTARGETS) + +# Target for development building of the deb package +deb: + PREFIX= INCLUDE_PREFIX=/usr dpkg-buildpackage -us -uc --build=full + diff --git a/README.md b/README.md new file mode 100644 index 0000000..fc2410b --- /dev/null +++ b/README.md @@ -0,0 +1,12 @@ +The fstrap interpreter +====================== + +The fstrap interpreter is intended to be a prefix to a tar file, for +executing scripts in that tar file. More specifically, it sets up a +file access overlay for using path names via the tar file where +available, and referring to the file system otherwise. + +The actual work is done through the libfstrap.so dynamic library which +is set as LD_PRELOAD library whilst invoking the first tar file entry +for execution. + diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..5a99af3 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,4 @@ +pathmap (0.1) experimental; urgency=medium + + * creation + -- Ralph Ronnquist Mon, 29 Mar 2021 12:51:07 +1100 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +9 diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..e41cdbe --- /dev/null +++ b/debian/copyright @@ -0,0 +1,22 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: pathmap +Source: + +Files: debian/* +Copyright: 2021 Ralph Ronnquist +License: GPL-2+ + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package 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 General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". diff --git a/debian/rules b/debian/rules new file mode 100644 index 0000000..9354bd2 --- /dev/null +++ b/debian/rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f + +%: + dh $@ + +# +#override_dh_usrlocal: +# true diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000..89ae9db --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +3.0 (native) diff --git a/libpathmap.8.adoc b/libpathmap.8.adoc new file mode 100644 index 0000000..0430292 --- /dev/null +++ b/libpathmap.8.adoc @@ -0,0 +1,62 @@ +libpathmap.so(8) +================ +:doctype: manpage +:revdate: {sys:date "+%Y-%m-%d %H:%M:%S"} +:COLON: : +:EQUALS: = + +NAME +---- +libpathmap.so - preload utility to redirect pathnames + +SYNOPSYS +-------- ++LD_PRELOAD=libpathmap.so+ _command_ + +DESCRIPTION +----------- + +This dynamic library, libpathmap.so, is intended to be used as a +"preload" library for programs for which pathnames are to be mapped to +a different common prefix. The effect is somewhat similar to +chroot+ +in that absolute pathnames, which normally are from the root of the +file system, get mapped to be relative to the choosen prefix point. + ++libpathmap.so+ is "configured" by setting environment variable ++PATHMAPNOT+ to be the path prefixes, given as a colon separated list, +that +libpathmap.so+ should be concerned with. The first of them is +then used as the prefix to add to the program's pathnames (when +opening files) except to those pathnames that start with any of the +prefixes in the list, including the first. + +For example, if the prefix +/elsewhere+ should be added to all +pathnames for a program +prgrm+ then the command line might be: + +---- +PATHMAPNOT=/elsewhere LD_PRELOAD=libpathmap.so prgrm +---- + +However, if +prgrm+ is a dynamically linked executable, then all +libraries + +ENVIRONMENT +----------- + +PATHMAPNOT:: + +This environment variable tells which path prefixes, given as a colon +separated list, +libpathmap.so+ should be concerned with. The first +prefix is the one to add to all pathnames except to those of any of +the prefixes in the list. + +EXAMPLES +-------- + +Assume there is a directory +/home/test/extra+ + +> env PATHMAPNOT=/home/test:/proc:/dev:/lib:/usr:/bin \ + LD_PRELOAD=libpathmap.so \ + ls /extra + +SEE ALSO +-------- diff --git a/libpathmap.c b/libpathmap.c new file mode 100644 index 0000000..5628030 --- /dev/null +++ b/libpathmap.c @@ -0,0 +1,421 @@ +/** + * PRELOAD utility that maps all rooted paths except some to have an + * additional root path prefix. This is configured with an environment + * variable PATHMAPNOT that is a colon separated list of pathname + * prefixes to *not* map with the first one being the additional root + * path prefix. The environment variable is loaded on the first call. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include + +/************************************************************ + * Data structure for pathname mapping + * + * Pathnames are passed in to the library via the environment variable + * PATHMAPNOT as a colon separated list of pathnames that are not to + * be mapped. The first value of PATHMAPNOT is used as prefix to add + * to all paths except the ones in the list (the first inlcuded). + * + * The given pathnames are loaded into a sorted table, offering + * O[log(n)] lookup complexity, and the map prefix is also held + * separately as the 'root'. + */ + +#define PATHMAPNOT "PATHMAPNOT" + +static struct { + char **data; // Array of char* + int count; + int root_length; + char *root; +} prefix; + +// Alphabetical ordering of char* records. +static int alphorder(const void *a, const void *b) { + int x = strcmp( *(const char**)a, *(const char**)b ); + return x; +} + +// Utility function to load the prefixes. +static void load_prefixes() { + char *data = getenv( PATHMAPNOT ); + char *p = data; + prefix.count = 0; + if ( data == 0 || *data == 0 ) { + return; + } + prefix.count++; + while ( *p ) { + if ( *(p++) == ':' ) { + prefix.count++; + } + } + prefix.data = (char**) calloc( prefix.count, sizeof( char* ) ); + if ( data == 0 ) { + perror( PATHMAPNOT ); + exit( 1 ); + } + char *path = data; + int n = 0; + for ( p = data; *p; p++ ) { + if ( *p == ':' ) { + prefix.data[ n++ ] = strndup( path, ( p - path ) ); + path = p+1; + } + } + prefix.data[ n++ ] = strndup( path, ( p - path ) ); + prefix.root = prefix.data[ 0 ]; + prefix.root_length = strlen( prefix.root ); + qsort( prefix.data, n, sizeof( char* ), alphorder ); +} + +// Binary search for a given path prefix. Returns the index of longest +// prefix match or (-i-1)<0 for mismatch (indicating insertion point i) +static int binsearch(const char *path) { + int lo = 0; + int hi = prefix.count; + while ( lo < hi ) { + int m = ( lo + hi ) / 2; + int x = strcmp( path, prefix.data[ m ] ); + if ( x == 0 ) { + return m; + } + if ( x < 0 ) { + hi = m; + } else { + lo = m + 1; + } + } + // lo = insertion point for mismatch; check if lo-1 is prefix + if ( lo > 0 ) { + int n = strlen( prefix.data[ lo - 1 ] ); + if ( ( strncmp( prefix.data[ lo - 1 ], path, n ) == 0 ) && + ( *(path+n) == '/' ) ) { + return lo - 1; + } + } + return - lo - 1; +} + +// Utility function to lookup a matching prefix for the given path. If +// one is found, then 0 is returned. Otherwise memory is allocated for +// a new string that consists of the root path followed by the given +// path. +static char *maybe_add_prefix(const char *path) { + fprintf( stderr, "libpathmap: check %s\n", path ); + if ( prefix.count > 0 && *path == '/' ) { + int x = binsearch( path ); + //fprintf( stderr, "libpathmap: %d %s\n", x, path ); + if ( x < 0 ) { + char *p = (char*)malloc( strlen( path ) + prefix.root_length + 1 ); + memcpy( p, prefix.root, prefix.root_length ); + strcpy( p + prefix.root_length, path ); + fprintf( stderr, "libpathmap: => %s\n", p ); + return p; + } + } + return 0; +} + +int open(const char *pathname, int flags, ...) { + static int (*real_open) (const char *pathname, int flags, ...); + if ( real_open == 0 ) { + real_open = dlsym( RTLD_NEXT, "open" ); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x; + + // If O_CREAT is used to create a file, the file access mode must be given. + if ( flags & O_CREAT ) { + va_list args; + va_start( args, flags ); + int mode = va_arg( args, int ); + va_end( args ); + x = real_open( pathname, flags, mode ); + } else { + x = real_open( pathname, flags); + } + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int __open(const char *pathname, int flags, ...) { + static int (*real_open) (const char *pathname, int flags, ...); + if ( real_open == 0 ) { + real_open = dlsym( RTLD_NEXT, "__open" ); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x; + + // If O_CREAT is used to create a file, the file access mode must be given. + if ( flags & O_CREAT ) { + va_list args; + va_start( args, flags ); + int mode = va_arg( args, int ); + va_end( args ); + x = real_open( pathname, flags, mode ); + } else { + x = real_open( pathname, flags); + } + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int open64(const char *pathname, int flags, ...) { + static int (*real_open64)(const char *pathname, int flags, ...); + if ( real_open64 == 0 ) { + real_open64 = dlsym(RTLD_NEXT, "open64"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x; + + // If O_CREAT is used to create a file, the file access mode must be given. + if (flags & O_CREAT) { + va_list args; + va_start(args, flags); + int mode = va_arg(args, int); + va_end(args); + x = real_open64( pathname, flags, mode ); + } else { + x =real_open64( pathname, flags); + } + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int openat(int dirfd,const char *pathname, int flags, ...) { + static int (*real_openat) (int dirfd,const char *pathname, int flags, ...); + if ( real_openat == 0 ) { + real_openat = dlsym( RTLD_NEXT, "openat" ); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x; + if ( flags & O_CREAT ) { + va_list args; + va_start( args, flags ); + int mode = va_arg( args, int ); + va_end( args ); + x = real_openat( dirfd, pathname, flags, mode ); + } else { + x = real_openat( dirfd, pathname, flags); + } + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int __openat_2(int dirfd,const char *pathname, int flags, ...) { + static int (*real___openat_2) ( + int dirfd,const char *pathname, int flags, ...); + if ( real___openat_2 == 0 ) { + real___openat_2 = dlsym( RTLD_NEXT, "__openat_2" ); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x; + if ( flags & O_CREAT ) { + va_list args; + va_start( args, flags ); + int mode = va_arg( args, int ); + va_end( args ); + x = real___openat_2( dirfd, pathname, flags, mode ); + } else { + x = real___openat_2( dirfd, pathname, flags); + } + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int openat64(int dirfd,const char *pathname, int flags, ...) { + static int (*real_openat64)( + int dirfd,const char *pathname, int flags, ...); + if ( real_openat64 == 0 ) { + real_openat64 = dlsym(RTLD_NEXT, "openat64"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x; + if (flags & O_CREAT) { + va_list args; + va_start(args, flags); + int mode = va_arg(args, int); + va_end(args); + x = real_openat64( dirfd, pathname, flags, mode ); + } else { + x =real_openat64( dirfd, pathname, flags); + } + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +FILE *fopen(const char *pathname,const char * mode) { + static FILE *(*real_fopen)(const char *pathname,const char *mode); + if ( real_fopen == 0 ) { + real_fopen = dlsym(RTLD_NEXT, "fopen"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + FILE *x = real_fopen( pathname, mode ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +FILE *fopen64(const char *pathname,const char * mode) { + static FILE *(*real_fopen64)(const char *pathname,const char *mode); + if ( real_fopen64 == 0 ) { + real_fopen64 = dlsym(RTLD_NEXT, "fopen64"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + FILE *x = real_fopen64( pathname, mode ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +FILE *freopen(const char *pathname,const char * mode,FILE *stream) { + static FILE *(*real_freopen)( + const char *pathname,const char *mode,FILE *stream); + if ( real_freopen == 0 ) { + real_freopen = dlsym(RTLD_NEXT, "freopen"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + FILE *x = real_freopen( pathname, mode, stream ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +DIR *opendir(const char *pathname) { + static DIR *(*real_opendir)(const char *pathname); + if ( real_opendir == 0 ) { + real_opendir = dlsym(RTLD_NEXT, "opendir"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + DIR *x = real_opendir( pathname ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int __xstat(int v,const char *pathname, struct stat *statbuf) { + static int (*real_xstat)(int v,const char *pathname,struct stat *statbuf); + if ( real_xstat == 0 ) { + real_xstat = dlsym(RTLD_NEXT, "__xstat"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x = real_xstat( v, pathname, statbuf ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int __lxstat(int v,const char *pathname, struct stat *statbuf) { + static int (*real_lxstat)(int v,const char *pathname,struct stat *statbuf); + if ( real_lxstat == 0 ) { + real_lxstat = dlsym(RTLD_NEXT, "__lxstat"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x = real_lxstat( v, pathname, statbuf ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int stat(const char *pathname, struct stat *statbuf) { + static int (*real_stat)(const char *pathname,struct stat *statbuf); + if ( real_stat == 0 ) { + real_stat = dlsym(RTLD_NEXT, "stat"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x = real_stat( pathname, statbuf ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +int lstat(const char *pathname, struct stat *statbuf) { + static int (*real_lstat)(const char *pathname,struct stat *statbuf); + if ( real_lstat == 0 ) { + real_lstat = dlsym(RTLD_NEXT, "lstat"); + } + const char *new_path = maybe_add_prefix( pathname ); + if ( new_path ) { + pathname = new_path; + } + int x = real_lstat( pathname, statbuf ); + if ( new_path ) { + free( (void*) new_path ); + } + return x; +} + +/** + * Initialize the dynamic library. + */ +void so_init() { + load_prefixes(); +} + diff --git a/libtarmap.8.adoc b/libtarmap.8.adoc new file mode 100644 index 0000000..31f92bb --- /dev/null +++ b/libtarmap.8.adoc @@ -0,0 +1,62 @@ +libtarmap.so(8) +=============== +:doctype: manpage +:revdate: {sys:date "+%Y-%m-%d %H:%M:%S"} +:COLON: : +:EQUALS: = + +NAME +---- +libtarmap.so - preload utility to map pathnames into a tar file + +SYNOPSYS +-------- ++LD_PRELOAD=libtarmap.so+ +TARMAP=+_tarfile_ _command_ + +DESCRIPTION +----------- + +This dynamic library, libtarmap.so, is intended to be used as a +"preload" library for programs for which pathnames are to be mapped to +a different common prefix. The effect is somewhat similar to +chroot+ +in that absolute pathnames, which normally are from the root of the +file system, get mapped to be relative to the choosen prefix point. + ++libtarmap.so+ is "configured" by setting environment variable ++PATHMAPNOT+ to be the path prefixes, given as a colon separated list, +that +libtarmap.so+ should be concerned with. The first of them is +then used as the prefix to add to the program's pathnames (when +opening files) except to those pathnames that start with any of the +prefixes in the list, including the first. + +For example, if the prefix +/elsewhere+ should be added to all +pathnames for a program +prgrm+ then the command line might be: + +---- +PATHMAPNOT=/elsewhere LD_PRELOAD=libtarmap.so prgrm +---- + +However, if +prgrm+ is a dynamically linked executable, then all +libraries + +ENVIRONMENT +----------- + +PATHMAPNOT:: + +This environment variable tells which path prefixes, given as a colon +separated list, +libtarmap.so+ should be concerned with. The first +prefix is the one to add to all pathnames except to those of any of +the prefixes in the list. + +EXAMPLES +-------- + +Assume there is a directory +/home/test/extra+ + +> env PATHMAPNOT=/home/test:/proc:/dev:/lib:/usr:/bin \ + LD_PRELOAD=libtarmap.so \ + ls /extra + +SEE ALSO +-------- diff --git a/libtarmap.c b/libtarmap.c new file mode 100644 index 0000000..f10c9cc --- /dev/null +++ b/libtarmap.c @@ -0,0 +1,174 @@ +/** + * libtarmap implements a preload library for faked file access that + * opens and reads files from a tar file first where possible. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static int (*real_open)(const char *pathname, int flags); +static FILE *(*real_openat)(int dirfd, const char *pathname, int flags); +static FILE *(*real_fopen)(const char *pathname, const char *mode); + +// The environment variable name +#define TARMAP "TARMAP" + +// Maximal allowed size of filenames ("tar tf" output) +#define DATASZ 10000000 + +static struct { + char *tarmap; // TARMAP value + char *head; // Command preamble + char *buffer; // All file names of the tar file + int size; // Byte size of buffer + char **table; // File name index in alphabetical order + int count; // Number of file names +} data; + +// Ordering condition for two char** +static int alphaorder(const void *a,const void *b) { + int x = strcmp( *(const char**)a, *(const char**)b ); + return x; +} + +// Combine two strings with a space between as a new malloc string +static char *join(const char *head,const char *tail) { + int n = strlen( head ); + char *p = (char*) malloc( n + strlen( tail ) + 2 ); + strcpy( p, head ); + strcpy( p + n, " " ); + strcpy( p + n + 1, tail ); + return p; +} + +// Run popen with TARMAP unset +static inline FILE *popen_notarmap(const char *cmd) { + unsetenv( TARMAP ); // Inhibit tarmap for the command subprocess + FILE *file = popen( cmd, "r" ); + setenv( TARMAP, data.tarmap, 1 ); // Re-enable for this process + return file; +} + +// Try opening the pathname in the tar +static FILE *tryopentar(const char *pathname) { + fprintf( stderr, "libtarmap: %s\n", pathname ); + if ( bsearch( &pathname, data.table, data.count, sizeof( char * ), + alphaorder ) ) { + char *p = join( data.head, pathname ); + fprintf( stderr, "libtarmap: => %s\n", p ); + FILE *file = popen_notarmap( p ); + free( p ); + return file; + } + return 0; +} + +// Override "openat" +FILE *openat(int dirfd, const char *pathname, int flags) { + if ( data.tarmap ) { + if ( strncmp( pathname, "/", 1 ) == 0 ) { + FILE *file = tryopentar( pathname + 1 ); + if ( file ) { + return file; + } + } + } + return ( real_openat )? real_openat( dirfd, pathname, flags ) : 0; +} + +// Override "open" +int open(const char *pathname, int flags) { + if ( data.tarmap ) { + if ( strncmp( pathname, "/", 1 ) == 0 ) { + FILE *file = tryopentar( pathname + 1 ); + if ( file ) { + return fileno( file ); + } + } + } + return ( real_open )? real_open( pathname, flags ) : -1; +} + +// Override "fopen" +FILE *fopen(const char *pathname, const char *mode) { + if ( data.tarmap ) { + if ( strncmp( pathname, "/", 1 ) == 0 ) { + FILE *file = tryopentar( pathname + 1 ); + if ( file ) { + return file; + } + } + } + return ( real_fopen )? real_fopen( pathname, mode ) : 0; +} + +/** + * Initialize the dynamic library. + */ +void so_init() { + void *lib = dlopen( "libc.so.6", RTLD_LAZY ); + real_open = dlsym( lib, "open" ); + real_openat = dlsym( lib, "openat" ); + real_fopen = dlsym( lib, "fopen" ); + char *tarfile = getenv( TARMAP ); + if ( tarfile == 0 || *tarfile == 0 ) { + fprintf( stderr, "(libtarmap: no tar)\n" ); + data.tarmap = 0; + return; // Stop here for unset or cleared environment + } + fprintf( stderr, "libtarmap: tarfile = %s\n", tarfile ); + if ( ( data.tarmap = realpath( tarfile, 0 ) ) == 0 ) { + // Cannot find the tar file .. that's total badness! + perror( tarfile ); + exit( 1 ); + } + data.head = join( "/bin/tar xOf", data.tarmap ); + char *cmd = join( "/bin/tar tf", data.tarmap ); + FILE *file = popen_notarmap( cmd ); + if ( file == 0 ) { + // cannot open tar file .. that's total badness! + perror( data.tarmap ); + exit( 1 ); + } + data.buffer = malloc( DATASZ ); + data.size = read( fileno( file ), data.buffer, DATASZ ); + if ( data.size == 0 ) { + perror( cmd ); + // Not a tar or empty tar .. that's total badness! + fprintf( stderr, "*** libtarmap: exiting\n" ); + exit( 1 ); + } + if ( data.size >= DATASZ ) { + // Too many filenmames .. that's total badness! ENAMETOOLONG + fprintf( stderr, "*** libtarmap: too large pathname table\n"); + exit( 1 ); + } + data.buffer = realloc( data.buffer, data.size ); + pclose( file ); + free( cmd ); + cmd = 0; + char *end = data.buffer + data.size; + char *p; + int n = 0; + for ( p = data.buffer; p < end; p++ ) { + if ( *p == '\n' ) { + n++; + *p = '\000'; + } + } + data.table = (char**) calloc( sizeof( char* ), data.count ); + char *name = data.buffer; + for ( p = data.buffer; p < end; p++ ) { + if ( *p == 0 ) { + data.table[ data.count++ ] = name; + name = p+1; + } + } + qsort( data.table, data.count, sizeof( char* ), alphaorder ); +} diff --git a/tarmap.c b/tarmap.c new file mode 100644 index 0000000..215fe5e --- /dev/null +++ b/tarmap.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +#define MAXSIZE 1000000 +// Add/create string to end of env var with colon separation +static char *makeEnv(char *name,char *value) { + static char buffer[ MAXSIZE ]; // new variable value + char *old = getenv( name ); + int length = strlen( name ) + 1 + strlen( value ); + if ( old ) { + length += 1 + strlen( old ); + } + if ( length >= MAXSIZE ) { + fprintf( stderr, "%s\n", "*** tarmap: LD_PRELOAD .. exiting" ); + exit( 1 ); + } + if ( old ) { + sprintf( buffer, "%s=%s:%s", name, value, old ); + } else { + sprintf( buffer, "%s=%s", name, value ); + } + old = strndup( buffer, length ); + if ( old == 0 ) { + fprintf( stderr, "%s\n", "*** tarmap: OOM .. exiting" ); + exit( 1 ); + } + return old; +} + +int main(int argc,char *argv[],char *envp[]) { + if ( argc < 3 ) { + fprintf( stderr, "tarmap tar-file command [ argument ]\n" ); + exit( 1 ); + } + int n = 0; + int i_preload = -1; + int i_tarmap = -1; + for ( n = 0; envp[n]; n++) { + if ( strcmp( envp[n], "LD_PRELOAD=" ) == 0 ) { + i_preload = n; + } else if ( strcmp( envp[n], "TARMAP=" ) ) { + i_tarmap = n; + } + } + if ( i_preload < 0 ) { + i_preload = n++; + } + if ( i_tarmap < 0 ) { + i_tarmap = n++; + } + char **nenvp = (char**) calloc( sizeof( char* ), n+1 ); + memcpy( nenvp, envp, n * sizeof( char*) ); + nenvp[ i_preload ] = makeEnv( "LD_PRELOAD", "libtarmap.so" ); + nenvp[ i_tarmap ] = makeEnv( "TARMAP", argv[1] ); + execve( argv[2], argv+2, nenvp ); + perror( "tarmap exec" ); + return 1; +} -- 2.47.2