From 0522b4bf4e125b7ceb67f7177db692aed3a0ebf9 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Fri, 12 Jun 2020 17:54:14 -0700 Subject: forgot file --- sys/cmd/dvtm/dvtm-editor.c | 180 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 sys/cmd/dvtm/dvtm-editor.c (limited to 'sys') diff --git a/sys/cmd/dvtm/dvtm-editor.c b/sys/cmd/dvtm/dvtm-editor.c new file mode 100644 index 0000000..45a61b2 --- /dev/null +++ b/sys/cmd/dvtm/dvtm-editor.c @@ -0,0 +1,180 @@ +/* Invoke $EDITOR as a filter. + * + * Copyright (c) 2016 Dmitry Bogatov + * Copyright (c) 2017 Marc André Tanner + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void error(const char *msg, ...) { + va_list ap; + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + fprintf(stderr, "\n"); +} + +int main(int argc, char *argv[]) +{ + int exit_status = EXIT_FAILURE, tmp_write = -1; + + const char *editor = getenv("DVTM_EDITOR"); + if (!editor) + editor = getenv("VISUAL"); + if (!editor) + editor = getenv("EDITOR"); + if (!editor) + editor = "vi"; + + char tempname[] = "/tmp/dvtm-editor.XXXXXX"; + if ((tmp_write = mkstemp(tempname)) == -1) { + error("failed to open temporary file `%s'", tempname); + goto err; + } + + /* POSIX does not mandates modes of temporary file. */ + if (fchmod(tmp_write, 0600) == -1) { + error("failed to change mode of temporary file `%s'", tempname); + goto err; + } + + char buffer[2048]; + ssize_t bytes; + while ((bytes = read(STDIN_FILENO, buffer, sizeof(buffer))) > 0) { + do { + ssize_t written = write(tmp_write, buffer, bytes); + if (written == -1) { + error("failed to write data to temporary file `%s'", + tempname); + goto err; + } + bytes -= written; + } while (bytes > 0); + } + + if (fsync(tmp_write) == -1) { + error("failed to fsync temporary file `%s'", tempname); + goto err; + } + + struct stat stat_before; + if (fstat(tmp_write, &stat_before) == -1) { + error("failed to stat newly created temporary file `%s'", tempname); + goto err; + } + + if (close(tmp_write) == -1) { + error("failed to close temporary file `%s'", tempname); + goto err; + } + + pid_t pid = fork(); + if (pid == -1) { + error("failed to fork editor process"); + goto err; + } else if (pid == 0) { + int tty = open("/dev/tty", O_RDWR); + if (tty == -1) { + error("failed to open /dev/tty"); + _exit(1); + } + + if (dup2(tty, STDIN_FILENO) == -1) { + error("failed to set tty as stdin"); + _exit(1); + } + + if (dup2(tty, STDOUT_FILENO) == -1) { + error("failed to set tty as stdout"); + _exit(1); + } + + if (dup2(tty, STDERR_FILENO) == -1) { + error("failed to set tty as stderr"); + _exit(1); + } + + close(tty); + + const char *editor_argv[argc+2]; + editor_argv[0] = editor; + for (int i = 1; i < argc; i++) + editor_argv[i] = argv[i]; + editor_argv[argc] = tempname; + editor_argv[argc+1] = NULL; + + execvp(editor, (char* const*)editor_argv); + error("failed to exec editor process `%s'", editor); + _exit(127); + } + + int status; + if (waitpid(pid, &status, 0) == -1) { + error("waitpid failed"); + goto err; + } + if (!WIFEXITED(status)) { + error("editor invocation failed"); + goto err; + } + if ((status = WEXITSTATUS(status)) != 0) { + error("editor terminated with exit status: %d", status); + goto err; + } + + int tmp_read = open(tempname, O_RDONLY); + if (tmp_read == -1) { + error("failed to open for reading of edited temporary file `%s'", + tempname); + goto err; + } + + struct stat stat_after; + if (fstat(tmp_read, &stat_after) == -1) { + error("failed to stat edited temporary file `%s'", tempname); + goto err; + } + + if (stat_before.st_mtime == stat_after.st_mtime) + goto ok; /* no modifications */ + + while ((bytes = read(tmp_read, buffer, sizeof(buffer))) > 0) { + do { + ssize_t written = write(STDOUT_FILENO, buffer, bytes); + if (written == -1) { + error("failed to write data to stdout"); + goto err; + } + bytes -= written; + } while (bytes > 0); + } + +ok: + exit_status = EXIT_SUCCESS; +err: + if (tmp_write != -1) + unlink(tempname); + return exit_status; +} -- cgit v1.2.1