Home | History | Annotate | Line # | Download | only in ipc
      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