xref: /minix/external/bsd/nvi/dist/ipc/ip_run.c (revision 0a6a1f1d)
1 /*	$NetBSD: ip_run.c,v 1.7 2014/01/26 21:43:45 christos Exp $	*/
2 /*-
3  * Copyright (c) 1996
4  *	Rob Zimmermann.  All rights reserved.
5  * Copyright (c) 1996
6  *	Keith Bostic.  All rights reserved.
7  *
8  * See the LICENSE file for redistribution information.
9  */
10 
11 #include "config.h"
12 
13 #include <sys/cdefs.h>
14 #if 0
15 #ifndef lint
16 static const char sccsid[] = "Id: ip_run.c,v 8.17 2000/07/04 21:48:54 skimo Exp  (Berkeley) Date: 2000/07/04 21:48:54 ";
17 #endif /* not lint */
18 #else
19 __RCSID("$NetBSD: ip_run.c,v 1.7 2014/01/26 21:43:45 christos Exp $");
20 #endif
21 
22 #include <sys/types.h>
23 #include <sys/queue.h>
24 #include <sys/stat.h>
25 
26 #include <bitstring.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include <sys/socket.h>
35 
36 #include "../common/common.h"
37 #include "ip.h"
38 #include "pathnames.h"
39 
40 static void arg_format __P((char *, int *, char **[], int, int));
41 static void fatal __P((void)) __dead;
42 #ifdef DEBUG
43 static void attach __P((void));
44 #endif
45 static int channel(int rpipe[2], int wpipe[2]);
46 
47 const char	*vi_progname = "vi";		/* Global: program name. */
48 
49 /*
50  * vi_run --
51  *	Run the vi program.
52  *
53  * PUBLIC: int vi_run __P((IPVI *, int, char *[]));
54  */
55 int
vi_run(ipvi,argc,argv)56 vi_run(ipvi, argc, argv)
57 	IPVI *ipvi;
58 	int argc;
59 	char *argv[];
60 {
61 	struct stat sb;
62 	int pflag, rpipe[2], wpipe[2];
63 	char *execp, **p_av, **t_av;
64 
65 	pflag = 0;
66 	execp = __UNCONST(vi_progname);
67 
68 	/* Strip out any arguments that vi isn't going to understand. */
69 	for (p_av = t_av = argv;;) {
70 		if (*t_av == NULL) {
71 			*p_av = NULL;
72 			break;
73 		}
74 		if (!strcmp(*t_av, "--")) {
75 			while ((*p_av++ = *++t_av) != NULL);
76 			break;
77 		}
78 #ifdef DEBUG
79 		if (!memcmp(*t_av, "-D", sizeof("-D") - 1)) {
80 			attach();
81 
82 			++t_av;
83 			--argc;
84 			continue;
85 		}
86 #endif
87 #ifdef TRACE
88 		if (!memcmp(*t_av, "-T", sizeof("-T") - 1)) {
89 			char *p = &t_av[0][sizeof("-T") - 1];
90 			if (*p == '\0') {
91 				--argc;
92 				p = *++t_av;
93 			}
94 			vtrace_init(p);
95 			++t_av;
96 			--argc;
97 			continue;
98 		}
99 #endif
100 		if (!memcmp(*t_av, "-P", sizeof("-P") - 1)) {
101 			if (t_av[0][2] != '\0') {
102 				pflag = 1;
103 				execp = t_av[0] + 2;
104 				++t_av;
105 				--argc;
106 				continue;
107 			}
108 			if (t_av[1] != NULL) {
109 				pflag = 1;
110 				execp = t_av[1];
111 				t_av += 2;
112 				argc -= 2;
113 				continue;
114 			}
115 		}
116 		*p_av++ = *t_av++;
117 	}
118 
119 	/*
120 	 * Open the communications channels.  The pipes are named from the
121 	 * parent's viewpoint, meaning the screen reads from rpipe[0] and
122 	 * writes to wpipe[1].  The vi process reads from wpipe[0], and it
123 	 * writes to rpipe[1].
124 	 */
125 	if (channel(rpipe, wpipe) == -1)
126 		fatal();
127 	ipvi->ifd = rpipe[0];
128 	ipvi->ofd = wpipe[1];
129 
130 	/*
131 	 * Reformat our arguments, adding a -I to the list.  The first file
132 	 * descriptor for the -I argument is vi's input, and the second is
133 	 * vi's output.
134 	 */
135 	arg_format(execp, &argc, &argv, wpipe[0], rpipe[1]);
136 
137 	/* Run vi. */
138 	switch (ipvi->pid = fork()) {
139 	case -1:				/* Error. */
140 		fatal();
141 		/* NOTREACHED */
142 	case 0:					/* Child: Vi. */
143 		(void)close(rpipe[0]);
144 		(void)close(wpipe[1]);
145 
146 		/*
147 		 * If the user didn't override the path and there's a local
148 		 * (debugging) nvi, run it, otherwise run the user's path,
149 		 * if specified, else run the compiled in path.
150 		 */
151 		/* coverity[+toctou] */
152 		if (!pflag && stat("vi-ipc", &sb) == 0)
153 			execvp("vi-ipc", argv);
154 		execvp(execp, argv);
155 		(void)fprintf(stderr,
156 		    "%s: %s %s\n", vi_progname, execp, strerror(errno));
157 		(void)fprintf(stderr,
158 #ifdef DEBUG
159 	    "usage: %s [-D] [-P vi_program] [-T trace] [vi arguments]\n",
160 #else
161 	    "usage: %s [-P vi_program] [vi arguments]\n",
162 #endif
163 		    vi_progname);
164 		_exit (1);
165 	default:				/* Parent: Screen. */
166 		(void)close(rpipe[1]);
167 		(void)close(wpipe[0]);
168 		break;
169 	}
170 	free(argv[1]);
171 	free(argv);
172 	return (0);
173 }
174 
175 /*
176  * fatal --
177  *	Fatal error.
178  */
179 static void
fatal()180 fatal()
181 {
182 	(void)fprintf(stderr, "%s: %s\n", vi_progname, strerror(errno));
183 	exit (1);
184 }
185 
186 static int
channel(int rpipe[2],int wpipe[2])187 channel(int rpipe[2], int wpipe[2])
188 {
189 	int x;
190 	if ((x = pipe(rpipe) == -1) || pipe(wpipe) == -1) {
191 		int sockets[2];
192 
193 		if (x != -1) {
194 			close(rpipe[0]);
195 			close(rpipe[1]);
196 		}
197 
198 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) == -1)
199 			return -1;
200 
201 		rpipe[0] = sockets[0];
202 		wpipe[0] = sockets[1];
203 		if (((rpipe[1] = dup(sockets[1])) == -1) ||
204 		    ((wpipe[1] = dup(sockets[0])) == -1)) {
205 			close(sockets[0]);
206 			close(sockets[1]);
207 			if (rpipe[1] != -1)
208 				close(rpipe[1]);
209 			return -1;
210 		}
211 
212 	}
213 	return 0;
214 }
215 
216 /*
217  * arg_format --
218  *	Reformat our arguments to add the -I argument for vi.
219  */
220 static void
arg_format(char * execp,int * argcp,char ** argvp[],int i_fd,int o_fd)221 arg_format(char *execp, int *argcp, char **argvp[], int i_fd, int o_fd)
222 {
223 	char *iarg, **largv = NULL /* XXX gcc */, *p, **p_av, **t_av;
224 
225 	/* Get space for the argument array and the -I argument. */
226 	if ((iarg = malloc(64)) == NULL ||
227 	    (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL)
228 		fatal();
229 	memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1);
230 
231 	/* Reset argv[0] to be the exec'd program. */
232 	if ((p = strrchr(execp, '/')) == NULL)
233 		largv[0] = execp;
234 	else
235 		largv[0] = p + 1;
236 
237 	/* Create the -I argument. */
238 	(void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd);
239 	largv[1] = iarg;
240 
241 	/* Copy any remaining arguments into the array. */
242 	for (p_av = (*argvp) + 1, t_av = largv + 2;;)
243 		if ((*t_av++ = *p_av++) == NULL)
244 			break;
245 
246 	/* Reset the argument array. */
247 	*argvp = largv;
248 }
249 
250 #ifdef DEBUG
251 /*
252  * attach --
253  *	Pause and let the user attach a debugger.
254  */
255 static void
attach()256 attach()
257 {
258 	int fd;
259 	char ch;
260 
261 	(void)printf("process %lu waiting, enter <CR> to continue: ",
262 	    (u_long)getpid());
263 	(void)fflush(stdout);
264 
265 	if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
266 		(void)fprintf(stderr,
267 		    "%s: %s, %s\n", vi_progname, _PATH_TTY, strerror(errno));
268 		exit (1);;
269 	}
270 	do {
271 		if (read(fd, &ch, 1) != 1) {
272 			(void)close(fd);
273 			return;
274 		}
275 	} while (ch != '\n' && ch != '\r');
276 	(void)close(fd);
277 }
278 #endif
279