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