ip_run.c revision 1.3 1 /* $NetBSD: ip_run.c,v 1.3 2013/11/22 19:59:36 martin 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));
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 if (!pflag && stat("vi-ipc", &sb) == 0)
147 execvp("vi-ipc", argv);
148 execvp(execp, argv);
149 (void)fprintf(stderr,
150 "%s: %s %s\n", vi_progname, execp, strerror(errno));
151 (void)fprintf(stderr,
152 #ifdef DEBUG
153 "usage: %s [-D] [-P vi_program] [-T trace] [vi arguments]\n",
154 #else
155 "usage: %s [-P vi_program] [vi arguments]\n",
156 #endif
157 vi_progname);
158 _exit (1);
159 default: /* Parent: Screen. */
160 (void)close(rpipe[1]);
161 (void)close(wpipe[0]);
162 break;
163 }
164 return (0);
165 }
166
167 /*
168 * fatal --
169 * Fatal error.
170 */
171 static void
172 fatal()
173 {
174 (void)fprintf(stderr, "%s: %s\n", vi_progname, strerror(errno));
175 exit (1);
176 }
177
178 static int
179 channel(int rpipe[2], int wpipe[2])
180 {
181 int x;
182 if ((x = pipe(rpipe) == -1) || pipe(wpipe) == -1) {
183 int sockets[2];
184
185 if (x != -1) {
186 close(rpipe[0]);
187 close(rpipe[1]);
188 }
189
190 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) == -1)
191 return -1;
192
193 rpipe[0] = sockets[0];
194 wpipe[0] = sockets[1];
195 if (((rpipe[1] = dup(sockets[1])) == -1) ||
196 ((wpipe[1] = dup(sockets[0])) == -1)) {
197 close(sockets[0]);
198 close(sockets[1]);
199 if (rpipe[1] != -1)
200 close(rpipe[1]);
201 return -1;
202 }
203
204 }
205 return 0;
206 }
207
208 /*
209 * arg_format --
210 * Reformat our arguments to add the -I argument for vi.
211 */
212 static void
213 arg_format(char *execp, int *argcp, char **argvp[], int i_fd, int o_fd)
214 {
215 char *iarg, **largv = NULL /* XXX gcc */, *p, **p_av, **t_av;
216
217 /* Get space for the argument array and the -I argument. */
218 if ((iarg = malloc(64)) == NULL ||
219 (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL)
220 fatal();
221 memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1);
222
223 /* Reset argv[0] to be the exec'd program. */
224 if ((p = strrchr(execp, '/')) == NULL)
225 largv[0] = execp;
226 else
227 largv[0] = p + 1;
228
229 /* Create the -I argument. */
230 (void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd);
231 largv[1] = iarg;
232
233 /* Copy any remaining arguments into the array. */
234 for (p_av = (*argvp) + 1, t_av = largv + 2;;)
235 if ((*t_av++ = *p_av++) == NULL)
236 break;
237
238 /* Reset the argument array. */
239 *argvp = largv;
240 }
241
242 #ifdef DEBUG
243 /*
244 * attach --
245 * Pause and let the user attach a debugger.
246 */
247 static void
248 attach()
249 {
250 int fd;
251 char ch;
252
253 (void)printf("process %lu waiting, enter <CR> to continue: ",
254 (u_long)getpid());
255 (void)fflush(stdout);
256
257 if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
258 (void)fprintf(stderr,
259 "%s: %s, %s\n", vi_progname, _PATH_TTY, strerror(errno));
260 exit (1);;
261 }
262 do {
263 if (read(fd, &ch, 1) != 1) {
264 (void)close(fd);
265 return;
266 }
267 } while (ch != '\n' && ch != '\r');
268 (void)close(fd);
269 }
270 #endif
271