GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/sdiff/edit.c Lines: 59 87 67.8 %
Date: 2017-11-13 Branches: 40 79 50.6 %

Line Branch Exec Source
1
/*	$OpenBSD: edit.c,v 1.20 2013/11/26 21:08:12 deraadt Exp $ */
2
3
/*
4
 * Written by Raymond Lai <ray@cyth.net>.
5
 * Public domain.
6
 */
7
8
#include <sys/types.h>
9
#include <sys/wait.h>
10
11
#include <ctype.h>
12
#include <err.h>
13
#include <errno.h>
14
#include <paths.h>
15
#include <signal.h>
16
#include <stdio.h>
17
#include <stdlib.h>
18
#include <string.h>
19
#include <unistd.h>
20
21
#include "common.h"
22
#include "extern.h"
23
24
int editit(const char *);
25
26
/*
27
 * Execute an editor on the specified pathname, which is interpreted
28
 * from the shell.  This means flags may be included.
29
 *
30
 * Returns -1 on error, or the exit value on success.
31
 */
32
int
33
editit(const char *pathname)
34
{
35
48
	char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p;
36
	sig_t sighup, sigint, sigquit, sigchld;
37
	pid_t pid;
38
24
	int saved_errno, st, ret = -1;
39
40
24
	ed = getenv("VISUAL");
41

48
	if (ed == NULL || ed[0] == '\0')
42
		ed = getenv("EDITOR");
43

48
	if (ed == NULL || ed[0] == '\0')
44
		ed = _PATH_VI;
45
24
	if (asprintf(&p, "%s %s", ed, pathname) == -1)
46
		return (-1);
47
24
	argp[2] = p;
48
49
24
	sighup = signal(SIGHUP, SIG_IGN);
50
24
	sigint = signal(SIGINT, SIG_IGN);
51
24
	sigquit = signal(SIGQUIT, SIG_IGN);
52
24
	sigchld = signal(SIGCHLD, SIG_DFL);
53
24
	if ((pid = fork()) == -1)
54
		goto fail;
55
24
	if (pid == 0) {
56
		execv(_PATH_BSHELL, argp);
57
		_exit(127);
58
	}
59
48
	while (waitpid(pid, &st, 0) == -1)
60
		if (errno != EINTR)
61
			goto fail;
62
24
	if (!WIFEXITED(st))
63
		errno = EINTR;
64
	else
65
24
		ret = WEXITSTATUS(st);
66
67
 fail:
68
24
	saved_errno = errno;
69
24
	(void)signal(SIGHUP, sighup);
70
24
	(void)signal(SIGINT, sigint);
71
24
	(void)signal(SIGQUIT, sigquit);
72
24
	(void)signal(SIGCHLD, sigchld);
73
24
	free(p);
74
24
	errno = saved_errno;
75
24
	return (ret);
76
24
}
77
78
/*
79
 * Parse edit command.  Returns 0 on success, -1 on error.
80
 */
81
int
82
eparse(const char *cmd, const char *left, const char *right)
83
{
84
	FILE *file;
85
	size_t nread;
86
	int fd;
87
48
	char *filename;
88
24
	char buf[BUFSIZ], *text;
89
90
	/* Skip whitespace. */
91
48
	while (isspace((unsigned char)*cmd))
92
		++cmd;
93
94
48
	text = NULL;
95

48
	switch (*cmd) {
96
	case '\0':
97
		/* Edit empty file. */
98
		break;
99
100
	case 'b':
101
		/* Both strings. */
102
		if (left == NULL)
103
			goto RIGHT;
104
		if (right == NULL)
105
			goto LEFT;
106
107
		/* Neither column is blank, so print both. */
108
		if (asprintf(&text, "%s\n%s\n", left, right) == -1)
109
			err(2, "could not allocate memory");
110
		break;
111
112
	case 'l':
113
LEFT:
114
		/* Skip if there is no left column. */
115
12
		if (left == NULL)
116
			break;
117
118
8
		if (asprintf(&text, "%s\n", left) == -1)
119
			err(2, "could not allocate memory");
120
121
		break;
122
123
	case 'r':
124
RIGHT:
125
		/* Skip if there is no right column. */
126
12
		if (right == NULL)
127
			break;
128
129
8
		if (asprintf(&text, "%s\n", right) == -1)
130
			err(2, "could not allocate memory");
131
132
		break;
133
134
	default:
135
		return (-1);
136
	}
137
138
	/* Create temp file. */
139
24
	if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
140
		err(2, "asprintf");
141
24
	if ((fd = mkstemp(filename)) == -1)
142
		err(2, "mkstemp");
143
24
	if (text != NULL) {
144
		size_t len;
145
		ssize_t nwritten;
146
147
16
		len = strlen(text);
148

32
		if ((nwritten = write(fd, text, len)) == -1 ||
149
16
		    nwritten != len) {
150
			warn("error writing to temp file");
151
			cleanup(filename);
152
		}
153
16
	}
154
24
	close(fd);
155
156
	/* text is no longer used. */
157
24
	free(text);
158
159
	/* Edit temp file. */
160
24
	if (editit(filename) == -1) {
161
		warn("error editing %s", filename);
162
		cleanup(filename);
163
	}
164
165
	/* Open temporary file. */
166
24
	if (!(file = fopen(filename, "r"))) {
167
		warn("could not open edited file: %s", filename);
168
		cleanup(filename);
169
	}
170
171
	/* Copy temporary file contents to output file. */
172
80
	for (nread = sizeof(buf); nread == sizeof(buf);) {
173
		size_t nwritten;
174
175
24
		nread = fread(buf, sizeof(*buf), sizeof(buf), file);
176
		/* Test for error or end of file. */
177

48
		if (nread != sizeof(buf) &&
178


96
		    (ferror(file) || !feof(file))) {
179
			warnx("error reading edited file: %s", filename);
180
			cleanup(filename);
181
		}
182
183
		/*
184
		 * If we have nothing to read, break out of loop
185
		 * instead of writing nothing.
186
		 */
187
24
		if (!nread)
188
8
			break;
189
190
		/* Write data we just read. */
191
16
		nwritten = fwrite(buf, sizeof(*buf), nread, outfp);
192
16
		if (nwritten != nread) {
193
			warnx("error writing to output file");
194
			cleanup(filename);
195
		}
196
16
	}
197
198
	/* We've reached the end of the temporary file, so remove it. */
199
24
	if (unlink(filename))
200
		warn("could not delete: %s", filename);
201
24
	fclose(file);
202
203
24
	free(filename);
204
205
24
	return (0);
206
24
}