diff --git a/commands/ash/Makefile b/commands/ash/Makefile index cbbb0e588..37799751e 100755 --- a/commands/ash/Makefile +++ b/commands/ash/Makefile @@ -1,41 +1,61 @@ # Makefile for ash. -SRCS= builtins.c cd.c dirent.c error.c eval.c exec.c expand.c input.c \ +SRCS= alias.c builtins.c cd.c error.c eval.c exec.c expand.c histedit.c \ + input.c \ jobs.c mail.c main.c memalloc.c miscbltin.c mystring.c nodes.c \ - options.c parser.c redir.c show.c signames.c syntax.c trap.c \ + options.c parser.c redir.c setmode.c show.c signames.c syntax.c \ + trap.c \ output.c var.c -OBJS= builtins.o cd.o dirent.o error.o eval.o exec.o expand.o input.o \ +OBJS= alias.o builtins.o cd.o error.o eval.o exec.o expand.o histedit.o \ + input.o \ jobs.o mail.o main.o memalloc.o miscbltin.o mystring.o nodes.o \ - options.o parser.o redir.o show.o signames.o syntax.o trap.o \ + options.o parser.o redir.o setmode.o show.o signames.o syntax.o \ + trap.o \ output.o var.o init.o \ - bltin/echo.o bltin/expr.o bltin/operators.o bltin/regexp.o + bltin/echo.o bltin/expr.o bltin/operators.o bltin/regexp.o \ + arith.o arith_lex.o -# -# Set READLINE in shell.h and add -ledit to LIBS if you want to use the -# editline package by Simmule Turner and Rich Salz. (The big, bloated -# and GPL contaminated FSF readline should work too.) -# -CPPFLAGS= -DSHELL -I. -D_MINIX -D_POSIX_SOURCE -CFLAGS= -wo -i $(CPPFLAGS) -LIBS= -ledit -CC = exec cc +LEX=flex +YACC=yacc +.c.o: + $(CC) $(CFLAGS) -c $< -o $@ + +# Enable this line to disable command line editing +#EDIT=-DNO_HISTORY +# Enable this line to use the editline library instead of libedit +EDIT=-DEDITLINE +EDITLIB=-ledit + +FLEXLIB=-lfl + +# Enable this line if your system does not have a +NO_PATHS_H=-DNO_PATHS_H + +# Enable this if you don't want job control +NO_JOBS=-DJOBS=0 +MKB_NO_JOBS=-j + +CPPFLAGS= -DSHELL -I. -D_MINIX $(EDIT) $(NO_PATHS_H) $(NO_JOBS) +CFLAGS= $(OPT) $(CPPFLAGS) +LIBS= $(EDITLIB) $(FLEXLIB) CLEANFILES= $(OBJS) \ - builtins.c builtins.h init.c mkinit mknodes mksignames mksyntax \ - nodes.c nodes.h signames.c signames.h syntax.c syntax.h token.def \ + arith.c arith_y.h arith_lex.c builtins.c builtins.h init.c \ + mkinit mknodes mksignames mksyntax \ + nodes.c nodes.h signames.c signames.h syntax.c syntax.h token.h \ bltin/operators.h bltin/operators.c all: sh sh: $(OBJS) - $(CC) $(CFLAGS) -o sh $(OBJS) $(LIBS) - install -S 100k sh + $(CC) $(CFLAGS) -fnone -o sh $(OBJS) $(LIBS) -install: /usr/bin/ash /usr/bin/sh /bin/sh /bin/bigsh +install: /usr/bin/ash /usr/bin/sh /bin/sh /usr/man/man1/ash.1 \ + /usr/man/man1/echo.1 /usr/man/man1/expr.1 /usr/bin/ash: sh - install -cs -o bin $? $@ + install -c $? $@ /usr/bin/sh: /usr/bin/ash install -l $? $@ @@ -43,8 +63,14 @@ install: /usr/bin/ash /usr/bin/sh /bin/sh /bin/bigsh /bin/sh: /usr/bin/ash install -lcs $? $@ -/bin/bigsh: /usr/bin/ash - install -S 1500000 -lcs $? $@ +/usr/man/man1/ash.1: sh.1 + install -lc $? $@ + +/usr/man/man1/echo.1: bltin/echo.1 + install -lc $? $@ + +/usr/man/man1/expr.1: bltin/expr.1 + install -lc $? $@ clean: rm -f $(CLEANFILES) sh core @@ -54,11 +80,18 @@ parser.o: token.def token.def: mktokens sh mktokens -builtins.c builtins.h: builtins.table shell.h - sh mkbuiltins shell.h builtins.table +arith.c: arith.y + $(YACC) -d $? + mv y.tab.c $@ + mv y.tab.h arith_y.h -init.o: mkinit $(SRCS) - ./mkinit '$(CC) -c $(CFLAGS) init.c' $(SRCS) +arith_lex.c: arith_lex.l + +builtins.c builtins.h: builtins.def shell.h + sh mkbuiltins $(MKB_NO_JOBS) . shell.h builtins.def + +init.c: mkinit $(SRCS) + ./mkinit $(SRCS) mkinit: mkinit.c $(CC) $(CFLAGS) mkinit.c -o $@ @@ -81,20 +114,8 @@ syntax.c syntax.h: mksyntax mksyntax: mksyntax.c parser.h $(CC) $(CFLAGS) mksyntax.c -o $@ -bltin/operators.h: bltin/mkexpr bltin/binary_op bltin/unary_op - cd bltin && sh mkexpr - -bltin/echo.o: bltin/echo.c - cd bltin && $(CC) -I.. $(CFLAGS) -c echo.c - -bltin/expr.o: bltin/expr.c - cd bltin && $(CC) -I.. $(CFLAGS) -c expr.c - -bltin/operators.o: bltin/operators.c - cd bltin && $(CC) -I.. $(CFLAGS) -c operators.c - -bltin/regexp.o: bltin/regexp.c - cd bltin && $(CC) -I.. $(CFLAGS) -c regexp.c +bltin/operators.h: bltin/mkexpr bltin/unary_op bltin/binary_op + cd bltin && sh mkexpr unary_op binary_op # Dependencies you say? This will have to do. $(OBJS): error.h eval.h exec.h expand.h init.h input.h \ @@ -103,3 +124,6 @@ $(OBJS): error.h eval.h exec.h expand.h init.h input.h \ builtins.h nodes.h signames.h syntax.h bltin/expr.o bltin/operators.o: bltin/operators.h + +# +# $PchId: Makefile,v 1.4 2006/05/22 12:40:46 philip Exp $ diff --git a/commands/ash/TOUR b/commands/ash/TOUR index 669c0a933..afd0c8dd2 100755 --- a/commands/ash/TOUR +++ b/commands/ash/TOUR @@ -1,4 +1,13 @@ -# @(#)TOUR 5.1 (Berkeley) 3/7/91 +# @(#)TOUR 8.1 (Berkeley) 5/31/93 +# $FreeBSD: src/bin/sh/TOUR,v 1.6 1999/08/27 23:15:07 peter Exp $ + +NOTE -- This is the original TOUR paper distributed with ash and +does not represent the current state of the shell. It is provided anyway +since it provides helpful information for how the shell is structured, +but be warned that things have changed -- the current shell is +still under development. + +================================================================ A Tour through Ash @@ -20,7 +29,7 @@ programs is: mknodes nodetypes nodes.h nodes.c mksignames - signames.h signames.c mksyntax - syntax.h syntax.c - mktokens - token.def + mktokens - token.h bltin/mkexpr unary_op binary_op operators.h operators.c There are undoubtedly too many of these. Mkinit searches all the @@ -346,3 +355,6 @@ cause the preprocessor can't handle functions with a variable number of arguments. Defining DEBUG also causes the shell to generate a core dump if it is sent a quit signal. The tracing code is in show.c. + +# +# $PchId: TOUR,v 1.3 2006/03/31 11:33:46 philip Exp $ diff --git a/commands/ash/alias.c b/commands/ash/alias.c new file mode 100644 index 000000000..90ef85ba0 --- /dev/null +++ b/commands/ash/alias.c @@ -0,0 +1,265 @@ +/*- + * Copyright (c) 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[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95"; +#endif +#endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include "shell.h" +#include "input.h" +#include "output.h" +#include "error.h" +#include "memalloc.h" +#include "mystring.h" +#include "alias.h" +#include "options.h" /* XXX for argptr (should remove?) */ +#include "builtins.h" + +#define ATABSIZE 39 + +STATIC struct alias *atab[ATABSIZE]; + +STATIC void setalias(char *, char *); +STATIC int unalias(char *); +STATIC struct alias **hashalias(char *); + +STATIC +void +setalias(char *name, char *val) +{ + struct alias *ap, **app; + + app = hashalias(name); + for (ap = *app; ap; ap = ap->next) { + if (equal(name, ap->name)) { + INTOFF; + ckfree(ap->val); + ap->val = savestr(val); + INTON; + return; + } + } + /* not found */ + INTOFF; + ap = ckmalloc(sizeof (struct alias)); + ap->name = savestr(name); + /* + * XXX - HACK: in order that the parser will not finish reading the + * alias value off the input before processing the next alias, we + * dummy up an extra space at the end of the alias. This is a crock + * and should be re-thought. The idea (if you feel inclined to help) + * is to avoid alias recursions. The mechanism used is: when + * expanding an alias, the value of the alias is pushed back on the + * input as a string and a pointer to the alias is stored with the + * string. The alias is marked as being in use. When the input + * routine finishes reading the string, it marks the alias not + * in use. The problem is synchronization with the parser. Since + * it reads ahead, the alias is marked not in use before the + * resulting token(s) is next checked for further alias sub. The + * H A C K is that we add a little fluff after the alias value + * so that the string will not be exhausted. This is a good + * idea ------- ***NOT*** + */ +#ifdef notyet + ap->val = savestr(val); +#else /* hack */ + { + int len = strlen(val); + ap->val = ckmalloc(len + 2); + memcpy(ap->val, val, len); + ap->val[len] = ' '; /* fluff */ + ap->val[len+1] = '\0'; + } +#endif + ap->flag = 0; + ap->next = *app; + *app = ap; + INTON; +} + +STATIC int +unalias(char *name) +{ + struct alias *ap, **app; + + app = hashalias(name); + + for (ap = *app; ap; app = &(ap->next), ap = ap->next) { + if (equal(name, ap->name)) { + /* + * if the alias is currently in use (i.e. its + * buffer is being used by the input routine) we + * just null out the name instead of freeing it. + * We could clear it out later, but this situation + * is so rare that it hardly seems worth it. + */ + if (ap->flag & ALIASINUSE) + *ap->name = '\0'; + else { + INTOFF; + *app = ap->next; + ckfree(ap->name); + ckfree(ap->val); + ckfree(ap); + INTON; + } + return (0); + } + } + + return (1); +} + +#ifdef mkinit +INCLUDE "alias.h" +SHELLPROC { + rmaliases(); +} +#endif + +void +rmaliases(void) +{ + struct alias *ap, *tmp; + int i; + + INTOFF; + for (i = 0; i < ATABSIZE; i++) { + ap = atab[i]; + atab[i] = NULL; + while (ap) { + ckfree(ap->name); + ckfree(ap->val); + tmp = ap; + ap = ap->next; + ckfree(tmp); + } + } + INTON; +} + +struct alias * +lookupalias(char *name, int check) +{ + struct alias *ap = *hashalias(name); + + for (; ap; ap = ap->next) { + if (equal(name, ap->name)) { + if (check && (ap->flag & ALIASINUSE)) + return (NULL); + return (ap); + } + } + + return (NULL); +} + +/* + * TODO - sort output + */ +int +aliascmd(int argc, char **argv) +{ + char *n, *v; + int ret = 0; + struct alias *ap; + + if (argc == 1) { + int i; + + for (i = 0; i < ATABSIZE; i++) + for (ap = atab[i]; ap; ap = ap->next) { + if (*ap->name != '\0') { + out1fmt("alias %s=", ap->name); + out1qstr(ap->val); + out1c('\n'); + } + } + return (0); + } + while ((n = *++argv) != NULL) { + if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ + if ((ap = lookupalias(n, 0)) == NULL) { + outfmt(out2, "alias: %s not found\n", n); + ret = 1; + } else { + out1fmt("alias %s=", n); + out1qstr(ap->val); + out1c('\n'); + } + else { + *v++ = '\0'; + setalias(n, v); + } + } + + return (ret); +} + +int +unaliascmd(int argc __unused, char **argv __unused) +{ + int i; + + while ((i = nextopt("a")) != '\0') { + if (i == 'a') { + rmaliases(); + return (0); + } + } + for (i = 0; *argptr; argptr++) + i = unalias(*argptr); + + return (i); +} + +STATIC struct alias ** +hashalias(char *p) +{ + unsigned int hashval; + + hashval = *p << 4; + while (*p) + hashval+= *p++; + return &atab[hashval % ATABSIZE]; +} + +/* + * $PchId: alias.c,v 1.5 2006/05/22 12:41:12 philip Exp $ + */ diff --git a/commands/ash/alias.h b/commands/ash/alias.h new file mode 100644 index 000000000..e541908f4 --- /dev/null +++ b/commands/ash/alias.h @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 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. + * + * @(#)alias.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/alias.h,v 1.8 2004/04/06 20:06:51 markm Exp $ + */ + +#define ALIASINUSE 1 + +struct alias { + struct alias *next; + char *name; + char *val; + int flag; +}; + +struct alias *lookupalias(char *, int); +int aliascmd(int, char **); +int unaliascmd(int, char **); +void rmaliases(void); + +/* + * $PchId: alias.h,v 1.4 2006/03/31 11:30:54 philip Exp $ + */ diff --git a/commands/ash/arith.h b/commands/ash/arith.h new file mode 100644 index 000000000..90c0a6701 --- /dev/null +++ b/commands/ash/arith.h @@ -0,0 +1,39 @@ +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)arith.h 1.1 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/arith.h,v 1.9 2004/04/06 20:06:51 markm Exp $ + */ + +int arith(char *); +int arith_assign(char *, arith_t); +int expcmd(int, char **); + +/* + * $PchId: arith.h,v 1.3 2006/03/31 11:25:25 philip Exp $ + */ diff --git a/commands/ash/arith.y b/commands/ash/arith.y new file mode 100644 index 000000000..f20eb3287 --- /dev/null +++ b/commands/ash/arith.y @@ -0,0 +1,366 @@ +%{ +/*- + * Copyright (c) 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95"; +#endif +#endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19 2004/05/24 10:11:31 stefanf Exp $"); +*/ + +#include +#include +#include + +#include "shell.h" +#include "arith.h" +#include "arith_lex.h" +#include "var.h" +%} +%union { + arith_t l_value; + char* s_value; +} +%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN +%token ARITH_VAR + +%type expr +%right ARITH_ASSIGN +%right ARITH_ADDASSIGN ARITH_SUBASSIGN +%right ARITH_MULASSIGN ARITH_DIVASSIGN ARITH_REMASSIGN +%right ARITH_RSHASSIGN ARITH_LSHASSIGN +%right ARITH_BANDASSIGN ARITH_BXORASSIGN ARITH_BORASSIGN +%left ARITH_OR +%left ARITH_AND +%left ARITH_BOR +%left ARITH_BXOR +%left ARITH_BAND +%left ARITH_EQ ARITH_NE +%left ARITH_LT ARITH_GT ARITH_GE ARITH_LE +%left ARITH_LSHIFT ARITH_RSHIFT +%left ARITH_ADD ARITH_SUB +%left ARITH_MUL ARITH_DIV ARITH_REM +%left ARITH_UNARYMINUS ARITH_UNARYPLUS ARITH_NOT ARITH_BNOT +%% + +exp: + expr + { return ($1); } + ; + +expr: + ARITH_LPAREN expr ARITH_RPAREN + { $$ = $2; } | + expr ARITH_OR expr + { $$ = $1 ? $1 : $3 ? $3 : 0; } | + expr ARITH_AND expr + { $$ = $1 ? ( $3 ? $3 : 0 ) : 0; } | + expr ARITH_BOR expr + { $$ = $1 | $3; } | + expr ARITH_BXOR expr + { $$ = $1 ^ $3; } | + expr ARITH_BAND expr + { $$ = $1 & $3; } | + expr ARITH_EQ expr + { $$ = $1 == $3; } | + expr ARITH_GT expr + { $$ = $1 > $3; } | + expr ARITH_GE expr + { $$ = $1 >= $3; } | + expr ARITH_LT expr + { $$ = $1 < $3; } | + expr ARITH_LE expr + { $$ = $1 <= $3; } | + expr ARITH_NE expr + { $$ = $1 != $3; } | + expr ARITH_LSHIFT expr + { $$ = $1 << $3; } | + expr ARITH_RSHIFT expr + { $$ = $1 >> $3; } | + expr ARITH_ADD expr + { $$ = $1 + $3; } | + expr ARITH_SUB expr + { $$ = $1 - $3; } | + expr ARITH_MUL expr + { $$ = $1 * $3; } | + expr ARITH_DIV expr + { + if ($3 == 0) + yyerror("division by zero"); + $$ = $1 / $3; + } | + expr ARITH_REM expr + { + if ($3 == 0) + yyerror("division by zero"); + $$ = $1 % $3; + } | + ARITH_NOT expr + { $$ = !($2); } | + ARITH_BNOT expr + { $$ = ~($2); } | + ARITH_SUB expr %prec ARITH_UNARYMINUS + { $$ = -($2); } | + ARITH_ADD expr %prec ARITH_UNARYPLUS + { $$ = $2; } | + ARITH_NUM | + ARITH_VAR + { + char *p; + arith_t arith_val; + char *str_val; + + if (lookupvar($1) == NULL) + setvarsafe($1, "0", 0); + str_val = lookupvar($1); + arith_val = strtoarith_t(str_val, &p, 0); + /* + * Conversion is successful only in case + * we've converted _all_ characters. + */ + if (*p != '\0') + yyerror("variable conversion error"); + $$ = arith_val; + } | + ARITH_VAR ARITH_ASSIGN expr + { + if (arith_assign($1, $3) != 0) + yyerror("variable assignment error"); + $$ = $3; + } | + ARITH_VAR ARITH_ADDASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) + $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_SUBASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) - $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_MULASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) * $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_DIVASSIGN expr + { + arith_t value; + + if ($3 == 0) + yyerror("division by zero"); + + value = atoarith_t(lookupvar($1)) / $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_REMASSIGN expr + { + arith_t value; + + if ($3 == 0) + yyerror("division by zero"); + + value = atoarith_t(lookupvar($1)) % $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_RSHASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) >> $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_LSHASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) << $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_BANDASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) & $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_BXORASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) ^ $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } | + ARITH_VAR ARITH_BORASSIGN expr + { + arith_t value; + + value = atoarith_t(lookupvar($1)) | $3; + if (arith_assign($1, value) != 0) + yyerror("variable assignment error"); + $$ = value; + } ; +%% +#include "error.h" +#include "output.h" +#include "memalloc.h" +#include "builtins.h" + +#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3) + +char *arith_buf, *arith_startbuf; + +int yylex(void); +int yyparse(void); + +int +arith_assign(char *name, arith_t value) +{ + char *str; + int ret; + + str = (char *)ckmalloc(lstrlen(value)); + sprintf(str, ARITH_FORMAT_STR, value); + ret = setvarsafe(name, str, 0); + free(str); + return ret; +} + +int +arith(char *s) +{ + long result; + + arith_buf = arith_startbuf = s; + + INTOFF; + result = yyparse(); + arith_lex_reset(); /* Reprime lex. */ + INTON; + + return result; +} + +void +yyerror(char *s) +{ + + yyerrok; + yyclearin; + arith_lex_reset(); /* Reprime lex. */ + error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); +} + +/* + * The exp(1) builtin. + */ +int +expcmd(int argc, char **argv) +{ + char *p; + char *concat; + char **ap; + long i; + + if (argc > 1) { + p = argv[1]; + if (argc > 2) { + /* + * Concatenate arguments. + */ + STARTSTACKSTR(concat); + ap = argv + 2; + for (;;) { + while (*p) + STPUTC(*p++, concat); + if ((p = *ap++) == NULL) + break; + STPUTC(' ', concat); + } + STPUTC('\0', concat); + p = grabstackstr(concat); + } + } else + p = ""; + + i = arith(p); + + out1fmt("%ld\n", i); + return !i; +} + +/*************************/ +#ifdef TEST_ARITH +#include +main(int argc, char *argv[]) +{ + printf("%d\n", exp(argv[1])); +} + +error(char *s) +{ + fprintf(stderr, "exp: %s\n", s); + exit(1); +} +#endif + +/* + * $PchId: arith.y,v 1.6 2006/05/22 12:41:47 philip Exp $ + */ diff --git a/commands/ash/arith_lex.h b/commands/ash/arith_lex.h new file mode 100644 index 000000000..301befacf --- /dev/null +++ b/commands/ash/arith_lex.h @@ -0,0 +1,12 @@ +/* +arith_lex.h + +Created: July 1995 by Philip Homburg +*/ + +int yylex(void); +void arith_lex_reset(void); + +/* + * $PchId: arith_lex.h,v 1.1 2001/05/18 19:57:55 philip Exp $ + */ diff --git a/commands/ash/arith_lex.l b/commands/ash/arith_lex.l new file mode 100644 index 000000000..6c5a3616f --- /dev/null +++ b/commands/ash/arith_lex.l @@ -0,0 +1,138 @@ +%{ +/*- + * Copyright (c) 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. + */ + +#if 0 +#ifndef lint +static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95"; +#endif +#endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/arith_lex.l,v 1.22 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include + +#include "shell.h" +#include "arith_lex.h" +#include "arith_y.h" +#include "error.h" +#include "memalloc.h" +#include "var.h" + +extern char *arith_buf, *arith_startbuf; +#undef YY_INPUT +#define YY_INPUT(buf,result,max) \ + result = (*buf = *arith_buf++) ? 1 : YY_NULL; +#define YY_NO_UNPUT +%} + +%% +[ \t\n] { ; } + +0x[a-fA-F0-9]+ { + yylval.l_value = strtoarith_t(yytext, NULL, 16); + return ARITH_NUM; + } + +0[0-7]+ { + yylval.l_value = strtoarith_t(yytext, NULL, 8); + return ARITH_NUM; + } + +[0-9]+ { + yylval.l_value = strtoarith_t(yytext, NULL, 10); + return ARITH_NUM; + } + +[A-Za-z][A-Za-z0-9_]* { + /* + * If variable doesn't exist, we should initialize + * it to zero. + */ + char *temp; + if (lookupvar(yytext) == NULL) + setvarsafe(yytext, "0", 0); + temp = (char *)ckmalloc(strlen(yytext) + 1); + yylval.s_value = strcpy(temp, yytext); + + return ARITH_VAR; + } + +"(" { return ARITH_LPAREN; } +")" { return ARITH_RPAREN; } +"||" { return ARITH_OR; } +"&&" { return ARITH_AND; } +"|" { return ARITH_BOR; } +"^" { return ARITH_BXOR; } +"&" { return ARITH_BAND; } +"==" { return ARITH_EQ; } +"!=" { return ARITH_NE; } +">" { return ARITH_GT; } +">=" { return ARITH_GE; } +"<" { return ARITH_LT; } +"<=" { return ARITH_LE; } +"<<" { return ARITH_LSHIFT; } +">>" { return ARITH_RSHIFT; } +"*" { return ARITH_MUL; } +"/" { return ARITH_DIV; } +"%" { return ARITH_REM; } +"+" { return ARITH_ADD; } +"-" { return ARITH_SUB; } +"~" { return ARITH_BNOT; } +"!" { return ARITH_NOT; } +"=" { return ARITH_ASSIGN; } +"+=" { return ARITH_ADDASSIGN; } +"-=" { return ARITH_SUBASSIGN; } +"*=" { return ARITH_MULASSIGN; } +"/=" { return ARITH_DIVASSIGN; } +"%=" { return ARITH_REMASSIGN; } +">>=" { return ARITH_RSHASSIGN; } +"<<=" { return ARITH_LSHASSIGN; } +"&=" { return ARITH_BANDASSIGN; } +"^=" { return ARITH_BXORASSIGN; } +"|=" { return ARITH_BORASSIGN; } +. { + error("arith: syntax error: \"%s\"\n", arith_startbuf); + } +%% + +void +arith_lex_reset(void) +{ + YY_NEW_FILE; +} + +/* + * $PchId: arith_lex.l,v 1.5 2006/04/10 14:35:29 philip Exp $ + */ diff --git a/commands/ash/bltin/bltin.h b/commands/ash/bltin/bltin.h index 5859a01bc..4dc41fac6 100755 --- a/commands/ash/bltin/bltin.h +++ b/commands/ash/bltin/bltin.h @@ -1,26 +1,78 @@ +/*- + * 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. + * + * @(#)bltin.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/bltin/bltin.h,v 1.13 2004/04/06 20:06:53 markm Exp $ + */ + /* * This file is included by programs which are optionally built into the * shell. If SHELL is defined, we try to map the standard UNIX library * routines to ash routines using defines. - * - * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. - * This file is part of ash, which is distributed under the terms specified - * by the Ash General Public License. See the file named LICENSE. */ #include "../shell.h" #include "../mystring.h" #ifdef SHELL +#include "builtins.h" #include "../output.h" +#undef stdout #define stdout out1 +#undef stderr #define stderr out2 #define printf out1fmt +#undef putc #define putc(c, file) outc(c, file) +#undef putchar #define putchar(c) out1c(c) #define fprintf outfmt #define fputs outstr #define fflush flushout #define INITARGS(argv) +#define warnx1(a, b, c) { \ + char buf[64]; \ + (void)snprintf(buf, sizeof(buf), a); \ + error("%s", buf); \ +} +#define warnx2(a, b, c) { \ + char buf[64]; \ + (void)snprintf(buf, sizeof(buf), a, b); \ + error("%s", buf); \ +} +#define warnx3(a, b, c) { \ + char buf[64]; \ + (void)snprintf(buf, sizeof(buf), a, b, c); \ + error("%s", buf); \ +} + #else #undef NULL #include @@ -28,13 +80,12 @@ #define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else #endif -#ifdef __STDC__ pointer stalloc(int); -void error(char *, ...); -#else -pointer stalloc(); -void error(); -#endif +void error(const char *, ...); extern char *commandname; + +/* + * $PchId: bltin.h,v 1.4 2006/03/29 11:39:00 philip Exp $ + */ diff --git a/commands/ash/bltin/echo.c b/commands/ash/bltin/echo.c index 8855af2dd..9051c0c2c 100755 --- a/commands/ash/bltin/echo.c +++ b/commands/ash/bltin/echo.c @@ -1,74 +1,126 @@ -/* - * Echo command. +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. * - * Copyright (C) 1989 by Kenneth Almquist. All rights reserved. - * This file is part of ash, which is distributed under the terms specified - * by the Ash General Public License. See the file named LICENSE. + * 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. + * + * @(#)echo.c 8.2 (Berkeley) 5/4/95 */ -#define main echocmd +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/bltin/echo.c,v 1.14 2004/04/06 20:06:53 markm Exp $"); +*/ + +/* + * Echo command. + */ + +#ifdef __minix +#define MINIX +#endif #include "bltin.h" +#ifndef MINIX +/* #define eflag 1 */ +#else #undef eflag - - -main(argc, argv) char **argv; { - register char **ap; - register char *p; - register char c; - int count; - int nflag = 0; -#ifndef eflag - int eflag = 0; #endif - ap = argv; - if (argc) - ap++; - if ((p = *ap) != NULL) { - if (equal(p, "--")) { - ap++; - } - if (equal(p, "-n")) { - nflag++; - ap++; - } else if (equal(p, "-e")) { +int +echocmd(argc, argv) + int argc; + char **argv; +{ + char **ap; + char *p; + char c; + int count; + int nflag = 0; #ifndef eflag - eflag++; + int eflag = 0; #endif - ap++; - } - } - while ((p = *ap++) != NULL) { - while ((c = *p++) != '\0') { - if (c == '\\' && eflag) { - switch (*p++) { - case 'b': c = '\b'; break; - case 'c': return 0; /* exit */ - case 'f': c = '\f'; break; - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'v': c = '\v'; break; - case '\\': break; /* c = '\\' */ - case '0': - c = 0; - count = 3; - while (--count >= 0 && (unsigned)(*p - '0') < 8) - c = (c << 3) + (*p++ - '0'); - break; - default: - p--; - break; + + ap = argv; + if (argc) + ap++; + if ((p = *ap) != NULL) { +#ifdef MINIX + if (equal(p, "--")) { + ap++; + } +#endif + if (equal(p, "-n")) { + nflag++; + ap++; + } else if (equal(p, "-e")) { +#ifndef eflag + eflag++; +#endif + ap++; + } + } + while ((p = *ap++) != NULL) { + while ((c = *p++) != '\0') { + if (c == '\\' && eflag) { + switch (*p++) { + case 'a': c = '\a'; break; + case 'b': c = '\b'; break; + case 'c': return 0; /* exit */ + case 'e': c = '\033'; break; + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\\': break; /* c = '\\' */ + case '0': + c = 0; + count = 3; + while (--count >= 0 && (unsigned)(*p - '0') < 8) + c = (c << 3) + (*p++ - '0'); + break; + default: + p--; + break; + } } - } - putchar(c); - } - if (*ap) - putchar(' '); - } - if (! nflag) - putchar('\n'); - return 0; + putchar(c); + } + if (*ap) + putchar(' '); + } + if (! nflag) + putchar('\n'); + return 0; } + +/* + * $PchId: echo.c,v 1.5 2006/05/23 12:05:56 philip Exp $ + */ diff --git a/commands/ash/bltin/expr.c b/commands/ash/bltin/expr.c index 3e9305d86..07052186c 100755 --- a/commands/ash/bltin/expr.c +++ b/commands/ash/bltin/expr.c @@ -7,17 +7,14 @@ */ -#define main exprcmd - #include "bltin.h" #include "operators.h" +#include #include #include +#include +#include -#ifndef S_ISLNK -#define lstat stat -#define S_ISLNK(mode) (0) -#endif #define STACKSIZE 12 #define NESTINCR 16 @@ -50,7 +47,6 @@ struct operator { struct filestat { - int op; /* OP_FILE or OP_LFILE */ char *name; /* name of file */ int rcode; /* return code from stat */ struct stat stat; /* status info on file */ @@ -63,24 +59,18 @@ extern short number_parens; /* number of \( \) pairs */ #ifdef __STDC__ -int expr_is_false(struct value *); -void expr_operator(int, struct value *, struct filestat *); -int lookup_op(char *, char *const*); -char *re_compile(char *); /* defined in regexp.c */ -int re_match(char *, char *); /* defined in regexp.c */ -long atol(const char *); +static int expr_is_false(struct value *); +static void expr_operator(int, struct value *, struct filestat *); +static int lookup_op(char *, char *const*); #else -int expr_is_false(); -void expr_operator(); -int lookup_op(); -char *re_compile(); /* defined in regexp.c */ -int re_match(); /* defined in regexp.c */ -long atol(); +static int expr_is_false(); +static void expr_operator(); +static int lookup_op(); #endif -main(argc, argv) char **argv; { +exprcmd(argc, argv) char **argv; { char **ap; char *opname; char c; @@ -146,6 +136,13 @@ overflow: error("Expression too complex"); continue; } else { + if (opname[0] == '\'') { + for (p = opname ; *++p != '\0' ; ); + if (--p > opname && *p == '\'') { + *p = '\0'; + opname++; + } + } valsp->type = STRING; valsp->u.string = opname; valsp++; @@ -193,19 +190,11 @@ overflow: error("Expression too complex"); valsp->u.string = ""; } valsp->type = STRING; - if (c >= OP_FILE - && (fs.op != c - || fs.name == NULL + if (c == OP_FILE + && (fs.name == NULL || ! equal(fs.name, valsp->u.string))) { - fs.op = c; fs.name = valsp->u.string; - if (c == OP_FILE) { - fs.rcode = stat(valsp->u.string, - &fs.stat); - } else { - fs.rcode = lstat(valsp->u.string, - &fs.stat); - } + fs.rcode = stat(valsp->u.string, &fs.stat); } } if (binary < FIRST_BINARY_OP) @@ -250,7 +239,7 @@ done: } -int +static int expr_is_false(val) struct value *val; { @@ -274,14 +263,16 @@ expr_is_false(val) * to stat, to avoid repeated stat calls on the same file. */ -void +static void expr_operator(op, sp, fs) int op; struct value *sp; struct filestat *fs; { - int i; + int i, r; struct stat st1, st2; + regex_t pat; + regmatch_t rm[2]; switch (op) { case NOT: @@ -343,16 +334,16 @@ filebit: if (fs->stat.st_mode & i && fs->rcode >= 0) goto true; goto false; + case ISSLINK: + if (lstat(fs->name, &st1) == -1) + goto false; + if (S_ISLNK(st1.st_mode)) + goto true; + goto false; case ISSIZE: sp->u.num = fs->rcode >= 0? fs->stat.st_size : 0L; sp->type = INTEGER; break; - case ISLINK1: - case ISLINK2: - if (S_ISLNK(fs->stat.st_mode) && fs->rcode >= 0) - goto true; - fs->op = OP_FILE; /* not a symlink, so expect a -d or so next */ - goto false; case NEWER: if (stat(sp->u.string, &st1) != 0) { sp->u.num = 0; @@ -439,19 +430,21 @@ filebit: break; case MATCHPAT: { - char *pat; - - pat = re_compile((sp + 1)->u.string); - if (re_match(pat, sp->u.string)) { - if (number_parens > 0) { - sp->u.string = match_begin[1]; - sp->u.string[match_length[1]] = '\0'; + r = regcomp(&pat, (sp + 1)->u.string, 0); + if (r) + error("Bad regular expression"); + if (regexec(&pat, sp->u.string, 2, rm, 0) == 0 && + rm[0].rm_so == 0) + { + if (pat.re_nsub > 0) { + sp->u.string[rm[1].rm_eo] = '\0'; + sp->u.string = sp->u.string+rm[1].rm_so; } else { - sp->u.num = match_length[0]; + sp->u.num = rm[0].rm_eo; sp->type = INTEGER; } } else { - if (number_parens > 0) { + if (pat.re_nsub > 0) { sp->u.string[0] = '\0'; } else { sp->u.num = 0; @@ -464,7 +457,7 @@ filebit: } -int +static int lookup_op(name, table) char *name; char *const*table; diff --git a/commands/ash/bltin/mkexpr b/commands/ash/bltin/mkexpr index a5b9b9d87..7b7397f9c 100755 --- a/commands/ash/bltin/mkexpr +++ b/commands/ash/bltin/mkexpr @@ -5,21 +5,28 @@ # All calls to awk removed, because Minix bawk is deficient. (kjb) +if [ $# -ne 2 ] +then + echo "Usage: $0 " >&2 + exit 1 +fi +unary_op="$1" +binary_op="$2" + exec > operators.h i=0 -sed -e '/^[^#]/!d' unary_op binary_op | while read line +sed -e '/^[^#]/!d' "$unary_op" "$binary_op" | while read line do set -$- $line echo "#define $1 $i" i=`expr $i + 1` done echo -echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' unary_op | wc -l` +echo "#define FIRST_BINARY_OP" `sed -e '/^[^#]/!d' "$unary_op" | wc -l` echo ' #define OP_INT 1 /* arguments to operator are integer */ #define OP_STRING 2 /* arguments to operator are string */ #define OP_FILE 3 /* argument is a file name */ -#define OP_LFILE 4 /* argument is a file name of a symlink? */ extern char *const unary_op[]; extern char *const binary_op[]; @@ -31,14 +38,15 @@ echo '/* * Operators used in the expr/test command. */ -#include "../shell.h" +#include +#include "shell.h" #include "operators.h" char *const unary_op[] = {' sed -e '/^[^#]/!d s/[ ][ ]*/ /g s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/ - ' unary_op + ' "$unary_op" echo ' NULL }; @@ -46,7 +54,7 @@ char *const binary_op[] = {' sed -e '/^[^#]/!d s/[ ][ ]*/ /g s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/ - ' binary_op + ' "$binary_op" echo ' NULL }; @@ -54,7 +62,7 @@ const char op_priority[] = {' sed -e '/^[^#]/!d s/[ ][ ]*/ /g s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/ \1,/ - ' unary_op binary_op + ' "$unary_op" "$binary_op" echo '}; const char op_argflag[] = {' @@ -62,5 +70,5 @@ sed -e '/^[^#]/!d s/[ ][ ]*/ /g s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/ s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/ \1,/ - ' unary_op binary_op + ' "$unary_op" "$binary_op" echo '};' diff --git a/commands/ash/bltin/myregexp.h b/commands/ash/bltin/myregexp.h new file mode 100644 index 000000000..83006a18a --- /dev/null +++ b/commands/ash/bltin/myregexp.h @@ -0,0 +1,8 @@ +/* +myregexp.h + +Created: July 1995 by Philip Homburg +*/ + +char *re_compile(char *pattern); +int re_match(char *pattern, char *string); diff --git a/commands/ash/bltin/regexp.c b/commands/ash/bltin/regexp.c index cd026ac95..7ef68ba1f 100755 --- a/commands/ash/bltin/regexp.c +++ b/commands/ash/bltin/regexp.c @@ -8,7 +8,9 @@ */ #include "bltin.h" +#include "myregexp.h" +#include #define RE_END 0 /* end of regular expression */ #define RE_LITERAL 1 /* normal character follows */ @@ -27,7 +29,7 @@ char *match_begin[10]; short match_length[10]; short number_parens; -static int match(); +static int match(char *pattern, char *string); @@ -48,7 +50,6 @@ re_compile(pattern) char stack[10]; int paren_num; int i; - char *malloc(); p = pattern; if (*p == '^') @@ -176,6 +177,7 @@ out: +int re_match(pattern, string) char *pattern; char *string; @@ -246,7 +248,7 @@ ccl: p++; } p++; - if (found == negate || c == 0) + if (found == negate) goto bad; break; case RE_LP: diff --git a/commands/ash/bltin/unary_op b/commands/ash/bltin/unary_op index 4a9ddccf7..26748aa62 100755 --- a/commands/ash/bltin/unary_op +++ b/commands/ash/bltin/unary_op @@ -16,9 +16,8 @@ ISFIFO -p 12 OP_FILE ISSETUID -u 12 OP_FILE ISSETGID -g 12 OP_FILE ISSTICKY -k 12 OP_FILE +ISSLINK -h 12 OP_FILE ISSIZE -s 12 OP_FILE -ISLINK1 -h 12 OP_LFILE -ISLINK2 -L 12 OP_LFILE ISTTY -t 12 OP_INT NULSTR -z 12 OP_STRING STRLEN -n 12 OP_STRING diff --git a/commands/ash/build b/commands/ash/build deleted file mode 100755 index 3ee5f0395..000000000 --- a/commands/ash/build +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -make clean -make && make install diff --git a/commands/ash/builtins.table b/commands/ash/builtins old mode 100755 new mode 100644 similarity index 88% rename from commands/ash/builtins.table rename to commands/ash/builtins index 864cdb3d3..57409b1fc --- a/commands/ash/builtins.table +++ b/commands/ash/builtins @@ -1,7 +1,7 @@ #!/bin/sh - # -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -34,19 +34,21 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)builtins 5.1 (Berkeley) 3/7/91 +# @(#)builtins 8.1 (Berkeley) 5/31/93 # # This file lists all the builtin commands. The first column is the name # of a C routine. The -j flag, if present, specifies that this command # is to be excluded from systems without job control. The rest of the line # specifies the command name or names used to run the command. The entry -# for nullcmd, which is run when the user does not specify a command, must +# for bltincmd, which is run when the user does not specify a command, must # come first. # # Copyright (C) 1989 by Kenneth Almquist. All rights reserved. # This file is part of ash, which is distributed under the terms specified # by the Ash General Public License. See the file named LICENSE. +# +# NOTE: bltincmd must come first! bltincmd command #alloccmd alloc @@ -59,17 +61,19 @@ echocmd echo evalcmd eval execcmd exec exitcmd exit +expcmd exp let exportcmd export readonly -exprcmd expr test [ +#exprcmd expr test [ +histcmd fc fgcmd -j fg getoptscmd getopts hashcmd hash jobidcmd jobid jobscmd jobs -#lccmd lc #linecmd line localcmd local #nlechocmd nlecho +printfcmd printf pwdcmd pwd readcmd read returncmd return @@ -77,7 +81,10 @@ setcmd set setvarcmd setvar shiftcmd shift trapcmd trap -truecmd : true false +truecmd : true umaskcmd umask +unaliascmd unalias unsetcmd unset waitcmd wait +#foocmd foo +aliascmd alias diff --git a/commands/ash/builtins.def b/commands/ash/builtins.def new file mode 100644 index 000000000..0deae5977 --- /dev/null +++ b/commands/ash/builtins.def @@ -0,0 +1,94 @@ +#!/bin/sh - +# +# 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. +# +# @(#)builtins.def 8.4 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/builtins.def,v 1.14 2004/04/06 20:06:51 markm Exp $ + +# +# This file lists all the builtin commands. The first column is the name +# of a C routine. The -j flag, if present, specifies that this command +# is to be excluded from systems without job control, and the -h flag, +# if present specifies that this command is to be excluded from systems +# based on the NO_HISTORY compile-time symbol. The rest of the line +# specifies the command name or names used to run the command. The entry +# for bltincmd, which is run when the user does not specify a command, must +# come first. +# +# NOTE: bltincmd must come first! + +bltincmd builtin +commandcmd command +#alloccmd alloc +bgcmd -j bg +breakcmd break continue +#catfcmd catf +cdcmd cd chdir +dotcmd . +echocmd echo +evalcmd eval +execcmd exec +exitcmd exit +expcmd exp let +exportcmd export readonly +exprcmd expr test [ +falsecmd false +histcmd -h fc +fgcmd -j fg +getoptscmd getopts +hashcmd hash +jobidcmd jobid +jobscmd jobs +#linecmd line +localcmd local +#nlechocmd nlecho +#printfcmd printf +pwdcmd pwd +readcmd read +returncmd return +setcmd set +setvarcmd setvar +shiftcmd shift +trapcmd trap +truecmd : true +typecmd type +umaskcmd umask +unaliascmd unalias +unsetcmd unset +waitcmd wait +#foocmd foo +aliascmd alias +ulimitcmd ulimit +bindcmd bind +wordexpcmd wordexp + +# +# $PchId: builtins.def,v 1.5 2006/03/31 10:50:57 philip Exp $ diff --git a/commands/ash/cd.c b/commands/ash/cd.c index d1baf3754..e54289d7c 100755 --- a/commands/ash/cd.c +++ b/commands/ash/cd.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,22 @@ */ #ifndef lint -static char sccsid[] = "@(#)cd.c 5.2 (Berkeley) 3/13/91"; +#if 0 +static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include +#include +#include +#include +#include +#include /* * The cd and pwd commands. @@ -50,115 +60,124 @@ static char sccsid[] = "@(#)cd.c 5.2 (Berkeley) 3/13/91"; #include "output.h" #include "memalloc.h" #include "error.h" +#include "exec.h" +#include "redir.h" #include "mystring.h" -#include -#include -#include +#include "builtins.h" +#include "show.h" +#include "cd.h" - -#ifdef __STDC__ +STATIC int cdlogical(char *); +STATIC int cdphysical(char *); STATIC int docd(char *, int, int); -STATIC void updatepwd(char *); -STATIC void getpwd(void); STATIC char *getcomponent(void); -#else -STATIC int docd(); -STATIC void updatepwd(); -STATIC void getpwd(); -STATIC char *getcomponent(); -#endif +STATIC int updatepwd(char *); - -char *curdir; /* current working directory */ +STATIC char *curdir = NULL; /* current working directory */ +STATIC char *prevdir; /* previous working directory */ STATIC char *cdcomppath; -#if UDIR || TILDE -extern int didudir; /* set if /u/logname or ~logname expanded */ -#endif - - int -cdcmd(argc, argv) char **argv; { +cdcmd(int argc, char **argv) +{ char *dest; char *path; char *p; struct stat statb; - char *padvance(); - int tohome= 0; + int ch, phys, print = 0; - nextopt(nullstr); - if ((dest = *argptr) == NULL) { - if ((dest = bltinlookup("HOME", 1)) == NULL) - error("HOME not set"); - tohome = 1; + optreset = 1; optind = 1; opterr = 0; /* initialize getopt */ + phys = Pflag; + while ((ch = getopt(argc, argv, "LP")) != -1) { + switch (ch) { + case 'L': + phys = 0; + break; + case 'P': + phys = 1; + break; + default: + error("unknown option: -%c", optopt); + break; + } + } + argc -= optind; + argv += optind; + + if (argc > 1) + error("too many arguments"); + + if ((dest = *argv) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) + error("HOME not set"); + if (*dest == '\0') + dest = "."; + if (dest[0] == '-' && dest[1] == '\0') { + dest = prevdir ? prevdir : curdir; + if (dest) + print = 1; + else + dest = "."; } if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL) path = nullstr; while ((p = padvance(&path, dest)) != NULL) { - if (stat(p, &statb) >= 0 - && (statb.st_mode & S_IFMT) == S_IFDIR - && docd(p, strcmp(p, dest), tohome) >= 0) - return 0; + if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { + if (!print) { + /* + * XXX - rethink + */ + if (p[0] == '.' && p[1] == '/' && p[2] != '\0') + p += 2; + print = strcmp(p, dest); + } + if (docd(p, print, phys) >= 0) + return 0; + } } error("can't cd to %s", dest); + /*NOTREACHED*/ + return 0; } /* - * Actually do the chdir. If the name refers to symbolic links, we - * compute the actual directory name before doing the cd. In an - * interactive shell, print the directory name if "print" is nonzero - * or if the name refers to a symbolic link. We also print the name - * if "/u/logname" was expanded in it, since this is similar to a - * symbolic link. (The check for this breaks if the user gives the - * cd command some additional, unused arguments.) + * Actually change the directory. In an interactive shell, print the + * directory name if "print" is nonzero. */ - -#if SYMLINKS == 0 STATIC int -docd(dest, print, tohome) - char *dest; - { -#if UDIR || TILDE - if (didudir) - print = 1; -#endif - INTOFF; - if (chdir(dest) < 0) { - INTON; - return -1; - } - updatepwd(dest); - INTON; - if (print && iflag) - out1fmt("%s\n", stackblock()); +docd(char *dest, int print, int phys) +{ + + TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, phys)); + + /* If logical cd fails, fall back to physical. */ + if ((phys || cdlogical(dest) < 0) && cdphysical(dest) < 0) + return (-1); + + if (print && iflag && curdir) + out1fmt("%s\n", curdir); + return 0; } -#else - - - STATIC int -docd(dest, print, tohome) - char *dest; - { - register char *p; - register char *q; - char *symlink; +cdlogical(char *dest) +{ + char *p; + char *q; char *component; struct stat statb; int first; - int i; + int badstat; - TRACE(("docd(\"%s\", %d, %d) called\n", dest, print, tohome)); -#if UDIR || TILDE - if (didudir) - print = 1; -#endif - -top: - cdcomppath = dest; + /* + * Check each component of the path. If we find a symlink or + * something we can't stat, clear curdir to force a getcwd() + * next time we get the value of the current directory. + */ + badstat = 0; + cdcomppath = stalloc(strlen(dest) + 1); + scopy(dest, cdcomppath); STARTSTACKSTR(p); if (*dest == '/') { STPUTC('/', p); @@ -166,7 +185,7 @@ top: } first = 1; while ((q = getcomponent()) != NULL) { - if (q[0] == '\0' || q[0] == '.' && q[1] == '\0') + if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) continue; if (! first) STPUTC('/', p); @@ -177,71 +196,42 @@ top: if (equal(component, "..")) continue; STACKSTRNUL(p); - if (lstat(stackblock(), &statb) < 0) - error("lstat %s failed", stackblock()); - if ((statb.st_mode & S_IFMT) != S_IFLNK) - continue; - - /* Hit a symbolic link. We have to start all over again. */ - print = 1; - STPUTC('\0', p); - symlink = grabstackstr(p); - i = (int)statb.st_size + 2; /* 2 for '/' and '\0' */ - if (cdcomppath != NULL) - i += strlen(cdcomppath); - p = stalloc(i); - if (readlink(symlink, p, (int)statb.st_size) < 0) { - error("readlink %s failed", stackblock()); + if (lstat(stackblock(), &statb) < 0) { + badstat = 1; + break; } - if (cdcomppath != NULL) { - p[(int)statb.st_size] = '/'; - scopy(cdcomppath, p + (int)statb.st_size + 1); - } else { - p[(int)statb.st_size] = '\0'; - } - if (p[0] != '/') { /* relative path name */ - char *r; - q = r = symlink; - while (*q) { - if (*q++ == '/') - r = q; - } - *r = '\0'; - dest = stalloc(strlen(symlink) + strlen(p) + 1); - scopy(symlink, dest); - strcat(dest, p); - } else { - dest = p; - } - goto top; } - STPUTC('\0', p); - p = grabstackstr(p); + INTOFF; - /* The empty string is not a legal argument to chdir on a POSIX 1003.1 - * system. */ - if (p[0] != '\0' && chdir(p) < 0) { + if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) { INTON; - return -1; + return (-1); } - updatepwd(p); INTON; - if (print && !tohome && iflag) - out1fmt("%s\n", p); - return 0; + return (0); } -#endif /* SYMLINKS */ +STATIC int +cdphysical(char *dest) +{ + INTOFF; + if (chdir(dest) < 0 || updatepwd(NULL) < 0) { + INTON; + return (-1); + } + INTON; + return (0); +} /* * Get the next component of the path name pointed to by cdcomppath. * This routine overwrites the string pointed to by cdcomppath. */ - STATIC char * -getcomponent() { - register char *p; +getcomponent(void) +{ + char *p; char *start; if ((p = cdcomppath) == NULL) @@ -259,29 +249,43 @@ getcomponent() { } - /* * Update curdir (the name of the current directory) in response to a * cd command. We also call hashcd to let the routines in exec.c know * that the current directory has changed. */ - -void hashcd(); - -STATIC void -updatepwd(dir) - char *dir; - { +STATIC int +updatepwd(char *dir) +{ char *new; char *p; hashcd(); /* update command hash table */ + + /* + * If our argument is NULL, we don't know the current directory + * any more because we traversed a symbolic link or something + * we couldn't stat(). + */ + if (dir == NULL || curdir == NULL) { + if (prevdir) + ckfree(prevdir); + INTOFF; + prevdir = curdir; + curdir = NULL; + if (getpwd() == NULL) { + INTON; + return (-1); + } + setvar("PWD", curdir, VEXPORT); + setvar("OLDPWD", prevdir, VEXPORT); + INTON; + return (0); + } cdcomppath = stalloc(strlen(dir) + 1); scopy(dir, cdcomppath); STARTSTACKSTR(new); if (*dir != '/') { - if (curdir == NULL) - return; p = curdir; while (*p) STPUTC(*p++, new); @@ -300,73 +304,87 @@ updatepwd(dir) if (new == stackblock()) STPUTC('/', new); STACKSTRNUL(new); - if (curdir) - ckfree(curdir); + INTOFF; + if (prevdir) + ckfree(prevdir); + prevdir = curdir; curdir = savestr(stackblock()); + setvar("PWD", curdir, VEXPORT); + setvar("OLDPWD", prevdir, VEXPORT); + INTON; + + return (0); } - - int -pwdcmd(argc, argv) char **argv; { - getpwd(); - out1str(curdir); - out1c('\n'); +pwdcmd(int argc, char **argv) +{ + char buf[PATH_MAX]; + int ch, phys; + + optreset = 1; optind = 1; opterr = 0; /* initialize getopt */ + phys = Pflag; + while ((ch = getopt(argc, argv, "LP")) != -1) { + switch (ch) { + case 'L': + phys = 0; + break; + case 'P': + phys = 1; + break; + default: + error("unknown option: -%c", optopt); + break; + } + } + argc -= optind; + argv += optind; + + if (argc != 0) + error("too many arguments"); + + if (!phys && getpwd()) { + out1str(curdir); + out1c('\n'); + } else { + if (getcwd(buf, sizeof(buf)) == NULL) + error(".: %s", strerror(errno)); + out1str(buf); + out1c('\n'); + } + return 0; } - - /* - * Run /bin/pwd to find out what the current directory is. We suppress - * interrupts throughout most of this, but the user can still break out - * of it by killing the pwd program. If we already know the current + * Find out what the current directory is. If we already know the current * directory, this routine returns immediately. */ - -#define MAXPWD 256 - -STATIC void -getpwd() { - char buf[MAXPWD]; - char *p; - int i; - int status; - struct job *jp; - int pip[2]; +char * +getpwd(void) +{ + char buf[PATH_MAX]; if (curdir) - return; - INTOFF; - if (pipe(pip) < 0) - error("Pipe call failed"); - jp = makejob((union node *)NULL, 1); - if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) { - close(pip[0]); - if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); - close(pip[1]); + return curdir; + if (getcwd(buf, sizeof(buf)) == NULL) { + char *pwd = getenv("PWD"); + struct stat stdot, stpwd; + + if (pwd && *pwd == '/' && stat(".", &stdot) != -1 && + stat(pwd, &stpwd) != -1 && + stdot.st_dev == stpwd.st_dev && + stdot.st_ino == stpwd.st_ino) { + curdir = savestr(pwd); + return curdir; } - execl("/bin/pwd", "pwd", (char *)0); - error("Cannot exec /bin/pwd"); + return NULL; } - close(pip[1]); - pip[1] = -1; - p = buf; - while ((i = read(pip[0], p, buf + MAXPWD - p)) > 0 - || i == -1 && errno == EINTR) { - if (i > 0) - p += i; - } - close(pip[0]); - pip[0] = -1; - status = waitforjob(jp); - if (status != 0) - error((char *)0); - if (i < 0 || p == buf || p[-1] != '\n') - error("pwd command failed"); - p[-1] = '\0'; curdir = savestr(buf); - INTON; + + return curdir; } + +/* + * $PchId: cd.c,v 1.6 2006/05/22 12:42:03 philip Exp $ + */ diff --git a/commands/ash/cd.h b/commands/ash/cd.h new file mode 100644 index 000000000..f4546f206 --- /dev/null +++ b/commands/ash/cd.h @@ -0,0 +1,38 @@ +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * $FreeBSD: src/bin/sh/cd.h,v 1.7 2004/04/06 20:06:51 markm Exp $ + */ + +char *getpwd(void); +int cdcmd (int, char **); +int pwdcmd(int, char **); + +/* + * $PchId: cd.h,v 1.3 2006/03/31 09:59:04 philip Exp $ + */ diff --git a/commands/ash/complete.c b/commands/ash/complete.c new file mode 100644 index 000000000..b7ebd30a8 --- /dev/null +++ b/commands/ash/complete.c @@ -0,0 +1,354 @@ +/* +complete.c + +Created: July 1995 by Philip Homburg +*/ + +#include +#include +#include +#include +#include +#include +#include "myhistedit.h" +#include "shell.h" + +#include "complete.h" +#include "error.h" +#include "expand.h" +#include "nodes.h" +#include "memalloc.h" + +static char **getlist(EditLine *el, int *baselen, int *isdir); +static char **getlist_tilde(char *prefix); +static int vstrcmp(const void *v1, const void *v2); +static void print_list(char **list); +static int install_extra(EditLine *el, char **list, int baselen, int isdir); + +unsigned char complete(EditLine *el, int ch) +{ + struct stackmark mark; + const LineInfo *lf; + char **list; + int baselen, prefix, isdir; + + /* Direct the cursor the the end of the word. */ + for(;;) + { + lf = el_line(el); + if (lf->cursor < lf->lastchar && + !isspace((unsigned char)*lf->cursor)) + { + (*(char **)&lf->cursor)++; /* XXX */ + } + else + break; + } + + setstackmark(&mark); + list= getlist(el, &baselen, &isdir); + if (list) + { + prefix= install_extra(el, list, baselen, isdir); + el_push(el, "i"); + } + popstackmark(&mark); + if (list) + return CC_REFRESH; + else + return CC_ERROR; +} + +unsigned char complete_list(EditLine *el, int ch) +{ + struct stackmark mark; + char **list; + + setstackmark(&mark); + list= getlist(el, NULL, NULL); + if (list) + { + print_list(list); + re_goto_bottom(el); + } + popstackmark(&mark); + if (list) + { + return CC_REFRESH; + } + else + return CC_ERROR; +} + +unsigned char complete_or_list(EditLine *el, int ch) +{ + struct stackmark mark; + const LineInfo *lf; + char **list; + int baselen, prefix, isdir; + + setstackmark(&mark); + list= getlist(el, &baselen, &isdir); + if (list) + { + prefix= install_extra(el, list, baselen, isdir); + if (prefix == baselen) + { + print_list(list); + re_goto_bottom(el); + } + } + popstackmark(&mark); + if (list) + return CC_REFRESH; + else + return CC_ERROR; +} + +unsigned char complete_expand(EditLine *el, int ch) +{ + printf("complete_expand\n"); + return CC_ERROR; +} + +static char **getlist(EditLine *el, int *baselen, int *isdir) +{ + const LineInfo *lf; + const char *begin, *end; + char *dirnam, *basenam; + union node arg; + struct arglist arglist; + DIR *dir; + struct dirent *dirent; + int i, l, n; + char *p, **list; + struct strlist *slp, *nslp; + struct stat sb; + + lf = el_line(el); + + /* Try to find to begin and end of the word that we have to comple. */ + begin= lf->cursor; + while (begin > lf->buffer && !isspace((unsigned char)begin[-1])) + begin--; + end= lf->cursor; + while (end < lf->lastchar && !isspace((unsigned char)end[0])) + end++; + + *(const char **)&lf->cursor= end; /* XXX */ + + /* Copy the word to a string */ + dirnam= stalloc(end-begin+1); + strncpy(dirnam, begin, end-begin); + dirnam[end-begin]= '\0'; + + /* Cut the word in two pieces: a path and a (partial) component. */ + basenam= strrchr(dirnam, '/'); + if (basenam) + { + basenam++; + p= stalloc(strlen(basenam) + 1); + strcpy(p, basenam); + *basenam= '\0'; + basenam= p; + } + else + { + if (dirnam[0] == '~') + return getlist_tilde(dirnam); + basenam= dirnam; + dirnam= "./"; + } + if (baselen) + *baselen= strlen(basenam); + + arg.type= NARG; + arg.narg.next= NULL; + arg.narg.text= dirnam; + arg.narg.backquote= NULL; + arglist.list= NULL; + arglist.lastp= &arglist.list; + expandarg(&arg, &arglist, EXP_TILDE); + + INTOFF; + list= NULL; + dir= opendir(arglist.list->text); + if (dir) + { + slp= NULL; + n= 0; + l= strlen(basenam); + while(dirent= readdir(dir)) + { + if (strncmp(dirent->d_name, basenam, l) != 0) + continue; + if (l == 0 && dirent->d_name[0] == '.') + continue; + nslp= stalloc(sizeof(*nslp)); + nslp->next= slp; + slp= nslp; + slp->text= stalloc(strlen(dirent->d_name)+1); + strcpy(slp->text, dirent->d_name); + n++; + if (n == 1 && isdir != NULL) + { + /* Try to findout whether this entry is a + * file or a directory. + */ + p= stalloc(strlen(arglist.list->text) + + strlen(dirent->d_name) + 1); + strcpy(p, arglist.list->text); + strcat(p, dirent->d_name); + if (stat(p, &sb) == -1) + printf("stat '%s' failed: %s\n", + p, strerror(errno)); + if (stat(p, &sb) == 0 && S_ISDIR(sb.st_mode)) + *isdir= 1; + else + *isdir= 0; + } + } + closedir(dir); + if (n != 0) + { + list= stalloc((n+1)*sizeof(*list)); + for(i= 0; slp; i++, slp= slp->next) + list[i]= slp->text; + if (i != n) + error("complete'make_list: i != n"); + list[i]= NULL; + qsort(list, n, sizeof(*list), vstrcmp); + } + } + INTON; + return list; +} + +static char **getlist_tilde(char *prefix) +{ + printf("should ~-complete '%s'\n", prefix); + return NULL; +} + +static int vstrcmp(const void *v1, const void *v2) +{ + return strcmp(*(char **)v1, *(char **)v2); +} + +#define MAXCOLS 40 +#define SEPWIDTH 4 + +static void print_list(char **list) +{ + struct + { + int cols; + int start[MAXCOLS+1]; + int width[MAXCOLS]; + } best, next; + int e, i, j, l, n, o, cols, maxw, width; + int linewidth= 80; + + /* Count the number of entries. */ + for (n= 0; list[n]; n++) + ; /* do nothing */ + if (n == 0) + error("complete'print_list: n= 0"); + + /* Try to maximize the number of columns */ + for (cols= 1; cols<= MAXCOLS; cols++) + { + next.cols= cols; + + o= 0; + width= 0; + for(j= 0; j maxw) + maxw= l; + } + next.width[j]= maxw; + width += maxw; + o += e; + } + next.start[j]= o; + if (cols > 1 && width-SEPWIDTH>linewidth) + break; + best= next; + } + cols= best.cols; + e= best.start[1]; + printf("\n"); + for(i= 0; i0) + { + if (strncmp(list[0], *lp, l) != 0) + l--; + else + break; + } + } + if (l > baselen || list[1] == NULL) + { + p= stalloc(l-baselen+2); + strncpy(p, list[0]+baselen, l-baselen); + if (list[1] == NULL) + { + p[l-baselen]= isdir ? '/' : ' '; + p[l-baselen+1]= '\0'; + l++; + } + else + p[l-baselen]= '\0'; + if (el_insertstr(el, p) == -1) + return -1; + } + return l; +} + +/* + * $PchId: complete.c,v 1.2 2006/04/10 14:35:53 philip Exp $ + */ diff --git a/commands/ash/complete.h b/commands/ash/complete.h new file mode 100644 index 000000000..af859f9eb --- /dev/null +++ b/commands/ash/complete.h @@ -0,0 +1,14 @@ +/* +complete.h + +Created: July 1995 by Philip Homburg +*/ + +unsigned char complete(EditLine *el, int ch); +unsigned char complete_list(EditLine *el, int ch); +unsigned char complete_or_list(EditLine *el, int ch); +unsigned char complete_expand(EditLine *el, int ch); + +/* + * $PchId: complete.h,v 1.1 2001/05/17 07:12:05 philip Exp $ + */ diff --git a/commands/ash/dirent.c b/commands/ash/dirent.c deleted file mode 100755 index 521fcc627..000000000 --- a/commands/ash/dirent.c +++ /dev/null @@ -1,194 +0,0 @@ -/*- - * Copyright (c) 1991 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 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 -static char sccsid[] = "@(#)dirent.c 5.1 (Berkeley) 3/7/91"; -#endif /* not lint */ - -#include "shell.h" /* definitions for pointer, NULL, DIRENT, and BSD */ - -#if ! DIRENT - -#include -#include -#include -#include -#include - -#ifndef S_ISDIR /* macro to test for directory file */ -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#endif - -#ifdef BSD - -#ifdef __STDC__ -int stat(char *, struct stat *); -#else -int stat(); -#endif - - -/* - * The BSD opendir routine doesn't check that what is being opened is a - * directory, so we have to include the check in a wrapper routine. - */ - -#undef opendir - -DIR * -myopendir(dirname) - char *dirname; /* name of directory */ - { - struct stat statb; - - if (stat(dirname, &statb) != 0 || ! S_ISDIR(statb.st_mode)) { - errno = ENOTDIR; - return NULL; /* not a directory */ - } - return opendir(dirname); -} - -#else /* not BSD */ - -/* - * Dirent routines for old style file systems. - */ - -#ifdef __STDC__ -pointer malloc(unsigned); -void free(pointer); -int open(char *, int, ...); -int close(int); -int fstat(int, struct stat *); -#else -pointer malloc(); -void free(); -int open(); -int close(); -int fstat(); -#endif - - -DIR * -opendir(dirname) - char *dirname; /* name of directory */ - { - register DIR *dirp; /* -> malloc'ed storage */ - register int fd; /* file descriptor for read */ - struct stat statb; /* result of fstat() */ - -#ifdef O_NDELAY - fd = open(dirname, O_RDONLY|O_NDELAY); -#else - fd = open(dirname, O_RDONLY); -#endif - if (fd < 0) - return NULL; /* errno set by open() */ - - if (fstat(fd, &statb) != 0 || !S_ISDIR(statb.st_mode)) { - (void)close(fd); - errno = ENOTDIR; - return NULL; /* not a directory */ - } - - if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { - (void)close(fd); - errno = ENOMEM; - return NULL; /* not enough memory */ - } - - dirp->dd_fd = fd; - dirp->dd_nleft = 0; /* refill needed */ - - return dirp; -} - - - -int -closedir(dirp) - register DIR *dirp; /* stream from opendir() */ - { - register int fd; - - if (dirp == NULL) { - errno = EFAULT; - return -1; /* invalid pointer */ - } - - fd = dirp->dd_fd; - free((pointer)dirp); - return close(fd); -} - - - -struct dirent * -readdir(dirp) - register DIR *dirp; /* stream from opendir() */ - { - register struct direct *dp; - register char *p, *q; - register int i; - - do { - if ((dirp->dd_nleft -= sizeof (struct direct)) < 0) { - if ((i = read(dirp->dd_fd, - (char *)dirp->dd_buf, - DIRBUFENT*sizeof(struct direct))) <= 0) { - if (i == 0) - errno = 0; /* unnecessary */ - return NULL; /* EOF or error */ - } - dirp->dd_loc = dirp->dd_buf; - dirp->dd_nleft = i - sizeof (struct direct); - } - dp = dirp->dd_loc++; - } while (dp->d_ino == 0); - dirp->dd_entry.d_ino = dp->d_ino; - - /* now copy the name, nul terminating it */ - p = dp->d_name; - q = dirp->dd_entry.d_name; - i = DIRSIZ; - while (--i >= 0 && *p != '\0') - *q++ = *p++; - *q = '\0'; - return &dirp->dd_entry; -} - -#endif /* BSD */ -#endif /* DIRENT */ diff --git a/commands/ash/errmsg.c b/commands/ash/errmsg.c new file mode 100644 index 000000000..2a0303b66 --- /dev/null +++ b/commands/ash/errmsg.c @@ -0,0 +1,127 @@ +/*- + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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 +static char sccsid[] = "@(#)errmsg.c 8.1 (Berkeley) 5/31/93"; +#endif /* not lint */ + +#include "shell.h" +#include "output.h" +#include "errmsg.h" +#include + + +#define ALL (E_OPEN|E_CREAT|E_EXEC) + + +struct errname { + short errcode; /* error number */ + short action; /* operation which encountered the error */ + char *msg; /* text describing the error */ +}; + + +STATIC const struct errname errormsg[] = { + EINTR, ALL, "interrupted", + EACCES, ALL, "permission denied", + EIO, ALL, "I/O error", + ENOENT, E_OPEN, "no such file", + ENOENT, E_CREAT, "directory nonexistent", + ENOENT, E_EXEC, "not found", + ENOTDIR, E_OPEN, "no such file", + ENOTDIR, E_CREAT, "directory nonexistent", + ENOTDIR, E_EXEC, "not found", + EISDIR, ALL, "is a directory", +/* EMFILE, ALL, "too many open files", */ + ENFILE, ALL, "file table overflow", + ENOSPC, ALL, "file system full", +#ifdef EDQUOT + EDQUOT, ALL, "disk quota exceeded", +#endif +#ifdef ENOSR + ENOSR, ALL, "no streams resources", +#endif + ENXIO, ALL, "no such device or address", + EROFS, ALL, "read-only file system", + ETXTBSY, ALL, "text busy", +#ifdef SYSV + EAGAIN, E_EXEC, "not enough memory", +#endif + ENOMEM, ALL, "not enough memory", +#ifdef ENOLINK + ENOLINK, ALL, "remote access failed" +#endif +#ifdef EMULTIHOP + EMULTIHOP, ALL, "remote access failed", +#endif +#ifdef ECOMM + ECOMM, ALL, "remote access failed", +#endif +#ifdef ESTALE + ESTALE, ALL, "remote access failed", +#endif +#ifdef ETIMEDOUT + ETIMEDOUT, ALL, "remote access failed", +#endif +#ifdef ELOOP + ELOOP, ALL, "symbolic link loop", +#endif + E2BIG, E_EXEC, "argument list too long", +#ifdef ELIBACC + ELIBACC, E_EXEC, "shared library missing", +#endif + 0, 0, NULL +}; + + +/* + * Return a string describing an error. The returned string may be a + * pointer to a static buffer that will be overwritten on the next call. + * Action describes the operation that got the error. + */ + +char * +errmsg(e, action) { + struct errname const *ep; + static char buf[12]; + + for (ep = errormsg ; ep->errcode ; ep++) { + if (ep->errcode == e && (ep->action & action) != 0) + return ep->msg; + } + fmtstr(buf, sizeof buf, "error %d", e); + return buf; +} diff --git a/commands/ash/errmsg.h b/commands/ash/errmsg.h new file mode 100644 index 000000000..03cb605ec --- /dev/null +++ b/commands/ash/errmsg.h @@ -0,0 +1,47 @@ +/*- + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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. + * + * @(#)errmsg.h 8.1 (Berkeley) 5/31/93 + */ + +#define E_OPEN 01 +#define E_CREAT 02 +#define E_EXEC 04 + +#ifdef __STDC__ +char *errmsg(int, int); +#else +char *errmsg(); +#endif diff --git a/commands/ash/error.c b/commands/ash/error.c index af4275e4b..a24807e44 100755 --- a/commands/ash/error.c +++ b/commands/ash/error.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,14 @@ */ #ifndef lint -static char sccsid[] = "@(#)error.c 5.1 (Berkeley) 3/7/91"; +#if 0 +static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/error.c,v 1.25 2004/04/06 20:06:51 markm Exp $"); +*/ /* * Errors and exceptions. @@ -47,14 +49,14 @@ static char sccsid[] = "@(#)error.c 5.1 (Berkeley) 3/7/91"; #include "options.h" #include "output.h" #include "error.h" -#include +#include "nodes.h" /* show.h needs nodes.h */ +#include "show.h" +#include "trap.h" #include -#ifdef __STDC__ -#include "stdarg.h" -#else -#include -#endif +#include +#include #include +#include /* @@ -62,12 +64,14 @@ static char sccsid[] = "@(#)error.c 5.1 (Berkeley) 3/7/91"; */ struct jmploc *handler; -int exception; -volatile int suppressint; -volatile int intpending; +volatile sig_atomic_t exception; +volatile sig_atomic_t suppressint; +volatile sig_atomic_t intpending; char *commandname; +static void exverror(int, const char *, va_list) __printf0like(2, 0); + /* * Called to raise an exception. Since C doesn't include exceptions, we * just do a longjmp to the exception handler. The type of exception is @@ -75,7 +79,8 @@ char *commandname; */ void -exraise(e) { +exraise(int e) +{ if (handler == NULL) abort(); exception = e; @@ -87,69 +92,63 @@ exraise(e) { * Called from trap.c when a SIGINT is received. (If the user specifies * that SIGINT is to be trapped or ignored using the trap builtin, then * this routine is not called.) Suppressint is nonzero when interrupts - * are held using the INTOFF macro. The call to _exit is necessary because - * there is a short period after a fork before the signal handlers are - * set to the appropriate value for the child. (The test for iflag is - * just defensive programming.) + * are held using the INTOFF macro. If SIGINTs are not suppressed and + * the shell is not a root shell, then we want to be terminated if we + * get here, as if we were terminated directly by a SIGINT. Arrange for + * this here. */ void -onint() { - if (suppressint) { +onint(void) +{ + sigset_t sigset; + + /* + * The !in_dotrap here is safe. The only way we can arrive here + * with in_dotrap set is that a trap handler set SIGINT to SIG_DFL + * and killed itself. + */ + + if (suppressint && !in_dotrap) { intpending++; return; } intpending = 0; -#ifdef BSD - sigsetmask(0); + sigemptyset(&sigset); + sigprocmask(SIG_SETMASK, &sigset, NULL); + + /* + * This doesn't seem to be needed, since main() emits a newline. + */ +#if 0 + if (tcgetpgrp(0) == getpid()) + write(STDERR_FILENO, "\n", 1); #endif if (rootshell && iflag) exraise(EXINT); - else - _exit(128 + SIGINT); -} - - - -void -error2(a, b) - char *a, *b; - { - error("%s: %s", a, b); + else { + signal(SIGINT, SIG_DFL); + kill(getpid(), SIGINT); + } } /* - * Error is called to raise the error exception. If the first argument + * Exverror is called to raise the error exception. If the first argument * is not NULL then error prints an error message using printf style * formatting. It then raises the error exception. */ - -#ifdef __STDC__ -void -error(char *msg, ...) { -#else -void -error(va_alist) - va_dcl - { - char *msg; -#endif - va_list ap; - +static void +exverror(int cond, const char *msg, va_list ap) +{ CLEAR_PENDING_INT; INTOFF; -#ifdef __STDC__ - va_start(ap, msg); -#else - va_start(ap); - msg = va_arg(ap, char *); -#endif + #if DEBUG if (msg) - TRACE(("error(\"%s\") pid=%d\n", msg, getpid())); + TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); else - TRACE(("error(NULL) pid=%d\n", getpid())); + TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); #endif if (msg) { if (commandname) @@ -157,96 +156,30 @@ error(va_alist) doformat(&errout, msg, ap); out2c('\n'); } - va_end(ap); flushall(); - exraise(EXERROR); + exraise(cond); } -#ifdef notdef /* These strange error messages only confuse. -- kjb */ -/* - * Table of error messages. - */ - -struct errname { - short errcode; /* error number */ - short action; /* operation which encountered the error */ - char *msg; /* text describing the error */ -}; - - -#define ALL (E_OPEN|E_CREAT|E_EXEC) - -STATIC const struct errname errormsg[] = { - EINTR, ALL, "interrupted", - EACCES, ALL, "permission denied", - EIO, ALL, "I/O error", - ENOENT, E_OPEN, "no such file", - ENOENT, E_CREAT, "directory nonexistent", - ENOENT, E_EXEC, "not found", - ENOTDIR, E_OPEN, "no such file", - ENOTDIR, E_CREAT, "directory nonexistent", - ENOTDIR, E_EXEC, "not found", - ENOEXEC, ALL, "not an executable", - EISDIR, ALL, "is a directory", -/* EMFILE, ALL, "too many open files", */ - ENFILE, ALL, "file table overflow", - ENOSPC, ALL, "file system full", -#ifdef EDQUOT - EDQUOT, ALL, "disk quota exceeded", -#endif -#ifdef ENOSR - ENOSR, ALL, "no streams resources", -#endif - ENXIO, ALL, "no such device or address", - EROFS, ALL, "read-only file system", - ETXTBSY, ALL, "text busy", -#ifdef SYSV - EAGAIN, E_EXEC, "not enough memory", -#endif - ENOMEM, ALL, "not enough memory", -#ifdef ENOLINK - ENOLINK, ALL, "remote access failed", -#endif -#ifdef EMULTIHOP - EMULTIHOP, ALL, "remote access failed", -#endif -#ifdef ECOMM - ECOMM, ALL, "remote access failed", -#endif -#ifdef ESTALE - ESTALE, ALL, "remote access failed", -#endif -#ifdef ETIMEDOUT - ETIMEDOUT, ALL, "remote access failed", -#endif -#ifdef ELOOP - ELOOP, ALL, "symbolic link loop", -#endif - E2BIG, E_EXEC, "argument list too long", -#ifdef ELIBACC - ELIBACC, E_EXEC, "shared library missing", -#endif - 0, 0, NULL -}; - - -/* - * Return a string describing an error. The returned string may be a - * pointer to a static buffer that will be overwritten on the next call. - * Action describes the operation that got the error. - */ - -char * -errmsg(e, action) { - const struct errname *ep; - static char buf[12]; - - for (ep = errormsg ; ep->errcode ; ep++) { - if (ep->errcode == e && (ep->action & action) != 0) - return ep->msg; - } - fmtstr(buf, sizeof buf, "error %d", e); - return buf; +void +error(const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + exverror(EXERROR, msg, ap); + va_end(ap); } -#endif + + +void +exerror(int cond, const char *msg, ...) +{ + va_list ap; + va_start(ap, msg); + exverror(cond, msg, ap); + va_end(ap); +} + +/* + * $PchId: error.c,v 1.5 2006/04/10 14:36:23 philip Exp $ + */ diff --git a/commands/ash/error.h b/commands/ash/error.h index 4cd22507a..6597d9038 100755 --- a/commands/ash/error.h +++ b/commands/ash/error.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,41 +29,35 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)error.h 5.1 (Berkeley) 3/7/91 + * @(#)error.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/error.h,v 1.17 2004/04/06 20:06:51 markm Exp $ */ -/* - * Types of operations (passed to the errmsg routine). - */ - -#define E_OPEN 01 /* opening a file */ -#define E_CREAT 02 /* creating a file */ -#define E_EXEC 04 /* executing a program */ - - /* * We enclose jmp_buf in a structure so that we can declare pointers to * jump locations. The global variable handler contains the location to * jump to when an exception occurs, and the global variable exception - * contains a code identifying the exeception. To implement nested + * contains a code identifying the exception. To implement nested * exception handlers, the user should save the value of handler on entry * to an inner scope, set handler to point to a jmploc structure for the * inner scope, and restore handler on exit from the scope. */ #include +#include struct jmploc { jmp_buf loc; }; extern struct jmploc *handler; -extern int exception; +extern volatile sig_atomic_t exception; /* exceptions */ #define EXINT 0 /* SIGINT received */ #define EXERROR 1 /* a generic error */ #define EXSHELLPROC 2 /* execute a shell procedure */ +#define EXEXEC 3 /* command execution failed */ /* @@ -77,32 +67,21 @@ extern int exception; * more fun than worrying about efficiency and portability. :-)) */ -extern volatile int suppressint; -extern volatile int intpending; -extern char *commandname; /* name of command--printed on error */ +extern volatile sig_atomic_t suppressint; +extern volatile sig_atomic_t intpending; #define INTOFF suppressint++ -#define INTON if (--suppressint == 0 && intpending) onint(); else +#define INTON { if (--suppressint == 0 && intpending) onint(); } #define FORCEINTON {suppressint = 0; if (intpending) onint();} #define CLEAR_PENDING_INT intpending = 0 #define int_pending() intpending -#ifdef __STDC__ +#define __printf0like(a,b) + void exraise(int); void onint(void); -void error2(char *, char *); -void error(char *, ...); -char *errmsg(int, int); -#else -void exraise(); -void onint(); -void error2(); -void error(); -char *errmsg(); -#endif - -/* Errmsg uses confusingly different messages. Prefer strerror(). -- kjb */ -#define errmsg(errno, action) strerror(errno) +void error(const char *, ...) __printf0like(1, 2); +void exerror(int, const char *, ...) __printf0like(2, 3); /* @@ -111,6 +90,12 @@ char *errmsg(); */ #ifdef BSD +#ifndef __minix #define setjmp(jmploc) _setjmp(jmploc) #define longjmp(jmploc, val) _longjmp(jmploc, val) #endif +#endif + +/* + * $PchId: error.h,v 1.5 2006/04/10 14:36:43 philip Exp $ + */ diff --git a/commands/ash/eval.c b/commands/ash/eval.c index 388a8000d..02c4da1f6 100755 --- a/commands/ash/eval.c +++ b/commands/ash/eval.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Kenneth Almquist. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,23 @@ */ #ifndef lint -static char sccsid[] = "@(#)eval.c 5.3 (Berkeley) 4/12/91"; +#if 0 +static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/eval.c,v 1.42 2004/04/06 20:06:51 markm Exp $"); +*/ + +#ifndef NO_PATHS_H +#include +#endif +#include +#include +#include +#include /* For WIFSIGNALED(status) */ +#include /* * Evaluate a command. @@ -59,22 +70,21 @@ static char sccsid[] = "@(#)eval.c 5.3 (Berkeley) 4/12/91"; #include "var.h" #include "memalloc.h" #include "error.h" +#include "show.h" #include "mystring.h" -#include -#include +#if !defined(NO_HISTORY) && !defined(EDITLINE) +#include "myhistedit.h" +#endif +#ifndef _PATH_STDPATH +#define _PATH_STDPATH "/usr/bin:/bin:/usr/sbin:/sbin:" +#endif /* flags in argument to evaltree */ #define EV_EXIT 01 /* exit after evaluating tree */ #define EV_TESTED 02 /* exit status is checked; ignore -e flag */ #define EV_BACKCMD 04 /* command executing within back quotes */ - -/* reasons for skipping commands (see comment on breakcmd routine) */ -#define SKIPBREAK 1 -#define SKIPCONT 2 -#define SKIPFUNC 3 - MKINIT int evalskip; /* set if we are skipping commands */ STATIC int skipcount; /* number of levels to skip */ MKINIT int loopnest; /* current loop nesting level */ @@ -87,7 +97,6 @@ int exitstatus; /* exit status of last command */ int oexitstatus; /* saved exit status */ -#ifdef __STDC__ STATIC void evalloop(union node *); STATIC void evalfor(union node *); STATIC void evalcase(union node *, int); @@ -96,17 +105,6 @@ STATIC void expredir(union node *); STATIC void evalpipe(union node *); STATIC void evalcommand(union node *, int, struct backcmd *); STATIC void prehash(union node *); -#else -STATIC void evalloop(); -STATIC void evalfor(); -STATIC void evalcase(); -STATIC void evalsubshell(); -STATIC void expredir(); -STATIC void evalpipe(); -STATIC void evalcommand(); -STATIC void prehash(); -#endif - /* @@ -130,11 +128,11 @@ SHELLPROC { /* - * The eval commmand. + * The eval command. */ -evalcmd(argc, argv) - char **argv; +int +evalcmd(int argc, char **argv) { char *p; char *concat; @@ -166,9 +164,8 @@ evalcmd(argc, argv) */ void -evalstring(s) - char *s; - { +evalstring(char *s) +{ union node *n; struct stackmark smark; @@ -190,14 +187,17 @@ evalstring(s) */ void -evaltree(n, flags) - union node *n; - { +evaltree(union node *n, int flags) +{ if (n == NULL) { TRACE(("evaltree(NULL) called\n")); - return; + exitstatus = 0; + goto out; } - TRACE(("evaltree(0x%x: %d) called\n", (int)n, n->type)); +#if !defined(NO_HISTORY) && !defined(EDITLINE) + displayhist = 1; /* show history substitutions done with fc */ +#endif + TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); switch (n->type) { case NSEMI: evaltree(n->nbinary.ch1, 0); @@ -207,8 +207,9 @@ evaltree(n, flags) break; case NAND: evaltree(n->nbinary.ch1, EV_TESTED); - if (evalskip || exitstatus != 0) + if (evalskip || exitstatus != 0) { goto out; + } evaltree(n->nbinary.ch2, flags); break; case NOR: @@ -230,19 +231,15 @@ evaltree(n, flags) evalsubshell(n, flags); break; case NIF: { - int status = 0; - evaltree(n->nif.test, EV_TESTED); if (evalskip) goto out; - if (exitstatus == 0) { + if (exitstatus == 0) evaltree(n->nif.ifpart, flags); - status = exitstatus; - } else if (n->nif.elsepart) { + else if (n->nif.elsepart) evaltree(n->nif.elsepart, flags); - status = exitstatus; - } - exitstatus = status; + else + exitstatus = 0; break; } case NWHILE: @@ -259,6 +256,11 @@ evaltree(n, flags) defun(n->narg.text, n->narg.next); exitstatus = 0; break; + case NNOT: + evaltree(n->nnot.com, EV_TESTED); + exitstatus = !exitstatus; + break; + case NPIPE: evalpipe(n); break; @@ -273,18 +275,16 @@ evaltree(n, flags) out: if (pendingsigs) dotrap(); - if ((flags & EV_EXIT) || (eflag && exitstatus - && !(flags & EV_TESTED) && (n->type == NCMD || - n->type == NSUBSHELL))) { + if ((flags & EV_EXIT) || (eflag && exitstatus + && !(flags & EV_TESTED) && (n->type == NCMD || + n->type == NSUBSHELL))) exitshell(exitstatus); - } } STATIC void -evalloop(n) - union node *n; - { +evalloop(union node *n) +{ int status; loopnest++; @@ -319,9 +319,8 @@ skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { STATIC void -evalfor(n) - union node *n; - { +evalfor(union node *n) +{ struct arglist arglist; union node *argp; struct strlist *sp; @@ -331,7 +330,7 @@ evalfor(n) arglist.lastp = &arglist.list; for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { oexitstatus = exitstatus; - expandarg(argp, &arglist, 1); + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); if (evalskip) goto out; } @@ -360,9 +359,8 @@ out: STATIC void -evalcase(n, flags) - union node *n; - { +evalcase(union node *n, int flags) +{ union node *cp; union node *patp; struct arglist arglist; @@ -370,8 +368,8 @@ evalcase(n, flags) setstackmark(&smark); arglist.lastp = &arglist.list; - oexitstatus = exitstatus; - expandarg(n->ncase.expr, &arglist, 0); + oexitstatus = exitstatus; + expandarg(n->ncase.expr, &arglist, EXP_TILDE); for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { if (casematch(patp, arglist.list->text)) { @@ -393,9 +391,8 @@ out: */ STATIC void -evalsubshell(n, flags) - union node *n; - { +evalsubshell(union node *n, int flags) +{ struct job *jp; int backgnd = (n->type == NBACKGND); @@ -409,7 +406,7 @@ evalsubshell(n, flags) } if (! backgnd) { INTOFF; - exitstatus = waitforjob(jp); + exitstatus = waitforjob(jp, (int *)NULL); INTON; } } @@ -421,20 +418,30 @@ evalsubshell(n, flags) */ STATIC void -expredir(n) - union node *n; - { - register union node *redir; +expredir(union node *n) +{ + union node *redir; for (redir = n ; redir ; redir = redir->nfile.next) { + struct arglist fn; + fn.lastp = &fn.list; oexitstatus = exitstatus; - if (redir->type == NFROM - || redir->type == NTO - || redir->type == NAPPEND) { - struct arglist fn; - fn.lastp = &fn.list; - expandarg(redir->nfile.fname, &fn, 0); + switch (redir->type) { + case NFROM: + case NTO: + case NFROMTO: + case NAPPEND: + case NCLOBBER: + expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); redir->nfile.expfname = fn.list->text; + break; + case NFROMFD: + case NTOFD: + if (redir->ndup.vname) { + expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); + fixredir(redir, fn.list->text, 1); + } + break; } } } @@ -449,16 +456,15 @@ expredir(n) */ STATIC void -evalpipe(n) - union node *n; - { +evalpipe(union node *n) +{ struct job *jp; struct nodelist *lp; int pipelen; int prevfd; int pip[2]; - TRACE(("evalpipe(0x%x) called\n", (int)n)); + TRACE(("evalpipe(0x%lx) called\n", (long)n)); pipelen = 0; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) pipelen++; @@ -471,21 +477,20 @@ evalpipe(n) if (lp->next) { if (pipe(pip) < 0) { close(prevfd); - error("Pipe call failed"); + error("Pipe call failed: %s", strerror(errno)); } } if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { INTON; if (prevfd > 0) { - close(0); - copyfd(prevfd, 0); + dup2(prevfd, 0); close(prevfd); } if (pip[1] >= 0) { - close(pip[0]); + if (!(prevfd >= 0 && pip[0] == 0)) + close(pip[0]); if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); + dup2(pip[1], 1); close(pip[1]); } } @@ -499,7 +504,7 @@ evalpipe(n) INTON; if (n->npipe.backgnd == 0) { INTOFF; - exitstatus = waitforjob(jp); + exitstatus = waitforjob(jp, (int *)NULL); TRACE(("evalpipe: job done exit status %d\n", exitstatus)); INTON; } @@ -515,10 +520,8 @@ evalpipe(n) */ void -evalbackcmd(n, result) - union node *n; - struct backcmd *result; - { +evalbackcmd(union node *n, struct backcmd *result) +{ int pip[2]; struct job *jp; struct stackmark smark; /* unnecessary */ @@ -529,21 +532,22 @@ evalbackcmd(n, result) result->nleft = 0; result->jp = NULL; if (n == NULL) { - /* `` */ - } else + exitstatus = 0; + goto out; + } if (n->type == NCMD) { - exitstatus = oexitstatus; + exitstatus = oexitstatus; evalcommand(n, EV_BACKCMD, result); } else { + exitstatus = 0; if (pipe(pip) < 0) - error("Pipe call failed"); + error("Pipe call failed: %s", strerror(errno)); jp = makejob(n, 1); if (forkshell(jp, n, FORK_NOJOB) == 0) { FORCEINTON; close(pip[0]); if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); + dup2(pip[1], 1); close(pip[1]); } evaltree(n, EV_EXIT); @@ -552,8 +556,9 @@ evalbackcmd(n, result) result->fd = pip[0]; result->jp = jp; } +out: popstackmark(&smark); - TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", + TRACE(("evalbackcmd done: fd=%d buf=%p nleft=%d jp=%p\n", result->fd, result->buf, result->nleft, result->jp)); } @@ -564,10 +569,8 @@ evalbackcmd(n, result) */ STATIC void -evalcommand(cmd, flags, backcmd) - union node *cmd; - struct backcmd *backcmd; - { +evalcommand(union node *cmd, int flags, struct backcmd *backcmd) +{ struct stackmark smark; union node *argp; struct arglist arglist; @@ -577,7 +580,6 @@ evalcommand(cmd, flags, backcmd) char **envp; int varflag; struct strlist *sp; - register char *p; int mode; int pip[2]; struct cmdentry cmdentry; @@ -589,27 +591,38 @@ evalcommand(cmd, flags, backcmd) struct localvar *volatile savelocalvars; volatile int e; char *lastarg; + int realstatus; + int do_clearcmdentry; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &argv; + (void) &argc; + (void) &lastarg; + (void) &flags; + (void) &do_clearcmdentry; +#endif /* First expand the arguments. */ - TRACE(("evalcommand(0x%x, %d) called\n", (int)cmd, flags)); + TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); setstackmark(&smark); arglist.lastp = &arglist.list; varlist.lastp = &varlist.list; varflag = 1; - oexitstatus = exitstatus; + do_clearcmdentry = 0; + oexitstatus = exitstatus; exitstatus = 0; for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { - p = argp->narg.text; + char *p = argp->narg.text; if (varflag && is_name(*p)) { do { p++; } while (is_in_name(*p)); if (*p == '=') { - expandarg(argp, &varlist, 0); + expandarg(argp, &varlist, EXP_VARTILDE); continue; } } - expandarg(argp, &arglist, 1); + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); varflag = 0; } *arglist.lastp = NULL; @@ -619,8 +632,11 @@ evalcommand(cmd, flags, backcmd) for (sp = arglist.list ; sp ; sp = sp->next) argc++; argv = stalloc(sizeof (char *) * (argc + 1)); - for (sp = arglist.list ; sp ; sp = sp->next) + + for (sp = arglist.list ; sp ; sp = sp->next) { + TRACE(("evalcommand arg: %s\n", sp->text)); *argv++ = sp->text; + } *argv = NULL; lastarg = NULL; if (iflag && funcnest == 0 && argc > 0) @@ -628,7 +644,7 @@ evalcommand(cmd, flags, backcmd) argv -= argc; /* Print the command if xflag is set. */ - if (xflag == 1) { + if (xflag) { outc('+', &errout); for (sp = varlist.list ; sp ; sp = sp->next) { outc(' ', &errout); @@ -647,11 +663,42 @@ evalcommand(cmd, flags, backcmd) cmdentry.cmdtype = CMDBUILTIN; cmdentry.u.index = BLTINCMD; } else { - find_command(argv[0], &cmdentry, 1); + static const char PATH[] = "PATH="; + char *path = pathval(); + + /* + * Modify the command lookup path, if a PATH= assignment + * is present + */ + for (sp = varlist.list ; sp ; sp = sp->next) + if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) { + path = sp->text + sizeof(PATH) - 1; + /* + * On `PATH=... command`, we need to make + * sure that the command isn't using the + * non-updated hash table of the outer PATH + * setting and we need to make sure that + * the hash table isn't filled with items + * from the temporary setting. + * + * It would be better to forbit using and + * updating the table while this command + * runs, by the command finding mechanism + * is heavily integrated with hash handling, + * so we just delete the hash before and after + * the command runs. Partly deleting like + * changepatch() does doesn't seem worth the + * bookinging effort, since most such runs add + * directories in front of the new PATH. + */ + clearcmdentry(0); + do_clearcmdentry = 1; + } + + find_command(argv[0], &cmdentry, 1, path); if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ - exitstatus = 2; + exitstatus = 127; flushout(&errout); - popstackmark(&smark); return; } /* implement the bltin builtin here */ @@ -662,9 +709,8 @@ evalcommand(cmd, flags, backcmd) break; if ((cmdentry.u.index = find_builtin(*argv)) < 0) { outfmt(&errout, "%s: not found\n", *argv); - exitstatus = 2; + exitstatus = 127; flushout(&errout); - popstackmark(&smark); return; } if (cmdentry.u.index != BLTINCMD) @@ -675,17 +721,21 @@ evalcommand(cmd, flags, backcmd) /* Fork off a child process if necessary. */ if (cmd->ncmd.backgnd - || cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0 - || (flags & EV_BACKCMD) != 0 + || (cmdentry.cmdtype == CMDNORMAL + && ((flags & EV_EXIT) == 0 || Tflag)) + || ((flags & EV_BACKCMD) != 0 && (cmdentry.cmdtype != CMDBUILTIN + || cmdentry.u.index == CDCMD || cmdentry.u.index == DOTCMD - || cmdentry.u.index == EVALCMD)) { + || cmdentry.u.index == EVALCMD)) + || (cmdentry.cmdtype == CMDBUILTIN && + cmdentry.u.index == COMMANDCMD)) { jp = makejob(cmd, 1); mode = cmd->ncmd.backgnd; if (flags & EV_BACKCMD) { mode = FORK_NOJOB; if (pipe(pip) < 0) - error("Pipe call failed"); + error("Pipe call failed: %s", strerror(errno)); } if (forkshell(jp, cmd, mode) != 0) goto parent; /* at end of routine */ @@ -693,8 +743,7 @@ evalcommand(cmd, flags, backcmd) FORCEINTON; close(pip[0]); if (pip[1] != 1) { - close(1); - copyfd(pip[1], 1); + dup2(pip[1], 1); close(pip[1]); } } @@ -704,10 +753,13 @@ evalcommand(cmd, flags, backcmd) /* This is the child process if a fork occurred. */ /* Execute the command. */ if (cmdentry.cmdtype == CMDFUNCTION) { +#if DEBUG trputs("Shell function: "); trargs(argv); +#endif redirect(cmd->ncmd.redirect, REDIR_PUSH); saveparam = shellparam; shellparam.malloc = 0; + shellparam.reset = 1; shellparam.nparam = argc - 1; shellparam.p = argv + 1; shellparam.optnext = NULL; @@ -752,7 +804,9 @@ evalcommand(cmd, flags, backcmd) if (flags & EV_EXIT) exitshell(exitstatus); } else if (cmdentry.cmdtype == CMDBUILTIN) { +#if DEBUG trputs("builtin command: "); trargs(argv); +#endif mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; if (flags == EV_BACKCMD) { memout.nleft = 0; @@ -777,6 +831,7 @@ evalcommand(cmd, flags, backcmd) exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); flushall(); cmddone: + cmdenviron = NULL; out1 = &output; out2 = &errout; freestdout(); @@ -788,10 +843,15 @@ cmddone: } handler = savehandler; if (e != -1) { - if (e != EXERROR || cmdentry.u.index == BLTINCMD - || cmdentry.u.index == DOTCMD - || cmdentry.u.index == EVALCMD - || cmdentry.u.index == EXECCMD) + if ((e != EXERROR && e != EXEXEC) + || cmdentry.u.index == BLTINCMD + || cmdentry.u.index == DOTCMD + || cmdentry.u.index == EVALCMD +#ifndef NO_HISTORY + || cmdentry.u.index == HISTCMD +#endif + || cmdentry.u.index == EXECCMD + || cmdentry.u.index == COMMANDCMD) exraise(e); FORCEINTON; } @@ -803,19 +863,15 @@ cmddone: memout.buf = NULL; } } else { +#if DEBUG trputs("normal command: "); trargs(argv); +#endif clearredir(); redirect(cmd->ncmd.redirect, 0); - if (varlist.list) { - p = stalloc(strlen(pathval()) + 1); - scopy(pathval(), p); - } else { - p = pathval(); - } for (sp = varlist.list ; sp ; sp = sp->next) setvareq(sp->text, VEXPORT|VSTACK); envp = environment(); - shellexec(argv, envp, p, cmdentry.u.index); + shellexec(argv, envp, pathval(), cmdentry.u.index); /*NOTREACHED*/ } goto out; @@ -823,8 +879,12 @@ cmddone: parent: /* parent process gets here (if we forked) */ if (mode == 0) { /* argument to fork */ INTOFF; - exitstatus = waitforjob(jp); + exitstatus = waitforjob(jp, &realstatus); INTON; + if (iflag && loopnest > 0 && WIFSIGNALED(realstatus)) { + evalskip = SKIPBREAK; + skipcount = loopnest; + } } else if (mode == 2) { backcmd->fd = pip[0]; close(pip[1]); @@ -834,6 +894,8 @@ parent: /* parent process gets here (if we forked) */ out: if (lastarg) setvar("_", lastarg, 0); + if (do_clearcmdentry) + clearcmdentry(0); popstackmark(&smark); } @@ -847,13 +909,14 @@ out: */ STATIC void -prehash(n) - union node *n; - { +prehash(union node *n) +{ struct cmdentry entry; - if (n->type == NCMD && goodname(n->ncmd.args->narg.text)) - find_command(n->ncmd.args->narg.text, &entry, 0); + if (n->type == NCMD && n->ncmd.args) + if (goodname(n->ncmd.args->narg.text)) + find_command(n->ncmd.args->narg.text, &entry, 0, + pathval()); } @@ -868,8 +931,14 @@ prehash(n) * specified variables. */ -bltincmd(argc, argv) char **argv; { +int +bltincmd(int argc __unused, char **argv __unused) +{ listsetvar(cmdenviron); + /* + * Preserve exitstatus of a previous possible redirection + * as POSIX mandates + */ return exitstatus; } @@ -885,12 +954,11 @@ bltincmd(argc, argv) char **argv; { * in the standard shell so we don't make it one here. */ -breakcmd(argc, argv) char **argv; { - int n; +int +breakcmd(int argc, char **argv) +{ + int n = argc > 1 ? number(argv[1]) : 1; - n = 1; - if (argc > 1) - n = number(argv[1]); if (n > loopnest) n = loopnest; if (n > 0) { @@ -900,40 +968,108 @@ breakcmd(argc, argv) char **argv; { return 0; } +/* + * The `command' command. + */ +int +commandcmd(int argc, char **argv) +{ + static char stdpath[] = _PATH_STDPATH; + struct jmploc loc, *old; + struct strlist *sp; + char *path; + int ch; + + for (sp = cmdenviron; sp ; sp = sp->next) + setvareq(sp->text, VEXPORT|VSTACK); + path = pathval(); + + optind = optreset = 1; + opterr = 0; + while ((ch = getopt(argc, argv, "p")) != -1) { + switch (ch) { + case 'p': + path = stdpath; + break; + case '?': + default: + error("unknown option: -%c", optopt); + } + } + argc -= optind; + argv += optind; + + if (argc != 0) { + old = handler; + handler = &loc; + if (setjmp(handler->loc) == 0) + shellexec(argv, environment(), path, 0); + handler = old; + if (exception == EXEXEC) + exit(exerrno); + exraise(exception); + } + + /* + * Do nothing successfully if no command was specified; + * ksh also does this. + */ + exit(0); +} + /* * The return command. */ -returncmd(argc, argv) char **argv; { - int ret; +int +returncmd(int argc, char **argv) +{ + int ret = argc > 1 ? number(argv[1]) : oexitstatus; - ret = oexitstatus; - if (argc > 1) - ret = number(argv[1]); if (funcnest) { evalskip = SKIPFUNC; skipcount = 1; + } else { + /* skip the rest of the file */ + evalskip = SKIPFILE; + skipcount = 1; } return ret; } -truecmd(argc, argv) char **argv; { - return strcmp(argv[0], "false") == 0 ? 1 : 0; +int +falsecmd(int argc __unused, char **argv __unused) +{ + return 1; } -execcmd(argc, argv) char **argv; { +int +truecmd(int argc __unused, char **argv __unused) +{ + return 0; +} + + +int +execcmd(int argc, char **argv) +{ if (argc > 1) { + struct strlist *sp; + iflag = 0; /* exit on error */ - setinteractive(0); -#if JOBS - jflag = 0; - setjobctl(0); -#endif + mflag = 0; + optschanged(); + for (sp = cmdenviron; sp ; sp = sp->next) + setvareq(sp->text, VEXPORT|VSTACK); shellexec(argv + 1, environment(), pathval(), 0); } return 0; } + +/* + * $PchId: eval.c,v 1.7 2006/04/10 14:46:14 philip Exp $ + */ diff --git a/commands/ash/eval.h b/commands/ash/eval.h index 04499cb6c..b8b9415b9 100755 --- a/commands/ash/eval.h +++ b/commands/ash/eval.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)eval.h 5.2 (Berkeley) 4/12/91 + * @(#)eval.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/eval.h,v 1.10 2004/04/06 20:06:51 markm Exp $ */ extern char *commandname; /* currently executing command */ @@ -48,18 +45,30 @@ struct backcmd { /* result of evalbackcmd */ struct job *jp; /* job structure for command */ }; - -#ifdef __STDC__ +int evalcmd(int, char **); void evalstring(char *); union node; /* BLETCH for ansi C */ void evaltree(union node *, int); void evalbackcmd(union node *, struct backcmd *); -#else -void evalstring(); -void evaltree(); -void evalbackcmd(); -#endif +int bltincmd(int, char **); +int breakcmd(int, char **); +int returncmd(int, char **); +int falsecmd(int, char **); +int truecmd(int, char **); +int execcmd(int, char **); +int commandcmd(int, char **); /* in_function returns nonzero if we are currently evaluating a function */ #define in_function() funcnest extern int funcnest; +extern int evalskip; + +/* reasons for skipping commands (see comment on breakcmd routine) */ +#define SKIPBREAK 1 +#define SKIPCONT 2 +#define SKIPFUNC 3 +#define SKIPFILE 4 + +/* + * $PchId: eval.h,v 1.3 2006/03/30 15:39:25 philip Exp $ + */ diff --git a/commands/ash/exec.c b/commands/ash/exec.c index ad7158eb7..5020819cd 100755 --- a/commands/ash/exec.c +++ b/commands/ash/exec.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,21 @@ */ #ifndef lint -static char sccsid[] = "@(#)exec.c 5.2 (Berkeley) 3/13/91"; +#if 0 +static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.24.2.1 2004/09/30 04:41:55 des Exp $"); +*/ + +#include +#include +#include +#include +#include +#include /* * When commands are first encountered, they are entered in a hash table. @@ -64,11 +73,9 @@ static char sccsid[] = "@(#)exec.c 5.2 (Berkeley) 3/13/91"; #include "error.h" #include "init.h" #include "mystring.h" -#include -#include -#include -#include -#include +#include "show.h" +#include "jobs.h" +#include "alias.h" #define CMDTABLESIZE 31 /* should be prime */ @@ -87,23 +94,14 @@ struct tblentry { STATIC struct tblentry *cmdtable[CMDTABLESIZE]; STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */ +int exerrno = 0; /* Last exec error */ -#ifdef __STDC__ STATIC void tryexec(char *, char **, char **); -STATIC void execinterp(char **, char **); -STATIC void printentry(struct tblentry *); -STATIC void clearcmdentry(int); +STATIC void printentry(struct tblentry *, int); STATIC struct tblentry *cmdlookup(char *, int); STATIC void delete_cmd_entry(void); -#else -STATIC void tryexec(); -STATIC void execinterp(); -STATIC void printentry(); -STATIC void clearcmdentry(); -STATIC struct tblentry *cmdlookup(); -STATIC void delete_cmd_entry(); -#endif +STATIC void addcmdentry(char *, struct cmdentry *); @@ -113,10 +111,8 @@ STATIC void delete_cmd_entry(); */ void -shellexec(argv, envp, path, index) - char **argv, **envp; - char *path; - { +shellexec(char **argv, char **envp, char *path, int index) +{ char *cmdname; int e; @@ -134,40 +130,37 @@ shellexec(argv, envp, path, index) stunalloc(cmdname); } } - error2(argv[0], errmsg(e, E_EXEC)); + + /* Map to POSIX errors */ + switch (e) { + case EACCES: + exerrno = 126; + break; + case ENOENT: + exerrno = 127; + break; + default: + exerrno = 2; + break; + } + if (e == ENOENT || e == ENOTDIR) + exerror(EXEXEC, "%s: not found", argv[0]); + exerror(EXEXEC, "%s: %s", argv[0], strerror(e)); } STATIC void -tryexec(cmd, argv, envp) - char *cmd; - char **argv; - char **envp; - { +tryexec(char *cmd, char **argv, char **envp) +{ int e; - char *p; -#ifdef SYSV - do { - execve(cmd, argv, envp); - } while (errno == EINTR); -#else execve(cmd, argv, envp); -#endif -#if HASHBANG +#if !__minix_vmd e = errno; if (e == ENOEXEC) { initshellproc(); setinputfile(cmd, 0); commandname = arg0 = savestr(argv[0]); -#ifndef BSD - pgetc(); pungetc(); /* fill up input buffer */ - p = parsenextc; - if (parsenleft > 2 && p[0] == '#' && p[1] == '!') { - argv[0] = cmd; - execinterp(argv, envp); - } -#endif setparam(argv + 1); exraise(EXSHELLPROC); /*NOTREACHED*/ @@ -176,88 +169,6 @@ tryexec(cmd, argv, envp) #endif } - -#if !defined(BSD) && HASHBANG -/* - * Execute an interpreter introduced by "#!", for systems where this - * feature has not been built into the kernel. If the interpreter is - * the shell, return (effectively ignoring the "#!"). If the execution - * of the interpreter fails, exit. - * - * This code peeks inside the input buffer in order to avoid actually - * reading any input. It would benefit from a rewrite. - */ - -#define NEWARGS 5 - -STATIC void -execinterp(argv, envp) - char **argv, **envp; - { - int n; - char *inp; - char *outp; - char c; - char *p; - char **ap; - char *newargs[NEWARGS]; - int i; - char **ap2; - char **new; - - n = parsenleft - 2; - inp = parsenextc + 2; - ap = newargs; - for (;;) { - while (--n >= 0 && (*inp == ' ' || *inp == '\t')) - inp++; - if (n < 0) - goto bad; - if ((c = *inp++) == '\n') - break; - if (ap == &newargs[NEWARGS]) -bad: error("Bad #! line"); - STARTSTACKSTR(outp); - do { - STPUTC(c, outp); - } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n'); - STPUTC('\0', outp); - n++, inp--; - *ap++ = grabstackstr(outp); - } -#if !__minix - if (ap == newargs + 1) { /* if no args, maybe no exec is needed */ - p = newargs[0]; - for (;;) { - if (equal(p, "sh") || equal(p, "ash")) { - return; - } - while (*p != '/') { - if (*p == '\0') - goto break2; - p++; - } - p++; - } -break2:; - } -#endif - i = (char *)ap - (char *)newargs; /* size in bytes */ - if (i == 0) - error("Bad #! line"); - for (ap2 = argv ; *ap2++ != NULL ; ); - new = ckmalloc(i + ((char *)ap2 - (char *)argv)); - ap = newargs, ap2 = new; - while ((i -= sizeof (char **)) >= 0) - *ap2++ = *ap++; - ap = argv; - while (*ap2++ = *ap++); - shellexec(new, envp, pathval(), 0); -} -#endif - - - /* * Do a path search. The variable path (passed by reference) should be * set to the start of the path before the first call; padvance will update @@ -271,11 +182,9 @@ break2:; char *pathopt; char * -padvance(path, name) - char **path; - char *name; - { - register char *p, *q; +padvance(char **path, char *name) +{ + char *p, *q; char *start; int len; @@ -288,7 +197,7 @@ padvance(path, name) growstackblock(); q = stackblock(); if (p != start) { - bcopy(start, q, p - start); + memcpy(q, start, p - start); q += p - start; *q++ = '/'; } @@ -310,7 +219,9 @@ padvance(path, name) /*** Command hashing code ***/ -hashcmd(argc, argv) char **argv; { +int +hashcmd(int argc __unused, char **argv __unused) +{ struct tblentry **pp; struct tblentry *cmdp; int c; @@ -318,14 +229,6 @@ hashcmd(argc, argv) char **argv; { struct cmdentry entry; char *name; - if (argc <= 1) { - for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { - for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { - printentry(cmdp); - } - } - return 0; - } verbose = 0; while ((c = nextopt("rv")) != '\0') { if (c == 'r') { @@ -334,16 +237,28 @@ hashcmd(argc, argv) char **argv; { verbose++; } } + if (*argptr == NULL) { + for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + if (cmdp->cmdtype == CMDNORMAL) + printentry(cmdp, verbose); + } + } + return 0; + } while ((name = *argptr) != NULL) { if ((cmdp = cmdlookup(name, 0)) != NULL && (cmdp->cmdtype == CMDNORMAL - || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) + || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) delete_cmd_entry(); - find_command(name, &entry, 1); + find_command(name, &entry, 1, pathval()); if (verbose) { if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ cmdp = cmdlookup(name, 0); - printentry(cmdp); + if (cmdp != NULL) + printentry(cmdp, verbose); + else + outfmt(&errout, "%s: not found\n", name); } flushall(); } @@ -354,9 +269,8 @@ hashcmd(argc, argv) char **argv; { STATIC void -printentry(cmdp) - struct tblentry *cmdp; - { +printentry(struct tblentry *cmdp, int verbose) +{ int index; char *path; char *name; @@ -373,6 +287,14 @@ printentry(cmdp) out1fmt("builtin %s", cmdp->cmdname); } else if (cmdp->cmdtype == CMDFUNCTION) { out1fmt("function %s", cmdp->cmdname); + if (verbose) { + INTOFF; + name = commandtext(cmdp->param.func); + out1c(' '); + out1str(name); + ckfree(name); + INTON; + } #if DEBUG } else { error("internal error: cmdtype %d", cmdp->cmdtype); @@ -391,14 +313,11 @@ printentry(cmdp) */ void -find_command(name, entry, printerr) - char *name; - struct cmdentry *entry; - { +find_command(char *name, struct cmdentry *entry, int printerr, char *path) +{ struct tblentry *cmdp; int index; int prev; - char *path; char *fullname; struct stat statb; int e; @@ -434,7 +353,6 @@ find_command(name, entry, printerr) prev = cmdp->param.index; } - path = pathval(); e = ENOENT; index = -1; loop: @@ -464,17 +382,13 @@ loop: TRACE(("searchexec \"%s\": no change\n", name)); goto success; } - while (stat(fullname, &statb) < 0) { -#ifdef SYSV - if (errno == EINTR) - continue; -#endif + if (stat(fullname, &statb) < 0) { if (errno != ENOENT && errno != ENOTDIR) e = errno; goto loop; } e = EACCES; /* if we fail, this will be the error */ - if ((statb.st_mode & S_IFMT) != S_IFREG) + if (!S_ISREG(statb.st_mode)) goto loop; if (pathopt) { /* this is a %func directory */ stalloc(strlen(fullname) + 1); @@ -484,6 +398,7 @@ loop: stunalloc(fullname); goto success; } +#ifdef notdef if (statb.st_uid == geteuid()) { if ((statb.st_mode & 0100) == 0) goto loop; @@ -491,23 +406,10 @@ loop: if ((statb.st_mode & 010) == 0) goto loop; } else { -#if __minix_vmd || defined(BSD) - gid_t group_list[NGROUPS_MAX]; - int ngroups, i; - - ngroups = getgroups(NGROUPS_MAX, group_list); - - for (i = 0; i < ngroups; i++) { - if (statb.st_gid == group_list[i]) break; - } - if (i < ngroups) { - if ((statb.st_mode & 010) == 0) - goto loop; - } else -#endif if ((statb.st_mode & 01) == 0) goto loop; } +#endif TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); INTOFF; cmdp = cmdlookup(name, 1); @@ -520,8 +422,12 @@ loop: /* We failed. If there was an entry for this command, delete it */ if (cmdp) delete_cmd_entry(); - if (printerr) - outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC)); + if (printerr) { + if (e == ENOENT || e == ENOTDIR) + outfmt(out2, "%s: not found\n", name); + else + outfmt(out2, "%s: %s\n", name, strerror(e)); + } entry->cmdtype = CMDUNKNOWN; return; @@ -538,10 +444,9 @@ success: */ int -find_builtin(name) - char *name; - { - const register struct builtincmd *bp; +find_builtin(char *name) +{ + const struct builtincmd *bp; for (bp = builtincmd ; bp->name ; bp++) { if (*bp->name == *name && equal(bp->name, name)) @@ -558,14 +463,15 @@ find_builtin(name) */ void -hashcd() { +hashcd(void) +{ struct tblentry **pp; struct tblentry *cmdp; for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { if (cmdp->cmdtype == CMDNORMAL - || cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0) + || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) cmdp->rehash = 1; } } @@ -580,10 +486,9 @@ hashcd() { */ void -changepath(newval) - char *newval; - { - char *old, *new; +changepath(const char *newval) +{ + const char *old, *new; int index; int firstchange; int bltin; @@ -596,8 +501,8 @@ changepath(newval) for (;;) { if (*old != *new) { firstchange = index; - if (*old == '\0' && *new == ':' - || *old == ':' && *new == '\0') + if ((*old == '\0' && *new == ':') + || (*old == ':' && *new == '\0')) firstchange++; old = new; /* ignore subsequent differences */ } @@ -624,8 +529,9 @@ changepath(newval) * PATH which has changed. */ -STATIC void -clearcmdentry(firstchange) { +void +clearcmdentry(int firstchange) +{ struct tblentry **tblp; struct tblentry **pp; struct tblentry *cmdp; @@ -634,8 +540,10 @@ clearcmdentry(firstchange) { for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { pp = tblp; while ((cmdp = *pp) != NULL) { - if (cmdp->cmdtype == CMDNORMAL && cmdp->param.index >= firstchange - || cmdp->cmdtype == CMDBUILTIN && builtinloc >= firstchange) { + if ((cmdp->cmdtype == CMDNORMAL && + cmdp->param.index >= firstchange) + || (cmdp->cmdtype == CMDBUILTIN && + builtinloc >= firstchange)) { *pp = cmdp->next; ckfree(cmdp); } else { @@ -652,15 +560,15 @@ clearcmdentry(firstchange) { */ #ifdef mkinit -MKINIT void deletefuncs(); - +INCLUDE "exec.h" SHELLPROC { deletefuncs(); } #endif void -deletefuncs() { +deletefuncs(void) +{ struct tblentry **tblp; struct tblentry **pp; struct tblentry *cmdp; @@ -691,15 +599,14 @@ deletefuncs() { * entry. */ -struct tblentry **lastcmdentry; +STATIC struct tblentry **lastcmdentry; STATIC struct tblentry * -cmdlookup(name, add) - char *name; - { +cmdlookup(char *name, int add) +{ int hashval; - register char *p; + char *p; struct tblentry *cmdp; struct tblentry **pp; @@ -728,13 +635,13 @@ cmdlookup(name, add) return cmdp; } - /* * Delete the command entry returned on the last lookup. */ STATIC void -delete_cmd_entry() { +delete_cmd_entry(void) +{ struct tblentry *cmdp; INTOFF; @@ -746,35 +653,14 @@ delete_cmd_entry() { -#ifdef notdef -void -getcmdentry(name, entry) - char *name; - struct cmdentry *entry; - { - struct tblentry *cmdp = cmdlookup(name, 0); - - if (cmdp) { - entry->u = cmdp->param; - entry->cmdtype = cmdp->cmdtype; - } else { - entry->cmdtype = CMDUNKNOWN; - entry->u.index = 0; - } -} -#endif - - /* * Add a new command entry, replacing any existing command entry for * the same name. */ -void -addcmdentry(name, entry) - char *name; - struct cmdentry *entry; - { +static void +addcmdentry(char *name, struct cmdentry *entry) +{ struct tblentry *cmdp; INTOFF; @@ -793,10 +679,8 @@ addcmdentry(name, entry) */ void -defun(name, func) - char *name; - union node *func; - { +defun(char *name, union node *func) +{ struct cmdentry entry; INTOFF; @@ -811,14 +695,98 @@ defun(name, func) * Delete a function if it exists. */ -void -unsetfunc(name) - char *name; - { +int +unsetfunc(char *name) +{ struct tblentry *cmdp; if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { freefunc(cmdp->param.func); delete_cmd_entry(); + return (0); } + return (0); } + +/* + * Locate and print what a word is... + */ + +int +typecmd(int argc, char **argv) +{ + struct cmdentry entry; + struct tblentry *cmdp; + char **pp; + struct alias *ap; + int i; + int error = 0; + extern char *const parsekwd[]; + + for (i = 1; i < argc; i++) { + out1str(argv[i]); + /* First look at the keywords */ + for (pp = (char **)parsekwd; *pp; pp++) + if (**pp == *argv[i] && equal(*pp, argv[i])) + break; + + if (*pp) { + out1str(" is a shell keyword\n"); + continue; + } + + /* Then look at the aliases */ + if ((ap = lookupalias(argv[i], 1)) != NULL) { + out1fmt(" is an alias for %s\n", ap->val); + continue; + } + + /* Then check if it is a tracked alias */ + if ((cmdp = cmdlookup(argv[i], 0)) != NULL) { + entry.cmdtype = cmdp->cmdtype; + entry.u = cmdp->param; + } + else { + /* Finally use brute force */ + find_command(argv[i], &entry, 0, pathval()); + } + + switch (entry.cmdtype) { + case CMDNORMAL: { + if (strchr(argv[i], '/') == NULL) { + char *path = pathval(), *name; + int j = entry.u.index; + do { + name = padvance(&path, argv[i]); + stunalloc(name); + } while (--j >= 0); + out1fmt(" is%s %s\n", + cmdp ? " a tracked alias for" : "", name); + } else { + if (access(argv[i], X_OK) == 0) + out1fmt(" is %s\n", argv[i]); + else + out1fmt(": %s\n", strerror(errno)); + } + break; + } + case CMDFUNCTION: + out1str(" is a shell function\n"); + break; + + case CMDBUILTIN: + out1str(" is a shell builtin\n"); + break; + + default: + out1str(": not found\n"); + error |= 127; + break; + } + } + return error; +} + +/* + * $PchId: exec.c,v 1.6 2006/04/10 14:47:03 philip Exp $ + */ diff --git a/commands/ash/exec.h b/commands/ash/exec.h index cd333dc94..eef4c9533 100755 --- a/commands/ash/exec.h +++ b/commands/ash/exec.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)exec.h 5.1 (Berkeley) 3/7/91 + * @(#)exec.h 8.3 (Berkeley) 6/8/95 + * $FreeBSD: src/bin/sh/exec.h,v 1.12 2004/04/06 20:06:51 markm Exp $ */ /* values of cmdtype */ @@ -53,23 +50,21 @@ struct cmdentry { extern char *pathopt; /* set by padvance */ +extern int exerrno; /* last exec error */ -#ifdef __STDC__ void shellexec(char **, char **, char *, int); char *padvance(char **, char *); -void find_command(char *, struct cmdentry *, int); +int hashcmd(int, char **); +void find_command(char *, struct cmdentry *, int, char *); int find_builtin(char *); void hashcd(void); -void changepath(char *); +void changepath(const char *); +void deletefuncs(void); void defun(char *, union node *); -void unsetfunc(char *); -#else -void shellexec(); -char *padvance(); -void find_command(); -int find_builtin(); -void hashcd(); -void changepath(); -void defun(); -void unsetfunc(); -#endif +int unsetfunc(char *); +int typecmd(int, char **); +void clearcmdentry(int); + +/* + * $PchId: exec.h,v 1.5 2006/04/10 14:47:34 philip Exp $ + */ diff --git a/commands/ash/expand.c b/commands/ash/expand.c index 28ef32ab0..a0ef6924d 100755 --- a/commands/ash/expand.c +++ b/commands/ash/expand.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,25 @@ */ #ifndef lint -static char sccsid[] = "@(#)expand.c 5.1 (Berkeley) 3/7/91"; +#if 0 +static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/expand.c,v 1.46 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* * Routines to expand arguments to commands. We have to deal with @@ -58,13 +71,8 @@ static char sccsid[] = "@(#)expand.c 5.1 (Berkeley) 3/7/91"; #include "memalloc.h" #include "error.h" #include "mystring.h" -#include -#include -#include -#include -#if USEGETPW -#include -#endif +#include "arith.h" +#include "show.h" /* * Structure specifying which parts of the string should be searched @@ -79,67 +87,51 @@ struct ifsregion { }; -char *expdest; /* output of current string */ -struct nodelist *argbackq; /* list of back quote expressions */ -struct ifsregion ifsfirst; /* first struct in list of ifs regions */ -struct ifsregion *ifslastp; /* last struct in list */ -struct arglist exparg; /* holds expanded arg list */ -#if UDIR || TILDE -/* - * Set if the last argument processed had /u/logname or ~logname expanded. - * This variable is read by the cd command. - */ -int didudir; -#endif +STATIC char *expdest; /* output of current string */ +STATIC struct nodelist *argbackq; /* list of back quote expressions */ +STATIC struct ifsregion ifsfirst; /* first struct in list of ifs regions */ +STATIC struct ifsregion *ifslastp; /* last struct in list */ +STATIC struct arglist exparg; /* holds expanded arg list */ -#ifdef __STDC__ STATIC void argstr(char *, int); +STATIC char *exptilde(char *, int); STATIC void expbackq(union node *, int, int); +STATIC int subevalvar(char *, char *, int, int, int, int); STATIC char *evalvar(char *, int); -STATIC int varisset(int); -STATIC void varvalue(int, int, int); +STATIC int varisset(char *, int); +STATIC void varvalue(char *, int, int); STATIC void recordregion(int, int, int); +STATIC void removerecordregions(int); STATIC void ifsbreakup(char *, struct arglist *); -STATIC void expandmeta(struct strlist *); +STATIC void expandmeta(struct strlist *, int); STATIC void expmeta(char *, char *); STATIC void addfname(char *); STATIC struct strlist *expsort(struct strlist *); STATIC struct strlist *msort(struct strlist *, int); -STATIC int pmatch(char *, char *); -#else -STATIC void argstr(); -STATIC void expbackq(); -STATIC char *evalvar(); -STATIC int varisset(); -STATIC void varvalue(); -STATIC void recordregion(); -STATIC void ifsbreakup(); -STATIC void expandmeta(); -STATIC void expmeta(); -STATIC void addfname(); -STATIC struct strlist *expsort(); -STATIC struct strlist *msort(); -STATIC int pmatch(); -#endif -#if UDIR || TILDE -#ifdef __STDC__ -STATIC char *expudir(char *); -#else -STATIC char *expudir(); -#endif -#endif /* UDIR || TILDE */ +STATIC int pmatch(char *, char *, int); +STATIC char *cvtnum(int, char *); +STATIC int collate_range_cmp(int, int); +STATIC void expari(int); +STATIC int +collate_range_cmp(int c1, int c2) +{ + static char s1[2], s2[2]; + s1[0] = c1; + s2[0] = c2; + return (strcoll(s1, s2)); +} /* * Expand shell variables and backquotes inside a here document. + * union node *arg the document + * int fd; where to write the expanded version */ void -expandhere(arg, fd) - union node *arg; /* the document */ - int fd; /* where to write the expanded version */ - { +expandhere(union node *arg, int fd) +{ herefd = fd; expandarg(arg, (struct arglist *)NULL, 0); xwrite(fd, stackblock(), expdest - stackblock()); @@ -148,38 +140,39 @@ expandhere(arg, fd) /* * Perform variable substitution and command substitution on an argument, - * placing the resulting list of arguments in arglist. If full is true, + * placing the resulting list of arguments in arglist. If EXP_FULL is true, * perform splitting and file name expansion. When arglist is NULL, perform * here document expansion. */ void -expandarg(arg, arglist, full) - union node *arg; - struct arglist *arglist; - { +expandarg(union node *arg, struct arglist *arglist, int flag) +{ struct strlist *sp; char *p; -#if UDIR || TILDE - didudir = 0; -#endif argbackq = arg->narg.backquote; STARTSTACKSTR(expdest); ifsfirst.next = NULL; ifslastp = NULL; - argstr(arg->narg.text, full); - if (arglist == NULL) + argstr(arg->narg.text, flag); + if (arglist == NULL) { return; /* here document expanded */ + } STPUTC('\0', expdest); p = grabstackstr(expdest); exparg.lastp = &exparg.list; - if (full) { + /* + * TODO - EXP_REDIR + */ + if (flag & EXP_FULL) { ifsbreakup(p, &exparg); *exparg.lastp = NULL; exparg.lastp = &exparg.list; - expandmeta(exparg.list); + expandmeta(exparg.list, flag); } else { + if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ + rmescapes(p); sp = (struct strlist *)stalloc(sizeof (struct strlist)); sp->text = p; *exparg.lastp = sp; @@ -203,36 +196,66 @@ expandarg(arg, arglist, full) /* - * Perform variable and command substitution. If full is set, output CTLESC - * characters to allow for further processing. If full is not set, treat + * Perform variable and command substitution. If EXP_FULL is set, output CTLESC + * characters to allow for further processing. Otherwise treat * $@ like $* since no splitting will be performed. */ STATIC void -argstr(p, full) - register char *p; - { +argstr(char *p, int flag) +{ char c; + int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ + int firsteq = 1; + if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) + p = exptilde(p, flag); for (;;) { switch (c = *p++) { case '\0': - case CTLENDVAR: + case CTLENDVAR: /* ??? */ goto breakloop; + case CTLQUOTEMARK: + /* "$@" syntax adherence hack */ + if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=') + break; + if ((flag & EXP_FULL) != 0) + STPUTC(c, expdest); + break; case CTLESC: - if (full) + if (quotes) STPUTC(c, expdest); c = *p++; STPUTC(c, expdest); break; case CTLVAR: - p = evalvar(p, full); + p = evalvar(p, flag); break; case CTLBACKQ: case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c & CTLQUOTE, full); + expbackq(argbackq->n, c & CTLQUOTE, flag); argbackq = argbackq->next; break; + case CTLENDARI: + expari(flag); + break; + case ':': + case '=': + /* + * sort of a hack - expand tildes in variable + * assignments (after the first '=' and after ':'s). + */ + STPUTC(c, expdest); + if (flag & EXP_VARTILDE && *p == '~') { + if (c == '=') { + if (firsteq) + firsteq = 0; + else + break; + } + p = exptilde(p, flag); + } + break; default: STPUTC(c, expdest); } @@ -240,15 +263,159 @@ argstr(p, full) breakloop:; } +STATIC char * +exptilde(char *p, int flag) +{ + char c, *startp = p; + struct passwd *pw; + char *home; + int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); + + while ((c = *p) != '\0') { + switch(c) { + case CTLESC: + return (startp); + case CTLQUOTEMARK: + return (startp); + case ':': + if (flag & EXP_VARTILDE) + goto done; + break; + case '/': + goto done; + } + p++; + } +done: + *p = '\0'; + if (*(startp+1) == '\0') { + if ((home = lookupvar("HOME")) == NULL) + goto lose; + } else { + if ((pw = getpwnam(startp+1)) == NULL) + goto lose; + home = pw->pw_dir; + } + if (*home == '\0') + goto lose; + *p = c; + while ((c = *home++) != '\0') { + if (quotes && SQSYNTAX[(int)c] == CCTL) + STPUTC(CTLESC, expdest); + STPUTC(c, expdest); + } + return (p); +lose: + *p = c; + return (startp); +} + + +STATIC void +removerecordregions(int endoff) +{ + if (ifslastp == NULL) + return; + + if (ifsfirst.endoff > endoff) { + while (ifsfirst.next != NULL) { + struct ifsregion *ifsp; + INTOFF; + ifsp = ifsfirst.next->next; + ckfree(ifsfirst.next); + ifsfirst.next = ifsp; + INTON; + } + if (ifsfirst.begoff > endoff) + ifslastp = NULL; + else { + ifslastp = &ifsfirst; + ifsfirst.endoff = endoff; + } + return; + } + + ifslastp = &ifsfirst; + while (ifslastp->next && ifslastp->next->begoff < endoff) + ifslastp=ifslastp->next; + while (ifslastp->next != NULL) { + struct ifsregion *ifsp; + INTOFF; + ifsp = ifslastp->next->next; + ckfree(ifslastp->next); + ifslastp->next = ifsp; + INTON; + } + if (ifslastp->endoff > endoff) + ifslastp->endoff = endoff; +} + +/* + * Expand arithmetic expression. Backup to start of expression, + * evaluate, place result in (backed up) result, adjust string position. + */ +STATIC void +expari(int flag) +{ + char *p, *start; + int result; + int begoff; + int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); + int quoted; + + + /* + * This routine is slightly over-complicated for + * efficiency. First we make sure there is + * enough space for the result, which may be bigger + * than the expression if we add exponentiation. Next we + * scan backwards looking for the start of arithmetic. If the + * next previous character is a CTLESC character, then we + * have to rescan starting from the beginning since CTLESC + * characters have to be processed left to right. + */ +#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10 +#error "integers with more than 10 digits are not supported" +#endif + CHECKSTRSPACE(12 - 2, expdest); + USTPUTC('\0', expdest); + start = stackblock(); + p = expdest - 2; + while (p >= start && *p != CTLARI) + --p; + if (p < start || *p != CTLARI) + error("missing CTLARI (shouldn't happen)"); + if (p > start && *(p - 1) == CTLESC) + for (p = start; *p != CTLARI; p++) + if (*p == CTLESC) + p++; + + if (p[1] == '"') + quoted=1; + else + quoted=0; + begoff = p - start; + removerecordregions(begoff); + if (quotes) + rmescapes(p+2); + result = arith(p+2); + fmtstr(p, 12, "%d", result); + while (*p++) + ; + if (quoted == 0) + recordregion(begoff, p - 1 - start, 0); + result = expdest - p + 1; + STADJUST(-result, expdest); +} + /* * Expand stuff in backwards quotes. */ STATIC void -expbackq(cmd, quoted, full) - union node *cmd; - { +expbackq(union node *cmd, int quoted, int flag) +{ struct backcmd in; int i; char buf[128]; @@ -260,12 +427,14 @@ expbackq(cmd, quoted, full) int startloc = dest - stackblock(); char const *syntax = quoted? DQSYNTAX : BASESYNTAX; int saveherefd; + int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); + int nnl; INTOFF; saveifs = ifsfirst; savelastp = ifslastp; saveargbackq = argbackq; - saveherefd = herefd; + saveherefd = herefd; herefd = -1; p = grabstackstr(dest); evalbackcmd(cmd, &in); @@ -277,6 +446,8 @@ expbackq(cmd, quoted, full) p = in.buf; lastc = '\0'; + nnl = 0; + /* Don't copy trailing newlines */ for (;;) { if (--in.nleft < 0) { if (in.fd < 0) @@ -290,20 +461,26 @@ expbackq(cmd, quoted, full) } lastc = *p++; if (lastc != '\0') { - if (full && syntax[lastc] == CCTL) + if (quotes && syntax[(int)lastc] == CCTL) STPUTC(CTLESC, dest); - STPUTC(lastc, dest); + if (lastc == '\n') { + nnl++; + } else { + while (nnl > 0) { + nnl--; + STPUTC('\n', dest); + } + STPUTC(lastc, dest); + } } } - if (lastc == '\n') { - STUNPUTC(dest); - } + if (in.fd >= 0) close(in.fd); if (in.buf) ckfree(in.buf); if (in.jp) - exitstatus = waitforjob(in.jp); + exitstatus = waitforjob(in.jp, (int *)NULL); if (quoted == 0) recordregion(startloc, dest - stackblock(), 0); TRACE(("evalbackq: size=%d: \"%.*s\"\n", @@ -316,26 +493,150 @@ expbackq(cmd, quoted, full) +STATIC int +subevalvar(char *p, char *str, int strloc, int subtype, int startloc, + int varflags) +{ + char *startp; + char *loc = NULL; + char *q; + int c = 0; + int saveherefd = herefd; + struct nodelist *saveargbackq = argbackq; + int amount; + + herefd = -1; + argstr(p, 0); + STACKSTRNUL(expdest); + herefd = saveherefd; + argbackq = saveargbackq; + startp = stackblock() + startloc; + if (str == NULL) + str = stackblock() + strloc; + + switch (subtype) { + case VSASSIGN: + setvar(str, startp, 0); + amount = startp - expdest; + STADJUST(amount, expdest); + varflags &= ~VSNUL; + if (c != 0) + *loc = c; + return 1; + + case VSQUESTION: + if (*p != CTLENDVAR) { + outfmt(&errout, "%s\n", startp); + error((char *)NULL); + } + error("%.*s: parameter %snot set", (int)(p - str - 1), + str, (varflags & VSNUL) ? "null or " + : nullstr); + return 0; + + case VSTRIMLEFT: + for (loc = startp; loc < str; loc++) { + c = *loc; + *loc = '\0'; + if (patmatch(str, startp, varflags & VSQUOTE)) { + *loc = c; + goto recordleft; + } + *loc = c; + if ((varflags & VSQUOTE) && *loc == CTLESC) + loc++; + } + return 0; + + case VSTRIMLEFTMAX: + for (loc = str - 1; loc >= startp;) { + c = *loc; + *loc = '\0'; + if (patmatch(str, startp, varflags & VSQUOTE)) { + *loc = c; + goto recordleft; + } + *loc = c; + loc--; + if ((varflags & VSQUOTE) && loc > startp && + *(loc - 1) == CTLESC) { + for (q = startp; q < loc; q++) + if (*q == CTLESC) + q++; + if (q > loc) + loc--; + } + } + return 0; + + case VSTRIMRIGHT: + for (loc = str - 1; loc >= startp;) { + if (patmatch(str, loc, varflags & VSQUOTE)) { + amount = loc - expdest; + STADJUST(amount, expdest); + return 1; + } + loc--; + if ((varflags & VSQUOTE) && loc > startp && + *(loc - 1) == CTLESC) { + for (q = startp; q < loc; q++) + if (*q == CTLESC) + q++; + if (q > loc) + loc--; + } + } + return 0; + + case VSTRIMRIGHTMAX: + for (loc = startp; loc < str - 1; loc++) { + if (patmatch(str, loc, varflags & VSQUOTE)) { + amount = loc - expdest; + STADJUST(amount, expdest); + return 1; + } + if ((varflags & VSQUOTE) && *loc == CTLESC) + loc++; + } + return 0; + + + default: + abort(); + } + +recordleft: + amount = ((str - 1) - (loc - startp)) - expdest; + STADJUST(amount, expdest); + while (loc != str - 1) + *startp++ = *loc++; + return 1; +} + + /* * Expand a variable, and return a pointer to the next character in the * input string. */ STATIC char * -evalvar(p, full) - char *p; - { +evalvar(char *p, int flag) +{ int subtype; - int flags; + int varflags; char *var; char *val; + int patloc; int c; int set; int special; int startloc; + int varlen; + int easy; + int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); - flags = *p++; - subtype = flags & VSTYPE; + varflags = *p++; + subtype = varflags & VSTYPE; var = p; special = 0; if (! is_name(*p)) @@ -343,72 +644,139 @@ evalvar(p, full) p = strchr(p, '=') + 1; again: /* jump here after setting a variable with ${var=text} */ if (special) { - set = varisset(*var); + set = varisset(var, varflags & VSNUL); val = NULL; } else { - val = lookupvar(var); - if (val == NULL || (flags & VSNUL) && val[0] == '\0') { + val = bltinlookup(var, 1); + if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { val = NULL; set = 0; } else set = 1; } + varlen = 0; startloc = expdest - stackblock(); + if (!set && uflag) { + switch (subtype) { + case VSNORMAL: + case VSTRIMLEFT: + case VSTRIMLEFTMAX: + case VSTRIMRIGHT: + case VSTRIMRIGHTMAX: + case VSLENGTH: + error("%.*s: parameter not set", (int)(p - var - 1), + var); + } + } if (set && subtype != VSPLUS) { /* insert the value of the variable */ if (special) { - varvalue(*var, flags & VSQUOTE, full); + varvalue(var, varflags & VSQUOTE, flag & EXP_FULL); + if (subtype == VSLENGTH) { + varlen = expdest - stackblock() - startloc; + STADJUST(-varlen, expdest); + } } else { - char const *syntax = (flags & VSQUOTE)? DQSYNTAX : BASESYNTAX; + char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX + : BASESYNTAX; + + if (subtype == VSLENGTH) { + for (;*val; val++) + varlen++; + } + else { + while (*val) { + if (quotes && + syntax[(int)*val] == CCTL) + STPUTC(CTLESC, expdest); + STPUTC(*val++, expdest); + } - while (*val) { - if (full && syntax[*val] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*val++, expdest); } } } + if (subtype == VSPLUS) set = ! set; - if (((flags & VSQUOTE) == 0 || (*var == '@' && shellparam.nparam != 1)) - && (set || subtype == VSNORMAL)) - recordregion(startloc, expdest - stackblock(), flags & VSQUOTE); - if (! set && subtype != VSNORMAL) { - if (subtype == VSPLUS || subtype == VSMINUS) { - argstr(p, full); - } else { - char *startp; - int saveherefd = herefd; - herefd = -1; - argstr(p, 0); - STACKSTRNUL(expdest); - herefd = saveherefd; - startp = stackblock() + startloc; - if (subtype == VSASSIGN) { - setvar(var, startp, 0); - STADJUST(startp - expdest, expdest); - flags &=~ VSNUL; + + easy = ((varflags & VSQUOTE) == 0 || + (*var == '@' && shellparam.nparam != 1)); + + + switch (subtype) { + case VSLENGTH: + expdest = cvtnum(varlen, expdest); + goto record; + + case VSNORMAL: + if (!easy) + break; +record: + recordregion(startloc, expdest - stackblock(), + varflags & VSQUOTE); + break; + + case VSPLUS: + case VSMINUS: + if (!set) { + argstr(p, flag); + break; + } + if (easy) + goto record; + break; + + case VSTRIMLEFT: + case VSTRIMLEFTMAX: + case VSTRIMRIGHT: + case VSTRIMRIGHTMAX: + if (!set) + break; + /* + * Terminate the string and start recording the pattern + * right after it + */ + STPUTC('\0', expdest); + patloc = expdest - stackblock(); + if (subevalvar(p, NULL, patloc, subtype, + startloc, varflags) == 0) { + int amount = (expdest - stackblock() - patloc) + 1; + STADJUST(-amount, expdest); + } + /* Remove any recorded regions beyond start of variable */ + removerecordregions(startloc); + goto record; + + case VSASSIGN: + case VSQUESTION: + if (!set) { + if (subevalvar(p, var, 0, subtype, startloc, varflags)) { + varflags &= ~VSNUL; + /* + * Remove any recorded regions beyond + * start of variable + */ + removerecordregions(startloc); goto again; } - /* subtype == VSQUESTION */ - if (*p != CTLENDVAR) { - outfmt(&errout, "%s\n", startp); - error((char *)NULL); - } - error("%.*s: parameter %snot set", p - var - 1, - var, (flags & VSNUL)? "null or " : nullstr); + break; } + if (easy) + goto record; + break; + + default: + abort(); } + if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; for (;;) { if ((c = *p++) == CTLESC) p++; else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { - if (set) { - if (argbackq != NULL) - argbackq = argbackq->next; - } + if (set) + argbackq = argbackq->next; } else if (c == CTLVAR) { if ((*p++ & VSTYPE) != VSNORMAL) nesting++; @@ -428,23 +796,37 @@ again: /* jump here after setting a variable with ${var=text} */ */ STATIC int -varisset(name) - char name; - { - char **ap; +varisset(char *name, int nulok) +{ - if (name == '!') { - if (backgndpid == -1) - return 0; - } else if (name == '@' || name == '*') { + if (*name == '!') + return backgndpid != -1; + else if (*name == '@' || *name == '*') { if (*shellparam.p == NULL) return 0; - } else if ((unsigned)(name -= '1') <= '9' - '1') { - ap = shellparam.p; - do { - if (*ap++ == NULL) - return 0; - } while (--name >= 0); + + if (nulok) { + char **av; + + for (av = shellparam.p; *av; av++) + if (**av != '\0') + return 1; + return 0; + } + } else if (is_digit(*name)) { + char *ap; + int num = atoi(name); + + if (num > shellparam.nparam) + return 0; + + if (num == 0) + ap = arg0; + else + ap = shellparam.p[num - 1]; + + if (nulok && (ap == NULL || *ap == '\0')) + return 0; } return 1; } @@ -456,11 +838,9 @@ varisset(name) */ STATIC void -varvalue(name, quoted, allow_split) - char name; - { +varvalue(char *name, int quoted, int allow_split) +{ int num; - char temp[32]; char *p; int i; extern int oexitstatus; @@ -468,7 +848,22 @@ varvalue(name, quoted, allow_split) char **ap; char const *syntax; - switch (name) { +#define STRTODEST(p) \ + do {\ + if (allow_split) { \ + syntax = quoted? DQSYNTAX : BASESYNTAX; \ + while (*p) { \ + if (syntax[(int)*p] == CCTL) \ + STPUTC(CTLESC, expdest); \ + STPUTC(*p++, expdest); \ + } \ + } else \ + while (*p) \ + STPUTC(*p++, expdest); \ + } while (0) + + + switch (*name) { case '$': num = rootpid; goto numvar; @@ -481,59 +876,46 @@ varvalue(name, quoted, allow_split) case '!': num = backgndpid; numvar: - p = temp + 31; - temp[31] = '\0'; - do { - *--p = num % 10 + '0'; - } while ((num /= 10) != 0); - while (*p) - STPUTC(*p++, expdest); + expdest = cvtnum(num, expdest); break; case '-': - for (i = 0 ; optchar[i] ; i++) { - if (optval[i]) - STPUTC(optchar[i], expdest); + for (i = 0 ; i < NOPTS ; i++) { + if (optlist[i].val) + STPUTC(optlist[i].letter, expdest); } break; case '@': - if (allow_split) { - sep = '\0'; - goto allargs; - } - /* fall through */ - case '*': - sep = ' '; -allargs: - /* Only emit CTLESC if we will do further processing, - i.e. if allow_split is set. */ - syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX; - for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { - /* should insert CTLESC characters */ - while (*p) { - if (syntax[*p] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*p++, expdest); + if (allow_split && quoted) { + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { + STRTODEST(p); + if (*ap) + STPUTC('\0', expdest); } - if (*ap) + break; + } + /* FALLTHROUGH */ + case '*': + if (ifsset() != 0) + sep = ifsval()[0]; + else + sep = ' '; + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { + STRTODEST(p); + if (*ap && sep) STPUTC(sep, expdest); } break; case '0': p = arg0; -string: - /* Only emit CTLESC if we will do further processing, - i.e. if allow_split is set. */ - syntax = quoted && allow_split ? DQSYNTAX : BASESYNTAX; - while (*p) { - if (syntax[*p] == CCTL) - STPUTC(CTLESC, expdest); - STPUTC(*p++, expdest); - } + STRTODEST(p); break; default: - if ((unsigned)(name -= '1') <= '9' - '1') { - p = shellparam.p[name]; - goto string; + if (is_digit(*name)) { + num = atoi(name); + if (num > 0 && num <= shellparam.nparam) { + p = shellparam.p[num - 1]; + STRTODEST(p); + } } break; } @@ -547,8 +929,9 @@ string: */ STATIC void -recordregion(start, end, nulonly) { - register struct ifsregion *ifsp; +recordregion(int start, int end, int nulonly) +{ + struct ifsregion *ifsp; if (ifslastp == NULL) { ifsp = &ifsfirst; @@ -570,55 +953,79 @@ recordregion(start, end, nulonly) { * strings to the argument list. The regions of the string to be * searched for IFS characters have been stored by recordregion. */ - STATIC void -ifsbreakup(string, arglist) - char *string; - struct arglist *arglist; - { +ifsbreakup(char *string, struct arglist *arglist) +{ struct ifsregion *ifsp; struct strlist *sp; char *start; - register char *p; + char *p; char *q; char *ifs; + int ifsspc; + int nulonly; + start = string; + ifsspc = 0; + nulonly = 0; if (ifslastp != NULL) { ifsp = &ifsfirst; do { p = string + ifsp->begoff; - ifs = ifsp->nulonly? nullstr : ifsval(); + nulonly = ifsp->nulonly; + ifs = nulonly ? nullstr : + ( ifsset() ? ifsval() : " \t\n" ); + ifsspc = 0; while (p < string + ifsp->endoff) { q = p; if (*p == CTLESC) p++; - if (strchr(ifs, *p++)) { - if (q > start || *ifs != ' ') { - *q = '\0'; - sp = (struct strlist *)stalloc(sizeof *sp); - sp->text = start; - *arglist->lastp = sp; - arglist->lastp = &sp->next; + if (strchr(ifs, *p)) { + if (!nulonly) + ifsspc = (strchr(" \t\n", *p) != NULL); + /* Ignore IFS whitespace at start */ + if (q == start && ifsspc) { + p++; + start = p; + continue; } - if (*ifs == ' ') { + *q = '\0'; + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; + p++; + if (!nulonly) { for (;;) { - if (p >= string + ifsp->endoff) + if (p >= string + ifsp->endoff) { break; + } q = p; if (*p == CTLESC) p++; - if (strchr(ifs, *p++) == NULL) { + if (strchr(ifs, *p) == NULL ) { p = q; break; - } + } else if (strchr(" \t\n",*p) == NULL) { + if (ifsspc) { + p++; + ifsspc = 0; + } else { + p = q; + break; + } + } else + p++; } } start = p; - } + } else + p++; } } while ((ifsp = ifsp->next) != NULL); - if (*start || (*ifs != ' ' && start > string)) { + if (*start || (!ifsspc && start > string && + (nulonly || 1))) { sp = (struct strlist *)stalloc(sizeof *sp); sp->text = start; *arglist->lastp = sp; @@ -639,30 +1046,22 @@ ifsbreakup(string, arglist) * should be escapes. The results are stored in the list exparg. */ -char *expdir; +STATIC char *expdir; STATIC void -expandmeta(str) - struct strlist *str; - { +expandmeta(struct strlist *str, int flag __unused) +{ char *p; struct strlist **savelastp; struct strlist *sp; char c; + /* TODO - EXP_REDIR */ while (str) { if (fflag) goto nometa; p = str->text; -#if UDIR - if (p[0] == '/' && p[1] == 'u' && p[2] == '/') - str->text = p = expudir(p); -#endif -#if TILDE - if (p[0] == '~') - str->text = p = expudir(p); -#endif for (;;) { /* fast check for meta chars */ if ((c = *p++) == '\0') goto nometa; @@ -671,22 +1070,23 @@ expandmeta(str) } savelastp = exparg.lastp; INTOFF; - if (expdir == NULL) - { + if (expdir == NULL) { int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ } + expmeta(expdir, str->text); ckfree(expdir); expdir = NULL; INTON; if (exparg.lastp == savelastp) { - if (! zflag) { + /* + * no matches + */ nometa: - *exparg.lastp = str; - rmescapes(str->text); - exparg.lastp = &str->next; - } + *exparg.lastp = str; + rmescapes(str->text); + exparg.lastp = &str->next; } else { *exparg.lastp = NULL; *savelastp = sp = expsort(*savelastp); @@ -699,114 +1099,14 @@ nometa: } -#if UDIR || TILDE -/* - * UDIR: Expand /u/username into the home directory for the specified user. - * TILDE: Expand ~username into the home directory for the specified user. - * We hope not to use the getpw stuff here, because then we would have to load - * in stdio and who knows what else. With networked password files there is - * no choice alas. - */ - -#define MAXLOGNAME 32 -#define MAXPWLINE 128 - -char *pfgets(); - - -STATIC char * -expudir(path) - char *path; - { - register char *p, *q, *r; - char name[MAXLOGNAME]; - char line[MAXPWLINE]; - int i; -#if USEGETPW - struct passwd *pw; -#endif - - r = path; /* result on failure */ - p = r + (*r == '~' ? 1 : 3); /* the 1 skips "~", 3 skips "/u/" */ - q = name; - while (*p && *p != '/') { - if (q >= name + MAXLOGNAME - 1) - return r; /* fail, name too long */ - *q++ = *p++; - } - *q = '\0'; - -#if TILDE - if (*name == 0 && *r == '~') { - /* null name, use $HOME */ - if ((q = lookupvar("HOME")) == NULL) - return r; /* fail, home not set */ - i = strlen(q); - r = stalloc(i + strlen(p) + 1); - scopy(q, r); - scopy(p, r + i); - TRACE(("expudir converts %s to %s\n", path, r)); - didudir = 1; - path = r; - return r; - } -#endif -#if !USEGETPW /* can do without the bloat */ - setinputfile("/etc/passwd", 1); - q = line + strlen(name); - while (pfgets(line, MAXPWLINE) != NULL) { - if (line[0] == name[0] && prefix(name, line) && *q == ':') { - /* skip to start of home directory */ - i = 4; - do { - while (*++q && *q != ':'); - } while (--i > 0); - if (*q == '\0') - break; /* fail, corrupted /etc/passwd */ - q++; - for (r = q ; *r && *r != '\n' && *r != ':' ; r++); - *r = '\0'; /* nul terminate home directory */ - i = r - q; /* i = strlen(q) */ - r = stalloc(i + strlen(p) + 1); - scopy(q, r); - scopy(p, r + i); - TRACE(("expudir converts %s to %s\n", path, r)); - didudir = 1; - path = r; /* succeed */ - break; - } - } - popfile(); -#else - if ((pw = getpwnam(name)) != NULL) { - /* user exists */ - q = pw->pw_dir; - i = strlen(q); - r = stalloc(i + strlen(p) + 1); - scopy(q, r); - scopy(p, r + i); - TRACE(("expudir converts %s to %s\n", path, r)); - didudir = 1; - path = r; - } - endpwent(); -#endif /* USEGETPW */ - - return r; -} -#endif - - /* * Do metacharacter (i.e. *, ?, [...]) expansion. */ STATIC void -expmeta(enddir, name) - char *enddir; - char *name; - { - register char *p; +expmeta(char *enddir, char *name) +{ + char *p; char *q; char *start; char *endname; @@ -824,9 +1124,11 @@ expmeta(enddir, name) metaflag = 1; else if (*p == '[') { q = p + 1; - if (*q == '!') + if (*q == '!' || *q == '^') q++; for (;;) { + while (*q == CTLQUOTEMARK) + q++; if (*q == CTLESC) q++; if (*q == '/' || *q == '\0') @@ -840,6 +1142,8 @@ expmeta(enddir, name) metaflag = 1; } else if (*p == '\0') break; + else if (*p == CTLQUOTEMARK) + continue; else if (*p == CTLESC) p++; if (*p == '/') { @@ -852,6 +1156,8 @@ expmeta(enddir, name) if (enddir != expdir) metaflag++; for (p = name ; ; p++) { + if (*p == CTLQUOTEMARK) + continue; if (*p == CTLESC) p++; *enddir++ = *p; @@ -866,6 +1172,8 @@ expmeta(enddir, name) if (start != name) { p = name; while (p < start) { + while (*p == CTLQUOTEMARK) + p++; if (*p == CTLESC) p++; *enddir++ = *p++; @@ -890,18 +1198,25 @@ expmeta(enddir, name) *endname++ = '\0'; } matchdot = 0; - if (start[0] == '.' || start[0] == CTLESC && start[1] == '.') + p = start; + while (*p == CTLQUOTEMARK) + p++; + if (*p == CTLESC) + p++; + if (*p == '.') matchdot++; while (! int_pending() && (dp = readdir(dirp)) != NULL) { if (dp->d_name[0] == '.' && ! matchdot) continue; - if (patmatch(start, dp->d_name)) { + if (patmatch(start, dp->d_name, 0)) { if (atend) { scopy(dp->d_name, enddir); addfname(expdir); } else { char *q; - for (p = enddir, q = dp->d_name ; *p++ = *q++ ;); + for (p = enddir, q = dp->d_name; + (*p++ = *q++) != '\0';) + continue; p[-1] = '/'; expmeta(p, endname); } @@ -918,9 +1233,8 @@ expmeta(enddir, name) */ STATIC void -addfname(name) - char *name; - { +addfname(char *name) +{ char *p; struct strlist *sp; @@ -940,9 +1254,8 @@ addfname(name) */ STATIC struct strlist * -expsort(str) - struct strlist *str; - { +expsort(struct strlist *str) +{ int len; struct strlist *sp; @@ -954,17 +1267,16 @@ expsort(str) STATIC struct strlist * -msort(list, len) - struct strlist *list; - { - struct strlist *p, *q; +msort(struct strlist *list, int len) +{ + struct strlist *p, *q = NULL; struct strlist **lpp; int half; int n; if (len <= 1) return list; - half = len >> 1; + half = len >> 1; p = list; for (n = half ; --n >= 0 ; ) { q = p; @@ -1001,24 +1313,22 @@ msort(list, len) */ int -patmatch(pattern, string) - char *pattern; - char *string; - { +patmatch(char *pattern, char *string, int squoted) +{ +#ifdef notdef if (pattern[0] == '!' && pattern[1] == '!') return 1 - pmatch(pattern + 2, string); else - return pmatch(pattern, string); +#endif + return pmatch(pattern, string, squoted); } STATIC int -pmatch(pattern, string) - char *pattern; - char *string; - { - register char *p, *q; - register char c; +pmatch(char *pattern, char *string, int squoted) +{ + char *p, *q; + char c; p = pattern; q = string; @@ -1027,25 +1337,41 @@ pmatch(pattern, string) case '\0': goto breakloop; case CTLESC: + if (squoted && *q == CTLESC) + q++; if (*q++ != *p++) return 0; break; + case CTLQUOTEMARK: + continue; case '?': + if (squoted && *q == CTLESC) + q++; if (*q++ == '\0') return 0; break; case '*': c = *p; - if (c != CTLESC && c != '?' && c != '*' && c != '[') { + while (c == CTLQUOTEMARK || c == '*') + c = *++p; + if (c != CTLESC && c != CTLQUOTEMARK && + c != '?' && c != '*' && c != '[') { while (*q != c) { + if (squoted && *q == CTLESC && + q[1] == c) + break; if (*q == '\0') return 0; + if (squoted && *q == CTLESC) + q++; q++; } } do { - if (pmatch(p, q)) + if (pmatch(p, q, squoted)) return 1; + if (squoted && *q == CTLESC) + q++; } while (*q++ != '\0'); return 0; case '[': { @@ -1054,9 +1380,11 @@ pmatch(pattern, string) char chr; endp = p; - if (*endp == '!') + if (*endp == '!' || *endp == '^') endp++; for (;;) { + while (*endp == CTLQUOTEMARK) + endp++; if (*endp == '\0') goto dft; /* no matching ] */ if (*endp == CTLESC) @@ -1065,21 +1393,31 @@ pmatch(pattern, string) break; } invert = 0; - if (*p == '!') { + if (*p == '!' || *p == '^') { invert++; p++; } found = 0; chr = *q++; + if (squoted && chr == CTLESC) + chr = *q++; + if (chr == '\0') + return 0; c = *p++; do { + if (c == CTLQUOTEMARK) + continue; if (c == CTLESC) c = *p++; if (*p == '-' && p[1] != ']') { p++; + while (*p == CTLQUOTEMARK) + p++; if (*p == CTLESC) p++; - if (chr >= c && chr <= *p) + if ( collate_range_cmp(chr, c) >= 0 + && collate_range_cmp(chr, *p) <= 0 + ) found = 1; p++; } else { @@ -1091,7 +1429,9 @@ pmatch(pattern, string) return 0; break; } -dft: default: +dft: default: + if (squoted && *q == CTLESC) + q++; if (*q++ != c) return 0; break; @@ -1110,18 +1450,21 @@ breakloop: */ void -rmescapes(str) - char *str; - { - register char *p, *q; +rmescapes(char *str) +{ + char *p, *q; p = str; - while (*p != CTLESC) { + while (*p != CTLESC && *p != CTLQUOTEMARK) { if (*p++ == '\0') return; } q = p; while (*p) { + if (*p == CTLQUOTEMARK) { + p++; + continue; + } if (*p == CTLESC) p++; *q++ = *p++; @@ -1136,10 +1479,8 @@ rmescapes(str) */ int -casematch(pattern, val) - union node *pattern; - char *val; - { +casematch(union node *pattern, char *val) +{ struct stackmark smark; int result; char *p; @@ -1148,12 +1489,60 @@ casematch(pattern, val) argbackq = pattern->narg.backquote; STARTSTACKSTR(expdest); ifslastp = NULL; - /* Preserve any CTLESC characters inserted previously, so that - we won't expand reg exps which are inside strings. */ - argstr(pattern->narg.text, 1); + argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); STPUTC('\0', expdest); p = grabstackstr(expdest); - result = patmatch(p, val); + result = patmatch(p, val, 0); popstackmark(&smark); return result; } + +/* + * Our own itoa(). + */ + +STATIC char * +cvtnum(int num, char *buf) +{ + char temp[32]; + int neg = num < 0; + char *p = temp + 31; + + temp[31] = '\0'; + + do { + *--p = num % 10 + '0'; + } while ((num /= 10) != 0); + + if (neg) + *--p = '-'; + + while (*p) + STPUTC(*p++, buf); + return buf; +} + +/* + * Do most of the work for wordexp(3). + */ + +int +wordexpcmd(int argc, char **argv) +{ + size_t len; + int i; + + out1fmt("%08x", argc - 1); + for (i = 1, len = 0; i < argc; i++) + len += strlen(argv[i]); + out1fmt("%08x", (int)len); + for (i = 1; i < argc; i++) { + out1str(argv[i]); + out1c('\0'); + } + return (0); +} + +/* + * $PchId: expand.c,v 1.6 2006/04/10 14:52:06 philip Exp $ + */ diff --git a/commands/ash/expand.h b/commands/ash/expand.h index 65ecf8b09..061d85f04 100755 --- a/commands/ash/expand.h +++ b/commands/ash/expand.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)expand.h 5.1 (Berkeley) 3/7/91 + * @(#)expand.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/expand.h,v 1.12 2004/04/06 20:06:51 markm Exp $ */ struct strlist { @@ -47,17 +44,24 @@ struct arglist { struct strlist **lastp; }; -#ifdef __STDC__ +/* + * expandarg() flags + */ +#define EXP_FULL 0x1 /* perform word splitting & file globbing */ +#define EXP_TILDE 0x2 /* do normal tilde expansion */ +#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ +#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ +#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ + + union node; -void expandarg(union node *, struct arglist *, int); void expandhere(union node *, int); -int patmatch(char *, char *); +void expandarg(union node *, struct arglist *, int); +int patmatch(char *, char *, int); void rmescapes(char *); int casematch(union node *, char *); -#else -void expandarg(); -void expandhere(); -int patmatch(); -void rmescapes(); -int casematch(); -#endif +int wordexpcmd(int, char **); + +/* + * $PchId: expand.h,v 1.4 2006/03/30 14:50:52 philip Exp $ + */ diff --git a/commands/ash/funcs/cmv b/commands/ash/funcs/cmv index 0c6c4d3ba..0e701e5cb 100755 --- a/commands/ash/funcs/cmv +++ b/commands/ash/funcs/cmv @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,7 +28,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)cmv 5.1 (Berkeley) 3/7/91 +# @(#)cmv 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/cmv,v 1.7 2004/04/06 20:06:53 markm Exp $ # Conditional move--don't replace an existing file. @@ -47,3 +44,6 @@ cmv() { fi /bin/mv "$1" "$2" } + +# +# $PchId: cmv,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/dirs b/commands/ash/funcs/dirs index a31d23123..337c70945 100755 --- a/commands/ash/funcs/dirs +++ b/commands/ash/funcs/dirs @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,7 +28,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)dirs 5.1 (Berkeley) 3/7/91 +# @(#)dirs 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/dirs,v 1.7 2004/04/06 20:06:53 markm Exp $ # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris @@ -71,3 +68,6 @@ dirs () { echo "`pwd` $DSTACK" return 0 } + +# +# $PchId: dirs,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/kill b/commands/ash/funcs/kill index 9e643183f..3c858ca20 100755 --- a/commands/ash/funcs/kill +++ b/commands/ash/funcs/kill @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,7 +28,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)kill 5.1 (Berkeley) 3/7/91 +# @(#)kill 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/kill,v 1.7 2004/04/06 20:06:53 markm Exp $ # Convert job names to process ids and then run /bin/kill. @@ -47,3 +44,6 @@ kill() { done /bin/kill $args } + +# +# $PchId: kill,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/login b/commands/ash/funcs/login index 6e24b437c..d4720ed1b 100755 --- a/commands/ash/funcs/login +++ b/commands/ash/funcs/login @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,7 +28,11 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)login 5.1 (Berkeley) 3/7/91 +# @(#)login 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/login,v 1.7 2004/04/06 20:06:53 markm Exp $ # replaces the login builtin in the BSD shell login () exec login "$@" + +# +# $PchId: login,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/newgrp b/commands/ash/funcs/newgrp index 7980ff54d..c2ab4fd18 100755 --- a/commands/ash/funcs/newgrp +++ b/commands/ash/funcs/newgrp @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,6 +28,10 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)newgrp 5.1 (Berkeley) 3/7/91 +# @(#)newgrp 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/newgrp,v 1.7 2004/04/06 20:06:53 markm Exp $ newgrp() exec newgrp "$@" + +# +# $PchId: newgrp,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/popd b/commands/ash/funcs/popd index 4cecba9ee..a2654e573 100755 --- a/commands/ash/funcs/popd +++ b/commands/ash/funcs/popd @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,7 +28,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)popd 5.1 (Berkeley) 3/7/91 +# @(#)popd 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/popd,v 1.7 2004/04/06 20:06:53 markm Exp $ # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris @@ -71,3 +68,6 @@ dirs () { echo "`pwd` $DSTACK" return 0 } + +# +# $PchId: popd,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/pushd b/commands/ash/funcs/pushd index 4e8c48cf6..799bef4ee 100755 --- a/commands/ash/funcs/pushd +++ b/commands/ash/funcs/pushd @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,7 +28,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)pushd 5.1 (Berkeley) 3/7/91 +# @(#)pushd 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/pushd,v 1.7 2004/04/06 20:06:53 markm Exp $ # pushd, popd, and dirs --- written by Chris Bertin # Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris @@ -71,3 +68,6 @@ dirs () { echo "`pwd` $DSTACK" return 0 } + +# +# $PchId: pushd,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/funcs/suspend b/commands/ash/funcs/suspend index 6c4e5795d..3d354e1e4 100755 --- a/commands/ash/funcs/suspend +++ b/commands/ash/funcs/suspend @@ -1,5 +1,5 @@ -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -12,10 +12,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -32,10 +28,14 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)suspend 5.1 (Berkeley) 3/7/91 +# @(#)suspend 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/funcs/suspend,v 1.7 2004/04/06 20:06:53 markm Exp $ suspend() { local - set +j kill -TSTP 0 } + +# +# $PchId: suspend,v 1.2 2006/03/29 10:43:18 philip Exp $ diff --git a/commands/ash/histedit.c b/commands/ash/histedit.c new file mode 100644 index 000000000..1e6ed1a00 --- /dev/null +++ b/commands/ash/histedit.c @@ -0,0 +1,533 @@ +/*- + * Copyright (c) 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[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95"; +#endif +#endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#ifndef NO_PATHS_H +#include +#endif +#include +#include +#include +/* + * Editline and history functions (and glue). + */ +#include "shell.h" +#include "parser.h" +#include "var.h" +#include "options.h" +#include "main.h" +#include "output.h" +#include "mystring.h" +#include "builtins.h" +#if !defined(NO_HISTORY) && !defined(EDITLINE) +#include "myhistedit.h" +#include "complete.h" +#include "error.h" +#include "eval.h" +#include "memalloc.h" + +#define MAXHISTLOOPS 4 /* max recursions through fc */ +#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ + +History *hist; /* history cookie */ +EditLine *el; /* editline cookie */ +int displayhist; +static FILE *el_in, *el_out, *el_err; + +STATIC char *fc_replace(const char *, char *, char *); +STATIC int not_fcnumber(char *); +STATIC int str_to_event(char *, int); + +/* + * Set history and editing status. Called whenever the status may + * have changed (figures out what to do). + */ +void +histedit(void) +{ + +#define editing (Eflag || Vflag) + + if (iflag) { + if (!hist) { + /* + * turn history on + */ + INTOFF; + hist = history_init(); + INTON; + + if (hist != NULL) + sethistsize(histsizeval()); + else + out2str("sh: can't initialize history\n"); + } + if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ + /* + * turn editing on + */ + INTOFF; + if (el_in == NULL) + el_in = fdopen(0, "r"); + if (el_err == NULL) + el_err = fdopen(1, "w"); + if (el_out == NULL) + el_out = fdopen(2, "w"); + if (el_in == NULL || el_err == NULL || el_out == NULL) + goto bad; + el = el_init(arg0, el_in, el_out, el_err); + if (el != NULL) { + if (hist) + el_set(el, EL_HIST, history, hist); + el_set(el, EL_PROMPT, getprompt); + } else { +bad: + out2str("sh: can't initialize editing\n"); + } + INTON; + } else if (!editing && el) { + INTOFF; + el_end(el); + el = NULL; + INTON; + } + if (el) { + if (Vflag) + el_set(el, EL_EDITOR, "vi"); + else if (Eflag) + el_set(el, EL_EDITOR, "emacs"); + el_set(el, EL_ADDFN, "ed-do-complete", + "Complete Argument", complete); + el_set(el, EL_ADDFN, "ed-list-complete", + "List Argument Completions", complete_list); + el_set(el, EL_ADDFN, "ed-maybe-complete", + "Complete Argument Or List Completions", + complete_or_list); + el_set(el, EL_ADDFN, "ed-expand", + "Expand Completions", complete_expand); + el_set(el, EL_BIND, "^I", "ed-maybe-complete", NULL); + el_set(el, EL_BIND, "-a", "=", "ed-list-complete", + NULL); + el_set(el, EL_BIND, "-a", "\\\\", "ed-do-complete", + NULL); + el_set(el, EL_BIND, "-a", "*", "ed-expand", + NULL); + el_source(el, NULL); + } + } else { + INTOFF; + if (el) { /* no editing if not interactive */ + el_end(el); + el = NULL; + } + if (hist) { + history_end(hist); + hist = NULL; + } + INTON; + } +} + + +void +sethistsize(hs) + const char *hs; +{ + int histsize; + HistEvent he; + + if (hist != NULL) { + if (hs == NULL || *hs == '\0' || + (histsize = atoi(hs)) < 0) + histsize = 100; + history(hist, &he, H_EVENT, histsize); + } +} + +int +histcmd(int argc, char **argv) +{ + int ch; + char *editor = NULL; + HistEvent he; + int lflg = 0, nflg = 0, rflg = 0, sflg = 0; + int i, retval; + char *firststr, *laststr; + int first, last, direction; + char *pat = NULL, *repl; + static int active = 0; + struct jmploc jmploc; + struct jmploc *volatile savehandler; + char editfile[PATH_MAX]; + FILE *efp; + int oldhistnum; +#ifdef __GNUC__ + /* Avoid longjmp clobbering */ + (void) &editor; + (void) &lflg; + (void) &nflg; + (void) &rflg; + (void) &sflg; + (void) &firststr; + (void) &laststr; + (void) &pat; + (void) &repl; + (void) &efp; + (void) &argc; + (void) &argv; +#endif + + if (hist == NULL) + error("history not active"); + + if (argc == 1) + error("missing history argument"); + + optreset = 1; optind = 1; /* initialize getopt */ + opterr = 0; + while (not_fcnumber(argv[optind]) && + (ch = getopt(argc, argv, ":e:lnrs")) != -1) + switch ((char)ch) { + case 'e': + editor = optarg; + break; + case 'l': + lflg = 1; + break; + case 'n': + nflg = 1; + break; + case 'r': + rflg = 1; + break; + case 's': + sflg = 1; + break; + case ':': + error("option -%c expects argument", optopt); + case '?': + default: + error("unknown option: -%c", optopt); + } + argc -= optind, argv += optind; + + /* + * If executing... + */ + if (lflg == 0 || editor || sflg) { + lflg = 0; /* ignore */ + editfile[0] = '\0'; + /* + * Catch interrupts to reset active counter and + * cleanup temp files. + */ + if (setjmp(jmploc.loc)) { + active = 0; + if (*editfile) + unlink(editfile); + handler = savehandler; + longjmp(handler->loc, 1); + } + savehandler = handler; + handler = &jmploc; + if (++active > MAXHISTLOOPS) { + active = 0; + displayhist = 0; + error("called recursively too many times"); + } + /* + * Set editor. + */ + if (sflg == 0) { + if (editor == NULL && + (editor = bltinlookup("FCEDIT", 1)) == NULL && + (editor = bltinlookup("EDITOR", 1)) == NULL) + editor = DEFEDITOR; + if (editor[0] == '-' && editor[1] == '\0') { + sflg = 1; /* no edit */ + editor = NULL; + } + } + } + + /* + * If executing, parse [old=new] now + */ + if (lflg == 0 && argc > 0 && + ((repl = strchr(argv[0], '=')) != NULL)) { + pat = argv[0]; + *repl++ = '\0'; + argc--, argv++; + } + /* + * determine [first] and [last] + */ + switch (argc) { + case 0: + firststr = lflg ? "-16" : "-1"; + laststr = "-1"; + break; + case 1: + firststr = argv[0]; + laststr = lflg ? "-1" : argv[0]; + break; + case 2: + firststr = argv[0]; + laststr = argv[1]; + break; + default: + error("too many args"); + } + /* + * Turn into event numbers. + */ + first = str_to_event(firststr, 0); + last = str_to_event(laststr, 1); + + if (rflg) { + i = last; + last = first; + first = i; + } + /* + * XXX - this should not depend on the event numbers + * always increasing. Add sequence numbers or offset + * to the history element in next (diskbased) release. + */ + direction = first < last ? H_PREV : H_NEXT; + + /* + * If editing, grab a temp file. + */ + if (editor) { + int fd; + INTOFF; /* easier */ + sprintf(editfile, "%s/_shXXXXXX", _PATH_TMP); + if ((fd = mkstemp(editfile)) < 0) + error("can't create temporary file %s", editfile); + if ((efp = fdopen(fd, "w")) == NULL) { + close(fd); + error("can't allocate stdio buffer for temp"); + } + } + + /* + * Loop through selected history events. If listing or executing, + * do it now. Otherwise, put into temp file and call the editor + * after. + * + * The history interface needs rethinking, as the following + * convolutions will demonstrate. + */ + history(hist, &he, H_FIRST); + retval = history(hist, &he, H_NEXT_EVENT, first); + for (;retval != -1; retval = history(hist, &he, direction)) { + if (lflg) { + if (!nflg) + out1fmt("%5d ", he.num); + out1str(he.str); + } else { + char *s = pat ? + fc_replace(he.str, pat, repl) : (char *)he.str; + + if (sflg) { + if (displayhist) { + out2str(s); + } + evalstring(s); + if (displayhist && hist) { + /* + * XXX what about recursive and + * relative histnums. + */ + oldhistnum = he.num; + history(hist, &he, H_ENTER, s); + /* + * XXX H_ENTER moves the internal + * cursor, set it back to the current + * entry. + */ + retval = history(hist, &he, + H_NEXT_EVENT, oldhistnum); + } + } else + fputs(s, efp); + } + /* + * At end? (if we were to loose last, we'd sure be + * messed up). + */ + if (he.num == last) + break; + } + if (editor) { + char *editcmd; + + fclose(efp); + editcmd = stalloc(strlen(editor) + strlen(editfile) + 2); + sprintf(editcmd, "%s %s", editor, editfile); + evalstring(editcmd); /* XXX - should use no JC command */ + INTON; + readcmdfile(editfile); /* XXX - should read back - quick tst */ + unlink(editfile); + } + + if (lflg == 0 && active > 0) + --active; + if (displayhist) + displayhist = 0; + return 0; +} + +STATIC char * +fc_replace(const char *s, char *p, char *r) +{ + char *dest; + int plen = strlen(p); + + STARTSTACKSTR(dest); + while (*s) { + if (*s == *p && strncmp(s, p, plen) == 0) { + while (*r) + STPUTC(*r++, dest); + s += plen; + *p = '\0'; /* so no more matches */ + } else + STPUTC(*s++, dest); + } + STACKSTRNUL(dest); + dest = grabstackstr(dest); + + return (dest); +} + +STATIC int +not_fcnumber(char *s) +{ + if (s == NULL) + return (0); + if (*s == '-') + s++; + return (!is_number(s)); +} + +STATIC int +str_to_event(char *str, int last) +{ + HistEvent he; + char *s = str; + int relative = 0; + int i, retval; + + retval = history(hist, &he, H_FIRST); + switch (*s) { + case '-': + relative = 1; + /*FALLTHROUGH*/ + case '+': + s++; + } + if (is_number(s)) { + i = atoi(s); + if (relative) { + while (retval != -1 && i--) { + retval = history(hist, &he, H_NEXT); + } + if (retval == -1) + retval = history(hist, &he, H_LAST); + } else { + retval = history(hist, &he, H_NEXT_EVENT, i); + if (retval == -1) { + /* + * the notion of first and last is + * backwards to that of the history package + */ + retval = history(hist, &he, last ? H_FIRST : H_LAST); + } + } + if (retval == -1) + error("history number %s not found (internal error)", + str); + } else { + /* + * pattern + */ + retval = history(hist, &he, H_PREV_STR, str); + if (retval == -1) + error("history pattern not found: %s", str); + } + return (he.num); +} + +int +bindcmd(int argc, char **argv) +{ + + if (el == NULL) + error("line editing is disabled"); + return (el_parse(el, argc, argv)); +} + +#else +#include "error.h" + +int +histcmd(int argc, char **argv) +{ + + error("not compiled with history support"); + /*NOTREACHED*/ + return (0); +} + +int +bindcmd(int argc, char **argv) +{ + + error("not compiled with line editing support"); + return (0); +} +#endif /* !NO_HISTORY && !EDITLINE */ + +/* + * $PchId: histedit.c,v 1.6 2006/04/10 14:52:58 philip Exp $ + */ diff --git a/commands/ash/init.h b/commands/ash/init.h index 51efdb4b4..0cfb9c4ca 100755 --- a/commands/ash/init.h +++ b/commands/ash/init.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,15 +29,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)init.h 5.1 (Berkeley) 3/7/91 + * @(#)init.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/init.h,v 1.8 2004/04/06 20:06:51 markm Exp $ */ -#ifdef __STDC__ void init(void); void reset(void); void initshellproc(void); -#else -void init(); -void reset(); -void initshellproc(); -#endif + +/* + * $PchId: init.h,v 1.3 2006/03/30 14:31:06 philip Exp $ + */ diff --git a/commands/ash/input.c b/commands/ash/input.c index 1ed7e0174..c44b4a87c 100755 --- a/commands/ash/input.c +++ b/commands/ash/input.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,26 +31,61 @@ */ #ifndef lint -static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 7/1/91"; +#if 0 +static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include /* defines BUFSIZ */ +#include +#include +#include +#include +#include /* * This file implements the input routines used by the parser. */ -#include -#include /* defines BUFSIZ */ #include "shell.h" -#include -#include +#include "redir.h" #include "syntax.h" #include "input.h" #include "output.h" +#include "options.h" #include "memalloc.h" #include "error.h" +#include "alias.h" +#include "parser.h" +#ifdef EDITLINE +#ifdef __minix_vmd +#include +#else +/* What about other systems? */ +#endif +#else +#include "myhistedit.h" +#endif +#include "redir.h" +#include "trap.h" + +static void popstring(void); #define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ +MKINIT +struct strpush { + struct strpush *prev; /* preceding string on stack */ + char *prevstring; + int prevnleft; + int prevlleft; + struct alias *ap; /* if push was associated with an alias */ +}; /* * The parsefile structure pointed to by the global variable parsefile @@ -63,36 +94,34 @@ static char sccsid[] = "@(#)input.c 5.4 (Berkeley) 7/1/91"; MKINIT struct parsefile { + struct parsefile *prev; /* preceding file on stack */ int linno; /* current line */ int fd; /* file descriptor (or -1 if string) */ - int nleft; /* number of chars left in buffer */ + int nleft; /* number of chars left in this line */ + int lleft; /* number of lines left in this buffer */ char *nextc; /* next char in buffer */ - struct parsefile *prev; /* preceding file on stack */ char *buf; /* input buffer */ + struct strpush *strpush; /* for pushing strings at this level */ + struct strpush basestrpush; /* so pushing one is fast */ }; int plinno = 1; /* input line number */ MKINIT int parsenleft; /* copy of parsefile->nleft */ +MKINIT int parselleft; /* copy of parsefile->lleft */ char *parsenextc; /* copy of parsefile->nextc */ MKINIT struct parsefile basepf; /* top level input file */ char basebuf[BUFSIZ]; /* buffer for top level input file */ -struct parsefile *parsefile = &basepf; /* current input file */ -char *pushedstring; /* copy of parsenextc when text pushed back */ -int pushednleft; /* copy of parsenleft when text pushed back */ +STATIC struct parsefile *parsefile = &basepf; /* current input file */ +int init_editline = 0; /* editline library initialized? */ +int whichprompt; /* -1 == PSE, 1 == PS1, 2 == PS2 */ -#if READLINE -char *readline __P((const char *prompt)); -char *r_use_prompt = NULL; /* the prompt to use with readline */ +#ifndef EDITLINE +EditLine *el; /* cookie for editline package */ #endif -#ifdef __STDC__ STATIC void pushfile(void); -#else -STATIC void pushfile(); -#endif - - +static int preadfd(void); #ifdef mkinit INCLUDE "input.h" @@ -106,7 +135,7 @@ INIT { RESET { if (exception != EXSHELLPROC) - parsenleft = 0; /* clear input buffer */ + parselleft = parsenleft = 0; /* clear input buffer */ popallfiles(); } @@ -121,10 +150,9 @@ SHELLPROC { */ char * -pfgets(line, len) - char *line; - { - register char *p = line; +pfgets(char *line, int len) +{ + char *p = line; int nleft = len; int c; @@ -151,64 +179,74 @@ pfgets(line, len) */ int -pgetc() { +pgetc(void) +{ return pgetc_macro(); } -/* - * Refill the input buffer and return the next input character: - * - * 1) If a string was pushed back on the input, switch back to the regular - * buffer. - * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading - * from a string so we can't refill the buffer, return EOF. - * 3) Call read to read in the characters. - * 4) Delete all nul characters from the buffer. - */ +static int +preadfd(void) +{ + int nr; + parsenextc = parsefile->buf; -int -preadbuffer() { - register char *p, *q; - register int i; - - if (pushedstring) { - parsenextc = pushedstring; - pushedstring = NULL; - parsenleft = pushednleft; - if (--parsenleft >= 0) - return *parsenextc++; +#if !defined(NO_HISTORY) && !defined(EDITLINE) + if (el != NULL && gotwinch) { + gotwinch = 0; + el_resize(el); } - if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) - return PEOF; - flushout(&output); - flushout(&errout); -#if READLINE - /* Use the readline() call if a prompt is to be printed (interactive). */ - if (r_use_prompt != NULL) { - char *prompt; - char *line; - - p = parsenextc = parsefile->buf; - - prompt = r_use_prompt; - r_use_prompt = NULL; - - if ((line = readline(prompt)) == NULL) { - parsenleft = EOF_NLEFT; - return PEOF; - } - strcpy(p, line); - free(line); - i = strlen(p); - p[i++] = '\n'; - } else { #endif retry: - p = parsenextc = parsefile->buf; - i = read(parsefile->fd, p, BUFSIZ); - if (i <= 0) { - if (i < 0) { +#ifndef NO_HISTORY +#ifdef EDITLINE + if (parsefile->fd == 0) { + static const char *rl_cp= NULL; + static size_t rl_off= 0; + + if (!rl_cp) + { + rl_cp = readline(getprompt(NULL)); + if (rl_cp == NULL) + nr = 0; + } + if (rl_cp) + { + nr= strlen(rl_cp+rl_off); + if (nr >= BUFSIZ-1) + { + nr= BUFSIZ-1; + (void) memcpy(parsenextc, rl_cp+rl_off, nr); + rl_off += nr; + } + else + { + (void) memcpy(parsenextc, rl_cp+rl_off, nr); + parsenextc[nr++]= '\n'; + free(rl_cp); + rl_cp= NULL; + rl_off= 0; + } + } + } else +#else /* !EDITLINE */ + if (parsefile->fd == 0 && el) { + const char *rl_cp; + + rl_cp = el_gets(el, &nr); + if (rl_cp == NULL) + nr = 0; + else { + /* XXX - BUFSIZE should redesign so not necessary */ + (void) strcpy(parsenextc, rl_cp); + } + } else +#endif /* !EDITLINE */ +#endif + nr = read(parsefile->fd, parsenextc, BUFSIZ - 1); + + if (nr <= 0) { + if (nr < 0) { if (errno == EINTR) goto retry; #ifdef EWOULDBLOCK @@ -222,35 +260,106 @@ retry: } } } -#endif +#endif /* EWOULDBLOCK */ } - parsenleft = EOF_NLEFT; - return PEOF; + nr = -1; } -#if READLINE - } -#endif - parsenleft = i - 1; - - /* delete nul characters */ - for (;;) { - if (*p++ == '\0') - break; - if (--i <= 0) - return *parsenextc++; /* no nul characters */ - } - q = p - 1; - while (--i > 0) { - if (*p != '\0') - *q++ = *p; - p++; - } - if (q == parsefile->buf) - goto retry; /* buffer contained nothing but nuls */ - parsenleft = q - parsefile->buf - 1; - return *parsenextc++; + return nr; } +/* + * Refill the input buffer and return the next input character: + * + * 1) If a string was pushed back on the input, pop it; + * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading + * from a string so we can't refill the buffer, return EOF. + * 3) If there is more in this buffer, use it else call read to fill it. + * 4) Process input up to the next newline, deleting nul characters. + */ + +int +preadbuffer(void) +{ + char *p, *q; + int more; + int something; + char savec; + + if (parsefile->strpush) { + popstring(); + if (--parsenleft >= 0) + return (*parsenextc++); + } + if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) + return PEOF; + flushout(&output); + flushout(&errout); + +again: + if (parselleft <= 0) { + if ((parselleft = preadfd()) == -1) { + parselleft = parsenleft = EOF_NLEFT; + return PEOF; + } + } + + q = p = parsenextc; + + /* delete nul characters */ + something = 0; + for (more = 1; more;) { + switch (*p) { + case '\0': + p++; /* Skip nul */ + goto check; + + case '\t': + case ' ': + break; + + case '\n': + parsenleft = q - parsenextc; + more = 0; /* Stop processing here */ + break; + + default: + something = 1; + break; + } + + *q++ = *p++; +check: + if (--parselleft <= 0) { + parsenleft = q - parsenextc - 1; + if (parsenleft < 0) + goto again; + *q = '\0'; + more = 0; + } + } + + savec = *q; + *q = '\0'; + +#if !defined(NO_HISTORY) && !defined(EDITLINE) + if (parsefile->fd == 0 && hist && something) { + HistEvent he; + INTOFF; + history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD, + parsenextc); + INTON; + } +#endif + + if (vflag) { + out2str(parsenextc); + flushout(out2); + } + + *q = savec; + + return *parsenextc++; +} /* * Undo the last call to pgetc. Only one character may be pushed back. @@ -258,28 +367,57 @@ retry: */ void -pungetc() { +pungetc(void) +{ parsenleft++; parsenextc--; } - /* - * Push a string back onto the input. This code doesn't work if the user - * tries to push back more than one string at once. + * Push a string back onto the input at this current parsefile level. + * We handle aliases this way. */ - void -ppushback(string, length) - char *string; - { - pushedstring = parsenextc; - pushednleft = parsenleft; - parsenextc = string; - parsenleft = length; +pushstring(char *s, int len, void *ap) +{ + struct strpush *sp; + + INTOFF; +/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ + if (parsefile->strpush) { + sp = ckmalloc(sizeof (struct strpush)); + sp->prev = parsefile->strpush; + parsefile->strpush = sp; + } else + sp = parsefile->strpush = &(parsefile->basestrpush); + sp->prevstring = parsenextc; + sp->prevnleft = parsenleft; + sp->prevlleft = parselleft; + sp->ap = (struct alias *)ap; + if (ap) + ((struct alias *)ap)->flag |= ALIASINUSE; + parsenextc = s; + parsenleft = len; + INTON; } +static void +popstring(void) +{ + struct strpush *sp = parsefile->strpush; + INTOFF; + parsenextc = sp->prevstring; + parsenleft = sp->prevnleft; + parselleft = sp->prevlleft; +/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ + if (sp->ap) + sp->ap->flag &= ~ALIASINUSE; + parsefile->strpush = sp->prev; + if (sp != &(parsefile->basestrpush)) + ckfree(sp); + INTON; +} /* * Set the input to take input from a file. If push is set, push the @@ -287,17 +425,16 @@ ppushback(string, length) */ void -setinputfile(fname, push) - char *fname; - { +setinputfile(char *fname, int push) +{ int fd; int fd2; INTOFF; if ((fd = open(fname, O_RDONLY)) < 0) - error("Can't open %s", fname); + error("Can't open %s: %s", fname, strerror(errno)); if (fd < 10) { - fd2 = copyfd(fd, 10); + fd2 = fcntl(fd, F_DUPFD, 10); close(fd); if (fd2 < 0) error("Out of file descriptors"); @@ -314,8 +451,9 @@ setinputfile(fname, push) */ void -setinputfd(fd, push) { - (void) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); +setinputfd(int fd, int push) +{ + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); if (push) { pushfile(); parsefile->buf = ckmalloc(BUFSIZ); @@ -325,7 +463,7 @@ setinputfd(fd, push) { parsefile->fd = fd; if (parsefile->buf == NULL) parsefile->buf = ckmalloc(BUFSIZ); - parsenleft = 0; + parselleft = parsenleft = 0; plinno = 1; } @@ -335,14 +473,13 @@ setinputfd(fd, push) { */ void -setinputstring(string, push) - char *string; - { +setinputstring(char *string, int push) +{ INTOFF; if (push) pushfile(); parsenextc = string; - parsenleft = strlen(string); + parselleft = parsenleft = strlen(string); parsefile->buf = NULL; plinno = 1; INTON; @@ -356,21 +493,26 @@ setinputstring(string, push) */ STATIC void -pushfile() { +pushfile(void) +{ struct parsefile *pf; parsefile->nleft = parsenleft; + parsefile->lleft = parselleft; parsefile->nextc = parsenextc; parsefile->linno = plinno; pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); pf->prev = parsefile; pf->fd = -1; + pf->strpush = NULL; + pf->basestrpush.prev = NULL; parsefile = pf; } void -popfile() { +popfile(void) +{ struct parsefile *pf = parsefile; INTOFF; @@ -378,9 +520,12 @@ popfile() { close(pf->fd); if (pf->buf) ckfree(pf->buf); + while (pf->strpush) + popstring(); parsefile = pf->prev; ckfree(pf); parsenleft = parsefile->nleft; + parselleft = parsefile->lleft; parsenextc = parsefile->nextc; plinno = parsefile->linno; INTON; @@ -392,7 +537,8 @@ popfile() { */ void -popallfiles() { +popallfiles(void) +{ while (parsefile != &basepf) popfile(); } @@ -405,10 +551,15 @@ popallfiles() { */ void -closescript() { +closescript(void) +{ popallfiles(); if (parsefile->fd > 0) { close(parsefile->fd); parsefile->fd = 0; } } + +/* + * $PchId: input.c,v 1.6 2006/05/23 12:00:32 philip Exp $ + */ diff --git a/commands/ash/input.h b/commands/ash/input.h index 656bb2930..97267b513 100755 --- a/commands/ash/input.h +++ b/commands/ash/input.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)input.h 5.1 (Berkeley) 3/7/91 + * @(#)input.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/input.h,v 1.9 2004/04/06 20:06:51 markm Exp $ */ /* PEOF (the end of file marker) is defined in syntax.h */ @@ -46,39 +43,22 @@ extern int plinno; extern int parsenleft; /* number of characters left in input buffer */ extern char *parsenextc; /* next character in input buffer */ +extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */ - -#ifdef __STDC__ char *pfgets(char *, int); int pgetc(void); int preadbuffer(void); void pungetc(void); -void ppushback(char *, int); +void pushstring(char *, int, void *); void setinputfile(char *, int); void setinputfd(int, int); void setinputstring(char *, int); void popfile(void); void popallfiles(void); void closescript(void); -#else -char *pfgets(); -int pgetc(); -int preadbuffer(); -void pungetc(); -void ppushback(); -void setinputfile(); -void setinputfd(); -void setinputstring(); -void popfile(); -void popallfiles(); -void closescript(); -#endif #define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) -#if READLINE -/* The variable "r_use_prompt" indicates the prompt to use with readline, - * *and* that readline may only be used if non-NULL. +/* + * $PchId: input.h,v 1.3 2006/03/30 13:49:37 philip Exp $ */ -extern char *r_use_prompt; -#endif diff --git a/commands/ash/jobs.c b/commands/ash/jobs.c index ae9c5038c..792ffe7e4 100755 --- a/commands/ash/jobs.c +++ b/commands/ash/jobs.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,117 +31,173 @@ */ #ifndef lint -static char sccsid[] = "@(#)jobs.c 5.1 (Berkeley) 3/7/91"; +#if 0 +static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/jobs.c,v 1.67 2004/04/06 20:06:51 markm Exp $"); +*/ #include "shell.h" + +#include +#include +#include +#include +#ifndef NO_PATHS_H +#include +#endif +#include +#include +#ifdef POSIX +#include +#include +#elif defined(BSD) +#include +#include +#include +#include +#endif +#include + #if JOBS -#include "sgtty.h" +#include #undef CEOF /* syntax.h redefines this */ #endif +#include "redir.h" +#include "show.h" #include "main.h" #include "parser.h" #include "nodes.h" #include "jobs.h" #include "options.h" #include "trap.h" -#include "signames.h" #include "syntax.h" #include "input.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "mystring.h" -#include "redir.h" -#include -#include -#include -#include -#ifdef BSD -#include -#include -#include -#include -#endif -#if POSIX -#include +#include "builtins.h" + +#ifdef __minix +/* #define NO_KILLPG */ #endif +#ifndef _PATH_TTY +#define _PATH_TTY "/dev/tty" +#endif +#ifndef _PATH_DEVNULL +#define _PATH_DEVNULL "/dev/null" +#endif - -struct job *jobtab; /* array of jobs */ -int njobs; /* size of array */ +STATIC struct job *jobtab; /* array of jobs */ +STATIC int njobs; /* size of array */ MKINIT pid_t backgndpid = -1; /* pid of last background process */ #if JOBS -int initialpgrp; /* pgrp of shell on invocation */ -pid_t curjob; /* current job */ +STATIC struct job *jobmru; /* most recently used job list */ +STATIC pid_t initialpgrp; /* pgrp of shell on invocation */ +#endif +int in_waitcmd = 0; /* are we in waitcmd()? */ +int in_dowait = 0; /* are we in dowait()? */ +volatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */ +static int ttyfd = -1; + +#ifndef WCOREDUMP +#define WCOREDUMP(s) ((s) & 0x80) #endif -#ifdef __STDC__ -STATIC void restartjob(struct job *); -STATIC struct job *getjob(char *); -STATIC void freejob(struct job *); -STATIC int procrunning(int); -STATIC int dowait(int, struct job *); -STATIC int waitproc(int, int *); -STATIC char *commandtext(union node *); -#else -STATIC void restartjob(); -STATIC struct job *getjob(); -STATIC void freejob(); -STATIC int procrunning(); -STATIC int dowait(); -STATIC int waitproc(); -STATIC char *commandtext(); -#endif - - - #if JOBS +STATIC void restartjob(struct job *); +#endif +STATIC void freejob(struct job *); +STATIC struct job *getjob(char *); +STATIC pid_t dowait(int, struct job *); +STATIC pid_t waitproc(int, int *); +STATIC void cmdtxt(union node *); +STATIC void cmdputs(char *); +#if JOBS +STATIC void setcurjob(struct job *); +STATIC void deljob(struct job *); +STATIC struct job *getcurjob(struct job *); +#endif +STATIC void showjob(struct job *, pid_t, int, int); + +#ifdef NO_KILLPG +static int killpg(pid_t,int); +#endif + /* * Turn job control on and off. - * - * Note: This code assumes that the third arg to ioctl is a character - * pointer, which is true on Berkeley systems but not System V. Since - * System V doesn't have job control yet, this isn't a problem now. */ MKINIT int jobctl; +#if JOBS void -setjobctl(on) { - int ldisc; +setjobctl(int on) +{ + int i; if (on == jobctl || rootshell == 0) return; if (on) { + if (ttyfd != -1) + close(ttyfd); + if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) { + i = 0; + while (i <= 2 && !isatty(i)) + i++; + if (i > 2 || (ttyfd = fcntl(i, F_DUPFD, 10)) < 0) + goto out; + } + if (ttyfd < 10) { + /* + * Keep our TTY file descriptor out of the way of + * the user's redirections. + */ + if ((i = fcntl(ttyfd, F_DUPFD, 10)) < 0) { + close(ttyfd); + ttyfd = -1; + goto out; + } + close(ttyfd); + ttyfd = i; + } + if (fcntl(ttyfd, F_SETFD, FD_CLOEXEC) < 0) { + close(ttyfd); + ttyfd = -1; + goto out; + } do { /* while we are in the background */ - if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { - out2str("ash: can't access tty; job control turned off\n"); - jflag = 0; + initialpgrp = tcgetpgrp(ttyfd); + if (initialpgrp < 0) { +out: out2str("sh: can't access tty; job control turned off\n"); + mflag = 0; return; } if (initialpgrp == -1) - initialpgrp = getpgrp(0); - else if (initialpgrp != getpgrp(0)) { - killpg(initialpgrp, SIGTTIN); + initialpgrp = getpgrp(); + else if (initialpgrp != getpgrp()) { + killpg(0, SIGTTIN); continue; } } while (0); - if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { - out2str("ash: need new tty driver to run job control; job control turned off\n"); - jflag = 0; - return; - } setsignal(SIGTSTP); setsignal(SIGTTOU); - setpgrp(0, rootpid); - ioctl(2, TIOCSPGRP, (char *)&rootpid); + setsignal(SIGTTIN); + setpgid(0, rootpid); + tcsetpgrp(ttyfd, rootpid); } else { /* turning job control off */ - setpgrp(0, initialpgrp); - ioctl(2, TIOCSPGRP, (char *)&initialpgrp); + setpgid(0, initialpgrp); + tcsetpgrp(ttyfd, initialpgrp); + close(ttyfd); + ttyfd = -1; setsignal(SIGTSTP); setsignal(SIGTTOU); + setsignal(SIGTTIN); } jobctl = on; } @@ -153,6 +205,8 @@ setjobctl(on) { #ifdef mkinit +INCLUDE +INCLUDE SHELLPROC { backgndpid = -1; @@ -166,50 +220,66 @@ SHELLPROC { #if JOBS -fgcmd(argc, argv) char **argv; { +int +fgcmd(int argc __unused, char **argv) +{ struct job *jp; - int pgrp; + pid_t pgrp; int status; jp = getjob(argv[1]); if (jp->jobctl == 0) error("job not created under job control"); + out1str(jp->ps[0].cmd); + out1c('\n'); + flushout(&output); pgrp = jp->ps[0].pid; - ioctl(2, TIOCSPGRP, (char *)&pgrp); + tcsetpgrp(ttyfd, pgrp); restartjob(jp); + jp->foreground = 1; INTOFF; - status = waitforjob(jp); + status = waitforjob(jp, (int *)NULL); INTON; return status; } -bgcmd(argc, argv) char **argv; { +int +bgcmd(int argc, char **argv) +{ + char s[64]; struct job *jp; do { jp = getjob(*++argv); if (jp->jobctl == 0) error("job not created under job control"); + if (jp->state == JOBDONE) + continue; restartjob(jp); + jp->foreground = 0; + fmtstr(s, 64, "[%td] ", jp - jobtab + 1); + out1str(s); + out1str(jp->ps[0].cmd); + out1c('\n'); } while (--argc > 1); return 0; } STATIC void -restartjob(jp) - struct job *jp; - { +restartjob(struct job *jp) +{ struct procstat *ps; int i; if (jp->state == JOBDONE) return; + setcurjob(jp); INTOFF; killpg(jp->ps[0].pid, SIGCONT); for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { - if ((ps->status & 0377) == 0177) { + if (WIFSTOPPED(ps->status)) { ps->status = -1; jp->state = 0; } @@ -220,11 +290,121 @@ restartjob(jp) int -jobscmd(argc, argv) char **argv; { - showjobs(0); - return 0; +jobscmd(int argc, char *argv[]) +{ + char *id; + int ch, sformat, lformat; + + optind = optreset = 1; + opterr = 0; + sformat = lformat = 0; + while ((ch = getopt(argc, argv, "ls")) != -1) { + switch (ch) { + case 'l': + lformat = 1; + break; + case 's': + sformat = 1; + break; + case '?': + default: + error("unknown option: -%c", optopt); + } + } + argc -= optind; + argv += optind; + + if (argc == 0) + showjobs(0, sformat, lformat); + else + while ((id = *argv++) != NULL) + showjob(getjob(id), 0, sformat, lformat); + + return (0); } +STATIC void +showjob(struct job *jp, pid_t pid, int sformat, int lformat) +{ + char s[64]; + struct procstat *ps; + struct job *j; + int col, curr, i, jobno, prev, procno; + char c; + + procno = jp->nprocs; + jobno = jp - jobtab + 1; + curr = prev = 0; +#if JOBS + if ((j = getcurjob(NULL)) != NULL) { + curr = j - jobtab + 1; + if ((j = getcurjob(j)) != NULL) + prev = j - jobtab + 1; + } +#endif + for (ps = jp->ps ; ; ps++) { /* for each process */ + if (sformat) { + out1fmt("%d\n", (int)ps->pid); + goto skip; + } + if (!lformat && ps != jp->ps && pid == 0) + goto skip; + if (pid != 0 && pid != ps->pid) + goto skip; + if (jobno == curr && ps == jp->ps) + c = '+'; + else if (jobno == prev && ps == jp->ps) + c = '-'; + else + c = ' '; + if (ps == jp->ps) + fmtstr(s, 64, "[%d] %c ", jobno, c); + else + fmtstr(s, 64, " %c ", c); + out1str(s); + col = strlen(s); + if (lformat) { + fmtstr(s, 64, "%d ", (int)ps->pid); + out1str(s); + col += strlen(s); + } + s[0] = '\0'; + if (ps != jp->ps) { + *s = '\0'; + } else if (ps->status == -1) { + strcpy(s, "Running"); + } else if (WIFEXITED(ps->status)) { + if (WEXITSTATUS(ps->status) == 0) + strcpy(s, "Done"); + else + fmtstr(s, 64, "Done (%d)", + WEXITSTATUS(ps->status)); + } else { +#if JOBS + if (WIFSTOPPED(ps->status)) + i = WSTOPSIG(ps->status); + else +#endif + i = WTERMSIG(ps->status); + if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F)) + scopy(strsiglist(i & 0x7F), s); + else + fmtstr(s, 64, "Signal %d", i & 0x7F); + if (WCOREDUMP(ps->status)) + strcat(s, " (core dumped)"); + } + out1str(s); + col += strlen(s); + do { + out1c(' '); + col++; + } while (col < 30); + out1str(ps->cmd); + out1c('\n'); +skip: if (--procno <= 0) + break; + } +} /* * Print a list of jobs. If "change" is nonzero, only print jobs whose @@ -236,14 +416,10 @@ jobscmd(argc, argv) char **argv; { */ void -showjobs(change) { +showjobs(int change, int sformat, int lformat) +{ int jobno; - int procno; - int i; struct job *jp; - struct procstat *ps; - int col; - char s[64]; TRACE(("showjobs(%d) called\n", change)); while (dowait(0, (struct job *)NULL) > 0); @@ -256,43 +432,7 @@ showjobs(change) { } if (change && ! jp->changed) continue; - procno = jp->nprocs; - for (ps = jp->ps ; ; ps++) { /* for each process */ - if (ps == jp->ps) - fmtstr(s, 64, "[%d] %d ", jobno, ps->pid); - else - fmtstr(s, 64, " %d ", ps->pid); - out1str(s); - col = strlen(s); - s[0] = '\0'; - if (ps->status == -1) { - /* don't print anything */ - } else if ((ps->status & 0xFF) == 0) { - fmtstr(s, 64, "Exit %d", ps->status >> 8); - } else { - i = ps->status; -#if JOBS - if ((i & 0xFF) == 0177) - i >>= 8; -#endif - if ((i & 0x7F) <= MAXSIG && sigmesg[i & 0x7F]) - scopy(sigmesg[i & 0x7F], s); - else - fmtstr(s, 64, "Signal %d", i & 0x7F); - if (i & 0x80) - strcat(s, " (core dumped)"); - } - out1str(s); - col += strlen(s); - do { - out1c(' '); - col++; - } while (col < 30); - out1str(ps->cmd); - out1c('\n'); - if (--procno <= 0) - break; - } + showjob(jp, 0, sformat, lformat); jp->changed = 0; if (jp->state == JOBDONE) { freejob(jp); @@ -306,9 +446,8 @@ showjobs(change) { */ STATIC void -freejob(jp) - struct job *jp; - { +freejob(struct job *jp) +{ struct procstat *ps; int i; @@ -321,8 +460,7 @@ freejob(jp) ckfree(jp->ps); jp->used = 0; #if JOBS - if (curjob == jp - jobtab + 1) - curjob = 0; + deljob(jp); #endif INTON; } @@ -330,9 +468,10 @@ freejob(jp) int -waitcmd(argc, argv) char **argv; { +waitcmd(int argc, char **argv) +{ struct job *job; - int status; + int status, retval; struct job *jp; if (argc > 1) { @@ -340,44 +479,57 @@ waitcmd(argc, argv) char **argv; { } else { job = NULL; } - for (;;) { /* loop until process terminated or stopped */ + + /* + * Loop until a process is terminated or stopped, or a SIGINT is + * received. + */ + + in_waitcmd++; + do { if (job != NULL) { if (job->state) { status = job->ps[job->nprocs - 1].status; - if ((status & 0xFF) == 0) - status = status >> 8 & 0xFF; + if (WIFEXITED(status)) + retval = WEXITSTATUS(status); #if JOBS - else if ((status & 0xFF) == 0177) - status = (status >> 8 & 0x7F) + 128; + else if (WIFSTOPPED(status)) + retval = WSTOPSIG(status) + 128; #endif else - status = (status & 0x7F) + 128; + retval = WTERMSIG(status) + 128; if (! iflag) freejob(job); - return status; + in_waitcmd--; + return retval; } } else { for (jp = jobtab ; ; jp++) { if (jp >= jobtab + njobs) { /* no running procs */ + in_waitcmd--; return 0; } if (jp->used && jp->state == 0) break; } } - dowait(1, (struct job *)NULL); - } + } while (dowait(1, (struct job *)NULL) != -1); + in_waitcmd--; + + return 0; } -jobidcmd(argc, argv) char **argv; { +int +jobidcmd(int argc __unused, char **argv) +{ struct job *jp; int i; jp = getjob(argv[1]); for (i = 0 ; i < jp->nprocs ; ) { - out1fmt("%d", jp->ps[i].pid); + out1fmt("%d", (int)jp->ps[i].pid); out1c(++i < jp->nprocs? ' ' : '\n'); } return 0; @@ -390,20 +542,18 @@ jobidcmd(argc, argv) char **argv; { */ STATIC struct job * -getjob(name) - char *name; - { +getjob(char *name) +{ int jobno; - register struct job *jp; - int pid; + struct job *found, *jp; + pid_t pid; int i; if (name == NULL) { #if JOBS -currentjob: - if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) +currentjob: if ((jp = getcurjob(NULL)) == NULL) error("No current job"); - return &jobtab[jobno - 1]; + return (jp); #else error("No current job"); #endif @@ -416,9 +566,28 @@ currentjob: #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[2] == '\0') { + if ((jp = getcurjob(NULL)) == NULL || + (jp = getcurjob(jp)) == NULL) + error("No previous job"); + return (jp); #endif + } else if (name[1] == '?') { + found = NULL; + for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { + if (jp->used && jp->nprocs > 0 + && strstr(jp->ps[0].cmd, name + 2) != NULL) { + if (found) + error("%s: ambiguous", name); + found = jp; + } + } + if (found != NULL) + return (found); } else { - register struct job *found = NULL; + found = NULL; for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { if (jp->used && jp->nprocs > 0 && prefix(name + 1, jp->ps[0].cmd)) { @@ -431,7 +600,7 @@ currentjob: return found; } } else if (is_number(name)) { - pid = number(name); + pid = (pid_t)number(name); for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { if (jp->used && jp->nprocs > 0 && jp->ps[jp->nprocs - 1].pid == pid) @@ -439,6 +608,8 @@ currentjob: } } error("No such job: %s", name); + /*NOTREACHED*/ + return NULL; } @@ -448,9 +619,8 @@ currentjob: */ struct job * -makejob(node, nprocs) - union node *node; - { +makejob(union node *node __unused, int nprocs) +{ int i; struct job *jp; @@ -459,14 +629,25 @@ makejob(node, nprocs) INTOFF; if (njobs == 0) { jobtab = ckmalloc(4 * sizeof jobtab[0]); +#if JOBS + jobmru = NULL; +#endif } else { jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); - bcopy(jobtab, jp, njobs * sizeof jp[0]); - for (i= 0; iused = 1; jp->changed = 0; jp->nprocs = 0; + jp->foreground = 0; #if JOBS jp->jobctl = jobctl; + jp->next = NULL; #endif if (nprocs > 1) { jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); @@ -492,10 +675,70 @@ makejob(node, nprocs) jp->ps = &jp->ps0; } INTON; - TRACE(("makejob(0x%x, %d) returns %%%d\n", (int)node, nprocs, jp - jobtab + 1)); + TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, + jp - jobtab + 1)); return jp; -} +} +#if JOBS +STATIC void +setcurjob(struct job *cj) +{ + struct job *jp, *prev; + + for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) { + if (jp == cj) { + if (prev != NULL) + prev->next = jp->next; + else + jobmru = jp->next; + jp->next = jobmru; + jobmru = cj; + return; + } + } + cj->next = jobmru; + jobmru = cj; +} + +STATIC void +deljob(struct job *j) +{ + struct job *jp, *prev; + + for (prev = NULL, jp = jobmru; jp != NULL; prev = jp, jp = jp->next) { + if (jp == j) { + if (prev != NULL) + prev->next = jp->next; + else + jobmru = jp->next; + return; + } + } +} + +/* + * Return the most recently used job that isn't `nj', and preferably one + * that is stopped. + */ +STATIC struct job * +getcurjob(struct job *nj) +{ + struct job *jp; + + /* Try to find a stopped one.. */ + for (jp = jobmru; jp != NULL; jp = jp->next) + if (jp->used && jp != nj && jp->state == JOBSTOPPED) + return (jp); + /* Otherwise the most recently used job that isn't `nj' */ + for (jp = jobmru; jp != NULL; jp = jp->next) + if (jp->used && jp != nj) + return (jp); + + return (NULL); +} + +#endif /* * Fork of a subshell. If we are doing job control, give the subshell its @@ -512,73 +755,76 @@ makejob(node, nprocs) * in a pipeline). */ -int -forkshell(jp, n, mode) - union node *n; - struct job *jp; - { - int pid; - int pgrp; +pid_t +forkshell(struct job *jp, union node *n, int mode) +{ + pid_t pid; + pid_t pgrp; - TRACE(("forkshell(%%%d, 0x%x, %d) called\n", jp - jobtab, (int)n, mode)); + TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n, + mode)); INTOFF; + flushall(); pid = fork(); if (pid == -1) { TRACE(("Fork failed, errno=%d\n", errno)); INTON; - error("Cannot fork"); + error("Cannot fork: %s", strerror(errno)); } if (pid == 0) { struct job *p; int wasroot; int i; - TRACE(("Child shell %d\n", getpid())); + TRACE(("Child shell %d\n", (int)getpid())); wasroot = rootshell; rootshell = 0; - for (i = njobs, p = jobtab ; --i >= 0 ; p++) - if (p->used) - freejob(p); closescript(); INTON; clear_traps(); #if JOBS jobctl = 0; /* do job control only in root shell */ - if (wasroot && mode != FORK_NOJOB && jflag) { + if (wasroot && mode != FORK_NOJOB && mflag) { if (jp == NULL || jp->nprocs == 0) pgrp = getpid(); else pgrp = jp->ps[0].pid; - setpgrp(0, pgrp); - if (mode == FORK_FG) { + if (setpgid(0, pgrp) == 0 && mode == FORK_FG) { /*** this causes superfluous TIOCSPGRPS ***/ - if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) - error("TIOCSPGRP failed, errno=%d\n", errno); + if (tcsetpgrp(ttyfd, pgrp) < 0) + error("tcsetpgrp failed, errno=%d", errno); } setsignal(SIGTSTP); setsignal(SIGTTOU); } else if (mode == FORK_BG) { ignoresig(SIGINT); ignoresig(SIGQUIT); - if ((jp == NULL || jp->nprocs == 0) - && ! fd0_redirected_p ()) { + if ((jp == NULL || jp->nprocs == 0) && + ! fd0_redirected_p ()) { close(0); - if (open("/dev/null", O_RDONLY) != 0) - error("Can't open /dev/null"); + if (open(_PATH_DEVNULL, O_RDONLY) != 0) + error("Can't open %s: %s", + _PATH_DEVNULL, strerror(errno)); } } #else if (mode == FORK_BG) { ignoresig(SIGINT); ignoresig(SIGQUIT); - if ((jp == NULL || jp->nprocs == 0) - && ! fd0_redirected_p ()) { + if ((jp == NULL || jp->nprocs == 0) && + ! fd0_redirected_p ()) { close(0); - if (open("/dev/null", O_RDONLY) != 0) - error("Can't open /dev/null"); + if (open(_PATH_DEVNULL, O_RDONLY) != 0) + error("Can't open %s: %s", + _PATH_DEVNULL, strerror(errno)); } } #endif + INTOFF; + for (i = njobs, p = jobtab ; --i >= 0 ; p++) + if (p->used) + freejob(p); + INTON; if (wasroot && iflag) { setsignal(SIGINT); setsignal(SIGQUIT); @@ -586,13 +832,13 @@ forkshell(jp, n, mode) } return pid; } - if (rootshell && mode != FORK_NOJOB && jflag) { + if (rootshell && mode != FORK_NOJOB && mflag) { if (jp == NULL || jp->nprocs == 0) pgrp = pid; else pgrp = jp->ps[0].pid; #if JOBS - setpgrp(pid, pgrp); + setpgid(pid, pgrp); #endif } if (mode == FORK_BG) @@ -604,9 +850,13 @@ forkshell(jp, n, mode) ps->cmd = nullstr; if (iflag && rootshell && n) ps->cmd = commandtext(n); + jp->foreground = mode == FORK_FG; +#if JOBS + setcurjob(jp); +#endif } INTON; - TRACE(("In parent shell: child = %d\n", pid)); + TRACE(("In parent shell: child = %d\n", (int)pid)); return pid; } @@ -623,7 +873,7 @@ forkshell(jp, n, mode) * the interactive program catches interrupts, the user doesn't want * these interrupts to also abort the loop. The approach we take here * is to have the shell ignore interrupt signals while waiting for a - * forground process to terminate, and then send itself an interrupt + * foreground process to terminate, and then send itself an interrupt * signal if the child process was terminated by an interrupt signal. * Unfortunately, some programs want to do a bit of cleanup and then * exit on interrupt; unless these processes terminate themselves by @@ -632,41 +882,47 @@ forkshell(jp, n, mode) */ int -waitforjob(jp) - register struct job *jp; - { +waitforjob(struct job *jp, int *origstatus) +{ #if JOBS - int mypgrp = getpgrp(0); + pid_t mypgrp = getpgrp(); #endif int status; int st; INTOFF; TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); - while (jp->state == 0 && dowait(1, jp) != -1) ; + while (jp->state == 0) + if (dowait(1, jp) == -1) + dotrap(); #if JOBS if (jp->jobctl) { - if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) - error("TIOCSPGRP failed, errno=%d\n", errno); + if (tcsetpgrp(ttyfd, mypgrp) < 0) + error("tcsetpgrp failed, errno=%d\n", errno); } if (jp->state == JOBSTOPPED) - curjob = jp - jobtab + 1; + setcurjob(jp); #endif status = jp->ps[jp->nprocs - 1].status; + if (origstatus != NULL) + *origstatus = status; /* convert to 8 bits */ - if ((status & 0xFF) == 0) - st = status >> 8 & 0xFF; + if (WIFEXITED(status)) + st = WEXITSTATUS(status); #if JOBS - else if ((status & 0xFF) == 0177) - st = (status >> 8 & 0x7F) + 128; + else if (WIFSTOPPED(status)) + st = WSTOPSIG(status) + 128; #endif else - st = (status & 0x7F) + 128; + st = WTERMSIG(status) + 128; if (! JOBS || jp->state == JOBDONE) freejob(jp); - CLEAR_PENDING_INT; - if ((status & 0x7F) == SIGINT) - kill(getpid(), SIGINT); + if (int_pending()) { + if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) + kill(getpid(), SIGINT); + else + CLEAR_PENDING_INT; + } INTON; return st; } @@ -677,25 +933,31 @@ waitforjob(jp) * Wait for a process to terminate. */ -STATIC int -dowait(block, job) - struct job *job; - { - int pid; - int status; +STATIC pid_t +dowait(int block, struct job *job) +{ + pid_t pid; + int status, core; struct procstat *sp; struct job *jp; struct job *thisjob; int done; int stopped; - int core; + int sig; + int i; + in_dowait++; TRACE(("dowait(%d) called\n", block)); do { pid = waitproc(block, &status); - TRACE(("wait returns %d, status=%d, errno=%d\n", - pid, status, errno)); - } while (pid == -1 && errno == EINTR); + TRACE(("wait returns %d, status=%d\n", (int)pid, status)); + } while ((pid == -1 && errno == EINTR && breakwaitcmd == 0) || + (pid > 0 && WIFSTOPPED(status) && !iflag)); + in_dowait--; + if (breakwaitcmd != 0) { + breakwaitcmd = 0; + return -1; + } if (pid <= 0) return pid; INTOFF; @@ -708,13 +970,15 @@ dowait(block, job) if (sp->pid == -1) continue; if (sp->pid == pid) { - TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status)); + TRACE(("Changing status of proc %d from 0x%x to 0x%x\n", + (int)pid, sp->status, + status)); sp->status = status; thisjob = jp; } if (sp->status == -1) stopped = 0; - else if ((sp->status & 0377) == 0177) + else if (WIFSTOPPED(sp->status)) done = 0; } if (stopped) { /* stopped or done */ @@ -723,8 +987,8 @@ dowait(block, job) TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); jp->state = state; #if JOBS - if (done && curjob == jp - jobtab + 1) - curjob = 0; /* no current job */ + if (done) + deljob(jp); #endif } } @@ -732,32 +996,34 @@ dowait(block, job) } INTON; if (! rootshell || ! iflag || (job && thisjob == job)) { + core = WCOREDUMP(status); #if JOBS - if ((status & 0xFF) == 0177) - status >>= 8; + if (WIFSTOPPED(status)) + sig = WSTOPSIG(status); + else #endif - core = status & 0x80; - status &= 0x7F; - if (status != 0 && status != SIGINT && status != SIGPIPE) { - if (thisjob != job) - outfmt(out2, "%d: ", pid); -#if JOBS - if (status == SIGTSTP && rootshell && iflag) - outfmt(out2, "%%%d ", job - jobtab + 1); -#endif - if (status <= MAXSIG && sigmesg[status]) - out2str(sigmesg[status]); + { + if (WIFEXITED(status)) + sig = 0; else - outfmt(out2, "Signal %d", status); - if (core) - out2str(" - core dumped"); - out2c('\n'); - flushout(&errout); - } else { - TRACE(("Not printing status: status=%d\n", status)); + sig = WTERMSIG(status); + } + if (sig != 0 && sig != SIGINT && sig != SIGPIPE) { + if (!mflag || + (thisjob->foreground && !WIFSTOPPED(status))) { + i = WTERMSIG(status); + if ((i & 0x7F) < _NSIG && strsiglist(i & 0x7F)) + out1str(strsiglist(i & 0x7F)); + else + out1fmt("Signal %d", i & 0x7F); + if (core) + out1str(" (core dumped)"); + out1c('\n'); + } else + showjob(thisjob, pid, 0, 0); } } else { - TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job)); + TRACE(("Not printing status, rootshell=%d, job=%p\n", rootshell, job)); if (thisjob) thisjob->changed = 1; } @@ -770,80 +1036,58 @@ dowait(block, job) * Do a wait system call. If job control is compiled in, we accept * stopped processes. If block is zero, we return a value of zero * rather than blocking. - * - * System V doesn't have a non-blocking wait system call. It does - * have a SIGCLD signal that is sent to a process when one of it's - * children dies. The obvious way to use SIGCLD would be to install - * a handler for SIGCLD which simply bumped a counter when a SIGCLD - * was received, and have waitproc bump another counter when it got - * the status of a process. Waitproc would then know that a wait - * system call would not block if the two counters were different. - * This approach doesn't work because if a process has children that - * have not been waited for, System V will send it a SIGCLD when it - * installs a signal handler for SIGCLD. What this means is that when - * a child exits, the shell will be sent SIGCLD signals continuously - * until is runs out of stack space, unless it does a wait call before - * restoring the signal handler. The code below takes advantage of - * this (mis)feature by installing a signal handler for SIGCLD and - * then checking to see whether it was called. If there are any - * children to be waited for, it will be. - * - * If neither SYSV nor BSD is defined, we don't implement nonblocking - * waits at all. In this case, the user will not be informed when - * a background process until the next time she runs a real program - * (as opposed to running a builtin command or just typing return), - * and the jobs command may give out of date information. */ +STATIC pid_t +waitproc(int block, int *status) +{ +#if POSIX + int flags; -#ifdef SYSV -STATIC int gotsigchild; - -STATIC int onsigchild() { - gotsigchild = 1; -} -#endif - - -STATIC int -waitproc(block, status) - int *status; - { -#ifdef BSD +#if JOBS + flags = ((rootshell && is_interactive) ? WUNTRACED : 0); +#else + flags = 0; +#endif /* JOBS */ + return waitpid(-1, status, (block == 0 ? WNOHANG : 0) | flags); +#else /* !POSIX */ + /* Assume BSD */ int flags; #if JOBS flags = WUNTRACED; #else flags = 0; -#endif +#endif /* JOBS */ if (block == 0) flags |= WNOHANG; - return wait3((union wait *)status, flags, (struct rusage *)NULL); -#else -#ifdef SYSV - int (*save)(); - - if (block == 0) { - gotsigchild = 0; - save = signal(SIGCLD, onsigchild); - signal(SIGCLD, save); - if (gotsigchild == 0) - return 0; - } - return wait(status); -#else -#if POSIX - return waitpid(-1, status, block == 0 ? WNOHANG : 0); -#else - if (block == 0) - return 0; - return wait(status); -#endif -#endif -#endif + return wait3(status, flags, (struct rusage *)NULL); +#endif /* POSIX */ } +/* + * return 1 if there are stopped jobs, otherwise 0 + */ +int job_warning = 0; +int +stoppedjobs(void) +{ + int jobno; + struct job *jp; + if (job_warning) + return (0); + for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { + if (jp->used == 0) + continue; + if (jp->state == JOBSTOPPED) { + out2str("You have stopped jobs.\n"); + job_warning = 2; + return (1); + } + } + + return (0); +} /* * Return a string identifying a command (to be printed by the @@ -852,16 +1096,15 @@ waitproc(block, status) STATIC char *cmdnextc; STATIC int cmdnleft; -STATIC void cmdtxt(), cmdputs(); +#define MAXCMDTEXT 200 -STATIC char * -commandtext(n) - union node *n; - { +char * +commandtext(union node *n) +{ char *name; - cmdnextc = name = ckmalloc(50); - cmdnleft = 50 - 4; + cmdnextc = name = ckmalloc(MAXCMDTEXT); + cmdnleft = MAXCMDTEXT - 4; cmdtxt(n); *cmdnextc = '\0'; return name; @@ -869,17 +1112,16 @@ commandtext(n) STATIC void -cmdtxt(n) - union node *n; - { +cmdtxt(union node *n) +{ union node *np; struct nodelist *lp; char *p; int i; char s[2]; - if (n == NULL) return; - + if (n == NULL) + return; switch (n->type) { case NSEMI: cmdtxt(n->nbinary.ch1); @@ -964,8 +1206,12 @@ until: p = ">>"; i = 1; goto redir; case NTOFD: p = ">&"; i = 1; goto redir; + case NCLOBBER: + p = ">|"; i = 1; goto redir; case NFROM: p = "<"; i = 0; goto redir; + case NFROMTO: + p = "<>"; i = 0; goto redir; case NFROMFD: p = "<&"; i = 0; goto redir; redir: @@ -976,7 +1222,10 @@ redir: } cmdputs(p); if (n->type == NTOFD || n->type == NFROMFD) { - s[0] = n->ndup.dupfd + '0'; + if (n->ndup.dupfd >= 0) + s[0] = n->ndup.dupfd + '0'; + else + s[0] = '-'; s[1] = '\0'; cmdputs(s); } else { @@ -996,11 +1245,10 @@ redir: STATIC void -cmdputs(s) - char *s; - { - register char *p, *q; - register char c; +cmdputs(char *s) +{ + char *p, *q; + char c; int subtype = 0; if (cmdnleft <= 0) @@ -1020,7 +1268,7 @@ cmdputs(s) subtype = 0; } else if (c == CTLENDVAR) { *q++ = '}'; - } else if (c == CTLBACKQ | c == CTLBACKQ+CTLQUOTE) + } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) cmdnleft++; /* ignore it */ else *q++ = c; @@ -1033,3 +1281,16 @@ cmdputs(s) } cmdnextc = q; } + +#ifdef NO_KILLPG +static int killpg(grp, sig) +pid_t grp; +int sig; +{ + return kill(-grp, sig); +} +#endif + +/* + * $PchId: jobs.c,v 1.7 2006/05/22 12:02:13 philip Exp $ + */ diff --git a/commands/ash/jobs.h b/commands/ash/jobs.h index b87262fe2..db436aa8b 100755 --- a/commands/ash/jobs.h +++ b/commands/ash/jobs.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)jobs.h 5.1 (Berkeley) 3/7/91 + * @(#)jobs.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/jobs.h,v 1.18 2004/04/06 20:06:51 markm Exp $ */ /* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ @@ -41,6 +38,7 @@ #define FORK_BG 1 #define FORK_NOJOB 2 +#include /* for sig_atomic_t */ /* * A job structure contains information about a job. A job is either a @@ -51,7 +49,7 @@ struct procstat { pid_t pid; /* process id */ - short status; /* status flags (defined above) */ + int status; /* status flags (defined above) */ char *cmd; /* text of command being run */ }; @@ -64,33 +62,41 @@ struct procstat { struct job { struct procstat ps0; /* status of process */ struct procstat *ps; /* status or processes when more than one */ - pid_t nprocs; /* number of processes */ + short nprocs; /* number of processes */ pid_t pgrp; /* process group of this job */ char state; /* true if job is finished */ char used; /* true if this entry is in used */ char changed; /* true if status has changed */ + char foreground; /* true if running in the foreground */ #if JOBS char jobctl; /* job running under job control */ + struct job *next; /* job used after this one */ #endif }; extern pid_t backgndpid; /* pid of last background process */ +extern int job_warning; /* user was warned about stopped jobs */ +extern int in_waitcmd; /* are we in waitcmd()? */ +extern int in_dowait; /* are we in dowait()? */ +extern volatile sig_atomic_t breakwaitcmd; /* break wait to process traps? */ - -#ifdef __STDC__ void setjobctl(int); -void showjobs(int); +int fgcmd(int, char **); +int bgcmd(int, char **); +int jobscmd(int, char **); +void showjobs(int, int, int); +int waitcmd(int, char **); +int jobidcmd(int, char **); struct job *makejob(union node *, int); -int forkshell(struct job *, union node *, int); -int waitforjob(struct job *); -#else -void setjobctl(); -void showjobs(); -struct job *makejob(); -int forkshell(); -int waitforjob(); -#endif +pid_t forkshell(struct job *, union node *, int); +int waitforjob(struct job *, int *); +int stoppedjobs(void); +char *commandtext(union node *); #if ! JOBS #define setjobctl(on) /* do nothing */ #endif + +/* + * $PchId: jobs.h,v 1.4 2006/03/30 12:07:24 philip Exp $ + */ diff --git a/commands/ash/machdep.h b/commands/ash/machdep.h index e4ee3c944..4de7acd21 100755 --- a/commands/ash/machdep.h +++ b/commands/ash/machdep.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)machdep.h 5.1 (Berkeley) 3/7/91 + * @(#)machdep.h 8.2 (Berkeley) 5/4/95 */ /* @@ -47,5 +47,9 @@ union align { char *cp; }; -#define ALIGN(nbytes) ((nbytes) + sizeof(union align) - 1 &~ (sizeof(union align) - 1)) +#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1)) #endif + +/* + * $PchId: machdep.h,v 1.2 2001/05/15 16:36:26 philip Exp $ + */ diff --git a/commands/ash/mail.c b/commands/ash/mail.c index a90d4a011..14bc1d91e 100755 --- a/commands/ash/mail.c +++ b/commands/ash/mail.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,14 @@ */ #ifndef lint -static char sccsid[] = "@(#)mail.c 5.1 (Berkeley) 3/7/91"; +#if 0 +static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $"); +*/ /* * Routines to check for mail. (Perhaps make part of main.c?) @@ -48,8 +50,10 @@ static char sccsid[] = "@(#)mail.c 5.1 (Berkeley) 3/7/91"; #include "output.h" #include "memalloc.h" #include "error.h" +#include "mail.h" #include #include +#include #define MAXMBOXES 10 @@ -67,11 +71,12 @@ STATIC time_t mailtime[MAXMBOXES]; /* times of mailboxes */ */ void -chkmail(silent) { - register int i; +chkmail(int silent) +{ + int i; char *mpath; char *p; - register char *q; + char *q; struct stackmark smark; struct stat statb; @@ -91,18 +96,28 @@ chkmail(silent) { if (q[-1] != '/') abort(); q[-1] = '\0'; /* delete trailing '/' */ +#ifdef notdef /* this is what the System V shell claims to do (it lies) */ if (stat(p, &statb) < 0) statb.st_mtime = 0; - if (!silent - && statb.st_size > 0 - && statb.st_mtime > mailtime[i] - && statb.st_mtime > statb.st_atime - ) { - out2str(pathopt? pathopt : "You have mail"); + if (statb.st_mtime > mailtime[i] && ! silent) { + out2str(pathopt? pathopt : "you have mail"); out2c('\n'); } mailtime[i] = statb.st_mtime; +#else /* this is what it should do */ + if (stat(p, &statb) < 0) + statb.st_size = 0; + if (statb.st_size > mailtime[i] && ! silent) { + out2str(pathopt? pathopt : "you have mail"); + out2c('\n'); + } + mailtime[i] = statb.st_size; +#endif } nmboxes = i; popstackmark(&smark); } + +/* + * $PchId: mail.c,v 1.5 2006/05/22 12:02:37 philip Exp $ + */ diff --git a/commands/ash/mail.h b/commands/ash/mail.h index 8280791e8..4d67b0ae9 100755 --- a/commands/ash/mail.h +++ b/commands/ash/mail.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,11 +29,12 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mail.h 5.1 (Berkeley) 3/7/91 + * @(#)mail.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/mail.h,v 1.8 2004/04/06 20:06:51 markm Exp $ */ -#ifdef __STDC__ void chkmail(int); -#else -void chkmail(); -#endif + +/* + * $PchId: mail.h,v 1.3 2006/03/30 11:53:44 philip Exp $ + */ diff --git a/commands/ash/main.c b/commands/ash/main.c index e8200eaf2..262756db4 100755 --- a/commands/ash/main.c +++ b/commands/ash/main.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,18 +31,29 @@ */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char const copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)main.c 5.2 (Berkeley) 3/13/91"; +#if 0 +static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $"); +*/ -#include +#include #include +#include +#include #include +#include +#include + #include "shell.h" #include "main.h" #include "mail.h" @@ -54,38 +61,26 @@ static char sccsid[] = "@(#)main.c 5.2 (Berkeley) 3/13/91"; #include "output.h" #include "parser.h" #include "nodes.h" +#include "expand.h" #include "eval.h" #include "jobs.h" #include "input.h" #include "trap.h" -#if ATTY #include "var.h" -#endif +#include "show.h" #include "memalloc.h" #include "error.h" #include "init.h" #include "mystring.h" - -#define PROFILE 0 +#include "exec.h" +#include "cd.h" +#include "builtins.h" int rootpid; int rootshell; -STATIC union node *curcmd; -STATIC union node *prevcmd; -extern int errno; -#if PROFILE -short profile_buf[16384]; -extern int etext(); -#endif -#ifdef __STDC__ STATIC void read_profile(char *); -char *getenv(char *); -#else -STATIC void read_profile(); -char *getenv(); -#endif - +STATIC char *find_dot_file(char *); /* * Main routine. We initialize things, parse the arguments, execute @@ -95,16 +90,15 @@ char *getenv(); * is used to figure out how far we had gotten. */ -main(argc, argv) char **argv; { +int +main(int argc, char *argv[]) +{ struct jmploc jmploc; struct stackmark smark; volatile int state; - char *shinit, *home; - char *profile = NULL, *ashrc = NULL; + char *shinit; -#if PROFILE - monitor(4, etext, profile_buf, sizeof profile_buf, 50); -#endif + (void) setlocale(LC_ALL, ""); state = 0; if (setjmp(jmploc.loc)) { /* @@ -112,21 +106,32 @@ main(argc, argv) char **argv; { * exception EXSHELLPROC to clean up before executing * the shell procedure. */ - if (exception == EXSHELLPROC) { + switch (exception) { + case EXSHELLPROC: rootpid = getpid(); rootshell = 1; minusc = NULL; state = 3; - } else if (state == 0 || iflag == 0 || ! rootshell) - exitshell(2); + break; + + case EXEXEC: + exitstatus = exerrno; + break; + + case EXERROR: + exitstatus = 2; + break; + + default: + break; + } + + if (exception != EXSHELLPROC) { + if (state == 0 || iflag == 0 || ! rootshell) + exitshell(exitstatus); + } reset(); -#if ATTY - if (exception == EXINT - && (! attyset() || equal(termval(), "emacs"))) -#else - if (exception == EXINT) -#endif - { + if (exception == EXINT) { out2c('\n'); flushout(&errout); } @@ -151,57 +156,38 @@ main(argc, argv) char **argv; { init(); setstackmark(&smark); procargs(argc, argv); - if (eflag) eflag = 2; /* Truly enable [ex]flag after init. */ - if (xflag) xflag = 2; + if (getpwd() == NULL && iflag) + out2str("sh: cannot determine working directory\n"); if (argv[0] && argv[0][0] == '-') { state = 1; read_profile("/etc/profile"); state1: state = 2; - if ((home = getenv("HOME")) != NULL - && (profile = (char *) malloc(strlen(home) + 10)) != NULL) - { - strcpy(profile, home); - strcat(profile, "/.profile"); - read_profile(profile); - } else { + if (privileged == 0) read_profile(".profile"); - } - } else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) { - state = 2; - evalstring(shinit); + else + read_profile("/etc/suid_profile"); } state2: - if (profile != NULL) free(profile); - state = 3; - if (!argv[0] || argv[0][0] != '-') { - if ((home = getenv("HOME")) != NULL - && (ashrc = (char *) malloc(strlen(home) + 8)) != NULL) - { - strcpy(ashrc, home); - strcat(ashrc, "/.ashrc"); - read_profile(ashrc); + if (!privileged && iflag) { + if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { + state = 3; + read_profile(shinit); } } state3: - if (ashrc != NULL) free(ashrc); - if (eflag) eflag = 1; /* Init done, enable [ex]flag */ - if (xflag) xflag = 1; - exitstatus = 0; /* Init shouldn't influence initial $? */ - state = 4; if (minusc) { evalstring(minusc); } if (sflag || minusc == NULL) { -state4: +state4: /* XXX ??? - why isn't this before the "if" statement */ cmdloop(1); } -#if PROFILE - monitor(0); -#endif exitshell(exitstatus); + /*NOTREACHED*/ + return 0; } @@ -211,52 +197,49 @@ state4: */ void -cmdloop(top) { +cmdloop(int top) +{ union node *n; struct stackmark smark; int inter; - int numeof; + int numeof = 0; TRACE(("cmdloop(%d) called\n", top)); setstackmark(&smark); - numeof = 0; for (;;) { if (pendingsigs) dotrap(); inter = 0; if (iflag && top) { inter++; - showjobs(1); + showjobs(1, 0, 0); chkmail(0); flushout(&output); } n = parsecmd(inter); -#if DEBUG - /* showtree(n); */ -#endif + /* showtree(n); DEBUG */ if (n == NEOF) { - if (Iflag == 0 || numeof >= 50) + if (!top || numeof >= 50) break; - out2str("\nUse \"exit\" to leave shell.\n"); + if (!stoppedjobs()) { + if (!Iflag) + break; + out2str("\nUse \"exit\" to leave shell.\n"); + } numeof++; } else if (n != NULL && nflag == 0) { - if (inter) { - INTOFF; - if (prevcmd) - freefunc(prevcmd); - prevcmd = curcmd; - curcmd = copyfunc(n); - INTON; - } + job_warning = (job_warning == 2) ? 1 : 0; + numeof = 0; evaltree(n, 0); -#ifdef notdef - if (exitstatus) /*DEBUG*/ - outfmt(&errout, "Exit status 0x%X\n", exitstatus); -#endif } popstackmark(&smark); + setstackmark(&smark); + if (evalskip == SKIPFILE) { + evalskip = 0; + break; + } } - popstackmark(&smark); /* unnecessary */ + popstackmark(&smark); } @@ -266,9 +249,8 @@ cmdloop(top) { */ STATIC void -read_profile(name) - char *name; - { +read_profile(char *name) +{ int fd; INTOFF; @@ -288,32 +270,63 @@ read_profile(name) */ void -readcmdfile(name) - char *name; - { +readcmdfile(char *name) +{ int fd; INTOFF; if ((fd = open(name, O_RDONLY)) >= 0) setinputfd(fd, 1); else - error("Can't open %s", name); + error("Can't open %s: %s", name, strerror(errno)); INTON; cmdloop(0); popfile(); } + /* - * Take commands from a file. To be compatable we should do a path - * search for the file, but a path search doesn't make any sense. + * Take commands from a file. To be compatible we should do a path + * search for the file, which is necessary to find sub-commands. */ -dotcmd(argc, argv) char **argv; { + +STATIC char * +find_dot_file(char *basename) +{ + static char localname[FILENAME_MAX+1]; + char *fullname; + char *path = pathval(); + struct stat statb; + + /* don't try this for absolute or relative paths */ + if( strchr(basename, '/')) + return basename; + + while ((fullname = padvance(&path, basename)) != NULL) { + strcpy(localname, fullname); + stunalloc(fullname); + if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) + return localname; + } + return basename; +} + +int +dotcmd(int argc, char **argv) +{ + struct strlist *sp; exitstatus = 0; + + for (sp = cmdenviron; sp ; sp = sp->next) + setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); + if (argc >= 2) { /* That's what SVR2 does */ - setinputfile(argv[1], 1); - commandname = argv[1]; + char *fullname = find_dot_file(argv[1]); + + setinputfile(fullname, 1); + commandname = fullname; cmdloop(0); popfile(); } @@ -321,40 +334,22 @@ dotcmd(argc, argv) char **argv; { } -exitcmd(argc, argv) char **argv; { +int +exitcmd(int argc, char **argv) +{ extern int oexitstatus; + + if (stoppedjobs()) + return 0; if (argc > 1) exitstatus = number(argv[1]); else exitstatus = oexitstatus; exitshell(exitstatus); + /*NOTREACHED*/ + return 0; } - -lccmd(argc, argv) char **argv; { - if (argc > 1) { - defun(argv[1], prevcmd); - return 0; - } else { - INTOFF; - freefunc(curcmd); - curcmd = prevcmd; - prevcmd = NULL; - INTON; - evaltree(curcmd, 0); - return exitstatus; - } -} - - - -#ifdef notdef /* - * Should never be called. + * $PchId: main.c,v 1.5 2006/05/22 12:03:02 philip Exp $ */ - -void -exit(exitstatus) { - _exit(exitstatus); -} -#endif diff --git a/commands/ash/main.h b/commands/ash/main.h index c5fda20ce..55ab91b7a 100755 --- a/commands/ash/main.h +++ b/commands/ash/main.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,16 +29,18 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)main.h 5.1 (Berkeley) 3/7/91 + * @(#)main.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/main.h,v 1.8 2004/04/06 20:06:51 markm Exp $ */ extern int rootpid; /* pid of main shell */ extern int rootshell; /* true if we aren't a child of the main shell */ -#ifdef __STDC__ void readcmdfile(char *); void cmdloop(int); -#else -void readcmdfile(); -void cmdloop(); -#endif +int dotcmd(int, char **); +int exitcmd(int, char **); + +/* + * $PchId: main.h,v 1.3 2006/03/30 11:43:59 philip Exp $ + */ diff --git a/commands/ash/memalloc.c b/commands/ash/memalloc.c index 31fcd3a3a..8f567cce9 100755 --- a/commands/ash/memalloc.c +++ b/commands/ash/memalloc.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,24 +31,33 @@ */ #ifndef lint -static char sccsid[] = "@(#)memalloc.c 5.2 (Berkeley) 3/13/91"; +#if 0 +static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/memalloc.c,v 1.26 2004/04/06 20:06:51 markm Exp $"); +*/ #include "shell.h" #include "output.h" +#include "machdep.h" #include "memalloc.h" #include "error.h" -#include "machdep.h" #include "mystring.h" +#include "expand.h" +#include +#include /* * Like malloc, but returns an error when out of space. */ pointer -ckmalloc(nbytes) { - register pointer p; - pointer malloc(); +ckmalloc(int nbytes) +{ + pointer p; if ((p = malloc(nbytes)) == NULL) error("Out of space"); @@ -65,11 +70,8 @@ ckmalloc(nbytes) { */ pointer -ckrealloc(p, nbytes) - register pointer p; - { - pointer realloc(); - +ckrealloc(pointer p, int nbytes) +{ if ((p = realloc(p, nbytes)) == NULL) error("Out of space"); return p; @@ -81,10 +83,9 @@ ckrealloc(p, nbytes) */ char * -savestr(s) - char *s; - { - register char *p; +savestr(char *s) +{ + char *p; p = ckmalloc(strlen(s) + 1); scopy(s, p); @@ -97,47 +98,56 @@ savestr(s) * to make this more efficient, and also to avoid all sorts of exception * handling code to handle interrupts in the middle of a parse. * - * The size 504 was chosen because the Ultrix malloc handles that size - * well. + * The size 496 was chosen because with 16-byte alignment the total size + * for the allocated block is 512. */ -#define MINSIZE 504 /* minimum size of a block */ +#define MINSIZE 496 /* minimum size of a block. */ struct stack_block { struct stack_block *prev; - char space[MINSIZE]; + /* Data follows */ }; +#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block))) -struct stack_block stackbase; -struct stack_block *stackp = &stackbase; -char *stacknxt = stackbase.space; -int stacknleft = MINSIZE; +STATIC struct stack_block *stackp; +STATIC struct stackmark *markp; +char *stacknxt; +int stacknleft; int sstrnleft; int herefd = -1; +static void +stnewblock(int nbytes) +{ + struct stack_block *sp; + int allocsize; + + if (nbytes < MINSIZE) + nbytes = MINSIZE; + + allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes); + + INTOFF; + sp = ckmalloc(allocsize); + sp->prev = stackp; + stacknxt = SPACE(sp); + stacknleft = allocsize - (stacknxt - (char*)sp); + stackp = sp; + INTON; +} + pointer -stalloc(nbytes) { - register char *p; +stalloc(int nbytes) +{ + char *p; nbytes = ALIGN(nbytes); - if (nbytes > stacknleft) { - int blocksize; - struct stack_block *sp; - - blocksize = nbytes; - if (blocksize < MINSIZE) - blocksize = MINSIZE; - INTOFF; - sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); - sp->prev = stackp; - stacknxt = sp->space; - stacknleft = blocksize; - stackp = sp; - INTON; - } + if (nbytes > stacknleft) + stnewblock(nbytes); p = stacknxt; stacknxt += nbytes; stacknleft -= nbytes; @@ -146,11 +156,10 @@ stalloc(nbytes) { void -stunalloc(p) - pointer p; - { +stunalloc(pointer p) +{ if (p == NULL) { /*DEBUG */ - write(2, "stunalloc\n", 10); + write(STDERR_FILENO, "stunalloc\n", 10); abort(); } stacknleft += stacknxt - (char *)p; @@ -160,22 +169,23 @@ stunalloc(p) void -setstackmark(mark) - struct stackmark *mark; - { +setstackmark(struct stackmark *mark) +{ mark->stackp = stackp; mark->stacknxt = stacknxt; mark->stacknleft = stacknleft; + mark->marknext = markp; + markp = mark; } void -popstackmark(mark) - struct stackmark *mark; - { +popstackmark(struct stackmark *mark) +{ struct stack_block *sp; INTOFF; + markp = mark->marknext; while (stackp != mark->stackp) { sp = stackp; stackp = sp->prev; @@ -198,35 +208,56 @@ popstackmark(mark) */ void -growstackblock() { +growstackblock(void) +{ char *p; - int newlen = stacknleft * 2 + 100; - char *oldspace = stacknxt; - int oldlen = stacknleft; + int newlen; + char *oldspace; + int oldlen; struct stack_block *sp; + struct stack_block *oldstackp; + struct stackmark *xmark; - if (stacknxt == stackp->space && stackp != &stackbase) { + newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100; + newlen = ALIGN(newlen); + oldspace = stacknxt; + oldlen = stacknleft; + + if (stackp != NULL && stacknxt == SPACE(stackp)) { INTOFF; - sp = stackp; - stackp = sp->prev; - sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); + oldstackp = stackp; + stackp = oldstackp->prev; + sp = ckrealloc((pointer)oldstackp, newlen); sp->prev = stackp; stackp = sp; - stacknxt = sp->space; - stacknleft = newlen; + stacknxt = SPACE(sp); + stacknleft = newlen - (stacknxt - (char*)sp); + + /* + * Stack marks pointing to the start of the old block + * must be relocated to point to the new block + */ + xmark = markp; + while (xmark != NULL && xmark->stackp == oldstackp) { + xmark->stackp = stackp; + xmark->stacknxt = stacknxt; + xmark->stacknleft = stacknleft; + xmark = xmark->marknext; + } INTON; } else { p = stalloc(newlen); - bcopy(oldspace, p, oldlen); - stacknxt = p; /* free the space */ - stacknleft += newlen; /* we just allocated */ + if (oldlen != 0) + memcpy(p, oldspace, oldlen); + stunalloc(p); } } void -grabstackblock(len) { +grabstackblock(int len) +{ len = ALIGN(len); stacknxt += len; stacknleft -= len; @@ -254,8 +285,11 @@ grabstackblock(len) { char * -growstackstr() { - int len = stackblocksize(); +growstackstr(void) +{ + int len; + + len = stackblocksize(); if (herefd >= 0 && len >= 1024) { xwrite(herefd, stackblock(), len); sstrnleft = len - 1; @@ -272,8 +306,11 @@ growstackstr() { */ char * -makestrspace() { - int len = stackblocksize() - sstrnleft; +makestrspace(void) +{ + int len; + + len = stackblocksize() - sstrnleft; growstackblock(); sstrnleft = stackblocksize() - len; return stackblock() + len; @@ -282,11 +319,13 @@ makestrspace() { void -ungrabstackstr(s, p) - char *s; - char *p; - { +ungrabstackstr(char *s, char *p) +{ stacknleft += stacknxt - s; stacknxt = s; sstrnleft = stacknleft - (p - s); } + +/* + * $PchId: memalloc.c,v 1.5 2006/05/22 12:03:26 philip Exp $ + */ diff --git a/commands/ash/memalloc.h b/commands/ash/memalloc.h index 4c663ae20..f3c9138f0 100755 --- a/commands/ash/memalloc.h +++ b/commands/ash/memalloc.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,13 +29,15 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)memalloc.h 5.1 (Berkeley) 3/7/91 + * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/memalloc.h,v 1.9 2004/04/06 20:06:51 markm Exp $ */ struct stackmark { struct stack_block *stackp; char *stacknxt; int stacknleft; + struct stackmark *marknext; }; @@ -48,10 +46,8 @@ extern int stacknleft; extern int sstrnleft; extern int herefd; -#ifdef __STDC__ pointer ckmalloc(int); pointer ckrealloc(pointer, int); -void free(pointer); /* defined in C library */ char *savestr(char *); pointer stalloc(int); void stunalloc(pointer); @@ -62,21 +58,6 @@ void grabstackblock(int); char *growstackstr(void); char *makestrspace(void); void ungrabstackstr(char *, char *); -#else -pointer ckmalloc(); -pointer ckrealloc(); -void free(); /* defined in C library */ -char *savestr(); -pointer stalloc(); -void stunalloc(); -void setstackmark(); -void popstackmark(); -void growstackblock(); -void grabstackblock(); -char *growstackstr(); -char *makestrspace(); -void ungrabstackstr(); -#endif @@ -84,7 +65,7 @@ void ungrabstackstr(); #define stackblocksize() stacknleft #define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() #define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) -#define CHECKSTRSPACE(n, p) if (sstrnleft < n) p = makestrspace(); else +#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); } #define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) #define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) #define STUNPUTC(p) (++sstrnleft, --p) @@ -93,3 +74,7 @@ void ungrabstackstr(); #define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) #define ckfree(p) free((pointer)(p)) + +/* + * $PchId: memalloc.h,v 1.3 2006/03/30 11:39:41 philip Exp $ + */ diff --git a/commands/ash/miscbltin.c b/commands/ash/miscbltin.c index f8345b4a6..86f05788d 100755 --- a/commands/ash/miscbltin.c +++ b/commands/ash/miscbltin.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,13 +31,32 @@ */ #ifndef lint -static char sccsid[] = "@(#)miscbltin.c 5.2 (Berkeley) 3/13/91"; +#if 0 +static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp $"); +*/ /* - * Miscelaneous builtins. + * Miscellaneous builtins. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "shell.h" #include "options.h" #include "var.h" @@ -49,38 +64,71 @@ static char sccsid[] = "@(#)miscbltin.c 5.2 (Berkeley) 3/13/91"; #include "memalloc.h" #include "error.h" #include "mystring.h" +#include "builtins.h" #undef eflag -extern char **argptr; /* argument list for builtin command */ - - /* - * The read builtin. The -e option causes backslashes to escape the - * following character. + * 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. */ -readcmd(argc, argv) char **argv; { +int +readcmd(int argc __unused, char **argv __unused) +{ char **ap; int backslash; char c; - int eflag; + int rflag; char *prompt; char *ifs; char *p; int startword; int status; int i; + struct timeval tv; + char *tvptr; +#ifndef __minix_vmd + fd_set ifds; +#endif + struct termios told, tnew; + int tsaved; - eflag = 0; + rflag = 0; prompt = NULL; - while ((i = nextopt("ep:")) != '\0') { - if (i == 'p') - prompt = optarg; - else - eflag = 1; + 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); @@ -90,12 +138,45 @@ readcmd(argc, argv) char **argv; { error("arg count"); if ((ifs = bltinlookup("IFS", 1)) == NULL) ifs = nullstr; + + if (tv.tv_sec >= 0) { +#ifdef __minix + abort(); +#else + /* + * See if we can disable input processing; this will + * not give the desired result if we are in a pipeline + * and someone upstream is still in line-by-line mode. + */ + tsaved = 0; + if (tcgetattr(0, &told) == 0) { + memcpy(&tnew, &told, sizeof(told)); + cfmakeraw(&tnew); + tcsetattr(0, TCSANOW, &tnew); + tsaved = 1; + } + /* + * Wait for something to become available. + */ + FD_ZERO(&ifds); + FD_SET(0, &ifds); + status = select(1, &ifds, NULL, NULL, &tv); + if (tsaved) + tcsetattr(0, TCSANOW, &told); + /* + * If there's nothing ready, return an error. + */ + if (status <= 0) + return(1); +#endif + } + status = 0; startword = 1; backslash = 0; STARTSTACKSTR(p); for (;;) { - if (read(0, &c, 1) != 1) { + if (read(STDIN_FILENO, &c, 1) != 1) { status = 1; break; } @@ -107,7 +188,7 @@ readcmd(argc, argv) char **argv; { STPUTC(c, p); continue; } - if (eflag && c == '\\') { + if (!rflag && c == '\\') { backslash++; continue; } @@ -118,7 +199,7 @@ readcmd(argc, argv) char **argv; { } startword = 0; if (backslash && c == '\\') { - if (read(0, &c, 1) != 1) { + if (read(STDIN_FILENO, &c, 1) != 1) { status = 1; break; } @@ -142,25 +223,274 @@ readcmd(argc, argv) char **argv; { -umaskcmd(argc, argv) char **argv; { +int +umaskcmd(int argc __unused, char **argv) +{ + char *ap; int mask; - char *p; int i; + int symbolic_mode = 0; - if ((p = argv[1]) == NULL) { - INTOFF; - mask = umask(0); - umask(mask); - INTON; - out1fmt("%.4o\n", mask); /* %#o might be better */ + 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 { - mask = 0; - do { - if ((unsigned)(i = *p - '0') >= 8) - error("Illegal number: %s", argv[1]); - mask = (mask << 3) + i; - } while (*++p != '\0'); - umask(mask); + if (isdigit(*ap)) { + mask = 0; + do { + if (*ap >= '8' || *ap < '0') + error("Illegal number: %s", argv[1]); + mask = (mask << 3) + (*ap - '0'); + } while (*++ap != '\0'); + umask(mask); + } else { + void *set; + if ((set = setmode (ap)) == 0) + error("Illegal number: %s", ap); + + mask = getmode (set, ~mask & 0777); + umask(~mask & 0777); + free(set); + } } return 0; } + +#ifdef __minix +struct rlimit +{ + unsigned long rlim_cur; /* current (soft) limit */ + unsigned long rlim_max; /* maximum value for rlim_cur */ +}; +#define RLIM_INFINITY (((unsigned long)1 << 31) - 1) + +int getrlimit (int, struct rlimit *); +int setrlimit (int, const struct rlimit *); + +int getrlimit(resource, rlp) +int resource; +struct rlimit *rlp; +{ + errno= ENOSYS; + return -1; +} +int setrlimit(resource, rlp) +int resource; +const struct rlimit *rlp; +{ + errno= ENOSYS; + return -1; +} +#endif + +/* + * 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 + { (char *) 0, (char *)0, 0, 0, '\0' } +}; + +int +ulimitcmd(int argc __unused, char **argv __unused) +{ + int c; + intmax_t val = 0; + enum { SOFT = 0x1, HARD = 0x2 } + how = SOFT | HARD; + const struct limits *l; + int set, all = 0; + int optc, what; + struct rlimit limit; + + what = 'f'; + while ((optc = nextopt("HSatfdsmcnuvlb")) != '\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 { + val = 0; + + while ((c = *p++) >= '0' && c <= '9') + { + val = (val * 10) + (long)(c - '0'); + if (val < 0) + break; + } + if (c) + error("bad number"); + val *= l->factor; + } + } + 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 (how & SOFT) + val = limit.rlim_cur; + else if (how & HARD) + val = limit.rlim_max; + + 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); + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; + out1fmt("%jd\n", (intmax_t)val); + } + } + 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 { + if (how & SOFT) + val = limit.rlim_cur; + else if (how & HARD) + val = limit.rlim_max; + + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; + out1fmt("%jd\n", (intmax_t)val); + } + } + return 0; +} + +/* + * $PchId: miscbltin.c,v 1.7 2006/05/23 11:59:08 philip Exp $ + */ diff --git a/commands/ash/mkbuiltins b/commands/ash/mkbuiltins index e729cdaf7..73109ad70 100755 --- a/commands/ash/mkbuiltins +++ b/commands/ash/mkbuiltins @@ -1,7 +1,7 @@ #!/bin/sh - # -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -14,10 +14,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -34,90 +30,69 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)mkbuiltins 5.2 (Berkeley) 3/8/91 +# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/mkbuiltins,v 1.13 2004/04/06 20:06:51 markm Exp $ -# All calls to awk removed, because Minix bawk is deficient. (kjb) - -if [ $# != 2 ] -then - echo "USAGE: $0 shell.h builtins" - exit 1 +#temp=`/usr/bin/mktemp -t ka` +temp=/tmp/mkb$$ +havehist=1 +if [ "X$1" = "X-h" ]; then + havehist=0 + shift fi -SHL=$1 -BLTINS=$2 - -temp=/tmp/ka$$ -exec > builtins.c +havejobs=0 +if [ "X$1" = "X-j" ]; then + havejobs=0 + shift +elif grep '^#define[ ]*JOBS[ ]*1' $2 > /dev/null +then havejobs=1 +fi +objdir=$1 +exec > ${objdir}/builtins.c cat <<\! /* * This file was generated by the mkbuiltins program. */ +#include #include "shell.h" #include "builtins.h" ! -if grep '^#define JOBS[ ]*1' $SHL > /dev/null -then - # Job control. - sed -e '/^#/d - s/ / /g - s/ #.*// - /^ *$/d - s/-j//' $BLTINS > $temp -else - # No job control. - sed -e '/^#/d - s/ / /g - s/ #.*// - /^ *$/d - /-j/d' $BLTINS > $temp -fi -sed -e 's/ .*// - s/\(.*\)/int \1();/' $temp +awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \ + print $0}' $3 | sed 's/-[hj]//' > $temp +#awk '{ printf "int %s();\n", $1}' $temp echo ' -int (*const builtinfunc[])() = {' -sed -e 's/ .*// - s/\(.*\)/ \1,/' $temp +int (*const builtinfunc[]) (int, char **) = {' +awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp echo '}; const struct builtincmd builtincmd[] = {' -i=0 -while read line -do - set -$- $line - shift - for fun - do - echo " \"$fun\", $i," - done - i=`expr $i + 1` -done < $temp -echo ' NULL, 0 +awk '{ for (i = 2 ; i <= NF ; i++) { + printf "\t{ \"%s\", %d },\n", $i, NR-1 + }}' $temp +echo ' { NULL, 0 } };' -exec > builtins.h +exec > ${objdir}/builtins.h cat <<\! /* * This file was generated by the mkbuiltins program. */ -#include ! -i=0 tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp | - while read line - do - set -$- $line - echo "#define $1 $i" - i=`expr $i + 1` - done + awk '{ printf "#define %s %d\n", $1, NR-1}' echo ' struct builtincmd { char *name; int code; }; -extern int (*const builtinfunc[])(); +extern int (*const builtinfunc[]) (int, char **); extern const struct builtincmd builtincmd[];' +awk '{ printf "int %s (int, char **);\n", $1 }' < $temp rm -f $temp + +# +# $PchId: mkbuiltins,v 1.6 2006/05/22 12:42:58 philip Exp $ diff --git a/commands/ash/mkinit.c b/commands/ash/mkinit.c index c27cbbdf9..dfb6829ab 100755 --- a/commands/ash/mkinit.c +++ b/commands/ash/mkinit.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,43 +31,51 @@ */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char const copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mkinit.c 5.3 (Berkeley) 3/13/91"; +#if 0 +static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/mkinit.c,v 1.17 2004/04/06 20:06:51 markm Exp $"); +*/ /* * This program scans all the source files for code to handle various * special events and combines this code into one file. This (allegedly) * improves the structure of the program since there is no need for * anyone outside of a module to know that that module performs special - * operations on particular events. The command is executed iff init.c - * is actually changed. + * operations on particular events. * - * Usage: mkinit command sourcefile... + * Usage: mkinit sourcefile... */ -#include - #include #include +#include +#include #include +#include +#include +#ifdef __minix +#define __unused +#endif /* * OUTFILE is the name of the output file. Output is initially written - * to the file OUTTEMP, which is then moved to OUTFILE if OUTTEMP and - * OUTFILE are different. + * to the file OUTTEMP, which is then moved to OUTFILE. */ #define OUTFILE "init.c" #define OUTTEMP "init.c.new" -#define OUTOBJ "init.o" /* @@ -89,7 +93,7 @@ struct text { int nleft; struct block *start; struct block *last; -}; +}; struct block { struct block *next; @@ -105,7 +109,7 @@ struct event { char *name; /* name of event (e.g. INIT) */ char *routine; /* name of routine called on event */ char *comment; /* comment describing routine */ - struct text code; /* code for handling event */ + struct text code; /* code for handling event */ }; @@ -148,42 +152,35 @@ struct text decls; /* declarations */ int amiddecls; /* for formatting */ -void readfile(), doevent(), doinclude(), dodecl(), output(); -void addstr(), addchar(), writetext(); +static void readfile(char *); +static int match(char *, char *); +static int gooddefine(char *); +static void doevent(struct event *, FILE *, char *); +static void doinclude(char *); +static void dodecl(char *, FILE *); +static void output(void); +static void addstr(char *, struct text *); +static void addchar(int, struct text *); +static void writetext(struct text *, FILE *); +static FILE *ckfopen(char *, char *); +static void *ckmalloc(int); +static char *savestr(char *); +static void error(char *); #define equal(s1, s2) (strcmp(s1, s2) == 0) -FILE *ckfopen(); -char *savestr(); -void *ckmalloc __P((int)); -void error(); - -main(argc, argv) - char **argv; - { +int +main(int argc __unused, char *argv[]) +{ char **ap; - int fd; - char c; - if (argc < 2) - error("Usage: mkinit command file..."); header_files[0] = "\"shell.h\""; header_files[1] = "\"mystring.h\""; - for (ap = argv + 2 ; *ap ; ap++) + for (ap = argv + 1 ; *ap ; ap++) readfile(*ap); output(); - if (file_changed()) { - unlink(OUTFILE); - link(OUTTEMP, OUTFILE); - unlink(OUTTEMP); - } else { - unlink(OUTTEMP); - if (touch(OUTOBJ)) - exit(0); /* no compilation necessary */ - } - printf("%s\n", argv[1]); - execl("/bin/sh", "sh", "-c", argv[1], (char *)0); - error("Can't exec shell"); + rename(OUTTEMP, OUTFILE); + exit(0); } @@ -191,10 +188,9 @@ main(argc, argv) * Parse an input file. */ -void -readfile(fname) - char *fname; - { +static void +readfile(char *fname) +{ FILE *fp; char line[1024]; struct event *ep; @@ -215,19 +211,31 @@ readfile(fname) doinclude(line); if (line[0] == 'M' && match("MKINIT", line)) dodecl(line, fp); - if (line[0] == '#' && gooddefine(line)) + if (line[0] == '#' && gooddefine(line)) { + char *cp; + char line2[1024]; + static const char undef[] = "#undef "; + + strcpy(line2, line); + memcpy(line2, undef, sizeof(undef) - 1); + cp = line2 + sizeof(undef) - 1; + while(*cp && (*cp == ' ' || *cp == '\t')) + cp++; + while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp++ = '\n'; *cp = '\0'; + addstr(line2, &defines); addstr(line, &defines); + } } fclose(fp); } -int -match(name, line) - char *name; - char *line; - { - register char *p, *q; +static int +match(char *name, char *line) +{ + char *p, *q; p = name, q = line; while (*p) { @@ -240,11 +248,10 @@ match(name, line) } -int -gooddefine(line) - char *line; - { - register char *p; +static int +gooddefine(char *line) +{ + char *p; if (! match("#define", line)) return 0; /* not a define */ @@ -264,12 +271,9 @@ gooddefine(line) } -void -doevent(ep, fp, fname) - register struct event *ep; - FILE *fp; - char *fname; - { +static void +doevent(struct event *ep, FILE *fp, char *fname) +{ char line[1024]; int indent; char *p; @@ -304,13 +308,12 @@ doevent(ep, fp, fname) } -void -doinclude(line) - char *line; - { - register char *p; +static void +doinclude(char *line) +{ + char *p; char *name; - register char **pp; + char **pp; for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); if (*p == '\0') @@ -329,13 +332,11 @@ doinclude(line) } -void -dodecl(line1, fp) - char *line1; - FILE *fp; - { +static void +dodecl(char *line1, FILE *fp) +{ char line[1024]; - register char *p, *q; + char *p, *q; if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ addchar('\n', &decls); @@ -350,7 +351,8 @@ dodecl(line1, fp) if (! amiddecls) addchar('\n', &decls); q = NULL; - for (p = line1 + 6 ; *p != '=' && *p != '/' ; p++); + for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) + continue; if (*p == '=') { /* eliminate initialization */ for (q = p ; *q && *q != ';' ; q++); if (*q == '\0') @@ -375,8 +377,9 @@ dodecl(line1, fp) * Write the output to the file OUTTEMP. */ -void -output() { +static void +output(void) +{ FILE *fp; char **pp; struct event *ep; @@ -392,7 +395,7 @@ output() { for (ep = event ; ep->name ; ep++) { fputs("\n\n\n", fp); fputs(ep->comment, fp); - fprintf(fp, "\nvoid\n%s() {\n", ep->routine); + fprintf(fp, "\nvoid\n%s(void) {\n", ep->routine); writetext(&ep->code, fp); fprintf(fp, "}\n"); } @@ -400,62 +403,15 @@ output() { } -/* - * Return true if the new output file is different from the old one. - */ - -int -file_changed() { - register FILE *f1, *f2; - register int c; - - if ((f1 = fopen(OUTFILE, "r")) == NULL - || (f2 = fopen(OUTTEMP, "r")) == NULL) - return 1; - while ((c = getc(f1)) == getc(f2)) { - if (c == EOF) - return 0; - } - return 1; -} - - -/* - * Touch a file. Returns 0 on failure, 1 on success. - */ - -int -touch(file) - char *file; - { - int fd; - char c; - - if ((fd = open(file, O_RDWR)) < 0) - return 0; - if (read(fd, &c, 1) != 1) { - close(fd); - return 0; - } - lseek(fd, 0L, 0); - write(fd, &c, 1); - close(fd); - return 1; -} - - - /* * A text structure is simply a block of text that is kept in memory. * Addstr appends a string to the text struct, and addchar appends a single * character. */ -void -addstr(s, text) - register char *s; - register struct text *text; - { +static void +addstr(char *s, struct text *text) +{ while (*s) { if (--text->nleft < 0) addchar(*s++, text); @@ -465,10 +421,9 @@ addstr(s, text) } -void -addchar(c, text) - register struct text *text; - { +static void +addchar(int c, struct text *text) +{ struct block *bp; if (--text->nleft < 0) { @@ -487,11 +442,9 @@ addchar(c, text) /* * Write the contents of a text structure to a file. */ -void -writetext(text, fp) - struct text *text; - FILE *fp; - { +static void +writetext(struct text *text, FILE *fp) +{ struct block *bp; if (text->start != NULL) { @@ -501,47 +454,47 @@ writetext(text, fp) } } -FILE * -ckfopen(file, mode) - char *file; - char *mode; - { +static FILE * +ckfopen(char *file, char *mode) +{ FILE *fp; if ((fp = fopen(file, mode)) == NULL) { - fprintf(stderr, "Can't open %s\n", file); + fprintf(stderr, "Can't open %s: %s\n", file, strerror(errno)); exit(2); } return fp; } -void * -ckmalloc(nbytes) { - register char *p; - char *malloc(); +static void * +ckmalloc(int nbytes) +{ + char *p; if ((p = malloc(nbytes)) == NULL) error("Out of space"); return p; } -char * -savestr(s) - char *s; - { - register char *p; +static char * +savestr(char *s) +{ + char *p; p = ckmalloc(strlen(s) + 1); strcpy(p, s); return p; } -void -error(msg) - char *msg; - { +static void +error(char *msg) +{ if (curfile != NULL) fprintf(stderr, "%s:%d: ", curfile, linno); fprintf(stderr, "%s\n", msg); exit(2); } + +/* + * $PchId: mkinit.c,v 1.6 2006/05/22 12:16:50 philip Exp $ + */ diff --git a/commands/ash/mknodes.c b/commands/ash/mknodes.c index ff7d89b61..d9582d010 100755 --- a/commands/ash/mknodes.c +++ b/commands/ash/mknodes.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -34,15 +30,20 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char const copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mknodes.c 5.1 (Berkeley) 3/7/91"; +static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95"; #endif /* not lint */ +#endif +/* +__FBSDID("$FreeBSD: src/bin/sh/mknodes.c,v 1.17 2004/04/06 20:06:51 markm Exp $"); +*/ /* * This program reads the nodetypes file and nodes.c.pat file. It generates @@ -50,7 +51,10 @@ static char sccsid[] = "@(#)mknodes.c 5.1 (Berkeley) 3/7/91"; */ #include - +#include +#include +#include +#include #define MAXTYPES 50 /* max number of node types */ #define MAXFIELDS 20 /* max fields in a structure */ @@ -80,31 +84,42 @@ struct str { /* struct representing a node structure */ }; -int ntypes; /* number of node types */ -char *nodename[MAXTYPES]; /* names of the nodes */ -struct str *nodestr[MAXTYPES]; /* type of structure used by the node */ -int nstr; /* number of structures */ -struct str str[MAXTYPES]; /* the structures */ -struct str *curstr; /* current structure */ +static int ntypes; /* number of node types */ +static char *nodename[MAXTYPES]; /* names of the nodes */ +static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */ +static int nstr; /* number of structures */ +static struct str str[MAXTYPES]; /* the structures */ +static struct str *curstr; /* current structure */ +static FILE *infp; +static char line[1024]; +static int linno; +static char *linep; + +#ifndef __printf0like +#define __printf0like(a,b) +#endif + +static void parsenode(void); +static void parsefield(void); +static void output(char *); +static void outsizes(FILE *); +static void outfunc(FILE *, int); +static void indent(int, FILE *); +static int nextfield(char *); +static void skipbl(void); +static int readline(void); +static void error(const char *, ...) __printf0like(1, 2); +static char *savestr(const char *); -FILE *infp = stdin; -char line[1024]; -int linno; -char *linep; - - -char *savestr(); -#define equal(s1, s2) (strcmp(s1, s2) == 0) - - -main(argc, argv) - char **argv; - { +int +main(int argc, char *argv[]) +{ if (argc != 3) - error("usage: mknodes file\n"); + error("usage: mknodes file"); + infp = stdin; if ((infp = fopen(argv[1], "r")) == NULL) - error("Can't open %s", argv[1]); + error("Can't open %s: %s", argv[1], strerror(errno)); while (readline()) { if (line[0] == ' ' || line[0] == '\t') parsefield(); @@ -112,12 +127,14 @@ main(argc, argv) parsenode(); } output(argv[2]); - return 0; + exit(0); } -parsenode() { +static void +parsenode(void) +{ char name[BUFLEN]; char tag[BUFLEN]; struct str *sp; @@ -131,7 +148,7 @@ parsenode() { error("Garbage at end of line"); nodename[ntypes] = savestr(name); for (sp = str ; sp < str + nstr ; sp++) { - if (equal(sp->tag, tag)) + if (strcmp(sp->tag, tag) == 0) break; } if (sp >= str + nstr) { @@ -145,7 +162,9 @@ parsenode() { } -parsefield() { +static void +parsefield(void) +{ char name[BUFLEN]; char type[BUFLEN]; char decl[2 * BUFLEN]; @@ -159,21 +178,21 @@ parsefield() { error("No field type"); fp = &curstr->field[curstr->nfields]; fp->name = savestr(name); - if (equal(type, "nodeptr")) { + if (strcmp(type, "nodeptr") == 0) { fp->type = T_NODE; sprintf(decl, "union node *%s", name); - } else if (equal(type, "nodelist")) { + } else if (strcmp(type, "nodelist") == 0) { fp->type = T_NODELIST; sprintf(decl, "struct nodelist *%s", name); - } else if (equal(type, "string")) { + } else if (strcmp(type, "string") == 0) { fp->type = T_STRING; sprintf(decl, "char *%s", name); - } else if (equal(type, "int")) { + } else if (strcmp(type, "int") == 0) { fp->type = T_INT; sprintf(decl, "int %s", name); - } else if (equal(type, "other")) { + } else if (strcmp(type, "other") == 0) { fp->type = T_OTHER; - } else if (equal(type, "temp")) { + } else if (strcmp(type, "temp") == 0) { fp->type = T_TEMP; } else { error("Unknown type %s", type); @@ -196,9 +215,9 @@ char writer[] = "\ */\n\ \n"; -output(file) - char *file; - { +static void +output(char *file) +{ FILE *hfile; FILE *cfile; FILE *patfile; @@ -208,9 +227,9 @@ output(file) char *p; if ((patfile = fopen(file, "r")) == NULL) - error("Can't open %s", file); + error("Can't open %s: %s", file, strerror(errno)); if ((hfile = fopen("nodes.h", "w")) == NULL) - error("Can't create nodes.h"); + error("Can't create nodes.h: %s", strerror(errno)); if ((cfile = fopen("nodes.c", "w")) == NULL) error("Can't create nodes.c"); fputs(writer, hfile); @@ -234,22 +253,17 @@ output(file) fputs("\tstruct nodelist *next;\n", hfile); fputs("\tunion node *n;\n", hfile); fputs("};\n\n\n", hfile); - fputs("#ifdef __STDC__\n", hfile); fputs("union node *copyfunc(union node *);\n", hfile); fputs("void freefunc(union node *);\n", hfile); - fputs("#else\n", hfile); - fputs("union node *copyfunc();\n", hfile); - fputs("void freefunc();\n", hfile); - fputs("#endif\n", hfile); fputs(writer, cfile); while (fgets(line, sizeof line, patfile) != NULL) { for (p = line ; *p == ' ' || *p == '\t' ; p++); - if (equal(p, "%SIZES\n")) + if (strcmp(p, "%SIZES\n") == 0) outsizes(cfile); - else if (equal(p, "%CALCSIZE\n")) + else if (strcmp(p, "%CALCSIZE\n") == 0) outfunc(cfile, 1); - else if (equal(p, "%COPY\n")) + else if (strcmp(p, "%COPY\n") == 0) outfunc(cfile, 0); else fputs(line, cfile); @@ -258,9 +272,9 @@ output(file) -outsizes(cfile) - FILE *cfile; - { +static void +outsizes(FILE *cfile) +{ int i; fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes); @@ -271,9 +285,9 @@ outsizes(cfile) } -outfunc(cfile, calcsize) - FILE *cfile; - { +static void +outfunc(FILE *cfile, int calcsize) +{ struct str *sp; struct field *fp; int i; @@ -287,8 +301,7 @@ outfunc(cfile, calcsize) fputs(" funcblocksize += nodesize[n->type];\n", cfile); else { fputs(" new = funcblock;\n", cfile); - fputs(" *(char **)&funcblock += nodesize[n->type];\n", - cfile); + fputs(" funcblock = (char *)funcblock + nodesize[n->type];\n", cfile); } fputs(" switch (n->type) {\n", cfile); for (sp = str ; sp < &str[nstr] ; sp++) { @@ -351,9 +364,9 @@ outfunc(cfile, calcsize) } -indent(amount, fp) - FILE *fp; - { +static void +indent(int amount, FILE *fp) +{ while (amount >= 8) { putc('\t', fp); amount -= 8; @@ -364,11 +377,10 @@ indent(amount, fp) } -int -nextfield(buf) - char *buf; - { - register char *p, *q; +static int +nextfield(char *buf) +{ + char *p, *q; p = linep; while (*p == ' ' || *p == '\t') @@ -382,15 +394,18 @@ nextfield(buf) } -skipbl() { +static void +skipbl(void) +{ while (*linep == ' ' || *linep == '\t') linep++; } -int -readline() { - register char *p; +static int +readline(void) +{ + char *p; if (fgets(line, 1024, infp) == NULL) return 0; @@ -407,26 +422,34 @@ readline() { -error(msg, a1, a2, a3, a4, a5, a6) - char *msg; - { - fprintf(stderr, "line %d: ", linno); - fprintf(stderr, msg, a1, a2, a3, a4, a5, a6); - putc('\n', stderr); +static void +error(const char *msg, ...) +{ + va_list va; + va_start(va, msg); + + (void) fprintf(stderr, "line %d: ", linno); + (void) vfprintf(stderr, msg, va); + (void) fputc('\n', stderr); + + va_end(va); + exit(2); } -char * -savestr(s) - char *s; - { - register char *p; - char *malloc(); +static char * +savestr(const char *s) +{ + char *p; if ((p = malloc(strlen(s) + 1)) == NULL) error("Out of space"); - strcpy(p, s); + (void) strcpy(p, s); return p; } + +/* + * $PchId: mknodes.c,v 1.6 2006/05/23 12:05:14 philip Exp $ + */ diff --git a/commands/ash/mksignames.c b/commands/ash/mksignames.c index 640fcfd14..bbead25e1 100755 --- a/commands/ash/mksignames.c +++ b/commands/ash/mksignames.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -35,23 +35,23 @@ */ #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mksignames.c 5.1 (Berkeley) 3/7/91"; +static char sccsid[] = "@(#)mksignames.c 8.1 (Berkeley) 5/31/93"; #endif /* not lint */ /* * This program generates the signames.h and signames.c files. */ -#include #include +#include #include - +int main(int argc, char *argv[]); struct sig { int signo; /* signal number */ @@ -198,3 +198,7 @@ main(argc, argv) char **argv; { fprintf(cfile, "};\n"); exit(0); } + +/* + * $PchId: mksignames.c,v 1.2 2001/05/14 19:22:26 philip Exp $ + */ diff --git a/commands/ash/mksyntax.c b/commands/ash/mksyntax.c index 5b26fc004..71aadd557 100755 --- a/commands/ash/mksyntax.c +++ b/commands/ash/mksyntax.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -34,23 +30,33 @@ * SUCH DAMAGE. */ +#if 0 #ifndef lint -char copyright[] = -"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ - All rights reserved.\n"; +static char const copyright[] = +"@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint -static char sccsid[] = "@(#)mksyntax.c 5.2 (Berkeley) 3/8/91"; +static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95"; #endif /* not lint */ +#endif +/* +__FBSDID("$FreeBSD: src/bin/sh/mksyntax.c,v 1.23 2004/04/06 20:06:51 markm Exp $"); +*/ /* * This program creates syntax.h and syntax.c. */ #include +#include +#include #include "parser.h" +#ifdef __minix +#define __unused +#endif struct synclass { char *name; @@ -59,19 +65,21 @@ struct synclass { /* Syntax classes */ struct synclass synclass[] = { - "CWORD", "character is nothing special", - "CNL", "newline character", - "CBACK", "a backslash character", - "CSQUOTE", "single quote", - "CDQUOTE", "double quote", - "CENDQUOTE", "a terminating quote", - "CBQUOTE", "backwards single quote", - "CVAR", "a dollar sign", - "CENDVAR", "a '}' character", - "CEOF", "end of file", - "CCTL", "like CWORD, except it must be escaped", - "CSPCL", "these terminate a word", - NULL, NULL + { "CWORD", "character is nothing special" }, + { "CNL", "newline character" }, + { "CBACK", "a backslash character" }, + { "CSQUOTE", "single quote" }, + { "CDQUOTE", "double quote" }, + { "CENDQUOTE", "a terminating quote" }, + { "CBQUOTE", "backwards single quote" }, + { "CVAR", "a dollar sign" }, + { "CENDVAR", "a '}' character" }, + { "CLP", "a left paren in arithmetic" }, + { "CRP", "a right paren in arithmetic" }, + { "CEOF", "end of file" }, + { "CCTL", "like CWORD, except it must be escaped" }, + { "CSPCL", "these terminate a word" }, + { NULL, NULL } }; @@ -80,31 +88,39 @@ struct synclass synclass[] = { * you may have to change the definition of the is_in_name macro. */ struct synclass is_entry[] = { - "ISDIGIT", "a digit", - "ISUPPER", "an upper case letter", - "ISLOWER", "a lower case letter", - "ISUNDER", "an underscore", - "ISSPECL", "the name of a special parameter", - NULL, NULL, + { "ISDIGIT", "a digit" }, + { "ISUPPER", "an upper case letter" }, + { "ISLOWER", "a lower case letter" }, + { "ISUNDER", "an underscore" }, + { "ISSPECL", "the name of a special parameter" }, + { NULL, NULL } }; -char writer[] = "\ +static char writer[] = "\ /*\n\ * This file was generated by the mksyntax program.\n\ */\n\ \n"; -FILE *cfile; -FILE *hfile; -char *syntax[513]; -int base; -int size; /* number of values which a char variable can have */ -int nbits; /* number of bits in a character */ -int digit_contig; /* true if digits are contiguous */ +static FILE *cfile; +static FILE *hfile; +static char *syntax[513]; +static int base; +static int size; /* number of values which a char variable can have */ +static int nbits; /* number of bits in a character */ +static int digit_contig;/* true if digits are contiguous */ +static void filltable(char *); +static void init(void); +static void add(char *, char *); +static void print(char *); +static void output_type_macros(void); +static void digit_convert(void); -main() { +int +main(int argc __unused, char **argv __unused) +{ char c; char d; int sign; @@ -136,7 +152,9 @@ main() { if (d == c) break; } +#if 0 printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits); +#endif if (nbits > 9) { fputs("Characters can't have more than 9 bits\n", stderr); exit(2); @@ -151,14 +169,14 @@ main() { digit_contig = 0; } - fputs("#include \n", hfile); + fputs("#include \n", hfile); /* Generate the #define statements in the header file */ fputs("/* Syntax classes */\n", hfile); for (i = 0 ; synclass[i].name ; i++) { sprintf(buf, "#define %s %d", synclass[i].name, i); fputs(buf, hfile); - for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07) + for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07) putc('\t', hfile); fprintf(hfile, "/* %s */\n", synclass[i].comment); } @@ -167,7 +185,7 @@ main() { for (i = 0 ; is_entry[i].name ; i++) { sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i); fputs(buf, hfile); - for (pos = strlen(buf) ; pos < 32 ; pos = pos + 8 &~ 07) + for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07) putc('\t', hfile); fprintf(hfile, "/* %s */\n", is_entry[i].comment); } @@ -178,6 +196,7 @@ main() { fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile); fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile); fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile); + fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile); putc('\n', hfile); output_type_macros(); /* is_digit, etc. */ putc('\n', hfile); @@ -204,14 +223,28 @@ main() { add("`", "CBQUOTE"); add("$", "CVAR"); add("}", "CENDVAR"); - add("!*?[=", "CCTL"); + /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ + add("!*?[=~:/-", "CCTL"); print("dqsyntax"); init(); fputs("\n/* syntax table used when in single quotes */\n", cfile); add("\n", "CNL"); add("'", "CENDQUOTE"); - add("!*?[=", "CCTL"); + /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ + add("!*?[=~:/-", "CCTL"); print("sqsyntax"); + init(); + fputs("\n/* syntax table used when in arithmetic */\n", cfile); + add("\n", "CNL"); + add("\\", "CBACK"); + add("`", "CBQUOTE"); + add("'", "CSQUOTE"); + add("\"", "CDQUOTE"); + add("$", "CVAR"); + add("}", "CENDVAR"); + add("(", "CLP"); + add(")", "CRP"); + print("arisyntax"); filltable("0"); fputs("\n/* character classification table */\n", cfile); add("0123456789", "ISDIGIT"); @@ -231,9 +264,9 @@ main() { * Clear the syntax table. */ -filltable(dftval) - char *dftval; - { +static void +filltable(char *dftval) +{ int i; for (i = 0 ; i < size ; i++) @@ -245,7 +278,9 @@ filltable(dftval) * Initialize the syntax table with default values. */ -init() { +static void +init(void) +{ filltable("CWORD"); syntax[0] = "CEOF"; syntax[base + CTLESC] = "CCTL"; @@ -253,6 +288,9 @@ init() { syntax[base + CTLENDVAR] = "CCTL"; syntax[base + CTLBACKQ] = "CCTL"; syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL"; + syntax[base + CTLARI] = "CCTL"; + syntax[base + CTLENDARI] = "CCTL"; + syntax[base + CTLQUOTEMARK] = "CCTL"; } @@ -260,9 +298,9 @@ init() { * Add entries to the syntax table. */ -add(p, type) - char *p, *type; - { +static void +add(char *p, char *type) +{ while (*p) syntax[*p++ + base] = type; } @@ -273,9 +311,9 @@ add(p, type) * Output the syntax table. */ -print(name) - char *name; - { +static void +print(char *name) +{ int i; int col; @@ -306,16 +344,18 @@ print(name) * contiguous, we can test for them quickly. */ -char *macro[] = { +static char *macro[] = { "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)", - "#define is_alpha(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER))", - "#define is_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER))", - "#define is_in_name(c)\t((is_type+SYNBASE)[c] & (ISUPPER|ISLOWER|ISUNDER|ISDIGIT))", + "#define is_alpha(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && isalpha((unsigned char) (c)))", + "#define is_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalpha((unsigned char) (c))))", + "#define is_in_name(c)\t((c) != PEOF && ((c) < CTLESC || (c) > CTLQUOTEMARK) && ((c) == '_' || isalnum((unsigned char) (c))))", "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))", NULL }; -output_type_macros() { +static void +output_type_macros(void) +{ char **pp; if (digit_contig) @@ -334,7 +374,9 @@ output_type_macros() { * Output digit conversion table (if digits are not contiguous). */ -digit_convert() { +static void +digit_convert(void) +{ int maxdigit; static char digit[] = "0123456789"; char *p; @@ -350,7 +392,11 @@ digit_convert() { for (p = digit ; *p && *p != i ; p++); if (*p == '\0') p = digit; - fprintf(cfile, " %d,\n", p - digit); + fprintf(cfile, " %d,\n", (int)(p - digit)); } fputs("};\n", cfile); } + +/* + * $PchId: mksyntax.c,v 1.7 2006/05/23 12:04:27 philip Exp $ + */ diff --git a/commands/ash/mktokens b/commands/ash/mktokens index a9c33985c..e529902b4 100755 --- a/commands/ash/mktokens +++ b/commands/ash/mktokens @@ -1,7 +1,7 @@ #!/bin/sh - # -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -14,10 +14,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -34,7 +30,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)mktokens 5.1 (Berkeley) 3/7/91 +# @(#)mktokens 8.1 (Berkeley) 5/31/93 +# $FreeBSD: src/bin/sh/mktokens,v 1.9 2004/04/06 20:06:51 markm Exp $ # All calls to awk removed, because Minix bawk is deficient. (kjb) @@ -42,7 +39,9 @@ # token marks the end of a list. The third column is the name to print in # error messages. -cat > /tmp/ka$$ <<\! +#temp=`/usr/bin/mktemp -t ka` +temp=/tmp/mkt$$ +cat > $temp <<\! TEOF 1 end of file TNL 0 newline TSEMI 0 ";" @@ -70,16 +69,17 @@ TBEGIN 0 "{" TEND 1 "}" TCASE 0 "case" TESAC 1 "esac" +TNOT 0 "!" ! -nl=`wc -l /tmp/ka$$` -exec > token.def +nl=`wc -l $temp` +exec > token.h i=0 while read line do set -$- $line echo "#define $1 $i" i=`expr $i + 1` -done + +extern History *hist; +extern EditLine *el; +extern int displayhist; + +void histedit(void); +void sethistsize(const char *); +int histcmd(int, char **); +int bindcmd(int, char **); + +/* From libedit */ +void re_goto_bottom(EditLine *); + +/* + * $PchId: myhistedit.h,v 1.5 2006/03/29 15:55:18 philip Exp $ + */ + diff --git a/commands/ash/mystring.c b/commands/ash/mystring.c index 42635cf12..7957c333a 100755 --- a/commands/ash/mystring.c +++ b/commands/ash/mystring.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,14 @@ */ #ifndef lint -static char sccsid[] = "@(#)mystring.c 5.1 (Berkeley) 3/7/91"; +#if 0 +static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $"); +*/ /* * String functions. @@ -44,12 +46,11 @@ static char sccsid[] = "@(#)mystring.c 5.1 (Berkeley) 3/7/91"; * equal(s1, s2) Return true if strings are equal. * scopy(from, to) Copy a string. * scopyn(from, to, n) Like scopy, but checks for overflow. - * strchr(s, c) Find first occurance of c in s. - * bcopy(from, to, n) Copy a block of memory. * number(s) Convert a string of digits to an integer. * is_number(s) Return true if s is a string of digits. */ +#include #include "shell.h" #include "syntax.h" #include "error.h" @@ -58,6 +59,14 @@ static char sccsid[] = "@(#)mystring.c 5.1 (Berkeley) 3/7/91"; char nullstr[1]; /* zero length string */ +/* + * equal - #defined in mystring.h + */ + +/* + * scopy - #defined in mystring.h + */ + /* * scopyn - copy a string from "from" to "to", truncating the string @@ -66,11 +75,8 @@ char nullstr[1]; /* zero length string */ */ void -scopyn(from, to, size) - register char const *from; - register char *to; - register int size; - { +scopyn(const char *from, char *to, int size) +{ while (--size > 0) { if ((*to++ = *from++) == '\0') @@ -80,59 +86,13 @@ scopyn(from, to, size) } -/* - * strchr - find first occurrence of a character in a string. - */ - -#ifndef SYS5 -char * -mystrchr(s, charwanted) - char const *s; - register char charwanted; - { - register char const *scan; - - /* - * The odd placement of the two tests is so NUL is findable. - */ - for (scan = s ; *scan != charwanted ; ) /* ++ moved down for opt. */ - if (*scan++ == '\0') - return NULL; - return (char *)scan; -} -#endif - - - -/* - * bcopy - copy bytes - * - * This routine was derived from code by Henry Spencer. - */ - -void -mybcopy(src, dst, length) - pointer dst; - const pointer src; - register int length; - { - register char *d = dst; - register char *s = src; - - while (--length >= 0) - *d++ = *s++; -} - - /* * prefix -- see if pfx is a prefix of string. */ int -prefix(pfx, string) - register char const *pfx; - register char const *string; - { +prefix(const char *pfx, const char *string) +{ while (*pfx) { if (*pfx++ != *string++) return 0; @@ -147,12 +107,10 @@ prefix(pfx, string) */ int -number(s) - const char *s; - { - +number(const char *s) +{ if (! is_number(s)) - error2("Illegal number", (char *)s); + error("Illegal number: %s", (char *)s); return atoi(s); } @@ -163,12 +121,15 @@ number(s) */ int -is_number(p) - register const char *p; - { +is_number(const char *p) +{ do { if (! is_digit(*p)) return 0; } while (*++p != '\0'); return 1; } + +/* + * $PchId: mystring.c,v 1.4 2006/05/22 12:21:53 philip Exp $ + */ diff --git a/commands/ash/mystring.h b/commands/ash/mystring.h index 6eaa1df0b..9e9939cd0 100755 --- a/commands/ash/mystring.h +++ b/commands/ash/mystring.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,39 +29,20 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)mystring.h 5.1 (Berkeley) 3/7/91 + * @(#)mystring.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/mystring.h,v 1.8 2004/04/06 20:06:51 markm Exp $ */ -#ifndef SYSV -#define strchr mystrchr -#endif +#include -#ifdef __STDC__ void scopyn(const char *, char *, int); -char *strchr(const char *, int); -void mybcopy(const pointer, pointer, int); int prefix(const char *, const char *); int number(const char *); int is_number(const char *); -int strcmp(const char *, const char *); /* from C library */ -char *strcpy(char *, const char *); /* from C library */ -int strlen(const char *); /* from C library */ -char *strcat(char *, const char *); /* from C library */ -char *strerror(int); /* from C library */ -#else -void scopyn(); -char *strchr(); -void mybcopy(); -int prefix(); -int number(); -int is_number(); -int strcmp(); -char *strcpy(); -int strlen(); -char *strcat(); -char *strerror(); -#endif #define equal(s1, s2) (strcmp(s1, s2) == 0) #define scopy(s1, s2) ((void)strcpy(s2, s1)) -#define bcopy(src, dst, n) mybcopy((pointer)(src), (pointer)(dst), n) + +/* + * $PchId: mystring.h,v 1.3 2006/03/29 15:49:08 philip Exp $ + */ diff --git a/commands/ash/nodes.c.pat b/commands/ash/nodes.c.pat index 5193a295d..fb867053e 100755 --- a/commands/ash/nodes.c.pat +++ b/commands/ash/nodes.c.pat @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,9 +29,11 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)nodes.c.pat 5.2 (Berkeley) 3/8/91 + * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/nodes.c.pat,v 1.15 2004/04/06 20:06:51 markm Exp $ */ +#include /* * Routine for dealing with parsed shell commands. */ @@ -43,35 +41,26 @@ #include "shell.h" #include "nodes.h" #include "memalloc.h" -#include "machdep.h" #include "mystring.h" - -int funcblocksize; /* size of structures in function */ -int funcstringsize; /* size of strings in node */ -#ifdef __STDC__ -pointer funcblock; /* block to allocate function from */ -#else -char *funcblock; /* block to allocate function from */ +#ifndef __minix +#include #endif -char *funcstring; /* block to allocate strings from */ +#include "machdep.h" + +STATIC int funcblocksize; /* size of structures in function */ +STATIC int funcstringsize; /* size of strings in node */ +STATIC pointer funcblock; /* block to allocate function from */ +STATIC char *funcstring; /* block to allocate strings from */ %SIZES -#ifdef __STDC__ STATIC void calcsize(union node *); STATIC void sizenodelist(struct nodelist *); STATIC union node *copynode(union node *); STATIC struct nodelist *copynodelist(struct nodelist *); STATIC char *nodesavestr(char *); -#else -STATIC void calcsize(); -STATIC void sizenodelist(); -STATIC union node *copynode(); -STATIC struct nodelist *copynodelist(); -STATIC char *nodesavestr(); -#endif @@ -80,86 +69,81 @@ STATIC char *nodesavestr(); */ union node * -copyfunc(n) - union node *n; - { - if (n == NULL) - return NULL; - funcblocksize = 0; - funcstringsize = 0; - calcsize(n); - funcblock = ckmalloc(funcblocksize + funcstringsize); - funcstring = (char *)funcblock + funcblocksize; - return copynode(n); +copyfunc(union node *n) +{ + if (n == NULL) + return NULL; + funcblocksize = 0; + funcstringsize = 0; + calcsize(n); + funcblock = ckmalloc(funcblocksize + funcstringsize); + funcstring = (char *)funcblock + funcblocksize; + return copynode(n); } STATIC void -calcsize(n) - union node *n; - { - %CALCSIZE +calcsize(union node *n) +{ + %CALCSIZE } STATIC void -sizenodelist(lp) - struct nodelist *lp; - { - while (lp) { - funcblocksize += ALIGN(sizeof (struct nodelist)); - calcsize(lp->n); - lp = lp->next; - } +sizenodelist(struct nodelist *lp) +{ + while (lp) { + funcblocksize += ALIGN(sizeof(struct nodelist)); + calcsize(lp->n); + lp = lp->next; + } } STATIC union node * -copynode(n) - union node *n; - { - union node *new; +copynode(union node *n) +{ + union node *new; - %COPY - return new; + %COPY + return new; } STATIC struct nodelist * -copynodelist(lp) - struct nodelist *lp; - { - struct nodelist *start; - struct nodelist **lpp; +copynodelist(struct nodelist *lp) +{ + struct nodelist *start; + struct nodelist **lpp; - lpp = &start; - while (lp) { - *lpp = funcblock; - *(char **)&funcblock += ALIGN(sizeof (struct nodelist)); - (*lpp)->n = copynode(lp->n); - lp = lp->next; - lpp = &(*lpp)->next; - } - *lpp = NULL; - return start; + lpp = &start; + while (lp) { + *lpp = funcblock; + funcblock = (char *)funcblock + ALIGN(sizeof(struct nodelist)); + (*lpp)->n = copynode(lp->n); + lp = lp->next; + lpp = &(*lpp)->next; + } + *lpp = NULL; + return start; } STATIC char * -nodesavestr(s) - char *s; - { - register char *p = s; - register char *q = funcstring; - char *rtn = funcstring; +nodesavestr(char *s) +{ + char *p = s; + char *q = funcstring; + char *rtn = funcstring; - while (*q++ = *p++); - funcstring = q; - return rtn; + while ((*q++ = *p++) != '\0') + continue; + funcstring = q; + return rtn; } @@ -169,9 +153,12 @@ nodesavestr(s) */ void -freefunc(n) - union node *n; - { - if (n) - ckfree(n); +freefunc(union node *n) +{ + if (n) + ckfree(n); } + +/* + * $PchId: nodes.c.pat,v 1.5 2006/05/22 12:43:57 philip Exp $ + */ diff --git a/commands/ash/nodetypes b/commands/ash/nodetypes index b7c680c7e..2c25c1d33 100755 --- a/commands/ash/nodetypes +++ b/commands/ash/nodetypes @@ -1,7 +1,6 @@ -#!/bin/sh - # -# Copyright (c) 1991 The Regents of the University of California. -# All rights reserved. +# 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. @@ -14,10 +13,6 @@ # 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. -# 3. All advertising materials mentioning features or use of this software -# must display the following acknowledgement: -# This product includes software developed by the University of -# California, Berkeley and its contributors. # 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. @@ -34,7 +29,8 @@ # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # -# @(#)nodetypes 5.1 (Berkeley) 3/7/91 +# @(#)nodetypes 8.2 (Berkeley) 5/4/95 +# $FreeBSD: src/bin/sh/nodetypes,v 1.9 2004/04/06 20:06:51 markm Exp $ # This file describes the nodes used in parse trees. Unindented lines # contain a node type followed by a structure tag. Subsequent indented @@ -118,7 +114,9 @@ NARG narg # represents a word NTO nfile # fd> fname NFROM nfile # fd< fname +NFROMTO nfile # fd<> fname NAPPEND nfile # fd>> fname +NCLOBBER nfile # fd>| fname type int next nodeptr # next redirection in list fd int # file descriptor being redirected @@ -131,6 +129,8 @@ NFROMFD ndup # fd>&dupfd next nodeptr # next redirection in list fd int # file descriptor being redirected dupfd int # file descriptor to duplicate + vname nodeptr # file name if fd>&$var + NHERE nhere # fd<<\! NXHERE nhere # fd< +__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include +#include #include "shell.h" #define DEFINE_OPTIONS @@ -52,25 +58,24 @@ static char sccsid[] = "@(#)options.c 5.2 (Berkeley) 3/13/91"; #include "memalloc.h" #include "error.h" #include "mystring.h" +#include "builtins.h" +#if !defined(NO_HISTORY) && !defined(EDITLINE) +#include "myhistedit.h" +#endif char *arg0; /* value of $0 */ struct shparam shellparam; /* current positional parameters */ char **argptr; /* argument list for builtin commands */ -char *optarg; /* set by nextopt (like getopt) */ +char *shoptarg; /* set by nextopt (like getopt) */ char *optptr; /* used by nextopt */ -int editable; /* isatty(0) && isatty(1) */ char *minusc; /* argument to -c option */ -#ifdef __STDC__ STATIC void options(int); +STATIC void minus_o(char *, int); STATIC void setoption(int, int); -#else -STATIC void options(); -STATIC void setoption(); -#endif - +STATIC int getopts(char *, char *, char **, char ***, char **); /* @@ -78,46 +83,55 @@ STATIC void setoption(); */ void -procargs(argc, argv) - char **argv; - { - char *p; +procargs(int argc, char **argv) +{ + int i; argptr = argv; if (argc > 0) argptr++; - for (p = optval ; p < optval + sizeof optval - 1 ; p++) - *p = 2; + for (i = 0; i < NOPTS; i++) + optlist[i].val = 2; + privileged = (getuid() != geteuid() || getgid() != getegid()); options(1); if (*argptr == NULL && minusc == NULL) sflag = 1; - editable = (isatty(0) && isatty(1)); - if (iflag == 2 && sflag == 1 && editable) + if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) iflag = 1; - if (jflag == 2) - jflag = iflag; - for (p = optval ; p < optval + sizeof optval - 1 ; p++) - if (*p == 2) - *p = 0; + if (mflag == 2) + mflag = iflag; + for (i = 0; i < NOPTS; i++) + if (optlist[i].val == 2) + optlist[i].val = 0; arg0 = argv[0]; - if (sflag == 0) { - arg0 = *argptr++; - if (minusc == NULL) { - commandname = arg0; - setinputfile(commandname, 0); - } + if (sflag == 0 && minusc == NULL) { + commandname = arg0 = *argptr++; + setinputfile(commandname, 0); } + /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ + if (argptr && minusc && *argptr) + arg0 = *argptr++; + shellparam.p = argptr; + shellparam.reset = 1; /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ while (*argptr) { shellparam.nparam++; argptr++; } - setinteractive(iflag); - setjobctl(jflag); + optschanged(); } +void +optschanged(void) +{ + setinteractive(iflag); +#if !defined(NO_HISTORY) && !defined(EDITLINE) + histedit(); +#endif + setjobctl(mflag); +} /* * Process shell options. The global variable argptr contains a pointer @@ -125,8 +139,9 @@ procargs(argc, argv) */ STATIC void -options(cmdline) { - register char *p; +options(int cmdline) +{ + char *p; int val; int c; @@ -136,14 +151,14 @@ options(cmdline) { argptr++; if ((c = *p++) == '-') { val = 1; - if (p[0] == '\0' || p[0] == '-' && p[1] == '\0') { + if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { if (!cmdline) { /* "-" means turn off -x and -v */ if (p[0] == '\0') xflag = vflag = 0; /* "--" means reset params */ else if (*argptr == NULL) - setparam(argptr); + setparam(argptr); } break; /* "-" or "--" terminates options */ } @@ -166,26 +181,79 @@ options(cmdline) { #ifdef NOHACK break; #endif + } else if (c == 'o') { + minus_o(*argptr, val); + if (*argptr) + argptr++; } else { + if (c == 'p' && !val && privileged) { + (void) setuid(getuid()); + (void) setgid(getgid()); + } setoption(c, val); } } - if (! cmdline) - break; + } +} + +STATIC void +minus_o(char *name, int val) +{ + int doneset, i; + + if (name == NULL) { + if (val) { + /* "Pretty" output. */ + out1str("Current option settings\n"); + for (i = 0; i < NOPTS; i++) + out1fmt("%-16s%s\n", optlist[i].name, + optlist[i].val ? "on" : "off"); + } else { + /* Output suitable for re-input to shell. */ + for (doneset = i = 0; i < NOPTS; i++) + if (optlist[i].val) { + if (!doneset) { + out1str("set"); + doneset = 1; + } + out1fmt(" -o %s", optlist[i].name); + } + if (doneset) + out1c('\n'); + } + } else { + for (i = 0; i < NOPTS; i++) + if (equal(name, optlist[i].name)) { + if (!val && privileged && equal(name, "privileged")) { + (void) setuid(getuid()); + (void) setgid(getgid()); + } + setoption(optlist[i].letter, val); + return; + } + error("Illegal option -o %s", name); } } STATIC void -setoption(flag, val) - char flag; - int val; - { - register char *p; +setoption(int flag, int val) +{ + int i; - if ((p = strchr(optchar, flag)) == NULL) - error("Illegal option -%c", flag); - optval[p - optchar] = val; + for (i = 0; i < NOPTS; i++) + if (optlist[i].letter == flag) { + optlist[i].val = val; + if (val) { + /* #%$ hack for ksh semantics */ + if (flag == 'V') + Eflag = 0; + else if (flag == 'E') + Vflag = 0; + } + return; + } + error("Illegal option -%c", flag); } @@ -194,10 +262,12 @@ setoption(flag, val) INCLUDE "options.h" SHELLPROC { - char *p; + int i; + + for (i = 0; i < NOPTS; i++) + optlist[i].val = 0; + optschanged(); - for (p = optval ; p < optval + sizeof optval ; p++) - *p = 0; } #endif @@ -207,9 +277,8 @@ SHELLPROC { */ void -setparam(argv) - char **argv; - { +setparam(char **argv) +{ char **newparam; char **ap; int nparam; @@ -233,9 +302,8 @@ setparam(argv) */ void -freeparam(param) - struct shparam *param; - { +freeparam(struct shparam *param) +{ char **ap; if (param->malloc) { @@ -251,7 +319,9 @@ freeparam(param) * The shift builtin command. */ -shiftcmd(argc, argv) char **argv; { +int +shiftcmd(int argc, char **argv) +{ int n; char **ap1, **ap2; @@ -259,7 +329,7 @@ shiftcmd(argc, argv) char **argv; { if (argc > 1) n = number(argv[1]); if (n > shellparam.nparam) - n = shellparam.nparam; + error("can't shift that many"); INTOFF; shellparam.nparam -= n; for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { @@ -279,13 +349,14 @@ shiftcmd(argc, argv) char **argv; { * The set command builtin. */ -setcmd(argc, argv) char **argv; { +int +setcmd(int argc, char **argv) +{ if (argc == 1) return showvarscmd(argc, argv); INTOFF; options(0); - setinteractive(iflag); - setjobctl(jflag); + optschanged(); if (*argptr != NULL) { setparam(argptr); } @@ -294,6 +365,15 @@ setcmd(argc, argv) char **argv; { } +void +getoptsreset(const char *value) +{ + if (number(value) == 1) { + shellparam.optnext = NULL; + shellparam.reset = 1; + } +} + /* * The getopts builtin. Shellparam.optnext points to the next argument * to be processed. Shellparam.optptr points to the next character to @@ -301,63 +381,127 @@ setcmd(argc, argv) char **argv; { * then it's the first time getopts has been called. */ -getoptscmd(argc, argv) char **argv; { - register char *p, *q; - char c; +int +getoptscmd(int argc, char **argv) +{ + char **optbase = NULL; + + if (argc < 3) + error("usage: getopts optstring var [arg]"); + else if (argc == 3) + optbase = shellparam.p; + else + optbase = &argv[3]; + + if (shellparam.reset == 1) { + shellparam.optnext = optbase; + shellparam.optptr = NULL; + shellparam.reset = 0; + } + + return getopts(argv[1], argv[2], optbase, &shellparam.optnext, + &shellparam.optptr); +} + +STATIC int +getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, + char **optptr) +{ + char *p, *q; + char c = '?'; + int done = 0; + int ind = 0; + int err = 0; char s[10]; - if (argc != 3) - error("Usage: getopts optstring var"); - if (shellparam.optnext == NULL) { - shellparam.optnext = shellparam.p; - shellparam.optptr = NULL; - } - if ((p = shellparam.optptr) == NULL || *p == '\0') { - p = *shellparam.optnext; + if ((p = *optptr) == NULL || *p == '\0') { + /* Current word is done, advance */ + if (*optnext == NULL) + return 1; + p = **optnext; if (p == NULL || *p != '-' || *++p == '\0') { atend: - fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); - setvar("OPTIND", s, 0); - shellparam.optnext = NULL; - return 1; + ind = *optnext - optfirst + 1; + *optnext = NULL; + p = NULL; + done = 1; + goto out; } - shellparam.optnext++; + (*optnext)++; if (p[0] == '-' && p[1] == '\0') /* check for "--" */ goto atend; } + c = *p++; - for (q = argv[1] ; *q != c ; ) { + for (q = optstr; *q != c; ) { if (*q == '\0') { - out1fmt("Illegal option -%c\n", c); + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; + err |= setvarsafe("OPTARG", s, 0); + } + else { + out1fmt("Illegal option -%c\n", c); + (void) unsetvar("OPTARG"); + } c = '?'; - goto out; + goto bad; } if (*++q == ':') q++; } + if (*++q == ':') { - if (*p == '\0') { - if ((p = *shellparam.optnext) == NULL) { - out1fmt("No arg for -%c option\n", c); - c = '?'; - goto out; + if (*p == '\0' && (p = **optnext) == NULL) { + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; + err |= setvarsafe("OPTARG", s, 0); + c = ':'; } - shellparam.optnext++; + else { + out1fmt("No arg for -%c option\n", c); + (void) unsetvar("OPTARG"); + c = '?'; + } + goto bad; } - setvar("OPTARG", p, 0); - p = ""; + + if (p == **optnext) + (*optnext)++; + setvarsafe("OPTARG", p, 0); + p = NULL; } + else + setvarsafe("OPTARG", "", 0); + ind = *optnext - optfirst + 1; + goto out; + +bad: + ind = 1; + *optnext = NULL; + p = NULL; out: - shellparam.optptr = p; + *optptr = p; + fmtstr(s, sizeof(s), "%d", ind); + err |= setvarsafe("OPTIND", s, VNOFUNC); s[0] = c; s[1] = '\0'; - setvar(argv[2], s, 0); - fmtstr(s, 10, "%d", shellparam.optnext - shellparam.p + 1); - setvar("OPTIND", s, 0); - return 0; + err |= setvarsafe(optvar, s, 0); + if (err) { + *optnext = NULL; + *optptr = NULL; + flushall(); + exraise(EXERROR); + } + return done; } /* + * XXX - should get rid of. have all builtins use getopt(3). the + * library getopt must have the BSD extension static variable "optreset" + * otherwise it can't be used within the shell safely. + * * Standard option processing (a la getopt) for builtin routines. The * only argument that is passed to nextopt is the option string; the * other arguments are unnecessary. It return the character, or '\0' on @@ -365,10 +509,9 @@ out: */ int -nextopt(optstring) - char *optstring; - { - register char *p, *q; +nextopt(char *optstring) +{ + char *p, *q; char c; if ((p = optptr) == NULL || *p == '\0') { @@ -389,9 +532,13 @@ nextopt(optstring) if (*++q == ':') { if (*p == '\0' && (p = *argptr++) == NULL) error("No arg for -%c option", c); - optarg = p; + shoptarg = p; p = NULL; } optptr = p; return c; } + +/* + * $PchId: options.c,v 1.5 2006/05/22 12:23:10 philip Exp $ + */ diff --git a/commands/ash/options.h b/commands/ash/options.h index 7d86de33d..27b461a88 100755 --- a/commands/ash/options.h +++ b/commands/ash/options.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,38 +29,71 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)options.h 5.1 (Berkeley) 3/7/91 + * @(#)options.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/options.h,v 1.13 2004/04/06 20:06:51 markm Exp $ */ struct shparam { - int nparam; /* number of positional parameters (without $0) */ - char malloc; /* true if parameter list dynamicly allocated */ + int nparam; /* # of positional parameters (without $0) */ + unsigned char malloc; /* if parameter list dynamically allocated */ + unsigned char reset; /* if getopts has been reset */ char **p; /* parameter list */ - char **optnext; /* next parameter to be processed by getopts */ - char *optptr; /* used by getopts */ + char **optnext; /* next parameter to be processed by getopts */ + char *optptr; /* used by getopts */ }; -#define eflag optval[0] -#define fflag optval[1] -#define Iflag optval[2] -#define iflag optval[3] -#define jflag optval[4] -#define nflag optval[5] -#define sflag optval[6] -#define xflag optval[7] -#define zflag optval[8] -#define vflag optval[9] +#define eflag optlist[0].val +#define fflag optlist[1].val +#define Iflag optlist[2].val +#define iflag optlist[3].val +#define mflag optlist[4].val +#define nflag optlist[5].val +#define sflag optlist[6].val +#define xflag optlist[7].val +#define vflag optlist[8].val +#define Vflag optlist[9].val +#define Eflag optlist[10].val +#define Cflag optlist[11].val +#define aflag optlist[12].val +#define bflag optlist[13].val +#define uflag optlist[14].val +#define privileged optlist[15].val +#define Tflag optlist[16].val +#define Pflag optlist[17].val -#define NOPTS 10 +#define NOPTS 18 + +struct optent { + const char *name; + const char letter; + char val; +}; #ifdef DEFINE_OPTIONS -const char optchar[NOPTS+1] = "efIijnsxzv"; /* shell flags */ -char optval[NOPTS+1]; /* values of option flags */ +struct optent optlist[NOPTS] = { + { "errexit", 'e', 0 }, + { "noglob", 'f', 0 }, + { "ignoreeof", 'I', 0 }, + { "interactive",'i', 0 }, + { "monitor", 'm', 0 }, + { "noexec", 'n', 0 }, + { "stdin", 's', 0 }, + { "xtrace", 'x', 0 }, + { "verbose", 'v', 0 }, + { "vi", 'V', 0 }, + { "emacs", 'E', 0 }, + { "noclobber", 'C', 0 }, + { "allexport", 'a', 0 }, + { "notify", 'b', 0 }, + { "nounset", 'u', 0 }, + { "privileged", 'p', 0 }, + { "trapsasync", 'T', 0 }, + { "physical", 'P', 0 }, +}; #else -extern const char optchar[NOPTS+1]; -extern char optval[NOPTS+1]; +extern struct optent optlist[NOPTS]; #endif @@ -72,19 +101,19 @@ extern char *minusc; /* argument to -c option */ extern char *arg0; /* $0 */ extern struct shparam shellparam; /* $@ */ extern char **argptr; /* argument list for builtin commands */ -extern char *optarg; /* set by nextopt */ +extern char *shoptarg; /* set by nextopt */ extern char *optptr; /* used by nextopt */ -extern int editable; /* isatty(0) && isatty(1) */ - -#ifdef __STDC__ void procargs(int, char **); +void optschanged(void); void setparam(char **); void freeparam(struct shparam *); +int shiftcmd(int, char **); +int setcmd(int, char **); +int getoptscmd(int, char **); int nextopt(char *); -#else -void procargs(); -void setparam(); -void freeparam(); -int nextopt(); -#endif +void getoptsreset(const char *); + +/* + * $PchId: options.h,v 1.4 2006/03/29 15:37:43 philip Exp $ + */ diff --git a/commands/ash/output.c b/commands/ash/output.c index 03e48e474..fb89e2ade 100755 --- a/commands/ash/output.c +++ b/commands/ash/output.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,7 +31,7 @@ */ #ifndef lint -static char sccsid[] = "@(#)output.c 5.1 (Berkeley) 3/7/91"; +static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93"; #endif /* not lint */ /* @@ -55,12 +51,16 @@ static char sccsid[] = "@(#)output.c 5.1 (Berkeley) 3/7/91"; #include "output.h" #include "memalloc.h" #include "error.h" +#include "var.h" #ifdef __STDC__ #include "stdarg.h" #else #include #endif #include +#include +#include +#include #define OUTBUFSIZ BUFSIZ @@ -115,27 +115,63 @@ open_mem(block, length, file) void out1str(p) - char *p; + const char *p; { outstr(p, out1); } +void +out1qstr(const char *p) +{ + outqstr(p, out1); +} + void -out2str(p) - char *p; - { +out2str(const char *p) +{ outstr(p, out2); } void outstr(p, file) - register char *p; + register const char *p; register struct output *file; { while (*p) outc(*p++, file); + if (file == out2) + flushout(file); +} + +/* Like outstr(), but quote for re-input into the shell. */ +void +outqstr(const char *p, struct output *file) +{ + char ch; + + if (p[strcspn(p, "|&;<>()$`\\\"'")] == '\0' && (!ifsset() || + p[strcspn(p, ifsval())] == '\0')) { + outstr(p, file); + return; + } + + out1c('\''); + while ((ch = *p++) != '\0') { + switch (ch) { + case '\'': + /* + * Can't quote single quotes inside single quotes; + * close them, write escaped single quote, open again. + */ + outstr("'\\''", file); + break; + default: + outc(ch, file); + } + } + out1c('\''); } @@ -208,7 +244,8 @@ freestdout() { #ifdef __STDC__ void -outfmt(struct output *file, char *fmt, ...) { +outfmt(struct output *file, const char *fmt, ...) +{ va_list ap; va_start(ap, fmt); @@ -218,7 +255,8 @@ outfmt(struct output *file, char *fmt, ...) { void -out1fmt(char *fmt, ...) { +out1fmt(const char *fmt, ...) +{ va_list ap; va_start(ap, fmt); @@ -226,9 +264,20 @@ out1fmt(char *fmt, ...) { va_end(ap); } +void +dprintf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + doformat(out2, fmt, ap); + va_end(ap); + flushout(out2); +} void -fmtstr(char *outbuf, int length, char *fmt, ...) { +fmtstr(char *outbuf, int length, const char *fmt, ...) +{ va_list ap; struct output strout; @@ -275,6 +324,19 @@ out1fmt(va_alist) va_end(ap); } +void +dprintf(va_alist) + va_dcl + { + va_list ap; + char *fmt; + + va_start(ap); + fmt = va_arg(ap, char *); + doformat(out2, fmt, ap); + va_end(ap); + flushout(out2); +} void fmtstr(va_alist) @@ -325,11 +387,8 @@ static const char digit[17] = "0123456789ABCDEF"; void -doformat(dest, f, ap) - register struct output *dest; - register char *f; /* format string */ - va_list ap; - { +doformat(struct output *dest, const char *f, va_list ap) +{ register char c; char temp[TEMPSIZE]; int flushleft; @@ -517,15 +576,6 @@ xwrite(fd, buf, nbytes) } } - /* - * Version of ioctl that retries after a signal is caught. + * $PchId: output.c,v 1.6 2006/05/22 12:46:03 philip Exp $ */ - -int -xioctl(fd, request, arg) { - int i; - - while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); - return i; -} diff --git a/commands/ash/output.h b/commands/ash/output.h index b8b814c3e..44b8b2a28 100755 --- a/commands/ash/output.h +++ b/commands/ash/output.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,11 +29,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)output.h 5.1 (Berkeley) 3/7/91 + * @(#)output.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/output.h,v 1.13 2004/04/06 20:06:51 markm Exp $ */ #ifndef OUTPUT_INCL +#include + struct output { char *nextc; int nleft; @@ -53,38 +52,27 @@ extern struct output memout; extern struct output *out1; extern struct output *out2; +#ifndef __printflike +#define __printflike(a,b) +#endif -#ifdef __STDC__ -void outstr(char *, struct output *); -void out1str(char *); -void out2str(char *); -void outfmt(struct output *, char *, ...); -void out1fmt(char *, ...); -void fmtstr(char *, int, char *, ...); -/* void doformat(struct output *, char *, va_list); */ -void doformat(); +void open_mem(char *, int, struct output *); +void out1str(const char *); +void out1qstr(const char *); +void out2str(const char *); +void out2qstr(const char *); +void outstr(const char *, struct output *); +void outqstr(const char *, struct output *); void emptyoutbuf(struct output *); void flushall(void); void flushout(struct output *); void freestdout(void); +void outfmt(struct output *, const char *, ...) __printflike(2, 3); +void out1fmt(const char *, ...) __printflike(1, 2); +void dprintf(const char *, ...) __printflike(1, 2); +void fmtstr(char *, int, const char *, ...) __printflike(3, 4); +void doformat(struct output *, const char *, va_list) __printflike(2, 0); int xwrite(int, char *, int); -int xioctl(int, int, int); -#else -void outstr(); -void out1str(); -void out2str(); -void outfmt(); -void out1fmt(); -void fmtstr(); -/* void doformat(); */ -void doformat(); -void emptyoutbuf(); -void flushall(); -void flushout(); -void freestdout(); -int xwrite(); -int xioctl(); -#endif #define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c))) #define out1c(c) outc(c, out1); @@ -92,3 +80,7 @@ int xioctl(); #define OUTPUT_INCL #endif + +/* + * $PchId: output.h,v 1.5 2006/05/23 12:04:54 philip Exp $ + */ diff --git a/commands/ash/parser.c b/commands/ash/parser.c index 318a8a45d..d837829ff 100755 --- a/commands/ash/parser.c +++ b/commands/ash/parser.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,14 +31,22 @@ */ #ifndef lint -static char sccsid[] = "@(#)parser.c 5.3 (Berkeley) 4/12/91"; +#if 0 +static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/parser.c,v 1.51.2.1 2005/03/03 03:43:20 obrien Exp $"); +*/ + +#include +#include #include "shell.h" #include "parser.h" #include "nodes.h" #include "expand.h" /* defines rmescapes() */ -#include "redir.h" /* defines copyfd() */ #include "syntax.h" #include "options.h" #include "input.h" @@ -51,16 +55,22 @@ static char sccsid[] = "@(#)parser.c 5.3 (Berkeley) 4/12/91"; #include "error.h" #include "memalloc.h" #include "mystring.h" - +#include "alias.h" +#include "show.h" +#include "eval.h" +#if !defined(NO_HISTORY) && !defined(EDITLINE) +#include "myhistedit.h" +#endif /* * Shell command parser. */ -#define EOFMARKLEN 79 +#define EOFMARKLEN 79 +#define PROMPTLEN 128 /* values returned by readtoken */ -#include "token.def" +#include "token.h" @@ -73,20 +83,22 @@ struct heredoc { -struct heredoc *heredoclist; /* list of here documents to read */ -int parsebackquote; /* nonzero if we are inside backquotes */ -int doprompt; /* if set, prompt the user */ -int needprompt; /* true if interactive and at start of line */ -int lasttoken; /* last token read */ +STATIC struct heredoc *heredoclist; /* list of here documents to read */ +STATIC int parsebackquote; /* nonzero if we are inside backquotes */ +STATIC int doprompt; /* if set, prompt the user */ +STATIC int needprompt; /* true if interactive and at start of line */ +STATIC int lasttoken; /* last token read */ MKINIT int tokpushback; /* last token pushed back */ -char *wordtext; /* text of last word returned by readtoken */ -int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ -struct nodelist *backquotelist; -union node *redirnode; -struct heredoc *heredoc; -int quoteflag; /* set if (part of) last token was quoted */ -int startlinno; /* line # where last token started */ +STATIC char *wordtext; /* text of last word returned by readtoken */ +MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ +STATIC struct nodelist *backquotelist; +STATIC union node *redirnode; +STATIC struct heredoc *heredoc; +STATIC int quoteflag; /* set if (part of) last token was quoted */ +STATIC int startlinno; /* line # where last token started */ +/* XXX When 'noaliases' is set to one, no alias expansion takes place. */ +static int noaliases = 0; #define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ #ifdef GDB_HACK @@ -95,27 +107,22 @@ static const char types[] = "}-+?="; #endif -STATIC union node *list __P((int)); -STATIC union node *andor __P((void)); -STATIC union node *pipeline __P((void)); -STATIC union node *command __P((void)); -STATIC union node *simplecmd __P((union node **, union node *)); -STATIC void parsefname __P((void)); -STATIC void parseheredoc __P((void)); -STATIC int readtoken __P((void)); -STATIC int readtoken1 __P((int, char const *, char *, int)); -STATIC void attyline __P((void)); -STATIC int noexpand __P((char *)); -STATIC void synexpect __P((int)); -STATIC void synerror __P((char *)); - -#if ATTY || READLINE -STATIC void putprompt __P((char *)); -#else /* not ATTY */ -#define putprompt(s) out2str(s) -#endif - - +STATIC union node *list(int); +STATIC union node *andor(void); +STATIC union node *pipeline(void); +STATIC union node *command(void); +STATIC union node *simplecmd(union node **, union node *); +STATIC union node *makename(void); +STATIC void parsefname(void); +STATIC void parseheredoc(void); +STATIC int peektoken(void); +STATIC int readtoken(void); +STATIC int xxreadtoken(void); +STATIC int readtoken1(int, char const *, char *, int); +STATIC int noexpand(char *); +STATIC void synexpect(int); +STATIC void synerror(char *); +STATIC void setprompt(int); /* @@ -124,15 +131,21 @@ STATIC void putprompt __P((char *)); */ union node * -parsecmd(interact) { +parsecmd(int interact) +{ int t; extern int exitstatus; + tokpushback = 0; doprompt = interact; if (doprompt) - putprompt(exitstatus == 0 ? ps1val() : pseval()); + setprompt(exitstatus == 0 || (vpse.flags & VUNSET) + ? 1 : -1); + else + setprompt(0); needprompt = 0; - if ((t = readtoken()) == TEOF) + t = readtoken(); + if (t == TEOF) return NEOF; if (t == TNL) return NULL; @@ -142,36 +155,48 @@ parsecmd(interact) { STATIC union node * -list(nlflag) { - union node *n1, *n2, *n3, **pn; - int first; +list(int nlflag) +{ + union node *n1, *n2, *n3; + int tok; checkkwd = 2; if (nlflag == 0 && tokendlist[peektoken()]) return NULL; - n1 = andor(); - for (first = 1; ; first = 0) { - switch (readtoken()) { - case TBACKGND: - pn = &n1; - if (!first && n1->type == NSEMI) pn = &n1->nbinary.ch2; - if ((*pn)->type == NCMD || (*pn)->type == NPIPE) { - (*pn)->ncmd.backgnd = 1; - } else if ((*pn)->type == NREDIR) { - (*pn)->type = NBACKGND; + n1 = NULL; + for (;;) { + n2 = andor(); + tok = readtoken(); + if (tok == TBACKGND) { + if (n2->type == NCMD || n2->type == NPIPE) { + n2->ncmd.backgnd = 1; + } else if (n2->type == NREDIR) { + n2->type = NBACKGND; } else { n3 = (union node *)stalloc(sizeof (struct nredir)); n3->type = NBACKGND; - n3->nredir.n = *pn; + n3->nredir.n = n2; n3->nredir.redirect = NULL; - *pn = n3; + n2 = n3; } - goto tsemi; + } + if (n1 == NULL) { + n1 = n2; + } + else { + n3 = (union node *)stalloc(sizeof (struct nbinary)); + n3->type = NSEMI; + n3->nbinary.ch1 = n1; + n3->nbinary.ch2 = n2; + n1 = n3; + } + switch (tok) { + case TBACKGND: + case TSEMI: + tok = readtoken(); + /* FALLTHROUGH */ case TNL: - tokpushback++; - /* fall through */ -tsemi: case TSEMI: - if (readtoken() == TNL) { + if (tok == TNL) { parseheredoc(); if (nlflag) return n1; @@ -181,12 +206,6 @@ tsemi: case TSEMI: checkkwd = 2; if (tokendlist[peektoken()]) return n1; - n2 = andor(); - n3 = (union node *)stalloc(sizeof (struct nbinary)); - n3->type = NSEMI; - n3->nbinary.ch1 = n1; - n3->nbinary.ch2 = n2; - n1 = n3; break; case TEOF: if (heredoclist) @@ -206,7 +225,8 @@ tsemi: case TSEMI: STATIC union node * -andor() { +andor(void) +{ union node *n1, *n2, *n3; int t; @@ -232,10 +252,17 @@ andor() { STATIC union node * -pipeline() { - union node *n1, *pipenode; +pipeline(void) +{ + union node *n1, *n2, *pipenode; struct nodelist *lp, *prev; + int negate; + negate = 0; + TRACE(("pipeline: entered\n")); + while (readtoken() == TNOT) + negate = !negate; + tokpushback++; n1 = command(); if (readtoken() == TPIPE) { pipenode = (union node *)stalloc(sizeof (struct npipe)); @@ -254,22 +281,31 @@ pipeline() { n1 = pipenode; } tokpushback++; - return n1; + if (negate) { + n2 = (union node *)stalloc(sizeof (struct nnot)); + n2->type = NNOT; + n2->nnot.com = n1; + return n2; + } else + return n1; } STATIC union node * -command() { +command(void) +{ union node *n1, *n2; union node *ap, **app; union node *cp, **cpp; union node *redir, **rpp; - int t; + int t, negate = 0; checkkwd = 2; - redir = 0; + redir = NULL; + n1 = NULL; rpp = &redir; + /* Check for redirection which may precede command */ while (readtoken() == TREDIR) { *rpp = n2 = redirnode; @@ -278,11 +314,18 @@ command() { } tokpushback++; + while (readtoken() == TNOT) { + TRACE(("command: TNOT recognized\n")); + negate = !negate; + } + tokpushback++; + switch (readtoken()) { case TIF: n1 = (union node *)stalloc(sizeof (struct nif)); n1->type = NIF; - n1->nif.test = list(0); + if ((n1->nif.test = list(0)) == NULL) + synexpect(-1); if (readtoken() != TTHEN) synexpect(TTHEN); n1->nif.ifpart = list(0); @@ -291,7 +334,8 @@ command() { n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); n2 = n2->nif.elsepart; n2->type = NIF; - n2->nif.test = list(0); + if ((n2->nif.test = list(0)) == NULL) + synexpect(-1); if (readtoken() != TTHEN) synexpect(TTHEN); n2->nif.ifpart = list(0); @@ -311,7 +355,8 @@ command() { int got; n1 = (union node *)stalloc(sizeof (struct nbinary)); n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; - n1->nbinary.ch1 = list(0); + if ((n1->nbinary.ch1 = list(0)) == NULL) + synexpect(-1); if ((got=readtoken()) != TDO) { TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); synexpect(TDO); @@ -340,8 +385,6 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); } *app = NULL; n1->nfor.args = ap; - /* A newline or semicolon is required here to end - the list. */ if (lasttoken != TNL && lasttoken != TSEMI) synexpect(-1); } else { @@ -355,8 +398,10 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); n2->narg.backquote = NULL; n2->narg.next = NULL; n1->nfor.args = n2; - /* A newline or semicolon is optional here. Anything - else gets pushed back so we can read it again. */ + /* + * Newline or semicolon here is optional (but note + * that the original Bourne shell only allowed NL). + */ if (lasttoken != TNL && lasttoken != TSEMI) tokpushback++; } @@ -386,34 +431,40 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); if (lasttoken != TWORD || ! equal(wordtext, "in")) synerror("expecting \"in\""); cpp = &n1->ncase.cases; - while (checkkwd = 2, readtoken() == TWORD) { + noaliases = 1; /* turn off alias expansion */ + checkkwd = 2, readtoken(); + while (lasttoken != TESAC) { *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); cp->type = NCLIST; app = &cp->nclist.pattern; + if (lasttoken == TLP) + readtoken(); for (;;) { *app = ap = (union node *)stalloc(sizeof (struct narg)); ap->type = NARG; ap->narg.text = wordtext; ap->narg.backquote = backquotelist; - if (readtoken() != TPIPE) + if (checkkwd = 2, readtoken() != TPIPE) break; app = &ap->narg.next; - if (readtoken() != TWORD) - synexpect(TWORD); + readtoken(); } ap->narg.next = NULL; if (lasttoken != TRP) - synexpect(TRP); + noaliases = 0, synexpect(TRP); cp->nclist.body = list(0); - if ((t = readtoken()) == TESAC) - tokpushback++; - else if (t != TENDCASE) - synexpect(TENDCASE); + + checkkwd = 2; + if ((t = readtoken()) != TESAC) { + if (t != TENDCASE) + noaliases = 0, synexpect(TENDCASE); + else + checkkwd = 2, readtoken(); + } cpp = &cp->nclist.next; } + noaliases = 0; /* reset alias expansion */ *cpp = NULL; - if (lasttoken != TESAC) - synexpect(TESAC); checkkwd = 1; break; case TLP: @@ -432,14 +483,22 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); checkkwd = 1; break; /* Handle an empty command like other simple commands. */ - case TNL: case TSEMI: - case TEND: - case TRP: + case TAND: + case TOR: + /* + * An empty command before a ; doesn't make much sense, and + * should certainly be disallowed in the case of `if ;'. + */ + if (!redir) + synexpect(-1); + case TNL: case TEOF: case TWORD: + case TRP: tokpushback++; - return simplecmd(rpp, redir); + n1 = simplecmd(rpp, redir); + goto checkneg; default: synexpect(-1); } @@ -461,29 +520,47 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); } n1->nredir.redirect = redir; } - return n1; + +checkneg: + if (negate) { + n2 = (union node *)stalloc(sizeof (struct nnot)); + n2->type = NNOT; + n2->nnot.com = n1; + return n2; + } + else + return n1; } STATIC union node * -simplecmd(rpp, redir) - union node **rpp, *redir; - { +simplecmd(union node **rpp, union node *redir) +{ union node *args, **app; union node **orig_rpp = rpp; - union node *n; + union node *n = NULL, *n2; + int negate = 0; - /* If we don't have any redirections already, then we must reset - rpp to be the address of the local redir variable. */ + /* If we don't have any redirections already, then we must reset */ + /* rpp to be the address of the local redir variable. */ if (redir == 0) rpp = &redir; args = NULL; app = &args; - /* We save the incoming value, because we need this for shell - functions. There can not be a redirect or an argument between - the function name and the open parenthesis. */ + /* + * We save the incoming value, because we need this for shell + * functions. There can not be a redirect or an argument between + * the function name and the open parenthesis. + */ orig_rpp = rpp; + + while (readtoken() == TNOT) { + TRACE(("command: TNOT recognized\n")); + negate = !negate; + } + tokpushback++; + for (;;) { if (readtoken() == TWORD) { n = (union node *)stalloc(sizeof (struct narg)); @@ -507,7 +584,7 @@ simplecmd(rpp, redir) #endif n->type = NDEFUN; n->narg.next = command(); - return n; + goto checkneg; } else { tokpushback++; break; @@ -520,12 +597,54 @@ simplecmd(rpp, redir) n->ncmd.backgnd = 0; n->ncmd.args = args; n->ncmd.redirect = redir; + +checkneg: + if (negate) { + n2 = (union node *)stalloc(sizeof (struct nnot)); + n2->type = NNOT; + n2->nnot.com = n; + return n2; + } + else + return n; +} + +STATIC union node * +makename(void) +{ + union node *n; + + n = (union node *)stalloc(sizeof (struct narg)); + n->type = NARG; + n->narg.next = NULL; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; return n; } +void fixredir(union node *n, const char *text, int err) +{ + TRACE(("Fix redir %s %d\n", text, err)); + if (!err) + n->ndup.vname = NULL; + + if (is_digit(text[0]) && text[1] == '\0') + n->ndup.dupfd = digit_val(text[0]); + else if (text[0] == '-' && text[1] == '\0') + n->ndup.dupfd = -1; + else { + + if (err) + synerror("Bad fd number"); + else + n->ndup.vname = makename(); + } +} + STATIC void -parsefname() { +parsefname(void) +{ union node *n = redirnode; if (readtoken() != TWORD) @@ -554,23 +673,9 @@ parsefname() { p->next = here; } } else if (n->type == NTOFD || n->type == NFROMFD) { - if (is_digit(wordtext[0])) - n->ndup.dupfd = digit_val(wordtext[0]); - else if (wordtext[0] == '-') - n->ndup.dupfd = -1; - else - goto bad; - if (wordtext[1] != '\0') { -bad: - synerror("Bad fd number"); - } + fixredir(n, wordtext, 0); } else { - n->nfile.fname = (union node *)stalloc(sizeof (struct narg)); - n = n->nfile.fname; - n->type = NARG; - n->narg.next = NULL; - n->narg.text = wordtext; - n->narg.backquote = backquotelist; + n->nfile.fname = makename(); } } @@ -580,7 +685,8 @@ bad: */ STATIC void -parseheredoc() { +parseheredoc(void) +{ struct heredoc *here; union node *n; @@ -588,7 +694,7 @@ parseheredoc() { here = heredoclist; heredoclist = here->next; if (needprompt) { - putprompt(ps2val()); + setprompt(2); needprompt = 0; } readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, @@ -603,7 +709,8 @@ parseheredoc() { } STATIC int -peektoken() { +peektoken(void) +{ int t; t = readtoken(); @@ -611,15 +718,17 @@ peektoken() { return (t); } -STATIC int xxreadtoken(); - STATIC int -readtoken() { +readtoken(void) +{ int t; + int savecheckkwd = checkkwd; + struct alias *ap; #if DEBUG int alreadyseen = tokpushback; #endif - + + top: t = xxreadtoken(); if (checkkwd) { @@ -635,19 +744,29 @@ readtoken() { } else checkkwd = 0; /* - * check for keywords + * check for keywords and aliases */ - if (t == TWORD && !quoteflag) { - register char *const *pp; + if (t == TWORD && !quoteflag) + { + const char * const *pp; for (pp = parsekwd; *pp; pp++) { - if (**pp == *wordtext && equal(*pp, wordtext)) { + if (**pp == *wordtext && equal(*pp, wordtext)) + { lasttoken = t = pp - parsekwd + KWDOFFSET; TRACE(("keyword %s recognized\n", tokname[t])); - break; + goto out; } } + if (noaliases == 0 && + (ap = lookupalias(wordtext, 1)) != NULL) { + pushstring(ap->val, strlen(ap->val), ap); + checkkwd = savecheckkwd; + goto top; + } } +out: + checkkwd = (t == TNOT) ? savecheckkwd : 0; } #if DEBUG if (!alreadyseen) @@ -680,15 +799,16 @@ readtoken() { #define RETURN(token) return lasttoken = token STATIC int -xxreadtoken() { - register c; +xxreadtoken(void) +{ + int c; if (tokpushback) { tokpushback = 0; return lasttoken; } if (needprompt) { - putprompt(ps2val()); + setprompt(2); needprompt = 0; } startlinno = plinno; @@ -707,7 +827,9 @@ xxreadtoken() { if (pgetc() == '\n') { startlinno = ++plinno; if (doprompt) - putprompt(ps2val()); + setprompt(2); + else + setprompt(0); continue; } pungetc(); @@ -765,23 +887,37 @@ breakloop: #define PARSESUB() {goto parsesub; parsesub_return:;} #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} +#define PARSEARITH() {goto parsearith; parsearith_return:;} STATIC int -readtoken1(firstc, syntax, eofmark, striptabs) - int firstc; - char const *syntax; - char *eofmark; - int striptabs; - { - register c = firstc; - register char *out; +readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) +{ + int c = firstc; + char *out; int len; char line[EOFMARKLEN + 1]; struct nodelist *bqlist; int quotef; int dblquote; - int varnest; + int varnest; /* levels of variables expansion */ + int arinest; /* levels of arithmetic expansion */ + int parenlevel; /* levels of parens in arithmetic */ int oldstyle; + char const *prevsyntax; /* syntax before arithmetic */ + int synentry; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &out; + (void) "ef; + (void) &dblquote; + (void) &varnest; + (void) &arinest; + (void) &parenlevel; + (void) &oldstyle; + (void) &prevsyntax; + (void) &syntax; + (void) &synentry; +#endif startlinno = plinno; dblquote = 0; @@ -790,30 +926,27 @@ readtoken1(firstc, syntax, eofmark, striptabs) quotef = 0; bqlist = NULL; varnest = 0; + arinest = 0; + parenlevel = 0; + STARTSTACKSTR(out); loop: { /* for each line, until end of word */ -#if ATTY - if (c == '\034' && doprompt - && attyset() && ! equal(termval(), "emacs")) { - attyline(); - if (syntax == BASESYNTAX) - return readtoken(); - c = pgetc(); - goto loop; - } -#endif CHECKEND(); /* set c to PEOF if at end of here document */ for (;;) { /* until end of line or end of word */ CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ - switch(syntax[c]) { + + synentry = syntax[c]; + + switch(synentry) { case CNL: /* '\n' */ if (syntax == BASESYNTAX) goto endword; /* exit outer loop */ USTPUTC(c, out); plinno++; - if (doprompt) { - putprompt(ps2val()); - } + if (doprompt) + setprompt(2); + else + setprompt(0); c = pgetc(); goto loop; /* continue outer loop */ case CWORD: @@ -831,31 +964,46 @@ readtoken1(firstc, syntax, eofmark, striptabs) pungetc(); } else if (c == '\n') { if (doprompt) - putprompt(ps2val()); + setprompt(2); + else + setprompt(0); } else { - if (dblquote && c != '\\' && c != '`' && c != '$' - && (c != '"' || eofmark != NULL)) + if (dblquote && c != '\\' && + c != '`' && c != '$' && + (c != '"' || eofmark != NULL)) USTPUTC('\\', out); if (SQSYNTAX[c] == CCTL) USTPUTC(CTLESC, out); + else if (eofmark == NULL) + USTPUTC(CTLQUOTEMARK, out); USTPUTC(c, out); quotef++; } break; case CSQUOTE: + if (eofmark == NULL) + USTPUTC(CTLQUOTEMARK, out); syntax = SQSYNTAX; break; case CDQUOTE: + if (eofmark == NULL) + USTPUTC(CTLQUOTEMARK, out); syntax = DQSYNTAX; dblquote = 1; break; case CENDQUOTE: - if (eofmark) { + if (eofmark != NULL && arinest == 0 && + varnest == 0) { USTPUTC(c, out); } else { - syntax = BASESYNTAX; + if (arinest) { + syntax = ARISYNTAX; + dblquote = 0; + } else if (eofmark == NULL) { + syntax = BASESYNTAX; + dblquote = 0; + } quotef++; - dblquote = 0; } break; case CVAR: /* '$' */ @@ -869,6 +1017,35 @@ readtoken1(firstc, syntax, eofmark, striptabs) USTPUTC(c, out); } break; + case CLP: /* '(' in arithmetic */ + parenlevel++; + USTPUTC(c, out); + break; + case CRP: /* ')' in arithmetic */ + if (parenlevel > 0) { + USTPUTC(c, out); + --parenlevel; + } else { + if (pgetc() == ')') { + if (--arinest == 0) { + USTPUTC(CTLENDARI, out); + syntax = prevsyntax; + if (syntax == DQSYNTAX) + dblquote = 1; + else + dblquote = 0; + } else + USTPUTC(')', out); + } else { + /* + * unbalanced parens + * (don't 2nd guess - no error) + */ + pungetc(); + USTPUTC(')', out); + } + } + break; case CBQUOTE: /* '`' */ PARSEBACKQOLD(); break; @@ -883,6 +1060,8 @@ readtoken1(firstc, syntax, eofmark, striptabs) } } endword: + if (syntax == ARISYNTAX) + synerror("Missing '))'"); if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) synerror("Unterminated quoted string"); if (varnest != 0) { @@ -926,7 +1105,7 @@ checkend: { } if (c == *eofmark) { if (pfgets(line, sizeof line) != NULL) { - register char *p, *q; + char *p, *q; p = line; for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); @@ -935,7 +1114,7 @@ checkend: { plinno++; needprompt = doprompt; } else { - ppushback(line, strlen(line)); + pushstring(line, strlen(line), NULL); } } } @@ -962,6 +1141,8 @@ parseredir: { np->type = NAPPEND; else if (c == '&') np->type = NTOFD; + else if (c == '|') + np->type = NCLOBBER; else { np->type = NTO; pungetc(); @@ -985,6 +1166,8 @@ parseredir: { } } else if (c == '&') np->type = NFROMFD; + else if (c == '>') + np->type = NFROMTO; else { np->type = NFROM; pungetc(); @@ -1010,27 +1193,51 @@ parsesub: { #ifndef GDB_HACK static const char types[] = "}-+?="; #endif + int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ c = pgetc(); if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { USTPUTC('$', out); pungetc(); - } else if (c == '(') { /* $(command) */ - PARSEBACKQNEW(); + } else if (c == '(') { /* $(command) or $((arith)) */ + if (pgetc() == '(') { + PARSEARITH(); + } else { + pungetc(); + PARSEBACKQNEW(); + } } else { USTPUTC(CTLVAR, out); typeloc = out - stackblock(); USTPUTC(VSNORMAL, out); subtype = VSNORMAL; if (c == '{') { + bracketed_name = 1; c = pgetc(); - subtype = 0; + if (c == '#') { + if ((c = pgetc()) == '}') + c = '#'; + else + subtype = VSLENGTH; + } + else + subtype = 0; } if (is_name(c)) { do { STPUTC(c, out); c = pgetc(); } while (is_in_name(c)); + } else if (is_digit(c)) { + if (bracketed_name) { + do { + STPUTC(c, out); + c = pgetc(); + } while (is_digit(c)); + } else { + STPUTC(c, out); + c = pgetc(); + } } else { if (! is_special(c)) badsub: synerror("Bad substitution"); @@ -1040,18 +1247,35 @@ badsub: synerror("Bad substitution"); STPUTC('=', out); flags = 0; if (subtype == 0) { - if (c == ':') { + switch (c) { + case ':': flags = VSNUL; c = pgetc(); + /*FALLTHROUGH*/ + default: + p = strchr(types, c); + if (p == NULL) + goto badsub; + subtype = p - types + VSNORMAL; + break; + case '%': + case '#': + { + int cc = c; + subtype = c == '#' ? VSTRIMLEFT : + VSTRIMRIGHT; + c = pgetc(); + if (c == cc) + subtype++; + else + pungetc(); + break; + } } - p = strchr(types, c); - if (p == NULL) - goto badsub; - subtype = p - types + VSNORMAL; } else { pungetc(); } - if (dblquote) + if (subtype != VSLENGTH && (dblquote || arinest)) flags |= VSQUOTE; *(stackblock() + typeloc) = subtype | flags; if (subtype != VSNORMAL) @@ -1076,7 +1300,11 @@ parsebackq: { struct jmploc jmploc; struct jmploc *volatile savehandler; int savelen; - int savedoprompt; + int saveprompt; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &saveprompt; +#endif savepbq = parsebackquote; if (setjmp(jmploc.loc)) { @@ -1091,65 +1319,110 @@ parsebackq: { savelen = out - stackblock(); if (savelen > 0) { str = ckmalloc(savelen); - bcopy(stackblock(), str, savelen); + memcpy(str, stackblock(), savelen); } savehandler = handler; handler = &jmploc; INTON; - if (oldstyle) { - /* We must read until the closing backquote, giving special - treatment to some slashes, and then push the string and - reread it as input, interpreting it normally. */ - register char *out; - register c; - int savelen; - char *str; + if (oldstyle) { + /* We must read until the closing backquote, giving special + treatment to some slashes, and then push the string and + reread it as input, interpreting it normally. */ + char *out; + int c; + int savelen; + char *str; - STARTSTACKSTR(out); - while ((c = pgetc ()) != '`') { - if (c == '\\') { - c = pgetc (); - if (c != '\\' && c != '`' && c != '$' - && (!dblquote || c != '"')) - STPUTC('\\', out); + + STARTSTACKSTR(out); + for (;;) { + if (needprompt) { + setprompt(2); + needprompt = 0; } - if (c == '\n') { + switch (c = pgetc()) { + case '`': + goto done; + + 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 STPUTC after the + * switch). + */ + continue; + } + if (c != '\\' && c != '`' && c != '$' + && (!dblquote || c != '"')) + STPUTC('\\', out); + break; + + case '\n': plinno++; - if (doprompt) - putprompt(ps2val()); + needprompt = doprompt; + break; + + case PEOF: + startlinno = plinno; + synerror("EOF in backquote substitution"); + break; + + default: + break; } STPUTC(c, out); - } - STPUTC('\0', out); - savelen = out - stackblock(); - if (savelen > 0) { - str = ckmalloc(savelen); - bcopy(stackblock(), str, savelen); - } - setinputstring(str, 1); - savedoprompt = doprompt; - doprompt = 0; /* no prompts while rereading string */ - } + } +done: + STPUTC('\0', out); + savelen = out - stackblock(); + if (savelen > 0) { + str = ckmalloc(savelen); + memcpy(str, stackblock(), savelen); + setinputstring(str, 1); + } + } nlpp = &bqlist; while (*nlpp) nlpp = &(*nlpp)->next; *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); (*nlpp)->next = NULL; parsebackquote = oldstyle; - n = list(0); - if (!oldstyle && (readtoken() != TRP)) - synexpect(TRP); - (*nlpp)->n = n; - /* Start reading from old file again. */ + if (oldstyle) { - popfile(); - doprompt = savedoprompt; + saveprompt = doprompt; + doprompt = 0; + } + + n = list(0); + + if (oldstyle) + doprompt = saveprompt; + else { + if (readtoken() != TRP) + synexpect(TRP); + } + + (*nlpp)->n = n; + if (oldstyle) { + /* + * Start reading from old file again, ignoring any pushed back + * tokens left from the backquote parsing + */ + popfile(); + tokpushback = 0; } while (stackblocksize() <= savelen) growstackblock(); STARTSTACKSTR(out); if (str) { - bcopy(str, out, savelen); + memcpy(out, str, savelen); STADJUST(savelen, out); INTOFF; ckfree(str); @@ -1158,13 +1431,39 @@ parsebackq: { } parsebackquote = savepbq; handler = savehandler; - USTPUTC(CTLBACKQ + dblquote, out); + if (arinest || dblquote) + USTPUTC(CTLBACKQ | CTLQUOTE, out); + else + USTPUTC(CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; else goto parsebackq_newreturn; } +/* + * Parse an arithmetic expansion (indicate start of one and set state) + */ +parsearith: { + + if (++arinest == 1) { + prevsyntax = syntax; + syntax = ARISYNTAX; + USTPUTC(CTLARI, out); + if (dblquote) + USTPUTC('"',out); + else + USTPUTC(' ',out); + } else { + /* + * we collapse embedded arithmetic expansion to + * parenthesis, which should be equivalent + */ + USTPUTC('(', out); + } + goto parsearith_return; +} + } /* end of readtoken */ @@ -1172,104 +1471,28 @@ parsebackq: { #ifdef mkinit RESET { tokpushback = 0; + checkkwd = 0; } #endif - -#if READLINE -/* - * Remember a prompt for use with readline if input and output is a terminal. - */ - -STATIC void -putprompt(s) - char *s; - { - if (editable) { - r_use_prompt = s; - } else { - out2str(s); - } -} -#endif - -#if ATTY -/* - * Called to process a command generated by atty. We execute the line, - * and catch any errors that occur so they don't propagate outside of - * this routine. - */ - -STATIC void -attyline() { - char line[256]; - struct stackmark smark; - struct jmploc jmploc; - struct jmploc *volatile savehandler; - - if (pfgets(line, sizeof line) == NULL) - return; /* "can't happen" */ - if (setjmp(jmploc.loc)) { - if (exception == EXERROR) - out2str("\033]D\n"); - handler = savehandler; - longjmp(handler->loc, 1); - } - savehandler = handler; - handler = &jmploc; - setstackmark(&smark); - evalstring(line); - popstackmark(&smark); - handler = savehandler; - doprompt = 1; -} - - -/* - * Output a prompt for atty. We output the prompt as part of the - * appropriate escape sequence. - */ - -STATIC void -putprompt(s) - char *s; - { - register char *p; - - if (attyset() && ! equal(termval(), "emacs")) { - if (strchr(s, '\7')) - out2c('\7'); - out2str("\033]P1;"); - for (p = s ; *p ; p++) { - if ((unsigned)(*p - ' ') <= '~' - ' ') - out2c(*p); - } - out2c('\n'); - } else { - out2str(s); - } -} -#endif - - - /* * Returns true if the text contains nothing to expand (no dollar signs * or backquotes). */ STATIC int -noexpand(text) - char *text; - { - register char *p; - register char c; +noexpand(char *text) +{ + char *p; + char c; p = text; while ((c = *p++) != '\0') { + if ( c == CTLQUOTEMARK) + continue; if (c == CTLESC) p++; - else if (BASESYNTAX[c] == CCTL) + else if (BASESYNTAX[(int)c] == CCTL) return 0; } return 1; @@ -1282,10 +1505,9 @@ noexpand(text) */ int -goodname(name) - char *name; - { - register char *p; +goodname(char *name) +{ + char *p; p = name; if (! is_name(*p)) @@ -1305,7 +1527,8 @@ goodname(name) */ STATIC void -synexpect(token) { +synexpect(int token) +{ char msg[64]; if (token >= 0) { @@ -1319,11 +1542,135 @@ synexpect(token) { STATIC void -synerror(msg) - char *msg; - { +synerror(char *msg) +{ if (commandname) outfmt(&errout, "%s: %d: ", commandname, startlinno); outfmt(&errout, "Syntax error: %s\n", msg); error((char *)NULL); } + +STATIC void +setprompt(int which) +{ + whichprompt = which; + +#ifndef EDITLINE +#ifndef NO_HISTORY + if (!el) +#endif + out2str(getprompt(NULL)); +#endif /* EDITLINE */ +} + +/* + * called by editline -- any expansions to the prompt + * should be added here. + */ +char * +getprompt(void *unused __unused) +{ + static char ps[PROMPTLEN]; + char *fmt; + int i, j, trim; + + /* + * Select prompt format. + */ + switch (whichprompt) { + case -1: + fmt = pseval(); + break; + case 0: + fmt = ""; + break; + case 1: + fmt = ps1val(); + break; + case 2: + fmt = ps2val(); + break; + default: + return ""; + } + + /* + * Format prompt string. + */ + for (i = 0; (i < 127) && (*fmt != '\0'); i++, fmt++) + if (*fmt == '\\') + switch (*++fmt) { + + /* + * Hostname. + * + * \h specifies just the local hostname, + * \H specifies fully-qualified hostname. + */ + case 'h': + case 'H': + ps[i] == '\0'; + gethostname(&ps[i], PROMPTLEN - i); + /* Skip to end of hostname. */ + trim = (*fmt == 'h') ? '.' : '\0'; + while ((ps[i+1] != '\0') && (ps[i+1] != trim)) + i++; + break; + + /* + * Working directory. + * + * \W specifies just the final component, + * \w specifies the entire path. + */ + case 'W': + case 'w': + ps[i] == '\0'; + getcwd(&ps[i], PROMPTLEN - i); + if (*fmt == 'W') { + /* Final path component only. */ + trim = 1; + for (j = i; ps[j] != '\0'; j++) + if (ps[j] == '/') + trim = j + 1; + memmove(&ps[i], &ps[trim], + j - trim + 1); + } + /* Skip to end of path. */ + while (ps[i + 1] != '\0') + i++; + break; + + /* + * Superuser status. + * + * '$' for normal users, '#' for root. + */ + case '$': + ps[i] = (geteuid() != 0) ? '$' : '#'; + break; + + /* + * A literal \. + */ + case '\\': + ps[i] = '\\'; + break; + + /* + * Emit unrecognized formats verbatim. + */ + default: + ps[i++] = '\\'; + ps[i] = *fmt; + break; + } + else + ps[i] = *fmt; + ps[i] = '\0'; + return (ps); +} + +/* + * $PchId: parser.c,v 1.5 2006/05/22 12:27:09 philip Exp $ + */ diff --git a/commands/ash/parser.h b/commands/ash/parser.h index edb130a51..522902a4b 100755 --- a/commands/ash/parser.h +++ b/commands/ash/parser.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)parser.h 5.1 (Berkeley) 3/7/91 + * @(#)parser.h 8.3 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/parser.h,v 1.10 2004/04/06 20:06:51 markm Exp $ */ /* control characters in argument strings */ @@ -42,18 +39,27 @@ #define CTLENDVAR '\203' #define CTLBACKQ '\204' #define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ +/* CTLBACKQ | CTLQUOTE == '\205' */ +#define CTLARI '\206' +#define CTLENDARI '\207' +#define CTLQUOTEMARK '\210' /* variable substitution byte (follows CTLVAR) */ -#define VSTYPE 07 /* type of variable substitution */ -#define VSNUL 040 /* colon--treat the empty string as unset */ -#define VSQUOTE 0100 /* inside double quotes--suppress splitting */ +#define VSTYPE 0x0f /* type of variable substitution */ +#define VSNUL 0x10 /* colon--treat the empty string as unset */ +#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ /* values of VSTYPE field */ -#define VSNORMAL 1 /* normal variable: $var or ${var} */ -#define VSMINUS 2 /* ${var-text} */ -#define VSPLUS 3 /* ${var+text} */ -#define VSQUESTION 4 /* ${var?message} */ -#define VSASSIGN 5 /* ${var=text} */ +#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ +#define VSMINUS 0x2 /* ${var-text} */ +#define VSPLUS 0x3 /* ${var+text} */ +#define VSQUESTION 0x4 /* ${var?message} */ +#define VSASSIGN 0x5 /* ${var=text} */ +#define VSTRIMLEFT 0x6 /* ${var#pattern} */ +#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ +#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ +#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ +#define VSLENGTH 0xa /* ${#var} */ /* @@ -63,12 +69,14 @@ */ extern int tokpushback; #define NEOF ((union node *)&tokpushback) +extern int whichprompt; /* 1 == PS1, 2 == PS2 */ -#ifdef __STDC__ union node *parsecmd(int); +void fixredir(union node *, const char *, int); int goodname(char *); -#else -union node *parsecmd(); -int goodname(); -#endif +char *getprompt(void *); + +/* + * $PchId: parser.h,v 1.3 2006/03/29 14:33:35 philip Exp $ + */ diff --git a/commands/ash/redir.c b/commands/ash/redir.c index 5cded98d6..9fa35de48 100755 --- a/commands/ash/redir.c +++ b/commands/ash/redir.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,8 +31,23 @@ */ #ifndef lint -static char sccsid[] = "@(#)redir.c 5.1 (Berkeley) 3/7/91"; +#if 0 +static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include +#include +#include +#include +#include +#include +#include /* * Code for dealing with input/output redirection. @@ -47,15 +58,10 @@ static char sccsid[] = "@(#)redir.c 5.1 (Berkeley) 3/7/91"; #include "jobs.h" #include "expand.h" #include "redir.h" -#include "eval.h" #include "output.h" #include "memalloc.h" #include "error.h" -#include -#include -#include -#include -#include +#include "options.h" #define EMPTY -2 /* marks an unused slot in redirtab */ @@ -65,25 +71,21 @@ static char sccsid[] = "@(#)redir.c 5.1 (Berkeley) 3/7/91"; MKINIT struct redirtab { struct redirtab *next; - short renamed[10]; + int renamed[10]; }; MKINIT struct redirtab *redirlist; -/* We keep track of whether or not fd0 has been redirected. This is for - background commands, where we want to redirect fd0 to /dev/null only - if it hasn't already been redirected. */ -int fd0_redirected = 0; +/* + * We keep track of whether or not fd0 has been redirected. This is for + * background commands, where we want to redirect fd0 to /dev/null only + * if it hasn't already been redirected. +*/ +STATIC int fd0_redirected = 0; -#ifdef __STDC__ -STATIC void openredirect(union node *, char *); +STATIC void openredirect(union node *, char[10 ]); STATIC int openhere(union node *); -#else -STATIC void openredirect(); -STATIC int openhere(); -#endif - /* @@ -95,15 +97,14 @@ STATIC int openhere(); */ void -redirect(redir, flags) - union node *redir; - int flags; - { +redirect(union node *redir, int flags) +{ union node *n; - struct redirtab *sv; + struct redirtab *sv = NULL; int i; int fd; - char memory[10]; /* file descriptors to write to memory */ + int try; + char memory[10]; /* file descriptors to write to memory */ for (i = 10 ; --i >= 0 ; ) memory[i] = 0; @@ -117,21 +118,38 @@ redirect(redir, flags) } for (n = redir ; n ; n = n->nfile.next) { fd = n->nfile.fd; + try = 0; + if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && + n->ndup.dupfd == fd) + continue; /* redirect from/to same file descriptor */ + if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) { INTOFF; - if ((i = copyfd(fd, 10)) != EMPTY) { +again: + if ((i = fcntl(fd, F_DUPFD, 10)) == -1) { + switch (errno) { + case EBADF: + if (!try) { + openredirect(n, memory); + try++; + goto again; + } + /* FALLTHROUGH*/ + default: + INTON; + error("%d: %s", fd, strerror(errno)); + break; + } + } + if (!try) { sv->renamed[fd] = i; - close(fd); } INTON; - if (i == EMPTY) - error("Out of file descriptors"); - } else { - close(fd); } if (fd == 0) fd0_redirected++; - openredirect(n, memory); + if (!try) + openredirect(n, memory); } if (memory[1]) out1 = &memout; @@ -141,16 +159,15 @@ redirect(redir, flags) STATIC void -openredirect(redir, memory) - union node *redir; - char memory[10]; - { +openredirect(union node *redir, char memory[10]) +{ + struct stat sb; int fd = redir->nfile.fd; char *fname; int f; /* Assume redirection succeeds. */ - exitstatus = 0; + { extern int exitstatus; exitstatus = 0; } /* * We suppress interrupts so that we won't leave open file @@ -163,34 +180,35 @@ openredirect(redir, memory) case NFROM: fname = redir->nfile.expfname; if ((f = open(fname, O_RDONLY)) < 0) - error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); + error("cannot open %s: %s", fname, strerror(errno)); movefd: if (f != fd) { - copyfd(f, fd); + dup2(f, fd); 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; case NTO: fname = redir->nfile.expfname; -#ifdef O_CREAT + if (Cflag && stat(fname, &sb) != -1 && S_ISREG(sb.st_mode)) + error("cannot create %s: %s", fname, + strerror(EEXIST)); if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -#else - if ((f = creat(fname, 0666)) < 0) - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -#endif + error("cannot create %s: %s", fname, strerror(errno)); + goto movefd; + 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; case NAPPEND: fname = redir->nfile.expfname; -#ifdef O_APPEND if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); -#else - if ((f = open(fname, O_WRONLY)) < 0 - && (f = creat(fname, 0666)) < 0) - error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); - lseek(f, 0L, 2); -#endif + error("cannot create %s: %s", fname, strerror(errno)); goto movefd; case NTOFD: case NFROMFD: @@ -198,7 +216,9 @@ movefd: if (memory[redir->ndup.dupfd]) memory[fd] = 1; else - copyfd(redir->ndup.dupfd, fd); + dup2(redir->ndup.dupfd, fd); + } else { + close(fd); } break; case NHERE: @@ -219,14 +239,13 @@ movefd: */ STATIC int -openhere(redir) - union node *redir; - { +openhere(union node *redir) +{ int pip[2]; - int len; + int len = 0; if (pipe(pip) < 0) - error("Pipe call failed"); + error("Pipe call failed: %s", strerror(errno)); if (redir->type == NHERE) { len = strlen(redir->nhere.doc->narg.text); if (len <= PIPESIZE) { @@ -239,9 +258,7 @@ openhere(redir) signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGHUP, SIG_IGN); -#ifdef SIGTSTP signal(SIGTSTP, SIG_IGN); -#endif signal(SIGPIPE, SIG_DFL); if (redir->type == NHERE) xwrite(pip[1], redir->nhere.doc->narg.text, len); @@ -261,18 +278,20 @@ out: */ void -popredir() { - register struct redirtab *rp = redirlist; +popredir(void) +{ + struct redirtab *rp = redirlist; int i; for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] != EMPTY) { - if (i == 0) - fd0_redirected--; - close(i); + if (i == 0) + fd0_redirected--; if (rp->renamed[i] >= 0) { - copyfd(rp->renamed[i], i); + dup2(rp->renamed[i], i); close(rp->renamed[i]); + } else { + close(i); } } } @@ -282,8 +301,6 @@ popredir() { INTON; } - - /* * Undo all redirections. Called on error or interrupt. */ @@ -303,14 +320,21 @@ SHELLPROC { #endif +/* Return true if fd 0 has already been redirected at least once. */ +int +fd0_redirected_p(void) +{ + return fd0_redirected != 0; +} /* * Discard all saved file descriptors. */ void -clearredir() { - register struct redirtab *rp; +clearredir(void) +{ + struct redirtab *rp; int i; for (rp = redirlist ; rp ; rp = rp->next) { @@ -323,48 +347,6 @@ clearredir() { } } - - /* - * Copy a file descriptor, like the F_DUPFD option of fcntl. Returns -1 - * if the source file descriptor is closed, EMPTY if there are no unused - * file descriptors left. + * $PchId: redir.c,v 1.5 2006/05/22 12:27:37 philip Exp $ */ - -int -copyfd(from, to) { -#ifdef F_DUPFD - int newfd; - - newfd = fcntl(from, F_DUPFD, to); - if (newfd < 0 && errno == EMFILE) - return EMPTY; - return newfd; -#else - char toclose[32]; - int i; - int newfd; - int e; - - for (i = 0 ; i < to ; i++) - toclose[i] = 0; - INTOFF; - while ((newfd = dup(from)) >= 0 && newfd < to) - toclose[newfd] = 1; - e = errno; - for (i = 0 ; i < to ; i++) { - if (toclose[i]) - close(i); - } - INTON; - if (newfd < 0 && e == EMFILE) - return EMPTY; - return newfd; -#endif -} - -/* Return true if fd 0 has already been redirected at least once. */ -int -fd0_redirected_p () { - return fd0_redirected != 0; -} diff --git a/commands/ash/redir.h b/commands/ash/redir.h index 85ba6d12a..9b665d06f 100755 --- a/commands/ash/redir.h +++ b/commands/ash/redir.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,24 +29,21 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)redir.h 5.1 (Berkeley) 3/7/91 + * @(#)redir.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/redir.h,v 1.10 2004/04/06 20:06:51 markm Exp $ */ /* flags passed to redirect */ #define REDIR_PUSH 01 /* save previous values of file descriptors */ #define REDIR_BACKQ 02 /* save the command output in memory */ -#ifdef __STDC__ union node; void redirect(union node *, int); void popredir(void); -void clearredir(void); -int copyfd(int, int); int fd0_redirected_p(void); -#else -void redirect(); -void popredir(); -void clearredir(); -int copyfd(); -int fd0_redirected_p(); -#endif +void clearredir(void); + + +/* + * $PchId: redir.h,v 1.3 2006/03/29 14:13:34 philip Exp $ + */ diff --git a/commands/ash/setmode.c b/commands/ash/setmode.c new file mode 100644 index 000000000..d80c00bdd --- /dev/null +++ b/commands/ash/setmode.c @@ -0,0 +1,463 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Dave Borman at Cray Research, Inc. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)setmode.c 8.2 (Berkeley) 3/25/94"; +#endif /* LIBC_SCCS and not lint */ + +#include +#include + +#include +#include +#include +#include +#include + +#ifdef SETMODE_DEBUG +#include +#endif + +#include "shell.h" + +#ifndef S_ISTXT +#define S_ISTXT S_ISVTX +#endif + +#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ +#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ + +typedef struct bitcmd { + char cmd; + char cmd2; + mode_t bits; +} BITCMD; + +#define CMD2_CLR 0x01 +#define CMD2_SET 0x02 +#define CMD2_GBITS 0x04 +#define CMD2_OBITS 0x08 +#define CMD2_UBITS 0x10 + +static BITCMD *addcmd (BITCMD *, int, int, int, unsigned int); +static int compress_mode (BITCMD *); +#ifdef SETMODE_DEBUG +static void dumpmode __P((BITCMD *)); +#endif + +/* + * Given the old mode and an array of bitcmd structures, apply the operations + * described in the bitcmd structures to the old mode, and return the new mode. + * Note that there is no '=' command; a strict assignment is just a '-' (clear + * bits) followed by a '+' (set bits). + */ +mode_t +getmode(bbox, omode) + void *bbox; + mode_t omode; +{ + register BITCMD *set; + register mode_t clrval, newmode, value; + + set = (BITCMD *)bbox; + newmode = omode; + for (value = 0;; set++) + switch(set->cmd) { + /* + * When copying the user, group or other bits around, we "know" + * where the bits are in the mode so that we can do shifts to + * copy them around. If we don't use shifts, it gets real + * grundgy with lots of single bit checks and bit sets. + */ + case 'u': + value = (newmode & S_IRWXU) >> 6; + goto common; + + case 'g': + value = (newmode & S_IRWXG) >> 3; + goto common; + + case 'o': + value = newmode & S_IRWXO; +common: if (set->cmd2 & CMD2_CLR) { + clrval = + (set->cmd2 & CMD2_SET) ? S_IRWXO : value; + if (set->cmd2 & CMD2_UBITS) + newmode &= ~((clrval<<6) & set->bits); + if (set->cmd2 & CMD2_GBITS) + newmode &= ~((clrval<<3) & set->bits); + if (set->cmd2 & CMD2_OBITS) + newmode &= ~(clrval & set->bits); + } + if (set->cmd2 & CMD2_SET) { + if (set->cmd2 & CMD2_UBITS) + newmode |= (value<<6) & set->bits; + if (set->cmd2 & CMD2_GBITS) + newmode |= (value<<3) & set->bits; + if (set->cmd2 & CMD2_OBITS) + newmode |= value & set->bits; + } + break; + + case '+': + newmode |= set->bits; + break; + + case '-': + newmode &= ~set->bits; + break; + + case 'X': + if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) + newmode |= set->bits; + break; + + case '\0': + default: +#ifdef SETMODE_DEBUG + (void)printf("getmode:%04o -> %04o\n", omode, newmode); +#endif + return (newmode); + } +} + +#define ADDCMD(a, b, c, d) \ + if (set >= endset) { \ + register BITCMD *newset; \ + setlen += SET_LEN_INCR; \ + newset = realloc(saveset, sizeof(BITCMD) * setlen); \ + if (!saveset) \ + return (NULL); \ + set = newset + (set - saveset); \ + saveset = newset; \ + endset = newset + (setlen - 2); \ + } \ + set = addcmd(set, (a), (b), (c), (d)) + +#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) + +void * +setmode(p) + register char *p; +{ + register int perm, who; + register char op; + BITCMD *set, *saveset, *endset; + sigset_t sigset, sigoset; + mode_t mask; + int equalopdone, permXbits, setlen; + + if (!*p) + return (NULL); + + /* + * Get a copy of the mask for the permissions that are mask relative. + * Flip the bits, we want what's not set. Since it's possible that + * the caller is opening files inside a signal handler, protect them + * as best we can. + */ + sigfillset(&sigset); + (void)sigprocmask(SIG_BLOCK, &sigset, &sigoset); + (void)umask(mask = umask(0)); + mask = ~mask; + (void)sigprocmask(SIG_SETMASK, &sigoset, NULL); + + setlen = SET_LEN + 2; + + if ((set = malloc((unsigned int)(sizeof(BITCMD) * setlen))) == NULL) + return (NULL); + saveset = set; + endset = set + (setlen - 2); + + /* + * If an absolute number, get it and return; disallow non-octal digits + * or illegal bits. + */ + if (isdigit(*p)) { + perm = (mode_t)strtol(p, NULL, 8); + if (perm & ~(STANDARD_BITS|S_ISTXT)) { + free(saveset); + return (NULL); + } + while (*++p) + if (*p < '0' || *p > '7') { + free(saveset); + return (NULL); + } + ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); + return (saveset); + } + + /* + * Build list of structures to set/clear/copy bits as described by + * each clause of the symbolic mode. + */ + for (;;) { + /* First, find out which bits might be modified. */ + for (who = 0;; ++p) { + switch (*p) { + case 'a': + who |= STANDARD_BITS; + break; + case 'u': + who |= S_ISUID|S_IRWXU; + break; + case 'g': + who |= S_ISGID|S_IRWXG; + break; + case 'o': + who |= S_IRWXO; + break; + default: + goto getop; + } + } + +getop: if ((op = *p++) != '+' && op != '-' && op != '=') { + free(saveset); + return (NULL); + } + if (op == '=') + equalopdone = 0; + + who &= ~S_ISTXT; + for (perm = 0, permXbits = 0;; ++p) { + switch (*p) { + case 'r': + perm |= S_IRUSR|S_IRGRP|S_IROTH; + break; + case 's': + /* If only "other" bits ignore set-id. */ + if (who & ~S_IRWXO) + perm |= S_ISUID|S_ISGID; + break; + case 't': + /* If only "other" bits ignore sticky. */ + if (who & ~S_IRWXO) { + who |= S_ISTXT; + perm |= S_ISTXT; + } + break; + case 'w': + perm |= S_IWUSR|S_IWGRP|S_IWOTH; + break; + case 'X': + permXbits = S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'x': + perm |= S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'u': + case 'g': + case 'o': + /* + * When ever we hit 'u', 'g', or 'o', we have + * to flush out any partial mode that we have, + * and then do the copying of the mode bits. + */ + if (perm) { + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (op == '=') + equalopdone = 1; + if (op == '+' && permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + ADDCMD(*p, who, op, mask); + break; + + default: + /* + * Add any permissions that we haven't already + * done. + */ + if (perm || (op == '=' && !equalopdone)) { + if (op == '=') + equalopdone = 1; + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + goto apply; + } + } + +apply: if (!*p) + break; + if (*p != ',') + goto getop; + ++p; + } + set->cmd = 0; +#ifdef SETMODE_DEBUG + (void)printf("Before compress_mode()\n"); + dumpmode(saveset); +#endif + compress_mode(saveset); +#ifdef SETMODE_DEBUG + (void)printf("After compress_mode()\n"); + dumpmode(saveset); +#endif + return (saveset); +} + +static BITCMD * +addcmd(set, op, who, oparg, mask) + BITCMD *set; + register int oparg, who; + register int op; + unsigned int mask; +{ + switch (op) { + case '=': + set->cmd = '-'; + set->bits = who ? who : STANDARD_BITS; + set++; + + op = '+'; + /* FALLTHROUGH */ + case '+': + case '-': + case 'X': + set->cmd = op; + set->bits = (who ? who : mask) & oparg; + break; + + case 'u': + case 'g': + case 'o': + set->cmd = op; + if (who) { + set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | + ((who & S_IRGRP) ? CMD2_GBITS : 0) | + ((who & S_IROTH) ? CMD2_OBITS : 0); + set->bits = ~0; + } else { + set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; + set->bits = mask; + } + + if (oparg == '+') + set->cmd2 |= CMD2_SET; + else if (oparg == '-') + set->cmd2 |= CMD2_CLR; + else if (oparg == '=') + set->cmd2 |= CMD2_SET|CMD2_CLR; + break; + } + return (set + 1); +} + +#ifdef SETMODE_DEBUG +static void +dumpmode(set) + register BITCMD *set; +{ + for (; set->cmd; ++set) + (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", + set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", + set->cmd2 & CMD2_CLR ? " CLR" : "", + set->cmd2 & CMD2_SET ? " SET" : "", + set->cmd2 & CMD2_UBITS ? " UBITS" : "", + set->cmd2 & CMD2_GBITS ? " GBITS" : "", + set->cmd2 & CMD2_OBITS ? " OBITS" : ""); +} +#endif + +/* + * Given an array of bitcmd structures, compress by compacting consecutive + * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', + * 'g' and 'o' commands continue to be separate. They could probably be + * compacted, but it's not worth the effort. + */ +static int +compress_mode(set) + register BITCMD *set; +{ + register BITCMD *nset; + register int setbits, clrbits, Xbits, op; + + for (nset = set;;) { + /* Copy over any 'u', 'g' and 'o' commands. */ + while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { + *set++ = *nset++; + if (!op) + return; + } + + for (setbits = clrbits = Xbits = 0;; nset++) { + if ((op = nset->cmd) == '-') { + clrbits |= nset->bits; + setbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == '+') { + setbits |= nset->bits; + clrbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == 'X') + Xbits |= nset->bits & ~setbits; + else + break; + } + if (clrbits) { + set->cmd = '-'; + set->cmd2 = 0; + set->bits = clrbits; + set++; + } + if (setbits) { + set->cmd = '+'; + set->cmd2 = 0; + set->bits = setbits; + set++; + } + if (Xbits) { + set->cmd = 'X'; + set->cmd2 = 0; + set->bits = Xbits; + set++; + } + } +} + +/* + * $PchId: setmode.c,v 1.3 2006/05/23 11:57:34 philip Exp $ + */ diff --git a/commands/ash/shell.h b/commands/ash/shell.h index 04d59f5a1..5767b66ee 100755 --- a/commands/ash/shell.h +++ b/commands/ash/shell.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,19 +29,17 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)shell.h 5.4 (Berkeley) 4/12/91 + * @(#)shell.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $ */ +#include /* for mode_t */ + /* * The follow should be set to reflect the type of system you have: * JOBS -> 1 if you have Berkeley job control, 0 otherwise. - * SYMLINKS -> 1 if your system includes symbolic links, 0 otherwise. - * DIRENT -> 1 if your system has the SVR3 directory(3X) routines. - * UDIR -> 1 if you want the shell to simulate the /u directory. * TILDE -> 1 if you want the shell to expand ~logname. * USEGETPW -> 1 if getpwnam() must be used to look up a name. - * ATTY -> 1 to include code for atty(1). - * SHORTNAMES -> 1 if your linker cannot handle long names. * READLINE -> 1 if line editing by readline() should be enabled. * define BSD if you are running 4.2 BSD or later. * define SYSV if you are running under System V. @@ -56,52 +50,47 @@ * a quit signal will generate a core dump. */ +#ifndef JOBS +#define JOBS 1 +#endif +#ifndef BSD +#define BSD 1 +#endif +#ifndef DEBUG +#define DEBUG 0 +#endif +#define POSIX 1 -#define JOBS 0 - -/* Set SYMLINKS to 0 by request of Giovanni Falzoni, who wrote the - * symlink patches for Minix; email to minix-devel-l of thu 3 nov. +/* + * Type of used arithmetics. SUSv3 requires us to have at least signed long. */ +typedef long arith_t; +#define ARITH_FORMAT_STR "%ld" +#define atoarith_t(arg) strtol(arg, NULL, 0) +#define strtoarith_t(nptr, endptr, base) strtol(nptr, endptr, base) -#if 0 -#define SYMLINKS defined(S_ISLNK) -#else -#define SYMLINKS 0 -#endif - -#define DIRENT 1 -#define UDIR 0 -#define TILDE 1 -#define USEGETPW 0 -#define ATTY 0 -#define READLINE 1 -#define HASHBANG 0 -/* #define BSD */ -#define POSIX 1 -#define DEBUG 0 - -#ifdef __STDC__ typedef void *pointer; -#ifndef NULL -#define NULL (void *)0 -#endif -#else /* not __STDC__ */ -typedef char *pointer; -#ifndef NULL -#define NULL 0 -#endif -#endif /* not __STDC__ */ -#define STATIC /* empty */ -#define MKINIT /* empty */ - -#include -#include +#define STATIC static +#define MKINIT /* empty */ extern char nullstr[1]; /* null string */ - #if DEBUG -#define TRACE(param) trace param +#define TRACE(param) sh_trace param #else #define TRACE(param) #endif + +#ifdef __minix +#define __unused + +typedef long quad_t; /* XXX */ +typedef unsigned long u_quad_t; /* XXX */ +#endif + +mode_t getmode(void *, int /* mode_t */); +void *setmode(char *); + +/* + * $PchId: shell.h,v 1.7 2006/05/22 12:47:00 philip Exp $ + */ diff --git a/commands/ash/show.c b/commands/ash/show.c index 0860ab667..1b848927e 100755 --- a/commands/ash/show.c +++ b/commands/ash/show.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,38 +31,54 @@ */ #ifndef lint -static char sccsid[] = "@(#)show.c 5.2 (Berkeley) 4/12/91"; +#if 0 +static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/show.c,v 1.21 2004/04/06 20:06:51 markm Exp $"); +*/ +#include #include +#include +#include #include + #include "shell.h" #include "parser.h" #include "nodes.h" #include "mystring.h" - +#include "show.h" #if DEBUG -static shtree(), shcmd(), sharg(), indent(); +static void trputc(int c); +static void shtree(union node *, int, char *, FILE*); +static void shcmd(union node *, FILE *); +static void sharg(union node *, FILE *); +static void indent(int, char *, FILE *); +static void trstring(char *); +static void showtree(union node *n); -showtree(n) - union node *n; - { +static void +showtree(union node *n) +{ trputs("showtree called\n"); shtree(n, 1, NULL, stdout); } -static -shtree(n, ind, pfx, fp) - union node *n; - char *pfx; - FILE *fp; - { +static void +shtree(union node *n, int ind, char *pfx, FILE *fp) +{ struct nodelist *lp; char *s; + if (n == NULL) + return; + indent(ind, pfx, fp); switch(n->type) { case NSEMI: @@ -109,11 +121,9 @@ binop: -static -shcmd(cmd, fp) - union node *cmd; - FILE *fp; - { +static void +shcmd(union node *cmd, FILE *fp) +{ union node *np; int first; char *s; @@ -133,14 +143,20 @@ shcmd(cmd, fp) case NTO: s = ">"; dftfd = 1; break; case NAPPEND: s = ">>"; dftfd = 1; break; case NTOFD: s = ">&"; dftfd = 1; break; + case NCLOBBER: s = ">|"; dftfd = 1; break; case NFROM: s = "<"; dftfd = 0; break; + case NFROMTO: s = "<>"; dftfd = 0; break; case NFROMFD: s = "<&"; dftfd = 0; break; + default: s = "*error*"; dftfd = 0; break; } if (np->nfile.fd != dftfd) fprintf(fp, "%d", np->nfile.fd); fputs(s, fp); if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { - fprintf(fp, "%d", np->ndup.dupfd); + if (np->ndup.dupfd >= 0) + fprintf(fp, "%d", np->ndup.dupfd); + else + fprintf(fp, "-"); } else { sharg(np->nfile.fname, fp); } @@ -150,11 +166,9 @@ shcmd(cmd, fp) -static -sharg(arg, fp) - union node *arg; - FILE *fp; - { +static void +sharg(union node *arg, FILE *fp) +{ char *p; struct nodelist *bqlist; int subtype; @@ -174,10 +188,15 @@ sharg(arg, fp) putc('$', fp); putc('{', fp); subtype = *++p; + if (subtype == VSLENGTH) + putc('#', fp); + while (*p != '=') putc(*p++, fp); + if (subtype & VSNUL) putc(':', fp); + switch (subtype & VSTYPE) { case VSNORMAL: putc('}', fp); @@ -194,6 +213,22 @@ sharg(arg, fp) case VSASSIGN: putc('=', fp); break; + case VSTRIMLEFT: + putc('#', fp); + break; + case VSTRIMLEFTMAX: + putc('#', fp); + putc('#', fp); + break; + case VSTRIMRIGHT: + putc('%', fp); + break; + case VSTRIMRIGHTMAX: + putc('%', fp); + putc('%', fp); + break; + case VSLENGTH: + break; default: printf("", subtype); } @@ -216,11 +251,9 @@ sharg(arg, fp) } -static -indent(amount, pfx, fp) - char *pfx; - FILE *fp; - { +static void +indent(int amount, char *pfx, FILE *fp) +{ int i; for (i = 0 ; i < amount ; i++) { @@ -229,8 +262,6 @@ indent(amount, pfx, fp) putc('\t', fp); } } -#endif - /* @@ -247,52 +278,48 @@ int debug = 0; #endif -trputc(c) { -#if DEBUG +static void +trputc(int c) +{ if (tracefile == NULL) return; putc(c, tracefile); if (c == '\n') fflush(tracefile); -#endif } -trace(fmt, a1, a2, a3, a4, a5, a6, a7, a8) - char *fmt; - { -#if DEBUG - int e = errno; - if (tracefile == NULL) - return; - fprintf(tracefile, fmt, a1, a2, a3, a4, a5, a6, a7, a8); - if (strchr(fmt, '\n')) - fflush(tracefile); - errno = e; -#endif +void +sh_trace(const char *fmt, ...) +{ + va_list va; + va_start(va, fmt); + if (tracefile != NULL) { + (void) vfprintf(tracefile, fmt, va); + if (strchr(fmt, '\n')) + (void) fflush(tracefile); + } + va_end(va); } -trputs(s) - char *s; - { -#if DEBUG +void +trputs(char *s) +{ if (tracefile == NULL) return; fputs(s, tracefile); if (strchr(s, '\n')) fflush(tracefile); -#endif } -trstring(s) - char *s; - { - register char *p; +static void +trstring(char *s) +{ + char *p; char c; -#if DEBUG if (tracefile == NULL) return; putc('"', tracefile); @@ -324,14 +351,12 @@ backslash: putc('\\', tracefile); } } putc('"', tracefile); -#endif } -trargs(ap) - char **ap; - { -#if DEBUG +void +trargs(char **ap) +{ if (tracefile == NULL) return; while (*ap) { @@ -342,36 +367,43 @@ trargs(ap) putc('\n', tracefile); } fflush(tracefile); -#endif } -opentrace() { +void +opentrace(void) +{ char s[100]; - char *p; - char *getenv(); int flags; -#if DEBUG if (!debug) return; - if ((p = getenv("HOME")) == NULL) { - if (getuid() == 0) - p = "/"; - else - p = "/tmp"; +#ifdef not_this_way + { + char *p; + if ((p = getenv("HOME")) == NULL) { + if (geteuid() == 0) + p = "/"; + else + p = "/tmp"; + } + scopy(p, s); + strcat(s, "/trace"); } - scopy(p, s); - strcat(s, "/trace"); +#else + scopy("./trace", s); +#endif /* not_this_way */ if ((tracefile = fopen(s, "a")) == NULL) { - fprintf(stderr, "Can't open %s\n", s); + fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno)); return; } -#ifdef O_APPEND if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); -#endif fputs("\nTracing started.\n", tracefile); fflush(tracefile); -#endif } +#endif /* DEBUG */ + +/* + * $PchId: show.c,v 1.6 2006/05/22 12:27:51 philip Exp $ + */ diff --git a/commands/ash/show.h b/commands/ash/show.h new file mode 100644 index 000000000..59cb3e752 --- /dev/null +++ b/commands/ash/show.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * 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. + * + * @(#)show.h 1.1 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/show.h,v 1.11 2004/04/06 20:06:51 markm Exp $ + */ + +#ifdef DEBUG +void sh_trace(const char *, ...); +void trargs(char **); +void trputs(char *); +void opentrace(void); +#endif + +/* + * $PchId: show.h,v 1.4 2006/03/29 13:28:45 philip Exp $ + */ diff --git a/commands/ash/sys/cdefs.h b/commands/ash/sys/cdefs.h deleted file mode 100755 index 0c499191f..000000000 --- a/commands/ash/sys/cdefs.h +++ /dev/null @@ -1,15 +0,0 @@ -/* Replacement for something BSD has in sys/cdefs.h. */ - -#ifndef _ASH_SYS_CDEFS -#define _ASH_SYS_CDEFS - -#if __STDC__ -#define __P(params) params -#else -#define __P(params) () -#endif - -/* Probably in sys/types.h. */ -typedef void (*sig_t) __P(( int )); - -#endif /* _ASH_SYS_CDEFS */ diff --git a/commands/ash/test/malloc.c b/commands/ash/test/malloc.c deleted file mode 100755 index c54d71697..000000000 --- a/commands/ash/test/malloc.c +++ /dev/null @@ -1,1298 +0,0 @@ - -/**********************************************************/ -/* -/* This was file READ_ME -/* -/**********************************************************/ - -/* - PROGRAM - malloc(), free(), realloc() - AUTHOR - Dick Grune, Free University, Amsterdam - Modified by Ceriel Jacobs, Free University, Amsterdam, - to make it faster - VERSION - $Header$ - DESCRIPTION - This is an independent rewrite of the malloc/free package; it is - fast and efficient. Free blocks are kept in doubly linked lists, - list N holding blocks with sizes between 2**N and 2**(N+1)-1. - Consequently neither malloc nor free have to do any searching: - the cost of a call of malloc() (or free()) is constant, however - many blocks you have got. - - If you switch on the NON_STANDARD macro (see param.h) every block - costs 2 pointers overhead (otherwise it's 4). -*/ -/* - There is an organisational problem here: during devellopment - I want the package divided into modules, which implies external - names for the communication. The only external names I want in - the finished product are malloc, realloc and free. This requires - some hanky-panky. -*/ - - -/**********************************************************/ -/* -/* This was file size_type.h -/* -/**********************************************************/ - -#if _EM_WSIZE == _EM_PSIZE -typedef unsigned int size_type; -#elif _EM_LSIZE == _EM_PSIZE -typedef unsigned long size_type; -#else -#error funny pointer size -#endif -#include -#include - - -/**********************************************************/ -/* -/* This was file param.h -/* -/**********************************************************/ - -/* $Header$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ - -# undef NON_STANDARD /* If defined, the contents of a block - will NOT be left undisturbed after it - is freed, as opposed to what it says - in the manual (malloc(2)). - Setting this option reduces the memory - overhead considerably. I personally - consider the specified behaviour an - artefact of the original - implementation. - */ - -# define ASSERT /* If defined, some inexpensive tests - will be made to ensure the - correctness of some sensitive data. - It often turns an uncontrolled crash - into a controlled one. - */ - -# define CHECK /* If defined, extensive and expensive - tests will be done, inculding a - checksum on the mallinks (chunk - information blocks). The resulting - information will be printed on a file - called mal.out . - Additionally a function - maldump(n) int n; - will be defined, which will dump - pertinent info in pseudo-readable - form; it aborts afterwards if n != 0. - */ - -# undef EXTERN /* If defined, all static names will - become extern, which is a help in - using adb(1) or prof(1) - */ - -# define STORE /* If defined, separate free lists will - be kept of chunks with small sizes, - to speed things up a little. - */ - -# undef SYSTEM /* If defined, the system module is used. - Otherwise, "sbrk" is called directly. - */ - -#define ALIGNMENT 8 - /* alignment common to all types */ -#define LOG_MIN_SIZE 3 -#define LOG_MAX_SIZE 24 - - -/**********************************************************/ -/* -/* This was file impl.h -/* -/**********************************************************/ - -/* $Header$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -/* This file essentially describes how the mallink info block - is implemented. -*/ - -#define MIN_SIZE (1< -#include - -/* Malloc space is traversed by N doubly-linked lists of chunks, each - containing a couple of house-keeping data addressed as a - 'mallink' and a piece of useful space, called the block. - The N lists are accessed through their starting pointers in - free_list[]. Free_list[n] points to a list of chunks between - 2**(n+LOG_MIN_SIZE) and 2**(n+LOG_MIN_SIZE+1)-1, which means - that the smallest chunk is 2**LOG_MIN_SIZE (== MIN_SIZE). -*/ - -#ifdef SYSTEM -#include -#define SBRK sys_break -#else -#define SBRK _sbrk -#define ILL_BREAK (void *)(-1) /* funny failure value */ -#endif -extern void *SBRK(int incr); -#ifdef STORE -#define MAX_STORE 32 -private do_free(mallink *ml), sell_out(void); -privatedata mallink *store[MAX_STORE]; -#endif /* STORE */ - -void *privious_free= (void *)-1; -void * -malloc(register size_t n) -{check_mallinks("malloc entry");{ - register mallink *ml; - register int min_class; - void *tmp; - -{ static int reent= 0; if (!reent) { reent++; printf("malloc\n"); reent--; } } -privious_free= (void *)-1; - if (n == 0) { - return NULL; - } - if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n); -#ifdef STORE - if (n <= MAX_STORE*MIN_SIZE) { - /* look in the store first */ - register mallink **stp = &store[(n >> LOG_MIN_SIZE) - 1]; - - if (ml = *stp) { - *stp = log_next_of(ml); - set_store(ml, 0); - check_mallinks("malloc fast exit"); - assert(! in_store(ml)); - tmp= block_of_mallink(ml); -{ static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } } - return tmp; - } - } -#endif /* STORE */ - - check_work_empty("malloc, entry"); - - /* Acquire a chunk of at least size n if at all possible; - Try everything. - */ - { - /* Inline substitution of "smallest". - */ - register size_t n1 = n; - - assert(n1 < (1L << LOG_MAX_SIZE)); - min_class = 0; - - do { - n1 >>= 1; - min_class++; - } while (n1 >= MIN_SIZE); - } - - if (min_class >= MAX_FLIST) - return NULL; /* we don't deal in blocks that big */ - ml = first_present(min_class); - if (ml == MAL_NULL) { - /* Try and extend */ - register void *p; -#define GRABSIZE 4096 /* Power of 2 */ - register size_t req = - ((MIN_SIZE<= 0) p = SBRK((int)req); - } - if (p == ILL_BREAK) { - /* Now this is bad. The system will not give us - more memory. We can only liquidate our store - and hope it helps. - */ -#ifdef STORE - sell_out(); - ml = first_present(min_class); - if (ml == MAL_NULL) { -#endif /* STORE */ - /* In this emergency we try to locate a suitable - chunk in the free_list just below the safe - one; some of these chunks may fit the job. - */ - ml = search_free_list(min_class - 1, n); - if (!ml) /* really out of space */ - return NULL; - started_working_on(ml); - unlink_free_chunk(ml); - check_mallinks("suitable_chunk, forced"); -#ifdef STORE - } - else started_working_on(ml); -#endif /* STORE */ - } - else { - assert((size_type)p == align((size_type)p)); - ml = create_chunk(p, req); - } - check_mallinks("suitable_chunk, extended"); - } - else started_working_on(ml); - - /* we have a chunk */ - set_free(ml, 0); - calc_checksum(ml); - check_mallinks("suitable_chunk, removed"); - n += mallink_size(); - if (n + MIN_SIZE <= size_of(ml)) { - truncate(ml, n); - } - stopped_working_on(ml); - check_mallinks("malloc exit"); - check_work_empty("malloc exit"); -#ifdef STORE - assert(! in_store(ml)); -#endif - tmp= block_of_mallink(ml); -{ static int reent= 0; if (!reent) { reent++; printf("= 0x%x\n", tmp);reent--; } } - return tmp; -}} - -void -free(void *addr) -{check_mallinks("free entry");{ - register mallink *ml; - -printf("free 0x%x\n", addr); -if (privious_free == addr) { fflush(stdout); fflush(stderr); abort(); } -privious_free= addr; - if (addr == NULL) { - check_mallinks("free(0) very fast exit"); - return; - } - - ml = mallink_of_block(addr); -#ifdef STORE - - if (free_of(ml) || in_store(ml)) - return; /* user frees free block */ - if (size_of(ml) <= MAX_STORE*MIN_SIZE) { - /* return to store */ - mallink **stp = &store[(size_of(ml) >> LOG_MIN_SIZE) - 1]; - - set_log_next(ml, *stp); - *stp = ml; - set_store(ml, 1); - calc_checksum(ml); - check_mallinks("free fast exit"); - } - else { - do_free(ml); - check_mallinks("free exit"); - } -}} - -private -do_free(register mallink *ml) -{{ -#endif - -#ifndef STORE - if (free_of(ml)) return; -#endif /* STORE */ - started_working_on(ml); - set_free(ml, 1); - calc_checksum(ml); - if (! last_mallink(ml)) { - register mallink *next = phys_next_of(ml); - - if (free_of(next)) coalesce_forw(ml, next); - } - - if (! first_mallink(ml)) { - register mallink *prev = phys_prev_of(ml); - - if (free_of(prev)) { - coalesce_backw(ml, prev); - ml = prev; - } - } - link_free_chunk(ml); - stopped_working_on(ml); - check_work_empty("free"); - - /* Compile-time checks on param.h */ - switch (0) { - case MIN_SIZE < OFF_SET * sizeof(mallink): break; - case 1: break; - /* If this statement does not compile due to duplicate case - entry, the minimum size block cannot hold the links for - the free blocks. Either raise LOG_MIN_SIZE or switch - off NON_STANDARD. - */ - } - switch(0) { - case sizeof(void *) != sizeof(size_type): break; - case 1: break; - /* If this statement does not compile due to duplicate - case entry, size_type is not defined correctly. - Redefine and compile again. - */ - } -}} - -void * -realloc(void *addr, register size_t n) -{check_mallinks("realloc entry");{ - register mallink *ml, *ph_next; - register size_type size; - -printf("realloc 0x%x, %d\n", addr, n); - if (addr == NULL) { - /* Behave like most Unix realloc's when handed a - null-pointer - */ - return malloc(n); - } - if (n == 0) { - free(addr); - return NULL; - } - ml = mallink_of_block(addr); - if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n); -#ifdef STORE - if (in_store(ml)) { - register mallink *stp = store[(size_of(ml) >> LOG_MIN_SIZE) - 1]; - mallink *stp1 = NULL; - while (ml != stp) { - stp1 = stp; - stp = log_next_of(stp); - } - stp = log_next_of(stp); - if (! stp1) store[(size_of(ml) >> LOG_MIN_SIZE) - 1] = stp; - else set_log_next(stp1, stp); - set_store(ml, 0); - calc_checksum(ml); - } -#endif - if (free_of(ml)) { - unlink_free_chunk(ml); - set_free(ml, 0); /* user reallocs free block */ - } - started_working_on(ml); - size = size_of(ml); - if ( /* we can simplify the problem by adding the next chunk: */ - n > size && - !last_mallink(ml) && - (ph_next = phys_next_of(ml), free_of(ph_next)) && - n <= size + mallink_size() + size_of(ph_next) - ) { - /* add in the physically next chunk */ - unlink_free_chunk(ph_next); - combine_chunks(ml, ph_next); - size = size_of(ml); - check_mallinks("realloc, combining"); - } - if (n > size) { /* this didn't help */ - void *new; - register char *l1, *l2 = addr; - - stopped_working_on(ml); - if (!(new = l1 = malloc(n))) return NULL; /* no way */ - while (size--) *l1++ = *l2++; - free(addr); - check_work_empty("mv_realloc"); -#ifdef STORE - assert(! in_store(mallink_of_block(new))); -#endif - return new; - } - /* it helped, but maybe too well */ - n += mallink_size(); - if (n + MIN_SIZE <= size_of(ml)) { - truncate(ml, n); - } - stopped_working_on(ml); - check_mallinks("realloc exit"); - check_work_empty("realloc"); -#ifdef STORE - assert(! in_store(ml)); -#endif - return addr; -}} - -void * -calloc(size_t nmemb, size_t size) -{check_mallinks("calloc entry");{ - long *l1, *l2; - size_t n; - -printf("calloc\n"); - if (size == 0) return NULL; - if (nmemb == 0) return NULL; - - /* Check for overflow on the multiplication. The peephole-optimizer - * will eliminate all but one of the possibilities. - */ - if (sizeof(size_t) == sizeof(int)) { - if (UINT_MAX / size < nmemb) return NULL; - } else if (sizeof(size_t) == sizeof(long)) { - if (ULONG_MAX / size < nmemb) return NULL; - } else return NULL; /* can't happen, can it ? */ - - n = size * nmemb; - if (n < MIN_SIZE) n = align(MIN_SIZE); else n = align(n); - if (n >= (1L << LOG_MAX_SIZE)) return NULL; - l1 = (long *) malloc(n); - l2 = l1 + (n / sizeof(long)); /* n is at least long aligned */ - while ( l2 != l1 ) *--l2 = 0; - check_mallinks("calloc exit"); - check_work_empty("calloc exit"); - return (void *)l1; -}} -/* Auxiliary routines */ - -#ifdef STORE -private -sell_out(void) { - /* Frees all block in store. - */ - register mallink **stp; - - for (stp = &store[0]; stp < &store[MAX_STORE]; stp++) { - register mallink *ml = *stp; - - while (ml) { - *stp = log_next_of(ml); - set_store(ml, 0); - do_free(ml); - ml = *stp; - } - } - -} -#endif /* STORE */ - -#ifdef ASSERT -private -m_assert(const char *fn, int ln) -{ - char ch; - - while (*fn) - write(2, fn++, 1); - write(2, ": malloc assert failed in line ", 31); - ch = (ln / 100) + '0'; write(2, &ch, 1); ln %= 100; - ch = (ln / 10) + '0'; write(2, &ch, 1); ln %= 10; - ch = (ln / 1) + '0'; write(2, &ch, 1); - write(2, "\n", 1); - maldump(1); -} -#endif /* ASSERT */ - - -/**********************************************************/ -/* -/* This was file log.c -/* -/**********************************************************/ - -/* $Header$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ - -/* Logical manipulations. - The chunks are properly chained in the physical chain. -*/ - -privatedata mallink *free_list[MAX_FLIST]; - -private -link_free_chunk(register mallink *ml) -{ - /* The free chunk ml is inserted in its proper logical - chain. - */ - register mallink **mlp = &free_list[-1]; - register size_type n = size_of(ml); - register mallink *ml1; - - assert(n < (1L << LOG_MAX_SIZE)); - - do { - n >>= 1; - mlp++; - } - while (n >= MIN_SIZE); - - ml1 = *mlp; - set_log_prev(ml, MAL_NULL); - set_log_next(ml, ml1); - calc_checksum(ml); - if (ml1) { - /* link backwards - */ - set_log_prev(ml1, ml); - calc_checksum(ml1); - } - *mlp = ml; -} - -private -unlink_free_chunk(register mallink *ml) -{ - /* Unlinks a free chunk from (the middle of) the - logical chain. - */ - register mallink *next = log_next_of(ml); - register mallink *prev = log_prev_of(ml); - - if (!prev) { - /* it is the first in the chain */ - register mallink **mlp = &free_list[-1]; - register size_type n = size_of(ml); - - assert(n < (1L << LOG_MAX_SIZE)); - do { - n >>= 1; - mlp++; - } - while (n >= MIN_SIZE); - *mlp = next; - } - else { - set_log_next(prev, next); - calc_checksum(prev); - } - if (next) { - set_log_prev(next, prev); - calc_checksum(next); - } -} - -private mallink * -search_free_list(int class, size_t n) -{ - /* Searches the free_list[class] for a chunk of at least size n; - since it is searching a slightly undersized list, - such a block may not be there. - */ - register mallink *ml; - - for (ml = free_list[class]; ml; ml = log_next_of(ml)) - if (size_of(ml) >= n) - return ml; - return MAL_NULL; /* nothing found */ -} - -private mallink * -first_present(int class) -{ - /* Find the index i in free_list[] such that: - i >= class && free_list[i] != MAL_NULL. - Return MAL_NULL if no such i exists; - Otherwise, return the first block of this list, after - unlinking it. - */ - register mallink **mlp, *ml; - - for (mlp = &free_list[class]; mlp < &free_list[MAX_FLIST]; mlp++) { - if ((ml = *mlp) != MAL_NULL) { - - *mlp = log_next_of(ml); /* may be MAL_NULL */ - if (*mlp) { - /* unhook backward link - */ - set_log_prev(*mlp, MAL_NULL); - calc_checksum(*mlp); - } - return ml; - } - } - return MAL_NULL; -} - -#ifdef CHECK -private mallink * -free_list_entry(int i) { - /* To allow maldump.c access to log.c's private data. - */ - return free_list[i]; -} -#endif /* CHECK */ - - -/**********************************************************/ -/* -/* This was file phys.c -/* -/**********************************************************/ - -/* $Header$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -#include - -/* Physical manipulations. - The blocks concerned are not in any logical chain. -*/ - -private mallink * -create_chunk(void *p, size_t n) -{ - /* The newly acquired piece of memory at p, of length n, - is turned into a free chunk, properly chained in the - physical chain. - The address of the chunk is returned. - */ - register mallink *ml; - /* All of malloc memory is followed by a virtual chunk, the - mallink of which starts mallink_size() bytes past the last - byte in memory. - Its use is prevented by testing for ml == ml_last first. - */ - register mallink *last = ml_last; - - assert(!last || p == (char *)phys_next_of(last) - mallink_size()); - ml = (mallink *)((char *)p + mallink_size()); /* bump ml */ - new_mallink(ml); - started_working_on(ml); - set_free(ml, 1); - set_phys_prev(ml, last); - ml_last = ml; - - set_phys_next(ml, (mallink *)((char *)ml + n)); - calc_checksum(ml); - assert(size_of(ml) + mallink_size() == n); - if (last && free_of(last)) { - coalesce_backw(ml, last); - ml = last; - } - check_mallinks("create_chunk, phys. linked"); - return ml; -} - -private -truncate(register mallink *ml, size_t size) -{ - /* The chunk ml is truncated. - The chunk at ml is split in two. - The remaining part is then freed. - */ - register mallink *new = (mallink *)((char *)ml + size); - register mallink *ph_next = phys_next_of(ml); - - new_mallink(new); - set_free(new, 1); - set_phys_prev(new, ml); - set_phys_next(new, ph_next); - calc_checksum(new); - if (! last_mallink(ml)) { - set_phys_prev(ph_next, new); - calc_checksum(ph_next); - if (free_of(ph_next)) coalesce_forw(new, ph_next); - } - else ml_last = new; - set_phys_next(ml, new); - calc_checksum(ml); - - started_working_on(new); - link_free_chunk(new); - stopped_working_on(new); - check_mallinks("truncate"); -} - -private -combine_chunks(register mallink *ml1, register mallink *ml2) -{ - /* The chunks ml1 and ml2 are combined. - */ - register mallink *ml3 = phys_next_of(ml2); - - set_phys_next(ml1, ml3); - calc_checksum(ml1); - if (!last_mallink(ml2)) { - set_phys_prev(ml3, ml1); - calc_checksum(ml3); - } - if (ml_last == ml2) - ml_last = ml1; -} - - -/**********************************************************/ -/* -/* This was file check.c -/* -/**********************************************************/ - -/* $Header$ */ -/* - * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. - * See the copyright notice in the ACK home directory, in the file "Copyright". - */ -#include - -#ifdef CHECK /* otherwise this whole file is skipped */ - -/* ??? check these later */ -private acquire_malout(void), check_ml_last(const char *s); -private dump_all_mallinks(void), dump_free_list(int i); -private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml); -private working_on(mallink *ml); -private size_type checksum(mallink *ml); -static FILE *malout; - -private mallink *free_list_entry(int i); - -#define for_free_list(i,p) \ - for (p = free_list_entry(i); p; p = log_next_of(p)) - -#define for_all_mallinks(ml) /* backwards! */ \ - for (ml = ml_last; ml; \ - ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml)) - -/* Maldump */ - -static int pr_cnt = 0; - -maldump(int n) { - /* Dump pertinent info in pseudo-readable format; - abort afterwards if n != 0. - */ - static int dumping = 0; - int i; - - if (dumping) - return; - dumping++; - acquire_malout(); - fprintf(malout, - ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<"); - fprintf(malout, " ml_last = %p\n", ml_last); - if (++pr_cnt == 100) pr_cnt = 0; - dump_all_mallinks(); - fprintf(malout, - ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n"); - if (++pr_cnt == 100) pr_cnt = 0; - for (i = 0; i < MAX_FLIST; i++) - dump_free_list(i); - fprintf(malout, - ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n"); - fclose(malout); - dumping--; - if (n) - abort(); -} - -private -acquire_malout(void) { - static char buf[BUFSIZ]; - - if (!malout) { - malout = freopen("mal.out", "w", stderr); - setbuf(malout, buf); - } -} - -private -dump_all_mallinks(void) { - mallink *ml; - - for_all_mallinks (ml) { - if (print_loop(ml)) - return; - dump_mallink((char *)0, ml); - } -} - -private -dump_free_list(int i) { - mallink *ml = free_list_entry(i); - - if (!ml) - return; - fprintf(malout, "%2d: ", i); - for_free_list(i, ml) { - if (print_loop(ml)) - return; - fprintf(malout, "%p ", ml); - } - fprintf(malout, "<\n"); -} - -private int -print_loop(mallink *ml) { - if (print_of(ml) == pr_cnt) { - fprintf(malout, "... PRINT LOOP\n"); - return 1; - } - set_print(ml, pr_cnt); - return 0; -} - -private -dump_mallink(const char *s, mallink *ml) { - acquire_malout(); - if (s) - fprintf(malout, "%s: ", s); - fprintf(malout, "@: %p;", ml); - if (ml && checksum_of(ml) != checksum(ml)) - fprintf(malout, ">>>> CORRUPTED <<<<"); - if (!ml) { - fprintf(malout, "\n"); - return; - } - if (free_of(ml)) { - fprintf(malout, " l_p: %p;", _log_prev_of(ml)); - fprintf(malout, " l_n: %p;", _log_next_of(ml)); - } - fprintf(malout, " p_s: %p;", prev_size_of(ml)); - fprintf(malout, " t_s: %p;", _this_size_of(ml)); - fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml)); - fprintf(malout, " fr: %d;", free_of(ml)); - fprintf(malout, "\n"); -} - -/* Check_mallinks() checks the total data structure as accessible - through free_list[] and ml_last. All check_sums should be OK, - except those held in the small array off_colour. This is a - trick to allow to continue checking even when a few mallinks - are temporarily out of order. - Check_mallinks() tests for a lot of internal consistency. -*/ - -/* Some arbitrary constants */ -#define IN_ML_LAST 93 -#define IN_FREE_LIST 57 /* and in ml_last */ -#define CLEAR 21 - -#define VRIJ 1 -#define BEZET 2 - -private -check_mallinks(const char *s) { - mallink *ml; - size_type size; - int i; - char stat; - - check_ml_last(s); - stat = BEZET; - for_all_mallinks(ml) { - if (checksum_of(ml) != checksum(ml)) - Error("mallink info at %p corrupted", s, ml); - if (working_on(ml)) { - stat = BEZET; - continue; - } - if ( !last_mallink(ml) && - phys_prev_of(phys_next_of(ml)) != ml - ) - Error("upward chain bad at %p", s, ml); - if ( !first_mallink(ml) && - phys_next_of(phys_prev_of(ml)) != ml - ) - Error("downward chain bad at %p", s, ml); - if (free_of(ml)) { - if (stat == VRIJ) - Error("free mallink at %p follows free mallink", - s, ml); - stat = VRIJ; - } - else - stat = BEZET; - set_mark(ml, IN_ML_LAST); - } - - for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2) { - for_free_list(i, ml) { - if (working_on(ml)) - continue; - if (!free_of(ml)) - Error("occupied mallink %p occurs in free_list", s, ml); - switch (mark_of(ml)) { - case IN_ML_LAST: - set_mark(ml, IN_FREE_LIST); - break; - case IN_FREE_LIST: - Error("mallink %p occurs in 2 free_lists", - s, ml); - default: - Error("unknown mallink %p in free_list", - s, ml); - } - if (size_of(ml) < size) - Error("size of mallink %p too small", s, ml); - if (size_of(ml) >= 2*size) - Error("size of mallink %p too large", s, ml); - } - } - for_all_mallinks (ml) { - if (working_on(ml)) - continue; - if (free_of(ml) && mark_of(ml) != IN_FREE_LIST) - Error("free mallink %p is in no free_list", s, ml); - set_mark(ml, CLEAR); - } -} - -private -check_ml_last(const char *s) { - if (ml_last && _this_size_of(ml_last) == 0) - Error("size of ml_last == 0, at %p", s, ml_last); -} - -private size_type -checksum(mallink *ml) { - size_type sum = 0; - - if (free_of(ml)) { - sum += (size_type)_log_prev_of(ml); - sum += (size_type)_log_next_of(ml); - } - sum += (size_type)prev_size_of(ml); - sum += (size_type)_this_size_of(ml); - return sum; -} - -private -calc_checksum(mallink *ml) { - set_checksum(ml, checksum(ml)); -} - -#define N_COLOUR 10 -static mallink *off_colour[N_COLOUR]; - -private -started_working_on(mallink *ml) { - int i; - - for (i = 0; i < N_COLOUR; i++) - if (off_colour[i] == MAL_NULL) { - off_colour[i] = ml; - return; - } - Error("out of off_colour array at %p", "started_working_on", ml); -} - -private -stopped_working_on(mallink *ml) { - int i; - - for (i = 0; i < N_COLOUR; i++) - if (off_colour[i] == ml) { - off_colour[i] = MAL_NULL; - return; - } - Error("stopped working on mallink %p", "stopped_working_on", ml); -} - -private int -working_on(mallink *ml) { - int i; - - for (i = 0; i < N_COLOUR; i++) - if (off_colour[i] == ml) - return 1; - return 0; -} - -private -check_work_empty(const char *s) { - int i; - int cnt = 0; - - for (i = 0; i < N_COLOUR; i++) - if (off_colour[i] != MAL_NULL) - cnt++; - if (cnt != 0) - Error("off_colour not empty", s, MAL_NULL); -} - -private int -Error(const char *fmt, const char *s, mallink *ml) { - static int already_called = 0; - - if (already_called++) return 0; - setbuf(stdout, (char *) 0); - printf("%s: ", s); - printf(fmt, (long)ml); - printf("\n"); - acquire_malout(); - fprintf(malout, "%s: ", s); - fprintf(malout, fmt, (long)ml); - fprintf(malout, "\n"); - fflush(stdout); - maldump(1); - return 0; /* to satisfy lint */ -} - -#endif /* CHECK */ - diff --git a/commands/ash/trap.c b/commands/ash/trap.c index f4ec70fdf..83ce40991 100755 --- a/commands/ash/trap.c +++ b/commands/ash/trap.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,25 +31,45 @@ */ #ifndef lint -static char sccsid[] = "@(#)trap.c 5.2 (Berkeley) 4/12/91"; +#if 0 +static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/trap.c,v 1.29 2004/04/06 20:06:51 markm Exp $"); +*/ + +#include +#include +#include #include "shell.h" #include "main.h" #include "nodes.h" /* for other headers */ #include "eval.h" #include "jobs.h" +#include "show.h" #include "options.h" #include "syntax.h" -#include "signames.h" #include "output.h" #include "memalloc.h" #include "error.h" #include "trap.h" #include "mystring.h" -#include -#include +#if !defined(NO_HISTORY) && !defined(EDITLINE) +#include "myhistedit.h" +#endif +#include "builtins.h" +#ifdef __minix +#define NO_SIGINTERRUPT +#define NO_SYS_SIGNAME +#define NO_SYS_SIGLIST + +#endif + +typedef void (*sig_T)(int); /* * Sigmode records the current value of the signal handlers for the various @@ -64,40 +80,130 @@ static char sccsid[] = "@(#)trap.c 5.2 (Berkeley) 4/12/91"; #define S_DFL 1 /* default signal handling (SIG_DFL) */ #define S_CATCH 2 /* signal is caught */ #define S_IGN 3 /* signal is ignored (SIG_IGN) */ -#define S_HARD_IGN 4 /* signal is ignored permenantly */ +#define S_HARD_IGN 4 /* signal is ignored permanently */ +#define S_RESET 5 /* temporary - to reset a hard ignored sig */ -extern char nullstr[1]; /* null string */ +MKINIT char sigmode[_NSIG]; /* current value of signal */ +int pendingsigs; /* indicates some signal received */ +int is_interactive= -1; /* Shell is interactive */ +int in_dotrap; /* do we execute in a trap handler? */ +static char *volatile trap[_NSIG]; /* trap handler commands */ +static volatile sig_atomic_t gotsig[_NSIG]; + /* indicates specified signal received */ +static int ignore_sigchld; /* Used while handling SIGCHLD traps. */ +volatile sig_atomic_t gotwinch; + +static int sigstring_to_signum (char *); +static void printsignals (void); +static int getsigaction(int, sig_T *); +static void onsig (int); +#ifdef NO_SIGINTERRUPT +static int siginterrupt (int,int); +#endif +static char *strsigname (int); + + +/* + * Map a string to a signal number. + */ +static int +sigstring_to_signum(char *sig) +{ + + if (is_number(sig)) { + int signo; + + signo = atoi(sig); + return ((signo >= 0 && signo < _NSIG) ? signo : (-1)); + } else if (strcasecmp(sig, "exit") == 0) { + return (0); + } else { + int n; + + if (strncasecmp(sig, "sig", 3) == 0) + sig += 3; + for (n = 1; n < _NSIG; n++) + if (strcasecmp(strsigname(n), sig) == 0) + return (n); + } + return (-1); +} + + +/* + * Print a list of valid signal names. + */ +static void +printsignals(void) +{ + int n, outlen; + + outlen = 0; + for (n = 1; n < _NSIG; n++) { + if (strsigname(n)) { + out1fmt("%s", strsigname(n)); + outlen += strlen(strsigname(n)); + } else { + out1fmt("%d", n); + outlen += 3; /* good enough */ + } + ++outlen; + if (outlen > 70 || n == _NSIG - 1) { + out1str("\n"); + outlen = 0; + } else { + out1c(' '); + } + } +} -char *trap[MAXSIG+1]; /* trap handler commands */ -MKINIT char sigmode[MAXSIG]; /* current value of signal */ -char gotsig[MAXSIG]; /* indicates specified signal received */ -int pendingsigs; /* indicates some signal received */ /* * The trap builtin. */ - -trapcmd(argc, argv) char **argv; { +int +trapcmd(int argc, char **argv) +{ char *action; - char **ap; int signo; if (argc <= 1) { - for (signo = 0 ; signo <= MAXSIG ; signo++) { - if (trap[signo] != NULL) - out1fmt("%d: %s\n", signo, trap[signo]); + for (signo = 0 ; signo < _NSIG ; signo++) { + if (trap[signo] != NULL) { + if (signo == 0) { + out1fmt("trap -- '%s' %s\n", + trap[signo], "exit"); + } else if (strsigname(signo)) { + out1fmt("trap -- '%s' %s\n", + trap[signo], strsigname(signo)); + } else { + out1fmt("trap -- '%s' %d\n", + trap[signo], signo); + } + } } return 0; } - ap = argv + 1; - if (is_number(*ap)) - action = NULL; - else - action = *ap++; - while (*ap) { - if ((signo = number(*ap)) < 0 || signo > MAXSIG) - error("%s: bad trap", *ap); + action = NULL; + if (*++argv && strcmp(*argv, "--") == 0) + argv++; + if (*argv && sigstring_to_signum(*argv) == -1) { + if ((*argv)[0] != '-') { + action = *argv; + argv++; + } else if ((*argv)[1] == '\0') { + argv++; + } else if ((*argv)[1] == 'l' && (*argv)[2] == '\0') { + printsignals(); + return 0; + } else { + error("bad option %s", *argv); + } + } + while (*argv) { + if ((signo = sigstring_to_signum(*argv)) == -1) + error("bad signal %s", *argv); INTOFF; if (action) action = savestr(action); @@ -107,22 +213,21 @@ trapcmd(argc, argv) char **argv; { if (signo != 0) setsignal(signo); INTON; - ap++; + argv++; } return 0; } - /* * Clear traps on a fork. */ - void -clear_traps() { - char **tp; +clear_traps(void) +{ + char *volatile *tp; - for (tp = trap ; tp <= &trap[MAXSIG] ; tp++) { + for (tp = trap ; tp <= &trap[_NSIG - 1] ; tp++) { if (*tp && **tp) { /* trap not NULL or SIG_IGN */ INTOFF; ckfree(*tp); @@ -135,18 +240,16 @@ clear_traps() { } - /* * Set the signal handler for the specified signal. The routine figures * out what it should be set to. */ - -int -setsignal(signo) { +void +setsignal(int signo) +{ int action; - sig_t sigact; + sig_T sig, sigact = SIG_DFL; char *t; - extern void onsig(); if ((t = trap[signo]) == NULL) action = S_DFL; @@ -154,11 +257,10 @@ setsignal(signo) { action = S_CATCH; else action = S_IGN; - if (rootshell && action == S_DFL) { + if (action == S_DFL) { switch (signo) { case SIGINT: - if (iflag) - action = S_CATCH; + action = S_CATCH; break; case SIGQUIT: #if DEBUG @@ -169,68 +271,103 @@ setsignal(signo) { break; } #endif - /* FALLTHROUGH */ + action = S_CATCH; + break; case SIGTERM: - if (iflag) + if (rootshell && iflag) action = S_IGN; break; #if JOBS case SIGTSTP: case SIGTTOU: - if (jflag) + if (rootshell && mflag) action = S_IGN; break; +#endif +#ifndef NO_HISTORY + case SIGWINCH: + if (rootshell && iflag) + action = S_CATCH; + break; #endif } } - t = &sigmode[signo - 1]; - if (*t == 0) { /* current setting unknown */ + + t = &sigmode[signo]; + if (*t == 0) { /* - * There is a race condition here if action is not S_IGN. - * A signal can be ignored that shouldn't be. + * current setting unknown */ - if ((int)(sigact = signal(signo, SIG_IGN)) == -1) - error("Signal system call failed"); + if (!getsigaction(signo, &sigact)) { + /* + * Pretend it worked; maybe we should give a warning + * here, but other shells don't. We don't alter + * sigmode, so that we retry every time. + */ + return; + } if (sigact == SIG_IGN) { - *t = S_HARD_IGN; + if (mflag && (signo == SIGTSTP || + signo == SIGTTIN || signo == SIGTTOU)) { + *t = S_IGN; /* don't hard ignore these */ + } else + *t = S_HARD_IGN; } else { - *t = S_IGN; + *t = S_RESET; /* force to be set */ } } if (*t == S_HARD_IGN || *t == action) - return 0; + return; switch (action) { case S_DFL: sigact = SIG_DFL; break; case S_CATCH: sigact = onsig; break; case S_IGN: sigact = SIG_IGN; break; } *t = action; - return (int)signal(signo, sigact); + sig = signal(signo, sigact); + if (sig != SIG_ERR && action == S_CATCH) + siginterrupt(signo, 1); +} + + +/* + * Return the current setting for sig w/o changing it. + */ +static int +getsigaction(int signo, sig_T *sigact) +{ + struct sigaction sa; + + if (sigaction(signo, (struct sigaction *)0, &sa) == -1) + return 0; + *sigact = (sig_T) sa.sa_handler; + return 1; } /* * Ignore a signal. */ - void -ignoresig(signo) { - if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { +ignoresig(int signo) +{ + + if (sigmode[signo] != S_IGN && sigmode[signo] != S_HARD_IGN) { signal(signo, SIG_IGN); } - sigmode[signo - 1] = S_HARD_IGN; + sigmode[signo] = S_HARD_IGN; } #ifdef mkinit -INCLUDE "signames.h" +INCLUDE INCLUDE "trap.h" SHELLPROC { char *sm; clear_traps(); - for (sm = sigmode ; sm < sigmode + MAXSIG ; sm++) { + for (sm = sigmode ; sm < sigmode + _NSIG ; sm++) { if (*sm == S_IGN) *sm = S_HARD_IGN; } @@ -238,82 +375,119 @@ SHELLPROC { #endif - /* * Signal handler. */ +static void +onsig(int signo) +{ -void -onsig(signo) { +#ifndef BSD signal(signo, onsig); +#endif if (signo == SIGINT && trap[SIGINT] == NULL) { onint(); return; } - gotsig[signo - 1] = 1; - pendingsigs++; -} + if (signo != SIGCHLD || !ignore_sigchld) + gotsig[signo] = 1; + pendingsigs++; + + /* If we are currently in a wait builtin, prepare to break it */ + if ((signo == SIGINT || signo == SIGQUIT) && in_waitcmd != 0) + breakwaitcmd = 1; + /* + * If a trap is set, not ignored and not the null command, we need + * to make sure traps are executed even when a child blocks signals. + */ + if (Tflag && + trap[signo] != NULL && + ! trap[signo][0] == '\0' && + ! (trap[signo][0] == ':' && trap[signo][1] == '\0')) + breakwaitcmd = 1; + +#ifndef NO_HISTORY + if (signo == SIGWINCH) + gotwinch = 1; +#endif +} /* * Called to execute a trap. Perhaps we should avoid entering new trap * handlers while we are executing a trap handler. */ - void -dotrap() { +dotrap(void) +{ int i; int savestatus; + in_dotrap++; for (;;) { - for (i = 1 ; ; i++) { - if (gotsig[i - 1]) + for (i = 1; i < _NSIG; i++) { + if (gotsig[i]) { + gotsig[i] = 0; + if (trap[i]) { + /* + * Ignore SIGCHLD to avoid infinite + * recursion if the trap action does + * a fork. + */ + if (i == SIGCHLD) + ignore_sigchld++; + savestatus = exitstatus; + evalstring(trap[i]); + exitstatus = savestatus; + if (i == SIGCHLD) + ignore_sigchld--; + } break; - if (i >= MAXSIG) - goto done; + } } - gotsig[i - 1] = 0; - savestatus=exitstatus; - evalstring(trap[i]); - exitstatus=savestatus; + if (i >= _NSIG) + break; } -done: + in_dotrap--; pendingsigs = 0; } - /* * Controls whether the shell is interactive or not. */ - -int is_interactive; - void -setinteractive(on) { +setinteractive(int on) +{ if (on == is_interactive) return; setsignal(SIGINT); setsignal(SIGQUIT); setsignal(SIGTERM); +#ifndef NO_HISTORY + setsignal(SIGWINCH); +#endif is_interactive = on; } - /* * Called to exit the shell. */ - void -exitshell(status) { +exitshell(int status) +{ struct jmploc loc1, loc2; char *p; TRACE(("exitshell(%d) pid=%d\n", status, getpid())); - if (setjmp(loc1.loc)) goto l1; - if (setjmp(loc2.loc)) goto l2; + if (setjmp(loc1.loc)) { + goto l1; + } + if (setjmp(loc2.loc)) { + goto l2; + } handler = &loc1; if ((p = trap[0]) != NULL && *p != '\0') { trap[0] = NULL; @@ -326,3 +500,85 @@ l1: handler = &loc2; /* probably unnecessary */ #endif l2: _exit(status); } + +#ifdef NO_SIGINTERRUPT +static int siginterrupt(sig, flag) +int sig; +int flag; +{ + return 0; +} +#endif + +#ifdef NO_SYS_SIGNAME +static char *strsigname(sig) +int sig; +{ + switch(sig) + { + case 0: return "Signal 0"; /* 0 */ + case SIGHUP: return "hup"; /* 1 */ + case SIGINT: return "int"; /* 2 */ + case SIGQUIT: return "quit"; /* 3 */ + case SIGILL: return "ill"; /* 4 */ + case SIGTRAP: return "trap"; /* 5 */ + case SIGABRT: return "abrt"; /* 6 */ +#ifdef __minix_vmd + case SIGEMT: return "emt"; /* 7 */ +#else + case SIGBUS: return "bus"; /* 7 */ +#endif + case SIGFPE: return "fpe"; /* 8 */ + case SIGKILL: return "kill"; /* 9 */ + case SIGUSR1: return "usr1"; /* 10 */ + case SIGSEGV: return "segv"; /* 11 */ + case SIGUSR2: return "usr2"; /* 12 */ + case SIGPIPE: return "pipe"; /* 13 */ + case SIGALRM: return "alrm"; /* 14 */ + case SIGTERM: return "term"; /* 15 */ +#ifdef __minix_vmd + case 16: return "Signal 16"; /* 16 */ +#else + case SIGEMT: return "emt"; /* 16 */ +#endif + case SIGCHLD: return "chld"; /* 17 */ + case SIGCONT: return "cont"; /* 18 */ + case SIGSTOP: return "stop"; /* 19 */ + case SIGTSTP: return "tstp"; /* 20 */ + case SIGTTIN: return "ttin"; /* 21 */ + case SIGTTOU: return "ttou"; /* 22 */ + case SIGWINCH: return "winch"; /* 23 */ +#ifdef __minix_vmd + case SIGFPEMU: return "fpemu"; /* 30 */ +#endif + default: return "Signal n"; + } +} +#else +static char *strsigname(sig) +int sig; +{ + return sys_signame[sig]; +} +#endif + +#ifdef NO_SYS_SIGLIST +#include "signames.h" +char *strsiglist(sig) +int sig; +{ + if (sig > MAXSIG) + return NULL; + return sigmesg[sig]; +} +#else +char *strsiglist(sig) +int sig; +{ + return sys_siglist[sig]; +} +#endif + +/* + * $PchId: trap.c,v 1.7 2006/05/23 11:56:21 philip Exp $ + */ diff --git a/commands/ash/trap.h b/commands/ash/trap.h index afa984cb0..a61672ab6 100755 --- a/commands/ash/trap.h +++ b/commands/ash/trap.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,23 +29,24 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)trap.h 5.1 (Berkeley) 3/7/91 + * @(#)trap.h 8.3 (Berkeley) 6/5/95 + * $FreeBSD: src/bin/sh/trap.h,v 1.12 2004/04/06 20:06:51 markm Exp $ */ extern int pendingsigs; +extern int in_dotrap; +extern int is_interactive; +extern volatile sig_atomic_t gotwinch; -#ifdef __STDC__ +int trapcmd(int, char **); void clear_traps(void); -int setsignal(int); +void setsignal(int); void ignoresig(int); void dotrap(void); void setinteractive(int); void exitshell(int); -#else -void clear_traps(); -int setsignal(); -void ignoresig(); -void dotrap(); -void setinteractive(); -void exitshell(); -#endif +char *strsiglist(int); + +/* + * $PchId: trap.h,v 1.6 2006/05/22 12:48:30 philip Exp $ + */ diff --git a/commands/ash/var.c b/commands/ash/var.c index f6e38d05f..82d8de1d7 100755 --- a/commands/ash/var.c +++ b/commands/ash/var.c @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -35,13 +31,27 @@ */ #ifndef lint -static char sccsid[] = "@(#)var.c 5.3 (Berkeley) 4/12/91"; +#if 0 +static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95"; +#endif #endif /* not lint */ +/* +#include +__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $"); +*/ + +#include +#include +#ifndef NO_PATHS_H +#include +#endif /* * Shell variables. */ +#include + #include "shell.h" #include "output.h" #include "expand.h" @@ -55,7 +65,16 @@ static char sccsid[] = "@(#)var.c 5.3 (Berkeley) 4/12/91"; #include "memalloc.h" #include "error.h" #include "mystring.h" +#include "parser.h" +#if !defined(NO_HISTORY) && !defined(EDITLINE) +#include "myhistedit.h" +#endif +#include "builtins.h" + +#ifndef _PATH_DEFPATH +#define _PATH_DEFPATH "/usr/bin:/bin" +#endif #define VTABSIZE 39 @@ -64,48 +83,57 @@ struct varinit { struct var *var; int flags; char *text; + void (*func)(const char *); }; -#if ATTY -struct var vatty; +#ifndef NO_HISTORY +struct var vhistsize; #endif struct var vifs; struct var vmail; struct var vmpath; struct var vpath; +struct var vppid; struct var vps1; struct var vps2; struct var vpse; struct var vvers; -#if ATTY -struct var vterm; -#endif +STATIC struct var voptind; -const struct varinit varinit[] = { -#if ATTY - {&vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY="}, +STATIC const struct varinit varinit[] = { +#if !defined(NO_HISTORY) && !defined(EDITLINE) + { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", + sethistsize }, #endif - {&vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n"}, - {&vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL="}, - {&vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH="}, - {&vpath, VSTRFIXED|VTEXTFIXED, "PATH=:/bin:/usr/bin"}, - /* + { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", + NULL }, + { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", + NULL }, + { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", + NULL }, + { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH, + changepath }, + { &vppid, VSTRFIXED|VTEXTFIXED|VUNSET, "PPID=", + NULL }, + /* * vps1 depends on uid */ - {&vps2, VSTRFIXED|VTEXTFIXED, "PS2=> "}, - {&vpse, VSTRFIXED|VTEXTFIXED, "PSE=* "}, -#if ATTY - {&vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM="}, -#endif - {NULL, 0, NULL} + { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", + NULL }, + { &vpse, VSTRFIXED|VTEXTFIXED|VUNSET, "PSE=", + NULL }, + { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", + getoptsreset }, + { NULL, 0, NULL, + NULL } }; -struct var *vartab[VTABSIZE]; +STATIC struct var *vartab[VTABSIZE]; -STATIC void unsetvar __P((char *)); -STATIC struct var **hashvar __P((char *)); -STATIC int varequal __P((char *, char *)); +STATIC struct var **hashvar(char *); +STATIC int varequal(char *, char *); +STATIC int localevar(char *); /* * Initialize the varable symbol tables and import the environment @@ -133,7 +161,9 @@ INIT { */ void -initvar() { +initvar(void) +{ + char ppid[20]; const struct varinit *ip; struct var *vp; struct var **vpp; @@ -145,6 +175,7 @@ initvar() { *vpp = vp; vp->text = ip->text; vp->flags = ip->flags; + vp->func = ip->func; } } /* @@ -154,20 +185,48 @@ initvar() { vpp = hashvar("PS1="); vps1.next = *vpp; *vpp = &vps1; - vps1.text = getuid() ? "PS1=$ " : "PS1=# "; + vps1.text = geteuid() ? "PS1=$ " : "PS1=# "; vps1.flags = VSTRFIXED|VTEXTFIXED; } + if ((vppid.flags & VEXPORT) == 0) { + fmtstr(ppid, sizeof(ppid), "%d", (int)getppid()); + setvarsafe("PPID", ppid, 0); + } } /* - * Set the value of a variable. The flags argument is ored with the + * Safe version of setvar, returns 1 on success 0 on failure. + */ + +int +setvarsafe(char *name, char *val, int flags) +{ + struct jmploc jmploc; + struct jmploc *volatile savehandler = handler; + int err = 0; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &err; +#endif + + if (setjmp(jmploc.loc)) + err = 1; + else { + handler = &jmploc; + setvar(name, val, flags); + } + handler = savehandler; + return err; +} + +/* + * Set the value of a variable. The flags argument is tored with the * flags of the variable. If val is NULL, the variable is unset. */ void -setvar(name, val, flags) - char *name, *val; - { +setvar(char *name, char *val, int flags) +{ char *p, *q; int len; int namelen; @@ -176,8 +235,9 @@ setvar(name, val, flags) isbad = 0; p = name; - if (! is_name(*p++)) + if (! is_name(*p)) isbad = 1; + p++; for (;;) { if (! is_in_name(*p)) { if (*p == '\0' || *p == '=') @@ -188,7 +248,7 @@ setvar(name, val, flags) } namelen = p - name; if (isbad) - error("%.*s: is read only", namelen, name); + error("%.*s: bad variable name", namelen, name); len = namelen + 2; /* 2 is space for '=' and '\0' */ if (val == NULL) { flags |= VUNSET; @@ -206,7 +266,26 @@ setvar(name, val, flags) setvareq(nameeq, flags); } +STATIC int +localevar(char *s) +{ + static char *lnames[7] = { + "ALL", "COLLATE", "CTYPE", "MONETARY", + "NUMERIC", "TIME", NULL + }; + char **ss; + if (*s != 'L') + return 0; + if (varequal(s + 1, "ANG")) + return 1; + if (strncmp(s + 1, "C_", 2) != 0) + return 0; + for (ss = lnames; *ss ; ss++) + if (varequal(s + 3, *ss)) + return 1; + return 0; +} /* * Same as setvar except that the variable and value are passed in @@ -216,28 +295,42 @@ setvar(name, val, flags) */ void -setvareq(s, flags) - char *s; - { +setvareq(char *s, int flags) +{ struct var *vp, **vpp; + int len; + if (aflag) + flags |= VEXPORT; vpp = hashvar(s); for (vp = *vpp ; vp ; vp = vp->next) { if (varequal(s, vp->text)) { if (vp->flags & VREADONLY) { - int len = strchr(s, '=') - s; + len = strchr(s, '=') - s; error("%.*s: is read only", len, s); } INTOFF; - if (vp == &vpath) - changepath(s + 5); /* 5 = strlen("PATH=") */ + + if (vp->func && (flags & VNOFUNC) == 0) + (*vp->func)(strchr(s, '=') + 1); + if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0) ckfree(vp->text); - vp->flags &=~ (VTEXTFIXED|VSTACK|VUNSET); + + vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET); vp->flags |= flags; vp->text = s; + + /* + * We could roll this to a function, to handle it as + * a regular variable function callback, but why bother? + */ if (vp == &vmpath || (vp == &vmail && ! mpathset())) chkmail(1); + if ((vp->flags & VEXPORT) && localevar(s)) { + putenv(s); + (void) setlocale(LC_ALL, ""); + } INTON; return; } @@ -247,7 +340,14 @@ setvareq(s, flags) vp->flags = flags; vp->text = s; vp->next = *vpp; + vp->func = NULL; + INTOFF; *vpp = vp; + if ((vp->flags & VEXPORT) && localevar(s)) { + putenv(s); + (void) setlocale(LC_ALL, ""); + } + INTON; } @@ -257,9 +357,8 @@ setvareq(s, flags) */ void -listsetvar(list) - struct strlist *list; - { +listsetvar(struct strlist *list) +{ struct strlist *lp; INTOFF; @@ -276,9 +375,8 @@ listsetvar(list) */ char * -lookupvar(name) - char *name; - { +lookupvar(char *name) +{ struct var *v; for (v = *hashvar(name) ; v ; v = v->next) { @@ -300,9 +398,8 @@ lookupvar(name) */ char * -bltinlookup(name, doall) - char *name; - { +bltinlookup(char *name, int doall) +{ struct strlist *sp; struct var *v; @@ -312,8 +409,8 @@ bltinlookup(name, doall) } for (v = *hashvar(name) ; v ; v = v->next) { if (varequal(v->text, name)) { - if (v->flags & VUNSET - || ! doall && (v->flags & VEXPORT) == 0) + if ((v->flags & VUNSET) + || (!doall && (v->flags & VEXPORT) == 0)) return NULL; return strchr(v->text, '=') + 1; } @@ -329,7 +426,8 @@ bltinlookup(name, doall) */ char ** -environment() { +environment(void) +{ int nenv; struct var **vpp; struct var *vp; @@ -359,15 +457,14 @@ environment() { */ #ifdef mkinit -MKINIT void shprocvar(); - SHELLPROC { shprocvar(); } #endif void -shprocvar() { +shprocvar(void) +{ struct var **vpp; struct var *vp, **prev; @@ -400,14 +497,21 @@ shprocvar() { */ int -showvarscmd(argc, argv) char **argv; { +showvarscmd(int argc __unused, char **argv __unused) +{ struct var **vpp; struct var *vp; + const char *s; for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { for (vp = *vpp ; vp ; vp = vp->next) { - if ((vp->flags & VUNSET) == 0) - out1fmt("%s\n", vp->text); + if (vp->flags & VUNSET) + continue; + for (s = vp->text; *s != '='; s++) + out1c(*s); + out1c('='); + out1qstr(s + 1); + out1c('\n'); } } return 0; @@ -420,15 +524,35 @@ showvarscmd(argc, argv) char **argv; { */ int -exportcmd(argc, argv) char **argv; { +exportcmd(int argc, char **argv) +{ struct var **vpp; struct var *vp; char *name; char *p; + char *cmdname; + int ch, values; int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; + cmdname = argv[0]; + optreset = optind = 1; + opterr = 0; + values = 0; + while ((ch = getopt(argc, argv, "p")) != -1) { + switch (ch) { + case 'p': + values = 1; + break; + case '?': + default: + error("unknown option: -%c", optopt); + } + } + argc -= optind; + argv += optind; + listsetvar(cmdenviron); - if (argc > 1) { + if (argc != 0) { while ((name = *argptr++) != NULL) { if ((p = strchr(name, '=')) != NULL) { p++; @@ -436,7 +560,12 @@ exportcmd(argc, argv) char **argv; { vpp = hashvar(name); for (vp = *vpp ; vp ; vp = vp->next) { if (varequal(vp->text, name)) { + vp->flags |= flag; + if ((vp->flags & VEXPORT) && localevar(vp->text)) { + putenv(vp->text); + (void) setlocale(LC_ALL, ""); + } goto found; } } @@ -448,8 +577,16 @@ found:; for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { for (vp = *vpp ; vp ; vp = vp->next) { if (vp->flags & flag) { + if (values) { + out1str(cmdname); + out1c(' '); + } for (p = vp->text ; *p != '=' ; p++) out1c(*p); + if (values && !(vp->flags & VUNSET)) { + out1c('='); + out1qstr(p + 1); + } out1c('\n'); } } @@ -463,7 +600,9 @@ found:; * The "local" command. */ -localcmd(argc, argv) char **argv; { +int +localcmd(int argc __unused, char **argv __unused) +{ char *name; if (! in_function()) @@ -483,9 +622,8 @@ localcmd(argc, argv) char **argv; { */ void -mklocal(name) - char *name; - { +mklocal(char *name) +{ struct localvar *lvp; struct var **vpp; struct var *vp; @@ -493,8 +631,8 @@ mklocal(name) INTOFF; lvp = ckmalloc(sizeof (struct localvar)); if (name[0] == '-' && name[1] == '\0') { - lvp->text = ckmalloc(sizeof optval); - bcopy(optval, lvp->text, sizeof optval); + lvp->text = ckmalloc(sizeof optlist); + memcpy(lvp->text, optlist, sizeof optlist); vp = NULL; } else { vpp = hashvar(name); @@ -527,7 +665,8 @@ mklocal(name) */ void -poplocalvars() { +poplocalvars(void) +{ struct localvar *lvp; struct var *vp; @@ -535,10 +674,10 @@ poplocalvars() { localvars = lvp->next; vp = lvp->vp; if (vp == NULL) { /* $- saved */ - bcopy(lvp->text, optval, sizeof optval); + memcpy(optlist, lvp->text, sizeof optlist); ckfree(lvp->text); } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { - unsetvar(vp->text); + (void)unsetvar(vp->text); } else { if ((vp->flags & VTEXTFIXED) == 0) ckfree(vp->text); @@ -550,7 +689,9 @@ poplocalvars() { } -setvarcmd(argc, argv) char **argv; { +int +setvarcmd(int argc, char **argv) +{ if (argc <= 2) return unsetcmd(argc, argv); else if (argc == 3) @@ -567,14 +708,31 @@ setvarcmd(argc, argv) char **argv; { * with the same name. */ -unsetcmd(argc, argv) char **argv; { +int +unsetcmd(int argc __unused, char **argv __unused) +{ char **ap; + int i; + int flg_func = 0; + int flg_var = 0; + int ret = 0; - for (ap = argv + 1 ; *ap ; ap++) { - unsetfunc(*ap); - unsetvar(*ap); + while ((i = nextopt("vf")) != '\0') { + if (i == 'f') + flg_func = 1; + else + flg_var = 1; } - return 0; + if (flg_func == 0 && flg_var == 0) + flg_var = 1; + + for (ap = argptr; *ap ; ap++) { + if (flg_func) + ret |= unsetfunc(*ap); + if (flg_var) + ret |= unsetvar(*ap); + } + return ret; } @@ -582,22 +740,25 @@ unsetcmd(argc, argv) char **argv; { * Unset the specified variable. */ -STATIC void -unsetvar(s) - char *s; - { +int +unsetvar(char *s) +{ struct var **vpp; struct var *vp; vpp = hashvar(s); for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { if (varequal(vp->text, s)) { + if (vp->flags & VREADONLY) + return (1); INTOFF; - if (*(strchr(vp->text, '=') + 1) != '\0' - || vp->flags & VREADONLY) { + if (*(strchr(vp->text, '=') + 1) != '\0') setvar(s, nullstr, 0); + if ((vp->flags & VEXPORT) && localevar(vp->text)) { + unsetenv(s); + setlocale(LC_ALL, ""); } - vp->flags &=~ VEXPORT; + vp->flags &= ~VEXPORT; vp->flags |= VUNSET; if ((vp->flags & VSTRFIXED) == 0) { if ((vp->flags & VTEXTFIXED) == 0) @@ -606,9 +767,11 @@ unsetvar(s) ckfree(vp); } INTON; - return; + return (0); } } + + return (0); } @@ -618,14 +781,13 @@ unsetvar(s) */ STATIC struct var ** -hashvar(p) - register char *p; - { +hashvar(char *p) +{ unsigned int hashval; - hashval = *p << 4; + hashval = ((unsigned char) *p) << 4; while (*p && *p != '=') - hashval += *p++; + hashval += (unsigned char) *p++; return &vartab[hashval % VTABSIZE]; } @@ -638,9 +800,8 @@ hashvar(p) */ STATIC int -varequal(p, q) - register char *p, *q; - { +varequal(char *p, char *q) +{ while (*p == *q++) { if (*p++ == '=') return 1; @@ -649,3 +810,7 @@ varequal(p, q) return 1; return 0; } + +/* + * $PchId: var.c,v 1.5 2006/05/22 12:28:49 philip Exp $ + */ diff --git a/commands/ash/var.h b/commands/ash/var.h index 70a36065f..afa62565a 100755 --- a/commands/ash/var.h +++ b/commands/ash/var.h @@ -1,6 +1,6 @@ /*- - * Copyright (c) 1991 The Regents of the University of California. - * All rights reserved. + * 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. @@ -13,10 +13,6 @@ * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 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. @@ -33,7 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)var.h 5.1 (Berkeley) 3/7/91 + * @(#)var.h 8.2 (Berkeley) 5/4/95 + * $FreeBSD: src/bin/sh/var.h,v 1.12 2004/04/06 20:06:51 markm Exp $ */ /* @@ -41,43 +38,45 @@ */ /* flags */ -#define VEXPORT 01 /* variable is exported */ -#define VREADONLY 02 /* variable cannot be modified */ -#define VSTRFIXED 04 /* variable struct is staticly allocated */ -#define VTEXTFIXED 010 /* text is staticly allocated */ -#define VSTACK 020 /* text is allocated on the stack */ -#define VUNSET 040 /* the variable is not set */ +#define VEXPORT 0x01 /* variable is exported */ +#define VREADONLY 0x02 /* variable cannot be modified */ +#define VSTRFIXED 0x04 /* variable struct is staticly allocated */ +#define VTEXTFIXED 0x08 /* text is staticly allocated */ +#define VSTACK 0x10 /* text is allocated on the stack */ +#define VUNSET 0x20 /* the variable is not set */ +#define VNOFUNC 0x40 /* don't call the callback function */ struct var { struct var *next; /* next entry in hash list */ - int flags; /* flags are defined above */ - char *text; /* name=value */ + int flags; /* flags are defined above */ + char *text; /* name=value */ + void (*func)(const char *); + /* function to be called when */ + /* the variable gets set/unset */ }; struct localvar { - struct localvar *next; /* next local variable in list */ - struct var *vp; /* the variable that was made local */ - int flags; /* saved flags */ - char *text; /* saved text */ + struct localvar *next; /* next local variable in list */ + struct var *vp; /* the variable that was made local */ + int flags; /* saved flags */ + char *text; /* saved text */ }; struct localvar *localvars; -#if ATTY -extern struct var vatty; -#endif extern struct var vifs; extern struct var vmail; extern struct var vmpath; extern struct var vpath; +extern struct var vppid; extern struct var vps1; extern struct var vps2; extern struct var vpse; -#if ATTY -extern struct var vterm; +#ifndef NO_HISTORY +extern struct var vhistsize; #endif /* @@ -87,43 +86,39 @@ extern struct var vterm; */ #define ifsval() (vifs.text + 4) +#define ifsset() ((vifs.flags & VUNSET) == 0) #define mailval() (vmail.text + 5) #define mpathval() (vmpath.text + 9) #define pathval() (vpath.text + 5) #define ps1val() (vps1.text + 4) #define ps2val() (vps2.text + 4) #define pseval() (vpse.text + 4) -#if ATTY -#define termval() (vterm.text + 5) +#define optindval() (voptind.text + 7) +#ifndef NO_HISTORY +#define histsizeval() (vhistsize.text + 9) #endif -#if ATTY -#define attyset() ((vatty.flags & VUNSET) == 0) -#endif #define mpathset() ((vmpath.flags & VUNSET) == 0) - -#ifdef __STDC__ -void initvar(); +void initvar(void); void setvar(char *, char *, int); void setvareq(char *, int); struct strlist; void listsetvar(struct strlist *); char *lookupvar(char *); char *bltinlookup(char *, int); -char **environment(); +char **environment(void); +void shprocvar(void); int showvarscmd(int, char **); +int exportcmd(int, char **); +int localcmd(int, char **); void mklocal(char *); void poplocalvars(void); -#else -void initvar(); -void setvar(); -void setvareq(); -void listsetvar(); -char *lookupvar(); -char *bltinlookup(); -char **environment(); -int showvarscmd(); -void mklocal(); -void poplocalvars(); -#endif +int setvarcmd(int, char **); +int unsetcmd(int, char **); +int unsetvar(char *); +int setvarsafe(char *, char *, int); + +/* + * $PchId: var.h,v 1.4 2006/03/29 12:04:45 philip Exp $ + */