GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../ex/ex_shell.c Lines: 0 64 0.0 %
Date: 2017-11-07 Branches: 0 65 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: ex_shell.c,v 1.15 2015/03/28 12:54:37 bcallah Exp $	*/
2
3
/*-
4
 * Copyright (c) 1992, 1993, 1994
5
 *	The Regents of the University of California.  All rights reserved.
6
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7
 *	Keith Bostic.  All rights reserved.
8
 *
9
 * See the LICENSE file for redistribution information.
10
 */
11
12
#include "config.h"
13
14
#include <sys/queue.h>
15
#include <sys/wait.h>
16
17
#include <bitstring.h>
18
#include <ctype.h>
19
#include <errno.h>
20
#include <limits.h>
21
#include <signal.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24
#include <string.h>
25
#include <unistd.h>
26
27
#include "../common/common.h"
28
29
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
30
31
/*
32
 * ex_shell -- :sh[ell]
33
 *	Invoke the program named in the SHELL environment variable
34
 *	with the argument -i.
35
 *
36
 * PUBLIC: int ex_shell(SCR *, EXCMD *);
37
 */
38
int
39
ex_shell(SCR *sp, EXCMD *cmdp)
40
{
41
	int rval;
42
	char buf[PATH_MAX];
43
44
	/* We'll need a shell. */
45
	if (opts_empty(sp, O_SHELL, 0))
46
		return (1);
47
48
	/*
49
	 * XXX
50
	 * Assumes all shells use -i.
51
	 */
52
	(void)snprintf(buf, sizeof(buf), "%s -i", O_STR(sp, O_SHELL));
53
54
	/* Restore the window name. */
55
	(void)sp->gp->scr_rename(sp, NULL, 0);
56
57
	/* If we're still in a vi screen, move out explicitly. */
58
	rval = ex_exec_proc(sp, cmdp, buf, NULL, !F_ISSET(sp, SC_SCR_EXWROTE));
59
60
	/* Set the window name. */
61
	(void)sp->gp->scr_rename(sp, sp->frp->name, 1);
62
63
	/*
64
	 * !!!
65
	 * Historically, vi didn't require a continue message after the
66
	 * return of the shell.  Match it.
67
	 */
68
	F_SET(sp, SC_EX_WAIT_NO);
69
70
	return (rval);
71
}
72
73
/*
74
 * ex_exec_proc --
75
 *	Run a separate process.
76
 *
77
 * PUBLIC: int ex_exec_proc(SCR *, EXCMD *, char *, const char *, int);
78
 */
79
int
80
ex_exec_proc(SCR *sp, EXCMD *cmdp, char *cmd, const char *msg,
81
    int need_newline)
82
{
83
	GS *gp;
84
	const char *name;
85
	pid_t pid;
86
87
	gp = sp->gp;
88
89
	/* We'll need a shell. */
90
	if (opts_empty(sp, O_SHELL, 0))
91
		return (1);
92
93
	/* Enter ex mode. */
94
	if (F_ISSET(sp, SC_VI)) {
95
		if (gp->scr_screen(sp, SC_EX)) {
96
			ex_emsg(sp, cmdp->cmd->name, EXM_NOCANON);
97
			return (1);
98
		}
99
		(void)gp->scr_attr(sp, SA_ALTERNATE, 0);
100
		F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
101
	}
102
103
	/* Put out additional newline, message. */
104
	if (need_newline)
105
		(void)ex_puts(sp, "\n");
106
	if (msg != NULL) {
107
		(void)ex_puts(sp, msg);
108
		(void)ex_puts(sp, "\n");
109
	}
110
	(void)ex_fflush(sp);
111
112
	switch (pid = vfork()) {
113
	case -1:			/* Error. */
114
		msgq(sp, M_SYSERR, "vfork");
115
		return (1);
116
	case 0:				/* Utility. */
117
		if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
118
			name = O_STR(sp, O_SHELL);
119
		else
120
			++name;
121
		execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL);
122
		msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
123
		_exit(127);
124
		/* NOTREACHED */
125
	default:			/* Parent. */
126
		return (proc_wait(sp, pid, cmd, 0, 0));
127
	}
128
	/* NOTREACHED */
129
}
130
131
/*
132
 * proc_wait --
133
 *	Wait for one of the processes.
134
 *
135
 * !!!
136
 * The pid_t type varies in size from a short to a long depending on the
137
 * system.  It has to be cast into something or the standard promotion
138
 * rules get you.  I'm using a long based on the belief that nobody is
139
 * going to make it unsigned and it's unlikely to be a quad.
140
 *
141
 * PUBLIC: int proc_wait(SCR *, pid_t, const char *, int, int);
142
 */
143
int
144
proc_wait(SCR *sp, pid_t pid, const char *cmd, int silent, int okpipe)
145
{
146
	size_t len;
147
	int nf, pstat;
148
	char *p;
149
150
	/* Wait for the utility, ignoring interruptions. */
151
	for (;;) {
152
		errno = 0;
153
		if (waitpid(pid, &pstat, 0) != -1)
154
			break;
155
		if (errno != EINTR) {
156
			msgq(sp, M_SYSERR, "waitpid");
157
			return (1);
158
		}
159
	}
160
161
	/*
162
	 * Display the utility's exit status.  Ignore SIGPIPE from the
163
	 * parent-writer, as that only means that the utility chose to
164
	 * exit before reading all of its input.
165
	 */
166
	if (WIFSIGNALED(pstat) && (!okpipe || WTERMSIG(pstat) != SIGPIPE)) {
167
		for (; isblank(*cmd); ++cmd);
168
		p = msg_print(sp, cmd, &nf);
169
		len = strlen(p);
170
		msgq(sp, M_ERR, "%.*s%s: received signal: %s%s",
171
		    MINIMUM(len, 20), p, len > 20 ? " ..." : "",
172
		    strsignal(WTERMSIG(pstat)),
173
		    WCOREDUMP(pstat) ? "; core dumped" : "");
174
		if (nf)
175
			FREE_SPACE(sp, p, 0);
176
		return (1);
177
	}
178
179
	if (WIFEXITED(pstat) && WEXITSTATUS(pstat)) {
180
		/*
181
		 * Remain silent for "normal" errors when doing shell file
182
		 * name expansions, they almost certainly indicate nothing
183
		 * more than a failure to match.
184
		 *
185
		 * Remain silent for vi read filter errors.  It's historic
186
		 * practice.
187
		 */
188
		if (!silent) {
189
			for (; isblank(*cmd); ++cmd);
190
			p = msg_print(sp, cmd, &nf);
191
			len = strlen(p);
192
			msgq(sp, M_ERR, "%.*s%s: exited with status %d",
193
			    MINIMUM(len, 20), p, len > 20 ? " ..." : "",
194
			    WEXITSTATUS(pstat));
195
			if (nf)
196
				FREE_SPACE(sp, p, 0);
197
		}
198
		return (1);
199
	}
200
	return (0);
201
}