View | Details | Raw Unified | Return to bug 778 | Differences between
and this patch

Collapse All | Expand All

(-)regress/usr.bin/ssh/sftp-glob.sh (-14 / +51 lines)
Lines 3-28 Link Here
3
3
4
tid="sftp glob"
4
tid="sftp glob"
5
5
6
sftp_ls() {
7
	target=$1
8
	errtag=$2
9
	expected=$3
10
	unexpected=$4
11
	verbose "$tid: $errtag"
12
	echo -E "ls -l ${target}" | \
13
		${SFTP} -b - -P ${SFTPSERVER} 2>/dev/null | \
14
		grep -v "^sftp>" > ${RESULTS}
15
	if [ $? -ne 0 ]; then
16
		fail "$errtag failed"
17
	fi
18
	if test "x$expected" != "x" && \
19
	   ! fgrep "$expected" ${RESULTS} >/dev/null 2>&1 ; then
20
		fail "$expected missing from $errtag results"
21
	fi
22
	if test "x$unexpected" != "x" && \
23
	   fgrep "$unexpected" ${RESULTS} >/dev/null 2>&1 ; then
24
		fail "$unexpected present in $errtag results"
25
	fi
26
	rm -f ${RESULTS}
27
}
28
6
BASE=${OBJ}/glob
29
BASE=${OBJ}/glob
30
RESULTS=${OBJ}/results
7
DIR=${BASE}/dir
31
DIR=${BASE}/dir
8
DATA=${DIR}/file
32
DATA=${DIR}/file
9
33
34
GLOB1="${DIR}/g-wild*"
35
GLOB2="${DIR}/g-wildx"
36
QUOTE="${DIR}/g-quote\""
37
SLASH="${DIR}/g-sl\\ash"
38
ESLASH="${DIR}/g-slash\\"
39
QSLASH="${DIR}/g-qs\\\""
40
SPACE="${DIR}/g-q space"
41
10
rm -rf ${BASE}
42
rm -rf ${BASE}
11
mkdir -p ${DIR}
43
mkdir -p ${DIR}
12
touch ${DATA}
44
touch "${DATA}" "${GLOB1}" "${GLOB2}" "${QUOTE}"
45
touch "${QSLASH}" "${ESLASH}" "${SLASH}" "${SPACE}"
13
46
14
verbose "$tid: ls file"
47
#       target                   message                expected     unexpected
15
echo "ls -l ${DIR}/fil*" | ${SFTP} -P ${SFTPSERVER} 2>/dev/null | \
48
sftp_ls "${DIR}/fil*"            "file glob"            "${DATA}"    ""
16
	grep ${DATA} >/dev/null 2>&1
49
sftp_ls "${BASE}/d*"             "dir glob"             "`basename ${DATA}`" ""
17
if [ $? -ne 0 ]; then
50
sftp_ls "${DIR}/g-wild\"*\""     "quoted glob"          "g-wild*"    "g-wildx"
18
	fail "globbed ls file failed"
51
sftp_ls "${DIR}/g-wild\*"        "escaped glob"         "g-wild*"    "g-wildx"
19
fi
52
sftp_ls "${DIR}/g-quote\\\""     "escaped quote"        "g-quote\""  ""
20
53
sftp_ls "\"${DIR}/g-quote\\\"\"" "quoted quote"         "g-quote\""  ""
21
verbose "$tid: ls dir"
54
sftp_ls "'${DIR}/g-quote\"'"     "single-quoted quote"  "g-quote\""  ""
22
echo "ls -l ${BASE}/d*" | ${SFTP} -P ${SFTPSERVER} 2>/dev/null | \
55
sftp_ls "${DIR}/g-sl\\\\ash"     "escaped slash"        "g-sl\\ash"  ""
23
	grep file >/dev/null 2>&1
56
sftp_ls "'${DIR}/g-sl\\\\ash'"   "quoted slash"         "g-sl\\ash"  ""
24
if [ $? -ne 0 ]; then
57
sftp_ls "${DIR}/g-slash\\\\"     "escaped slash at EOL" "g-slash\\"  ""
25
	fail "globbed ls dir failed"
