Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Specify tmpdir at build #221

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions bootloader/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#include <fcntl.h>
#include <elf.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <libgen.h>
#include "xz.h"
#include "error.h"
#include "mmap.h"
Expand All @@ -27,6 +29,7 @@
/* Keep temporary files */
#define STATICX_KEEP_TEMPS "STATICX_KEEP_TEMPS"
#define TMPDIR "TMPDIR"
#define TMPROOTDIR "tmp_folder_define "



Expand Down Expand Up @@ -205,10 +208,36 @@ patch_app(const char *prog_path)
free(interp_path);
}

int
mkpath(const char *dir, mode_t mode)
{
struct stat sb;

if (!dir) {
errno = EINVAL;
return -1;
}

if (!stat(dir, &sb))
return 0;

mkpath(dirname(strdupa(dir)), mode);

return mkdir(dir, mode);
}

const char *
get_tmpdir(void)
{
const char *tmproot = getenv(TMPDIR) ?: "/tmp";
return tmproot;
}

static char *
create_tmpdir(void)
{
const char *tmproot = getenv(TMPDIR) ?: "/tmp";
const char *tmproot = get_tmpdir();
mkpath(tmproot, 0755);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are random lines indented with tabs.

char *template = path_join(tmproot, "staticx-XXXXXX");
char *tmpdir = mkdtemp(template);
if (!tmpdir)
Expand Down Expand Up @@ -408,20 +437,39 @@ get_real_prog_path(void)
return result;
}

char *get_tmp_root(void)
{
char *root_dir;
root_dir = TMPROOTDIR;

char *ret;
ret = (char*) malloc (strlen(root_dir)+1);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strcpy(ret, root_dir);
ret = strtrim(ret);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would we need to trim whitespace? Certainly staticx should be capable of writing a proper NUL-terminate C string.

return ret;
}
static void identify(void)
{
debug_printf("bootloader version %s\n", STATICX_VERSION);
debug_printf("compiled %s at %s by %s version %s\n",
__DATE__, __TIME__, COMPILER_PATH, __VERSION__);

/* If we're invoked by staticx, just exit */
if (getenv("STATICX_BOOTLOADER_IDENTIFY"))
exit(0);
}
static void set_tmpdir(void)
{
const char *tmproot = get_tmp_root();
debug_printf("tmproot: %s\n", tmproot);

if (strstr(tmproot, "tmp_folder_define") == NULL) {
setenv(TMPDIR, tmproot, 0);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As implemented:

  • --tmprootdir ignores TMPDIR set in the target environment.
  • --tmprootdir also affects TMPDIR for the child process (not just the staticx bootloader)

Is this intentional?

}
}
int
main(int argc, char **argv)
{
set_tmpdir();
identify();
xz_crc32_init();

Expand Down
30 changes: 30 additions & 0 deletions bootloader/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <errno.h>
#include <ftw.h> /* file tree walk */
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
#include "util.h"


Expand All @@ -30,3 +32,31 @@ remove_tree(const char *pathname)
errno = 0;
return nftw(pathname, remove_tree_fn, max_open_fd, flags);
}

char *strtrim(char *str)
{
char *start, *end;

if (!str) {
errno = EINVAL;
return NULL;
}

start = str;
while (isspace(*start))
start++;

if (*start == 0) {
str[0] = 0;
return str;
}

end = start + strlen(start) - 1;
while (end > start && isspace(*end))
end--;
*(++end) = 0;

memmove(str, start, end - start + 1);

return str;
}
5 changes: 4 additions & 1 deletion bootloader/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@
#define UTIL_H

int remove_tree(const char *pathname);

char *strtrim(char *str);
int mkpath (const char *dir, mode_t mode);
const char * get_tmpdir(void);
char *get_tmp_root(void);
#endif /* UTIL_H */
3 changes: 3 additions & 0 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ Options:
--debug Set loglevel to DEBUG and use a debug version of the
bootloader

--tmprootdir Set tmprootdir (where the files will be unpacked
default /tmp/staticx-XXXXXX)

