From 7d88cb3c1392393c2910f2f96c93549bb5482f9f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 30 May 2017 23:23:19 +0200 Subject: [PATCH] build: allow to build self-contained executable --- .gitignore | 1 + Dockerfile | 4 +- Makefile | 16 +++++- vis-single.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 vis-single.c diff --git a/.gitignore b/.gitignore index 1477acdad..0b4641297 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ /vis /vis-menu /vis-single +/vis-single-payload.inc /vis-digraph *.css *.gcda diff --git a/Dockerfile b/Dockerfile index a9d38054b..105fd6baa 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,10 +4,12 @@ # ./configure CC='cc --static' # make # docker cp vis:/tmp/vis/vis . +# make vis-single +# docker cp vis:/tmp/vis/vis-single . FROM alpine:edge ENV DIR /tmp/vis WORKDIR $DIR -RUN apk update && apk add musl-dev fortify-headers gcc make libtermkey-dev ncurses-dev ncurses-static lua5.3-dev lua5.3-lpeg lua-lpeg-dev acl-dev +RUN apk update && apk add musl-dev fortify-headers gcc make libtermkey-dev ncurses-dev ncurses-static lua5.3-dev lua5.3-lpeg lua-lpeg-dev acl-dev libarchive-dev xz-dev xz bzip2-dev RUN sed -i 's/Libs: /Libs: -L${INSTALL_CMOD} /' /usr/lib/pkgconfig/lua5.3.pc RUN mv /usr/lib/lua/5.3/lpeg.a /usr/lib/lua/5.3/liblpeg.a RUN sed -i 's/-ltermkey/-ltermkey -lunibilium/' /usr/lib/pkgconfig/termkey.pc diff --git a/Makefile b/Makefile index dd896e2df..b71238a6b 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,20 @@ vis-menu: vis-menu.c vis-digraph: vis-digraph.c ${CC} ${CFLAGS} ${CFLAGS_AUTO} ${CFLAGS_STD} ${CFLAGS_EXTRA} $< ${LDFLAGS} ${LDFLAGS_STD} ${LDFLAGS_AUTO} -o $@ +vis-single-payload.inc: $(EXECUTABLES) lua/* + echo '#ifndef VIS_SINGLE_PAYLOAD_H' > vis-single-payload.inc + echo '#define VIS_SINGLE_PAYLOAD_H' >> vis-single-payload.inc + echo 'unsigned char vis_single_payload[] = {' >> vis-single-payload.inc + tar c $(EXECUTABLES) $$(find lua -name '*.lua') | xz | od -t x1 -A none -v | \ + sed 's/\([0-9a-f]\+\)/0x\1,/g;$$s/,$$/ };/' >> vis-single-payload.inc + echo '#endif' >> vis-single-payload.inc + +vis-single: vis-single.c vis-single-payload.inc + for e in $(ELF); do \ + ${STRIP} "$$e"; \ + done + ${CC} ${CFLAGS} ${CFLAGS_AUTO} ${CFLAGS_STD} ${CFLAGS_EXTRA} $< ${LDFLAGS} ${LDFLAGS_STD} ${LDFLAGS_AUTO} -larchive -lacl -lbz2 -llzma -o $@ + debug: clean @$(MAKE) CFLAGS_EXTRA='${CFLAGS_EXTRA} ${CFLAGS_DEBUG}' @@ -91,7 +105,7 @@ test: clean: @echo cleaning - @rm -f $(ELF) vis-single vis-*.tar.gz *.gcov *.gcda *.gcno + @rm -f $(ELF) vis-single vis-single-payload.inc vis-*.tar.gz *.gcov *.gcda *.gcno dist: clean @echo creating dist tarball diff --git a/vis-single.c b/vis-single.c new file mode 100644 index 000000000..b6296c0d9 --- /dev/null +++ b/vis-single.c @@ -0,0 +1,151 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "vis-single-payload.inc" + +int copy_data(struct archive *ar, struct archive *aw) { + int r; + const void *buff; + size_t size; + int64_t offset; + + for (;;) { + if ((r = archive_read_data_block(ar, &buff, &size, &offset)) == ARCHIVE_EOF) + return ARCHIVE_OK; + + if (r != ARCHIVE_OK) { + fprintf(stderr, "archive_read_data_block() failed: %s\n", archive_error_string(ar)); + return r; + } + + if ((r = archive_write_data_block(aw, buff, size, offset)) != ARCHIVE_OK) { + fprintf(stderr, "archive_write_data_block() failed: %s\n", archive_error_string(aw)); + return r; + } + } + + return ARCHIVE_OK; +} + +int extract(const char *path) { + struct archive *a; + struct archive_entry *entry; + struct archive *ext; + char * abs_path = NULL; + const char * term; + char * termenv; + int r = ARCHIVE_FAILED; + + if ((a = archive_read_new()) == NULL) + return ARCHIVE_FAILED; + + if ((r = archive_read_support_filter_xz(a)) != ARCHIVE_OK) + goto out10; + + if ((r = archive_read_support_format_tar(a)) != ARCHIVE_OK) + goto out10; + + if ((ext = archive_write_disk_new()) == NULL) { + r = ARCHIVE_FAILED; + goto out10; + } + + if ((r = archive_read_open_memory(a, vis_single_payload, sizeof(vis_single_payload))) != ARCHIVE_OK) { + fprintf(stderr, "archive_read_open_memory() failed: %s\n", archive_error_string(a)); + goto out20; + } + + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + if (asprintf(&abs_path, "%s/%s", path, archive_entry_pathname(entry)) == -1) + goto out20; + + archive_entry_set_pathname(entry, abs_path); + free(abs_path); + + if ((r = archive_write_header(ext, entry)) != ARCHIVE_OK) { + fprintf(stderr, "archive_write_header() failed: %s\n", archive_error_string(ext)); + goto out20; + } + + if ((r = copy_data(a, ext)) != ARCHIVE_OK) + goto out20; + + if ((r = archive_write_finish_entry(ext)) != ARCHIVE_OK) { + fprintf(stderr, "archive_write_finish_entry() failed: %s\n", archive_error_string(ext)); + goto out20; + } + } + +out20: + archive_write_close(ext); + archive_write_free(ext); + +out10: + archive_read_close(a); + archive_read_free(a); + + return ARCHIVE_OK; +} + +int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { + return remove(fpath); +} + +int main(int argc, char **argv) { + char tmp_dirname_template[] = "/tmp/.vis-single-XXXXXX"; + const char *tmp_dirname; + char *abs_path = NULL; + const char *term; + char *termenv = NULL; + int child_pid, statval, rc = EXIT_FAILURE; + + if ((tmp_dirname = mkdtemp(tmp_dirname_template)) == NULL) { + perror ("mkdtemp: Could not create tmp directory"); + goto out10; + } + + if (extract(tmp_dirname) != ARCHIVE_OK) + goto out20; + + if (asprintf(&abs_path, "%s/vis", tmp_dirname) == -1) + goto out20; + + child_pid = fork(); + if (child_pid == -1) { + fprintf(stderr, "could not fork!\n"); + goto out30; + } else if (child_pid == 0) { + if ((term = getenv("TERM")) == NULL) { + puts("TERM is not defined!"); + goto out30; + } + + if (asprintf(&termenv, "TERM=%s", term) == -1) + goto out30; + + char *env[] = { termenv, NULL }; + execve(abs_path, argv, env); + } + + waitpid(child_pid, &statval, WUNTRACED|WCONTINUED); + rc = WEXITSTATUS(statval); + +out30: + free(abs_path); + free(termenv); + +out20: + nftw(tmp_dirname, unlink_cb, 64, FTW_DEPTH|FTW_PHYS); + +out10: + return rc; +}