aboutsummaryrefslogtreecommitdiff
path: root/vis-single.c
diff options
context:
space:
mode:
authorChristian Hesse <mail@eworm.de>2017-05-30 23:23:19 +0200
committerMarc André Tanner <mat@brain-dump.org>2017-05-31 15:37:25 +0200
commit7d88cb3c1392393c2910f2f96c93549bb5482f9f (patch)
tree55cd50da43661732c3d94cdafcc801ae8e4b4349 /vis-single.c
parent6a7802cd15d6921951cd4940229f038e631d7473 (diff)
downloadvis-7d88cb3c1392393c2910f2f96c93549bb5482f9f.tar.gz
vis-7d88cb3c1392393c2910f2f96c93549bb5482f9f.tar.xz
build: allow to build self-contained executable
Diffstat (limited to 'vis-single.c')
-rw-r--r--vis-single.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/vis-single.c b/vis-single.c
new file mode 100644
index 0000000..b6296c0
--- /dev/null
+++ b/vis-single.c
@@ -0,0 +1,151 @@
+#define _GNU_SOURCE
+
+#include <ftw.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <archive.h>
+#include <archive_entry.h>
+#include <sys/acl.h>
+
+#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;
+}