build: add git based version information back
[vis.git] / vis-single.c
blob8e06de508847c7aa12a75406bfe337025a14d2ad
1 #include <sys/wait.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <ftw.h>
5 #include <limits.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
12 #include <lzma.h>
13 #include <libuntar.h>
15 #ifndef PATH_MAX
16 #define PATH_MAX 4096
17 #endif
19 #include "vis-single-payload.inc"
21 #ifndef VIS_TMP
22 #define VIS_TMP "/tmp/.vis-single-XXXXXX"
23 #endif
25 #ifndef VIS_TERMINFO
26 #define VIS_TERMINFO "/etc/terminfo:/lib/terminfo:/usr/share/terminfo:" \
27 "/usr/lib/terminfo:/usr/local/share/terminfo:/usr/local/lib/terminfo"
28 #endif
30 static lzma_stream strm = LZMA_STREAM_INIT;
32 static int libtar_xzopen(const char *pathname, int flags, ...) {
33 int ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);
34 if (ret != LZMA_OK) {
35 fprintf(stderr, "lzma_stream_decoder error: %d\n", ret);
36 return ret;
39 strm.next_in = vis_single_payload;
40 strm.avail_in = sizeof(vis_single_payload);
42 return ret;
45 static int libtar_xzclose(int fd) {
46 lzma_end(&strm);
47 return 0;
50 static ssize_t libtar_xzread(int fd, void *buf, size_t count) {
51 strm.next_out = buf;
52 strm.avail_out = count;
54 int ret = lzma_code(&strm, LZMA_FINISH);
55 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
56 fprintf(stderr, "lzma_code error: %d\n", ret);
57 return -1;
60 return count - strm.avail_out;
63 tartype_t xztype = {
64 libtar_xzopen,
65 libtar_xzclose,
66 libtar_xzread,
69 int extract(char *directory) {
70 TAR *tar;
72 if (tar_open(&tar, NULL, &xztype, O_RDONLY, 0, 0) == -1) {
73 perror("tar_open");
74 return -1;
77 if (tar_extract_all(tar, directory) != 0) {
78 perror("tar_extract_all");
79 return -1;
82 if (tar_close(tar) != 0) {
83 perror("tar_close");
84 return -1;
87 return 0;
90 static int unlink_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
91 return remove(path);
94 int main(int argc, char **argv) {
95 int rc = EXIT_FAILURE;
96 char exe[256], path[PATH_MAX];
97 char tmp_dirname[] = VIS_TMP;
99 if (!mkdtemp(tmp_dirname)) {
100 perror("mkdtemp");
101 return rc;
104 char *old_path = getenv("PATH");
105 if (snprintf(path, sizeof(path), "%s%s%s", tmp_dirname,
106 old_path ? ":" : "", old_path ? old_path : "") < 0) {
107 goto err;
110 if (setenv("PATH", path, 1) == -1 ||
111 setenv("TERMINFO_DIRS", VIS_TERMINFO, 0) == -1) {
112 perror("setenv");
113 goto err;
116 if (extract(tmp_dirname) != 0)
117 goto err;
119 if (snprintf(exe, sizeof(exe), "%s/vis", tmp_dirname) < 0)
120 goto err;
122 int child_pid = fork();
123 if (child_pid == -1) {
124 perror("fork");
125 goto err;
126 } else if (child_pid == 0) {
127 execv(exe, argv);
128 perror("execv");
129 return EXIT_FAILURE;
132 signal(SIGINT, SIG_IGN);
134 for (;;) {
135 int status;
136 int w = waitpid(child_pid, &status, 0);
137 if (w == -1) {
138 perror("waitpid");
139 break;
141 if (w == child_pid) {
142 rc = WEXITSTATUS(status);
143 break;
147 err:
148 nftw(tmp_dirname, unlink_cb, 64, FTW_DEPTH|FTW_PHYS|FTW_MOUNT);
149 return rc;