diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2017-05-31 14:09:34 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2017-05-31 15:37:25 +0200 |
| commit | fae92a04cdfd5ebe8e07865446732b0287f4553a (patch) | |
| tree | 8b505f958be45f0eff5ce5bec869402714ede975 /vis-single.c | |
| parent | 2599e5c9be9fa8ef12ff92cff85f0c72be2b1aeb (diff) | |
| download | vis-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.c | 191 |
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; } |