58
sftp_ls "'${DIR}/g-slash\\\\'"   "quoted slash at EOL"  "g-slash\\"  ""
26
fi
59
sftp_ls "${DIR}/g-qs\\\\\\\""    "escaped slash+quote"  "g-qs\\\""   ""
60
sftp_ls "'${DIR}/g-qs\\\\\"'"    "quoted slash+quote"   "g-qs\\\""   ""
61
sftp_ls "${DIR}/g-q\\ space"     "escaped space"        "g-q space"  ""
62
sftp_ls "'${DIR}/g-q space'"     "quoted space"         "g-q space"  ""
27
63
28
rm -rf ${BASE}
64
rm -rf ${BASE}
65
(-)regress/usr.bin/ssh/test-exec.sh (-4 / +4 lines)
Lines 109-115 cleanup () Link Here
109
109
110
trace ()
110
trace ()
111
{
111
{
112
	echo "trace: $@" >>$TEST_SSH_LOGFILE
112
	echo -E "trace: $@" >>$TEST_SSH_LOGFILE
113
	if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then
113
	if [ "X$TEST_SSH_TRACE" = "Xyes" ]; then
114
		echo "$@"
114
		echo "$@"
115
	fi
115
	fi
Lines 117-123 trace () Link Here
117
117
118
verbose ()
118
verbose ()
119
{
119
{
120
	echo "verbose: $@" >>$TEST_SSH_LOGFILE
120
	echo -E "verbose: $@" >>$TEST_SSH_LOGFILE
121
	if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then
121
	if [ "X$TEST_SSH_QUIET" != "Xyes" ]; then
122
		echo "$@"
122
		echo "$@"
123
	fi
123
	fi
Lines 126-139 verbose () Link Here
126
126
127
fail ()
127
fail ()
128
{
128
{
129
	echo "FAIL: $@" >>$TEST_SSH_LOGFILE
129
	echo -E "FAIL: $@" >>$TEST_SSH_LOGFILE
130
	RESULT=1
130
	RESULT=1
131
	echo "$@"
131
	echo "$@"
132
}
132
}
133
133
134
fatal ()
134
fatal ()
135
{
135
{
136
	echo "FATAL: $@" >>$TEST_SSH_LOGFILE
136
	echo -E "FATAL: $@" >>$TEST_SSH_LOGFILE
137
	echo -n "FATAL: "
137
	echo -n "FATAL: "
138
	fail "$@"
138
	fail "$@"
139
	cleanup
139
	cleanup
(-)usr.bin/ssh/sftp.c (-171 / +276 lines)
Lines 22-27 Link Here
22
#include <sys/socket.h>
22
#include <sys/socket.h>
23
#include <sys/param.h>
23
#include <sys/param.h>
24
24
25
#include <ctype.h>
25
#include <errno.h>
26
#include <errno.h>
26
#include <glob.h>
27
#include <glob.h>
27
#include <histedit.h>
28
#include <histedit.h>
Lines 334-477 infer_path(const char *p, char **ifp) Link Here
334
}
335
}
335
336
336
static int
337
static int
337
parse_getput_flags(const char **cpp, int *pflag)
338
parse_getput_flags(const char *cmd, char **argv, int argc, int *pflag)
338
{
339
{
339
	const char *cp = *cpp;
340
	extern int optind, optreset, opterr;
341
	int ch;
340
342
341
	/* Check for flags */
343
	optind = optreset = 1;
342
	if (cp[0] == '-' && cp[1] && strchr(WHITESPACE, cp[2])) {
344
	opterr = 0;
343
		switch (cp[1]) {
345
346
	*pflag = 0;
347
	while ((ch = getopt(argc, argv, "Pp")) != -1) {
348
		switch (ch) {
344
		case 'p':
349
		case 'p':
345
		case 'P':
350
		case 'P':
346
			*pflag = 1;
351
			*pflag = 1;
347
			break;
352
			break;
348
		default:
353
		default:
349
			error("Invalid flag -%c", cp[1]);
354
			error("%s: Invalid flag -%c", cmd, ch);
350
			return(-1);
355
			return -1;
351
		}
352
		cp += 2;
353
		*cpp = cp + strspn(cp, WHITESPACE);
354
	}
355
356
	return(0);
357
}
358
359
static int
360
parse_ls_flags(const char **cpp, int *lflag)
361
{
362
	const char *cp = *cpp;
363
364
	/* Defaults */
365
	*lflag = LS_NAME_SORT;
366
367
	/* Check for flags */
368
	if (cp++[0] == '-') {
369
		for (; strchr(WHITESPACE, *cp) == NULL; cp++) {
370
			switch (*cp) {
371
			case 'l':
372
				*lflag &= ~VIEW_FLAGS;
373
				*lflag |= LS_LONG_VIEW;
374
				break;
375
			case '1':
376
				*lflag &= ~VIEW_FLAGS;
377
				*lflag |= LS_SHORT_VIEW;
378
				break;
379
			case 'n':
380
				*lflag &= ~VIEW_FLAGS;
381
				*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
382
				break;
383
			case 'S':
384
				*lflag &= ~SORT_FLAGS;
385
				*lflag |= LS_SIZE_SORT;
386
				break;
387
			case 't':
388
				*lflag &= ~SORT_FLAGS;
389
				*lflag |= LS_TIME_SORT;
390
				break;
391
			case 'r':
392
				*lflag |= LS_REVERSE_SORT;
393
				break;
394
			case 'f':
395
				*lflag &= ~SORT_FLAGS;
396
				break;
397
			case 'a':
398
				*lflag |= LS_SHOW_ALL;
399
				break;
400
			default:
401
				error("Invalid flag -%c", *cp);
402
				return(-1);
403
			}
404
		}
356
		}
405
		*cpp = cp + strspn(cp, WHITESPACE);
406
	}
357
	}
407
358
408
	return(0);
359
	return optind;
409
}
360
}
410
361
411
static int
362
static int
412
get_pathname(const char **cpp, char **path)
363
parse_ls_flags(char **argv, int argc, int *lflag)
413
{
364
{
414
	const char *cp = *cpp, *end;
365
	extern int optind, optreset, opterr;
415
	char quot;
366
	int ch;
416
	u_int i, j;
417
418
	cp += strspn(cp, WHITESPACE);
419
	if (!*cp) {
420
		*cpp = cp;
421
		*path = NULL;
422
		return (0);
423
	}
424
367
425
	*path = xmalloc(strlen(cp) + 1);
368
	optind = optreset = 1;
369
	opterr = 0;
426
370
427
	/* Check for quoted filenames */
371
	*lflag = LS_NAME_SORT;
428
	if (*cp == '\"' || *cp == '\'') {
372
	while ((ch = getopt(argc, argv, "1Saflnrt")) != -1) {
429
		quot = *cp++;
373
		switch (ch) {
430
374
		case '1':
431
		/* Search for terminating quote, unescape some chars */
375
			*lflag &= ~VIEW_FLAGS;
432
		for (i = j = 0; i <= strlen(cp); i++) {
376
			*lflag |= LS_SHORT_VIEW;
433
			if (cp[i] == quot) {	/* Found quote */
377
			break;
434
				i++;
378
		case 'S':
435
				(*path)[j] = '\0';
379
			*lflag &= ~SORT_FLAGS;
436
				break;
380
			*lflag |= LS_SIZE_SORT;
437
			}
381
			break;
438
			if (cp[i] == '\0') {	/* End of string */
382
		case 'a':
439
				error("Unterminated quote");
383
			*lflag |= LS_SHOW_ALL;
440
				goto fail;
384
			break;
441
			}
385
		case 'f':
442
			if (cp[i] == '\\') {	/* Escaped characters */
386
			*lflag &= ~SORT_FLAGS;
443
				i++;
387
			break;
444
				if (cp[i] != '\'' && cp[i] != '\"' &&
388
		case 'l':
445
				    cp[i] != '\\') {
389
			*lflag &= ~VIEW_FLAGS;
446
					error("Bad escaped character '\\%c'",
390
			*lflag |= LS_LONG_VIEW;
447
					    cp[i]);
391
			break;
448
					goto fail;
392
		case 'n':
449
				}
393
			*lflag &= ~VIEW_FLAGS;
450
			}
394
			*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
451
			(*path)[j++] = cp[i];
395
			break;
396
		case 'r':
397
			*lflag |= LS_REVERSE_SORT;
398
			break;
399
		case 't':
400
			*lflag &= ~SORT_FLAGS;
401
			*lflag |= LS_TIME_SORT;
402
			break;
403
		default:
404
			error("ls: Invalid flag -%c", ch);
405
			return -1;
452
		}
406
		}
453
454
		if (j == 0) {
455
			error("Empty quotes");
456
			goto fail;
457
		}
458
		*cpp = cp + i + strspn(cp + i, WHITESPACE);
459
	} else {
460
		/* Read to end of filename */
461
		end = strpbrk(cp, WHITESPACE);
462
		if (end == NULL)
463
			end = strchr(cp, '\0');
464
		*cpp = end + strspn(end, WHITESPACE);
465
466
		memcpy(*path, cp, end - cp);
467
		(*path)[end - cp] = '\0';
468
	}
407
	}
469
	return (0);
470
408
471
 fail:
409
	return optind;
472
	xfree(*path);
473
	*path = NULL;
474
	return (-1);
475
}
410
}
476
411
477
static int
412
static int
Lines 854-868 do_globbed_ls(struct sftp_conn *conn, ch Link Here
854
	return (0);
789
	return (0);
855
}
790
}
856
791
792
/*
793
 * Undo escaping of glob sequences in place. Used to undo extra escaping
794
 * applied in makeargv() when the string is destined for a function that
795
 * does not glob it.
796
 */
797
static void
798
undo_glob_escape(char *s)
799
{
800
	size_t i, j;
801
802
	for (i = j = 0;;) {
803
		if (s[i] == '\0') {
804
			s[j] = '\0';
805
			return;
806
		}
807
		if (s[i] != '\\') {
808
			s[j++] = s[i++];
809
			continue;
810
		}
811
		/* s[i] == '\\' */
812
		++i;
813
		switch (s[i]) {
814
		case '?':
815
		case '[':
816
		case '*':
817
		case '\\':
818
			s[j++] = s[i++];
819
			break;
820
		case '\0':
821
			s[j++] = '\\';
822
			s[j] = '\0';
823
			return;
824
		default:
825
			s[j++] = '\\';
826
			s[j++] = s[i++];
827
			break;
828
		}
829
	}
830
}
831
832
/*
833
 * Split a string into an argument vector using sh(1)-style quoting,
834
 * comment and escaping rules, but with some tweaks to handle glob(3)
835
 * wildcards.
836
 * Returns NULL on error or up to MAXARGS in static buffer (NULL terminated)
837
 */
838
#define MAXARGS 	128
839
#define MAXARGLEN	8192
840
static char **
841
makeargv(const char *arg, int *argcp)
842
{
843
	int argc, quot;
844
	size_t i, j;
845
	static char argvs[MAXARGLEN];
846
	static char *argv[MAXARGS + 1];
847
	enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
848
849
	*argcp = argc = 0;
850
	if (strlen(arg) > sizeof(argvs) - 1) {
851
 args_too_longs:
852
		error("string too long");
853
		return NULL;
854
	}
855
	state = MA_START;
856
	i = j = 0;
857
	for (;;) {
858
		if (isspace(arg[i])) {
859
			if (state == MA_UNQUOTED) {
860
				/* Terminate current argument */
861
				argvs[j++] = '\0';
862
				argc++;
863
				state = MA_START;
864
			} else if (state != MA_START)
865
				argvs[j++] = arg[i];
866
		} else if (arg[i] == '"' || arg[i] == '\'') {
867
			q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
868
			if (state == MA_START) {
869
				argv[argc] = argvs + j;
870
				state = q;
871
			} else if (state == MA_UNQUOTED) 
872
				state = q;
873
			else if (state == q)
874
				state = MA_UNQUOTED;
875
			else
876
				argvs[j++] = arg[i];
877
		} else if (arg[i] == '\\') {
878
			if (state == MA_SQUOTE || state == MA_DQUOTE) {
879
				quot = state == MA_SQUOTE ? '\'' : '"';
880
				/* Unescape quote we are in */
881
				/* XXX support \n and friends? */
882
				if (arg[i + 1] == quot) {
883
					i++;
884
					argvs[j++] = arg[i];
885
				} else if (arg[i + 1] == '?' ||
886
				    arg[i + 1] == '[' || arg[i + 1] == '*') {
887
					/*
888
					 * Special case for sftp: append
889
					 * double-escaped glob sequence -
890
					 * glob will undo one level of
891
					 * escaping. NB. string can grow here.
892
					 */
893
					if (j >= sizeof(argvs) - 5)
894
						goto args_too_longs;
895
					argvs[j++] = '\\';
896
					argvs[j++] = arg[i++];
897
					argvs[j++] = '\\';
898
					argvs[j++] = arg[i];
899
				} else {
900
					argvs[j++] = arg[i++];
901
					argvs[j++] = arg[i];
902
				}
903
			} else {
904
				if (state == MA_START) {
905
					argv[argc] = argvs + j;
906
					state = MA_UNQUOTED;
907
				}
908
				if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
909
				    arg[i + 1] == '*' || arg[i + 1] == '\\') {
910
					/*
911
					 * Special case for sftp: append
912
					 * escaped glob sequence -
913
					 * glob will undo one level of
914
					 * escaping.
915
					 */
916
					argvs[j++] = arg[i++];
917
					argvs[j++] = arg[i];
918
				} else {
919
					/* Unescape everything */
920
					/* XXX support \n and friends? */
921
					i++;
922
					argvs[j++] = arg[i];
923
				}
924
			}
925
		} else if (arg[i] == '#') {
926
			if (state == MA_SQUOTE || state == MA_DQUOTE)
927
				argvs[j++] = arg[i];
928
			else
929
				goto string_done;
930
		} else if (arg[i] == '\0') {
931
			if (state == MA_SQUOTE || state == MA_DQUOTE) {
932
				error("Unterminated quoted argument");
933
				return NULL;
934
			}
935
 string_done:
936
			if (state == MA_UNQUOTED) {
937
				argvs[j++] = '\0';
938
				argc++;
939
			}
940
			break;
941
		} else {
942
			if (state == MA_START) {
943
				argv[argc] = argvs + j;
944
				state = MA_UNQUOTED;
945
			}
946
			if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
947
			    (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
948
				/*
949
				 * Special case for sftp: escape quoted
950
				 * glob(3) wildcards. NB. string can grow
951
				 * here.
952
				 */
953
				if (j >= sizeof(argvs) - 3)
954
					goto args_too_longs;
955
				argvs[j++] = '\\';
956
				argvs[j++] = arg[i];
957
			} else
958
				argvs[j++] = arg[i];
959
		}
960
		i++;
961
	}
962
	*argcp = argc;
963
	return argv;
964
}
965
857
static int
966
static int
858
parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
967
parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
859
    unsigned long *n_arg, char **path1, char **path2)
968
    unsigned long *n_arg, char **path1, char **path2)
