--- /dev/null
+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
+
--- /dev/null
+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.
+
--- /dev/null
+pathmap (0.1) experimental; urgency=medium
+
+ * creation
+ -- Ralph Ronnquist <ralph.ronnquist@gmail.com> Mon, 29 Mar 2021 12:51:07 +1100
--- /dev/null
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: pathmap
+Source: <url://example.com>
+
+Files: debian/*
+Copyright: 2021 Ralph Ronnquist <ralph@ascii>
+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 <https://www.gnu.org/licenses/>
+ .
+ On Debian systems, the complete text of the GNU General
+ Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
--- /dev/null
+#!/usr/bin/make -f
+
+%:
+ dh $@
+
+#
+#override_dh_usrlocal:
+# true
--- /dev/null
+3.0 (native)
--- /dev/null
+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
+--------
--- /dev/null
+/**
+ * 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 <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <dirent.h>
+
+/************************************************************
+ * 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();
+}
+
--- /dev/null
+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
+--------
--- /dev/null
+/**
+ * libtarmap implements a preload library for faked file access that
+ * opens and reads files from a tar file first where possible.
+ */
+
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+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 );
+}
--- /dev/null
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+}