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