860
{
969
{
861
	const char *cmd, *cp = *cpp;
970
	const char *cmd, *cp = *cpp;
862
	char *cp2;
971
	char *cp2, **argv;
863
	int base = 0;
972
	int base = 0;
864
	long l;
973
	long l;
865
	int i, cmdnum;
974
	int i, cmdnum, optidx, argc;
866
975
867
	/* Skip leading whitespace */
976
	/* Skip leading whitespace */
868
	cp = cp + strspn(cp, WHITESPACE);
977
	cp = cp + strspn(cp, WHITESPACE);
Lines 878-894 parse_args(const char **cpp, int *pflag, Link Here
878
		cp++;
987
		cp++;
879
	}
988
	}
880
989
881
	/* Figure out which command we have */
990
	if ((argv = makeargv(cp, &argc)) == NULL)
882
	for (i = 0; cmds[i].c; i++) {
991
		return -1;
883
		int cmdlen = strlen(cmds[i].c);
884
992
885
		/* Check for command followed by whitespace */
993
	/* Figure out which command we have */
886
		if (!strncasecmp(cp, cmds[i].c, cmdlen) &&
994
	for (i = 0; cmds[i].c != NULL; i++) {
887
		    strchr(WHITESPACE, cp[cmdlen])) {
995
		if (strcasecmp(cmds[i].c, argv[0]) == 0)
888
			cp += cmdlen;
889
			cp = cp + strspn(cp, WHITESPACE);
890
			break;
996
			break;
891
		}
892
	}
997
	}
893
	cmdnum = cmds[i].n;
998
	cmdnum = cmds[i].n;
894
	cmd = cmds[i].c;
999
	cmd = cmds[i].c;
Lines 899-938 parse_args(const char **cpp, int *pflag, Link Here
899
		cmdnum = I_SHELL;
1004
		cmdnum = I_SHELL;
900
	} else if (cmdnum == -1) {
1005
	} else if (cmdnum == -1) {
901
		error("Invalid command.");
1006
		error("Invalid command.");
902
		return (-1);
1007
		return -1;
903
	}
1008
	}
