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