vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

vis-single.c

(3195B)


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