build: fix _XOPEN_SOURCE redefinition warning
[vis.git] / vis-single.c
blob11af10fba68228da3bf246e3183de22a505f434f
1 #include <sys/wait.h>
2 #include <errno.h>
3 #include <fcntl.h>
4 #include <ftw.h>
5 #include <limits.h>
6 #include <signal.h>
7 #include <stdint.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
13 #include <lzma.h>
14 #include <libuntar.h>
16 #ifndef PATH_MAX
17 #define PATH_MAX 4096
18 #endif
20 #include "vis-single-payload.inc"
22 #ifndef VIS_TMP
23 #define VIS_TMP "/tmp/.vis-single-XXXXXX"
24 #endif
26 #ifndef VIS_TERMINFO
27 #define VIS_TERMINFO "/etc/terminfo:/lib/terminfo:/usr/share/terminfo:" \
28 "/usr/lib/terminfo:/usr/local/share/terminfo:/usr/local/lib/terminfo"
29 #endif
31 static lzma_stream strm = LZMA_STREAM_INIT;
33 static int libtar_xzopen(const char *pathname, int flags, ...) {
34 int ret = lzma_stream_decoder(&strm, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);
35 if (ret != LZMA_OK) {
36 fprintf(stderr, "lzma_stream_decoder error: %d\n", ret);
37 return ret;
40 strm.next_in = vis_single_payload;
41 strm.avail_in = sizeof(vis_single_payload);
43 return ret;
46 static int libtar_xzclose(int fd) {
47 lzma_end(&strm);
48 return 0;
51 static ssize_t libtar_xzread(int fd, void *buf, size_t count) {
52 strm.next_out = buf;
53 strm.avail_out = count;
55 int ret = lzma_code(&strm, LZMA_FINISH);
56 if (ret != LZMA_OK && ret != LZMA_STREAM_END) {
57 fprintf(stderr, "lzma_code error: %d\n", ret);
58 return -1;
61 return count - strm.avail_out;
64 tartype_t xztype = {
65 libtar_xzopen,
66 libtar_xzclose,
67 libtar_xzread,
70 int extract(char *directory) {
71 TAR *tar;
73 if (tar_open(&tar, NULL, &xztype, O_RDONLY, 0, 0) == -1) {
74 perror("tar_open");
75 return -1;
78 if (tar_extract_all(tar, directory) != 0) {
79 perror("tar_extract_all");
80 return -1;
83 if (tar_close(tar) != 0) {
84 perror("tar_close");
85 return -1;
88 return 0;
91 static int unlink_cb(const char *path, const struct stat *sb, int typeflag, struct FTW *ftwbuf) {
92 return remove(path);
95 int main(int argc, char **argv) {
96 int rc = EXIT_FAILURE;
97 char exe[256], path[PATH_MAX];
98 char tmp_dirname[] = VIS_TMP;
100 if (!mkdtemp(tmp_dirname)) {
101 perror("mkdtemp");
102 return rc;
105 char *old_path = getenv("PATH");
106 if (snprintf(path, sizeof(path), "%s%s%s", tmp_dirname,
107 old_path ? ":" : "", old_path ? old_path : "") < 0) {
108 goto err;
111 if (setenv("PATH", path, 1) == -1 ||
112 setenv("TERMINFO_DIRS", VIS_TERMINFO, 0) == -1) {
113 perror("setenv");
114 goto err;
117 if (extract(tmp_dirname) != 0)
118 goto err;
120 if (snprintf(exe, sizeof(exe), "%s/vis", tmp_dirname) < 0)
121 goto err;
123 int child_pid = fork();
124 if (child_pid == -1) {
125 perror("fork");
126 goto err;
127 } else if (child_pid == 0) {
128 execv(exe, argv);
129 perror("execv");
130 return EXIT_FAILURE;
133 signal(SIGINT, SIG_IGN);
135 for (;;) {
136 int status;
137 int w = waitpid(child_pid, &status, 0);
138 if (w == -1) {
139 perror("waitpid");
140 break;
142 if (w == child_pid) {
143 rc = WEXITSTATUS(status);
144 break;
148 err:
149 nftw(tmp_dirname, unlink_cb, 64, FTW_DEPTH|FTW_PHYS|FTW_MOUNT);
150 return rc;