904
1009
905
	/* Get arguments and parse flags */
1010
	/* Get arguments and parse flags */
906
	*lflag = *pflag = *n_arg = 0;
1011
	*lflag = *pflag = *n_arg = 0;
907
	*path1 = *path2 = NULL;
1012
	*path1 = *path2 = NULL;
1013
	optidx = 1;
908
	switch (cmdnum) {
1014
	switch (cmdnum) {
909
	case I_GET:
1015
	case I_GET:
910
	case I_PUT:
1016
	case I_PUT:
911
		if (parse_getput_flags(&cp, pflag))
1017
		if ((optidx = parse_getput_flags(cmd, argv, argc, pflag)) == -1)
912
			return(-1);
1018
			return -1;
913
		/* Get first pathname (mandatory) */
1019
		/* Get first pathname (mandatory) */
914
		if (get_pathname(&cp, path1))
1020
		if (argc - optidx < 1) {
915
			return(-1);
916
		if (*path1 == NULL) {
917
			error("You must specify at least one path after a "
1021
			error("You must specify at least one path after a "
918
			    "%s command.", cmd);
1022
			    "%s command.", cmd);
919
			return(-1);
1023
			return -1;
1024
		}
1025
		*path1 = xstrdup(argv[optidx]);
1026
		/* Get second pathname (optional) */
1027
		if (argc - optidx > 1) {
1028
			*path2 = xstrdup(argv[optidx + 1]);
1029
			/* Destination is not globbed */
1030
			undo_glob_escape(*path2);
920
		}
1031
		}
921
		/* Try to get second pathname (optional) */
922
		if (get_pathname(&cp, path2))
923
			return(-1);
924
		break;
1032
		break;
925
	case I_RENAME:
1033
	case I_RENAME:
926
	case I_SYMLINK:
1034
	case I_SYMLINK:
927
		if (get_pathname(&cp, path1))
1035
		if (argc - optidx < 2) {
928
			return(-1);
929
		if (get_pathname(&cp, path2))
930
			return(-1);
931
		if (!*path1 || !*path2) {
932
			error("You must specify two paths after a %s "
1036
			error("You must specify two paths after a %s "
933
			    "command.", cmd);
1037
			    "command.", cmd);
934
			return(-1);
1038
			return -1;
935
		}
1039
		}
1040
		*path1 = xstrdup(argv[optidx]);
1041
		*path2 = xstrdup(argv[optidx + 1]);
1042
		/* Paths are not globbed */
1043
		undo_glob_escape(*path1);
1044
		undo_glob_escape(*path2);
936
		break;
1045
		break;
937
	case I_RM:
1046
	case I_RM:
938
	case I_MKDIR:
1047
	case I_MKDIR:
Lines 941-999 parse_args(const char **cpp, int *pflag, Link Here
941
	case I_LCHDIR:
1050
	case I_LCHDIR:
942
	case I_LMKDIR:
1051
	case I_LMKDIR:
943
		/* Get pathname (mandatory) */
1052
		/* Get pathname (mandatory) */
944
		if (get_pathname(&cp, path1))
1053
		if (argc - optidx < 1) {
945
			return(-1);
946
		if (*path1 == NULL) {
947
			error("You must specify a path after a %s command.",
1054
			error("You must specify a path after a %s command.",
948
			    cmd);
1055
			    cmd);
949
			return(-1);
1056
			return -1;
950
		}
1057
		}
1058
		*path1 = xstrdup(argv[optidx]);
1059
		/* Only "rm" globs */
1060
		if (cmdnum != I_RM)
1061
			undo_glob_escape(*path1);
951
		break;
1062
		break;
952
	case I_LS:
1063
	case I_LS:
953
		if (parse_ls_flags(&cp, lflag))
1064
		if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
954
			return(-1);
1065
			return(-1);
955
		/* Path is optional */
1066
		/* Path is optional */
956
		if (get_pathname(&cp, path1))
1067
		if (argc - optidx > 0)
957
			return(-1);
1068
			*path1 = xstrdup(argv[optidx]);
958
		break;
1069
		break;
959
	case I_LLS:
1070
	case I_LLS:
960
	case I_SHELL:
1071
	case I_SHELL:
961
		/* Uses the rest of the line */
1072
		/* Uses the rest of the line */
962
		break;
1073
		break;
963
	case I_LUMASK:
1074
	case I_LUMASK:
964
		base = 8;
965
	case I_CHMOD:
1075
	case I_CHMOD:
966
		base = 8;
1076
		base = 8;
967
	case I_CHOWN:
1077
	case I_CHOWN:
968
	case I_CHGRP:
1078
	case I_CHGRP:
969
		/* Get numeric arg (mandatory) */
1079
		/* Get numeric arg (mandatory) */
1080
		if (argc - optidx < 1)
1081
			goto need_num_arg;
970
		errno = 0;
1082
		errno = 0;
971
		l = strtol(cp, &cp2, base);
1083
		l = strtol(argv[optidx], &cp2, base);
972
		if (cp2 == cp || ((l == LONG_MIN || l == LONG_MAX) &&
1084
		if (cp2 == argv[optidx] || *cp2 != '\0' ||
973
		    errno == ERANGE) || l < 0) {
1085
		    ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
1086
		    l < 0) {
1087
 need_num_arg:
974
			error("You must supply a numeric argument "
1088
			error("You must supply a numeric argument "
975
			    "to the %s command.", cmd);
1089
			    "to the %s command.", cmd);
976
			return(-1);
1090
			return -1;
977
		}
1091
		}
978
		cp = cp2;
979
		*n_arg = l;
1092
		*n_arg = l;
980
		if (cmdnum == I_LUMASK && strchr(WHITESPACE, *cp))
1093
		if (cmdnum == I_LUMASK)
981
			break;
1094
			break;
982
		if (cmdnum == I_LUMASK || !strchr(WHITESPACE, *cp)) {
983
			error("You must supply a numeric argument "
984
			    "to the %s command.", cmd);
985
			return(-1);
986
		}
987
		cp += strspn(cp, WHITESPACE);
988
989
		/* Get pathname (mandatory) */
1095
		/* Get pathname (mandatory) */
990
		if (get_pathname(&cp, path1))
1096
		if (argc - optidx < 2) {
991
			return(-1);
992
		if (*path1 == NULL) {
993
			error("You must specify a path after a %s command.",
1097
			error("You must specify a path after a %s command.",
994
			    cmd);
1098
			    cmd);
995
			return(-1);
1099
			return -1;
996
		}
1100
		}
1101
		*path1 = xstrdup(argv[optidx + 1]);
997
		break;
1102
		break;
998
	case I_QUIT:
1103
	case I_QUIT:
999
	case I_PWD:
1104
	case I_PWD:

Return to bug 778