GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/sdiff/edit.c Lines: 0 88 0.0 %
Date: 2016-12-06 Branches: 0 77 0.0 %

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
	char *argp[] = {"sh", "-c", NULL, NULL}, *ed, *p;
36
	sig_t sighup, sigint, sigquit, sigchld;
37
	pid_t pid;
38
	int saved_errno, st, ret = -1;
39
40
	ed = getenv("VISUAL");
41
	if (ed == NULL || ed[0] == '\0')
42
		ed = getenv("EDITOR");
43
	if (ed == NULL || ed[0] == '\0')
44
		ed = _PATH_VI;
45
	if (asprintf(&p, "%s %s", ed, pathname) == -1)
46
		return (-1);
47
	argp[2] = p;
48
49
	sighup = signal(SIGHUP, SIG_IGN);
50
	sigint = signal(SIGINT, SIG_IGN);
51
	sigquit = signal(SIGQUIT, SIG_IGN);
52
	sigchld = signal(SIGCHLD, SIG_DFL);
53
	if ((pid = fork()) == -1)
54
		goto fail;
55
	if (pid == 0) {
56
		execv(_PATH_BSHELL, argp);
57
		_exit(127);
58
	}
59
	while (waitpid(pid, &st, 0) == -1)
60
		if (errno != EINTR)
61
			goto fail;
62
	if (!WIFEXITED(st))
63
		errno = EINTR;
64
	else
65
		ret = WEXITSTATUS(st);
66
67
 fail:
68
	saved_errno = errno;
69
	(void)signal(SIGHUP, sighup);
70
	(void)signal(SIGINT, sigint);
71
	(void)signal(SIGQUIT, sigquit);
72
	(void)signal(SIGCHLD, sigchld);
73
	free(p);
74
	errno = saved_errno;
75
	return (ret);
76
}
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
	char *filename;
88
	char buf[BUFSIZ], *text;
89
90
	/* Skip whitespace. */
91
	while (isspace((unsigned char)*cmd))
92
		++cmd;
93
94
	text = NULL;
95
	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
		if (left == NULL)
116
			break;
117
118
		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
		if (right == NULL)
127
			break;
128
129
		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
	if (asprintf(&filename, "%s/sdiff.XXXXXXXXXX", tmpdir) == -1)
140
		err(2, "asprintf");
141
	if ((fd = mkstemp(filename)) == -1)
142
		err(2, "mkstemp");
143
	if (text != NULL) {
144
		size_t len;
145
		ssize_t nwritten;
146
147
		len = strlen(text);
148
		if ((nwritten = write(fd, text, len)) == -1 ||
149
		    nwritten != len) {
150
			warn("error writing to temp file");
151
			cleanup(filename);
152
		}
153
	}
154
	close(fd);
155
156
	/* text is no longer used. */
157
	free(text);
158
159
	/* Edit temp file. */
160
	if (editit(filename) == -1) {
161
		warn("error editing %s", filename);
162
		cleanup(filename);
163
	}
164
165
	/* Open temporary file. */
166
	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
	for (nread = sizeof(buf); nread == sizeof(buf);) {
173
		size_t nwritten;
174
175
		nread = fread(buf, sizeof(*buf), sizeof(buf), file);
176
		/* Test for error or end of file. */
177
		if (nread != sizeof(buf) &&
178
		    (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
		if (!nread)
188
			break;
189
190
		/* Write data we just read. */
191
		nwritten = fwrite(buf, sizeof(*buf), nread, outfp);
192
		if (nwritten != nread) {
193
			warnx("error writing to output file");
194
			cleanup(filename);
195
		}
196
	}
197
198
	/* We've reached the end of the temporary file, so remove it. */
199
	if (unlink(filename))
200
		warn("could not delete: %s", filename);
201
	fclose(file);
202
203
	free(filename);
204
205
	return (0);
206
}