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