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