1 /* edit-stream.c --- invoke $EDITOR as filter */
2 /* Copyright (C) 2016 Dmitry Bogatov <KAction@gnu.org> ISC licensed */
4 #define _POSIX_C_SOURCE 200809L
12 /* stdio.h would be overkill */
13 #define write2(str) write(2, str, sizeof(str))
16 main(int argc
, char **argv
)
19 const char *tty
= ttyname(2); /* POSIX.1-2001, did you knew? */
21 write2("stderr is not tty");
24 int in
= open(tty
, O_RDONLY
);
26 write2("failed to open tty for reading");
29 char tempname
[] = "/tmp/edit-stream.XXXXXX";
30 int tempfd
= mkstemp(tempname
);
32 write2("failed to open temporary file");
35 /* POSIX does not mandates modes of temporary file. */
36 if (fchmod(tempfd
, 0600) == -1) {
37 write2("failed to change mode of temporary file");
38 goto err_remove_tempfile
;
42 while ((bytes
= read(0, buffer
, sizeof(buffer
))) > 0) {
43 /* Here actually must be loop, since write(2) does not guarates
44 * that it will be able to write everything. But I am reckless.
46 if (write(tempfd
, buffer
, bytes
) != bytes
) {
47 write2("failed to write data to temporary file");
48 goto err_remove_tempfile
;
51 if (fsync(tempfd
) == -1) {
52 write2("failed to fsync temporary file");
53 goto err_remove_tempfile
;
55 if (close(tempfd
) == -1) {
56 write2("failed to close temporary file");
57 goto err_remove_tempfile
;
59 if (dup2(in
, 0) == -1) {
60 write2("failed to set tty as stdin");
61 goto err_remove_tempfile
;
65 write2("failed to create copy of stdout");
66 goto err_remove_tempfile
;
68 /* Descriptor 2 (stderr) still points to tty */
69 if (dup2(2, 1) == -1) {
70 write2("failed to set tty as stdout");
71 goto err_close_stdout
;
73 const char *editor
= getenv("EDITOR");
75 write2("EDITOR is not set");
76 goto err_close_stdout
;
83 execlp(editor
, editor
, tempname
, NULL
);
87 if (wait(&status
) == -1) {
88 write2("wait failed");
89 goto err_close_stdout
;
91 if (!(WIFEXITED(status
) && WEXITSTATUS(status
) == 0)) {
92 write2("editor invocation failed");
93 goto err_close_stdout
;
95 int tempfd_r
= open(tempname
, O_RDONLY
);
97 write2("failed to open for reading edited temporary file");
98 goto err_close_stdout
;
100 while ((bytes
= read(tempfd_r
, buffer
, sizeof(buffer
))) > 0) {
101 if (write(stdout
, buffer
, bytes
) != bytes
) {
102 write2("failed to write data to stdout");
103 goto err_close_tempfile_read
;
109 /* Clean up on error is best efford. Descriptors are closed, files
110 are unlinked, but nothing is checked. */
111 err_close_tempfile_read
: