aboutsummaryrefslogtreecommitdiff
path: root/vis-single.c
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2017-05-31 14:09:34 +0200
committerMarc André Tanner <mat@brain-dump.org>2017-05-31 15:37:25 +0200
commitfae92a04cdfd5ebe8e07865446732b0287f4553a (patch)
tree8b505f958be45f0eff5ce5bec869402714ede975 /vis-single.c
parent2599e5c9be9fa8ef12ff92cff85f0c72be2b1aeb (diff)
downloadvis-fae92a04cdfd5ebe8e07865446732b0287f4553a.tar.gz
vis-fae92a04cdfd5ebe8e07865446732b0287f4553a.tar.xz
build: cleanup self contained executable
Set $PATH and $TERMINFO_DIRS environment variables, use chdir(2) to simplify extraction logic, improve error handling.
Diffstat (limited to 'vis-single.c')
-rw-r--r--vis-single.c191
1 files changed, 110 insertions, 81 deletions
diff --git a/vis-single.c b/vis-single.c
index b6296c0..dc6fe9f 100644
--- a/vis-single.c
+++ b/vis-single.c
@@ -1,18 +1,30 @@
-#define _GNU_SOURCE
-
+#include <sys/wait.h>
#include <ftw.h>
+#include <limits.h>
+#include <stdint.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 <archive.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
#include "vis-single-payload.inc"
-int copy_data(struct archive *ar, struct archive *aw) {
+#ifndef VIS_TMP
+#define VIS_TMP "/tmp/.vis-single-XXXXXX"
+#endif
+
+#ifndef VIS_TERMINFO
+#define VIS_TERMINFO "/etc/terminfo:/lib/terminfo:/usr/share/terminfo:" \
+ "/usr/lib/terminfo:/usr/local/share/terminfo:/usr/local/lib/terminfo"
+#endif
+
+static int copy_data(struct archive *ar, struct archive *aw) {
int r;
const void *buff;
size_t size;
@@ -36,116 +48,133 @@ int copy_data(struct archive *ar, struct archive *aw) {
return ARCHIVE_OK;
}
-int extract(const char *path) {
- struct archive *a;
+static int extract(void) {
+ struct archive *in = NULL, *out = NULL;
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)
+ if (!(in = archive_read_new()))
return ARCHIVE_FAILED;
- if ((r = archive_read_support_filter_xz(a)) != ARCHIVE_OK)
- goto out10;
+ if ((r = archive_read_support_filter_xz(in)) != ARCHIVE_OK)
+ goto err;
- if ((r = archive_read_support_format_tar(a)) != ARCHIVE_OK)
- goto out10;
+ if ((r = archive_read_support_format_tar(in)) != ARCHIVE_OK)
+ goto err;
- if ((ext = archive_write_disk_new()) == NULL) {
+ if (!(out = archive_write_disk_new())) {
r = ARCHIVE_FAILED;
- goto out10;
+ goto err;
}
- 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;
+ if ((r = archive_read_open_memory(in, vis_single_payload, sizeof(vis_single_payload))) != ARCHIVE_OK) {
+ fprintf(stderr, "archive_read_open_memory() failed: %s\n", archive_error_string(in));
+ goto err;
}
- 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;
+ while (archive_read_next_header(in, &entry) == ARCHIVE_OK) {
+ if ((r = archive_write_header(out, entry)) != ARCHIVE_OK) {
+ fprintf(stderr, "archive_write_header() failed: %s\n", archive_error_string(out));
+ goto err;
}
- if ((r = copy_data(a, ext)) != ARCHIVE_OK)
- goto out20;
+ if ((r = copy_data(in, out)) != ARCHIVE_OK)
+ goto err;
- if ((r = archive_write_finish_entry(ext)) != ARCHIVE_OK) {
- fprintf(stderr, "archive_write_finish_entry() failed: %s\n", archive_error_string(ext));
- goto out20;
+ if ((r = archive_write_finish_entry(out)) != ARCHIVE_OK) {
+ fprintf(stderr, "archive_write_finish_entry() failed: %s\n", archive_error_string(out));
+ goto err;
}
}
-out20:
- archive_write_close(ext);
- archive_write_free(ext);
+err:
+ if (out) {
+ archive_write_close(out);
+ archive_write_free(out);
+ }
-out10:
- archive_read_close(a);
- archive_read_free(a);
+ if (in) {
+ archive_read_close(in);
+ archive_read_free(in);
+ }
- return ARCHIVE_OK;
+ return r;
}
-int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
- return remove(fpath);
+static int unlink_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
+ return remove(path);
}
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;
+ char exe[256], cwd[PATH_MAX], path[PATH_MAX];
+ int rc = EXIT_FAILURE;
+
+ if (!getcwd(cwd, sizeof(cwd))) {
+ perror("getcwd");
+ return rc;
}
- if (extract(tmp_dirname) != ARCHIVE_OK)
- goto out20;
+ char tmp_dirname_template[] = VIS_TMP;
+ const char *tmp_dirname = mkdtemp(tmp_dirname_template);
- if (asprintf(&abs_path, "%s/vis", tmp_dirname) == -1)
- goto out20;
+ if (!tmp_dirname) {
+ perror("mkdtemp");
+ return rc;
+ }
- 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;
- }
+ char *old_path = getenv("PATH");
+ if (snprintf(path, sizeof(path), "%s%s%s", tmp_dirname,
+ old_path ? ":" : "", old_path ? old_path : "") < 0) {
+ goto err;
+ }
+
+ if (setenv("PATH", path, 1) == -1 ||
+ setenv("TERMINFO_DIRS", VIS_TERMINFO, 0) == -1) {
+ perror("setenv");
+ goto err;
+ }
- if (asprintf(&termenv, "TERM=%s", term) == -1)
- goto out30;
- char *env[] = { termenv, NULL };
- execve(abs_path, argv, env);
+ if (chdir(tmp_dirname) == -1) {
+ perror("chdir");
+ goto err;
}
- waitpid(child_pid, &statval, WUNTRACED|WCONTINUED);
- rc = WEXITSTATUS(statval);
+ if (extract() != ARCHIVE_OK)
+ goto err;
+
+ if (chdir(cwd) == -1) {
+ perror("chdir");
+ goto err;
+ }
-out30:
- free(abs_path);
- free(termenv);
+ if (snprintf(exe, sizeof(exe), "%s/vis", tmp_dirname) < 0)
+ goto err;
-out20:
- nftw(tmp_dirname, unlink_cb, 64, FTW_DEPTH|FTW_PHYS);
+ int child_pid = fork();
+ if (child_pid == -1) {
+ perror("fork");
+ goto err;
+ } else if (child_pid == 0) {
+ execv(exe, argv);
+ perror("execv");
+ return EXIT_FAILURE;
+ }
+
+ for (;;) {
+ int status;
+ int w = waitpid(child_pid, &status, 0);
+ if (w == -1) {
+ perror("waitpid");
+ break;
+ }
+ if (w == child_pid) {
+ rc = WEXITSTATUS(status);
+ break;
+ }
+ }
-out10:
+err:
+ nftw(tmp_dirname, unlink_cb, 64, FTW_DEPTH|FTW_PHYS|FTW_MOUNT);
return rc;
}