113b5b548SBaptiste Daroussin /* $OpenBSD: edit.c,v 1.19 2009/06/07 13:29:50 ray Exp $ */ 213b5b548SBaptiste Daroussin 313b5b548SBaptiste Daroussin /* 413b5b548SBaptiste Daroussin * Written by Raymond Lai <ray@cyth.net>. 513b5b548SBaptiste Daroussin * Public domain. 613b5b548SBaptiste Daroussin */ 713b5b548SBaptiste Daroussin 813b5b548SBaptiste Daroussin #include <sys/cdefs.h> 913b5b548SBaptiste Daroussin __FBSDID("$FreeBSD$"); 1013b5b548SBaptiste Daroussin 1113b5b548SBaptiste Daroussin #include <sys/types.h> 1213b5b548SBaptiste Daroussin #include <sys/wait.h> 1313b5b548SBaptiste Daroussin 1413b5b548SBaptiste Daroussin #include <ctype.h> 1513b5b548SBaptiste Daroussin #include <err.h> 1613b5b548SBaptiste Daroussin #include <errno.h> 1713b5b548SBaptiste Daroussin #include <paths.h> 1813b5b548SBaptiste Daroussin #include <signal.h> 1913b5b548SBaptiste Daroussin #include <stdio.h> 2013b5b548SBaptiste Daroussin #include <stdlib.h> 2113b5b548SBaptiste Daroussin #include <string.h> 2213b5b548SBaptiste Daroussin #include <unistd.h> 2313b5b548SBaptiste Daroussin 2413b5b548SBaptiste Daroussin #include "common.h" 2513b5b548SBaptiste Daroussin #include "extern.h" 2613b5b548SBaptiste Daroussin 2713b5b548SBaptiste Daroussin /* 2813b5b548SBaptiste Daroussin * Execute an editor on the specified pathname, which is interpreted 2913b5b548SBaptiste Daroussin * from the shell. This means flags may be included. 3013b5b548SBaptiste Daroussin * 3113b5b548SBaptiste Daroussin * Returns -1 on error, or the exit value on success. 3213b5b548SBaptiste Daroussin */ 33*e8ad1a6fSBaptiste Daroussin static int 3413b5b548SBaptiste Daroussin editit(const char *pathname) 3513b5b548SBaptiste Daroussin { 3613b5b548SBaptiste Daroussin sig_t sighup, sigint, sigquit, sigchld; 3713b5b548SBaptiste Daroussin pid_t pid; 3813b5b548SBaptiste Daroussin int saved_errno, st, ret = -1; 3915eaa1aeSBaptiste Daroussin const char *ed; 4013b5b548SBaptiste Daroussin 411ddda798SBaptiste Daroussin ed = getenv("VISUAL"); 421ddda798SBaptiste Daroussin if (ed == NULL) 431ddda798SBaptiste Daroussin ed = getenv("EDITOR"); 441ddda798SBaptiste Daroussin if (ed == NULL) 4513b5b548SBaptiste Daroussin ed = _PATH_VI; 4613b5b548SBaptiste Daroussin 4713b5b548SBaptiste Daroussin sighup = signal(SIGHUP, SIG_IGN); 4813b5b548SBaptiste Daroussin sigint = signal(SIGINT, SIG_IGN); 4913b5b548SBaptiste Daroussin sigquit = signal(SIGQUIT, SIG_IGN); 5013b5b548SBaptiste Daroussin sigchld = signal(SIGCHLD, SIG_DFL); 5113b5b548SBaptiste Daroussin if ((pid = fork()) == -1) 5213b5b548SBaptiste Daroussin goto fail; 5313b5b548SBaptiste Daroussin if (pid == 0) { 5415eaa1aeSBaptiste Daroussin execlp(ed, ed, pathname, (char *)NULL); 5513b5b548SBaptiste Daroussin _exit(127); 5613b5b548SBaptiste Daroussin } 5713b5b548SBaptiste Daroussin while (waitpid(pid, &st, 0) == -1) 5813b5b548SBaptiste Daroussin if (errno != EINTR) 5913b5b548SBaptiste Daroussin goto fail; 6013b5b548SBaptiste Daroussin if (!WIFEXITED(st)) 6113b5b548SBaptiste Daroussin errno = EINTR; 6213b5b548SBaptiste Daroussin else 6313b5b548SBaptiste Daroussin ret = WEXITSTATUS(st); 6413b5b548SBaptiste Daroussin 6513b5b548SBaptiste Daroussin fail: 6613b5b548SBaptiste Daroussin saved_errno = errno; 6713b5b548SBaptiste Daroussin (void)signal(SIGHUP, sighup); 6813b5b548SBaptiste Daroussin (void)signal(SIGINT, sigint); 6913b5b548SBaptiste Daroussin (void)signal(SIGQUIT, sigquit); 7013b5b548SBaptiste Daroussin (void)signal(SIGCHLD, sigchld); 7113b5b548SBaptiste Daroussin errno = saved_errno; 7213b5b548SBaptiste Daroussin return (ret); 7313b5b548SBaptiste Daroussin } 7413b5b548SBaptiste Daroussin 7513b5b548SBaptiste Daroussin /* 7613b5b548SBaptiste Daroussin * Parse edit command. Returns 0 on success, -1 on error. 7713b5b548SBaptiste Daroussin */ 7813b5b548SBaptiste Daroussin int 7913b5b548SBaptiste Daroussin eparse(const char *cmd, const char *left, const char *right) 8013b5b548SBaptiste Daroussin { 8113b5b548SBaptiste Daroussin FILE *file; 8213b5b548SBaptiste Daroussin size_t nread; 8313b5b548SBaptiste Daroussin int fd; 8413b5b548SBaptiste Daroussin char *filename; 8513b5b548SBaptiste Daroussin char buf[BUFSIZ], *text; 8613b5b548SBaptiste Daroussin 8713b5b548SBaptiste Daroussin /* Skip whitespace. */ 8813b5b548SBaptiste Daroussin while (isspace(*cmd)) 8913b5b548SBaptiste Daroussin ++cmd; 9013b5b548SBaptiste Daroussin 9113b5b548SBaptiste Daroussin text = NULL; 9213b5b548SBaptiste Daroussin switch (*cmd) { 9313b5b548SBaptiste Daroussin case '\0': 9413b5b548SBaptiste Daroussin /* Edit empty file. */ 9513b5b548SBaptiste Daroussin break; 9613b5b548SBaptiste Daroussin 9713b5b548SBaptiste Daroussin case 'b': 9813b5b548SBaptiste Daroussin /* Both strings. */ 9913b5b548SBaptiste Daroussin if (left == NULL) 10013b5b548SBaptiste Daroussin goto RIGHT; 10113b5b548SBaptiste Daroussin if (right == NULL) 10213b5b548SBaptiste Daroussin goto LEFT; 10313b5b548SBaptiste Daroussin 10413b5b548SBaptiste Daroussin /* Neither column is blank, so print both. */ 10513b5b548SBaptiste Daroussin if (asprintf(&text, "%s\n%s\n", left, right) == -1) 10613b5b548SBaptiste Daroussin err(2, "could not allocate memory"); 10713b5b548SBaptiste Daroussin break; 10813b5b548SBaptiste Daroussin 10913b5b548SBaptiste Daroussin case 'l': 11013b5b548SBaptiste Daroussin LEFT: 11113b5b548SBaptiste Daroussin /* Skip if there is no left column. */ 11213b5b548SBaptiste Daroussin if (left == NULL) 11313b5b548SBaptiste Daroussin break; 11413b5b548SBaptiste Daroussin 11513b5b548SBaptiste Daroussin if (asprintf(&text, "%s\n", left) == -1) 11613b5b548SBaptiste Daroussin err(2, "could not allocate memory"); 11713b5b548SBaptiste Daroussin 11813b5b548SBaptiste Daroussin break; 11913b5b548SBaptiste Daroussin 12013b5b548SBaptiste Daroussin case 'r': 12113b5b548SBaptiste Daroussin RIGHT: 12213b5b548SBaptiste Daroussin /* Skip if there is no right column. */ 12313b5b548SBaptiste Daroussin if (right == NULL) 12413b5b548SBaptiste Daroussin break; 12513b5b548SBaptiste Daroussin 12613b5b548SBaptiste Daroussin if (asprintf(&text, "%s\n", right) == -1) 12713b5b548SBaptiste Daroussin err(2, "could not allocate memory"); 12813b5b548SBaptiste Daroussin 12913b5b548SBaptiste Daroussin break; 13013b5b548SBaptiste Daroussin 13113b5b548SBaptiste Daroussin default: 13213b5b548SBaptiste Daroussin return (-1); 13313b5b548SBaptiste Daroussin } 13413b5b548SBaptiste Daroussin 13513b5b548SBaptiste Daroussin /* Create temp file. */ 13613b5b548SBaptiste Daroussin if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1) 13713b5b548SBaptiste Daroussin err(2, "asprintf"); 13813b5b548SBaptiste Daroussin if ((fd = mkstemp(filename)) == -1) 13913b5b548SBaptiste Daroussin err(2, "mkstemp"); 14013b5b548SBaptiste Daroussin if (text != NULL) { 14113b5b548SBaptiste Daroussin size_t len; 14213b5b548SBaptiste Daroussin ssize_t nwritten; 14313b5b548SBaptiste Daroussin 14413b5b548SBaptiste Daroussin len = strlen(text); 14513b5b548SBaptiste Daroussin if ((nwritten = write(fd, text, len)) == -1 || 14613b5b548SBaptiste Daroussin (size_t)nwritten != len) { 14713b5b548SBaptiste Daroussin warn("error writing to temp file"); 14813b5b548SBaptiste Daroussin cleanup(filename); 14913b5b548SBaptiste Daroussin } 15013b5b548SBaptiste Daroussin } 15113b5b548SBaptiste Daroussin close(fd); 15213b5b548SBaptiste Daroussin 15313b5b548SBaptiste Daroussin /* text is no longer used. */ 15413b5b548SBaptiste Daroussin free(text); 15513b5b548SBaptiste Daroussin 15613b5b548SBaptiste Daroussin /* Edit temp file. */ 15713b5b548SBaptiste Daroussin if (editit(filename) == -1) { 15813b5b548SBaptiste Daroussin warn("error editing %s", filename); 15913b5b548SBaptiste Daroussin cleanup(filename); 16013b5b548SBaptiste Daroussin } 16113b5b548SBaptiste Daroussin 16213b5b548SBaptiste Daroussin /* Open temporary file. */ 16313b5b548SBaptiste Daroussin if (!(file = fopen(filename, "r"))) { 16413b5b548SBaptiste Daroussin warn("could not open edited file: %s", filename); 16513b5b548SBaptiste Daroussin cleanup(filename); 16613b5b548SBaptiste Daroussin } 16713b5b548SBaptiste Daroussin 16813b5b548SBaptiste Daroussin /* Copy temporary file contents to output file. */ 16913b5b548SBaptiste Daroussin for (nread = sizeof(buf); nread == sizeof(buf);) { 17013b5b548SBaptiste Daroussin size_t nwritten; 17113b5b548SBaptiste Daroussin 17213b5b548SBaptiste Daroussin nread = fread(buf, sizeof(*buf), sizeof(buf), file); 17313b5b548SBaptiste Daroussin /* Test for error or end of file. */ 17413b5b548SBaptiste Daroussin if (nread != sizeof(buf) && 17513b5b548SBaptiste Daroussin (ferror(file) || !feof(file))) { 17613b5b548SBaptiste Daroussin warnx("error reading edited file: %s", filename); 17713b5b548SBaptiste Daroussin cleanup(filename); 17813b5b548SBaptiste Daroussin } 17913b5b548SBaptiste Daroussin 18013b5b548SBaptiste Daroussin /* 18113b5b548SBaptiste Daroussin * If we have nothing to read, break out of loop 18213b5b548SBaptiste Daroussin * instead of writing nothing. 18313b5b548SBaptiste Daroussin */ 18413b5b548SBaptiste Daroussin if (!nread) 18513b5b548SBaptiste Daroussin break; 18613b5b548SBaptiste Daroussin 18713b5b548SBaptiste Daroussin /* Write data we just read. */ 18813b5b548SBaptiste Daroussin nwritten = fwrite(buf, sizeof(*buf), nread, outfp); 18913b5b548SBaptiste Daroussin if (nwritten != nread) { 19013b5b548SBaptiste Daroussin warnx("error writing to output file"); 19113b5b548SBaptiste Daroussin cleanup(filename); 19213b5b548SBaptiste Daroussin } 19313b5b548SBaptiste Daroussin } 19413b5b548SBaptiste Daroussin 19513b5b548SBaptiste Daroussin /* We've reached the end of the temporary file, so remove it. */ 19613b5b548SBaptiste Daroussin if (unlink(filename)) 19713b5b548SBaptiste Daroussin warn("could not delete: %s", filename); 19813b5b548SBaptiste Daroussin fclose(file); 19913b5b548SBaptiste Daroussin 20013b5b548SBaptiste Daroussin free(filename); 20113b5b548SBaptiste Daroussin 20213b5b548SBaptiste Daroussin return (0); 20313b5b548SBaptiste Daroussin } 204