-V, --version Show StaticX version and exit


Expand Down
3 changes: 3 additions & 0 deletions staticx/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def parse_args():

ap.add_argument('--debug', action='store_true')

ap.add_argument('--tmprootdir', action="store", help="Set temp dir at compile time")

args = ap.parse_args()

if args.loglevel is None:
Expand All @@ -51,6 +53,7 @@ def main():
strip = args.strip,
compress = not args.no_compress,
debug = args.debug,
tmprootdir=args.tmprootdir
)
except Error as e:
if args.debug:
Expand Down
26 changes: 23 additions & 3 deletions staticx/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@
from .hooks import run_hooks
from .version import __version__


class StaticxGenerator:
"""StaticxGenerator is responsible for producing a staticx-ified executable.
"""

def __init__(self, prog, strip=False, compress=True, debug=False, cleanup=True):
def __init__(self, prog, strip=False, compress=True, debug=False, cleanup=True, tmprootdir=None):
"""
Parameters:
prog: Dynamic executable to staticx
Expand All @@ -42,10 +41,13 @@ def __init__(self, prog, strip=False, compress=True, debug=False, cleanup=True):
self.tmpoutput = None
self.tmpprog = None
self.tmpdir = mkdtemp(prefix='staticx-archive-')
self.tmprootdir = tmprootdir

f = NamedTemporaryFile(prefix='staticx-archive-', suffix='.tar')
self.sxar = SxArchive(fileobj=f, mode='w', compress=self.compress)

self.bootloader_tmpdir_whitespace_cnt = 1024
self.bootloader_repl_str = "tmp_folder_define"

def __enter__(self):
return self
Expand All @@ -71,13 +73,29 @@ def _cleanup(self):
self.sxar.close()
self.sxar = None

def _rewrite_tmpdir(self, bootloader):
if self.tmprootdir:
max_len = len(self.bootloader_repl_str) + 1024
if len(self.tmprootdir) > max_len:
raise InvalidInputError("tmprootdir needs to have maximum "+str(max_len)+" characters")

f = open(bootloader, 'rb')
repl = self.tmprootdir
repl_str = self.bootloader_repl_str + (" " * self.bootloader_tmpdir_whitespace_cnt)
repl = repl + (" " * (len(repl_str) - len(repl)))
contents = f.read().replace(bytes(repl_str, 'ascii'), bytes(repl, 'ascii'))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but this approach is simply not going to cut it. I don't want to perform a broad find/replace on the binary. There are too many potential pitfalls.

There are other, more robust ways that we could come up with, like:

  • Putting configuration variables / structure in a dedicated ELF section
  • Putting configuration in the Staticx Archive

f.close()
f = open(bootloader, 'wb')
f.write(contents)
f.close()

def _get_bootloader(self):
# Get a temporary copy of the bootloader
fbl = copy_asset_to_tempfile('bootloader', self.debug,
prefix='staticx-output-', delete=False)
with fbl:
self.tmpoutput = bootloader = fbl.name
self._rewrite_tmpdir(bootloader)
make_executable(bootloader)

# Verify the bootloader machine matches that of the user program
Expand Down Expand Up @@ -286,7 +304,7 @@ def _fixup_prog(self):
force_rpath=True, no_default_lib=True)


def generate(prog, output, libs=None, strip=False, compress=True, debug=False):
def generate(prog, output, libs=None, strip=False, compress=True, debug=False, tmprootdir=None):
"""Main API: Generate a staticx executable

Parameters:
Expand All @@ -306,12 +324,14 @@ def generate(prog, output, libs=None, strip=False, compress=True, debug=False):
logging.debug(" strip: {!r}".format(strip))
logging.debug(" compress: {!r}".format(compress))
logging.debug(" debug: {!r}".format(debug))
logging.debug(" tmprootdir: {!r}".format(tmprootdir))

gen = StaticxGenerator(
prog=prog,
strip=strip,
compress=compress,
debug=debug,
tmprootdir=tmprootdir,
)
with gen:
for lib in (libs or []):
Expand Down