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