summaryrefslogtreecommitdiffstats
path: root/bin
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2014-11-19 01:07:58 +0000
committersjg <sjg@FreeBSD.org>2014-11-19 01:07:58 +0000
commitb137080f19736ee33fede2e88bb54438604cf86b (patch)
tree377ac0ac449528621eb192cd245adadb5fd53668 /bin
parentab21a29eb607d4dfe389b965fbdee27558e791aa (diff)
parent4a8d07956d121238d006d34ffe7d6269744e8b1a (diff)
downloadFreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.zip
FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.tar.gz
Merge from head@274682
Diffstat (limited to 'bin')
-rw-r--r--bin/csh/Makefile2
-rw-r--r--bin/date/tests/Makefile2
-rwxr-xr-xbin/date/tests/format_string_test.sh92
-rw-r--r--bin/date/tests/legacy_test.sh91
-rw-r--r--bin/dd/dd.17
-rw-r--r--bin/df/Makefile4
-rw-r--r--bin/df/df.15
-rw-r--r--bin/df/df.c124
-rw-r--r--bin/ed/cbc.c2
-rw-r--r--bin/pkill/tests/Makefile2
-rw-r--r--bin/pkill/tests/pgrep-j_test.sh84
-rw-r--r--bin/pkill/tests/pkill-j_test.sh75
-rw-r--r--bin/ps/keyword.c1
-rw-r--r--bin/ps/ps.15
-rw-r--r--bin/rmail/Makefile2
-rw-r--r--bin/sh/arith_yacc.c4
-rw-r--r--bin/sh/eval.c15
-rw-r--r--bin/sh/expand.c74
-rw-r--r--bin/sh/histedit.c5
-rw-r--r--bin/sh/input.c29
-rw-r--r--bin/sh/input.h3
-rw-r--r--bin/sh/jobs.c159
-rw-r--r--bin/sh/mystring.c14
-rw-r--r--bin/sh/options.c31
-rw-r--r--bin/sh/options.h1
-rw-r--r--bin/sh/parser.c291
-rw-r--r--bin/sh/redir.c29
-rw-r--r--bin/sh/sh.146
-rw-r--r--bin/sh/tests/Makefile17
-rw-r--r--bin/sh/tests/builtins/Makefile13
-rw-r--r--bin/sh/tests/builtins/eval7.09
-rw-r--r--bin/sh/tests/builtins/eval8.77
-rw-r--r--bin/sh/tests/builtins/getopts9.09
-rw-r--r--bin/sh/tests/builtins/getopts9.0.stdout3
-rw-r--r--bin/sh/tests/builtins/lineno3.06
-rw-r--r--bin/sh/tests/builtins/lineno3.0.stdout2
-rw-r--r--bin/sh/tests/errors/Makefile8
-rw-r--r--bin/sh/tests/errors/bad-parm-exp2.22
-rw-r--r--bin/sh/tests/errors/bad-parm-exp2.2.stderr2
-rw-r--r--bin/sh/tests/errors/bad-parm-exp3.22
-rw-r--r--bin/sh/tests/errors/bad-parm-exp3.2.stderr2
-rw-r--r--bin/sh/tests/errors/bad-parm-exp4.22
-rw-r--r--bin/sh/tests/errors/bad-parm-exp4.2.stderr2
-rw-r--r--bin/sh/tests/errors/bad-parm-exp5.22
-rw-r--r--bin/sh/tests/errors/bad-parm-exp5.2.stderr2
-rw-r--r--bin/sh/tests/errors/bad-parm-exp6.22
-rw-r--r--bin/sh/tests/errors/bad-parm-exp6.2.stderr2
-rw-r--r--bin/sh/tests/execution/Makefile8
-rw-r--r--bin/sh/tests/expansion/Makefile10
-rw-r--r--bin/sh/tests/expansion/arith14.040
-rw-r--r--bin/sh/tests/expansion/redir1.026
-rwxr-xr-xbin/sh/tests/functional_test.sh72
-rw-r--r--bin/sh/tests/legacy_test.sh46
-rw-r--r--bin/sh/tests/parameters/Makefile10
-rw-r--r--bin/sh/tests/parameters/positional6.07
-rw-r--r--bin/sh/tests/parameters/positional7.08
-rw-r--r--bin/sh/tests/parser/Makefile20
-rw-r--r--bin/sh/tests/parser/heredoc12.047
-rw-r--r--bin/sh/tests/parser/line-cont1.016
-rw-r--r--bin/sh/tests/parser/line-cont10.018
-rw-r--r--bin/sh/tests/parser/line-cont11.023
-rw-r--r--bin/sh/tests/parser/line-cont2.04
-rw-r--r--bin/sh/tests/parser/line-cont3.07
-rw-r--r--bin/sh/tests/parser/line-cont4.08
-rw-r--r--bin/sh/tests/parser/line-cont5.014
-rw-r--r--bin/sh/tests/parser/line-cont6.023
-rw-r--r--bin/sh/tests/parser/line-cont7.07
-rw-r--r--bin/sh/tests/parser/line-cont8.06
-rw-r--r--bin/sh/tests/parser/line-cont9.06
-rw-r--r--bin/sh/tests/set-e/Makefile8
-rw-r--r--bin/sh/trap.c35
-rw-r--r--bin/sleep/Makefile6
-rw-r--r--bin/sleep/tests/Makefile12
73 files changed, 1156 insertions, 624 deletions
diff --git a/bin/csh/Makefile b/bin/csh/Makefile
index 9f305b4..fd34524 100644
--- a/bin/csh/Makefile
+++ b/bin/csh/Makefile
@@ -94,7 +94,7 @@ GENHDRS+= iconv.h
SRCS+= iconv_stub.c
iconv.h: ${.CURDIR}/iconv_stub.h
- cp ${.CURDIR}/iconv_stub.h ${.TARGET}
+ cp -f ${.CURDIR}/iconv_stub.h ${.TARGET}
.endif
.endif
diff --git a/bin/date/tests/Makefile b/bin/date/tests/Makefile
index 2301dcf..d023195 100644
--- a/bin/date/tests/Makefile
+++ b/bin/date/tests/Makefile
@@ -4,6 +4,6 @@
TESTSDIR= ${TESTSBASE}/bin/date
-TAP_TESTS_SH= legacy_test
+ATF_TESTS_SH= format_string_test
.include <bsd.test.mk>
diff --git a/bin/date/tests/format_string_test.sh b/bin/date/tests/format_string_test.sh
new file mode 100755
index 0000000..0bd4f1e
--- /dev/null
+++ b/bin/date/tests/format_string_test.sh
@@ -0,0 +1,92 @@
+#
+# Regression tests for date(1)
+#
+# Submitted by Edwin Groothuis <edwin@FreeBSD.org>
+#
+# $FreeBSD$
+#
+
+#
+# These two date/times have been chosen carefully -- they
+# create both the single digit and double/multidigit version of
+# the values.
+#
+# To create a new one, make sure you are using the UTC timezone!
+#
+
+TEST1=3222243 # 1970-02-07 07:04:03
+TEST2=1005600000 # 2001-11-12 21:11:12
+
+check()
+{
+ local format_string exp_output_1 exp_output_2
+
+ format_string=${1}
+ exp_output_1=${2}
+ exp_output_2=${3}
+
+ atf_check -o "inline:${exp_output_1}\n" \
+ date -r ${TEST1} +%${format_string}
+ atf_check -o "inline:${exp_output_2}\n" \
+ date -r ${TEST2} +%${format_string}
+}
+
+format_string_test()
+{
+ local desc exp_output_1 exp_output_2 flag
+
+ desc=${1}
+ flag=${2}
+ exp_output_1=${3}
+ exp_output_2=${4}
+
+ atf_test_case ${desc}_test
+ eval "
+${desc}_test_body() {
+ check ${flag} '${exp_output_1}' '${exp_output_2}';
+}"
+ atf_add_test_case ${desc}_test
+}
+
+atf_init_test_cases()
+{
+ format_string_test A A Saturday Monday
+ format_string_test a a Sat Mon
+ format_string_test B B February November
+ format_string_test b b Feb Nov
+ format_string_test C C 19 20
+ format_string_test c c "Sat Feb 7 07:04:03 1970" "Mon Nov 12 21:20:00 2001"
+ format_string_test D D 02/07/70 11/12/01
+ format_string_test d d 07 12
+ format_string_test e e " 7" 12
+ format_string_test F F "1970-02-07" "2001-11-12"
+ format_string_test G G 1970 2001
+ format_string_test g g 70 01
+ format_string_test H H 07 21
+ format_string_test h h Feb Nov
+ format_string_test I I 07 09
+ format_string_test j j 038 316
+ format_string_test k k " 7" 21
+ format_string_test l l " 7" " 9"
+ format_string_test M M 04 20
+ format_string_test m m 02 11
+ format_string_test p p AM PM
+ format_string_test R R 07:04 21:20
+ format_string_test r r "07:04:03 AM" "09:20:00 PM"
+ format_string_test S S 03 00
+ format_string_test s s ${TEST1} ${TEST2}
+ format_string_test U U 05 45
+ format_string_test u u 6 1
+ format_string_test V V 06 46
+ format_string_test v v " 7-Feb-1970" "12-Nov-2001"
+ format_string_test W W 05 46
+ format_string_test w w 6 1
+ format_string_test X X "07:04:03" "21:20:00"
+ format_string_test x x "02/07/70" "11/12/01"
+ format_string_test Y Y 1970 2001
+ format_string_test y y 70 01
+ format_string_test Z Z UTC UTC
+ format_string_test z z +0000 +0000
+ format_string_test percent % % %
+ format_string_test plus + "Sat Feb 7 07:04:03 UTC 1970" "Mon Nov 12 21:20:00 UTC 2001"
+}
diff --git a/bin/date/tests/legacy_test.sh b/bin/date/tests/legacy_test.sh
deleted file mode 100644
index 981bdd0..0000000
--- a/bin/date/tests/legacy_test.sh
+++ /dev/null
@@ -1,91 +0,0 @@
-#!/bin/sh
-
-#
-# Regression tests for date(1)
-#
-# Submitted by Edwin Groothuis <edwin@FreeBSD.org>
-#
-# $FreeBSD$
-#
-
-#
-# These two date/times have been chosen carefully, they
-# create both the single digit and double/multidigit version of
-# the values.
-#
-# To create a new one, make sure you are using the UTC timezone!
-#
-
-TEST1=3222243 # 1970-02-07 07:04:03
-TEST2=1005600000 # 2001-11-12 21:11:12
-
-export LC_ALL=C
-export TZ=UTC
-count=0
-
-check()
-{
- S=$1
- A1=$2
- A2=$3
-
- count=`expr ${count} + 1`
-
- if [ -z "${A2}" ]; then A2=${A1}; fi
-
- R=`date -r ${TEST1} +%${S}`
- if [ "${R}" = "${A1}" ]; then
- echo "ok ${S}{t1}"
- else
- echo "no ok ${S}{t1} - (got ${R}, expected ${A1})"
- fi
-
- R=`date -r ${TEST2} +%${S}`
- if [ "${R}" = "${A2}" ]; then
- echo "ok ${S}{t2}"
- else
- echo "no ok ${S}{t2} - (got ${R}, expected ${A2})"
- fi
-}
-
-echo "1..78"
-
-check A Saturday Monday
-check a Sat Mon
-check B February November
-check b Feb Nov
-check C 19 20
-check c "Sat Feb 7 07:04:03 1970" "Mon Nov 12 21:20:00 2001"
-check D 02/07/70 11/12/01
-check d 07 12
-check e " 7" 12
-check F "1970-02-07" "2001-11-12"
-check G 1970 2001
-check g 70 01
-check H 07 21
-check h Feb Nov
-check I 07 09
-check j 038 316
-check k " 7" 21
-check l " 7" " 9"
-check M 04 20
-check m 02 11
-check p AM PM
-check R 07:04 21:20
-check r "07:04:03 AM" "09:20:00 PM"
-check S 03 00
-check s ${TEST1} ${TEST2}
-check U 05 45
-check u 6 1
-check V 06 46
-check v " 7-Feb-1970" "12-Nov-2001"
-check W 05 46
-check w 6 1
-check X "07:04:03" "21:20:00"
-check x "02/07/70" "11/12/01"
-check Y 1970 2001
-check y 70 01
-check Z UTC UTC
-check z +0000 +0000
-check % % %
-check + "Sat Feb 7 07:04:03 UTC 1970" "Mon Nov 12 21:20:00 UTC 2001"
diff --git a/bin/dd/dd.1 b/bin/dd/dd.1
index 0541df8..1b4d57e 100644
--- a/bin/dd/dd.1
+++ b/bin/dd/dd.1
@@ -32,7 +32,7 @@
.\" @(#)dd.1 8.2 (Berkeley) 1/13/94
.\" $FreeBSD$
.\"
-.Dd April 2, 2014
+.Dd August 28, 2014
.Dt DD 1
.Os
.Sh NAME
@@ -408,6 +408,11 @@ To create an image of a Mode-1 CD-ROM, which is a commonly used format
for data CD-ROM disks, use a block size of 2048 bytes:
.Pp
.Dl "dd if=/dev/acd0 of=filename.iso bs=2048"
+.Pp
+Write a filesystem image to a memory stick, padding the end with zeros,
+if necessary, to a 1MiB boundary:
+.Pp
+.Dl "dd if=memstick.img of=/dev/da0 bs=1m conv=noerror,sync"
.Sh SEE ALSO
.Xr cp 1 ,
.Xr mt 1 ,
diff --git a/bin/df/Makefile b/bin/df/Makefile
index df6574c..fb7b09a 100644
--- a/bin/df/Makefile
+++ b/bin/df/Makefile
@@ -9,7 +9,7 @@ SRCS= df.c vfslist.c
CFLAGS+= -I${MOUNT}
-DPADD= ${LIBUTIL}
-LDADD= -lutil
+DPADD= ${LIBUTIL} ${LIBXO}
+LDADD= -lutil -lxo
.include <bsd.prog.mk>
diff --git a/bin/df/df.1 b/bin/df/df.1
index 85e1ab4..046247a 100644
--- a/bin/df/df.1
+++ b/bin/df/df.1
@@ -29,7 +29,7 @@
.\" @(#)df.1 8.3 (Berkeley) 5/8/95
.\" $FreeBSD$
.\"
-.Dd January 16, 2014
+.Dd November 6, 2014
.Dt DF 1
.Os
.Sh NAME
@@ -37,6 +37,7 @@
.Nd display free disk space
.Sh SYNOPSIS
.Nm
+.Op Fl -libxo
.Op Fl b | g | H | h | k | m | P
.Op Fl acilnT
.Op Fl \&,
@@ -193,7 +194,9 @@ If the value is outside, it will be set to the appropriate limit.
.Xr statfs 2 ,
.Xr getbsize 3 ,
.Xr getmntinfo 3 ,
+.Xr libxo 3 ,
.Xr localeconv 3 ,
+.Xr xo_parse_args 3 ,
.Xr fstab 5 ,
.Xr mount 8 ,
.Xr pstat 8 ,
diff --git a/bin/df/df.c b/bin/df/df.c
index 13ef129..997f789 100644
--- a/bin/df/df.c
+++ b/bin/df/df.c
@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
+#include <libxo/xo.h>
#include "extern.h"
@@ -82,7 +83,7 @@ static char *getmntpt(const char *);
static int int64width(int64_t);
static char *makenetvfslist(void);
static void prthuman(const struct statfs *, int64_t);
-static void prthumanval(int64_t);
+static void prthumanval(const char *, int64_t);
static intmax_t fsbtoblk(int64_t, uint64_t, u_long);
static void prtstat(struct statfs *, struct maxwidths *);
static size_t regetmntinfo(struct statfs **, long, const char **);
@@ -119,6 +120,11 @@ main(int argc, char *argv[])
totalbuf.f_bsize = DEV_BSIZE;
strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN);
vfslist = NULL;
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ exit(1);
+
while ((ch = getopt(argc, argv, "abcgHhiklmnPt:T,")) != -1)
switch (ch) {
case 'a':
@@ -161,7 +167,7 @@ main(int argc, char *argv[])
break;
case 'l':
if (vfslist != NULL)
- errx(1, "-l and -t are mutually exclusive.");
+ xo_errx(1, "-l and -t are mutually exclusive.");
vfslist = makevfslist(makenetvfslist());
lflag = 1;
break;
@@ -174,9 +180,9 @@ main(int argc, char *argv[])
break;
case 't':
if (lflag)
- errx(1, "-l and -t are mutually exclusive.");
+ xo_errx(1, "-l and -t are mutually exclusive.");
if (vfslist != NULL)
- errx(1, "only one -t option may be specified");
+ xo_errx(1, "only one -t option may be specified");
fstype = optarg;
vfslist = makevfslist(optarg);
break;
@@ -202,16 +208,19 @@ main(int argc, char *argv[])
/* just the filesystems specified on the command line */
mntbuf = malloc(argc * sizeof(*mntbuf));
if (mntbuf == NULL)
- err(1, "malloc()");
+ xo_err(1, "malloc()");
mntsize = 0;
/* continued in for loop below */
}
+ xo_open_container("storage-system-information");
+ xo_open_list("filesystem");
+
/* iterate through specified filesystems */
for (; *argv; argv++) {
if (stat(*argv, &stbuf) < 0) {
if ((mntpt = getmntpt(*argv)) == NULL) {
- warn("%s", *argv);
+ xo_warn("%s", *argv);
rv = 1;
continue;
}
@@ -220,20 +229,20 @@ main(int argc, char *argv[])
mdev.fspec = *argv;
mntpath = strdup("/tmp/df.XXXXXX");
if (mntpath == NULL) {
- warn("strdup failed");
+ xo_warn("strdup failed");
rv = 1;
continue;
}
mntpt = mkdtemp(mntpath);
if (mntpt == NULL) {
- warn("mkdtemp(\"%s\") failed", mntpath);
+ xo_warn("mkdtemp(\"%s\") failed", mntpath);
rv = 1;
free(mntpath);
continue;
}
if (mount(fstype, mntpt, MNT_RDONLY,
&mdev) != 0) {
- warn("%s", *argv);
+ xo_warn("%s", *argv);
rv = 1;
(void)rmdir(mntpt);
free(mntpath);
@@ -244,7 +253,7 @@ main(int argc, char *argv[])
if (cflag)
addstat(&totalbuf, &statfsbuf);
} else {
- warn("%s", *argv);
+ xo_warn("%s", *argv);
rv = 1;
}
(void)unmount(mntpt, 0);
@@ -260,7 +269,7 @@ main(int argc, char *argv[])
* implement nflag here.
*/
if (statfs(mntpt, &statfsbuf) < 0) {
- warn("%s", mntpt);
+ xo_warn("%s", mntpt);
rv = 1;
continue;
}
@@ -294,8 +303,14 @@ main(int argc, char *argv[])
for (i = 0; i < mntsize; i++)
if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
prtstat(&mntbuf[i], &maxwidths);
+
+ xo_close_list("filesystem");
+
if (cflag)
prtstat(&totalbuf, &maxwidths);
+
+ xo_close_container("storage-system-information");
+ xo_finish();
return (rv);
}
@@ -341,7 +356,7 @@ regetmntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
if (nflag || error < 0)
if (i != j) {
if (error < 0)
- warnx("%s stats possibly stale",
+ xo_warnx("%s stats possibly stale",
mntbuf[i].f_mntonname);
mntbuf[j] = mntbuf[i];
}
@@ -354,13 +369,13 @@ static void
prthuman(const struct statfs *sfsp, int64_t used)
{
- prthumanval(sfsp->f_blocks * sfsp->f_bsize);
- prthumanval(used * sfsp->f_bsize);
- prthumanval(sfsp->f_bavail * sfsp->f_bsize);
+ prthumanval(" {:blocks/%6s}", sfsp->f_blocks * sfsp->f_bsize);
+ prthumanval(" {:used/%6s}", used * sfsp->f_bsize);
+ prthumanval(" {:available/%6s}", sfsp->f_bavail * sfsp->f_bsize);
}
static void
-prthumanval(int64_t bytes)
+prthumanval(const char *fmt, int64_t bytes)
{
char buf[6];
int flags;
@@ -372,14 +387,15 @@ prthumanval(int64_t bytes)
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
bytes, "", HN_AUTOSCALE, flags);
- (void)printf(" %6s", buf);
+ xo_attr("value", "%lld", (long long) bytes);
+ xo_emit(fmt, buf);
}
/*
* Print an inode count in "human-readable" format.
*/
static void
-prthumanvalinode(int64_t bytes)
+prthumanvalinode(const char *fmt, int64_t bytes)
{
char buf[6];
int flags;
@@ -389,7 +405,8 @@ prthumanvalinode(int64_t bytes)
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
bytes, "", HN_AUTOSCALE, flags);
- (void)printf(" %5s", buf);
+ xo_attr("value", "%lld", (long long) bytes);
+ xo_emit(fmt, buf);
}
/*
@@ -434,70 +451,77 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp)
mwp->used = imax(mwp->used, (int)strlen("Used"));
mwp->avail = imax(mwp->avail, (int)strlen("Avail"));
- (void)printf("%-*s", mwp->mntfrom, "Filesystem");
+ xo_emit("{T:/%-*s}", mwp->mntfrom, "Filesystem");
if (Tflag)
- (void)printf(" %-*s", mwp->fstype, "Type");
- (void)printf(" %*s %*s %*s Capacity", mwp->total, header,
- mwp->used, "Used", mwp->avail, "Avail");
+ xo_emit(" {T:/%-*s}", mwp->fstype, "Type");
+ xo_emit(" {T:/%*s} {T:/%*s} {T:/%*s} Capacity",
+ mwp->total, header,
+ mwp->used, "Used", mwp->avail, "Avail");
if (iflag) {
mwp->iused = imax(hflag ? 0 : mwp->iused,
(int)strlen(" iused"));
mwp->ifree = imax(hflag ? 0 : mwp->ifree,
(int)strlen("ifree"));
- (void)printf(" %*s %*s %%iused",
+ xo_emit(" {T:/%*s} {T:/%*s} {T:\%iused}",
mwp->iused - 2, "iused", mwp->ifree, "ifree");
}
- (void)printf(" Mounted on\n");
+ xo_emit(" {T:Mounted on}\n");
}
+
+ xo_open_instance("filesystem");
/* Check for 0 block size. Can this happen? */
if (sfsp->f_bsize == 0) {
- warnx ("File system %s does not have a block size, assuming 512.",
+ xo_warnx ("File system %s does not have a block size, assuming 512.",
sfsp->f_mntonname);
sfsp->f_bsize = 512;
}
- (void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
+ xo_emit("{tk:name/%-*s}", mwp->mntfrom, sfsp->f_mntfromname);
if (Tflag)
- (void)printf(" %-*s", mwp->fstype, sfsp->f_fstypename);
+ xo_emit(" {:type/%-*s}", mwp->fstype, sfsp->f_fstypename);
used = sfsp->f_blocks - sfsp->f_bfree;
availblks = sfsp->f_bavail + used;
if (hflag) {
prthuman(sfsp, used);
} else {
if (thousands)
- format = " %*j'd %*j'd %*j'd";
+ format = " {t:total-blocks/%*j'd} {t:used-blocks/%*j'd} "
+ "{t:available-blocks/%*j'd}";
else
- format = " %*jd %*jd %*jd";
- (void)printf(format,
+ format = " {t:total-blocks/%*jd} {t:used-blocks/%*jd} "
+ "{t:available-blocks/%*jd}";
+ xo_emit(format,
mwp->total, fsbtoblk(sfsp->f_blocks,
sfsp->f_bsize, blocksize),
mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize),
mwp->avail, fsbtoblk(sfsp->f_bavail,
sfsp->f_bsize, blocksize));
}
- (void)printf(" %5.0f%%",
+ xo_emit(" {:used-percent/%5.0f}{U:%%}",
availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
if (iflag) {
inodes = sfsp->f_files;
used = inodes - sfsp->f_ffree;
if (hflag) {
- (void)printf(" ");
- prthumanvalinode(used);
- prthumanvalinode(sfsp->f_ffree);
+ xo_emit(" ");
+ prthumanvalinode(" {:inodes-used/%5s}", used);
+ prthumanvalinode(" {:inodes-free/%5s}", sfsp->f_ffree);
} else {
if (thousands)
- format = " %*j'd %*j'd";
+ format = " {:inodes-used/%*j'd} {:inodes-free/%*j'd}";
else
- format = " %*jd %*jd";
- (void)printf(format, mwp->iused, (intmax_t)used,
+ format = " {:inodes-used/%*jd} {:inodes-free/%*jd}";
+ xo_emit(format, mwp->iused, (intmax_t)used,
mwp->ifree, (intmax_t)sfsp->f_ffree);
}
- (void)printf(" %4.0f%% ", inodes == 0 ? 100.0 :
- (double)used / (double)inodes * 100.0);
+ xo_emit(" {:inodes-used-percent/%4.0f}{U:%%} ",
+ inodes == 0 ? 100.0 :
+ (double)used / (double)inodes * 100.0);
} else
- (void)printf(" ");
+ xo_emit(" ");
if (strncmp(sfsp->f_mntfromname, "total", MNAMELEN) != 0)
- (void)printf(" %s", sfsp->f_mntonname);
- (void)printf("\n");
+ xo_emit(" {:mounted-on}", sfsp->f_mntonname);
+ xo_emit("\n");
+ xo_close_instance("filesystem");
}
static void
@@ -564,7 +588,7 @@ static void
usage(void)
{
- (void)fprintf(stderr,
+ xo_error(
"usage: df [-b | -g | -H | -h | -k | -m | -P] [-acilnT] [-t type] [-,]\n"
" [file | filesystem ...]\n");
exit(EX_USAGE);
@@ -579,24 +603,24 @@ makenetvfslist(void)
int cnt, i, maxvfsconf;
if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) {
- warn("sysctl(vfs.conflist)");
+ xo_warn("sysctl(vfs.conflist)");
return (NULL);
}
xvfsp = malloc(buflen);
if (xvfsp == NULL) {
- warnx("malloc failed");
+ xo_warnx("malloc failed");
return (NULL);
}
keep_xvfsp = xvfsp;
if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) {
- warn("sysctl(vfs.conflist)");
+ xo_warn("sysctl(vfs.conflist)");
free(keep_xvfsp);
return (NULL);
}
maxvfsconf = buflen / sizeof(struct xvfsconf);
if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
- warnx("malloc failed");
+ xo_warnx("malloc failed");
free(keep_xvfsp);
return (NULL);
}
@@ -605,7 +629,7 @@ makenetvfslist(void)
if (xvfsp->vfc_flags & VFCF_NETWORK) {
listptr[cnt++] = strdup(xvfsp->vfc_name);
if (listptr[cnt-1] == NULL) {
- warnx("malloc failed");
+ xo_warnx("malloc failed");
free(listptr);
free(keep_xvfsp);
return (NULL);
@@ -617,7 +641,7 @@ makenetvfslist(void)
if (cnt == 0 ||
(str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
if (cnt > 0)
- warnx("malloc failed");
+ xo_warnx("malloc failed");
free(listptr);
free(keep_xvfsp);
return (NULL);
diff --git a/bin/ed/cbc.c b/bin/ed/cbc.c
index 31838f5..80ed95a 100644
--- a/bin/ed/cbc.c
+++ b/bin/ed/cbc.c
@@ -237,7 +237,7 @@ expand_des_key(char *obuf, char *kbuf)
/*
* now translate it, bombing on any illegal hex digit
*/
- for (i = 0; kbuf[i] && i < 16; i++)
+ for (i = 0; i < 16 && kbuf[i]; i++)
if ((nbuf[i] = hex_to_binary((int) kbuf[i], 16)) == -1)
des_error("bad hex digit in key");
while (i < 16)
diff --git a/bin/pkill/tests/Makefile b/bin/pkill/tests/Makefile
index b131d59..a4a2c91 100644
--- a/bin/pkill/tests/Makefile
+++ b/bin/pkill/tests/Makefile
@@ -14,6 +14,7 @@ TAP_TESTS_SH+= pgrep-g_test
TAP_TESTS_SH+= pgrep-i_test
TAP_TESTS_SH+= pgrep-j_test
TEST_METADATA.pgrep-j_test+= required_user="root"
+TEST_METADATA.pgrep-j_test+= required_programs="jail jls"
TAP_TESTS_SH+= pgrep-l_test
TAP_TESTS_SH+= pgrep-n_test
TAP_TESTS_SH+= pgrep-o_test
@@ -31,6 +32,7 @@ TAP_TESTS_SH+= pkill-g_test
TAP_TESTS_SH+= pkill-i_test
TAP_TESTS_SH+= pkill-j_test
TEST_METADATA.pkill-j_test+= required_user="root"
+TEST_METADATA.pkill-j_test+= required_programs="jail jls"
TAP_TESTS_SH+= pkill-s_test
TAP_TESTS_SH+= pkill-t_test
TAP_TESTS_SH+= pkill-x_test
diff --git a/bin/pkill/tests/pgrep-j_test.sh b/bin/pkill/tests/pgrep-j_test.sh
index 6656a9b..6acfb4b 100644
--- a/bin/pkill/tests/pgrep-j_test.sh
+++ b/bin/pkill/tests/pgrep-j_test.sh
@@ -1,7 +1,23 @@
#!/bin/sh
# $FreeBSD$
-base=`basename $0`
+jail_name_to_jid()
+{
+ local check_name="$1"
+ (
+ line="$(jls -n 2> /dev/null | grep name=$check_name )"
+ for nv in $line; do
+ local name="${nv%=*}"
+ if [ "${name}" = "jid" ]; then
+ eval $nv
+ echo $jid
+ break
+ fi
+ done
+ )
+}
+
+base=pgrep_j_test
echo "1..3"
@@ -9,21 +25,25 @@ name="pgrep -j <jid>"
if [ `id -u` -eq 0 ]; then
sleep=$(pwd)/sleep.txt
ln -sf /bin/sleep $sleep
- jail / $base-1 127.0.0.1 $sleep 5 &
- chpid=$!
- jail / $base-2 127.0.0.1 $sleep 5 &
- chpid2=$!
- $sleep 5 &
- chpid3=$!
- sleep 0.5
- jid=`jls | awk "/127\\.0\\.0\\.1.*${base}-1/ {print \$1}"`
- pid=`pgrep -f -j $jid $sleep`
- if [ "$pid" = "$chpid" ]; then
+ jail -c path=/ name=${base}_1_1 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_1_1.pid $sleep 5 &
+
+ jail -c path=/ name=${base}_1_2 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_1_2.pid $sleep 5 &
+
+ jid1=$(jail_name_to_jid ${base}_1_1)
+ jid2=$(jail_name_to_jid ${base}_1_2)
+ jid="${jid1},${jid2}"
+ pid1="$(pgrep -f -x -j $jid "$sleep 5" | sort)"
+ pid2=$(printf "%s\n%s" "$(cat ${PWD}/${base}_1_1.pid)" \
+ $(cat ${PWD}/${base}_1_2.pid) | sort)
+ if [ "$pid1" = "$pid2" ]; then
echo "ok 1 - $name"
else
echo "not ok 1 - $name"
fi
- kill $chpid $chpid2 $chpid3
+ [ -f ${PWD}/${base}_1_1.pid ] && kill $(cat ${PWD}/${base}_1_1.pid)
+ [ -f ${PWD}/${base}_1_2.pid ] && kill $(cat ${PWD}/${base}_1_2.pid)
rm -f $sleep
else
echo "ok 1 - $name # skip Test needs uid 0."
@@ -33,21 +53,23 @@ name="pgrep -j any"
if [ `id -u` -eq 0 ]; then
sleep=$(pwd)/sleep.txt
ln -sf /bin/sleep $sleep
- jail / $base-1 127.0.0.1 $sleep 5 &
- chpid=$!
- jail / $base-2 127.0.0.1 $sleep 5 &
- chpid2=$!
- $sleep 5 &
- chpid3=$!
- sleep 0.5
- pids=`pgrep -f -j any $sleep | sort`
- refpids=`{ echo $chpid; echo $chpid2; } | sort`
- if [ "$pids" = "$refpids" ]; then
+ jail -c path=/ name=${base}_2_1 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_2_1.pid $sleep 5 &
+
+ jail -c path=/ name=${base}_2_2 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_2_2.pid $sleep 5 &
+
+ sleep 2
+ pid1="$(pgrep -f -x -j any "$sleep 5" | sort)"
+ pid2=$(printf "%s\n%s" "$(cat ${PWD}/${base}_2_1.pid)" \
+ $(cat ${PWD}/${base}_2_2.pid) | sort)
+ if [ "$pid1" = "$pid2" ]; then
echo "ok 2 - $name"
else
echo "not ok 2 - $name"
fi
- kill $chpid $chpid2 $chpid3
+ [ -f ${PWD}/${base}_2_1.pid ] && kill $(cat ${PWD}/${base}_2_1.pid)
+ [ -f ${PWD}/${base}_2_2.pid ] && kill $(cat ${PWD}/${base}_2_2.pid)
rm -f $sleep
else
echo "ok 2 - $name # skip Test needs uid 0."
@@ -57,19 +79,19 @@ name="pgrep -j none"
if [ `id -u` -eq 0 ]; then
sleep=$(pwd)/sleep.txt
ln -sf /bin/sleep $sleep
- $sleep 5 &
- chpid=$!
- jail / $base 127.0.0.1 $sleep 5 &
- chpid2=$!
- sleep 0.5
- pid=`pgrep -f -j none $sleep`
- if [ "$pid" = "$chpid" ]; then
+ daemon -p ${PWD}/${base}_3_1.pid $sleep 5 &
+ jail -c path=/ name=${base}_3_2 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_3_2.pid $sleep 5 &
+ sleep 2
+ pid="$(pgrep -f -x -j none "$sleep 5")"
+ if [ "$pid" = "$(cat ${PWD}/${base}_3_1.pid)" ]; then
echo "ok 3 - $name"
else
echo "not ok 3 - $name"
fi
- kill $chpid $chpid2
rm -f $sleep
+ [ -f ${PWD}/${base}_3_1.pid ] && kill $(cat $PWD/${base}_3_1.pid)
+ [ -f ${PWD}/${base}_3_2.pid ] && kill $(cat $PWD/${base}_3_2.pid)
else
echo "ok 3 - $name # skip Test needs uid 0."
fi
diff --git a/bin/pkill/tests/pkill-j_test.sh b/bin/pkill/tests/pkill-j_test.sh
index 48e7c72..a844149 100644
--- a/bin/pkill/tests/pkill-j_test.sh
+++ b/bin/pkill/tests/pkill-j_test.sh
@@ -1,7 +1,23 @@
#!/bin/sh
# $FreeBSD$
-base=`basename $0`
+jail_name_to_jid()
+{
+ local check_name="$1"
+ (
+ line="$(jls -n 2> /dev/null | grep name=$check_name )"
+ for nv in $line; do
+ local name="${nv%=*}"
+ if [ "${name}" = "jid" ]; then
+ eval $nv
+ echo $jid
+ break
+ fi
+ done
+ )
+}
+
+base=pkill_j_test
echo "1..3"
@@ -9,21 +25,28 @@ name="pkill -j <jid>"
if [ `id -u` -eq 0 ]; then
sleep=$(pwd)/sleep.txt
ln -sf /bin/sleep $sleep
- jail / $base-1 127.0.0.1 $sleep 5 &
- chpid=$!
- jail / $base-2 127.0.0.1 $sleep 5 &
- chpid2=$!
+ jail -c path=/ name=${base}_1_1 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_1_1.pid $sleep 5 &
+
+ jail -c path=/ name=${base}_1_2 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_1_2.pid $sleep 5 &
+
$sleep 5 &
- chpid3=$!
sleep 0.5
- jid=`jls | awk "/127\\.0\\.0\\.1.*${base}-1/ {print \$1}"`
- if pkill -f -j $jid $sleep && sleep 0.5 &&
- ! kill $chpid && kill $chpid2 $chpid3; then
+ jid1=$(jail_name_to_jid ${base}_1_1)
+ jid2=$(jail_name_to_jid ${base}_1_2)
+ jid="${jid1},${jid2}"
+ if pkill -f -j "$jid" $sleep && sleep 0.5 &&
+ ! -f ${PWD}/${base}_1_1.pid &&
+ ! -f ${PWD}/${base}_1_2.pid ; then
echo "ok 1 - $name"
else
echo "not ok 1 - $name"
fi 2>/dev/null
rm -f $sleep
+ [ -f ${PWD}/${base}_1_1.pid ] && kill $(cat ${PWD}/${base}_1_1.pid)
+ [ -f ${PWD}/${base}_1_2.pid ] && kill $(cat ${PWD}/${base}_1_2.pid)
+ wait
else
echo "ok 1 - $name # skip Test needs uid 0."
fi
@@ -32,20 +55,26 @@ name="pkill -j any"
if [ `id -u` -eq 0 ]; then
sleep=$(pwd)/sleep.txt
ln -sf /bin/sleep $sleep
- jail / $base-1 127.0.0.1 $sleep 5 &
- chpid=$!
- jail / $base-2 127.0.0.1 $sleep 5 &
- chpid2=$!
+ jail -c path=/ name=${base}_2_1 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_2_1.pid $sleep 5 &
+
+ jail -c path=/ name=${base}_2_2 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_2_2.pid $sleep 5 &
+
$sleep 5 &
- chpid3=$!
sleep 0.5
+ chpid3=$!
if pkill -f -j any $sleep && sleep 0.5 &&
- ! kill $chpid && ! kill $chpid2 && kill $chpid3; then
+ [ ! -f ${PWD}/${base}_2_1.pid -a
+ ! -f ${PWD}/${base}_2_2.pid ] && kill $chpid3; then
echo "ok 2 - $name"
else
echo "not ok 2 - $name"
fi 2>/dev/null
rm -f $sleep
+ [ -f ${PWD}/${base}_2_1.pid ] && kill $(cat ${PWD}/${base}_2_1.pid)
+ [ -f ${PWD}/${base}_2_2.pid ] && kill $(cat ${PWD}/${base}_2_2.pid)
+ wait
else
echo "ok 2 - $name # skip Test needs uid 0."
fi
@@ -54,18 +83,20 @@ name="pkill -j none"
if [ `id -u` -eq 0 ]; then
sleep=$(pwd)/sleep.txt
ln -sf /bin/sleep $sleep
- $sleep 5 &
- chpid=$!
- jail / $base 127.0.0.1 $sleep 5 &
- chpid2=$!
- sleep 0.5
- if pkill -f -j none $sleep && sleep 0.5 &&
- ! kill $chpid && kill $chpid2; then
+ daemon -p ${PWD}/${base}_3_1.pid $sleep 5
+ jail -c path=/ name=${base}_3_2 ip4.addr=127.0.0.1 \
+ command=daemon -p ${PWD}/${base}_3_2.pid $sleep 5 &
+ sleep 1
+ if pkill -f -j none "$sleep 5" && sleep 1 &&
+ [ ! -f ${PWD}/${base}_3_1.pid -a -f ${PWD}/${base}_3_2.pid ] ; then
echo "ok 3 - $name"
else
+ ls ${PWD}/*.pid
echo "not ok 3 - $name"
fi 2>/dev/null
rm -f $sleep
+ [ -f ${PWD}/${base}_3_1.pid ] && kill $(cat ${base}_3_1.pid)
+ [ -f ${PWD}/${base}_3_2.pid ] && kill $(cat ${base}_3_2.pid)
else
echo "ok 3 - $name # skip Test needs uid 0."
fi
diff --git a/bin/ps/keyword.c b/bin/ps/keyword.c
index 3a0c323..38a9934 100644
--- a/bin/ps/keyword.c
+++ b/bin/ps/keyword.c
@@ -157,6 +157,7 @@ static VAR var[] = {
{"tdnam", "TDNAM", NULL, LJUST, tdnam, 0, CHAR, NULL, 0},
{"time", "TIME", NULL, USER, cputime, 0, CHAR, NULL, 0},
{"tpgid", "TPGID", NULL, 0, kvar, KOFF(ki_tpgid), UINT, PIDFMT, 0},
+ {"tracer", "TRACER", NULL, 0, kvar, KOFF(ki_tracer), UINT, PIDFMT, 0},
{"tsid", "TSID", NULL, 0, kvar, KOFF(ki_tsid), UINT, PIDFMT, 0},
{"tsiz", "TSIZ", NULL, 0, kvar, KOFF(ki_tsize), PGTOK, "ld", 0},
{"tt", "TT ", NULL, 0, tname, 0, CHAR, NULL, 0},
diff --git a/bin/ps/ps.1 b/bin/ps/ps.1
index 3d7edf7..294ecf9 100644
--- a/bin/ps/ps.1
+++ b/bin/ps/ps.1
@@ -29,7 +29,7 @@
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
.\" $FreeBSD$
.\"
-.Dd June 6, 2014
+.Dd August 27, 2014
.Dt PS 1
.Os
.Sh NAME
@@ -332,7 +332,6 @@ the include file
.It Dv "P_SINGLE_BOUNDARY" Ta No "0x400000" Ta "Threads should suspend at user boundary"
.It Dv "P_HWPMC" Ta No "0x800000" Ta "Process is using HWPMCs"
.It Dv "P_JAILED" Ta No "0x1000000" Ta "Process is in jail"
-.It Dv "P_ORPHAN" Ta No "0x2000000" Ta "Orphaned by original parent, reparented to debugger"
.It Dv "P_INEXEC" Ta No "0x4000000" Ta "Process is in execve()"
.It Dv "P_STATCHILD" Ta No "0x8000000" Ta "Child process stopped or exited"
.It Dv "P_INMEM" Ta No "0x10000000" Ta "Loaded into memory"
@@ -666,6 +665,8 @@ accumulated CPU time, user + system (alias
.Cm cputime )
.It Cm tpgid
control terminal process group ID
+.It Cm tracer
+tracer process ID
.\".It Cm trss
.\"text resident set size (in Kbytes)
.It Cm tsid
diff --git a/bin/rmail/Makefile b/bin/rmail/Makefile
index c07c9e1..ad788a4 100644
--- a/bin/rmail/Makefile
+++ b/bin/rmail/Makefile
@@ -14,8 +14,6 @@ MAN= rmail.8
WARNS?= 2
CFLAGS+=-I${SENDMAIL_DIR}/include -I.
-NO_PIE= yes
-
LIBSMDIR= ${.OBJDIR}/../../lib/libsm
LIBSM= ${LIBSMDIR}/libsm.a
diff --git a/bin/sh/arith_yacc.c b/bin/sh/arith_yacc.c
index 815d885..5000c6b 100644
--- a/bin/sh/arith_yacc.c
+++ b/bin/sh/arith_yacc.c
@@ -139,9 +139,9 @@ static arith_t do_binop(int op, arith_t a, arith_t b)
case ARITH_SUB:
return (uintmax_t)a - (uintmax_t)b;
case ARITH_LSHIFT:
- return (uintmax_t)a << b;
+ return (uintmax_t)a << (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
case ARITH_RSHIFT:
- return a >> b;
+ return a >> (b & (sizeof(uintmax_t) * CHAR_BIT - 1));
case ARITH_LT:
return a < b;
case ARITH_LE:
diff --git a/bin/sh/eval.c b/bin/sh/eval.c
index 3fd3050..c1a9cdb 100644
--- a/bin/sh/eval.c
+++ b/bin/sh/eval.c
@@ -168,6 +168,8 @@ evalstring(char *s, int flags)
else
evaltree(n, flags);
any = 1;
+ if (evalskip)
+ break;
}
popstackmark(&smark);
setstackmark(&smark);
@@ -316,9 +318,10 @@ evalloop(union node *n, int flags)
loopnest++;
status = 0;
for (;;) {
- evaltree(n->nbinary.ch1, EV_TESTED);
+ if (!evalskip)
+ evaltree(n->nbinary.ch1, EV_TESTED);
if (evalskip) {
-skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
+ if (evalskip == SKIPCONT && --skipcount <= 0) {
evalskip = 0;
continue;
}
@@ -337,8 +340,6 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) {
}
evaltree(n->nbinary.ch2, flags);
status = exitstatus;
- if (evalskip)
- goto skipping;
}
loopnest--;
exitstatus = status;
@@ -648,15 +649,15 @@ evalbackcmd(union node *n, struct backcmd *result)
struct jmploc *savehandler;
struct localvar *savelocalvars;
- setstackmark(&smark);
result->fd = -1;
result->buf = NULL;
result->nleft = 0;
result->jp = NULL;
if (n == NULL) {
exitstatus = 0;
- goto out;
+ return;
}
+ setstackmark(&smark);
exitstatus = oexitstatus;
if (is_valid_fast_cmdsubst(n)) {
savelocalvars = localvars;
@@ -698,7 +699,6 @@ evalbackcmd(union node *n, struct backcmd *result)
result->fd = pip[0];
result->jp = jp;
}
-out:
popstackmark(&smark);
TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n",
result->fd, result->buf, result->nleft, result->jp));
@@ -1039,6 +1039,7 @@ evalcommand(union node *cmd, int flags, struct backcmd *backcmd)
shellparam.reset = 1;
shellparam.nparam = argc - 1;
shellparam.p = argv + 1;
+ shellparam.optp = NULL;
shellparam.optnext = NULL;
INTOFF;
savelocalvars = localvars;
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index 15afc9c..d4c4c5a 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -328,24 +328,19 @@ exptilde(char *p, int flag)
done:
*p = '\0';
if (*(startp+1) == '\0') {
- if ((home = lookupvar("HOME")) == NULL)
- goto lose;
+ home = lookupvar("HOME");
} else {
- if ((pw = getpwnam(startp+1)) == NULL)
- goto lose;
- home = pw->pw_dir;
+ pw = getpwnam(startp+1);
+ home = pw != NULL ? pw->pw_dir : NULL;
}
- if (*home == '\0')
- goto lose;
*p = c;
+ if (home == NULL || *home == '\0')
+ return (startp);
if (quotes)
STPUTS_QUOTES(home, SQSYNTAX, expdest);
else
STPUTS(home, expdest);
return (p);
-lose:
- *p = c;
- return (startp);
}
@@ -867,7 +862,7 @@ varisset(const char *name, int nulok)
static void
strtodest(const char *p, int flag, int subtype, int quoted)
{
- if (flag & (EXP_FULL | EXP_CASE) && subtype != VSLENGTH)
+ if (flag & (EXP_FULL | EXP_CASE | EXP_REDIR) && subtype != VSLENGTH)
STPUTS_QUOTES(p, quoted ? DQSYNTAX : BASESYNTAX, expdest);
else
STPUTS(p, expdest);
@@ -883,30 +878,28 @@ varvalue(const char *name, int quoted, int subtype, int flag)
int num;
char *p;
int i;
- char sep;
+ char sep[2];
char **ap;
switch (*name) {
case '$':
num = rootpid;
- goto numvar;
+ break;
case '?':
num = oexitstatus;
- goto numvar;
+ break;
case '#':
num = shellparam.nparam;
- goto numvar;
+ break;
case '!':
num = backgndpidval();
-numvar:
- expdest = cvtnum(num, expdest);
break;
case '-':
for (i = 0 ; i < NOPTS ; i++) {
if (optlist[i].val)
STPUTC(optlist[i].letter, expdest);
}
- break;
+ return;
case '@':
if (flag & EXP_FULL && quoted) {
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
@@ -914,22 +907,25 @@ numvar:
if (*ap)
STPUTC('\0', expdest);
}
- break;
+ return;
}
/* FALLTHROUGH */
case '*':
if (ifsset())
- sep = ifsval()[0];
+ sep[0] = ifsval()[0];
else
- sep = ' ';
+ sep[0] = ' ';
+ sep[1] = '\0';
for (ap = shellparam.p ; (p = *ap++) != NULL ; ) {
strtodest(p, flag, subtype, quoted);
if (!*ap)
break;
- if (sep || (flag & EXP_FULL && !quoted && **ap != '\0'))
- STPUTC(sep, expdest);
+ if (sep[0])
+ strtodest(sep, flag, subtype, quoted);
+ else if (flag & EXP_FULL && !quoted && **ap != '\0')
+ STPUTC('\0', expdest);
}
- break;
+ return;
default:
if (is_digit(*name)) {
num = atoi(name);
@@ -938,11 +934,12 @@ numvar:
else if (num > 0 && num <= shellparam.nparam)
p = shellparam.p[num - 1];
else
- break;
+ return;
strtodest(p, flag, subtype, quoted);
}
- break;
+ return;
}
+ expdest = cvtnum(num, expdest);
}
@@ -1110,24 +1107,23 @@ expandmeta(struct strlist *str, int flag __unused)
/* TODO - EXP_REDIR */
while (str) {
- if (fflag)
- goto nometa;
- p = str->text;
- for (;;) { /* fast check for meta chars */
- if ((c = *p++) == '\0')
- goto nometa;
- if (c == '*' || c == '?' || c == '[')
- break;
- }
savelastp = exparg.lastp;
- INTOFF;
- expmeta(expdir, str->text);
- INTON;
+ if (!fflag) {
+ p = str->text;
+ for (; (c = *p) != '\0'; p++) {
+ /* fast check for meta chars */
+ if (c == '*' || c == '?' || c == '[') {
+ INTOFF;
+ expmeta(expdir, str->text);
+ INTON;
+ break;
+ }
+ }
+ }
if (exparg.lastp == savelastp) {
/*
* no matches
*/
-nometa:
*exparg.lastp = str;
rmescapes(str->text);
exparg.lastp = &str->next;
diff --git a/bin/sh/histedit.c b/bin/sh/histedit.c
index a8c376a..c65d1c7 100644
--- a/bin/sh/histedit.c
+++ b/bin/sh/histedit.c
@@ -166,9 +166,10 @@ sethistsize(const char *hs)
HistEvent he;
if (hist != NULL) {
- if (hs == NULL || *hs == '\0' ||
- (histsize = atoi(hs)) < 0)
+ if (hs == NULL || !is_number(hs))
histsize = 100;
+ else
+ histsize = atoi(hs);
history(hist, &he, H_SETSIZE, histsize);
history(hist, &he, H_SETUNIQUE, 1);
}
diff --git a/bin/sh/input.c b/bin/sh/input.c
index 05cc1eb..412f144 100644
--- a/bin/sh/input.c
+++ b/bin/sh/input.c
@@ -116,33 +116,6 @@ resetinput(void)
}
-/*
- * Read a line from the script.
- */
-
-char *
-pfgets(char *line, int len)
-{
- char *p = line;
- int nleft = len;
- int c;
-
- while (--nleft > 0) {
- c = pgetc_macro();
- if (c == PEOF) {
- if (p == line)
- return NULL;
- break;
- }
- *p++ = c;
- if (c == '\n')
- break;
- }
- *p = '\0';
- return line;
-}
-
-
/*
* Read a character from the script, returning PEOF on end of file.
@@ -338,7 +311,7 @@ pungetc(void)
* We handle aliases this way.
*/
void
-pushstring(char *s, int len, struct alias *ap)
+pushstring(const char *s, int len, struct alias *ap)
{
struct strpush *sp;
diff --git a/bin/sh/input.h b/bin/sh/input.h
index cc54eed..cb0af77 100644
--- a/bin/sh/input.h
+++ b/bin/sh/input.h
@@ -48,12 +48,11 @@ struct alias;
struct parsefile;
void resetinput(void);
-char *pfgets(char *, int);
int pgetc(void);
int preadbuffer(void);
int preadateof(void);
void pungetc(void);
-void pushstring(char *, int, struct alias *);
+void pushstring(const char *, int, struct alias *);
void setinputfile(const char *, int);
void setinputfd(int, int);
void setinputstring(const char *, int);
diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c
index 93553c1..765e6a2 100644
--- a/bin/sh/jobs.c
+++ b/bin/sh/jobs.c
@@ -118,6 +118,24 @@ static void showjob(struct job *, int);
static int jobctl;
#if JOBS
+static void
+jobctl_notty(void)
+{
+ if (ttyfd >= 0) {
+ close(ttyfd);
+ ttyfd = -1;
+ }
+ if (!iflag) {
+ setsignal(SIGTSTP);
+ setsignal(SIGTTOU);
+ setsignal(SIGTTIN);
+ jobctl = 1;
+ return;
+ }
+ out2fmt_flush("sh: can't access tty; job control turned off\n");
+ mflag = 0;
+}
+
void
setjobctl(int on)
{
@@ -133,8 +151,10 @@ setjobctl(int on)
while (i <= 2 && !isatty(i))
i++;
if (i > 2 ||
- (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0)
- goto out;
+ (ttyfd = fcntl(i, F_DUPFD_CLOEXEC, 10)) < 0) {
+ jobctl_notty();
+ return;
+ }
}
if (ttyfd < 10) {
/*
@@ -142,9 +162,8 @@ setjobctl(int on)
* the user's redirections.
*/
if ((i = fcntl(ttyfd, F_DUPFD_CLOEXEC, 10)) < 0) {
- close(ttyfd);
- ttyfd = -1;
- goto out;
+ jobctl_notty();
+ return;
}
close(ttyfd);
ttyfd = i;
@@ -152,11 +171,15 @@ setjobctl(int on)
do { /* while we are in the background */
initialpgrp = tcgetpgrp(ttyfd);
if (initialpgrp < 0) {
-out: out2fmt_flush("sh: can't access tty; job control turned off\n");
- mflag = 0;
+ jobctl_notty();
return;
}
if (initialpgrp != getpgrp()) {
+ if (!iflag) {
+ initialpgrp = -1;
+ jobctl_notty();
+ return;
+ }
kill(0, SIGTTIN);
continue;
}
@@ -168,9 +191,11 @@ out: out2fmt_flush("sh: can't access tty; job control turned off\n");
tcsetpgrp(ttyfd, rootpid);
} else { /* turning job control off */
setpgid(0, initialpgrp);
- tcsetpgrp(ttyfd, initialpgrp);
- close(ttyfd);
- ttyfd = -1;
+ if (ttyfd >= 0) {
+ tcsetpgrp(ttyfd, initialpgrp);
+ close(ttyfd);
+ ttyfd = -1;
+ }
setsignal(SIGTSTP);
setsignal(SIGTTOU);
setsignal(SIGTTIN);
@@ -195,7 +220,8 @@ fgcmd(int argc __unused, char **argv __unused)
printjobcmd(jp);
flushout(&output);
pgrp = jp->ps[0].pid;
- tcsetpgrp(ttyfd, pgrp);
+ if (ttyfd >= 0)
+ tcsetpgrp(ttyfd, pgrp);
restartjob(jp);
jp->foreground = 1;
INTOFF;
@@ -347,13 +373,13 @@ showjob(struct job *jp, int mode)
strcat(statestr, " (core dumped)");
}
- for (ps = jp->ps ; ; ps++) { /* for each process */
+ for (ps = jp->ps ; procno > 0 ; ps++, procno--) { /* for each process */
if (mode == SHOWJOBS_PIDS || mode == SHOWJOBS_PGIDS) {
out1fmt("%d\n", (int)ps->pid);
- goto skip;
+ continue;
}
if (mode != SHOWJOBS_VERBOSE && ps != jp->ps)
- goto skip;
+ continue;
if (jobno == curr && ps == jp->ps)
c = '+';
else if (jobno == prev && ps == jp->ps)
@@ -384,8 +410,6 @@ showjob(struct job *jp, int mode)
out1c('\n');
} else
printjobcmd(jp);
-skip: if (--procno <= 0)
- break;
}
}
@@ -568,23 +592,23 @@ getjob_nonotfound(const char *name)
if (name == NULL) {
#if JOBS
-currentjob: if ((jp = getcurjob(NULL)) == NULL)
- error("No current job");
- return (jp);
+ name = "%+";
#else
error("No current job");
#endif
- } else if (name[0] == '%') {
+ }
+ if (name[0] == '%') {
if (is_digit(name[1])) {
jobno = number(name + 1);
if (jobno > 0 && jobno <= njobs
&& jobtab[jobno - 1].used != 0)
return &jobtab[jobno - 1];
#if JOBS
- } else if (name[1] == '%' && name[2] == '\0') {
- goto currentjob;
- } else if (name[1] == '+' && name[2] == '\0') {
- goto currentjob;
+ } else if ((name[1] == '%' || name[1] == '+') &&
+ name[2] == '\0') {
+ if ((jp = getcurjob(NULL)) == NULL)
+ error("No current job");
+ return (jp);
} else if (name[1] == '-' && name[2] == '\0') {
if ((jp = getcurjob(NULL)) == NULL ||
(jp = getcurjob(jp)) == NULL)
@@ -847,7 +871,8 @@ forkshell(struct job *jp, union node *n, int mode)
pgrp = getpid();
else
pgrp = jp->ps[0].pid;
- if (setpgid(0, pgrp) == 0 && mode == FORK_FG) {
+ if (setpgid(0, pgrp) == 0 && mode == FORK_FG &&
+ ttyfd >= 0) {
/*** this causes superfluous TIOCSPGRPS ***/
if (tcsetpgrp(ttyfd, pgrp) < 0)
error("tcsetpgrp failed, errno=%d", errno);
@@ -1007,7 +1032,7 @@ waitforjob(struct job *jp, int *origstatus)
dotrap();
#if JOBS
if (jp->jobctl) {
- if (tcsetpgrp(ttyfd, rootpid) < 0)
+ if (ttyfd >= 0 && tcsetpgrp(ttyfd, rootpid) < 0)
error("tcsetpgrp failed, errno=%d\n", errno);
}
if (jp->state == JOBSTOPPED)
@@ -1263,13 +1288,43 @@ commandtext(union node *n)
static void
+cmdtxtdogroup(union node *n)
+{
+ cmdputs("; do ");
+ cmdtxt(n);
+ cmdputs("; done");
+}
+
+
+static void
+cmdtxtredir(union node *n, const char *op, int deffd)
+{
+ char s[2];
+
+ if (n->nfile.fd != deffd) {
+ s[0] = n->nfile.fd + '0';
+ s[1] = '\0';
+ cmdputs(s);
+ }
+ cmdputs(op);
+ if (n->type == NTOFD || n->type == NFROMFD) {
+ if (n->ndup.dupfd >= 0)
+ s[0] = n->ndup.dupfd + '0';
+ else
+ s[0] = '-';
+ s[1] = '\0';
+ cmdputs(s);
+ } else {
+ cmdtxt(n->nfile.fname);
+ }
+}
+
+
+static void
cmdtxt(union node *n)
{
union node *np;
struct nodelist *lp;
- const char *p;
- int i;
- char s[2];
if (n == NULL)
return;
@@ -1314,14 +1369,13 @@ cmdtxt(union node *n)
break;
case NWHILE:
cmdputs("while ");
- goto until;
+ cmdtxt(n->nbinary.ch1);
+ cmdtxtdogroup(n->nbinary.ch2);
+ break;
case NUNTIL:
cmdputs("until ");
-until:
cmdtxt(n->nbinary.ch1);
- cmdputs("; do ");
- cmdtxt(n->nbinary.ch2);
- cmdputs("; done");
+ cmdtxtdogroup(n->nbinary.ch2);
break;
case NFOR:
cmdputs("for ");
@@ -1356,36 +1410,25 @@ until:
cmdputs(n->narg.text);
break;
case NTO:
- p = ">"; i = 1; goto redir;
+ cmdtxtredir(n, ">", 1);
+ break;
case NAPPEND:
- p = ">>"; i = 1; goto redir;
+ cmdtxtredir(n, ">>", 1);
+ break;
case NTOFD:
- p = ">&"; i = 1; goto redir;
+ cmdtxtredir(n, ">&", 1);
+ break;
case NCLOBBER:
- p = ">|"; i = 1; goto redir;
+ cmdtxtredir(n, ">|", 1);
+ break;
case NFROM:
- p = "<"; i = 0; goto redir;
+ cmdtxtredir(n, "<", 0);
+ break;
case NFROMTO:
- p = "<>"; i = 0; goto redir;
+ cmdtxtredir(n, "<>", 0);
+ break;
case NFROMFD:
- p = "<&"; i = 0; goto redir;
-redir:
- if (n->nfile.fd != i) {
- s[0] = n->nfile.fd + '0';
- s[1] = '\0';
- cmdputs(s);
- }
- cmdputs(p);
- if (n->type == NTOFD || n->type == NFROMFD) {
- if (n->ndup.dupfd >= 0)
- s[0] = n->ndup.dupfd + '0';
- else
- s[0] = '-';
- s[1] = '\0';
- cmdputs(s);
- } else {
- cmdtxt(n->nfile.fname);
- }
+ cmdtxtredir(n, "<&", 0);
break;
case NHERE:
case NXHERE:
diff --git a/bin/sh/mystring.c b/bin/sh/mystring.c
index 03ea8ba..19de78d 100644
--- a/bin/sh/mystring.c
+++ b/bin/sh/mystring.c
@@ -82,9 +82,17 @@ number(const char *s)
int
is_number(const char *p)
{
- do {
- if (! is_digit(*p))
+ const char *q;
+
+ if (*p == '\0')
+ return 0;
+ while (*p == '0')
+ p++;
+ for (q = p; *q != '\0'; q++)
+ if (! is_digit(*q))
return 0;
- } while (*++p != '\0');
+ if (q - p > 10 ||
+ (q - p == 10 && memcmp(p, "2147483647", 10) > 0))
+ return 0;
return 1;
}
diff --git a/bin/sh/options.c b/bin/sh/options.c
index bf00a4e..860cf6c 100644
--- a/bin/sh/options.c
+++ b/bin/sh/options.c
@@ -325,6 +325,7 @@ setparam(char **argv)
shellparam.malloc = 1;
shellparam.nparam = nparam;
shellparam.p = newparam;
+ shellparam.optp = NULL;
shellparam.reset = 1;
shellparam.optnext = NULL;
}
@@ -344,6 +345,11 @@ freeparam(struct shparam *param)
ckfree(*ap);
ckfree(param->p);
}
+ if (param->optp) {
+ for (ap = param->optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(param->optp);
+ }
}
@@ -417,20 +423,33 @@ getoptsreset(const char *value)
int
getoptscmd(int argc, char **argv)
{
- char **optbase = NULL;
+ char **optbase = NULL, **ap;
+ int i;
if (argc < 3)
error("usage: getopts optstring var [arg]");
- else if (argc == 3)
- optbase = shellparam.p;
- else
- optbase = &argv[3];
if (shellparam.reset == 1) {
+ INTOFF;
+ if (shellparam.optp) {
+ for (ap = shellparam.optp ; *ap ; ap++)
+ ckfree(*ap);
+ ckfree(shellparam.optp);
+ shellparam.optp = NULL;
+ }
+ if (argc > 3) {
+ shellparam.optp = ckmalloc((argc - 2) * sizeof *ap);
+ memset(shellparam.optp, '\0', (argc - 2) * sizeof *ap);
+ for (i = 0; i < argc - 3; i++)
+ shellparam.optp[i] = savestr(argv[i + 3]);
+ }
+ INTON;
+ optbase = argc == 3 ? shellparam.p : shellparam.optp;
shellparam.optnext = optbase;
shellparam.optptr = NULL;
shellparam.reset = 0;
- }
+ } else
+ optbase = shellparam.optp ? shellparam.optp : shellparam.p;
return getopts(argv[1], argv[2], optbase, &shellparam.optnext,
&shellparam.optptr);
diff --git a/bin/sh/options.h b/bin/sh/options.h
index acc2a11..0994862 100644
--- a/bin/sh/options.h
+++ b/bin/sh/options.h
@@ -38,6 +38,7 @@ struct shparam {
unsigned char malloc; /* if parameter list dynamically allocated */
unsigned char reset; /* if getopts has been reset */
char **p; /* parameter list */
+ char **optp; /* parameter list for getopts */
char **optnext; /* next parameter to be processed by getopts */
char *optptr; /* used by getopts */
};
diff --git a/bin/sh/parser.c b/bin/sh/parser.c
index e6e9f82..7fae29e 100644
--- a/bin/sh/parser.c
+++ b/bin/sh/parser.c
@@ -66,7 +66,6 @@ __FBSDID("$FreeBSD$");
* Shell command parser.
*/
-#define EOFMARKLEN 79
#define PROMPTLEN 128
/* values of checkkwd variable */
@@ -126,6 +125,7 @@ static void consumetoken(int);
static void synexpect(int) __dead2;
static void synerror(const char *) __dead2;
static void setprompt(int);
+static int pgetc_linecont(void);
static void *
@@ -718,7 +718,6 @@ parsefname(void)
if (n->type == NHERE) {
struct heredoc *here = heredoc;
struct heredoc *p;
- int i;
if (quoteflag == 0)
n->type = NXHERE;
@@ -727,7 +726,7 @@ parsefname(void)
while (*wordtext == '\t')
wordtext++;
}
- if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN)
+ if (! noexpand(wordtext))
synerror("Illegal eof marker for << redirection");
rmescapes(wordtext);
here->eofmark = wordtext;
@@ -891,7 +890,9 @@ xxreadtoken(void)
continue;
}
pungetc();
- goto breakloop;
+ /* FALLTHROUGH */
+ default:
+ return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
case '\n':
plinno++;
needprompt = doprompt;
@@ -899,17 +900,17 @@ xxreadtoken(void)
case PEOF:
RETURN(TEOF);
case '&':
- if (pgetc() == '&')
+ if (pgetc_linecont() == '&')
RETURN(TAND);
pungetc();
RETURN(TBACKGND);
case '|':
- if (pgetc() == '|')
+ if (pgetc_linecont() == '|')
RETURN(TOR);
pungetc();
RETURN(TPIPE);
case ';':
- c = pgetc();
+ c = pgetc_linecont();
if (c == ';')
RETURN(TENDCASE);
else if (c == '&')
@@ -920,12 +921,8 @@ xxreadtoken(void)
RETURN(TLP);
case ')':
RETURN(TRP);
- default:
- goto breakloop;
}
}
-breakloop:
- return readtoken1(c, BASESYNTAX, (char *)NULL, 0);
#undef RETURN
}
@@ -946,6 +943,98 @@ struct tokenstate
/*
+ * Check to see whether we are at the end of the here document. When this
+ * is called, c is set to the first character of the next input line. If
+ * we are at the end of the here document, this routine sets the c to PEOF.
+ * The new value of c is returned.
+ */
+
+static int
+checkend(int c, const char *eofmark, int striptabs)
+{
+ if (striptabs) {
+ while (c == '\t')
+ c = pgetc();
+ }
+ if (c == *eofmark) {
+ int c2;
+ const char *q;
+
+ for (q = eofmark + 1; c2 = pgetc(), *q != '\0' && c2 == *q; q++)
+ ;
+ if ((c2 == PEOF || c2 == '\n') && *q == '\0') {
+ c = PEOF;
+ if (c2 == '\n') {
+ plinno++;
+ needprompt = doprompt;
+ }
+ } else {
+ pungetc();
+ pushstring(eofmark + 1, q - (eofmark + 1), NULL);
+ }
+ }
+ return (c);
+}
+
+
+/*
+ * Parse a redirection operator. The variable "out" points to a string
+ * specifying the fd to be redirected. The variable "c" contains the
+ * first character of the redirection operator.
+ */
+
+static void
+parseredir(char *out, int c)
+{
+ char fd = *out;
+ union node *np;
+
+ np = (union node *)stalloc(sizeof (struct nfile));
+ if (c == '>') {
+ np->nfile.fd = 1;
+ c = pgetc_linecont();
+ if (c == '>')
+ np->type = NAPPEND;
+ else if (c == '&')
+ np->type = NTOFD;
+ else if (c == '|')
+ np->type = NCLOBBER;
+ else {
+ np->type = NTO;
+ pungetc();
+ }
+ } else { /* c == '<' */
+ np->nfile.fd = 0;
+ c = pgetc_linecont();
+ if (c == '<') {
+ if (sizeof (struct nfile) != sizeof (struct nhere)) {
+ np = (union node *)stalloc(sizeof (struct nhere));
+ np->nfile.fd = 0;
+ }
+ np->type = NHERE;
+ heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
+ heredoc->here = np;
+ if ((c = pgetc_linecont()) == '-') {
+ heredoc->striptabs = 1;
+ } else {
+ heredoc->striptabs = 0;
+ pungetc();
+ }
+ } else if (c == '&')
+ np->type = NFROMFD;
+ else if (c == '>')
+ np->type = NFROMTO;
+ else {
+ np->type = NFROM;
+ pungetc();
+ }
+ }
+ if (fd != '\0')
+ np->nfile.fd = digit_val(fd);
+ redirnode = np;
+}
+
+/*
* Called to parse command substitutions.
*/
@@ -1006,25 +1095,12 @@ parsebackq(char *out, struct nodelist **pbqlist,
needprompt = 0;
}
CHECKSTRSPACE(2, oout);
- switch (c = pgetc()) {
- case '`':
- goto done;
-
+ c = pgetc_linecont();
+ if (c == '`')
+ break;
+ switch (c) {
case '\\':
- if ((c = pgetc()) == '\n') {
- plinno++;
- if (doprompt)
- setprompt(2);
- else
- setprompt(0);
- /*
- * If eating a newline, avoid putting
- * the newline into the new character
- * stream (via the USTPUTC after the
- * switch).
- */
- continue;
- }
+ c = pgetc();
if (c != '\\' && c != '`' && c != '$'
&& (!dblquote || c != '"'))
USTPUTC('\\', oout);
@@ -1045,7 +1121,6 @@ parsebackq(char *out, struct nodelist **pbqlist,
}
USTPUTC(c, oout);
}
-done:
USTPUTC('\0', oout);
olen = oout - stackblock();
INTOFF;
@@ -1246,6 +1321,13 @@ readcstyleesc(char *out)
c = pgetc();
if (c == PEOF)
synerror("Unterminated quoted string");
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ }
}
pungetc();
return out;
@@ -1269,8 +1351,6 @@ readcstyleesc(char *out)
* will run code that appears at the end of readtoken1.
*/
-#define CHECKEND() {goto checkend; checkend_return:;}
-#define PARSEREDIR() {goto parseredir; parseredir_return:;}
#define PARSESUB() {goto parsesub; parsesub_return:;}
#define PARSEARITH() {goto parsearith; parsearith_return:;}
@@ -1281,7 +1361,6 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
int c = firstc;
char *out;
int len;
- char line[EOFMARKLEN + 1];
struct nodelist *bqlist;
int quotef;
int newvarnest;
@@ -1303,7 +1382,9 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
STARTSTACKSTR(out);
loop: { /* for each line, until end of word */
- CHECKEND(); /* set c to PEOF if at end of here document */
+ if (eofmark)
+ /* set c to PEOF if at end of here document */
+ c = checkend(c, eofmark, striptabs);
for (;;) { /* until end of line or end of word */
CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */
@@ -1414,7 +1495,7 @@ readtoken1(int firstc, char const *initialsyntax, const char *eofmark,
USTPUTC(c, out);
--state[level].parenlevel;
} else {
- if (pgetc() == ')') {
+ if (pgetc_linecont() == ')') {
if (level > 0 &&
state[level].category == TSTATE_ARITH) {
level--;
@@ -1469,7 +1550,7 @@ endword:
&& quotef == 0
&& len <= 2
&& (*out == '\0' || is_digit(*out))) {
- PARSEREDIR();
+ parseredir(out, c);
return lasttoken = TREDIR;
} else {
pungetc();
@@ -1484,97 +1565,6 @@ endword:
/*
- * Check to see whether we are at the end of the here document. When this
- * is called, c is set to the first character of the next input line. If
- * we are at the end of the here document, this routine sets the c to PEOF.
- */
-
-checkend: {
- if (eofmark) {
- if (striptabs) {
- while (c == '\t')
- c = pgetc();
- }
- if (c == *eofmark) {
- if (pfgets(line, sizeof line) != NULL) {
- const char *p, *q;
-
- p = line;
- for (q = eofmark + 1 ; *q && *p == *q ; p++, q++);
- if ((*p == '\0' || *p == '\n') && *q == '\0') {
- c = PEOF;
- if (*p == '\n') {
- plinno++;
- needprompt = doprompt;
- }
- } else {
- pushstring(line, strlen(line), NULL);
- }
- }
- }
- }
- goto checkend_return;
-}
-
-
-/*
- * Parse a redirection operator. The variable "out" points to a string
- * specifying the fd to be redirected. The variable "c" contains the
- * first character of the redirection operator.
- */
-
-parseredir: {
- char fd = *out;
- union node *np;
-
- np = (union node *)stalloc(sizeof (struct nfile));
- if (c == '>') {
- np->nfile.fd = 1;
- c = pgetc();
- if (c == '>')
- np->type = NAPPEND;
- else if (c == '&')
- np->type = NTOFD;
- else if (c == '|')
- np->type = NCLOBBER;
- else {
- np->type = NTO;
- pungetc();
- }
- } else { /* c == '<' */
- np->nfile.fd = 0;
- c = pgetc();
- if (c == '<') {
- if (sizeof (struct nfile) != sizeof (struct nhere)) {
- np = (union node *)stalloc(sizeof (struct nhere));
- np->nfile.fd = 0;
- }
- np->type = NHERE;
- heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc));
- heredoc->here = np;
- if ((c = pgetc()) == '-') {
- heredoc->striptabs = 1;
- } else {
- heredoc->striptabs = 0;
- pungetc();
- }
- } else if (c == '&')
- np->type = NFROMFD;
- else if (c == '>')
- np->type = NFROMTO;
- else {
- np->type = NFROM;
- pungetc();
- }
- }
- if (fd != '\0')
- np->nfile.fd = digit_val(fd);
- redirnode = np;
- goto parseredir_return;
-}
-
-
-/*
* Parse a substitution. At this point, we have read the dollar sign
* and nothing else.
*/
@@ -1591,9 +1581,9 @@ parsesub: {
int length;
int c1;
- c = pgetc();
+ c = pgetc_linecont();
if (c == '(') { /* $(command) or $((arith)) */
- if (pgetc() == '(') {
+ if (pgetc_linecont() == '(') {
PARSEARITH();
} else {
pungetc();
@@ -1611,7 +1601,7 @@ parsesub: {
flags = 0;
if (c == '{') {
bracketed_name = 1;
- c = pgetc();
+ c = pgetc_linecont();
subtype = 0;
}
varname:
@@ -1619,7 +1609,7 @@ varname:
length = 0;
do {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_linecont();
length++;
} while (!is_eof(c) && is_in_name(c));
if (length == 6 &&
@@ -1638,22 +1628,22 @@ varname:
if (bracketed_name) {
do {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_linecont();
} while (is_digit(c));
} else {
STPUTC(c, out);
- c = pgetc();
+ c = pgetc_linecont();
}
} else if (is_special(c)) {
c1 = c;
- c = pgetc();
+ c = pgetc_linecont();
if (subtype == 0 && c1 == '#') {
subtype = VSLENGTH;
if (strchr(types, c) == NULL && c != ':' &&
c != '#' && c != '%')
goto varname;
c1 = c;
- c = pgetc();
+ c = pgetc_linecont();
if (c1 != '}' && c == '}') {
pungetc();
c = c1;
@@ -1678,7 +1668,7 @@ varname:
switch (c) {
case ':':
flags |= VSNUL;
- c = pgetc();
+ c = pgetc_linecont();
/*FALLTHROUGH*/
default:
p = strchr(types, c);
@@ -1698,7 +1688,7 @@ varname:
int cc = c;
subtype = c == '#' ? VSTRIMLEFT :
VSTRIMRIGHT;
- c = pgetc();
+ c = pgetc_linecont();
if (c == cc)
subtype++;
else
@@ -1907,6 +1897,29 @@ setprompt(int which)
}
}
+static int
+pgetc_linecont(void)
+{
+ int c;
+
+ while ((c = pgetc_macro()) == '\\') {
+ c = pgetc();
+ if (c == '\n') {
+ plinno++;
+ if (doprompt)
+ setprompt(2);
+ else
+ setprompt(0);
+ } else {
+ pungetc();
+ /* Allow the backslash to be pushed back. */
+ pushstring("\\", 1, NULL);
+ return (pgetc());
+ }
+ }
+ return (c);
+}
+
/*
* called by editline -- any expansions to the prompt
* should be added here.
@@ -1915,7 +1928,7 @@ char *
getprompt(void *unused __unused)
{
static char ps[PROMPTLEN];
- char *fmt;
+ const char *fmt;
const char *pwd;
int i, trim;
static char internal_error[] = "??";
@@ -2029,7 +2042,7 @@ expandstr(const char *ps)
parser_temp = NULL;
setinputstring(ps, 1);
doprompt = 0;
- readtoken1(pgetc(), DQSYNTAX, "\n\n", 0);
+ readtoken1(pgetc(), DQSYNTAX, "", 0);
if (backquotelist != NULL)
error("Command substitution not allowed here");
diff --git a/bin/sh/redir.c b/bin/sh/redir.c
index 6127e86..95d3238 100644
--- a/bin/sh/redir.c
+++ b/bin/sh/redir.c
@@ -173,21 +173,12 @@ openredirect(union node *redir, char memory[10])
fname = redir->nfile.expfname;
if ((f = open(fname, O_RDONLY)) < 0)
error("cannot open %s: %s", fname, strerror(errno));
-movefd:
- if (f != fd) {
- if (dup2(f, fd) == -1) {
- e = errno;
- close(f);
- error("%d: %s", fd, strerror(e));
- }
- close(f);
- }
break;
case NFROMTO:
fname = redir->nfile.expfname;
if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
error("cannot create %s: %s", fname, strerror(errno));
- goto movefd;
+ break;
case NTO:
if (Cflag) {
fname = redir->nfile.expfname;
@@ -205,19 +196,19 @@ movefd:
} else
error("cannot create %s: %s", fname,
strerror(EEXIST));
- goto movefd;
+ break;
}
/* FALLTHROUGH */
case NCLOBBER:
fname = redir->nfile.expfname;
if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
error("cannot create %s: %s", fname, strerror(errno));
- goto movefd;
+ break;
case NAPPEND:
fname = redir->nfile.expfname;
if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
error("cannot create %s: %s", fname, strerror(errno));
- goto movefd;
+ break;
case NTOFD:
case NFROMFD:
if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
@@ -231,14 +222,22 @@ movefd:
} else {
close(fd);
}
- break;
+ return;
case NHERE:
case NXHERE:
f = openhere(redir);
- goto movefd;
+ break;
default:
abort();
}
+ if (f != fd) {
+ if (dup2(f, fd) == -1) {
+ e = errno;
+ close(f);
+ error("%d: %s", fd, strerror(e));
+ }
+ close(f);
+ }
}
diff --git a/bin/sh/sh.1 b/bin/sh/sh.1
index 1c3f8fb..fa68720 100644
--- a/bin/sh/sh.1
+++ b/bin/sh/sh.1
@@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
-.Dd January 26, 2014
+.Dd November 14, 2014
.Dt SH 1
.Os
.Sh NAME
@@ -259,6 +259,12 @@ from input when in interactive mode.
Force the shell to behave interactively.
.It Fl m Li monitor
Turn on job control (set automatically when interactive).
+A new process group is created for each pipeline (called a job).
+It is possible to suspend jobs or to have them run in the foreground or
+in the background.
+In a non-interactive shell,
+this option can be set even if no terminal is available
+and is useful to place processes in separate process groups.
.It Fl n Li noexec
If not interactive, read commands but do not
execute them.
@@ -584,7 +590,8 @@ the following actions:
Leading words of the form
.Dq Li name=value
are stripped off and assigned to the environment of
-the simple command.
+the simple command
+(they do not affect expansions).
Redirection operators and
their arguments (as described below) are stripped
off and saved for processing.
@@ -788,10 +795,13 @@ should indicate the various exit codes and what they mean.
Additionally, the built-in commands return exit codes, as does
an executed shell function.
.Pp
-If a command is terminated by a signal, its exit status is 128 plus
-the signal number.
-Signal numbers are defined in the header file
-.In sys/signal.h .
+If a command is terminated by a signal, its exit status is greater than 128.
+The signal name can be found by passing the exit status to
+.Li kill -l .
+.Pp
+If there is no command word,
+the exit status is the exit status of the last command substitution executed,
+or zero if the command does not contain any command substitutions.
.Ss Complex Commands
Complex commands are combinations of simple commands
with control operators or keywords, together creating a larger complex
@@ -811,7 +821,8 @@ function definition
.El
.Pp
Unless otherwise stated, the exit status of a command is
-that of the last simple command executed by the command.
+that of the last simple command executed by the command,
+or zero if no simple command was executed.
.Ss Pipelines
A pipeline is a sequence of one or more commands separated
by the control operator
@@ -895,6 +906,8 @@ The format for running a command in background is:
If the shell is not interactive, the standard input of an
asynchronous command is set to
.Pa /dev/null .
+.Pp
+The exit status is zero.
.Ss Lists (Generally Speaking)
A list is a sequence of zero or more commands separated by
newlines, semicolons, or ampersands,
@@ -933,6 +946,13 @@ command is:
.Ic fi
.Ed
.Pp
+The exit status is that of selected
+.Ic then
+or
+.Ic else
+list,
+or zero if no list was selected.
+.Pp
The syntax of the
.Ic while
command is:
@@ -953,6 +973,9 @@ in place of
which causes it to
repeat until the exit status of the first list is zero.
.Pp
+The exit status is that of the last execution of the second list,
+or zero if it was never executed.
+.Pp
The syntax of the
.Ic for
command is:
@@ -1033,10 +1056,6 @@ continuing until a list terminated with
or the end of the
.Ic case
command.
-The exit code of the
-.Ic case
-command is the exit code of the last command executed in the list or
-zero if no patterns were matched.
.Ss Grouping Commands Together
Commands may be grouped by writing either
.Pp
@@ -1124,6 +1143,8 @@ and the syntax is:
The
.Ic local
command is implemented as a built-in command.
+The exit status is zero
+unless the command is not in a function or a variable name is invalid.
.Pp
When a variable is made local, it inherits the initial
value and exported and readonly flags from the variable
@@ -2515,7 +2536,8 @@ and so on,
decreasing the value of
.Li $#
by one.
-If there are zero positional parameters, shifting does not do anything.
+For portability, shifting if there are zero positional parameters
+should be avoided, since the shell may abort.
.It Ic test
A built-in equivalent of
.Xr test 1 .
diff --git a/bin/sh/tests/Makefile b/bin/sh/tests/Makefile
index 51c6dc4..c092962 100644
--- a/bin/sh/tests/Makefile
+++ b/bin/sh/tests/Makefile
@@ -4,15 +4,12 @@
TESTSDIR= ${TESTSBASE}/bin/sh
-TAP_TESTS_SH= legacy_test
-TAP_TESTS_SH_SED_legacy_test= -e 's,__SH__,/bin/sh,g'
-# Some tests in here are silently not run when the tests are executed as
-# root. Explicitly tell Kyua to drop privileges.
-#
-# TODO(jmmv): Kyua needs to do this by default, not only when explicitly
-# requested. See https://code.google.com/p/kyua/issues/detail?id=6
-TEST_METADATA.legacy_test+= required_user="unprivileged"
-
-SUBDIR+= builtins errors execution expansion parameters parser set-e
+TESTS_SUBDIRS+= builtins
+TESTS_SUBDIRS+= errors
+TESTS_SUBDIRS+= execution
+TESTS_SUBDIRS+= expansion
+TESTS_SUBDIRS+= parameters
+TESTS_SUBDIRS+= parser
+TESTS_SUBDIRS+= set-e
.include <bsd.test.mk>
diff --git a/bin/sh/tests/builtins/Makefile b/bin/sh/tests/builtins/Makefile
index 4c988da..5f5da4a 100644
--- a/bin/sh/tests/builtins/Makefile
+++ b/bin/sh/tests/builtins/Makefile
@@ -1,9 +1,13 @@
# $FreeBSD$
-.include <bsd.own.mk>
+.include <src.opts.mk>
-FILESDIR= ${TESTSBASE}/bin/sh/builtins
-KYUAFILE= no
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
+
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= alias.0 alias.0.stdout
FILES+= alias.1 alias.1.stderr
@@ -68,6 +72,8 @@ FILES+= eval3.0
FILES+= eval4.0
FILES+= eval5.0
FILES+= eval6.0
+FILES+= eval7.0
+FILES+= eval8.7
FILES+= exec1.0
FILES+= exec2.0
FILES+= exit1.0
@@ -96,6 +102,7 @@ FILES+= jobid2.0
FILES+= kill1.0 kill2.0
FILES+= lineno.0 lineno.0.stdout
FILES+= lineno2.0
+FILES+= lineno3.0 lineno3.0.stdout
FILES+= local1.0
FILES+= local2.0
FILES+= local3.0
diff --git a/bin/sh/tests/builtins/eval7.0 b/bin/sh/tests/builtins/eval7.0
new file mode 100644
index 0000000..a309c91
--- /dev/null
+++ b/bin/sh/tests/builtins/eval7.0
@@ -0,0 +1,9 @@
+# $FreeBSD$
+# Assumes that break can break out of a loop outside eval.
+
+while :; do
+ eval "break
+echo bad1"
+ echo bad2
+ exit 3
+done
diff --git a/bin/sh/tests/builtins/eval8.7 b/bin/sh/tests/builtins/eval8.7
new file mode 100644
index 0000000..af6064c
--- /dev/null
+++ b/bin/sh/tests/builtins/eval8.7
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+f() {
+ eval "return 7
+echo bad2"
+}
+f
diff --git a/bin/sh/tests/builtins/getopts9.0 b/bin/sh/tests/builtins/getopts9.0
new file mode 100644
index 0000000..d23fc43
--- /dev/null
+++ b/bin/sh/tests/builtins/getopts9.0
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+args='-ab'
+getopts ab opt $args
+echo $?:$opt:$OPTARG
+for dummy in dummy1 dummy2; do
+ getopts ab opt $args
+ echo $?:$opt:$OPTARG
+done
diff --git a/bin/sh/tests/builtins/getopts9.0.stdout b/bin/sh/tests/builtins/getopts9.0.stdout
new file mode 100644
index 0000000..4d32063
--- /dev/null
+++ b/bin/sh/tests/builtins/getopts9.0.stdout
@@ -0,0 +1,3 @@
+0:a:
+0:b:
+1:?:
diff --git a/bin/sh/tests/builtins/lineno3.0 b/bin/sh/tests/builtins/lineno3.0
new file mode 100644
index 0000000..eb8f9ab
--- /dev/null
+++ b/bin/sh/tests/builtins/lineno3.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+echo before: $LINENO
+dummy=$'a\0
+'
+echo after: $LINENO
diff --git a/bin/sh/tests/builtins/lineno3.0.stdout b/bin/sh/tests/builtins/lineno3.0.stdout
new file mode 100644
index 0000000..6e0e4ac
--- /dev/null
+++ b/bin/sh/tests/builtins/lineno3.0.stdout
@@ -0,0 +1,2 @@
+before: 3
+after: 6
diff --git a/bin/sh/tests/errors/Makefile b/bin/sh/tests/errors/Makefile
index 9f8b0f2..ace9a01 100644
--- a/bin/sh/tests/errors/Makefile
+++ b/bin/sh/tests/errors/Makefile
@@ -1,9 +1,11 @@
# $FreeBSD$
-.include <bsd.own.mk>
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
-FILESDIR= ${TESTSBASE}/bin/sh/errors
-KYUAFILE= no
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= assignment-error1.0
FILES+= assignment-error2.0
diff --git a/bin/sh/tests/errors/bad-parm-exp2.2 b/bin/sh/tests/errors/bad-parm-exp2.2
index 7e13d2b..a0826ec 100644
--- a/bin/sh/tests/errors/bad-parm-exp2.2
+++ b/bin/sh/tests/errors/bad-parm-exp2.2
@@ -1,2 +1,2 @@
# $FreeBSD$
-${}
+eval '${}'
diff --git a/bin/sh/tests/errors/bad-parm-exp2.2.stderr b/bin/sh/tests/errors/bad-parm-exp2.2.stderr
index d027a5a..51ea69c 100644
--- a/bin/sh/tests/errors/bad-parm-exp2.2.stderr
+++ b/bin/sh/tests/errors/bad-parm-exp2.2.stderr
@@ -1 +1 @@
-./errors/bad-parm-exp2.2: ${}: Bad substitution
+eval: ${}: Bad substitution
diff --git a/bin/sh/tests/errors/bad-parm-exp3.2 b/bin/sh/tests/errors/bad-parm-exp3.2
index a5ecba5..bb41208 100644
--- a/bin/sh/tests/errors/bad-parm-exp3.2
+++ b/bin/sh/tests/errors/bad-parm-exp3.2
@@ -1,2 +1,2 @@
# $FreeBSD$
-${foo/}
+eval '${foo/}'
diff --git a/bin/sh/tests/errors/bad-parm-exp3.2.stderr b/bin/sh/tests/errors/bad-parm-exp3.2.stderr
index ef40251..70473f9 100644
--- a/bin/sh/tests/errors/bad-parm-exp3.2.stderr
+++ b/bin/sh/tests/errors/bad-parm-exp3.2.stderr
@@ -1 +1 @@
-./errors/bad-parm-exp3.2: ${foo/}: Bad substitution
+eval: ${foo/}: Bad substitution
diff --git a/bin/sh/tests/errors/bad-parm-exp4.2 b/bin/sh/tests/errors/bad-parm-exp4.2
index 9eec8d0..2837f9b 100644
--- a/bin/sh/tests/errors/bad-parm-exp4.2
+++ b/bin/sh/tests/errors/bad-parm-exp4.2
@@ -1,2 +1,2 @@
# $FreeBSD$
-${foo:@abc}
+eval '${foo:@abc}'
diff --git a/bin/sh/tests/errors/bad-parm-exp4.2.stderr b/bin/sh/tests/errors/bad-parm-exp4.2.stderr
index 89bd80f..3363f51 100644
--- a/bin/sh/tests/errors/bad-parm-exp4.2.stderr
+++ b/bin/sh/tests/errors/bad-parm-exp4.2.stderr
@@ -1 +1 @@
-./errors/bad-parm-exp4.2: ${foo:@...}: Bad substitution
+eval: ${foo:@...}: Bad substitution
diff --git a/bin/sh/tests/errors/bad-parm-exp5.2 b/bin/sh/tests/errors/bad-parm-exp5.2
index 459281f..1ba343b 100644
--- a/bin/sh/tests/errors/bad-parm-exp5.2
+++ b/bin/sh/tests/errors/bad-parm-exp5.2
@@ -1,2 +1,2 @@
# $FreeBSD$
-${/}
+eval '${/}'
diff --git a/bin/sh/tests/errors/bad-parm-exp5.2.stderr b/bin/sh/tests/errors/bad-parm-exp5.2.stderr
index 89b1997..13763f8 100644
--- a/bin/sh/tests/errors/bad-parm-exp5.2.stderr
+++ b/bin/sh/tests/errors/bad-parm-exp5.2.stderr
@@ -1 +1 @@
-./errors/bad-parm-exp5.2: ${/}: Bad substitution
+eval: ${/}: Bad substitution
diff --git a/bin/sh/tests/errors/bad-parm-exp6.2 b/bin/sh/tests/errors/bad-parm-exp6.2
index ba51442..b53a91b 100644
--- a/bin/sh/tests/errors/bad-parm-exp6.2
+++ b/bin/sh/tests/errors/bad-parm-exp6.2
@@ -1,2 +1,2 @@
# $FreeBSD$
-${#foo^}
+eval '${#foo^}'
diff --git a/bin/sh/tests/errors/bad-parm-exp6.2.stderr b/bin/sh/tests/errors/bad-parm-exp6.2.stderr
index dbf14b5..cc56f65 100644
--- a/bin/sh/tests/errors/bad-parm-exp6.2.stderr
+++ b/bin/sh/tests/errors/bad-parm-exp6.2.stderr
@@ -1 +1 @@
-./errors/bad-parm-exp6.2: ${foo...}: Bad substitution
+eval: ${foo...}: Bad substitution
diff --git a/bin/sh/tests/execution/Makefile b/bin/sh/tests/execution/Makefile
index 302d0d8..2653d5f 100644
--- a/bin/sh/tests/execution/Makefile
+++ b/bin/sh/tests/execution/Makefile
@@ -1,9 +1,11 @@
# $FreeBSD$
-.include <bsd.own.mk>
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
-FILESDIR= ${TESTSBASE}/bin/sh/execution
-KYUAFILE= no
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= bg1.0
FILES+= bg2.0
diff --git a/bin/sh/tests/expansion/Makefile b/bin/sh/tests/expansion/Makefile
index bd24319..027bc95 100644
--- a/bin/sh/tests/expansion/Makefile
+++ b/bin/sh/tests/expansion/Makefile
@@ -1,9 +1,11 @@
# $FreeBSD$
-.include <bsd.own.mk>
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
-FILESDIR= ${TESTSBASE}/bin/sh/expansion
-KYUAFILE= no
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= arith1.0
FILES+= arith2.0
@@ -18,6 +20,7 @@ FILES+= arith10.0
FILES+= arith11.0
FILES+= arith12.0
FILES+= arith13.0
+FILES+= arith14.0
FILES+= assign1.0
FILES+= cmdsubst1.0
FILES+= cmdsubst2.0
@@ -69,6 +72,7 @@ FILES+= plus-minus7.0
FILES+= plus-minus8.0
FILES+= question1.0
FILES+= readonly1.0
+FILES+= redir1.0
FILES+= set-u1.0
FILES+= set-u2.0
FILES+= set-u3.0
diff --git a/bin/sh/tests/expansion/arith14.0 b/bin/sh/tests/expansion/arith14.0
new file mode 100644
index 0000000..8369043
--- /dev/null
+++ b/bin/sh/tests/expansion/arith14.0
@@ -0,0 +1,40 @@
+# $FreeBSD$
+# Check that <</>> use the low bits of the shift count.
+
+if [ $((1<<16<<16)) = 0 ]; then
+ width=32
+elif [ $((1<<32<<32)) = 0 ]; then
+ width=64
+elif [ $((1<<64<<64)) = 0 ]; then
+ width=128
+elif [ $((1<<64>>64)) = 1 ]; then
+ # Integers are wider than 128 bits; assume arbitrary precision.
+ # Nothing to test here.
+ exit 0
+else
+ echo "Cannot determine integer width"
+ exit 2
+fi
+
+twowidth=$((width * 2))
+j=43 k=$((1 << (width - 2))) r=0
+
+i=0
+while [ $i -lt $twowidth ]; do
+ if [ "$((j << i))" != "$((j << (i + width)))" ]; then
+ echo "Problem with $j << $i"
+ r=2
+ fi
+ i=$((i + 1))
+done
+
+i=0
+while [ $i -lt $twowidth ]; do
+ if [ "$((k >> i))" != "$((k >> (i + width)))" ]; then
+ echo "Problem with $k >> $i"
+ r=2
+ fi
+ i=$((i + 1))
+done
+
+exit $r
diff --git a/bin/sh/tests/expansion/redir1.0 b/bin/sh/tests/expansion/redir1.0
new file mode 100644
index 0000000..aa13e15
--- /dev/null
+++ b/bin/sh/tests/expansion/redir1.0
@@ -0,0 +1,26 @@
+# $FreeBSD$
+
+bad=0
+for i in 0 1 2 3; do
+ for j in 0 1 2 3 4 5 6 7; do
+ for k in 0 1 2 3 4 5 6 7; do
+ case $i$j$k in
+ 000) continue ;;
+ esac
+ set -- "$(printf \\$i$j$k@)"
+ set -- "${1%@}"
+ ff=
+ for f in /dev/null /dev/zero /; do
+ if [ -e "$f" ] && [ ! -e "$f$1" ]; then
+ ff=$f
+ fi
+ done
+ [ -n "$ff" ] || continue
+ if { true <$ff$1; } 2>/dev/null; then
+ echo "Bad: $i$j$k ($ff)" >&2
+ : $((bad += 1))
+ fi
+ done
+ done
+done
+exit $((bad ? 2 : 0))
diff --git a/bin/sh/tests/functional_test.sh b/bin/sh/tests/functional_test.sh
new file mode 100755
index 0000000..6980538
--- /dev/null
+++ b/bin/sh/tests/functional_test.sh
@@ -0,0 +1,72 @@
+#
+# Copyright 2014 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# $FreeBSD$
+
+SRCDIR=$(atf_get_srcdir)
+
+check()
+{
+ local tc=${1}; shift
+
+ export SH=$(atf_config_get bin.sh.test_shell /bin/sh)
+
+ local err_file="${SRCDIR}/${tc}.stderr"
+ [ -f "${err_file}" ] && err_flag="-e file:${err_file}"
+ local out_file="${SRCDIR}/${tc}.stdout"
+ [ -f "${out_file}" ] && out_flag="-o file:${out_file}"
+
+ atf_check -s exit:${tc##*.} ${err_flag} ${out_flag} ${SH} "${SRCDIR}/${tc}"
+}
+
+add_testcase()
+{
+ local tc=${1}
+ local tc_escaped word
+
+ case "${tc%.*}" in
+ *-*)
+ local IFS="-"
+ for word in ${tc%.*}; do
+ tc_escaped="${tc_escaped:+${tc_escaped}_}${word}"
+ done
+ ;;
+ *)
+ tc_escaped=${tc%.*}
+ ;;
+ esac
+
+ atf_test_case ${tc_escaped}
+ eval "${tc_escaped}_body() { check ${tc}; }"
+ atf_add_test_case ${tc_escaped}
+}
+
+atf_init_test_cases()
+{
+ for path in $(find -Es "${SRCDIR}" -regex '.*\.[0-9]+$'); do
+ add_testcase ${path##*/}
+ done
+}
diff --git a/bin/sh/tests/legacy_test.sh b/bin/sh/tests/legacy_test.sh
deleted file mode 100644
index d43f5dd..0000000
--- a/bin/sh/tests/legacy_test.sh
+++ /dev/null
@@ -1,46 +0,0 @@
-# $FreeBSD$
-
-: ${SH:="__SH__"}
-export SH
-
-# TODO(jmmv): The Kyua TAP interface should be passing us the value of
-# "srcdir" as an environment variable, just as it does with the ATF
-# interface in the form of a configuration variable. For now, just try
-# to guess this.
-: ${TESTS_DATA:=$(dirname ${0})}
-
-COUNTER=1
-
-do_test() {
- c=${COUNTER}
- COUNTER=$((COUNTER+1))
- ${SH} $1 > tmp.stdout 2> tmp.stderr
- if [ $? -ne $2 ]; then
- echo "not ok ${c} - ${1} # wrong exit status"
- rm tmp.stdout tmp.stderr
- return
- fi
- sed -I '' -e "s|^${TESTS_DATA}|.|" tmp.stderr
- for i in stdout stderr; do
- if [ -f ${1}.${i} ]; then
- if ! cmp -s tmp.${i} ${1}.${i}; then
- echo "not ok ${c} - ${1} # wrong output on ${i}"
- rm tmp.stdout tmp.stderr
- return
- fi
- elif [ -s tmp.${i} ]; then
- echo "not ok ${c} - ${1} # wrong output on ${i}"
- rm tmp.stdout tmp.stderr
- return
- fi
- done
- echo "ok ${c} - ${1}"
- rm tmp.stdout tmp.stderr
-}
-
-TESTS=$(find -Es ${TESTS_DATA} -regex ".*\.[0-9]+")
-printf "1..%d\n" $(echo ${TESTS} | wc -w)
-
-for i in ${TESTS} ; do
- do_test ${i} ${i##*.}
-done
diff --git a/bin/sh/tests/parameters/Makefile b/bin/sh/tests/parameters/Makefile
index da49d14..231ed4d 100644
--- a/bin/sh/tests/parameters/Makefile
+++ b/bin/sh/tests/parameters/Makefile
@@ -1,9 +1,11 @@
# $FreeBSD$
-.include <bsd.own.mk>
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
-FILESDIR= ${TESTSBASE}/bin/sh/parameters
-KYUAFILE= no
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= env1.0
FILES+= exitstatus1.0
@@ -16,6 +18,8 @@ FILES+= positional2.0
FILES+= positional3.0
FILES+= positional4.0
FILES+= positional5.0
+FILES+= positional6.0
+FILES+= positional7.0
FILES+= pwd1.0
FILES+= pwd2.0
diff --git a/bin/sh/tests/parameters/positional6.0 b/bin/sh/tests/parameters/positional6.0
new file mode 100644
index 0000000..1410668
--- /dev/null
+++ b/bin/sh/tests/parameters/positional6.0
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+IFS=?
+set p r
+v=pqrs
+r=${v#"$*"}
+[ "$r" = pqrs ]
diff --git a/bin/sh/tests/parameters/positional7.0 b/bin/sh/tests/parameters/positional7.0
new file mode 100644
index 0000000..f170ad3
--- /dev/null
+++ b/bin/sh/tests/parameters/positional7.0
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+set -- / ''
+IFS=*
+set -- "$*"
+IFS=:
+args="$*"
+[ "$#:$args" = "1:/*" ]
diff --git a/bin/sh/tests/parser/Makefile b/bin/sh/tests/parser/Makefile
index 03650b1..3c9e62c 100644
--- a/bin/sh/tests/parser/Makefile
+++ b/bin/sh/tests/parser/Makefile
@@ -1,9 +1,11 @@
# $FreeBSD$
-.include <bsd.own.mk>
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
-FILESDIR= ${TESTSBASE}/bin/sh/parser
-KYUAFILE= no
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= alias1.0
FILES+= alias2.0
@@ -52,6 +54,18 @@ FILES+= heredoc8.0
FILES+= heredoc9.0
FILES+= heredoc10.0
FILES+= heredoc11.0
+FILES+= heredoc12.0
+FILES+= line-cont1.0
+FILES+= line-cont2.0
+FILES+= line-cont3.0
+FILES+= line-cont4.0
+FILES+= line-cont5.0
+FILES+= line-cont6.0
+FILES+= line-cont7.0
+FILES+= line-cont8.0
+FILES+= line-cont9.0
+FILES+= line-cont10.0
+FILES+= line-cont11.0
FILES+= no-space1.0
FILES+= no-space2.0
FILES+= only-redir1.0
diff --git a/bin/sh/tests/parser/heredoc12.0 b/bin/sh/tests/parser/heredoc12.0
new file mode 100644
index 0000000..9648384
--- /dev/null
+++ b/bin/sh/tests/parser/heredoc12.0
@@ -0,0 +1,47 @@
+# $FreeBSD$
+
+failures=0
+
+check() {
+ if ! eval "[ $* ]"; then
+ echo "Failed: $*"
+ : $((failures += 1))
+ fi
+}
+
+longmark=`printf %01000d 4`
+longmarkstripped=`printf %0999d 0`
+
+check '"$(cat <<'"$longmark
+$longmark"'
+echo yes)" = "yes"'
+
+check '"$(cat <<\'"$longmark
+$longmark"'
+echo yes)" = "yes"'
+
+check '"$(cat <<'"$longmark
+yes
+$longmark"'
+)" = "yes"'
+
+check '"$(cat <<\'"$longmark
+yes
+$longmark"'
+)" = "yes"'
+
+check '"$(cat <<'"$longmark
+$longmarkstripped
+$longmark.
+$longmark"'
+)" = "'"$longmarkstripped
+$longmark."'"'
+
+check '"$(cat <<\'"$longmark
+$longmarkstripped
+$longmark.
+$longmark"'
+)" = "'"$longmarkstripped
+$longmark."'"'
+
+exit $((failures != 0))
diff --git a/bin/sh/tests/parser/line-cont1.0 b/bin/sh/tests/parser/line-cont1.0
new file mode 100644
index 0000000..7ef5eba
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont1.0
@@ -0,0 +1,16 @@
+# $FreeBSD$
+
+i\
+f
+t\
+r\
+u\
+e
+t\
+h\
+e\
+n
+:
+\
+f\
+i
diff --git a/bin/sh/tests/parser/line-cont10.0 b/bin/sh/tests/parser/line-cont10.0
new file mode 100644
index 0000000..1e74108
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont10.0
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+v=XaaaXbbbX
+[ "${v\
+#\
+*\
+a}.${v\
+#\
+#\
+*\
+a}.${v\
+%\
+b\
+*}.${v\
+%\
+%\
+b\
+*}" = aaXbbbX.XbbbX.XaaaXbb.XaaaX ]
diff --git a/bin/sh/tests/parser/line-cont11.0 b/bin/sh/tests/parser/line-cont11.0
new file mode 100644
index 0000000..22e4975
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont11.0
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+T=$(mktemp "${TMPDIR:-/tmp}/sh-test.XXXXXXXX") || exit
+trap 'rm -f -- "$T"' 0
+w='#A'
+# A naive pgetc_linecont() would push back two characters here, which
+# fails if a new buffer is read between the two characters.
+c='${w#\#}'
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+c=$c$c$c$c
+printf 'v=%s\n' "$c" >"$T"
+. "$T"
+if [ "${#v}" != 4096 ]; then
+ echo "Length is bad (${#v})"
+ exit 3
+fi
+case $v in
+*[!A]*) echo "Content is bad"; exit 3 ;;
+esac
diff --git a/bin/sh/tests/parser/line-cont2.0 b/bin/sh/tests/parser/line-cont2.0
new file mode 100644
index 0000000..9a293fa
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont2.0
@@ -0,0 +1,4 @@
+# $FreeBSD$
+
+[ "a\
+b" = ab ]
diff --git a/bin/sh/tests/parser/line-cont3.0 b/bin/sh/tests/parser/line-cont3.0
new file mode 100644
index 0000000..09d3aa8
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont3.0
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+v=`printf %s 'a\
+b'`
+w="`printf %s 'c\
+d'`"
+[ "$v$w" = abcd ]
diff --git a/bin/sh/tests/parser/line-cont4.0 b/bin/sh/tests/parser/line-cont4.0
new file mode 100644
index 0000000..5803276
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont4.0
@@ -0,0 +1,8 @@
+# $FreeBSD$
+
+v=abcd
+[ "$\
+v.$\
+{v}.${\
+v}.${v\
+}" = abcd.abcd.abcd.abcd ]
diff --git a/bin/sh/tests/parser/line-cont5.0 b/bin/sh/tests/parser/line-cont5.0
new file mode 100644
index 0000000..a7aa026
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont5.0
@@ -0,0 +1,14 @@
+# $FreeBSD$
+
+bad=1
+case x in
+x\
+) ;\
+; *) exit 7
+esac &\
+& bad= &\
+& : >\
+>/dev/null
+
+false |\
+| [ -z "$bad" ]
diff --git a/bin/sh/tests/parser/line-cont6.0 b/bin/sh/tests/parser/line-cont6.0
new file mode 100644
index 0000000..b12125b
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont6.0
@@ -0,0 +1,23 @@
+# $FreeBSD$
+
+v0\
+=abc
+
+v=$(cat <\
+<\
+E\
+O\
+F
+${v0}d
+EOF
+)
+
+w=$(cat <\
+<\
+-\
+EOF
+ efgh
+EOF
+)
+
+[ "$v.$w" = "abcd.efgh" ]
diff --git a/bin/sh/tests/parser/line-cont7.0 b/bin/sh/tests/parser/line-cont7.0
new file mode 100644
index 0000000..27f8aec
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont7.0
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+[ "$(\
+(
+1\
++ 1)\
+)" = 2 ]
diff --git a/bin/sh/tests/parser/line-cont8.0 b/bin/sh/tests/parser/line-cont8.0
new file mode 100644
index 0000000..88667760
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont8.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+set -- a b c d e f g h i j
+[ "${1\
+0\
+}" = j ]
diff --git a/bin/sh/tests/parser/line-cont9.0 b/bin/sh/tests/parser/line-cont9.0
new file mode 100644
index 0000000..4e73c8f
--- /dev/null
+++ b/bin/sh/tests/parser/line-cont9.0
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+[ "${$\
+:\
++\
+xyz}" = xyz ]
diff --git a/bin/sh/tests/set-e/Makefile b/bin/sh/tests/set-e/Makefile
index 55d7917..f733b60 100644
--- a/bin/sh/tests/set-e/Makefile
+++ b/bin/sh/tests/set-e/Makefile
@@ -1,9 +1,11 @@
# $FreeBSD$
-.include <bsd.own.mk>
+TESTSDIR= ${TESTSBASE}/bin/sh/${.CURDIR:T}
-FILESDIR= ${TESTSBASE}/bin/sh/set-e
-KYUAFILE= no
+.PATH: ${.CURDIR:H}
+ATF_TESTS_SH= functional_test
+
+FILESDIR= ${TESTSDIR}
FILES= and1.0
FILES+= and2.1
diff --git a/bin/sh/trap.c b/bin/sh/trap.c
index e5a2a91..8ea3b12 100644
--- a/bin/sh/trap.c
+++ b/bin/sh/trap.c
@@ -510,28 +510,25 @@ exitshell_savedstatus(void)
exiting_exitstatus = oexitstatus;
}
exitstatus = oexitstatus = exiting_exitstatus;
- if (setjmp(loc1.loc)) {
- goto l1;
- }
- if (setjmp(loc2.loc)) {
- goto l2;
- }
- handler = &loc1;
- if ((p = trap[0]) != NULL && *p != '\0') {
- /*
- * Reset evalskip, or the trap on EXIT could be
- * interrupted if the last command was a "return".
- */
- evalskip = 0;
- trap[0] = NULL;
- evalstring(p, 0);
+ if (!setjmp(loc1.loc)) {
+ handler = &loc1;
+ if ((p = trap[0]) != NULL && *p != '\0') {
+ /*
+ * Reset evalskip, or the trap on EXIT could be
+ * interrupted if the last command was a "return".
+ */
+ evalskip = 0;
+ trap[0] = NULL;
+ evalstring(p, 0);
+ }
}
-l1: handler = &loc2; /* probably unnecessary */
- flushall();
+ if (!setjmp(loc2.loc)) {
+ handler = &loc2; /* probably unnecessary */
+ flushall();
#if JOBS
- setjobctl(0);
+ setjobctl(0);
#endif
-l2:
+ }
if (sig != 0 && sig != SIGSTOP && sig != SIGTSTP && sig != SIGTTIN &&
sig != SIGTTOU) {
signal(sig, SIG_DFL);
diff --git a/bin/sleep/Makefile b/bin/sleep/Makefile
index 4ff7330..0ec3080 100644
--- a/bin/sleep/Makefile
+++ b/bin/sleep/Makefile
@@ -1,6 +1,12 @@
# @(#)Makefile 8.1 (Berkeley) 5/31/93
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= sleep
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/bin/sleep/tests/Makefile b/bin/sleep/tests/Makefile
new file mode 100644
index 0000000..9b286e6
--- /dev/null
+++ b/bin/sleep/tests/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+TESTSRC= ${.CURDIR}/../../../contrib/netbsd-tests/bin/sleep
+.PATH: ${TESTSRC}
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/bin/sleep
+ATF_TESTS_SH= sleep_test
+ATF_TESTS_SH_SRC_sleep_test= t_sleep.sh
+
+.include <bsd.test.mk>
OpenPOWER on IntegriCloud