1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <limits.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <lzma.h>
#include <libuntar.h>
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#include "vis-single-payload.inc"
#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 lzma_stream strm = LZMA_STREAM_INIT;
static int libtar_xzopen(const char *pathname, int flags, ...) {
int ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);
if (ret != LZMA_OK) {
fprintf(stderr, "lzma_stream_decoder error: %d\n", ret);
return ret;
}
strm.next_in = vis_single_payload;
strm.avail_in = sizeof(vis_single_payload);
return ret;
}
static int libtar_xzclose(int fd) {
lzma_end(&strm);
return 0;
}
static ssize_t libtar_xzread(int fd, void *buf, size_t count) {
strm.next_out = buf;
strm.avail_out = count;
int ret = lzma_code(&strm, LZMA_FINISH);
if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
fprintf(stderr, "lzma_code error: %d\n", ret);
return -1;
}
return count - strm.avail_out;
}
tartype_t xztype = {
libtar_xzopen,
libtar_xzclose,
libtar_xzread,
};
int extract(char *directory) {
TAR *tar;
if (tar_open(&tar, NULL, &xztype, O_RDONLY, 0, 0) == -1) {
perror("tar_open");
return -1;
}
if (tar_extract_all(tar, directory) != 0) {
perror("tar_extract_all");
return -1;
}
if (tar_close(tar) != 0) {
perror("tar_close");
return -1;
}
return 0;
}
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) {
int rc = EXIT_FAILURE;
char exe[256], path[PATH_MAX];
char tmp_dirname[] = VIS_TMP;
if (!mkdtemp(tmp_dirname)) {
perror("mkdtemp");
return rc;
}
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 (extract(tmp_dirname) != 0)
goto err;
if (snprintf(exe, sizeof(exe), "%s/vis", tmp_dirname) < 0)
goto err;
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;
}
signal(SIGINT, SIG_IGN);
for (;;) {
int status;
int w = waitpid(child_pid, &status, 0);
if (w == -1) {
perror("waitpid");
break;
}
if (w == child_pid) {
rc = WEXITSTATUS(status);
break;
}
}
err:
nftw(tmp_dirname, unlink_cb, 64, FTW_DEPTH|FTW_PHYS|FTW_MOUNT);
return rc;
}
|