xref: /openbsd/usr.bin/vi/ex/ex_argv.c (revision cca36db2)
1 /*	$OpenBSD: ex_argv.c,v 1.13 2009/10/27 23:59:47 deraadt Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  * Copyright (c) 1993, 1994, 1995, 1996
7  *	Keith Bostic.  All rights reserved.
8  *
9  * See the LICENSE file for redistribution information.
10  */
11 
12 #include "config.h"
13 
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 
17 #include <bitstring.h>
18 #include <ctype.h>
19 #include <dirent.h>
20 #include <errno.h>
21 #include <limits.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "../common/common.h"
28 
29 static int argv_alloc(SCR *, size_t);
30 static int argv_comp(const void *, const void *);
31 static int argv_fexp(SCR *, EXCMD *,
32 	char *, size_t, char *, size_t *, char **, size_t *, int);
33 static int argv_lexp(SCR *, EXCMD *, char *);
34 static int argv_sexp(SCR *, char **, size_t *, size_t *);
35 
36 /*
37  * argv_init --
38  *	Build  a prototype arguments list.
39  *
40  * PUBLIC: int argv_init(SCR *, EXCMD *);
41  */
42 int
43 argv_init(sp, excp)
44 	SCR *sp;
45 	EXCMD *excp;
46 {
47 	EX_PRIVATE *exp;
48 
49 	exp = EXP(sp);
50 	exp->argsoff = 0;
51 	argv_alloc(sp, 1);
52 
53 	excp->argv = exp->args;
54 	excp->argc = exp->argsoff;
55 	return (0);
56 }
57 
58 /*
59  * argv_exp0 --
60  *	Append a string to the argument list.
61  *
62  * PUBLIC: int argv_exp0(SCR *, EXCMD *, char *, size_t);
63  */
64 int
65 argv_exp0(sp, excp, cmd, cmdlen)
66 	SCR *sp;
67 	EXCMD *excp;
68 	char *cmd;
69 	size_t cmdlen;
70 {
71 	EX_PRIVATE *exp;
72 
73 	exp = EXP(sp);
74 	argv_alloc(sp, cmdlen);
75 	memcpy(exp->args[exp->argsoff]->bp, cmd, cmdlen);
76 	exp->args[exp->argsoff]->bp[cmdlen] = '\0';
77 	exp->args[exp->argsoff]->len = cmdlen;
78 	++exp->argsoff;
79 	excp->argv = exp->args;
80 	excp->argc = exp->argsoff;
81 	return (0);
82 }
83 
84 /*
85  * argv_exp1 --
86  *	Do file name expansion on a string, and append it to the
87  *	argument list.
88  *
89  * PUBLIC: int argv_exp1(SCR *, EXCMD *, char *, size_t, int);
90  */
91 int
92 argv_exp1(sp, excp, cmd, cmdlen, is_bang)
93 	SCR *sp;
94 	EXCMD *excp;
95 	char *cmd;
96 	size_t cmdlen;
97 	int is_bang;
98 {
99 	size_t blen, len;
100 	char *bp, *p, *t;
101 
102 	GET_SPACE_RET(sp, bp, blen, 512);
103 
104 	len = 0;
105 	if (argv_fexp(sp, excp, cmd, cmdlen, bp, &len, &bp, &blen, is_bang)) {
106 		FREE_SPACE(sp, bp, blen);
107 		return (1);
108 	}
109 
110 	/* If it's empty, we're done. */
111 	if (len != 0) {
112 		for (p = bp, t = bp + len; p < t; ++p)
113 			if (!isblank(*p))
114 				break;
115 		if (p == t)
116 			goto ret;
117 	} else
118 		goto ret;
119 
120 	(void)argv_exp0(sp, excp, bp, len);
121 
122 ret:	FREE_SPACE(sp, bp, blen);
123 	return (0);
124 }
125 
126 /*
127  * argv_exp2 --
128  *	Do file name and shell expansion on a string, and append it to
129  *	the argument list.
130  *
131  * PUBLIC: int argv_exp2(SCR *, EXCMD *, char *, size_t);
132  */
133 int
134 argv_exp2(sp, excp, cmd, cmdlen)
135 	SCR *sp;
136 	EXCMD *excp;
137 	char *cmd;
138 	size_t cmdlen;
139 {
140 	size_t blen, len, n;
141 	int rval;
142 	char *bp, *mp, *p;
143 
144 	GET_SPACE_RET(sp, bp, blen, 512);
145 
146 #define	SHELLECHO	"echo "
147 #define	SHELLOFFSET	(sizeof(SHELLECHO) - 1)
148 	memcpy(bp, SHELLECHO, SHELLOFFSET);
149 	p = bp + SHELLOFFSET;
150 	len = SHELLOFFSET;
151 
152 #if defined(DEBUG) && 0
153 	TRACE(sp, "file_argv: {%.*s}\n", (int)cmdlen, cmd);
154 #endif
155 
156 	if (argv_fexp(sp, excp, cmd, cmdlen, p, &len, &bp, &blen, 0)) {
157 		rval = 1;
158 		goto err;
159 	}
160 
161 #if defined(DEBUG) && 0
162 	TRACE(sp, "before shell: %d: {%s}\n", len, bp);
163 #endif
164 
165 	/*
166 	 * Do shell word expansion -- it's very, very hard to figure out what
167 	 * magic characters the user's shell expects.  Historically, it was a
168 	 * union of v7 shell and csh meta characters.  We match that practice
169 	 * by default, so ":read \%" tries to read a file named '%'.  It would
170 	 * make more sense to pass any special characters through the shell,
171 	 * but then, if your shell was csh, the above example will behave
172 	 * differently in nvi than in vi.  If you want to get other characters
173 	 * passed through to your shell, change the "meta" option.
174 	 *
175 	 * To avoid a function call per character, we do a first pass through
176 	 * the meta characters looking for characters that aren't expected
177 	 * to be there, and then we can ignore them in the user's argument.
178 	 */
179 	if (opts_empty(sp, O_SHELL, 1) || opts_empty(sp, O_SHELLMETA, 1))
180 		n = 0;
181 	else {
182 		for (p = mp = O_STR(sp, O_SHELLMETA); *p != '\0'; ++p)
183 			if (isblank(*p) || isalnum(*p))
184 				break;
185 		p = bp + SHELLOFFSET;
186 		n = len - SHELLOFFSET;
187 		if (*p != '\0') {
188 			for (; n > 0; --n, ++p)
189 				if (strchr(mp, *p) != NULL)
190 					break;
191 		} else
192 			for (; n > 0; --n, ++p)
193 				if (!isblank(*p) &&
194 				    !isalnum(*p) && strchr(mp, *p) != NULL)
195 					break;
196 	}
197 
198 	/*
199 	 * If we found a meta character in the string, fork a shell to expand
200 	 * it.  Unfortunately, this is comparatively slow.  Historically, it
201 	 * didn't matter much, since users don't enter meta characters as part
202 	 * of pathnames that frequently.  The addition of filename completion
203 	 * broke that assumption because it's easy to use.  As a result, lots
204 	 * folks have complained that the expansion code is too slow.  So, we
205 	 * detect filename completion as a special case, and do it internally.
206 	 * Note that this code assumes that the <asterisk> character is the
207 	 * match-anything meta character.  That feels safe -- if anyone writes
208 	 * a shell that doesn't follow that convention, I'd suggest giving them
209 	 * a festive hot-lead enema.
210 	 */
211 	switch (n) {
212 	case 0:
213 		p = bp + SHELLOFFSET;
214 		len -= SHELLOFFSET;
215 		rval = argv_exp3(sp, excp, p, len);
216 		break;
217 	case 1:
218 		if (*p == '*') {
219 			*p = '\0';
220 			rval = argv_lexp(sp, excp, bp + SHELLOFFSET);
221 			break;
222 		}
223 		/* FALLTHROUGH */
224 	default:
225 		if (argv_sexp(sp, &bp, &blen, &len)) {
226 			rval = 1;
227 			goto err;
228 		}
229 		p = bp;
230 		rval = argv_exp3(sp, excp, p, len);
231 		break;
232 	}
233 
234 err:	FREE_SPACE(sp, bp, blen);
235 	return (rval);
236 }
237 
238 /*
239  * argv_exp3 --
240  *	Take a string and break it up into an argv, which is appended
241  *	to the argument list.
242  *
243  * PUBLIC: int argv_exp3(SCR *, EXCMD *, char *, size_t);
244  */
245 int
246 argv_exp3(sp, excp, cmd, cmdlen)
247 	SCR *sp;
248 	EXCMD *excp;
249 	char *cmd;
250 	size_t cmdlen;
251 {
252 	EX_PRIVATE *exp;
253 	size_t len;
254 	int ch, off;
255 	char *ap, *p;
256 
257 	for (exp = EXP(sp); cmdlen > 0; ++exp->argsoff) {
258 		/* Skip any leading whitespace. */
259 		for (; cmdlen > 0; --cmdlen, ++cmd) {
260 			ch = *cmd;
261 			if (!isblank(ch))
262 				break;
263 		}
264 		if (cmdlen == 0)
265 			break;
266 
267 		/*
268 		 * Determine the length of this whitespace delimited
269 		 * argument.
270 		 *
271 		 * QUOTING NOTE:
272 		 *
273 		 * Skip any character preceded by the user's quoting
274 		 * character.
275 		 */
276 		for (ap = cmd, len = 0; cmdlen > 0; ++cmd, --cmdlen, ++len) {
277 			ch = *cmd;
278 			if (IS_ESCAPE(sp, excp, ch) && cmdlen > 1) {
279 				++cmd;
280 				--cmdlen;
281 			} else if (isblank(ch))
282 				break;
283 		}
284 
285 		/*
286 		 * Copy the argument into place.
287 		 *
288 		 * QUOTING NOTE:
289 		 *
290 		 * Lose quote chars.
291 		 */
292 		argv_alloc(sp, len);
293 		off = exp->argsoff;
294 		exp->args[off]->len = len;
295 		for (p = exp->args[off]->bp; len > 0; --len, *p++ = *ap++)
296 			if (IS_ESCAPE(sp, excp, *ap))
297 				++ap;
298 		*p = '\0';
299 	}
300 	excp->argv = exp->args;
301 	excp->argc = exp->argsoff;
302 
303 #if defined(DEBUG) && 0
304 	for (cnt = 0; cnt < exp->argsoff; ++cnt)
305 		TRACE(sp, "arg %d: {%s}\n", cnt, exp->argv[cnt]);
306 #endif
307 	return (0);
308 }
309 
310 /*
311  * argv_fexp --
312  *	Do file name and bang command expansion.
313  */
314 static int
315 argv_fexp(sp, excp, cmd, cmdlen, p, lenp, bpp, blenp, is_bang)
316 	SCR *sp;
317 	EXCMD *excp;
318 	char *cmd, *p, **bpp;
319 	size_t cmdlen, *lenp, *blenp;
320 	int is_bang;
321 {
322 	EX_PRIVATE *exp;
323 	char *bp, *t;
324 	size_t blen, len, off, tlen;
325 
326 	/* Replace file name characters. */
327 	for (bp = *bpp, blen = *blenp, len = *lenp; cmdlen > 0; --cmdlen, ++cmd)
328 		switch (*cmd) {
329 		case '!':
330 			if (!is_bang)
331 				goto ins_ch;
332 			exp = EXP(sp);
333 			if (exp->lastbcomm == NULL) {
334 				msgq(sp, M_ERR,
335 				    "115|No previous command to replace \"!\"");
336 				return (1);
337 			}
338 			len += tlen = strlen(exp->lastbcomm);
339 			off = p - bp;
340 			ADD_SPACE_RET(sp, bp, blen, len);
341 			p = bp + off;
342 			memcpy(p, exp->lastbcomm, tlen);
343 			p += tlen;
344 			F_SET(excp, E_MODIFY);
345 			break;
346 		case '%':
347 			if ((t = sp->frp->name) == NULL) {
348 				msgq(sp, M_ERR,
349 				    "116|No filename to substitute for %%");
350 				return (1);
351 			}
352 			tlen = strlen(t);
353 			len += tlen;
354 			off = p - bp;
355 			ADD_SPACE_RET(sp, bp, blen, len);
356 			p = bp + off;
357 			memcpy(p, t, tlen);
358 			p += tlen;
359 			F_SET(excp, E_MODIFY);
360 			break;
361 		case '#':
362 			if ((t = sp->alt_name) == NULL) {
363 				msgq(sp, M_ERR,
364 				    "117|No filename to substitute for #");
365 				return (1);
366 			}
367 			len += tlen = strlen(t);
368 			off = p - bp;
369 			ADD_SPACE_RET(sp, bp, blen, len);
370 			p = bp + off;
371 			memcpy(p, t, tlen);
372 			p += tlen;
373 			F_SET(excp, E_MODIFY);
374 			break;
375 		case '\\':
376 			/*
377 			 * QUOTING NOTE:
378 			 *
379 			 * Strip any backslashes that protected the file
380 			 * expansion characters.
381 			 */
382 			if (cmdlen > 1 &&
383 			    (cmd[1] == '%' || cmd[1] == '#' || cmd[1] == '!')) {
384 				++cmd;
385 				--cmdlen;
386 			}
387 			/* FALLTHROUGH */
388 		default:
389 ins_ch:			++len;
390 			off = p - bp;
391 			ADD_SPACE_RET(sp, bp, blen, len);
392 			p = bp + off;
393 			*p++ = *cmd;
394 		}
395 
396 	/* Nul termination. */
397 	++len;
398 	off = p - bp;
399 	ADD_SPACE_RET(sp, bp, blen, len);
400 	p = bp + off;
401 	*p = '\0';
402 
403 	/* Return the new string length, buffer, buffer length. */
404 	*lenp = len - 1;
405 	*bpp = bp;
406 	*blenp = blen;
407 	return (0);
408 }
409 
410 /*
411  * argv_alloc --
412  *	Make more space for arguments.
413  */
414 static int
415 argv_alloc(sp, len)
416 	SCR *sp;
417 	size_t len;
418 {
419 	ARGS *ap;
420 	EX_PRIVATE *exp;
421 	int cnt, off;
422 
423 	/*
424 	 * Allocate room for another argument, always leaving
425 	 * enough room for an ARGS structure with a length of 0.
426 	 */
427 #define	INCREMENT	20
428 	exp = EXP(sp);
429 	off = exp->argsoff;
430 	if (exp->argscnt == 0 || off + 2 >= exp->argscnt - 1) {
431 		cnt = exp->argscnt + INCREMENT;
432 		REALLOC(sp, exp->args, ARGS **, cnt * sizeof(ARGS *));
433 		if (exp->args == NULL) {
434 			(void)argv_free(sp);
435 			goto mem;
436 		}
437 		memset(&exp->args[exp->argscnt], 0, INCREMENT * sizeof(ARGS *));
438 		exp->argscnt = cnt;
439 	}
440 
441 	/* First argument. */
442 	if (exp->args[off] == NULL) {
443 		CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
444 		if (exp->args[off] == NULL)
445 			goto mem;
446 	}
447 
448 	/* First argument buffer. */
449 	ap = exp->args[off];
450 	ap->len = 0;
451 	if (ap->blen < len + 1) {
452 		ap->blen = len + 1;
453 		REALLOC(sp, ap->bp, CHAR_T *, ap->blen * sizeof(CHAR_T));
454 		if (ap->bp == NULL) {
455 			ap->bp = NULL;
456 			ap->blen = 0;
457 			F_CLR(ap, A_ALLOCATED);
458 mem:			msgq(sp, M_SYSERR, NULL);
459 			return (1);
460 		}
461 		F_SET(ap, A_ALLOCATED);
462 	}
463 
464 	/* Second argument. */
465 	if (exp->args[++off] == NULL) {
466 		CALLOC(sp, exp->args[off], ARGS *, 1, sizeof(ARGS));
467 		if (exp->args[off] == NULL)
468 			goto mem;
469 	}
470 	/* 0 length serves as end-of-argument marker. */
471 	exp->args[off]->len = 0;
472 	return (0);
473 }
474 
475 /*
476  * argv_free --
477  *	Free up argument structures.
478  *
479  * PUBLIC: int argv_free(SCR *);
480  */
481 int
482 argv_free(sp)
483 	SCR *sp;
484 {
485 	EX_PRIVATE *exp;
486 	int off;
487 
488 	exp = EXP(sp);
489 	if (exp->args != NULL) {
490 		for (off = 0; off < exp->argscnt; ++off) {
491 			if (exp->args[off] == NULL)
492 				continue;
493 			if (F_ISSET(exp->args[off], A_ALLOCATED))
494 				free(exp->args[off]->bp);
495 			free(exp->args[off]);
496 		}
497 		free(exp->args);
498 	}
499 	exp->args = NULL;
500 	exp->argscnt = 0;
501 	exp->argsoff = 0;
502 	return (0);
503 }
504 
505 /*
506  * argv_lexp --
507  *	Find all file names matching the prefix and append them to the
508  *	buffer.
509  */
510 static int
511 argv_lexp(sp, excp, path)
512 	SCR *sp;
513 	EXCMD *excp;
514 	char *path;
515 {
516 	struct dirent *dp;
517 	DIR *dirp;
518 	EX_PRIVATE *exp;
519 	int off;
520 	size_t dlen, len, nlen;
521 	char *dname, *name, *p;
522 
523 	exp = EXP(sp);
524 
525 	/* Set up the name and length for comparison. */
526 	if ((p = strrchr(path, '/')) == NULL) {
527 		dname = ".";
528 		dlen = 0;
529 		name = path;
530 	} else {
531 		if (p == path) {
532 			dname = "/";
533 			dlen = 1;
534 		} else {
535 			*p = '\0';
536 			dname = path;
537 			dlen = strlen(path);
538 		}
539 		name = p + 1;
540 	}
541 	nlen = strlen(name);
542 
543 	/*
544 	 * XXX
545 	 * We don't use the d_namlen field, it's not portable enough; we
546 	 * assume that d_name is nul terminated, instead.
547 	 */
548 	if ((dirp = opendir(dname)) == NULL) {
549 		msgq_str(sp, M_SYSERR, dname, "%s");
550 		return (1);
551 	}
552 	for (off = exp->argsoff; (dp = readdir(dirp)) != NULL;) {
553 		if (nlen == 0) {
554 			if (dp->d_name[0] == '.')
555 				continue;
556 			len = strlen(dp->d_name);
557 		} else {
558 			len = strlen(dp->d_name);
559 			if (len < nlen || memcmp(dp->d_name, name, nlen))
560 				continue;
561 		}
562 
563 		/* Directory + name + slash + null. */
564 		argv_alloc(sp, dlen + len + 2);
565 		p = exp->args[exp->argsoff]->bp;
566 		if (dlen != 0) {
567 			memcpy(p, dname, dlen);
568 			p += dlen;
569 			if (dlen > 1 || dname[0] != '/')
570 				*p++ = '/';
571 		}
572 		memcpy(p, dp->d_name, len + 1);
573 		exp->args[exp->argsoff]->len = dlen + len + 1;
574 		++exp->argsoff;
575 		excp->argv = exp->args;
576 		excp->argc = exp->argsoff;
577 	}
578 	closedir(dirp);
579 
580 	if (off == exp->argsoff) {
581 		/*
582 		 * If we didn't find a match, complain that the expansion
583 		 * failed.  We can't know for certain that's the error, but
584 		 * it's a good guess, and it matches historic practice.
585 		 */
586 		msgq(sp, M_ERR, "304|Shell expansion failed");
587 		return (1);
588 	}
589 	qsort(exp->args + off, exp->argsoff - off, sizeof(ARGS *), argv_comp);
590 	return (0);
591 }
592 
593 /*
594  * argv_comp --
595  *	Alphabetic comparison.
596  */
597 static int
598 argv_comp(a, b)
599 	const void *a, *b;
600 {
601 	return (strcmp((char *)(*(ARGS **)a)->bp, (char *)(*(ARGS **)b)->bp));
602 }
603 
604 /*
605  * argv_sexp --
606  *	Fork a shell, pipe a command through it, and read the output into
607  *	a buffer.
608  */
609 static int
610 argv_sexp(sp, bpp, blenp, lenp)
611 	SCR *sp;
612 	char **bpp;
613 	size_t *blenp, *lenp;
614 {
615 	enum { SEXP_ERR, SEXP_EXPANSION_ERR, SEXP_OK } rval;
616 	FILE *ifp;
617 	pid_t pid;
618 	size_t blen, len;
619 	int ch, std_output[2];
620 	char *bp, *p, *sh, *sh_path;
621 
622 	/* Secure means no shell access. */
623 	if (O_ISSET(sp, O_SECURE)) {
624 		msgq(sp, M_ERR,
625 "289|Shell expansions not supported when the secure edit option is set");
626 		return (1);
627 	}
628 
629 	sh_path = O_STR(sp, O_SHELL);
630 	if ((sh = strrchr(sh_path, '/')) == NULL)
631 		sh = sh_path;
632 	else
633 		++sh;
634 
635 	/* Local copies of the buffer variables. */
636 	bp = *bpp;
637 	blen = *blenp;
638 
639 	/*
640 	 * There are two different processes running through this code, named
641 	 * the utility (the shell) and the parent. The utility reads standard
642 	 * input and writes standard output and standard error output.  The
643 	 * parent writes to the utility, reads its standard output and ignores
644 	 * its standard error output.  Historically, the standard error output
645 	 * was discarded by vi, as it produces a lot of noise when file patterns
646 	 * don't match.
647 	 *
648 	 * The parent reads std_output[0], and the utility writes std_output[1].
649 	 */
650 	ifp = NULL;
651 	std_output[0] = std_output[1] = -1;
652 	if (pipe(std_output) < 0) {
653 		msgq(sp, M_SYSERR, "pipe");
654 		return (1);
655 	}
656 	if ((ifp = fdopen(std_output[0], "r")) == NULL) {
657 		msgq(sp, M_SYSERR, "fdopen");
658 		goto err;
659 	}
660 
661 	/*
662 	 * Do the minimal amount of work possible, the shell is going to run
663 	 * briefly and then exit.  We sincerely hope.
664 	 */
665 	switch (pid = vfork()) {
666 	case -1:			/* Error. */
667 		msgq(sp, M_SYSERR, "vfork");
668 err:		if (ifp != NULL)
669 			(void)fclose(ifp);
670 		else if (std_output[0] != -1)
671 			close(std_output[0]);
672 		if (std_output[1] != -1)
673 			close(std_output[0]);
674 		return (1);
675 	case 0:				/* Utility. */
676 		/* Redirect stdout to the write end of the pipe. */
677 		(void)dup2(std_output[1], STDOUT_FILENO);
678 
679 		/* Close the utility's file descriptors. */
680 		(void)close(std_output[0]);
681 		(void)close(std_output[1]);
682 		(void)close(STDERR_FILENO);
683 
684 		/*
685 		 * XXX
686 		 * Assume that all shells have -c.
687 		 */
688 		execl(sh_path, sh, "-c", bp, (char *)NULL);
689 		msgq_str(sp, M_SYSERR, sh_path, "118|Error: execl: %s");
690 		_exit(127);
691 	default:			/* Parent. */
692 		/* Close the pipe ends the parent won't use. */
693 		(void)close(std_output[1]);
694 		break;
695 	}
696 
697 	/*
698 	 * Copy process standard output into a buffer.
699 	 *
700 	 * !!!
701 	 * Historic vi apparently discarded leading \n and \r's from
702 	 * the shell output stream.  We don't on the grounds that any
703 	 * shell that does that is broken.
704 	 */
705 	for (p = bp, len = 0, ch = EOF;
706 	    (ch = getc(ifp)) != EOF; *p++ = ch, --blen, ++len)
707 		if (blen < 5) {
708 			ADD_SPACE_GOTO(sp, bp, *blenp, *blenp * 2);
709 			p = bp + len;
710 			blen = *blenp - len;
711 		}
712 
713 	/* Delete the final newline, nul terminate the string. */
714 	if (p > bp && (p[-1] == '\n' || p[-1] == '\r')) {
715 		--p;
716 		--len;
717 	}
718 	*p = '\0';
719 	*lenp = len;
720 	*bpp = bp;		/* *blenp is already updated. */
721 
722 	if (ferror(ifp))
723 		goto ioerr;
724 	if (fclose(ifp)) {
725 ioerr:		msgq_str(sp, M_ERR, sh, "119|I/O error: %s");
726 alloc_err:	rval = SEXP_ERR;
727 	} else
728 		rval = SEXP_OK;
729 
730 	/*
731 	 * Wait for the process.  If the shell process fails (e.g., "echo $q"
732 	 * where q wasn't a defined variable) or if the returned string has
733 	 * no characters or only blank characters, (e.g., "echo $5"), complain
734 	 * that the shell expansion failed.  We can't know for certain that's
735 	 * the error, but it's a good guess, and it matches historic practice.
736 	 * This won't catch "echo foo_$5", but that's not a common error and
737 	 * historic vi didn't catch it either.
738 	 */
739 	if (proc_wait(sp, pid, sh, 1, 0))
740 		rval = SEXP_EXPANSION_ERR;
741 
742 	for (p = bp; len; ++p, --len)
743 		if (!isblank(*p))
744 			break;
745 	if (len == 0)
746 		rval = SEXP_EXPANSION_ERR;
747 
748 	if (rval == SEXP_EXPANSION_ERR)
749 		msgq(sp, M_ERR, "304|Shell expansion failed");
750 
751 	return (rval == SEXP_OK ? 0 : 1);
752 }
753