Home | History | Annotate | Line # | Download | only in ipc
ip_run.c revision 1.2
      1 /*	$NetBSD: ip_run.c,v 1.2 2013/11/22 15:52:05 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));
     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 		if (!pflag && stat("vi-ipc", &sb) == 0)
    147 			execvp("vi-ipc", argv);
    148 		execvp(execp, argv);
    149 		(void)fprintf(stderr,
    150 		    "%s: %s %s\n", vi_progname, execp, strerror(errno));
    151 		(void)fprintf(stderr,
    152 #ifdef DEBUG
    153 	    "usage: %s [-D] [-P vi_program] [-T trace] [vi arguments]\n",
    154 #else
    155 	    "usage: %s [-P vi_program] [vi arguments]\n",
    156 #endif
    157 		    vi_progname);
    158 		_exit (1);
    159 	default:				/* Parent: Screen. */
    160 		(void)close(rpipe[1]);
    161 		(void)close(wpipe[0]);
    162 		break;
    163 	}
    164 	return (0);
    165 }
    166 
    167 /*
    168  * fatal --
    169  *	Fatal error.
    170  */
    171 static void
    172 fatal()
    173 {
    174 	(void)fprintf(stderr, "%s: %s\n", vi_progname, strerror(errno));
    175 	exit (1);
    176 }
    177 
    178 static int
    179 channel(int rpipe[2], int wpipe[2])
    180 {
    181 	int x;
    182 	if ((x = pipe(rpipe) == -1) || pipe(wpipe) == -1) {
    183 		int sockets[2];
    184 
    185 		if (x != -1) {
    186 			close(rpipe[0]);
    187 			close(rpipe[1]);
    188 		}
    189 
    190 		if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sockets) == -1)
    191 			return -1;
    192 
    193 		rpipe[0] = sockets[0];
    194 		wpipe[0] = sockets[1];
    195 		if (((rpipe[1] = dup(sockets[1])) == -1) ||
    196 		    ((wpipe[1] = dup(sockets[0])) == -1)) {
    197 			close(sockets[0]);
    198 			close(sockets[1]);
    199 			if (rpipe[1] != -1)
    200 				close(rpipe[1]);
    201 			return -1;
    202 		}
    203 
    204 	}
    205 	return 0;
    206 }
    207 
    208 /*
    209  * arg_format --
    210  *	Reformat our arguments to add the -I argument for vi.
    211  */
    212 static void
    213 arg_format(char *execp, int *argcp, char **argvp[], int i_fd, int o_fd)
    214 {
    215 	char *iarg, **largv, *p, **p_av, **t_av;
    216 
    217 	/* Get space for the argument array and the -I argument. */
    218 	if ((iarg = malloc(64)) == NULL ||
    219 	    (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL)
    220 		fatal();
    221 	memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1);
    222 
    223 	/* Reset argv[0] to be the exec'd program. */
    224 	if ((p = strrchr(execp, '/')) == NULL)
    225 		largv[0] = execp;
    226 	else
    227 		largv[0] = p + 1;
    228 
    229 	/* Create the -I argument. */
    230 	(void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd);
    231 	largv[1] = iarg;
    232 
    233 	/* Copy any remaining arguments into the array. */
    234 	for (p_av = (*argvp) + 1, t_av = largv + 2;;)
    235 		if ((*t_av++ = *p_av++) == NULL)
    236 			break;
    237 
    238 	/* Reset the argument array. */
    239 	*argvp = largv;
    240 }
    241 
    242 #ifdef DEBUG
    243 /*
    244  * attach --
    245  *	Pause and let the user attach a debugger.
    246  */
    247 static void
    248 attach()
    249 {
    250 	int fd;
    251 	char ch;
    252 
    253 	(void)printf("process %lu waiting, enter <CR> to continue: ",
    254 	    (u_long)getpid());
    255 	(void)fflush(stdout);
    256 
    257 	if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
    258 		(void)fprintf(stderr,
    259 		    "%s: %s, %s\n", vi_progname, _PATH_TTY, strerror(errno));
    260 		exit (1);;
    261 	}
    262 	do {
    263 		if (read(fd, &ch, 1) != 1) {
    264 			(void)close(fd);
    265 			return;
    266 		}
    267 	} while (ch != '\n' && ch != '\r');
    268 	(void)close(fd);
    269 }
    270 #endif
    271