diff options
author | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
---|---|---|
committer | sjg <sjg@FreeBSD.org> | 2014-11-19 01:07:58 +0000 |
commit | b137080f19736ee33fede2e88bb54438604cf86b (patch) | |
tree | 377ac0ac449528621eb192cd245adadb5fd53668 /bin | |
parent | ab21a29eb607d4dfe389b965fbdee27558e791aa (diff) | |
parent | 4a8d07956d121238d006d34ffe7d6269744e8b1a (diff) | |
download | FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.zip FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.tar.gz |
Merge from head@274682
Diffstat (limited to 'bin')
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> |