/* $NetBSD: ip_run.c,v 1.7 2014/01/26 21:43:45 christos Exp $ */ /*- * Copyright (c) 1996 * Rob Zimmermann. All rights reserved. * Copyright (c) 1996 * Keith Bostic. All rights reserved. * * See the LICENSE file for redistribution information. */ #include "config.h" #include <sys/cdefs.h> #if 0 #ifndef lint 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 "; #endif /* not lint */ #else __RCSID("$NetBSD: ip_run.c,v 1.7 2014/01/26 21:43:45 christos Exp $"); #endif #include <sys/types.h> #include <sys/queue.h> #include <sys/stat.h> #include <bitstring.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include "../common/common.h" #include "ip.h" #include "pathnames.h" static void arg_format __P((char *, int *, char **[], int, int)); static void fatal __P((void)) __dead; #ifdef DEBUG static void attach __P((void)); #endif static int channel(int rpipe[2], int wpipe[2]); const char *vi_progname = "vi"; /* Global: program name. */ /* * vi_run -- * Run the vi program. * * PUBLIC: int vi_run __P((IPVI *, int, char *[])); */ int vi_run(ipvi, argc, argv) IPVI *ipvi; int argc; char *argv[]; { struct stat sb; int pflag, rpipe[2], wpipe[2]; char *execp, **p_av, **t_av; pflag = 0; execp = __UNCONST(vi_progname); /* Strip out any arguments that vi isn't going to understand. */ for (p_av = t_av = argv;;) { if (*t_av == NULL) { *p_av = NULL; break; } if (!strcmp(*t_av, "--")) { while ((*p_av++ = *++t_av) != NULL); break; } #ifdef DEBUG if (!memcmp(*t_av, "-D", sizeof("-D") - 1)) { attach(); ++t_av; --argc; continue; } #endif #ifdef TRACE if (!memcmp(*t_av, "-T", sizeof("-T") - 1)) { char *p = &t_av[0][sizeof("-T") - 1]; if (*p == '\0') { --argc; p = *++t_av; } vtrace_init(p); ++t_av; --argc; continue; } #endif if (!memcmp(*t_av, "-P", sizeof("-P") - 1)) { if (t_av[0][2] != '\0') { pflag = 1; execp = t_av[0] + 2; ++t_av; --argc; continue; } if (t_av[1] != NULL) { pflag = 1; execp = t_av[1]; t_av += 2; argc -= 2; continue; } } *p_av++ = *t_av++; } /* * Open the communications channels. The pipes are named from the * parent's viewpoint, meaning the screen reads from rpipe[0] and * writes to wpipe[1]. The vi process reads from wpipe[0], and it * writes to rpipe[1]. */ if (channel(rpipe, wpipe) == -1) fatal(); ipvi->ifd = rpipe[0]; ipvi->ofd = wpipe[1]; /* * Reformat our arguments, adding a -I to the list. The first file * descriptor for the -I argument is vi's input, and the second is * vi's output. */ arg_format(execp, &argc, &argv, wpipe[0], rpipe[1]); /* Run vi. */ switch (ipvi->pid = fork()) { case -1: /* Error. */ fatal(); /* NOTREACHED */ case 0: /* Child: Vi. */ (void)close(rpipe[0]); (void)close(wpipe[1]); /* * If the user didn't override the path and there's a local * (debugging) nvi, run it, otherwise run the user's path, * if specified, else run the compiled in path. */ /* coverity[+toctou] */ if (!pflag && stat("vi-ipc", &sb) == 0) execvp("vi-ipc", argv); execvp(execp, argv); (void)fprintf(stderr, "%s: %s %s\n", vi_progname, execp, strerror(errno)); (void)fprintf(stderr, #ifdef DEBUG "usage: %s [-D] [-P vi_program] [-T trace] [vi arguments]\n", #else "usage: %s [-P vi_program] [vi arguments]\n", #endif vi_progname); _exit (1); default: /* Parent: Screen. */ (void)close(rpipe[1]); (void)close(wpipe[0]); break; } free(argv[1]); free(argv); return (0); } /* * fatal -- * Fatal error. */ static void fatal() { (void)fprintf(stderr, "%s: %s\n", vi_progname, strerror(errno)); exit (1); } static int channel(int rpipe[2], int wpipe[2]) { int x; if ((x = pipe(rpipe) == -1) || pipe(wpipe) == -1) { int sockets[2]; if (x != -1) { close(rpipe[0]); close(rpipe[1]); } if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) == -1) return -1; rpipe[0] = sockets[0]; wpipe[0] = sockets[1]; if (((rpipe[1] = dup(sockets[1])) == -1) || ((wpipe[1] = dup(sockets[0])) == -1)) { close(sockets[0]); close(sockets[1]); if (rpipe[1] != -1) close(rpipe[1]); return -1; } } return 0; } /* * arg_format -- * Reformat our arguments to add the -I argument for vi. */ static void arg_format(char *execp, int *argcp, char **argvp[], int i_fd, int o_fd) { char *iarg, **largv = NULL /* XXX gcc */, *p, **p_av, **t_av; /* Get space for the argument array and the -I argument. */ if ((iarg = malloc(64)) == NULL || (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL) fatal(); memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1); /* Reset argv[0] to be the exec'd program. */ if ((p = strrchr(execp, '/')) == NULL) largv[0] = execp; else largv[0] = p + 1; /* Create the -I argument. */ (void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd); largv[1] = iarg; /* Copy any remaining arguments into the array. */ for (p_av = (*argvp) + 1, t_av = largv + 2;;) if ((*t_av++ = *p_av++) == NULL) break; /* Reset the argument array. */ *argvp = largv; } #ifdef DEBUG /* * attach -- * Pause and let the user attach a debugger. */ static void attach() { int fd; char ch; (void)printf("process %lu waiting, enter <CR> to continue: ", (u_long)getpid()); (void)fflush(stdout); if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) { (void)fprintf(stderr, "%s: %s, %s\n", vi_progname, _PATH_TTY, strerror(errno)); exit (1);; } do { if (read(fd, &ch, 1) != 1) { (void)close(fd); return; } } while (ch != '\n' && ch != '\r'); (void)close(fd); } #endif