Index: head/bin/sh/miscbltin.c =================================================================== --- head/bin/sh/miscbltin.c (revision 286825) +++ head/bin/sh/miscbltin.c (revision 286826) @@ -1,523 +1,524 @@ /*- * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ #ifndef lint #if 0 static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); /* * Miscellaneous builtins. */ #include #include #include #include #include #include #include #include #include #include "shell.h" #include "options.h" #include "var.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "mystring.h" #include "syntax.h" #include "trap.h" #undef eflag int readcmd(int, char **); int umaskcmd(int, char **); int ulimitcmd(int, char **); /* * The read builtin. The -r option causes backslashes to be treated like * ordinary characters. * * This uses unbuffered input, which may be avoidable in some cases. * * Note that if IFS=' :' then read x y should work so that: * 'a b' x='a', y='b' * ' a b ' x='a', y='b' * ':b' x='', y='b' * ':' x='', y='' * '::' x='', y='' * ': :' x='', y='' * ':::' x='', y='::' * ':b c:' x='', y='b c:' */ int readcmd(int argc __unused, char **argv __unused) { char **ap; int backslash; char c; int rflag; char *prompt; const char *ifs; char *p; int startword; int status; int i; int is_ifs; int saveall = 0; struct timeval tv; char *tvptr; fd_set ifds; ssize_t nread; int sig; rflag = 0; prompt = NULL; tv.tv_sec = -1; tv.tv_usec = 0; while ((i = nextopt("erp:t:")) != '\0') { switch(i) { case 'p': prompt = shoptarg; break; case 'e': break; case 'r': rflag = 1; break; case 't': tv.tv_sec = strtol(shoptarg, &tvptr, 0); if (tvptr == shoptarg) error("timeout value"); switch(*tvptr) { case 0: case 's': break; case 'h': tv.tv_sec *= 60; /* FALLTHROUGH */ case 'm': tv.tv_sec *= 60; break; default: error("timeout unit"); } break; } } if (prompt && isatty(0)) { out2str(prompt); flushall(); } if (*(ap = argptr) == NULL) error("arg count"); if ((ifs = bltinlookup("IFS", 1)) == NULL) ifs = " \t\n"; if (tv.tv_sec >= 0) { /* * Wait for something to become available. */ FD_ZERO(&ifds); FD_SET(0, &ifds); status = select(1, &ifds, NULL, NULL, &tv); /* * If there's nothing ready, return an error. */ if (status <= 0) { sig = pendingsig; return (128 + (sig != 0 ? sig : SIGALRM)); } } status = 0; startword = 2; backslash = 0; STARTSTACKSTR(p); for (;;) { nread = read(STDIN_FILENO, &c, 1); if (nread == -1) { if (errno == EINTR) { sig = pendingsig; if (sig == 0) continue; status = 128 + sig; break; } warning("read error: %s", strerror(errno)); status = 2; break; } else if (nread != 1) { status = 1; break; } if (c == '\0') continue; CHECKSTRSPACE(1, p); if (backslash) { backslash = 0; - startword = 0; - if (c != '\n') + if (c != '\n') { + startword = 0; USTPUTC(c, p); + } continue; } if (!rflag && c == '\\') { backslash++; continue; } if (c == '\n') break; if (strchr(ifs, c)) is_ifs = strchr(" \t\n", c) ? 1 : 2; else is_ifs = 0; if (startword != 0) { if (is_ifs == 1) { /* Ignore leading IFS whitespace */ if (saveall) USTPUTC(c, p); continue; } if (is_ifs == 2 && startword == 1) { /* Only one non-whitespace IFS per word */ startword = 2; if (saveall) USTPUTC(c, p); continue; } } if (is_ifs == 0) { /* append this character to the current variable */ startword = 0; if (saveall) /* Not just a spare terminator */ saveall++; USTPUTC(c, p); continue; } /* end of variable... */ startword = is_ifs; if (ap[1] == NULL) { /* Last variable needs all IFS chars */ saveall++; USTPUTC(c, p); continue; } STACKSTRNUL(p); setvar(*ap, stackblock(), 0); ap++; STARTSTACKSTR(p); } STACKSTRNUL(p); /* Remove trailing IFS chars */ for (; stackblock() <= --p; *p = 0) { if (!strchr(ifs, *p)) break; if (strchr(" \t\n", *p)) /* Always remove whitespace */ continue; if (saveall > 1) /* Don't remove non-whitespace unless it was naked */ break; } setvar(*ap, stackblock(), 0); /* Set any remaining args to "" */ while (*++ap != NULL) setvar(*ap, "", 0); return status; } int umaskcmd(int argc __unused, char **argv __unused) { char *ap; int mask; int i; int symbolic_mode = 0; while ((i = nextopt("S")) != '\0') { symbolic_mode = 1; } INTOFF; mask = umask(0); umask(mask); INTON; if ((ap = *argptr) == NULL) { if (symbolic_mode) { char u[4], g[4], o[4]; i = 0; if ((mask & S_IRUSR) == 0) u[i++] = 'r'; if ((mask & S_IWUSR) == 0) u[i++] = 'w'; if ((mask & S_IXUSR) == 0) u[i++] = 'x'; u[i] = '\0'; i = 0; if ((mask & S_IRGRP) == 0) g[i++] = 'r'; if ((mask & S_IWGRP) == 0) g[i++] = 'w'; if ((mask & S_IXGRP) == 0) g[i++] = 'x'; g[i] = '\0'; i = 0; if ((mask & S_IROTH) == 0) o[i++] = 'r'; if ((mask & S_IWOTH) == 0) o[i++] = 'w'; if ((mask & S_IXOTH) == 0) o[i++] = 'x'; o[i] = '\0'; out1fmt("u=%s,g=%s,o=%s\n", u, g, o); } else { out1fmt("%.4o\n", mask); } } else { if (is_digit(*ap)) { mask = 0; do { if (*ap >= '8' || *ap < '0') error("Illegal number: %s", *argptr); mask = (mask << 3) + (*ap - '0'); } while (*++ap != '\0'); umask(mask); } else { void *set; INTOFF; if ((set = setmode (ap)) == 0) error("Illegal number: %s", ap); mask = getmode (set, ~mask & 0777); umask(~mask & 0777); free(set); INTON; } } return 0; } /* * ulimit builtin * * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with * ash by J.T. Conklin. * * Public domain. */ struct limits { const char *name; const char *units; int cmd; int factor; /* multiply by to get rlim_{cur,max} values */ char option; }; static const struct limits limits[] = { #ifdef RLIMIT_CPU { "cpu time", "seconds", RLIMIT_CPU, 1, 't' }, #endif #ifdef RLIMIT_FSIZE { "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' }, #endif #ifdef RLIMIT_DATA { "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' }, #endif #ifdef RLIMIT_STACK { "stack size", "kbytes", RLIMIT_STACK, 1024, 's' }, #endif #ifdef RLIMIT_CORE { "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' }, #endif #ifdef RLIMIT_RSS { "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' }, #endif #ifdef RLIMIT_MEMLOCK { "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' }, #endif #ifdef RLIMIT_NPROC { "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' }, #endif #ifdef RLIMIT_NOFILE { "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' }, #endif #ifdef RLIMIT_VMEM { "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' }, #endif #ifdef RLIMIT_SWAP { "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' }, #endif #ifdef RLIMIT_SBSIZE { "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' }, #endif #ifdef RLIMIT_NPTS { "pseudo-terminals", (char *)0, RLIMIT_NPTS, 1, 'p' }, #endif #ifdef RLIMIT_KQUEUES { "kqueues", (char *)0, RLIMIT_KQUEUES, 1, 'k' }, #endif { (char *) 0, (char *)0, 0, 0, '\0' } }; enum limithow { SOFT = 0x1, HARD = 0x2 }; static void printlimit(enum limithow how, const struct rlimit *limit, const struct limits *l) { rlim_t val = 0; if (how & SOFT) val = limit->rlim_cur; else if (how & HARD) val = limit->rlim_max; if (val == RLIM_INFINITY) out1str("unlimited\n"); else { val /= l->factor; out1fmt("%jd\n", (intmax_t)val); } } int ulimitcmd(int argc __unused, char **argv __unused) { rlim_t val = 0; enum limithow how = SOFT | HARD; const struct limits *l; int set, all = 0; int optc, what; struct rlimit limit; what = 'f'; while ((optc = nextopt("HSatfdsmcnuvlbpwk")) != '\0') switch (optc) { case 'H': how = HARD; break; case 'S': how = SOFT; break; case 'a': all = 1; break; default: what = optc; } for (l = limits; l->name && l->option != what; l++) ; if (!l->name) error("internal error (%c)", what); set = *argptr ? 1 : 0; if (set) { char *p = *argptr; if (all || argptr[1]) error("too many arguments"); if (strcmp(p, "unlimited") == 0) val = RLIM_INFINITY; else { char *end; uintmax_t uval; if (*p < '0' || *p > '9') error("bad number"); errno = 0; uval = strtoumax(p, &end, 10); if (errno != 0 || *end != '\0') error("bad number"); if (uval > UINTMAX_MAX / l->factor) error("bad number"); uval *= l->factor; val = (rlim_t)uval; if (val < 0 || (uintmax_t)val != uval || val == RLIM_INFINITY) error("bad number"); } } if (all) { for (l = limits; l->name; l++) { char optbuf[40]; if (getrlimit(l->cmd, &limit) < 0) error("can't get limit: %s", strerror(errno)); if (l->units) snprintf(optbuf, sizeof(optbuf), "(%s, -%c) ", l->units, l->option); else snprintf(optbuf, sizeof(optbuf), "(-%c) ", l->option); out1fmt("%-18s %18s ", l->name, optbuf); printlimit(how, &limit, l); } return 0; } if (getrlimit(l->cmd, &limit) < 0) error("can't get limit: %s", strerror(errno)); if (set) { if (how & SOFT) limit.rlim_cur = val; if (how & HARD) limit.rlim_max = val; if (setrlimit(l->cmd, &limit) < 0) error("bad limit: %s", strerror(errno)); } else printlimit(how, &limit, l); return 0; } Index: head/bin/sh/tests/builtins/Makefile =================================================================== --- head/bin/sh/tests/builtins/Makefile (revision 286825) +++ head/bin/sh/tests/builtins/Makefile (revision 286826) @@ -1,167 +1,168 @@ # $FreeBSD$ .include 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 FILES+= alias3.0 alias3.0.stdout FILES+= alias4.0 FILES+= break1.0 FILES+= break2.0 break2.0.stdout FILES+= break3.0 FILES+= break4.4 FILES+= break5.4 FILES+= break6.0 FILES+= builtin1.0 FILES+= case1.0 FILES+= case2.0 FILES+= case3.0 FILES+= case4.0 FILES+= case5.0 FILES+= case6.0 FILES+= case7.0 FILES+= case8.0 FILES+= case9.0 FILES+= case10.0 FILES+= case11.0 FILES+= case12.0 FILES+= case13.0 FILES+= case14.0 FILES+= case15.0 FILES+= case16.0 FILES+= case17.0 FILES+= case18.0 FILES+= case19.0 FILES+= cd1.0 FILES+= cd2.0 FILES+= cd3.0 FILES+= cd4.0 FILES+= cd5.0 FILES+= cd6.0 FILES+= cd7.0 FILES+= cd8.0 FILES+= command1.0 FILES+= command2.0 FILES+= command3.0 FILES+= command3.0.stdout FILES+= command4.0 FILES+= command5.0 FILES+= command5.0.stdout FILES+= command6.0 FILES+= command6.0.stdout FILES+= command7.0 FILES+= command8.0 FILES+= command9.0 FILES+= command10.0 FILES+= command11.0 FILES+= command12.0 FILES+= dot1.0 FILES+= dot2.0 FILES+= dot3.0 FILES+= dot4.0 FILES+= eval1.0 FILES+= eval2.0 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 FILES+= exit2.8 FILES+= exit3.0 FILES+= export1.0 FILES+= fc1.0 FILES+= fc2.0 FILES+= for1.0 FILES+= for2.0 FILES+= for3.0 FILES+= getopts1.0 getopts1.0.stdout FILES+= getopts2.0 getopts2.0.stdout FILES+= getopts3.0 FILES+= getopts4.0 FILES+= getopts5.0 FILES+= getopts6.0 FILES+= getopts7.0 FILES+= getopts8.0 getopts8.0.stdout FILES+= hash1.0 hash1.0.stdout FILES+= hash2.0 hash2.0.stdout FILES+= hash3.0 hash3.0.stdout FILES+= hash4.0 FILES+= jobid1.0 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 FILES+= local4.0 .if ${MK_NLS} != "no" FILES+= locale1.0 .endif FILES+= printf1.0 FILES+= printf2.0 FILES+= printf3.0 FILES+= printf4.0 FILES+= read1.0 read1.0.stdout FILES+= read2.0 FILES+= read3.0 read3.0.stdout FILES+= read4.0 read4.0.stdout FILES+= read5.0 FILES+= read6.0 FILES+= read7.0 +FILES+= read8.0 FILES+= return1.0 FILES+= return2.1 FILES+= return3.1 FILES+= return4.0 FILES+= return5.0 FILES+= return6.4 FILES+= return7.4 FILES+= return8.0 FILES+= set1.0 FILES+= set2.0 FILES+= trap1.0 FILES+= trap10.0 FILES+= trap11.0 FILES+= trap12.0 FILES+= trap13.0 FILES+= trap14.0 FILES+= trap15.0 FILES+= trap16.0 FILES+= trap2.0 FILES+= trap3.0 FILES+= trap4.0 FILES+= trap5.0 FILES+= trap6.0 FILES+= trap7.0 FILES+= trap8.0 FILES+= trap9.0 FILES+= type1.0 type1.0.stderr FILES+= type2.0 FILES+= type3.0 FILES+= unalias.0 FILES+= var-assign.0 FILES+= var-assign2.0 FILES+= wait1.0 FILES+= wait2.0 FILES+= wait3.0 FILES+= wait4.0 FILES+= wait5.0 FILES+= wait6.0 FILES+= wait7.0 FILES+= wait8.0 FILES+= wait9.127 FILES+= wait10.0 .include Index: head/bin/sh/tests/builtins/read8.0 =================================================================== --- head/bin/sh/tests/builtins/read8.0 (nonexistent) +++ head/bin/sh/tests/builtins/read8.0 (revision 286826) @@ -0,0 +1,17 @@ +# $FreeBSD$ + +read a b c <<\EOF +\ +A\ + \ + \ + \ +B\ + \ + \ +C\ + \ + \ + \ +EOF +[ "$a.$b.$c" = "A.B.C" ] Property changes on: head/bin/sh/tests/builtins/read8.0 ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property