Importing bin/sh

/etc/profile enables by default tabcompletion, as well as emacs mode,
in order to keep the old MINIX ash behavior.

Note: The shell now refuses to source a script without a relative or
      absolute path.
      This means:
        - '. myscript.sh' fails, while
        - '. ./myscript.sh' succeeds

Change-Id: I0be89b0747bd005e4c05cadb937af86883627dc6
This commit is contained in:
Lionel Sambuc 2014-08-03 23:10:41 +02:00 committed by Gerrit Code Review
parent 2d64210c1d
commit d90bee9749
117 changed files with 12265 additions and 10664 deletions

View file

@ -2,7 +2,7 @@
# @(#)Makefile 8.1 (Berkeley) 5/31/93
SUBDIR= cat chmod cp date df echo ed expr hostname \
kill ksh ln ls mkdir mv pax pwd rm rmdir \
kill ksh ln ls mkdir mv pax pwd rm rmdir sh \
sleep stty sync test
.include <bsd.subdir.mk>

88
bin/sh/Makefile Normal file
View file

@ -0,0 +1,88 @@
# $NetBSD: Makefile,v 1.99 2012/12/02 12:55:27 apb Exp $
# @(#)Makefile 8.4 (Berkeley) 5/5/95
.include <bsd.own.mk>
YHEADER=1
PROG= sh
SHSRCS= alias.c cd.c echo.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 options.c parser.c redir.c show.c trap.c output.c var.c \
test.c kill.c syntax.c
GENSRCS=arith.c arith_lex.c builtins.c init.c nodes.c
GENHDRS=arith.h builtins.h nodes.h token.h
SRCS= ${SHSRCS} ${GENSRCS}
DPSRCS+=${GENHDRS}
LDADD+= -ll -ledit -lterminfo
DPADD+= ${LIBL} ${LIBEDIT} ${LIBTERMINFO}
LFLAGS= -8 # 8-bit lex scanner for arithmetic
# Environment for scripts executed during build.
SCRIPT_ENV= \
AWK=${TOOL_AWK:Q} \
SED=${TOOL_SED:Q}
# The .depend file can get references to these temporary files
.OPTIONAL: lex.yy.c y.tab.c
.ifdef CRUNCHEDPROG
LFLAGS+=-L
YFLAGS+=-l
.endif
CPPFLAGS+=-DSHELL -I. -I${.CURDIR}
#XXX: For testing only.
#CPPFLAGS+=-DDEBUG=2
#COPTS+=-g
#CFLAGS+=-funsigned-char
#TARGET_CHARFLAG?= -DTARGET_CHAR="unsigned char" -funsigned-char
.ifdef SMALLPROG
CPPFLAGS+=-DSMALL
.else
SRCS+=printf.c
.endif
.PATH: ${.CURDIR}/bltin ${NETBSDSRCDIR}/bin/test \
${NETBSDSRCDIR}/usr.bin/printf \
${NETBSDSRCDIR}/bin/kill
CLEANFILES+= ${GENSRCS} ${GENHDRS} y.tab.h
CLEANFILES+= trace
token.h: mktokens
${_MKTARGET_CREATE}
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC}
.ORDER: builtins.h builtins.c
builtins.h builtins.c: mkbuiltins shell.h builtins.def
${_MKTARGET_CREATE}
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC} ${.OBJDIR}
[ -f builtins.h ]
init.c: mkinit.sh ${SHSRCS}
${_MKTARGET_CREATE}
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC}
.ORDER: nodes.h nodes.c
nodes.c nodes.h: mknodes.sh nodetypes nodes.c.pat
${_MKTARGET_CREATE}
${SCRIPT_ENV} ${HOST_SH} ${.ALLSRC} ${.OBJDIR}
[ -f nodes.h ]
.if ${USETOOLS} == "yes"
NBCOMPATLIB= -L${TOOLDIR}/lib -lnbcompat
.endif
.if make(install)
SUBDIR+=USD.doc
.endif
COPTS.printf.c = -Wno-format-nonliteral
COPTS.jobs.c = -Wno-format-nonliteral
.include <bsd.prog.mk>
.include <bsd.subdir.mk>

View file

@ -1,5 +1,5 @@
# $NetBSD: TOUR,v 1.10 2008/11/15 17:01:38 snj Exp $
# @(#)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
@ -22,7 +22,7 @@ SOURCE CODE GENERATORS: Files whose names begin with "mk" are
programs that generate source code. A complete list of these
programs is:
program intput files generates
program input files generates
------- ------------ ---------
mkbuiltins builtins builtins.h builtins.c
mkinit *.c init.c
@ -91,7 +91,7 @@ INTERRUPTS: In an interactive shell, an interrupt will cause an
EXINT exception to return to the main command loop. (Exception:
EXINT is not raised if the user traps interrupts using the trap
command.) The INTOFF and INTON macros (defined in exception.h)
provide uninterruptable critical sections. Between the execution
provide uninterruptible critical sections. Between the execution
of INTOFF and the execution of INTON, interrupt signals will be
held for later delivery. INTOFF and INTON can be nested.
@ -110,7 +110,7 @@ string was going to be:
p = stackptr;
*p++ = c; /* repeated as many times as needed */
stackptr = p;
The folloing three macros (defined in memalloc.h) perform these
The following three macros (defined in memalloc.h) perform these
operations, but grow the stack if you run off the end:
STARTSTACKSTR(p);
STPUTC(c, p); /* repeated as many times as needed */
@ -232,7 +232,7 @@ control is defined.
REDIR.C: Ash allows file descriptors to be redirected and then
restored without forking off a child process. This is accom-
plished by duplicating the original file descriptors. The redir-
tab structure records where the file descriptors have be dupli-
tab structure records where the file descriptors have been dupli-
cated to.
EXEC.C: The routine find_command locates a command, and enters
@ -327,7 +327,7 @@ is called at appropriate points to actually handle the signal.
When an interrupt is caught and no trap has been set for that
signal, the routine "onint" in error.c is called.
OUTPUT: Ash uses it's own output routines. There are three out-
OUTPUT: Ash uses its own output routines. There are three out-
put structures allocated. "Output" represents the standard out-
put, "errout" the standard error, and "memout" contains output
which is to be stored in memory. This last is used when a buil-
@ -355,6 +355,3 @@ 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 $

12
bin/sh/USD.doc/Makefile Normal file
View file

@ -0,0 +1,12 @@
# $NetBSD: Makefile,v 1.1 2010/08/22 01:58:16 perry Exp $
# @(#)Makefile 8.1 (Berkeley) 8/14/93
DIR= usd/03.shell
SRCS= Rv7man t.mac t1 t2 t3 t4
MACROS= -ms
paper.ps: ${SRCS}
${TOOL_REFER} -e -p ${SRCS} | \
${TOOL_ROFF_PS} ${MACROS} > ${.TARGET}
.include <bsd.doc.mk>

405
bin/sh/USD.doc/Rv7man Normal file
View file

@ -0,0 +1,405 @@
%A L. P. Deutsch
%A B. W. Lampson
%T An online editor
%J Comm. Assoc. Comp. Mach.
%V 10
%N 12
%D December 1967
%P 793-799, 803
%K qed
.[
%r 17
%K cstr
%R Comp. Sci. Tech. Rep. No. 17
%I Bell Laboratories
%C Murray Hill, New Jersey
%A B. W. Kernighan
%A L. L. Cherry
%T A System for Typesetting Mathematics
%d May 1974, revised April 1977
%J Comm. Assoc. Comp. Mach.
%K acm cacm
%V 18
%P 151-157
%D March 1975
.]
%T U\s-2NIX\s0 Time-Sharing System: Document Preparation
%K unix bstj
%A B. W. Kernighan
%A M. E. Lesk
%A J. F. Ossanna
%J Bell Sys. Tech. J.
%V 57
%N 6
%P 2115-2135
%D 1978
%A T. A. Dolotta
%A J. R. Mashey
%T An Introduction to the Programmer's Workbench
%J Proc. 2nd Int. Conf. on Software Engineering
%D October 13-15, 1976
%P 164-168
%T U\s-2NIX\s0 Time-Sharing System: The Programmer's Workbench
%A T. A. Dolotta
%A R. C. Haight
%A J. R. Mashey
%J Bell Sys. Tech. J.
%V 57
%N 6
%P 2177-2200
%D 1978
%K unix bstj
%T U\s-2NIX\s0 Time-Sharing System: U\s-2NIX\s0 on a Microprocessor
%K unix bstj
%A H. Lycklama
%J Bell Sys. Tech. J.
%V 57
%N 6
%P 2087-2101
%D 1978
%T The C Programming Language
%A B. W. Kernighan
%A D. M. Ritchie
%I Prentice-Hall
%C Englewood Cliffs, New Jersey
%D 1978
%T Computer Recreations
%A Aleph-null
%J Software Practice and Experience
%V 1
%N 2
%D April-June 1971
%P 201-204
%T U\s-2NIX\s0 Time-Sharing System: The U\s-2NIX\s0 Shell
%A S. R. Bourne
%K unix bstj
%J Bell Sys. Tech. J.
%V 57
%N 6
%P 1971-1990
%D 1978
%A L. P. Deutsch
%A B. W. Lampson
%T \*sSDS\*n 930 time-sharing system preliminary reference manual
%R Doc. 30.10.10, Project \*sGENIE\*n
%C Univ. Cal. at Berkeley
%D April 1965
%A R. J. Feiertag
%A E. I. Organick
%T The Multics input-output system
%J Proc. Third Symposium on Operating Systems Principles
%D October 18-20, 1971
%P 35-41
%A D. G. Bobrow
%A J. D. Burchfiel
%A D. L. Murphy
%A R. S. Tomlinson
%T \*sTENEX\*n, a Paged Time Sharing System for the \*sPDP\*n-10
%J Comm. Assoc. Comp. Mach.
%V 15
%N 3
%D March 1972
%K tenex
%P 135-143
%A R. E. Griswold
%A D. R. Hanson
%T An Overview of SL5
%J SIGPLAN Notices
%V 12
%N 4
%D April 1977
%P 40-50
%A E. W. Dijkstra
%T Cooperating Sequential Processes
%B Programming Languages
%E F. Genuys
%I Academic Press
%C New York
%D 1968
%P 43-112
%A J. A. Hawley
%A W. B. Meyer
%T M\s-2UNIX\s0, A Multiprocessing Version of U\s-2NIX\s0
%K munix unix
%R M.S. Thesis
%I Naval Postgraduate School
%C Monterey, Cal.
%D 1975
%T The U\s-2NIX\s0 Time-Sharing System
%K unix bstj
%A D. M. Ritchie
%A K. Thompson
%J Bell Sys. Tech. J.
%V 57
%N 6
%P 1905-1929
%D 1978
%A E. I. Organick
%T The M\s-2ULTICS\s0 System
%K multics
%I M.I.T. Press
%C Cambridge, Mass.
%D 1972
%T UNIX for Beginners
%A B. W. Kernighan
%D 1978
%T U\s-2NIX\s0 Programmer's Man\&ual
%A K. Thompson
%A D. M. Ritchie
%K unix
%I Bell Laboratories
%O Seventh Edition.
%D 1978
%A K. Thompson
%T The U\s-2NIX\s0 Command Language
%B Structured Programming\(emInfotech State of the Art Report
%I Infotech International Ltd.
%C Nicholson House, Maidenhead, Berkshire, England
%D March 1975
%P 375-384
%K unix
%X pwb
Brief description of shell syntax and semantics, without much
detail on implementation.
Much on pipes and convenience of hooking programs together.
Includes SERMONETTE:
"Many familiar computing `concepts' are missing from UNIX.
Files have no records. There are no access methods.
There are no file types. These concepts fill a much-needed gap.
I sincerely hope that when future systems are designed by
manufacturers the value of some of these ingrained notions is re-examined.
Like the politician and his `common man', manufacturers have
their `average user'.
%A J. R. Mashey
%T PWB/UNIX Shell Tutorial
%D September 30, 1977
%A D. F. Hartley (Ed.)
%T The Cambridge Multiple Access System \- Users Reference Manual
%I University Mathematical Laboratory
%C Cambridge, England
%D 1968
%A P. A. Crisman (Ed.)
%T The Compatible Time-Sharing System
%I M.I.T. Press
%K whole ctss book
%C Cambridge, Mass.
%D 1965
%T LR Parsing
%A A. V. Aho
%A S. C. Johnson
%J Comp. Surveys
%V 6
%N 2
%P 99-124
%D June 1974
%T Deterministic Parsing of Ambiguous Grammars
%A A. V. Aho
%A S. C. Johnson
%A J. D. Ullman
%J Comm. Assoc. Comp. Mach.
%K acm cacm
%V 18
%N 8
%P 441-452
%D August 1975
%A A. V. Aho
%A J. D. Ullman
%T Principles of Compiler Design
%I Addison-Wesley
%C Reading, Mass.
%D 1977
.[
%r 65
%R Comp. Sci. Tech. Rep. No. 65
%K CSTR
%A S. C. Johnson
%T Lint, a C Program Checker
%D December 1977
%O updated version TM 78-1273-3
%D 1978
.]
%T A Portable Compiler: Theory and Practice
%A S. C. Johnson
%J Proc. 5th ACM Symp. on Principles of Programming Languages
%P 97-104
%D January 1978
.[
%r 39
%K CSTR
%R Comp. Sci. Tech. Rep. No. 39
%I Bell Laboratories
%C Murray Hill, New Jersey
%A M. E. Lesk
%T Lex \(em A Lexical Analyzer Generator
%D October 1975
.]
.[
%r 32
%K CSTR
%R Comp. Sci. Tech. Rep. No. 32
%I Bell Laboratories
%C Murray Hill, New Jersey
%A S. C. Johnson
%T Yacc \(em Yet Another Compiler-Compiler
%D July 1975
.]
%T U\s-2NIX\s0 Time-Sharing System: Portability of C Programs and the U\s-2NIX\s0 System
%K unix bstj
%A S. C. Johnson
%A D. M. Ritchie
%J Bell Sys. Tech. J.
%V 57
%N 6
%P 2021-2048
%D 1978
%T Typing Documents on UNIX and GCOS: The -ms Macros for Troff
%A M. E. Lesk
%D 1977
%A K. Thompson
%A D. M. Ritchie
%T U\s-2NIX\s0 Programmer's Manual
%K unix
%I Bell Laboratories
%O Sixth Edition
%D May 1975
%T The Network U\s-2NIX\s0 System
%K unix
%A G. L. Chesson
%J Operating Systems Review
%V 9
%N 5
%P 60-66
%D 1975
%O Also in \f2Proc. 5th Symp. on Operating Systems Principles.\f1
%T Spider \(em An Experimental Data Communications System
%Z ctr127
%A A. G. Fraser
%J Proc. IEEE Conf. on Communications
%P 21F
%O IEEE Cat. No. 74CH0859-9-CSCB.
%D June 1974
%T A Virtual Channel Network
%A A. G. Fraser
%J Datamation
%P 51-56
%D February 1975
.[
%r 41
%K CSTR
%R Comp. Sci. Tech. Rep. No. 41
%I Bell Laboratories
%C Murray Hill, New Jersey
%A J. W. Hunt
%A M. D. McIlroy
%T An Algorithm for Differential File Comparison
%D June 1976
.]
%A F. P. Brooks, Jr.
%T The Mythical Man-Month
%I Addison-Wesley
%C Reading, Mass.
%D 1975
%X pwb
Readable, classic reference on software engineering and
problems of large projects, from someone with experience in them.
Required reading for any software engineer, even if conclusions may not
always be agreed with.
%br
"The second is the most dangerous system a man every designs." p.55.
%br
"Hence plan to throw one away; you will, anyhow." p.116.
%br
"Cosgrove has perceptively pointed out that the programmer delivers
satisfaction of a user need rather than any tangible product.
And both the actual need and the user's perception of that need
will change as programs are built, tested, and used." p.117.
%br
"The total cost of maintaining a widely used program is typically 40 percent
or more of the cost of developing it." p.121.
%br
"As shown above, amalgamating prose and program reduces the total
number of characters to be stored." p.175.
%T A Portable Compiler for the Language C
%A A. Snyder
%I Master's Thesis, M.I.T.
%C Cambridge, Mass.
%D 1974
%T The C Language Calling Sequence
%A M. E. Lesk
%A S. C. Johnson
%A D. M. Ritchie
%D 1977
%T Optimal Code Generation for Expression Trees
%A A. V. Aho
%A S. C. Johnson
%D 1975
%J J. Assoc. Comp. Mach.
%K acm jacm
%V 23
%N 3
%P 488-501
%O Also in \f2Proc. ACM Symp. on Theory of Computing,\f1 pp. 207-217, 1975.
%A R. Sethi
%A J. D. Ullman
%T The Generation of Optimal Code for Arithmetic Expressions
%J J. Assoc. Comp. Mach.
%K acm jacm
%V 17
%N 4
%D October 1970
%P 715-728
%O Reprinted as pp. 229-247 in \fICompiler Techniques\fR, ed. B. W. Pollack, Auerbach, Princeton NJ (1972).
%X pwb
Optimal approach for straight-line, fixed
number of regs.
%T Code Generation for Machines with Multiregister
Operations
%A A. V. Aho
%A S. C. Johnson
%A J. D. Ullman
%J Proc. 4th ACM Symp. on Principles of Programming Languages
%P 21-28
%D January 1977

69
bin/sh/USD.doc/t.mac Normal file
View file

@ -0,0 +1,69 @@
.\" $NetBSD: t.mac,v 1.2 2010/08/22 02:19:07 perry Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are
.\" met:
.\"
.\" Redistributions of source code and documentation must retain the above
.\" copyright notice, this list of conditions and the following
.\" disclaimer.
.\"
.\" Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\"
.\" This product includes software developed or owned by Caldera
.\" International, Inc. Neither the name of Caldera International, Inc.
.\" nor the names of other contributors may be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" @(#)t.mac 8.1 (Berkeley) 8/14/93
.\"
.ds ZZ \fB.\|.\|.\fP
.ds ST \v'.3m'\s+2*\s0\v'-.3m'
.ds DO \h'\w'do 'u'
.ds Ca \h'\w'case 'u'
.ds WH \h'\w'while 'u'
.ds VT \|\fB\(or\fP\|
.ds TH \h'\w'then 'u'
.ds DC \*(DO\*(Ca
.ds AP >\h'-.2m'>
.ds HE <\h'-.2m'<
. \" macros for algol 68c reference manual
.ds DA 1977 November 1
.ds md \v'.25m'
.ds mu \v'-.25m'
.ds U \*(mu\s-3
.ds V \s0\*(md
.ds L \*(md\s-3
.ds M \s0\*(mu
.ds S \s-1
.ds T \s0
. \" small 1
.ds O \*S1\*T
.ds h \|
.ds s \|\|
. \" ellipsis
.ds e .\|.\|.
. \" subscripts
.ds 1 \*(md\s-41\s0\*(mu
.ds 2 \*(md\s-42\s0\*(mu

553
bin/sh/USD.doc/t1 Normal file
View file

@ -0,0 +1,553 @@
.\" $NetBSD: t1,v 1.3 2010/08/22 02:19:07 perry Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are
.\" met:
.\"
.\" Redistributions of source code and documentation must retain the above
.\" copyright notice, this list of conditions and the following
.\" disclaimer.
.\"
.\" Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" All advertising materials mentioning features or use of this software
.\" must display the following acknowledgment:
.\"
.\" This product includes software developed or owned by Caldera
.\" International, Inc. Neither the name of Caldera International, Inc.
.\" nor the names of other contributors may be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" @(#)t1 8.1 (Berkeley) 8/14/93
.\"
.EH 'USD:3-%''An Introduction to the UNIX Shell'
.OH 'An Introduction to the UNIX Shell''USD:3-%'
.\".RP
.TL
An Introduction to the UNIX Shell
.AU
S. R. Bourne
.AI
Murray Hill, NJ
.AU
(Updated for 4.3BSD by Mark Seiden)
.AU
(Further updated by Perry E. Metzger)\(dg
.AB
.FS
\(dg This paper was updated in 2010 to reflect most features of modern
POSIX shells, which all follow the design of S.R. Bourne's original v7
Unix shell.
Among these are ash, bash, ksh and others.
Typically one of these will be installed as /bin/sh on a modern system.
It does not describe the behavior of the c shell (csh).
If it's the c shell (csh) you're interested in, a good place to
begin is William Joy's paper "An Introduction to the C shell" (USD:4).
.FE
.LP
The
.ul
shell
is a command programming language that provides an interface
to the
.UX
operating system.
Its features include
control-flow primitives, parameter passing, variables and
string substitution.
Constructs such as
.ul
while, if then else, case
and
.ul
for
are available.
Two-way communication is possible between the
.ul
shell
and commands.
String-valued parameters, typically file names or flags, may be
passed to a command.
A return code is set by commands that may be used to determine control-flow,
and the standard output from a command may be used
as shell input.
.LP
The
.ul
shell
can modify the environment
in which commands run.
Input and output can be redirected
to files, and processes that communicate through `pipes'
can be invoked.
Commands are found by
searching directories
in the file system in a
sequence that can be defined by the user.
Commands can be read either from the terminal or from a file,
which allows command procedures to be
stored for later use.
.AE
.ds ST \v'.3m'\s+2*\s0\v'-.3m'
.SH
1.0\ Introduction
.LP
The shell is both a command language
and a programming language
that provides an interface to the UNIX
operating system.
This memorandum describes, with
examples, the UNIX shell.
The first section covers most of the
everyday requirements
of terminal users.
Some familiarity with UNIX
is an advantage when reading this section;
see, for example,
"UNIX for beginners".
.[
unix beginn kernigh 1978
.]
Section 2 describes those features
of the shell primarily intended
for use within shell procedures.
These include the control-flow
primitives and string-valued variables
provided by the shell.
A knowledge of a programming language
would be a help when reading this section.
The last section describes the more
advanced features of the shell.
References of the form "see \fIpipe\fP (2)"
are to a section of the UNIX manual.
.[
seventh 1978 ritchie thompson
.]
.SH
1.1\ Simple\ commands
.LP
Simple commands consist of one or more words
separated by blanks.
The first word is the name of the command
to be executed; any remaining words
are passed as arguments to the command.
For example,
.DS
who
.DE
is a command that prints the names
of users logged in.
The command
.DS
ls \(mil
.DE
prints a list of files in the current
directory.
The argument \fI\(mil\fP tells \fIls\fP
to print status information, size and
the creation date for each file.
.SH
1.2\ Input\ output\ redirection
.LP
Most commands produce output on the standard output
that is initially connected to the terminal.
This output may be sent to a file
by writing, for example,
.DS
ls \(mil >file
.DE
The notation \fI>file\fP
is interpreted by the shell and is not passed
as an argument to \fIls.\fP
If \fIfile\fP does not exist then the
shell creates it;
otherwise the original contents of
\fIfile\fP are replaced with the output
from \fIls.\fP
Output may be appended to a file
using the notation
.DS
ls \(mil \*(APfile
.DE
In this case \fIfile\fP is also created if it does not already
exist.
.LP
The standard input of a command may be taken
from a file instead of the terminal by
writing, for example,
.DS
wc <file
.DE
The command \fIwc\fP reads its standard input
(in this case redirected from \fIfile\fP)
and prints the number of characters, words and
lines found.
If only the number of lines is required
then
.DS
wc \(mil <file
.DE
could be used.
.\" I considered adding the following, but have thought better of it
.\" for now.
.\" -- Perry Metzger
.\"
.\" .LP
.\" Error messages are typically printed by commands on a different
.\" channel, called standard error, which may also be redirected using the
.\" notation 2>\|.
.\" For example
.\" .DS
.\" command some args >out 2>errors
.\" .DE
.\" will redirect standard output to the file `out' but standard error
.\" (and thus all error messages) to `errors'.
.\" The notation 2>&1 sets standard error pointing to the same
.\" place as standard out.
.\" Thus:
.\" .DS
.\" command some args 2>&1 >everything
.\" .DE
.\" will put both standard out and standard error into the file `everything'.
.\" See section 3.7 below for more details.
.SH
1.3\ Pipelines\ and\ filters
.LP
The standard output of one command may be
connected to the standard input of another
by writing
the `pipe' operator,
indicated by \*(VT,
as in,
.DS
ls \(mil \*(VT wc
.DE
Two commands connected in this way constitute
a \fIpipeline\fP and
the overall effect is the same as
.DS
ls \(mil >file; wc <file
.DE
except that no \fIfile\fP is used.
Instead the two \fIprocesses\fP are connected
by a pipe (see \fIpipe\fP(2)) and are
run in parallel.
Pipes are unidirectional and
synchronization is achieved by
halting \fIwc\fP when there is
nothing to read and halting \fIls\fP
when the pipe is full.
.LP
A \fIfilter\fP is a command
that reads its standard input,
transforms it in some way,
and prints the result as output.
One such filter, \fIgrep,\fP
selects from its input those lines
that contain some specified string.
For example,
.DS
ls \*(VT grep old
.DE
prints those lines, if any, of the output
from \fIls\fP that contain
the string \fIold.\fP
Another useful filter is \fIsort\fP.
For example,
.DS
who \*(VT sort
.DE
will print an alphabetically sorted list
of logged in users.
.LP
A pipeline may consist of more than two commands,
for example,
.DS
ls \*(VT grep old \*(VT wc \(mil
.DE
prints the number of file names
in the current directory containing
the string \fIold.\fP
.SH
1.4\ Background\ commands
.LP
To execute a command (or pipeline) the shell normally
creates the new \fIprocesses\fP
and waits for them to finish.
A command may be run without waiting
for it to finish.
For example,
.DS
cc pgm.c &
.DE
calls the C compiler to compile
the file \fIpgm.c\|.\fP
The trailing \fB&\fP is an operator that instructs the shell
not to wait for the command to finish.
To help keep track of such a process
the shell reports its job number (see below) and process
id following its creation.
Such a command is said to be running in the \fIbackground\fP.
By contrast, a command executed without the \fB&\fP is said to be
running in the \fIforeground\fP.\(dg
.FS
\(dg Even after execution, one may move commands from the foreground
to the background, or temporarily suspend their execution (which is
known as \fIstopping\fP a command.
This is described in detail in section 3.10 on \fIJob Control\fB.
.FE
.LP
A list of currently active processes, including ones not associated
with the current shell, may be obtained using the \fIps\fP(1) command.
.SH
1.5\ File\ name\ generation
.LP
Many commands accept arguments
which are file names.
For example,
.DS
ls \(mil main.c
.DE
prints information relating to the file \fImain.c\fP\|.
.LP
The shell provides a mechanism
for generating a list of file names
that match a pattern.
For example,
.DS
ls \(mil \*(ST.c
.DE
generates, as arguments to \fIls,\fP
all file names in the current directory that end in \fI.c\|.\fP
The character \*(ST is a pattern that will match any string
including the null string.
In general \fIpatterns\fP are specified
as follows.
.RS
.IP \fB\*(ST\fR 8
Matches any string of characters
including the null string.
.IP \fB?\fR 8
Matches any single character.
.IP \fB[\*(ZZ]\fR 8
Matches any one of the characters
enclosed.
A pair of characters separated by a minus will
match any character lexically between
the pair.
.RE
.LP
For example,
.DS
[a\(miz]\*(ST
.DE
matches all names in the current directory
beginning with
one of the letters \fIa\fP through \fIz.\fP
.DS
/usr/fred/test/?
.DE
matches all names in the directory
\fB/usr/fred/test\fP that consist of a single character.
If no file name is found that matches
the pattern then the pattern is passed,
unchanged, as an argument.
.LP
This mechanism is useful both to save typing
and to select names according to some pattern.
It may also be used to find files.
For example,
.DS
echo /usr/fred/\*(ST/core
.DE
finds and prints the names of all \fIcore\fP files in sub-directories
of \fB/usr/fred\|.\fP
(\fIecho\fP is a standard UNIX command that prints
its arguments, separated by blanks.)
This last feature can be expensive,
requiring a scan of all
sub-directories of \fB/usr/fred\|.\fP
.LP
There is one exception to the general
rules given for patterns.
The character `\fB.\fP'
at the start of a file name must be explicitly
matched.
.DS
echo \*(ST
.DE
will therefore echo all file names in the current
directory not beginning
with `\fB.\fP'\|.
.DS
echo \fB.\fP\*(ST
.DE
will echo all those file names that begin with `\fB.\fP'\|.
This avoids inadvertent matching
of the names `\fB.\fP' and `\fB..\fP'
which mean `the current directory'
and `the parent directory'
respectively.
(Notice that \fIls\fP suppresses
information for the files `\fB.\fP' and `\fB..\fP'\|.)
.LP
Finally, the tilde character, `\fB\(ap\fP', may be used to indicate the
home directory of a user.
The `\fB\(ap\fP' at the beginning of a path name followed by a
non-alphabetic character expands to the current user's home
directory.
If the `\fB\(ap\fP' is followed by a login name, it expands to the named
user's home directory.
For example:
.DS
ls \(ap
cd \(apegbert/
.DE
will list the contents of the user's home directory and then change
to the home directory of the user ``egbert''.
.SH
1.6\ Quoting
.LP
Characters that have a special meaning
to the shell, such as \fB< > \*(ST ? \*(VT &\|,\fR
are called metacharacters.
A complete list of metacharacters is given
in appendix B.
Any character preceded by a \fB\\\fR is \fIquoted\fP
and loses its special meaning, if any.
The \fB\\\fP is elided so that
.DS
echo \\?
.DE
will echo a single \fB?\|,\fP
and
.DS
echo \\\\
.DE
will echo a single \fB\\\|.\fR
To allow long strings to be continued over
more than one line
the sequence \fB\\newline\fP
is ignored.
.LP
\fB\\\fP is convenient for quoting
single characters.
When more than one character needs
quoting the above mechanism is clumsy and
error prone.
A string of characters may be quoted
by enclosing the string between single quotes.
For example,
.DS
echo xx\'\*(ST\*(ST\*(ST\*(ST\'xx
.DE
will echo
.DS
xx\*(ST\*(ST\*(ST\*(STxx
.DE
The quoted string may not contain
a single quote
but may contain newlines, which are preserved.
This quoting mechanism is the most
simple and is recommended
for casual use.
.LP
A third quoting mechanism using double quotes
is also available
that prevents interpretation of some but not all
metacharacters.
Discussion of the
details is deferred
to section 3.5\|.
.SH
1.7\ Prompting
.LP
When the shell is used from a terminal it will
issue a prompt before reading a command.
By default this prompt is `\fB$\ \fR'\|.
It may be changed by saying,
for example,
.DS
\s-1PS1\s0="yesdear$ "
.DE
that sets the prompt to be the string \fIyesdear$\|.\fP
If a newline is typed and further input is needed
then the shell will issue the prompt `\fB>\ \fR'\|.
Sometimes this can be caused by mistyping
a quote mark.
If it is unexpected then entering the interrupt character
(typically \s-1CONTROL-C\s0)
will return the shell to read another command.
This prompt may be changed by saying, for example,
.DS
\s-1PS2\s0=more
.DE
Entering the interrupt character may also be used to terminate most
programs running as the current foreground job.
.LP
(\s-1PS1\s0 and \s-1PS2\s0 are \fIshell variables\fP, which will be
described in section 2.4 below.)
.SH
1.8\ The\ shell\ and\ login
.LP
Following \fIlogin\fP(1)
the shell is called to read and execute
commands typed at the terminal.
If the user's login directory
contains the file \fB.profile\fP
then it is assumed to contain commands
and is read by the shell before reading
any commands from the terminal.
.LP
(Most versions of the shell also specify a file that is read and
executed on start-up whether or not the shell is invoked by login.
The \s-1ENV\s0 shell variable, described in section 2.4 below, can be
used to override the name of this file.
See the shell manual page for further information.)
.SH
1.9\ Summary
.sp
.RS
.IP \(bu
\fBls\fP
.br
Print the names of files in the current directory.
.IP \(bu
\fBls >file\fP
.br
Put the output from \fIls\fP into \fIfile.\fP
.IP \(bu
\fBls \*(VT wc \(mil\fR
.br
Print the number of files in the current directory.
.IP \(bu
\fBls \*(VT grep old\fR
.br
Print those file names containing the string \fIold.\fP
.IP \(bu
\fBls \*(VT grep old \*(VT wc \(mil\fR
.br
Print the number of files whose name contains the string \fIold.\fP
.IP \(bu
\fBcc pgm.c &\fR
.br
Run \fIcc\fP in the background.
.RE

971
bin/sh/USD.doc/t2 Normal file
View file

@ -0,0 +1,971 @@
.\" $NetBSD: t2,v 1.3 2010/08/22 02:19:07 perry Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are
.\" met:
.\"
.\" Redistributions of source code and documentation must retain the above
.\" copyright notice, this list of conditions and the following
.\" disclaimer.
.\"
.\" Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" All advertising materials mentioning features or use of this software
.\" must display the following acknowledgment:
.\"
.\" This product includes software developed or owned by Caldera
.\" International, Inc. Neither the name of Caldera International, Inc.
.\" nor the names of other contributors may be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" @(#)t2 8.1 (Berkeley) 6/8/93
.\"
.SH
2.0\ Shell\ scripts
.LP
The shell may be used to read and execute commands
contained in a file.
For example,
.DS
sh file [ args \*(ZZ ]
.DE
calls the shell to read commands from \fIfile.\fP
Such a file is called a \fIshell script.\fP
Arguments may be supplied with the call
and are referred to in \fIfile\fP
using the positional parameters
\fB$1, $2, \*(ZZ\|.\fR
.LP
For example, if the file \fIwg\fP contains
.DS
who \*(VT grep $1
.DE
then
.DS
sh wg fred
.DE
is equivalent to
.DS
who \*(VT grep fred
.DE
.LP
UNIX files have three independent attributes,
\fIread,\fP \fIwrite\fP and \fIexecute.\fP
The UNIX command \fIchmod\fP(1) may be used
to make a file executable.
For example,
.DS
chmod +x wg
.DE
will ensure that the file \fIwg\fP has execute status.
Following this, the command
.DS
wg fred
.DE
is equivalent to
.DS
sh wg fred
.DE
This allows shell scripts and other programs
to be used interchangeably.
In either case a new process is created to
run the command.
.LP
The `\fB#\fP' character is used as a comment character by the shell.
All characters following the `#' on a line are ignored.
.LP
A typical modern system has several different shells, some with differing
command syntax, and it is desirable to specify which one should be
invoked when an executable script is invoked.
If the special comment
.DS
#!/\fIpath\fP/\fIto\fP/\fIinterpreter\fP
.DE
appears as the first line in a script, it is used to specify the
absolute pathname of the shell (or other interpreter) that should be
used to execute the file.
(Without such a line, \fB/bin/sh\fP is assumed.)
It is best if a script explicitly states
what shell it is intended for in this manner.
.LP
As well as providing names for the positional
parameters,
the number of positional parameters to a script
is available as \fB$#\|.\fP
The name of the file being executed
is available as \fB$0\|.\fP
.LP
A special shell parameter \fB$\*(ST\fP
is used to substitute for all positional parameters
except \fB$0\|.\fP
A typical use of this is to provide
some default arguments,
as in,
.DS
nroff \(miT450 \(mims $\*(ST
.DE
which simply prepends some arguments
to those already given.
(The variable \fB$@\fP also expands to ``all positional
parameters'', but is subtly different when expanded inside quotes.
See section 3.5, below.)
.SH
2.1\ Control\ flow\ -\ for
.LP
A frequent use of shell scripts is to loop
through the arguments (\fB$1, $2, \*(ZZ\fR)
executing commands once for each argument.
An example of such a script is
\fItel\fP that searches the file
\fB/usr/share/telnos\fR
that contains lines of the form
.DS
\*(ZZ
fred mh0123
bert mh0789
\*(ZZ
.DE
The text of \fItel\fP is
.DS
#!/bin/sh
for i
do
grep $i /usr/share/telnos
done
.DE
The command
.DS
tel fred
.DE
prints those lines in \fB/usr/share/telnos\fR
that contain the string \fIfred\|.\fP
.DS
tel fred bert
.DE
prints those lines containing \fIfred\fP
followed by those for \fIbert.\fP
.LP
The \fBfor\fP loop notation is recognized by the shell
and has the general form
.DS
\fBfor\fR \fIname\fR \fBin\fR \fIw1 w2 \*(ZZ\fR
\fBdo\fR \fIcommand-list\fR
\fBdone\fR
.DE
A \fIcommand-list\fP is a sequence of one or more
simple commands separated or terminated by a newline or semicolon.
Furthermore, reserved words
like \fBdo\fP and \fBdone\fP are only
recognized following a newline or
semicolon.
\fIname\fP is a shell variable that is set
to the words \fIw1 w2 \*(ZZ\fR in turn each time the \fIcommand-list\fP
following \fBdo\fP
is executed.
If \fBin\fR \fIw1 w2 \*(ZZ\fR
is omitted then the loop
is executed once for each positional parameter;
that is, \fBin\fR \fI$\*(ST\fR is assumed.
.LP
Another example of the use of the \fBfor\fP
loop is the \fIcreate\fP command
whose text is
.DS
for i do >$i; done
.DE
The command
.DS
create alpha beta
.DE
ensures that two empty files
\fIalpha\fP and \fIbeta\fP exist
and are empty.
The notation \fI>file\fP may be used on its
own to create or clear the contents of a file.
Notice also that a semicolon (or newline) is required before \fBdone.\fP
.SH
2.2\ Control\ flow\ -\ case
.LP
A multiple way branch is provided for by the
\fBcase\fP notation.
For example,
.DS
case $# in
\*(Ca1) cat \*(AP$1 ;;
\*(Ca2) cat \*(AP$2 <$1 ;;
\*(Ca\*(ST) echo \'usage: append [ from ] to\' ;;
esac
.DE
is an \fIappend\fP command.
When called
with one argument as
.DS
append file
.DE
\fB$#\fP is the string \fI1\fP and
the standard input is copied onto the
end of \fIfile\fP
using the \fIcat\fP command.
.DS
append file1 file2
.DE
appends the contents of \fIfile1\fP
onto \fIfile2.\fP
If the number of arguments supplied to
\fIappend\fP is other than 1 or 2
then a message is printed indicating
proper usage.
.LP
The general form of the \fBcase\fP command
is
.DS
\fBcase \fIword \fBin
\*(Ca\fIpattern\|\fB)\ \fIcommand-list\fB\|;;
\*(Ca\*(ZZ
\fBesac\fR
.DE
The shell attempts to match
\fIword\fR with each \fIpattern,\fR
in the order in which the patterns
appear.
If a match is found the
associated \fIcommand-list\fP is
executed and execution
of the \fBcase\fP is complete.
Since \*(ST is the pattern that matches any
string it can be used for the default case.
.LP
A word of caution:
no check is made to ensure that only
one pattern matches
the case argument.
The first match found defines the set of commands
to be executed.
In the example below the commands following
the second \*(ST will never be executed.
.DS
case $# in
\*(Ca\*(ST) \*(ZZ ;;
\*(Ca\*(ST) \*(ZZ ;;
esac
.DE
.LP
Another example of the use of the \fBcase\fP
construction is to distinguish
between different forms
of an argument.
The following example is a fragment of a \fIcc\fP command.
.DS
for i
do case $i in
\*(DC\(mi[ocs]) \*(ZZ ;;
\*(DC\(mi\*(ST) echo "unknown flag $i" ;;
\*(DC\*(ST.c) /lib/c0 $i \*(ZZ ;;
\*(DC\*(ST) echo "unexpected argument $i" ;;
\*(DOesac
done
.DE
.LP
To allow the same commands to be associated
with more than one pattern
the \fBcase\fP command provides
for alternative patterns
separated by a \*(VT\|.
For example,
.DS
case $i in
\*(Ca\(mix\*(VT\(miy) \*(ZZ
esac
.DE
is equivalent to
.DS
case $i in
\*(Ca\(mi[xy]) \*(ZZ
esac
.DE
.LP
The usual quoting conventions apply
so that
.DS
case $i in
\*(Ca\\?) \*(ZZ
.DE
will match the character \fB?\|.\fP
.SH
2.3\ Here\ documents
.LP
The shell script \fItel\fP
in section 2.1 uses the file \fB/usr/share/telnos\fR
to supply the data
for \fIgrep.\fP
An alternative is to include this
data
within the shell script as a \fIhere\fP document, as in,
.DS
for i
do grep $i \*(HE!
\*(DO\*(ZZ
\*(DOfred mh0123
\*(DObert mh0789
\*(DO\*(ZZ
!
done
.DE
In this example
the shell takes the lines between \fB\*(HE!\fR and \fB!\fR
as the standard input for \fIgrep.\fP
The string \fB!\fR is arbitrary, the document
being terminated by a line that consists
of the string following \*(HE\|.
.LP
Parameters are substituted in the document
before it is made available to \fIgrep\fP
as illustrated by the following script
called \fIedg\|.\fP
.DS
ed $3 \*(HE%
g/$1/s//$2/g
w
%
.DE
The call
.DS
edg string1 string2 file
.DE
is then equivalent to the command
.DS
ed file \*(HE%
g/string1/s//string2/g
w
%
.DE
and changes all occurrences of \fIstring1\fP
in \fIfile\fP to \fIstring2\|.\fP
Substitution can be prevented using \\
to quote the special character \fB$\fP
as in
.DS
ed $3 \*(HE+
1,\\$s/$1/$2/g
w
+
.DE
(This version of \fIedg\fP is equivalent to
the first except that \fIed\fP will print
a \fB?\fR if there are no occurrences of
the string \fB$1\|.\fP)
Substitution within a \fIhere\fP document
may be prevented entirely by quoting
the terminating string,
for example,
.DS
grep $i \*(HE'end'
\*(ZZ
end
.DE
The document is presented
without modification to \fIgrep.\fP
If parameter substitution is not required
in a \fIhere\fP document this latter form
is more efficient.
.SH
2.4\ Shell\ variables\(dg
.LP
.FS
Also known as \fIenvironment variables\fB, see \fIenvironment\fB(7).
.FE
The shell
provides string-valued variables.
Variable names begin with a letter
and consist of letters, digits and
underscores.
Variables may be given values by writing, for example,
.DS
user=fred\ box=m000\ acct=mh0000
.DE
which assigns values to the variables
\fBuser, box\fP and \fBacct.\fP
A variable may be set to the null string
by saying, for example,
.DS
null=
.DE
The value of a variable is substituted
by preceding its name with \fB$\|\fP;
for example,
.DS
echo $user
.DE
will echo \fIfred.\fP
.LP
Variables may be used interactively
to provide abbreviations for frequently
used strings.
For example,
.DS
b=/usr/fred/bin
mv pgm $b
.DE
will move the file \fIpgm\fP
from the current directory to the directory \fB/usr/fred/bin\|.\fR
A more general notation is available for parameter
(or variable)
substitution, as in,
.DS
echo ${user}
.DE
which is equivalent to
.DS
echo $user
.DE
and is used when the parameter name is
followed by a letter or digit.
For example,
.DS
tmp=/tmp/ps
ps a >${tmp}a
.DE
will direct the output of \fIps\fR
to the file \fB/tmp/psa,\fR
whereas,
.DS
ps a >$tmpa
.DE
would cause the value of the variable \fBtmpa\fP
to be substituted.
.LP
Except for \fB$?\fP the following
are set initially by the shell.
\fB$?\fP is set after executing each command.
.RS
.IP \fB$?\fP 8
The exit status (return code)
of the last command executed
as a decimal string.
Most commands return a zero exit status
if they complete successfully,
otherwise a non-zero exit status is returned.
Testing the value of return codes is dealt with
later under \fBif\fP and \fBwhile\fP commands.
.IP \fB$#\fP 8
The number of positional parameters
(in decimal).
Used, for example, in the \fIappend\fP command
to check the number of parameters.
.IP \fB$$\fP 8
The process number of this shell (in decimal).
Since process numbers are unique among
all existing processes, this string is
frequently used to generate
unique
temporary file names.
For example,
.DS
ps a >/tmp/ps$$
\*(ZZ
rm /tmp/ps$$
.DE
.IP \fB$\|!\fP 8
The process number of the last process
run in the background (in decimal).
.IP \fB$\(mi\fP 8
The current shell flags, such as
\fB\(mix\fR and \fB\(miv\|.\fR
.RE
.LP
Some variables have a special meaning to the
shell and should be avoided for general
use.
.RS
.IP \fB$\s-1MAIL\s0\fP 8
When used interactively
the shell looks at the file
specified by this variable
before it issues a prompt.
If the specified file has been modified
since it
was last looked at the shell
prints the message
\fIyou have mail\fP before prompting
for the next command.
This variable is typically set
in the file \fB.profile,\fP
in the user's login directory.
For example,
.DS
\s-1MAIL\s0=/usr/spool/mail/fred
.DE
.IP \fB$\s-1HOME\s0\fP 8
The default argument
for the \fIcd\fP command.
The current directory is used to resolve
file name references that do not begin with
a \fB/\|,\fR
and is changed using the \fIcd\fP command.
For example,
.DS
cd /usr/fred/bin
.DE
makes the current directory \fB/usr/fred/bin\|.\fR
.DS
cat wn
.DE
will print on the terminal the file \fIwn\fP
in this directory.
The command
\fIcd\fP with no argument
is equivalent to
.DS
cd $\s-1HOME\s0
.DE
This variable is also typically set in the
the user's login profile.
.IP \fB$\s-1PWD\s0\fP 8
The current working directory. Set by the \fIcd\fB command.
.IP \fB$\s-1PATH\s0\fP 8
A list of directories that contain commands (the \fIsearch path\fR\|).
Each time a command is executed by the shell
a list of directories is searched
for an executable file.
.ne 5
If \fB$\s-1PATH\s0\fP is not set
then the current directory,
\fB/bin\fP, and \fB/usr/bin\fP are searched by default.
.ne 5
Otherwise \fB$\s-1PATH\s0\fP consists of directory
names separated by \fB:\|.\fP
For example,
.DS
\s-1PATH\s0=\fB:\fP/usr/fred/bin\fB:\fP/bin\fB:\fP/usr/bin
.DE
specifies that the current directory
(the null string before the first \fB:\fP\|),
\fB/usr/fred/bin, /bin \fRand\fP /usr/bin\fR
are to be searched in that order.
In this way individual users
can have their own `private' commands
that are accessible independently
of the current directory.
If the command name contains a \fB/\fR then this directory search
is not used; a single attempt
is made to execute the command.
.IP \fB$\s-1PS1\s0\fP 8
The primary shell prompt string, by default, `\fB$\ \fR'.
.IP \fB$\s-1PS2\s0\fP 8
The shell prompt when further input is needed,
by default, `\fB>\ \fR'.
.IP \fB$\s-1IFS\s0\fP 8
The set of characters used by \fIblank
interpretation\fR (see section 3.5).
.IP \fB$\s-1ENV\s0\fP 8
The shell reads and executes the commands in the file
specified by this variable when it is initially started.
Unlike the \fB.profile\fP file, these commands are executed by all
shells, not just the one started at login.
(Most versions of the shell specify a filename that is used if
\s-1ENV\s0 is not explicitly set. See the manual page for your shell.)
.RE
.SH
2.5\ The\ test\ command
.LP
The \fItest\fP command, although not part of the shell,
is intended for use by shell programs.
For example,
.DS
test \(mif file
.DE
returns zero exit status if \fIfile\fP
exists and non-zero exit status otherwise.
In general \fItest\fP evaluates a predicate
and returns the result as its exit status.
Some of the more frequently used \fItest\fP
arguments are given here, see \fItest\fP(1)
for a complete specification.
.DS
test s true if the argument \fIs\fP is not the null string
test \(mif file true if \fIfile\fP exists
test \(mir file true if \fIfile\fP is readable
test \(miw file true if \fIfile\fP is writable
test \(mid file true if \fIfile\fP is a directory
.DE
The \fItest\fP command is known as `\fB[\fP' and may be invoked as
such.
For aesthetic reasons, the command ignores a close bracket `\fB]\fP' given
at the end of a command so
.DS
[ -f filename ]
.DE
and
.DS
test -f filename
.DE
are completely equivalent.
Typically, the bracket notation is used when \fItest\fP is invoked inside
shell control constructs.
.SH
2.6\ Control\ flow\ -\ while
.LP
The actions of
the \fBfor\fP loop and the \fBcase\fP
branch are determined by data available to the shell.
A \fBwhile\fP or \fBuntil\fP loop
and an \fBif then else\fP branch
are also provided whose
actions are determined by the exit status
returned by commands.
A \fBwhile\fP loop has the general form
.DS
\fBwhile\fP \fIcommand-list\*1\fP
\fBdo\fP \fIcommand-list\*2\fP
\fBdone\fP
.DE
.LP
The value tested by the \fBwhile\fP command
is the exit status of the last simple command
following \fBwhile.\fP
Each time round the loop
\fIcommand-list\*1\fP is executed;
if a zero exit status is returned then
\fIcommand-list\*2\fP
is executed;
otherwise, the loop terminates.
For example,
.DS
while [ $1 ]
do \*(ZZ
\*(DOshift
done
.DE
is equivalent to
.DS
for i
do \*(ZZ
done
.DE
\fIshift\fP is a shell command that
renames the positional parameters
\fB$2, $3, \*(ZZ\fR as \fB$1, $2, \*(ZZ\fR
and loses \fB$1\|.\fP
.LP
Another kind of use for the \fBwhile/until\fP
loop is to wait until some
external event occurs and then run
some commands.
In an \fBuntil\fP loop
the termination condition is reversed.
For example,
.DS
until [ \(mif file ]
do sleep 300; done
\fIcommands\fP
.DE
will loop until \fIfile\fP exists.
Each time round the loop it waits for
5 minutes before trying again.
(Presumably another process
will eventually create the file.)
.LP
The most recent enclosing loop may be exited with the \fBbreak\fP
command, or the rest of the body skipped and the next iteration begun
with the \fBcontinue\fP command.
.LP
The commands \fItrue\fP(1) and \fIfalse\fP(1) return 0 and non-zero
exit statuses respectively. They are sometimes of use in control flow,
e.g.:
.DS
while true
do date; sleep 5
done
.DE
is an infinite loop that prints the date and time every five seconds.
.SH
2.7\ Control\ flow\ -\ if
.LP
Also available is a
general conditional branch
of the form,
.DS
\fBif\fP \fIcommand-list
\fBthen \fIcommand-list
\fBelse \fIcommand-list
\fBfi\fR
.DE
that tests the value returned by the last simple command
following \fBif.\fP
.LP
The \fBif\fP command may be used
in conjunction with the \fItest\fP command
to test for the existence of a file as in
.DS
if [ \(mif file ]
then \fIprocess file\fP
else \fIdo something else\fP
fi
.DE
.LP
An example of the use of \fBif, case\fP
and \fBfor\fP constructions is given in
section 2.10\|.
.LP
A multiple test \fBif\fP command
of the form
.DS
if \*(ZZ
then \*(ZZ
else if \*(ZZ
then \*(ZZ
else if \*(ZZ
\*(ZZ
fi
fi
fi
.DE
may be written using an extension of the \fBif\fP
notation as,
.DS
if \*(ZZ
then \*(ZZ
elif \*(ZZ
then \*(ZZ
elif \*(ZZ
\*(ZZ
fi
.DE
.LP
The following example is an implementation of the \fItouch\fP command
which changes the `last modified' time for a list
of files.
The command may be used in conjunction
with \fImake\fP(1) to force recompilation of a list
of files.
.DS
#!/bin/sh
flag=
for i
do case $i in
\*(DC\(mic) flag=N ;;
\*(DC\*(ST) if [ \(mif $i ]
\*(DC then cp $i junk$$; mv junk$$ $i
\*(DC elif [ $flag ]
\*(DC then echo file \\'$i\\' does not exist
\*(DC else >$i
\*(DC fi
\*(DO esac
done
.DE
The \fB\(mic\fP flag is used in this command to
force subsequent files to be created if they do not already exist.
Otherwise, if the file does not exist, an error message is printed.
The shell variable \fIflag\fP
is set to some non-null string if the \fB\(mic\fP
argument is encountered.
The commands
.DS
cp \*(ZZ; mv \*(ZZ
.DE
copy the file and then overwrite it with the copy,
thus causing the last modified date to be updated.
.LP
The sequence
.DS
if command1
then command2
fi
.DE
may be written
.DS
command1 && command2
.DE
Conversely,
.DS
command1 \*(VT\*(VT command2
.DE
executes \fIcommand2\fP only if \fIcommand1\fP
fails.
In each case the value returned
is that of the last simple command executed.
.LP
Placing a `\fB!\fP' in front of a pipeline inverts its exit
status, almost in the manner of the C operator of the same name.
Thus:
.DS
if ! [ -d $1 ]
then
echo $1 is not a directory
fi
.DE
will print a message only if $1 is not a directory.
.SH
2.8\ Command\ grouping
.LP
Commands may be grouped in two ways,
.DS
\fB{\fI command-list\fB ; }\fR
.DE
and
.DS
\fB(\fI command-list\fB )\fR
.DE
.LP
In the first \fIcommand-list\fP is simply executed.
The second form executes \fIcommand-list\fP
as a separate process.
For example,
.DS
(cd x; rm junk )
.DE
executes \fIrm junk\fP in the directory
\fBx\fP without changing the current
directory of the invoking shell.
.LP
The commands
.DS
cd x; rm junk
.DE
have the same effect but leave the invoking
shell in the directory \fBx.\fP
.SH
2.9\ Shell\ Functions
.LP
A function may be defined by the syntax
.DS
\fIfuncname\fP() \fB{\fI command-list\fB ; }\fR
.DE
Functions are invoked within a script as though they were separate
commands of the same name.
While they are executed, the
positional parameters \fB$1, $2, \*(ZZ\fR are temporarily set to the
arguments passed to the function. For example:
.DS
count() {
echo $2 : $#
}
count a b c
.DE
would print `b : 3'.
.SH
2.10\ Debugging\ shell\ scripts
.LP
The shell provides two tracing mechanisms
to help when debugging shell scripts.
The first is invoked within the script
as
.DS
set \(miv
.DE
(\fBv\fP for verbose) and causes lines of the
script to be printed as they are read.
It is useful to help isolate syntax errors.
It may be invoked without modifying the script
by saying
.DS
sh \(miv \fIscript\fP \*(ZZ
.DE
where \fIscript\fP is the name of the shell script.
This flag may be used in conjunction
with the \fB\(min\fP flag which prevents
execution of subsequent commands.
(Note that saying \fIset \(min\fP at a terminal
will render the terminal useless
until an end-of-file is typed.)
.LP
The command
.DS
set \(mix
.DE
will produce an execution
trace.
Following parameter substitution
each command is printed as it is executed.
(Try these at the terminal to see
what effect they have.)
Both flags may be turned off by saying
.DS
set \(mi
.DE
and the current setting of the shell flags is available as \fB$\(mi\|\fR.
.SH
2.11\ The\ man\ command
.LP
The following is a simple implementation of the \fIman\fP command,
which is used to display sections of the UNIX manual on your terminal.
It is called, for example, as
.DS
man sh
man \(mit ed
man 2 fork
.DE
In the first the manual section for \fIsh\fP
is displayed..
Since no section is specified, section 1 is used.
The second example will typeset (\fB\(mit\fP option)
the manual section for \fIed.\fP
The last prints the \fIfork\fP manual page
from section 2, which covers system calls.
.sp 2
.DS
#!/bin/sh
cd /usr/share/man
# "#" is the comment character
# default is nroff ($N), section 1 ($s)
N=n\ s=1
for i
do case $i in
.sp .5
\*(DC[1\(mi9]\*(ST) s=$i ;;
.sp .5
\*(DC\(mit) N=t ;;
.sp .5
\*(DC\(min) N=n ;;
.sp .5
\*(DC\(mi\*(ST) echo unknown flag \\'$i\\' ;;
.sp .5
\*(DC\*(ST) if [ \(mif man$s/$i.$s ]
\*(DC then
\*(DC ${N}roff \(miman man$s/$i.$s
\*(DC else # look through all manual sections
\*(DC found=no
\*(DC for j in 1 2 3 4 5 6 7 8 9
\*(DC do
\*(DC \*(DOif [ \(mif man$j/$i.$j ]
\*(DC \*(DOthen
\*(DC \*(DO\*(THman $j $i
\*(DC \*(DO\*(THfound=yes
\*(DC \*(DO\*(THbreak
\*(DC \*(DOfi
\*(DC done
\*(DC case $found in
\*(DC \*(Cano) echo \\'$i: manual page not found\\'
\*(DC esac
\*(DC fi
\*(DOesac
done
.DE
.ce
.ft B
Figure 1. A version of the man command
.ft R

976
bin/sh/USD.doc/t3 Normal file
View file

@ -0,0 +1,976 @@
.\" $NetBSD: t3,v 1.3 2010/08/22 02:19:07 perry Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are
.\" met:
.\"
.\" Redistributions of source code and documentation must retain the above
.\" copyright notice, this list of conditions and the following
.\" disclaimer.
.\"
.\" Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\"
.\" This product includes software developed or owned by Caldera
.\" International, Inc. Neither the name of Caldera International, Inc.
.\" nor the names of other contributors may be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" @(#)t3 8.1 (Berkeley) 6/8/93
.\"
.SH
3.0\ Keyword\ parameters
.LP
Shell variables may be given values
by assignment
or when a shell script is invoked.
An argument to a command of the form
\fIname=value\fP
that precedes the command name
causes \fIvalue\fP
to be assigned to \fIname\fP
before execution of the command begins.
The value of \fIname\fP in the invoking
shell is not affected.
For example,
.DS
user=fred\ command
.DE
will execute \fIcommand\fP with
\fBuser\fP set to \fIfred\fP.
.\" Removed by Perry Metzger because -k is not in POSIX
.\"
.\" The \fB\(mik\fR flag causes arguments of the form
.\" \fIname=value\fP to be interpreted in this way
.\" anywhere in the argument list.
.\" Such \fInames\fP are sometimes
.\" called keyword parameters.
.\" If any arguments remain they
.\" are available as positional
.\" parameters \fB$1, $2, \*(ZZ\|.\fP
.LP
The \fIset\fP command
may also be used to set positional parameters
from within a script.
For example,
.DS
set\ \(mi\(mi\ \*(ST
.DE
will set \fB$1\fP to the first file name
in the current directory, \fB$2\fP to the next,
and so on.
Note that the first argument, \(mi\(mi, ensures correct treatment
when the first file name begins with a \(mi\|.
.LP
.SH
3.1\ Parameter\ transmission
.LP
When a command is executed both positional parameters
and shell variables may be set on invocation.
Variables are also made available implicitly
to a command
by specifying in advance that such parameters
are to be exported from the invoking shell.
For example,
.DS
export\ user\ box=red
.DE
marks the variables \fBuser\fP and \fBbox\fP
for export (setting \fBbox\fP to ``red'' in the process).
When a command is invoked
copies are made of all exportable variables
(also known as \fIenvironment variables\fP)
for use within the invoked program.
Modification of such variables
within an invoked command does not
affect the values in the invoking shell.
It is generally true of
a shell script or other program
that it
cannot modify the state
of its caller without explicit
actions on the part of the caller.
.\" Removed by Perry Metzger because this is confusing to beginners.
.\"
.\" (Shared file descriptors are an
.\" exception to this rule.)
.LP
Names whose value is intended to remain
constant may be declared \fIreadonly\|.\fP
The form of this command is the same as that of the \fIexport\fP
command,
.DS
readonly name[=value] \*(ZZ
.DE
Subsequent attempts to set readonly variables
are illegal.
.SH
3.2\ Parameter\ substitution
.LP
If a shell parameter is not set
then the null string is substituted for it.
For example, if the variable \fBd\fP
is not set
.DS
echo $d
.DE
or
.DS
echo ${d}
.DE
will echo nothing.
A default string may be given
as in
.DS
echo ${d:\(mi\fB.\fR}
.DE
which will echo
the value of the variable \fBd\fP
if it is set and not null and `\fB.\fP' otherwise.
The default string is evaluated using the usual
quoting conventions so that
.DS
echo ${d:\(mi\'\*(ST\'}
.DE
will echo \fB\*(ST\fP if the variable \fBd\fP
is not set or null.
Similarly
.DS
echo ${d:\(mi$1}
.DE
will echo the value of \fBd\fP if it is set and not null
and the value (if any) of \fB$1\fP otherwise.
.LP
The notation ${d:+\fB.\fR} performs the inverse operation. It
substitutes `\fB.\fP' if \fBd\fP is set or not null, and otherwise
substitutes null.
.LP
A variable may be assigned a default value
using
the notation
.DS
echo ${d:=\fB.\fR}
.DE
which substitutes the same string as
.DS
echo ${d:\(mi\fB.\fR}
.DE
and if \fBd\fP were not previously set or null
then it will be set to the string `\fB.\fP'\|.
.LP
If there is no sensible default then
the notation
.DS
echo ${d:?\fImessage\fP}
.DE
will echo the value of the variable \fBd\fP if it is set and not null,
otherwise \fImessage\fP is printed by the shell and
execution of the shell script is abandoned.
If \fImessage\fP is absent then a standard message
is printed.
A shell script that requires some variables
to be set might start as follows:
.DS
:\ ${user:?}\ ${acct:?}\ ${bin:?}
\*(ZZ
.DE
Colon (\fB:\fP) is a command
that is
built in to the shell and does nothing
once its arguments have been evaluated.
If any of the variables \fBuser, acct\fP
or \fBbin\fP are not set then the shell
will abandon execution of the script.
.SH
3.3\ Command\ substitution
.LP
The standard output from a command can be
substituted in a similar way to parameters.
The command \fIpwd\fP prints on its standard
output the name of the current directory.
For example, if the current directory is
\fB/usr/fred/bin\fR
then the commands
.DS
d=$(pwd)
.DE
(or the older notation d=\`pwd\`)
is equivalent to
.DS
d=/usr/fred/bin
.DE
.LP
The entire string inside $(\*(ZZ)\| (or between grave accents \`\*(ZZ\`)
is taken as the command
to be executed
and is replaced with the output from
the command.
(The difference between the $(\*(ZZ) and \`\*(ZZ\` notations is that
the former may be nested, while the latter cannot be.)
.LP
The command is written using the usual quoting conventions,
except that inside \`\*(ZZ\`
a \fB\`\fR must be escaped using
a \fB\\\|\fR.
For example,
.DS
ls $(echo "$HOME")
.DE
is equivalent to
.DS
ls $HOME
.DE
Command substitution occurs in all contexts
where parameter substitution occurs (including \fIhere\fP documents) and the
treatment of the resulting text is the same
in both cases.
This mechanism allows string
processing commands to be used within
shell scripts.
An example of such a command is \fIbasename\fP
which removes a specified suffix from a string.
For example,
.DS
basename main\fB.\fPc \fB.\fPc
.DE
will print the string \fImain\|.\fP
Its use is illustrated by the following
fragment from a \fIcc\fP command.
.DS
case $A in
\*(Ca\*(ZZ
\*(Ca\*(ST\fB.\fPc) B=$(basename $A \fB.\fPc)
\*(Ca\*(ZZ
esac
.DE
that sets \fBB\fP to the part of \fB$A\fP
with the suffix \fB.c\fP stripped.
.LP
Here are some composite examples.
.RS
.IP \(bu
.ft B
for i in \`ls \(mit\`; do \*(ZZ
.ft R
.br
The variable \fBi\fP is set
to the names of files in time order,
most recent first.
.IP \(bu
.ft B
set \(mi\(mi\| \`date\`; echo $6 $2 $3, $4
.ft R
.br
will print, e.g.,
.ft I
1977 Nov 1, 23:59:59
.ft R
.RE
.SH
3.4\ Arithmetic\ Expansion
.LP
Within a $((\*(ZZ)) construct, integer arithmetic operations are
evaluated.
(The $ in front of variable names is optional within $((\*(ZZ)).
For example:
.DS
x=5; y=1
echo $(($x+3*2))
echo $((y+=x))
echo $y
.DE
will print `11', then `6', then `6' again.
Most of the constructs permitted in C arithmetic operations are
permitted though some (like `++') are not universally supported \(em
see the shell manual page for details.
.SH
3.5\ Evaluation\ and\ quoting
.LP
The shell is a macro processor that
provides parameter substitution, command substitution and file
name generation for the arguments to commands.
This section discusses the order in which
these evaluations occur and the
effects of the various quoting mechanisms.
.LP
Commands are parsed initially according to the grammar
given in appendix A.
Before a command is executed
the following
substitutions occur.
.RS
.IP \(bu
parameter substitution, e.g. \fB$user\fP
.IP \(bu
command substitution, e.g. \fB$(pwd)\fP or \fB\`pwd\`\fP
.IP \(bu
arithmetic expansion, e.g. \fB$(($count+1))\fP
.RS
.LP
Only one evaluation occurs so that if, for example, the value of the variable
\fBX\fP
is the string \fI$y\fP
then
.DS
echo $X
.DE
will echo \fI$y\|.\fP
.RE
.IP \(bu
blank interpretation
.RS
.LP
Following the above substitutions
the resulting characters
are broken into non-blank words (\fIblank interpretation\fP).
For this purpose `blanks' are the characters of the string
\fB$\s-1IFS\s0\fP.
By default, this string consists of blank, tab and newline.
The null string
is not regarded as a word unless it is quoted.
For example,
.DS
echo \'\'
.DE
will pass on the null string as the first argument to \fIecho\fP,
whereas
.DS
echo $null
.DE
will call \fIecho\fR with no arguments
if the variable \fBnull\fP is not set
or set to the null string.
.RE
.IP \(bu
file name generation
.RS
.LP
Each word
is then scanned for the file pattern characters
\fB\*(ST, ?\fR and \fB[\*(ZZ]\fR
and an alphabetical list of file names
is generated to replace the word.
Each such file name is a separate argument.
.RE
.RE
.LP
The evaluations just described also occur
in the list of words associated with a \fBfor\fP
loop.
Only substitution occurs
in the \fIword\fP used
for a \fBcase\fP branch.
.LP
As well as the quoting mechanisms described
earlier using \fB\\\fR and \fB\'\*(ZZ\'\fR
a third quoting mechanism is provided using double quotes.
Within double quotes parameter and command substitution
occurs but file name generation and the interpretation
of blanks does not.
The following characters
have a special meaning within double quotes
and may be quoted using \fB\\\|.\fP
.DS
\fB$ \fPparameter substitution
\fB$()\fP command substitution
\fB\`\fP command substitution
\fB"\fP ends the quoted string
\fB\e\fP quotes the special characters \fB$ \` " \e\fP
.DE
For example,
.DS
echo "$x"
.DE
will pass the value of the variable \fBx\fP as a
single argument to \fIecho.\fP
Similarly,
.DS
echo "$\*(ST"
.DE
will pass the positional parameters as a single
argument and is equivalent to
.DS
echo "$1 $2 \*(ZZ"
.DE
The notation \fB$@\fP
is the same as \fB$\*(ST\fR
except when it is quoted.
.DS
echo "$@"
.DE
will pass the positional parameters, unevaluated, to \fIecho\fR
and is equivalent to
.DS
echo "$1" "$2" \*(ZZ
.DE
.LP
The following table gives, for each quoting mechanism,
the shell metacharacters that are evaluated.
.DS
.ce
.ft I
metacharacter
.ft
.in 1.5i
\e $ * \` " \'
\' n n n n n t
\` y n n t n n
" y y n y t n
t terminator
y interpreted
n not interpreted
.in
.ft B
.ce
Figure 2. Quoting mechanisms
.ft
.DE
.LP
In cases where more than one evaluation of a string
is required the built-in command \fIeval\fP
may be used.
For example,
if the variable \fBX\fP has the value
\fI$y\fP, and if \fBy\fP has the value \fIpqr\fP
then
.DS
eval echo $X
.DE
will echo the string \fIpqr\|.\fP
.LP
In general the \fIeval\fP command
evaluates its arguments (as do all commands)
and treats the result as input to the shell.
The input is read and the resulting command(s)
executed.
For example,
.DS
wg=\'eval who\*(VTgrep\'
$wg fred
.DE
is equivalent to
.DS
who\*(VTgrep fred
.DE
In this example,
\fIeval\fP is required
since there is no interpretation
of metacharacters, such as \fB\*(VT\|\fR, following
substitution.
.SH
3.6\ Error\ handling
.LP
The treatment of errors detected by
the shell depends on the type of error
and on whether the shell is being
used interactively.
An interactive shell is one whose
input and output are connected
to a terminal.
.\" Removed by Perry Metzger, obsolete and excess detail
.\"
.\" (as determined by
.\" \fIgtty\fP (2)).
A shell invoked with the \fB\(mii\fP
flag is also interactive.
.LP
Execution of a command (see also 3.7) may fail
for any of the following reasons.
.IP \(bu
Input output redirection may fail.
For example, if a file does not exist
or cannot be created.
.IP \(bu
The command itself does not exist
or cannot be executed.
.IP \(bu
The command terminates abnormally,
for example, with a "bus error"
or "memory fault".
See Figure 2 below for a complete list
of UNIX signals.
.IP \(bu
The command terminates normally
but returns a non-zero exit status.
.LP
In all of these cases the shell
will go on to execute the next command.
Except for the last case an error
message will be printed by the shell.
All remaining errors cause the shell
to exit from a script.
An interactive shell will return
to read another command from the terminal.
Such errors include the following.
.IP \(bu
Syntax errors.
e.g., if \*(ZZ then \*(ZZ done
.IP \(bu
A signal such as interrupt.
The shell waits for the current
command, if any, to finish execution and
then either exits or returns to the terminal.
.IP \(bu
Failure of any of the built-in commands
such as \fIcd.\fP
.LP
The shell flag \fB\(mie\fP
causes the shell to terminate
if any error is detected.
.DS
1 hangup
2 interrupt
3* quit
4* illegal instruction
5* trace trap
6* IOT instruction
7* EMT instruction
8* floating point exception
9 kill (cannot be caught or ignored)
10* bus error
11* segmentation violation
12* bad argument to system call
13 write on a pipe with no one to read it
14 alarm clock
15 software termination (from \fIkill\fP (1))
.DE
.ft B
.ce
Figure 3. UNIX signals\(dg
.ft
.FS
\(dg Additional signals have been added in modern Unix.
See \fIsigvec\fP(2) or \fIsignal\fP(3) for an up-to-date list.
.FE
Those signals marked with an asterisk
produce a core dump
if not caught.
However,
the shell itself ignores quit which is the only
external signal that can cause a dump.
The signals in this list of potential interest
to shell programs are 1, 2, 3, 14 and 15.
.SH
3.7\ Fault\ handling
.LP
shell scripts normally terminate
when an interrupt is received from the
terminal.
The \fItrap\fP command is used
if some cleaning up is required, such
as removing temporary files.
For example,
.DS
trap\ \'rm\ /tmp/ps$$; exit\'\ 2
.DE
sets a trap for signal 2 (terminal
interrupt), and if this signal is received
will execute the commands
.DS
rm /tmp/ps$$; exit
.DE
\fIexit\fP is
another built-in command
that terminates execution of a shell script.
The \fIexit\fP is required; otherwise,
after the trap has been taken,
the shell will resume executing
the script
at the place where it was interrupted.
.LP
UNIX signals can be handled in one of three ways.
They can be ignored, in which case
the signal is never sent to the process.
They can be caught, in which case the process
must decide what action to take when the
signal is received.
Lastly, they can be left to cause
termination of the process without
it having to take any further action.
If a signal is being ignored
on entry to the shell script, for example,
by invoking it in the background (see 3.7) then \fItrap\fP
commands (and the signal) are ignored.
.LP
The use of \fItrap\fP is illustrated
by this modified version of the \fItouch\fP
command (Figure 4).
The cleanup action is to remove the file \fBjunk$$\fR\|.
.DS
#!/bin/sh
flag=
trap\ \'rm\ \(mif\ junk$$;\ exit\'\ 1 2 3 15
for i
do\ case\ $i\ in
\*(DC\(mic) flag=N ;;
\*(DC\*(ST) if\ test\ \(mif\ $i
\*(DC then cp\ $i\ junk$$;\ mv\ junk$$ $i
\*(DC elif\ test\ $flag
\*(DC then echo\ file\ \\'$i\\'\ does\ not\ exist
\*(DC else >$i
\*(DC fi
\*(DOesac
done
.DE
.sp
.ft B
.ce
Figure 4. The touch command
.ft
.sp
The \fItrap\fP command
appears before the creation
of the temporary file;
otherwise it would be
possible for the process
to die without removing
the file.
.LP
Since there is no signal 0 in UNIX
it is used by the shell to indicate the
commands to be executed on exit from the
shell script.
.LP
A script may, itself, elect to
ignore signals by specifying the null
string as the argument to trap.
The following fragment is taken from the
\fInohup\fP command.
.DS
trap \'\' 1 2 3 15
.DE
which causes \fIhangup, interrupt, quit \fRand\fI kill\fR
to be ignored both by the
script and by invoked commands.
.LP
Traps may be reset by saying
.DS
trap 2 3
.DE
which resets the traps for signals 2 and 3 to their default values.
A list of the current values of traps may be obtained
by writing
.DS
trap
.DE
.LP
The script \fIscan\fP (Figure 5) is an example
of the use of \fItrap\fP where there is no exit
in the trap command.
\fIscan\fP takes each directory
in the current directory, prompts
with its name, and then executes
commands typed at the terminal
until an end of file or an interrupt is received.
Interrupts are ignored while executing
the requested commands but cause
termination when \fIscan\fP is
waiting for input.
.DS
d=\`pwd\`
for\ i\ in\ \*(ST
do\ if\ test\ \(mid\ $d/$i
\*(DOthen\ cd\ $d/$i
\*(DO\*(THwhile\ echo\ "$i:"
\*(DO\*(TH\*(WHtrap\ exit\ 2
\*(DO\*(TH\*(WHread\ x
\*(DO\*(THdo\ trap\ :\ 2;\ eval\ $x;\ done
\*(DOfi
done
.DE
.sp
.ft B
.ce
Figure 5. The scan command
.ft
.sp
\fIread x\fR is a built-in command that reads one line from the
standard input
and places the result in the variable \fBx\|.\fP
It returns a non-zero exit status if either
an end-of-file is read or an interrupt
is received.
.SH
3.8\ Command\ execution
.LP
To run a command (other than a built-in) the shell first creates
a new process using the system call \fIfork.\fP
The execution environment for the command
includes input, output and the states of signals, and
is established in the child process
before the command is executed.
The built-in command \fIexec\fP
is used in the rare cases when no fork
is required
and simply replaces the shell with a new command.
For example, a simple version of the \fInohup\fP
command looks like
.DS
trap \\'\\' 1 2 3 15
exec $\*(ST
.DE
The \fItrap\fP turns off the signals specified
so that they are ignored by subsequently created commands
and \fIexec\fP replaces the shell by the command
specified.
.LP
Most forms of input output redirection have already been
described.
In the following \fIword\fP is only subject
to parameter and command substitution.
No file name generation or blank interpretation
takes place so that, for example,
.DS
echo \*(ZZ >\*(ST.c
.DE
will write its output into a file whose name is \fB\*(ST.c\|.\fP
Input output specifications are evaluated left to right
as they appear in the command.
.IP >\ \fIword\fP 12
The standard output (file descriptor 1)
is sent to the file \fIword\fP which is
created if it does not already exist.
.IP \*(AP\ \fIword\fP 12
The standard output is sent to file \fIword.\fP
If the file exists then output is appended
(by seeking to the end);
otherwise the file is created.
.IP <\ \fIword\fP 12
The standard input (file descriptor 0)
is taken from the file \fIword.\fP
.IP \*(HE\ \fIword\fP 12
The standard input is taken from the lines
of shell input that follow up to but not
including a line consisting only of \fIword.\fP
If \fIword\fP is quoted then no interpretation
of the document occurs.
If \fIword\fP is not quoted
then parameter and command substitution
occur and \fB\\\fP is used to quote
the characters \fB\\\fP \fB$\fP \fB\`\fP and the first character
of \fIword.\fP
In the latter case \fB\\newline\fP is ignored (c.f. quoted strings).
.IP >&\ \fIdigit\fP 12
The file descriptor \fIdigit\fP is duplicated using the system
call \fIdup\fP (2)
and the result is used as the standard output.
.IP <&\ \fIdigit\fP 12
The standard input is duplicated from file descriptor \fIdigit.\fP
.IP <&\(mi 12
The standard input is closed.
.IP >&\(mi 12
The standard output is closed.
.LP
Any of the above may be preceded by a digit in which
case the file descriptor created is that specified by the digit
instead of the default 0 or 1.
For example,
.DS
\*(ZZ 2>file
.DE
runs a command with message output (file descriptor 2)
directed to \fIfile.\fP
.DS
\*(ZZ 2>&1
.DE
runs a command with its standard output and message output
merged.
(Strictly speaking file descriptor 2 is created
by duplicating file descriptor 1 but the effect is usually to
merge the two streams.)
.\" Removed by Perry Metzger, most of this is now obsolete
.\"
.\" .LP
.\" The environment for a command run in the background such as
.\" .DS
.\" list \*(ST.c \*(VT lpr &
.\" .DE
.\" is modified in two ways.
.\" Firstly, the default standard input
.\" for such a command is the empty file \fB/dev/null\|.\fR
.\" This prevents two processes (the shell and the command),
.\" which are running in parallel, from trying to
.\" read the same input.
.\" Chaos would ensue
.\" if this were not the case.
.\" For example,
.\" .DS
.\" ed file &
.\" .DE
.\" would allow both the editor and the shell
.\" to read from the same input at the same time.
.\" .LP
.\" The other modification to the environment of a background
.\" command is to turn off the QUIT and INTERRUPT signals
.\" so that they are ignored by the command.
.\" This allows these signals to be used
.\" at the terminal without causing background
.\" commands to terminate.
.\" For this reason the UNIX convention
.\" for a signal is that if it is set to 1
.\" (ignored) then it is never changed
.\" even for a short time.
.\" Note that the shell command \fItrap\fP
.\" has no effect for an ignored signal.
.SH
3.9\ Invoking\ the\ shell
.LP
The following flags are interpreted by the shell
when it is invoked.
If the first character of argument zero is a minus,
then commands are read from the file \fB.profile\|.\fP
.IP \fB\(mic\fP\ \fIstring\fP
.br
If the \fB\(mic\fP flag is present then
commands are read from \fIstring\|.\fP
.IP \fB\(mis\fP
If the \fB\(mis\fP flag is present or if no
arguments remain
then commands are read from the standard input.
Shell output is written to
file descriptor 2.
.IP \fB\(mii\fP
If the \fB\(mii\fP flag is present or
if the shell input and output are attached to a terminal (as told by \fIgtty\fP)
then this shell is \fIinteractive.\fP
In this case TERMINATE is ignored (so that \fBkill 0\fP
does not kill an interactive shell) and INTERRUPT is caught and ignored
(so that \fBwait\fP is interruptable).
In all cases QUIT is ignored by the shell.
.SH
3.10\ Job\ Control
.LP
When a command or pipeline (also known as a \fIjob\fP) is running in
the foreground, entering the stop character (typically
\s-1CONTROL-Z\s0 but user settable with the \fIstty\fP(1) command)
will usually cause the job to stop.
.LP
The jobs associated with the current shell may be listed by entering
the \fIjobs\fP command.
Each job has an associated \fIjob number\fP.
Jobs that are stopped may be continued by entering
.DS
bg %\fIjobnumber\fP
.DE
and jobs may be moved to the foreground by entering
.DS
fg %\fIjobnumber\fP
.DE
If there is a sole job with a particular name (say only one instance
of \fIcc\fP running), \fIfg\fP and \fIbg\fP may also use name of the
command in place of the number, as in:
.DS
bg %cc
.DE
If no `\fB%\fP' clause is entered, most recently stopped job
(indicated with a `+' by the \fIjobs\fP command) will be assumed.
See the manual page for the shell for more details.
.SH
3.11\ Aliases
.LP
The \fIalias\fP command creates a so-called shell alias, which is an
abbreviation that macro-expands at run time into some other command.
For example:
.DS
alias ls="ls -F"
.DE
would cause the command sequence \fBls -F\fP to be executed whenever
the user types \fBls\fP into the shell.
Note that if the user types \fBls -a\fP, the shell will in fact
execute \fBls -F -a\fP.
The command \fBalias\fP on its own prints out all current aliases.
The \fIunalias\fP command, as in:
.DS
unalias ls
.DE
will remove an existing alias.
Aliases can shadow pre-existing commands, as in the example above.
They are typically used to override the interactive behavior of
commands in small ways, for example to always invoke some program with
a favorite option, and are almost never found in scripts.
.SH
3.12\ Command\ Line\ Editing\ and\ Recall
.LP
When working interactively with the shell, it is often tedious to
retype previously entered commands, especially if they are complicated.
The shell therefore maintains a so-called \fIhistory\fP, which is
stored in the file specified by the \fB\s-1HISTFILE\s0\fP environment
variable if it is set.
Users may view, edit, and re-enter previous lines of input using
a small subset of the commands of the \fIvi\fP(1) or
\fIemacs\fP(1)\(dg editors.
.FS
Technically, vi command editing is standardized by POSIX while emacs
is not.
However, all modern shells support both styles.
.FE
Emacs style editing may be selected by entering
.DS
set -o emacs
.DE
and vi style editing may be selected with
.DS
set -o vi
.DE
The details of how command line editing works are beyond the scope of
this document.
See the shell manual page for details.
.SH
Acknowledgements
.LP
The design of the shell is
based in part on the original UNIX shell
.[
unix command language thompson
.]
and the PWB/UNIX shell,
.[
pwb shell mashey unix
.]
some
features having been taken from both.
Similarities also exist with the
command interpreters
of the Cambridge Multiple Access System
.[
cambridge multiple access system hartley
.]
and of CTSS.
.[
ctss
.]
.LP
I would like to thank Dennis Ritchie
and John Mashey for many
discussions during the design of the shell.
I am also grateful to the members of the Computing Science Research Center
and to Joe Maranzano for their
comments on drafts of this document.
.SH
.[
$LIST$
.]

180
bin/sh/USD.doc/t4 Normal file
View file

@ -0,0 +1,180 @@
.\" $NetBSD: t4,v 1.3 2010/08/22 02:19:07 perry Exp $
.\"
.\" Copyright (C) Caldera International Inc. 2001-2002. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions are
.\" met:
.\"
.\" Redistributions of source code and documentation must retain the above
.\" copyright notice, this list of conditions and the following
.\" disclaimer.
.\"
.\" Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\"
.\" This product includes software developed or owned by Caldera
.\" International, Inc. Neither the name of Caldera International, Inc.
.\" nor the names of other contributors may be used to endorse or promote
.\" products derived from this software without specific prior written
.\" permission.
.\"
.\" USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
.\" INTERNATIONAL, INC. 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 CALDERA INTERNATIONAL, INC. 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) RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
.\" IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" @(#)t4 8.1 (Berkeley) 8/14/93
.\"
.bp
.SH
Appendix\ A\ -\ Grammar
.LP
Note: This grammar needs updating, it is obsolete.
.LP
.LD
\fIitem: word
input-output
name = value
.sp 0.7
simple-command: item
simple-command item
.sp 0.7
command: simple-command
\fB( \fIcommand-list \fB)
\fB{ \fIcommand-list \fB}
\fBfor \fIname \fBdo \fIcommand-list \fBdone
\fBfor \fIname \fBin \fIword \*(ZZ \fBdo \fIcommand-list \fBdone
\fBwhile \fIcommand-list \fBdo \fIcommand-list \fBdone
\fBuntil \fIcommand-list \fBdo \fIcommand-list \fBdone
\fBcase \fIword \fBin \fIcase-part \*(ZZ \fBesac
\fBif \fIcommand-list \fBthen \fIcommand-list \fIelse-part \fBfi
.sp 0.7
\fIpipeline: command
pipeline \fB\*(VT\fI command
.sp 0.7
andor: pipeline
andor \fB&&\fI pipeline
andor \fB\*(VT\*(VT\fI pipeline
.sp 0.7
command-list: andor
command-list \fB;\fI
command-list \fB&\fI
command-list \fB;\fI andor
command-list \fB&\fI andor
.sp 0.7
input-output: \fB> \fIfile
\fB< \fIfile
\fB\*(AP \fIword
\fB\*(HE \fIword
.sp 0.7
file: word
\fB&\fI digit
\fB&\fI \(mi
.sp 0.7
case-part: pattern\fB ) \fIcommand-list\fB ;;
.sp 0.7
\fIpattern: word
pattern \fB\*(VT\fI word
.sp 0.7
\fIelse-part: \fBelif \fIcommand-list\fB then\fI command-list else-part\fP
\fBelse \fIcommand-list\fI
empty
.sp 0.7
empty:
.sp 0.7
word: \fRa sequence of non-blank characters\fI
.sp 0.7
name: \fRa sequence of letters, digits or underscores starting with a letter\fI
.sp 0.7
digit: \fB0 1 2 3 4 5 6 7 8 9\fP
.DE
.LP
.bp
.SH
Appendix\ B\ -\ Meta-characters\ and\ Reserved\ Words
.LP
a) syntactic
.RS
.IP \fB\*(VT\fR 6
pipe symbol
.IP \fB&&\fR 6
`andf' symbol
.IP \fB\*(VT\*(VT\fR 6
`orf' symbol
.IP \fB;\fP 8
command separator
.IP \fB;;\fP 8
case delimiter
.IP \fB&\fP 8
background commands
.IP \fB(\ )\fP 8
command grouping
.IP \fB<\fP 8
input redirection
.IP \fB\*(HE\fP 8
input from a here document
.IP \fB>\fP 8
output creation
.IP \fB\*(AP\fP 8
output append
.sp 2
.RE
.LP
b) patterns
.RS
.IP \fB\*(ST\fP 8
match any character(s) including none
.IP \fB?\fP 8
match any single character
.IP \fB[...]\fP 8
match any of the enclosed characters
.sp 2
.RE
.LP
c) substitution
.RS
.IP \fB${...}\fP 8
substitute shell variable
.IP \fB$(...)\fP 8
substitute command output
.IP \fB\`...\`\fP 8
substitute command output
.IP \fB$((...))\fP 8
substitute arithmetic expression
.sp 2
.RE
.LP
d) quoting
.RS
.IP \fB\e\fP 8
quote the next character
.IP \fB\'...\'\fP 8
quote the enclosed characters except for \'
.IP \fB"\&..."\fP 8
quote the enclosed characters except
for \fB$ \` \e "\fP
.sp 2
.RE
.LP
e) reserved words
.DS
.ft B
if then else elif fi
case in esac
for while until do done
! { }
.ft
.DE

View file

@ -1,3 +1,5 @@
/* $NetBSD: alias.c,v 1.14 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,15 +32,14 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: alias.c,v 1.14 2011/06/18 21:18:46 christos Exp $");
#endif
#endif /* not lint */
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
*/
#include <stdlib.h>
#include "shell.h"
@ -49,18 +50,20 @@ __FBSDID("$FreeBSD: src/bin/sh/alias.c,v 1.18 2004/04/06 20:06:51 markm Exp $");
#include "mystring.h"
#include "alias.h"
#include "options.h" /* XXX for argptr (should remove?) */
#include "builtins.h"
#include "var.h"
#define ATABSIZE 39
STATIC struct alias *atab[ATABSIZE];
struct alias *atab[ATABSIZE];
STATIC void setalias(const char *, const char *);
STATIC int unalias(const char *);
STATIC struct alias **hashalias(const char *);
STATIC void setalias(char *, char *);
STATIC int unalias(char *);
STATIC struct alias **hashalias(char *);
STATIC
void
setalias(const char *name, const char *val)
setalias(char *name, char *val)
{
struct alias *ap, **app;
@ -78,6 +81,7 @@ setalias(const char *name, const char *val)
INTOFF;
ap = ckmalloc(sizeof (struct alias));
ap->name = savestr(name);
ap->flag = 0;
/*
* XXX - HACK: in order that the parser will not finish reading the
* alias value off the input before processing the next alias, we
@ -87,7 +91,7 @@ setalias(const char *name, const char *val)
* 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
* routine finishes reading the string, it markes 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
@ -106,14 +110,13 @@ setalias(const char *name, const char *val)
ap->val[len+1] = '\0';
}
#endif
ap->flag = 0;
ap->next = *app;
*app = ap;
INTON;
}
STATIC int
unalias(const char *name)
unalias(char *name)
{
struct alias *ap, **app;
@ -146,7 +149,8 @@ unalias(const char *name)
}
#ifdef mkinit
INCLUDE "alias.h"
MKINIT void rmaliases(void);
SHELLPROC {
rmaliases();
}
@ -174,7 +178,7 @@ rmaliases(void)
}
struct alias *
lookupalias(const char *name, int check)
lookupalias(char *name, int check)
{
struct alias *ap = *hashalias(name);
@ -189,6 +193,17 @@ lookupalias(const char *name, int check)
return (NULL);
}
char *
get_alias_text(char *name)
{
struct alias *ap;
ap = lookupalias(name, 0);
if (ap == NULL)
return NULL;
return ap->val;
}
/*
* TODO - sort output
*/
@ -206,23 +221,23 @@ aliascmd(int argc, char **argv)
for (ap = atab[i]; ap; ap = ap->next) {
if (*ap->name != '\0') {
out1fmt("alias %s=", ap->name);
out1qstr(ap->val);
print_quoted(ap->val);
out1c('\n');
}
}
return (0);
}
while ((n = *++argv) != NULL) {
if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */
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);
print_quoted(ap->val);
out1c('\n');
}
else {
} else {
*v++ = '\0';
setalias(n, v);
}
@ -232,7 +247,7 @@ aliascmd(int argc, char **argv)
}
int
unaliascmd(int argc __unused, char **argv __unused)
unaliascmd(int argc, char **argv)
{
int i;
@ -249,7 +264,7 @@ unaliascmd(int argc __unused, char **argv __unused)
}
STATIC struct alias **
hashalias(const char *p)
hashalias(char *p)
{
unsigned int hashval;
@ -258,7 +273,3 @@ hashalias(const char *p)
hashval+= *p++;
return &atab[hashval % ATABSIZE];
}
/*
* $PchId: alias.c,v 1.5 2006/05/22 12:41:12 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: alias.h,v 1.7 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* 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
@ -42,11 +43,6 @@ struct alias {
int flag;
};
struct alias *lookupalias(const char *, int);
int aliascmd(int, char **);
int unaliascmd(int, char **);
struct alias *lookupalias(char *, int);
char *get_alias_text(char *);
void rmaliases(void);
/*
* $PchId: alias.h,v 1.4 2006/03/31 11:30:54 philip Exp $
*/

206
bin/sh/arith.y Normal file
View file

@ -0,0 +1,206 @@
%{
/* $NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $ */
/*-
* 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.
* 3. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)arith.y 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: arith.y,v 1.22 2012/03/20 18:42:29 matt Exp $");
#endif
#endif /* not lint */
#include <stdlib.h>
#include "expand.h"
#include "builtins.h"
#include "shell.h"
#include "error.h"
#include "output.h"
#include "memalloc.h"
typedef intmax_t YYSTYPE;
#define YYSTYPE YYSTYPE
intmax_t arith_result;
const char *arith_buf, *arith_startbuf;
__dead static void yyerror(const char *);
#ifdef TESTARITH
int main(int , char *[]);
int error(char *);
#endif
%}
%token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
%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 {
/*
* yyparse() returns int, so we have to save
* the desired result elsewhere.
*/
arith_result = $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
;
%%
intmax_t
arith(const char *s)
{
intmax_t result;
arith_buf = arith_startbuf = s;
INTOFF;
(void) yyparse();
result = arith_result;
arith_lex_reset(); /* reprime lex */
INTON;
return (result);
}
/*
* The exp(1) builtin.
*/
int
expcmd(int argc, char **argv)
{
const char *p;
char *concat;
char **ap;
intmax_t 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 = "";
(void)arith(p);
i = arith_result;
out1fmt("%"PRIdMAX"\n", i);
return (! i);
}
/*************************/
#ifdef TEST_ARITH
#include <stdio.h>
main(argc, argv)
char *argv[];
{
printf("%"PRIdMAX"\n", exp(argv[1]));
}
error(s)
char *s;
{
fprintf(stderr, "exp: %s\n", s);
exit(1);
}
#endif
static void
yyerror(const char *s)
{
yyerrok;
yyclearin;
arith_lex_reset(); /* reprime lex */
error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
/* NOTREACHED */
}

View file

@ -1,4 +1,6 @@
%{
/* $NetBSD: arith_lex.l,v 1.16 2012/03/20 18:42:29 matt Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@ -14,7 +16,7 @@
* 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
* 3. 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.
*
@ -31,103 +33,71 @@
* SUCH DAMAGE.
*/
#if 0
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)arith_lex.l 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: arith_lex.l,v 1.16 2012/03/20 18:42:29 matt Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/arith_lex.l,v 1.22 2004/04/06 20:06:51 markm Exp $");
*/
#include <string.h>
#include "shell.h"
#include <unistd.h>
#include "arith.h"
#include "error.h"
#include "memalloc.h"
#include "expand.h"
#include "var.h"
extern char *arith_buf, *arith_startbuf;
extern intmax_t yylval;
extern const 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
%}
%option nounput noinput
%%
[ \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);
0x[0-9a-fA-F]+ { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
0[0-7]* { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
[1-9][0-9]* { yylval = strtoimax(yytext, 0, 0); return(ARITH_NUM); }
[A-Za-z_][A-Za-z_0-9]* { char *v = lookupvar(yytext);
if (v) {
yylval = strtoimax(v, &v, 0);
if (*v == 0)
return ARITH_NUM;
}
error("arith: syntax error: \"%s\"", arith_startbuf);
}
"(" { 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); }
. { error("arith: syntax error: \"%s\"", arith_startbuf); }
%%
void
arith_lex_reset(void)
{
arith_lex_reset(void) {
#ifdef YY_NEW_FILE
YY_NEW_FILE;
#endif
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: bltin.h,v 1.13 2008/10/12 01:40:37 dholland Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -29,63 +31,70 @@
* 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 $
* @(#)bltin.h 8.1 (Berkeley) 5/31/93
*/
/*
* 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.
* shell.
*
* We always define SHELL_BUILTIN, to allow other included headers to
* hide some of their symbols if appropriate.
*
* If SHELL is defined, we try to map the standard UNIX library routines
* to ash routines using defines.
*/
#define SHELL_BUILTIN
#include "../shell.h"
#include "../mystring.h"
#ifdef SHELL
#include "builtins.h"
#include "../output.h"
#include "../error.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
#undef fileno
#undef ferror
#define FILE struct output
#define stdout out1
#define stderr out2
#define _RETURN_INT(x) ((x), 0) /* map from void foo() to int bar() */
#define fprintf(...) _RETURN_INT(outfmt(__VA_ARGS__))
#define printf(...) _RETURN_INT(out1fmt(__VA_ARGS__))
#define putc(c, file) _RETURN_INT(outc(c, file))
#define putchar(c) _RETURN_INT(out1c(c))
#define fputs(...) _RETURN_INT(outstr(__VA_ARGS__))
#define fflush(f) _RETURN_INT(flushout(f))
#define fileno(f) ((f)->fd)
#define ferror(f) ((f)->flags & OUTPUT_ERR)
#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); \
}
#define err sh_err
#define verr sh_verr
#define errx sh_errx
#define verrx sh_verrx
#define warn sh_warn
#define vwarn sh_vwarn
#define warnx sh_warnx
#define vwarnx sh_vwarnx
#define exit sh_exit
#define setprogname(s)
#define getprogname() commandname
#define setlocate(l,s) 0
#else
#define getenv(p) bltinlookup((p),0)
#else /* ! SHELL */
#undef NULL
#include <stdio.h>
#undef main
#define INITARGS(argv) if ((commandname = argv[0]) == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
#endif
#endif /* ! SHELL */
pointer stalloc(int);
void error(const char *, ...);
int echocmd(int, char **);
extern char *commandname;
/*
* $PchId: bltin.h,v 1.4 2006/03/29 11:39:00 philip Exp $
*/
extern const char *commandname;

109
bin/sh/bltin/echo.1 Normal file
View file

@ -0,0 +1,109 @@
.\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:40 agc Exp $
.\"
.\" 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.
.\" Copyright 1989 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. 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.1 8.1 (Berkeley) 5/31/93
.\"
.Dd May 31, 1993
.Dt ECHO 1
.Os
.Sh NAME
.Nm echo
.Nd produce message in a shell script
.Sh SYNOPSIS
.Nm
.Op Fl n | Fl e
.Ar args ...
.Sh DESCRIPTION
.Nm
prints its arguments on the standard output, separated by spaces.
Unless the
.Fl n
option is present, a newline is output following the arguments.
The
.Fl e
option causes
.Nm
to treat the escape sequences specially, as described in the following
paragraph.
The
.Fl e
option is the default, and is provided solely for compatibility with
other systems.
Only one of the options
.Fl n
and
.Fl e
may be given.
.Pp
If any of the following sequences of characters is encountered during
output, the sequence is not output. Instead, the specified action is
performed:
.Bl -tag -width indent
.It Li \eb
A backspace character is output.
.It Li \ec
Subsequent output is suppressed. This is normally used at the end of the
last argument to suppress the trailing newline that
.Nm
would otherwise output.
.It Li \ef
Output a form feed.
.It Li \en
Output a newline character.
.It Li \er
Output a carriage return.
.It Li \et
Output a (horizontal) tab character.
.It Li \ev
Output a vertical tab.
.It Li \e0 Ns Ar digits
Output the character whose value is given by zero to three digits.
If there are zero digits, a nul character is output.
.It Li \e\e
Output a backslash.
.El
.Sh HINTS
Remember that backslash is special to the shell and needs to be escaped.
To output a message to standard error, say
.Pp
.D1 echo message \*[Gt]\*[Am]2
.Sh BUGS
The octal character escape mechanism
.Pq Li \e0 Ns Ar digits
differs from the
C language mechanism.
.Pp
There is no way to force
.Nm
to treat its arguments literally, rather than interpreting them as
options and escape sequences.

View file

@ -1,3 +1,5 @@
/* $NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -29,61 +31,65 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)echo.c 8.2 (Berkeley) 5/4/95
* @(#)echo.c 8.1 (Berkeley) 5/31/93
*/
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/bltin/echo.c,v 1.14 2004/04/06 20:06:53 markm Exp $");
*/
/*
* Echo command.
*
* echo is steeped in tradition - several of them!
* netbsd has supported 'echo [-n | -e] args' in spite of -e not being
* documented anywhere.
* Posix requires that -n be supported, output from strings containing
* \ is implementation defined
* The Single Unix Spec requires that \ escapes be treated as if -e
* were set, but that -n not be treated as an option.
* (ksh supports 'echo [-eEn] args', but not -- so that it is actually
* impossible to actually output '-n')
*
* It is suggested that 'printf "%b" "string"' be used to get \ sequences
* expanded. printf is now a builtin of netbsd's sh and csh.
*/
#include <sys/cdefs.h>
__RCSID("$NetBSD: echo.c,v 1.14 2008/10/12 01:40:37 dholland Exp $");
#define main echocmd
#include "bltin.h"
int
echocmd(argc, argv)
int argc;
char **argv;
main(int argc, char **argv)
{
char **ap;
char *p;
char c;
int count;
int nflag = 0;
#ifdef __minix
int eflag = 0;
#endif
ap = argv;
if (argc)
ap++;
if ((p = *ap) != NULL) {
#ifdef __minix
if (equal(p, "--")) {
ap++;
}
#endif
if (equal(p, "-n")) {
nflag++;
nflag = 1;
ap++;
} else if (equal(p, "-e")) {
#ifdef __minix
eflag++;
#endif
eflag = 1;
ap++;
}
}
while ((p = *ap++) != NULL) {
while ((c = *p++) != '\0') {
if (c == '\\' && eflag) {
switch (*p++) {
case 'a': c = '\a'; break;
case 'a': c = '\a'; break; /* bell */
case 'b': c = '\b'; break;
case 'c': return 0; /* exit */
case 'e': c = '\033'; break;
case 'e': c = 033; break; /* escape */
case 'f': c = '\f'; break;
case 'n': c = '\n'; break;
case 'r': c = '\r'; break;
@ -97,6 +103,7 @@ echocmd(argc, argv)
c = (c << 3) + (*p++ - '0');
break;
default:
/* Output the '/' and char following */
p--;
break;
}
@ -108,9 +115,8 @@ echocmd(argc, argv)
}
if (! nflag)
putchar('\n');
fflush(stdout);
if (ferror(stdout))
return 1;
return 0;
}
/*
* $PchId: echo.c,v 1.5 2006/05/23 12:05:56 philip Exp $
*/

View file

@ -1,4 +1,5 @@
#!/bin/sh -
# $NetBSD: builtins.def,v 1.22 2012/12/31 14:10:15 dsl Exp $
#
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
@ -14,7 +15,7 @@
# 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
# 3. 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.
#
@ -31,63 +32,62 @@
# 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!
# of a C routine.
# The -j flag specifies that this command is to be excluded from systems
# without job control.
# The -h flag specifies that this command is to be excluded from systems
# based on the SMALL compile-time symbol.
# The -s flag specifies that this is a posix 'special builtin' command.
# The -u flag specifies that this is a posix 'standard utility'.
# The rest of the line specifies the command name or names used to run
# the command.
bltincmd builtin
commandcmd command
#if JOBS
bgcmd -j bg
#endif
breakcmd break continue
#catfcmd catf
cdcmd cd chdir
dotcmd .
bltincmd -u command
bgcmd -j -u bg
breakcmd -s break -s continue
cdcmd -u cd chdir
dotcmd -s .
echocmd echo
evalcmd eval
execcmd exec
exitcmd exit
evalcmd -s eval
execcmd -s exec
exitcmd -s exit
expcmd exp let
exportcmd export readonly
exprcmd expr test [
falsecmd false
histcmd -h fc
#if JOBS
fgcmd -j fg
#endif
getoptscmd getopts
exportcmd -s export -s readonly
falsecmd -u false
histcmd -h -u fc
inputrc inputrc
fgcmd -j -u fg
fgcmd_percent -j -u %
getoptscmd -u getopts
hashcmd hash
jobidcmd jobid
jobscmd jobs
jobscmd -u jobs
localcmd local
#ifndef SMALL
#printfcmd printf
printfcmd printf
#endif
pwdcmd pwd
readcmd read
returncmd return
setcmd set
pwdcmd -u pwd
readcmd -u read
returncmd -s return
setcmd -s set
setvarcmd setvar
shiftcmd shift
trapcmd trap
truecmd : true
shiftcmd -s shift
timescmd -s times
trapcmd -s trap
truecmd -s : -u true
typecmd type
umaskcmd umask
unaliascmd unalias
unsetcmd unset
waitcmd wait
aliascmd alias
umaskcmd -u umask
unaliascmd -u unalias
unsetcmd -s unset
waitcmd -u wait
aliascmd -u alias
ulimitcmd ulimit
bindcmd bind
testcmd test [
killcmd -u kill # mandated by posix for 'kill %job'
wordexpcmd wordexp
#newgrp -u newgrp # optional command in posix
#exprcmd expr

View file

@ -1,3 +1,5 @@
/* $NetBSD: cd.c,v 1.44 2011/08/31 16:24:54 plunky Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,15 +32,14 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)cd.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: cd.c,v 1.44 2011/08/31 16:24:54 plunky Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
*/
#include <sys/types.h>
#include <sys/stat.h>
@ -46,7 +47,6 @@ __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
/*
* The cd and pwd commands.
@ -57,68 +57,74 @@ __FBSDID("$FreeBSD: src/bin/sh/cd.c,v 1.34 2004/04/06 20:06:51 markm Exp $");
#include "nodes.h" /* for jobs.h */
#include "jobs.h"
#include "options.h"
#include "builtins.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "exec.h"
#include "redir.h"
#include "mystring.h"
#include "builtins.h"
#include "show.h"
#include "cd.h"
STATIC int cdlogical(const char *);
STATIC int cdphysical(const char *);
STATIC int docd(const char *, int, int);
STATIC int docd(const char *, int);
STATIC char *getcomponent(void);
STATIC int updatepwd(const char *);
STATIC void updatepwd(const char *);
STATIC void find_curdir(int noerror);
STATIC char *curdir = NULL; /* current working directory */
STATIC char *prevdir; /* previous working directory */
char *curdir = NULL; /* current working directory */
char *prevdir; /* previous working directory */
STATIC char *cdcomppath;
int
cdcmd(int argc, char **argv)
{
char *dest;
char *path;
char *p;
const char *dest;
const char *path, *p;
char *d;
struct stat statb;
int ch, phys, print = 0;
int print = cdprint; /* set -cdprint to enable */
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;
while (nextopt("P") != '\0')
;
/*
* Try (quite hard) to have 'curdir' defined, nothing has set
* it on entry to the shell, but we want 'cd fred; cd -' to work.
*/
getpwd(1);
dest = *argptr;
if (dest == NULL) {
dest = bltinlookup("HOME", 1);
if (dest == NULL)
error("HOME not set");
} else {
if (argptr[1]) {
/* Do 'ksh' style substitution */
if (!curdir)
error("PWD not set");
p = strstr(curdir, dest);
if (!p)
error("bad substitution");
d = stalloc(strlen(curdir) + strlen(argptr[1]) + 1);
memcpy(d, curdir, p - curdir);
strcpy(d + (p - curdir), argptr[1]);
strcat(d, p + strlen(dest));
dest = d;
print = 1;
}
}
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 = ".";
print = 1;
}
if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
if (*dest == '\0')
dest = ".";
p = dest;
if (*p == '.' && *++p == '.')
p++;
if (*p == 0 || *p == '/' || (path = bltinlookup("CDPATH", 1)) == NULL)
path = nullstr;
while ((p = padvance(&path, dest)) != NULL) {
if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) {
@ -127,41 +133,27 @@ cdcmd(int argc, char **argv)
* XXX - rethink
*/
if (p[0] == '.' && p[1] == '/' && p[2] != '\0')
p += 2;
print = strcmp(p, dest);
print = strcmp(p + 2, dest);
else
print = strcmp(p, dest);
}
if (docd(p, print, phys) >= 0)
if (docd(p, print) >= 0)
return 0;
}
}
error("can't cd to %s", dest);
/*NOTREACHED*/
return 0;
/* NOTREACHED */
}
/*
* Actually change the directory. In an interactive shell, print the
* Actually do the chdir. In an interactive shell, print the
* directory name if "print" is nonzero.
*/
STATIC int
docd(const 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;
}
STATIC int
cdlogical(const char *dest)
docd(const char *dest, int print)
{
char *p;
char *q;
@ -170,6 +162,8 @@ cdlogical(const char *dest)
int first;
int badstat;
TRACE(("docd(\"%s\", %d) called\n", dest, print));
/*
* Check each component of the path. If we find a symlink or
* something we can't stat, clear curdir to force a getcwd()
@ -196,38 +190,32 @@ cdlogical(const char *dest)
if (equal(component, ".."))
continue;
STACKSTRNUL(p);
if (lstat(stackblock(), &statb) < 0) {
if ((lstat(stackblock(), &statb) < 0)
|| (S_ISLNK(statb.st_mode))) {
/* print = 1; */
badstat = 1;
break;
}
}
INTOFF;
if (updatepwd(badstat ? NULL : dest) < 0 || chdir(curdir) < 0) {
if (chdir(dest) < 0) {
INTON;
return (-1);
return -1;
}
updatepwd(badstat ? NULL : dest);
INTON;
return (0);
if (print && iflag == 1 && curdir)
out1fmt("%s\n", curdir);
return 0;
}
STATIC int
cdphysical(const 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(void)
{
@ -249,12 +237,14 @@ getcomponent(void)
}
/*
* 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.
*/
STATIC int
STATIC void
updatepwd(const char *dir)
{
char *new;
@ -273,14 +263,14 @@ updatepwd(const char *dir)
INTOFF;
prevdir = curdir;
curdir = NULL;
if (getpwd() == NULL) {
INTON;
return (-1);
}
setvar("PWD", curdir, VEXPORT);
setvar("OLDPWD", prevdir, VEXPORT);
getpwd(1);
INTON;
return (0);
if (curdir) {
setvar("OLDPWD", prevdir, VEXPORT);
setvar("PWD", curdir, VEXPORT);
} else
unsetvar("PWD", 0);
return;
}
cdcomppath = stalloc(strlen(dir) + 1);
scopy(dir, cdcomppath);
@ -309,82 +299,166 @@ updatepwd(const char *dir)
ckfree(prevdir);
prevdir = curdir;
curdir = savestr(stackblock());
setvar("PWD", curdir, VEXPORT);
setvar("OLDPWD", prevdir, VEXPORT);
setvar("PWD", curdir, VEXPORT);
INTON;
return (0);
}
/*
* Posix says the default should be 'pwd -L' (as below), however
* the 'cd' command (above) does something much nearer to the
* posix 'cd -P' (not the posix default of 'cd -L').
* If 'cd' is changed to support -P/L then the default here
* needs to be revisited if the historic behaviour is to be kept.
*/
int
pwdcmd(int argc, char **argv)
{
char buf[PATH_MAX];
int ch, phys;
int i;
char opt = 'L';
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;
while ((i = nextopt("LP")) != '\0')
opt = i;
if (*argptr)
error("unexpected argument");
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');
}
if (opt == 'L')
getpwd(0);
else
find_curdir(0);
setvar("OLDPWD", prevdir, VEXPORT);
setvar("PWD", curdir, VEXPORT);
out1str(curdir);
out1c('\n');
return 0;
}
void
initpwd(void)
{
getpwd(1);
if (curdir)
setvar("PWD", curdir, VEXPORT);
else
sh_warnx("Cannot determine current working directory");
}
#define MAXPWD 256
/*
* Find out what the current directory is. If we already know the current
* directory, this routine returns immediately.
*/
char *
getpwd(void)
void
getpwd(int noerror)
{
char buf[PATH_MAX];
char *pwd;
struct stat stdot, stpwd;
static int first = 1;
if (curdir)
return curdir;
if (getcwd(buf, sizeof(buf)) == NULL) {
char *pwd = getenv("PWD");
struct stat stdot, stpwd;
return;
if (first) {
first = 0;
pwd = getenv("PWD");
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;
return;
}
return NULL;
}
curdir = savestr(buf);
return curdir;
find_curdir(noerror);
return;
}
/*
* $PchId: cd.c,v 1.6 2006/05/22 12:42:03 philip Exp $
*/
STATIC void
find_curdir(int noerror)
{
int i;
char *pwd;
/*
* Things are a bit complicated here; we could have just used
* getcwd, but traditionally getcwd is implemented using popen
* to /bin/pwd. This creates a problem for us, since we cannot
* keep track of the job if it is being ran behind our backs.
* So we re-implement getcwd(), and we suppress interrupts
* throughout the process. This is not completely safe, since
* the user can still break out of it by killing the pwd program.
* We still try to use getcwd for systems that we know have a
* c implementation of getcwd, that does not open a pipe to
* /bin/pwd.
*/
#if defined(__NetBSD__) || defined(__SVR4) || defined(__minix)
for (i = MAXPWD;; i *= 2) {
pwd = stalloc(i);
if (getcwd(pwd, i) != NULL) {
curdir = savestr(pwd);
return;
}
stunalloc(pwd);
if (errno == ERANGE)
continue;
if (!noerror)
error("getcwd() failed: %s", strerror(errno));
return;
}
#else
{
char *p;
int status;
struct job *jp;
int pip[2];
pwd = stalloc(MAXPWD);
INTOFF;
if (pipe(pip) < 0)
error("Pipe call failed");
jp = makejob(NULL, 1);
if (forkshell(jp, NULL, FORK_NOJOB) == 0) {
(void) close(pip[0]);
if (pip[1] != 1) {
close(1);
copyfd(pip[1], 1, 1);
close(pip[1]);
}
(void) execl("/bin/pwd", "pwd", (char *)0);
error("Cannot exec /bin/pwd");
}
(void) close(pip[1]);
pip[1] = -1;
p = pwd;
while ((i = read(pip[0], p, pwd + MAXPWD - p)) > 0
|| (i == -1 && errno == EINTR)) {
if (i > 0)
p += i;
}
(void) close(pip[0]);
pip[0] = -1;
status = waitforjob(jp);
if (status != 0)
error((char *)0);
if (i < 0 || p == pwd || p[-1] != '\n') {
if (noerror) {
INTON;
return;
}
error("pwd command failed");
}
p[-1] = '\0';
INTON;
curdir = savestr(pwd);
return;
}
#endif
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: cd.h,v 1.6 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1995
* The Regents of the University of California. All rights reserved.
@ -10,7 +12,7 @@
* 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
* 3. 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.
*
@ -26,13 +28,7 @@
* 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 $
*/
void initpwd(void);
void getpwd(int);

370
bin/sh/error.c Normal file
View file

@ -0,0 +1,370 @@
/* $NetBSD: error.c,v 1.38 2012/03/15 02:02:20 joerg Exp $ */
/*-
* 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)error.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: error.c,v 1.38 2012/03/15 02:02:20 joerg Exp $");
#endif
#endif /* not lint */
/*
* Errors and exceptions.
*/
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "shell.h"
#include "eval.h" /* for commandname */
#include "main.h"
#include "options.h"
#include "output.h"
#include "error.h"
#include "show.h"
/*
* Code to handle exceptions in C.
*/
struct jmploc *handler;
int exception;
volatile int suppressint;
volatile int intpending;
static void exverror(int, const char *, va_list) __dead;
/*
* 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
* stored in the global variable "exception".
*/
void
exraise(int e)
{
if (handler == NULL)
abort();
exception = e;
longjmp(handler->loc, 1);
}
/*
* 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.)
*/
void
onint(void)
{
sigset_t nsigset;
if (suppressint) {
intpending = 1;
return;
}
intpending = 0;
sigemptyset(&nsigset);
sigprocmask(SIG_SETMASK, &nsigset, NULL);
if (rootshell && iflag)
exraise(EXINT);
else {
signal(SIGINT, SIG_DFL);
raise(SIGINT);
}
/* NOTREACHED */
}
static __printflike(2, 0) void
exvwarning(int sv_errno, const char *msg, va_list ap)
{
/* Partially emulate line buffered output so that:
* printf '%d\n' 1 a 2
* and
* printf '%d %d %d\n' 1 a 2
* both generate sensible text when stdout and stderr are merged.
*/
if (output.nextc != output.buf && output.nextc[-1] == '\n')
flushout(&output);
if (commandname)
outfmt(&errout, "%s: ", commandname);
else
outfmt(&errout, "%s: ", getprogname());
if (msg != NULL) {
doformat(&errout, msg, ap);
if (sv_errno >= 0)
outfmt(&errout, ": ");
}
if (sv_errno >= 0)
outfmt(&errout, "%s", strerror(sv_errno));
out2c('\n');
flushout(&errout);
}
/*
* Exverror is called to raise the error exception. If the second argument
* is not NULL then error prints an error message using printf style
* formatting. It then raises the error exception.
*/
static __printflike(2, 0) void
exverror(int cond, const char *msg, va_list ap)
{
CLEAR_PENDING_INT;
INTOFF;
#ifdef DEBUG
if (msg) {
TRACE(("exverror(%d, \"", cond));
TRACEV((msg, ap));
TRACE(("\") pid=%d\n", getpid()));
} else
TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));
#endif
if (msg)
exvwarning(-1, msg, ap);
flushall();
exraise(cond);
/* NOTREACHED */
}
void
error(const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
exverror(EXERROR, msg, ap);
/* NOTREACHED */
va_end(ap);
}
void
exerror(int cond, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
exverror(cond, msg, ap);
/* NOTREACHED */
va_end(ap);
}
/*
* error/warning routines for external builtins
*/
void
sh_exit(int rval)
{
exerrno = rval & 255;
exraise(EXEXEC);
}
void
sh_err(int status, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
exvwarning(errno, fmt, ap);
va_end(ap);
sh_exit(status);
}
void
sh_verr(int status, const char *fmt, va_list ap)
{
exvwarning(errno, fmt, ap);
sh_exit(status);
}
void
sh_errx(int status, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
exvwarning(-1, fmt, ap);
va_end(ap);
sh_exit(status);
}
void
sh_verrx(int status, const char *fmt, va_list ap)
{
exvwarning(-1, fmt, ap);
sh_exit(status);
}
void
sh_warn(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
exvwarning(errno, fmt, ap);
va_end(ap);
}
void
sh_vwarn(const char *fmt, va_list ap)
{
exvwarning(errno, fmt, ap);
}
void
sh_warnx(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
exvwarning(-1, fmt, ap);
va_end(ap);
}
void
sh_vwarnx(const char *fmt, va_list ap)
{
exvwarning(-1, fmt, ap);
}
/*
* Table of error messages.
*/
struct errname {
short errcode; /* error number */
short action; /* operation which encountered the error */
const 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" },
{ EEXIST, ALL, "file exists" },
{ 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" },
#ifdef EMFILE
{ EMFILE, ALL, "too many open files" },
#endif
{ 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 EAGAIN
{ 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
#ifdef ENAMETOOLONG
{ ENAMETOOLONG, ALL, "file name too long" },
#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.
*/
const char *
errmsg(int e, int 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;
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: error.h,v 1.19 2012/03/15 02:02:20 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,28 +32,38 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
#include <stdarg.h>
/*
* 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 exception. To implement nested
* contains a code identifying the exeception. 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 <setjmp.h>
#include <signal.h>
struct jmploc {
jmp_buf loc;
};
extern struct jmploc *handler;
extern volatile sig_atomic_t exception;
extern int exception;
extern int exerrno; /* error for EXEXEC */
/* exceptions */
#define EXINT 0 /* SIGINT received */
@ -67,8 +79,8 @@ extern volatile sig_atomic_t exception;
* more fun than worrying about efficiency and portability. :-))
*/
extern volatile sig_atomic_t suppressint;
extern volatile sig_atomic_t intpending;
extern volatile int suppressint;
extern volatile int intpending;
#define INTOFF suppressint++
#define INTON { if (--suppressint == 0 && intpending) onint(); }
@ -76,12 +88,24 @@ extern volatile sig_atomic_t intpending;
#define CLEAR_PENDING_INT intpending = 0
#define int_pending() intpending
#define __printf0like(a,b)
void exraise(int);
#if ! defined(SHELL_BUILTIN)
void exraise(int) __dead;
void onint(void);
void error(const char *, ...) __printf0like(1, 2);
void exerror(int, const char *, ...) __printf0like(2, 3);
void error(const char *, ...) __dead __printflike(1, 2);
void exerror(int, const char *, ...) __dead __printflike(2, 3);
const char *errmsg(int, int);
#endif /* ! SHELL_BUILTIN */
void sh_err(int, const char *, ...) __dead __printflike(2, 3);
void sh_verr(int, const char *, va_list) __dead __printflike(2, 0);
void sh_errx(int, const char *, ...) __dead __printflike(2, 3);
void sh_verrx(int, const char *, va_list) __dead __printflike(2, 0);
void sh_warn(const char *, ...) __printflike(1, 2);
void sh_vwarn(const char *, va_list) __printflike(1, 0);
void sh_warnx(const char *, ...) __printflike(1, 2);
void sh_vwarnx(const char *, va_list) __printflike(1, 0);
void sh_exit(int) __dead;
/*
@ -89,13 +113,7 @@ void exerror(int, const char *, ...) __printf0like(2, 3);
* so we use _setjmp instead.
*/
#ifdef BSD
#ifndef __minix
#if defined(BSD) && !defined(__SVR4)
#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 $
*/

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
/* $NetBSD: eval.h,v 1.15 2008/02/15 17:26:06 matt Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,11 +32,11 @@
* SUCH DAMAGE.
*
* @(#)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 */
extern const char *commandname; /* currently executing command */
extern int exitstatus; /* exit status of last command */
extern int back_exitstatus; /* exit status of backquoted command */
extern struct strlist *cmdenviron; /* environment for builtin command */
@ -45,18 +47,10 @@ struct backcmd { /* result of evalbackcmd */
struct job *jp; /* job structure for command */
};
int evalcmd(int, char **);
void evalstring(char *);
void evalstring(char *, int);
union node; /* BLETCH for ansi C */
void evaltree(union node *, int);
void evalbackcmd(union node *, struct backcmd *);
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
@ -68,7 +62,3 @@ extern int evalskip;
#define SKIPCONT 2
#define SKIPFUNC 3
#define SKIPFILE 4
/*
* $PchId: eval.h,v 1.3 2006/03/30 15:39:25 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: exec.c,v 1.45 2013/11/01 16:49:02 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,21 +32,22 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)exec.c 8.4 (Berkeley) 6/8/95";
#else
__RCSID("$NetBSD: exec.c,v 1.45 2013/11/01 16:49:02 christos Exp $");
#endif
#endif /* not lint */
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/bin/sh/exec.c,v 1.24.2.1 2004/09/30 04:41:55 des Exp $");
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
/*
@ -97,13 +100,18 @@ STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */
int exerrno = 0; /* Last exec error */
STATIC void tryexec(char *, char **, char **);
STATIC void tryexec(char *, char **, char **, int);
STATIC void printentry(struct tblentry *, int);
STATIC struct tblentry *cmdlookup(char *, int);
STATIC void clearcmdentry(int);
STATIC struct tblentry *cmdlookup(const char *, int);
STATIC void delete_cmd_entry(void);
STATIC void addcmdentry(char *, struct cmdentry *);
#ifndef BSD
STATIC void execinterp(char **, char **);
#endif
extern const char *const parsekwd[];
/*
* Exec a program. Never returns. If you change this routine, you may
@ -111,19 +119,19 @@ STATIC void addcmdentry(char *, struct cmdentry *);
*/
void
shellexec(char **argv, char **envp, char *path, int index)
shellexec(char **argv, char **envp, const char *path, int idx, int vforked)
{
char *cmdname;
int e;
if (strchr(argv[0], '/') != NULL) {
tryexec(argv[0], argv, envp);
tryexec(argv[0], argv, envp, vforked);
e = errno;
} else {
e = ENOENT;
while ((cmdname = padvance(&path, argv[0])) != NULL) {
if (--index < 0 && pathopt == NULL) {
tryexec(cmdname, argv, envp);
if (--idx < 0 && pathopt == NULL) {
tryexec(cmdname, argv, envp, vforked);
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
}
@ -143,31 +151,137 @@ shellexec(char **argv, char **envp, char *path, int index)
exerrno = 2;
break;
}
if (e == ENOENT || e == ENOTDIR)
exerror(EXEXEC, "%s: not found", argv[0]);
exerror(EXEXEC, "%s: %s", argv[0], strerror(e));
TRACE(("shellexec failed for %s, errno %d, vforked %d, suppressint %d\n",
argv[0], e, vforked, suppressint ));
exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC));
/* NOTREACHED */
}
STATIC void
tryexec(char *cmd, char **argv, char **envp)
tryexec(char *cmd, char **argv, char **envp, int vforked)
{
int e;
#ifndef BSD
char *p;
#endif
#ifdef SYSV
do {
execve(cmd, argv, envp);
} while (errno == EINTR);
#else
execve(cmd, argv, envp);
#endif
e = errno;
if (e == ENOEXEC) {
if (vforked) {
/* We are currently vfork(2)ed, so raise an
* exception, and evalcommand will try again
* with a normal fork(2).
*/
exraise(EXSHELLPROC);
}
#ifdef DEBUG
TRACE(("execve(cmd=%s) returned ENOEXEC\n", cmd));
#endif
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*/
}
errno = e;
}
#ifndef BSD
/*
* 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(char **argv, char **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 (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:;
}
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);
/* NOTREACHED */
}
#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
@ -178,13 +292,14 @@ tryexec(char *cmd, char **argv, char **envp)
* NULL.
*/
char *pathopt;
const char *pathopt;
char *
padvance(char **path, char *name)
padvance(const char **path, const char *name)
{
char *p, *q;
char *start;
const char *p;
char *q;
const char *start;
int len;
if (*path == NULL)
@ -219,7 +334,7 @@ padvance(char **path, char *name)
int
hashcmd(int argc __unused, char **argv __unused)
hashcmd(int argc, char **argv)
{
struct tblentry **pp;
struct tblentry *cmdp;
@ -239,7 +354,7 @@ hashcmd(int argc __unused, char **argv __unused)
if (*argptr == NULL) {
for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) {
for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) {
if (cmdp->cmdtype == CMDNORMAL)
if (verbose || cmdp->cmdtype == CMDNORMAL)
printentry(cmdp, verbose);
}
}
@ -250,14 +365,12 @@ hashcmd(int argc __unused, char **argv __unused)
&& (cmdp->cmdtype == CMDNORMAL
|| (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)))
delete_cmd_entry();
find_command(name, &entry, 1, pathval());
find_command(name, &entry, DO_ERR, pathval());
if (verbose) {
if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */
cmdp = cmdlookup(name, 0);
if (cmdp != NULL)
printentry(cmdp, verbose);
else
outfmt(&errout, "%s: not found\n", name);
}
flushall();
}
@ -270,34 +383,40 @@ hashcmd(int argc __unused, char **argv __unused)
STATIC void
printentry(struct tblentry *cmdp, int verbose)
{
int index;
char *path;
int idx;
const char *path;
char *name;
if (cmdp->cmdtype == CMDNORMAL) {
index = cmdp->param.index;
switch (cmdp->cmdtype) {
case CMDNORMAL:
idx = cmdp->param.index;
path = pathval();
do {
name = padvance(&path, cmdp->cmdname);
stunalloc(name);
} while (--index >= 0);
} while (--idx >= 0);
out1str(name);
} else if (cmdp->cmdtype == CMDBUILTIN) {
break;
case CMDSPLBLTIN:
out1fmt("special builtin %s", cmdp->cmdname);
break;
case CMDBUILTIN:
out1fmt("builtin %s", cmdp->cmdname);
} else if (cmdp->cmdtype == CMDFUNCTION) {
break;
case CMDFUNCTION:
out1fmt("function %s", cmdp->cmdname);
if (verbose) {
struct procstat ps;
INTOFF;
name = commandtext(cmdp->param.func);
out1c(' ');
out1str(name);
ckfree(name);
commandtext(&ps, cmdp->param.func);
INTON;
out1str("() { ");
out1str(ps.cmd);
out1str("; }");
}
#if DEBUG
} else {
error("internal error: cmdtype %d", cmdp->cmdtype);
#endif
break;
default:
error("internal error: %s cmdtype %d", cmdp->cmdname, cmdp->cmdtype);
}
if (cmdp->rehash)
out1c('*');
@ -312,36 +431,78 @@ printentry(struct tblentry *cmdp, int verbose)
*/
void
find_command(char *name, struct cmdentry *entry, int printerr, char *path)
find_command(char *name, struct cmdentry *entry, int act, const char *path)
{
struct tblentry *cmdp;
int index;
struct tblentry *cmdp, loc_cmd;
int idx;
int prev;
char *fullname;
struct stat statb;
int e;
int i;
int (*bltin)(int,char **);
/* If name contains a slash, don't use the hash table */
/* If name contains a slash, don't use PATH or hash table */
if (strchr(name, '/') != NULL) {
if (act & DO_ABS) {
while (stat(name, &statb) < 0) {
#ifdef SYSV
if (errno == EINTR)
continue;
#endif
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
entry->cmdtype = CMDUNKNOWN;
entry->u.index = -1;
return;
}
entry->cmdtype = CMDNORMAL;
entry->u.index = -1;
return;
}
entry->cmdtype = CMDNORMAL;
entry->u.index = 0;
return;
}
/* If name is in the table, and not invalidated by cd, we're done */
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->rehash == 0)
goto success;
if (path != pathval())
act |= DO_ALTPATH;
if (act & DO_ALTPATH && strstr(path, "%builtin") != NULL)
act |= DO_ALTBLTIN;
/* If name is in the table, check answer will be ok */
if ((cmdp = cmdlookup(name, 0)) != NULL) {
do {
switch (cmdp->cmdtype) {
case CMDNORMAL:
if (act & DO_ALTPATH) {
cmdp = NULL;
continue;
}
break;
case CMDFUNCTION:
if (act & DO_NOFUNC) {
cmdp = NULL;
continue;
}
break;
case CMDBUILTIN:
if ((act & DO_ALTBLTIN) || builtinloc >= 0) {
cmdp = NULL;
continue;
}
break;
}
/* if not invalidated by cd, we're done */
if (cmdp->rehash == 0)
goto success;
} while (0);
}
/* If %builtin not in path, check for builtin next */
if (builtinloc < 0 && (i = find_builtin(name)) >= 0) {
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
INTON;
goto success;
}
if ((act & DO_ALTPATH ? !(act & DO_ALTBLTIN) : builtinloc < 0) &&
(bltin = find_builtin(name)) != 0)
goto builtin_success;
/* We have to search path. */
prev = -1; /* where to start */
@ -353,35 +514,35 @@ find_command(char *name, struct cmdentry *entry, int printerr, char *path)
}
e = ENOENT;
index = -1;
idx = -1;
loop:
while ((fullname = padvance(&path, name)) != NULL) {
stunalloc(fullname);
index++;
idx++;
if (pathopt) {
if (prefix("builtin", pathopt)) {
if ((i = find_builtin(name)) < 0)
if ((bltin = find_builtin(name)) == 0)
goto loop;
INTOFF;
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.index = i;
INTON;
goto success;
goto builtin_success;
} else if (prefix("func", pathopt)) {
/* handled below */
} else {
goto loop; /* ignore unimplemented options */
/* ignore unimplemented options */
goto loop;
}
}
/* if rehash, don't redo absolute path names */
if (fullname[0] == '/' && index <= prev) {
if (index < prev)
if (fullname[0] == '/' && idx <= prev) {
if (idx < prev)
goto loop;
TRACE(("searchexec \"%s\": no change\n", name));
goto success;
}
if (stat(fullname, &statb) < 0) {
while (stat(fullname, &statb) < 0) {
#ifdef SYSV
if (errno == EINTR)
continue;
#endif
if (errno != ENOENT && errno != ENOTDIR)
e = errno;
goto loop;
@ -390,14 +551,19 @@ loop:
if (!S_ISREG(statb.st_mode))
goto loop;
if (pathopt) { /* this is a %func directory */
if (act & DO_NOFUNC)
goto loop;
stalloc(strlen(fullname) + 1);
readcmdfile(fullname);
if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION)
if ((cmdp = cmdlookup(name, 0)) == NULL ||
cmdp->cmdtype != CMDFUNCTION)
error("%s not defined in %s", name, fullname);
stunalloc(fullname);
goto success;
}
#ifdef notdef
/* XXX this code stops root executing stuff, and is buggy
if you need a group from the group list. */
if (statb.st_uid == geteuid()) {
if ((statb.st_mode & 0100) == 0)
goto loop;
@ -411,9 +577,13 @@ loop:
#endif
TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname));
INTOFF;
cmdp = cmdlookup(name, 1);
if (act & DO_ALTPATH) {
stalloc(strlen(fullname) + 1);
cmdp = &loc_cmd;
} else
cmdp = cmdlookup(name, 1);
cmdp->cmdtype = CMDNORMAL;
cmdp->param.index = index;
cmdp->param.index = idx;
INTON;
goto success;
}
@ -421,19 +591,30 @@ loop:
/* We failed. If there was an entry for this command, delete it */
if (cmdp)
delete_cmd_entry();
if (printerr) {
if (e == ENOENT || e == ENOTDIR)
outfmt(out2, "%s: not found\n", name);
else
outfmt(out2, "%s: %s\n", name, strerror(e));
}
if (act & DO_ERR)
outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC));
entry->cmdtype = CMDUNKNOWN;
return;
builtin_success:
INTOFF;
if (act & DO_ALTPATH)
cmdp = &loc_cmd;
else
cmdp = cmdlookup(name, 1);
if (cmdp->cmdtype == CMDFUNCTION)
/* DO_NOFUNC must have been set */
cmdp = &loc_cmd;
cmdp->cmdtype = CMDBUILTIN;
cmdp->param.bltin = bltin;
INTON;
success:
cmdp->rehash = 0;
entry->cmdtype = cmdp->cmdtype;
entry->u = cmdp->param;
if (cmdp) {
cmdp->rehash = 0;
entry->cmdtype = cmdp->cmdtype;
entry->u = cmdp->param;
} else
entry->cmdtype = CMDUNKNOWN;
}
@ -443,15 +624,48 @@ success:
*/
int
find_builtin(char *name)
(*find_builtin(char *name))(int, char **)
{
const struct builtincmd *bp;
for (bp = builtincmd ; bp->name ; bp++) {
if (*bp->name == *name && equal(bp->name, name))
return bp->code;
if (*bp->name == *name
&& (*name == '%' || equal(bp->name, name)))
return bp->builtin;
}
return 0;
}
int
(*find_splbltin(char *name))(int, char **)
{
const struct builtincmd *bp;
for (bp = splbltincmd ; bp->name ; bp++) {
if (*bp->name == *name && equal(bp->name, name))
return bp->builtin;
}
return 0;
}
/*
* At shell startup put special builtins into hash table.
* ensures they are executed first (see posix).
* We stop functions being added with the same name
* (as they are impossible to call)
*/
void
hash_special_builtins(void)
{
const struct builtincmd *bp;
struct tblentry *cmdp;
for (bp = splbltincmd ; bp->name ; bp++) {
cmdp = cmdlookup(bp->name, 1);
cmdp->cmdtype = CMDSPLBLTIN;
cmdp->param.bltin = bp->builtin;
}
return -1;
}
@ -479,27 +693,28 @@ hashcd(void)
/*
* Fix command hash table when PATH changed.
* Called before PATH is changed. The argument is the new value of PATH;
* pathval() still returns the old value at this point. Called with
* interrupts off.
* pathval() still returns the old value at this point.
* Called with interrupts off.
*/
void
changepath(const char *newval)
{
const char *old, *new;
int index;
int idx;
int firstchange;
int bltin;
old = pathval();
new = newval;
firstchange = 9999; /* assume no change */
index = 0;
idx = 0;
bltin = -1;
for (;;) {
if (*old != *new) {
firstchange = index;
firstchange = idx;
if ((*old == '\0' && *new == ':')
|| (*old == ':' && *new == '\0'))
firstchange++;
@ -508,9 +723,9 @@ changepath(const char *newval)
if (*new == '\0')
break;
if (*new == '%' && bltin < 0 && prefix("builtin", new + 1))
bltin = index;
bltin = idx;
if (*new == ':') {
index++;
idx++;
}
new++, old++;
}
@ -528,7 +743,7 @@ changepath(const char *newval)
* PATH which has changed.
*/
void
STATIC void
clearcmdentry(int firstchange)
{
struct tblentry **tblp;
@ -559,7 +774,13 @@ clearcmdentry(int firstchange)
*/
#ifdef mkinit
INCLUDE "exec.h"
MKINIT void deletefuncs(void);
MKINIT void hash_special_builtins(void);
INIT {
hash_special_builtins();
}
SHELLPROC {
deletefuncs();
}
@ -598,14 +819,14 @@ deletefuncs(void)
* entry.
*/
STATIC struct tblentry **lastcmdentry;
struct tblentry **lastcmdentry;
STATIC struct tblentry *
cmdlookup(char *name, int add)
cmdlookup(const char *name, int add)
{
int hashval;
char *p;
const char *p;
struct tblentry *cmdp;
struct tblentry **pp;
@ -652,23 +873,42 @@ delete_cmd_entry(void)
#ifdef notdef
void
getcmdentry(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.
* the same name - except special builtins.
*/
static void
STATIC void
addcmdentry(char *name, struct cmdentry *entry)
{
struct tblentry *cmdp;
INTOFF;
cmdp = cmdlookup(name, 1);
if (cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
if (cmdp->cmdtype != CMDSPLBLTIN) {
if (cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
}
cmdp->cmdtype = entry->cmdtype;
cmdp->param = entry->u;
}
cmdp->cmdtype = entry->cmdtype;
cmdp->param = entry->u;
INTON;
}
@ -699,16 +939,17 @@ unsetfunc(char *name)
{
struct tblentry *cmdp;
if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) {
if ((cmdp = cmdlookup(name, 0)) != NULL &&
cmdp->cmdtype == CMDFUNCTION) {
freefunc(cmdp->param.func);
delete_cmd_entry();
return (0);
}
return (0);
return 0;
}
/*
* Locate and print what a word is...
* also used for 'command -[v|V]'
*/
int
@ -716,76 +957,115 @@ typecmd(int argc, char **argv)
{
struct cmdentry entry;
struct tblentry *cmdp;
char **pp;
const char * const *pp;
struct alias *ap;
int i;
int error = 0;
extern char *const parsekwd[];
int err = 0;
char *arg;
int c;
int V_flag = 0;
int v_flag = 0;
int p_flag = 0;
for (i = 1; i < argc; i++) {
out1str(argv[i]);
while ((c = nextopt("vVp")) != 0) {
switch (c) {
case 'v': v_flag = 1; break;
case 'V': V_flag = 1; break;
case 'p': p_flag = 1; break;
}
}
if (p_flag && (v_flag || V_flag))
error("cannot specify -p with -v or -V");
while ((arg = *argptr++)) {
if (!v_flag)
out1str(arg);
/* First look at the keywords */
for (pp = (char **)parsekwd; *pp; pp++)
if (**pp == *argv[i] && equal(*pp, argv[i]))
for (pp = parsekwd; *pp; pp++)
if (**pp == *arg && equal(*pp, arg))
break;
if (*pp) {
out1str(" is a shell keyword\n");
if (v_flag)
err = 1;
else
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);
if ((ap = lookupalias(arg, 1)) != NULL) {
if (!v_flag)
out1fmt(" is an alias for \n");
out1fmt("%s\n", ap->val);
continue;
}
/* Then check if it is a tracked alias */
if ((cmdp = cmdlookup(argv[i], 0)) != NULL) {
if ((cmdp = cmdlookup(arg, 0)) != NULL) {
entry.cmdtype = cmdp->cmdtype;
entry.u = cmdp->param;
}
else {
} else {
/* Finally use brute force */
find_command(argv[i], &entry, 0, pathval());
find_command(arg, &entry, DO_ABS, pathval());
}
switch (entry.cmdtype) {
case CMDNORMAL: {
if (strchr(argv[i], '/') == NULL) {
char *path = pathval(), *name;
if (strchr(arg, '/') == NULL) {
const char *path = pathval();
char *name;
int j = entry.u.index;
do {
name = padvance(&path, argv[i]);
name = padvance(&path, arg);
stunalloc(name);
} while (--j >= 0);
out1fmt(" is%s %s\n",
cmdp ? " a tracked alias for" : "", name);
if (!v_flag)
out1fmt(" is%s ",
cmdp ? " a tracked alias for" : "");
out1fmt("%s\n", name);
} else {
if (access(argv[i], X_OK) == 0)
out1fmt(" is %s\n", argv[i]);
else
out1fmt(": %s\n", strerror(errno));
if (access(arg, X_OK) == 0) {
if (!v_flag)
out1fmt(" is ");
out1fmt("%s\n", arg);
} else {
if (!v_flag)
out1fmt(": %s\n",
strerror(errno));
else
err = 126;
}
}
break;
break;
}
case CMDFUNCTION:
out1str(" is a shell function\n");
if (!v_flag)
out1str(" is a shell function\n");
else
out1fmt("%s\n", arg);
break;
case CMDBUILTIN:
out1str(" is a shell builtin\n");
if (!v_flag)
out1str(" is a shell builtin\n");
else
out1fmt("%s\n", arg);
break;
case CMDSPLBLTIN:
if (!v_flag)
out1str(" is a special shell builtin\n");
else
out1fmt("%s\n", arg);
break;
default:
out1str(": not found\n");
error |= 127;
if (!v_flag)
out1str(": not found\n");
err = 127;
break;
}
}
return error;
return err;
}
/*
* $PchId: exec.c,v 1.6 2006/04/10 14:47:03 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: exec.h,v 1.23 2012/03/15 02:02:20 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,41 +32,45 @@
* SUCH DAMAGE.
*
* @(#)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 */
#define CMDUNKNOWN -1 /* no entry in table for command */
#define CMDNORMAL 0 /* command is an executable program */
#define CMDBUILTIN 1 /* command is a shell builtin */
#define CMDFUNCTION 2 /* command is a shell function */
#define CMDUNKNOWN -1 /* no entry in table for command */
#define CMDNORMAL 0 /* command is an executable program */
#define CMDFUNCTION 1 /* command is a shell function */
#define CMDBUILTIN 2 /* command is a shell builtin */
#define CMDSPLBLTIN 3 /* command is a special shell builtin */
struct cmdentry {
int cmdtype;
union param {
int index;
int (*bltin)(int, char**);
union node *func;
} u;
};
extern char *pathopt; /* set by padvance */
extern int exerrno; /* last exec error */
/* action to find_command() */
#define DO_ERR 0x01 /* prints errors */
#define DO_ABS 0x02 /* checks absolute paths */
#define DO_NOFUNC 0x04 /* don't return shell functions, for command */
#define DO_ALTPATH 0x08 /* using alternate path */
#define DO_ALTBLTIN 0x20 /* %builtin in alt. path */
void shellexec(char **, char **, char *, int);
char *padvance(char **, char *);
int hashcmd(int, char **);
void find_command(char *, struct cmdentry *, int, char *);
int find_builtin(char *);
extern const char *pathopt; /* set by padvance */
void shellexec(char **, char **, const char *, int, int) __dead;
char *padvance(const char **, const char *);
void find_command(char *, struct cmdentry *, int, const char *);
int (*find_builtin(char *))(int, char **);
int (*find_splbltin(char *))(int, char **);
void hashcd(void);
void changepath(const char *);
void deletefuncs(void);
void getcmdentry(char *, struct cmdentry *);
void addcmdentry(char *, struct cmdentry *);
void defun(char *, union node *);
int unsetfunc(char *);
int typecmd(int, char **);
void clearcmdentry(int);
/*
* $PchId: exec.h,v 1.5 2006/04/10 14:47:34 philip Exp $
*/
void hash_special_builtins(void);

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
/* $NetBSD: expand.h,v 1.19 2012/12/22 20:15:22 dsl Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,9 +32,10 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
#include <inttypes.h>
struct strlist {
struct strlist *next;
char *text;
@ -52,23 +55,19 @@ struct arglist {
#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 */
#define EXP_IFS_SPLIT 0x20 /* need to record arguments for ifs breakup */
#define EXP_IN_QUOTES 0x40 /* don't set EXP_IFS_SPLIT again */
union node;
void expandhere(union node *, int);
void expandarg(union node *, struct arglist *, int);
void expari(int);
int patmatch(char *, char *, int);
void rmescapes(char *);
int casematch(union node *, char *);
int wordexpcmd(int, char **);
/* From arith.y */
int arith(char *);
int arith_assign(char *, arith_t);
int expcmd(int , char **);
intmax_t arith(const char *);
void arith_lex_reset(void);
/*
* $PchId: expand.h,v 1.4 2006/03/30 14:50:52 philip Exp $
*/
int yylex(void);

9
minix/commands/ash/funcs/cmv → bin/sh/funcs/cmv Executable file → Normal file
View file

@ -1,3 +1,4 @@
# $NetBSD: cmv,v 1.7 1995/05/11 21:31:05 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,7 +34,6 @@
# SUCH DAMAGE.
#
# @(#)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.
@ -44,6 +48,3 @@ cmv() {
fi
/bin/mv "$1" "$2"
}
#
# $PchId: cmv,v 1.2 2006/03/29 10:43:18 philip Exp $

9
minix/commands/ash/funcs/dirs → bin/sh/funcs/dirs Executable file → Normal file
View file

@ -1,3 +1,4 @@
# $NetBSD: dirs,v 1.7 1995/05/11 21:31:08 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,7 +34,6 @@
# SUCH DAMAGE.
#
# @(#)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
@ -68,6 +72,3 @@ dirs () {
echo "`pwd` $DSTACK"
return 0
}
#
# $PchId: dirs,v 1.2 2006/03/29 10:43:18 philip Exp $

9
minix/commands/ash/funcs/kill → bin/sh/funcs/kill Executable file → Normal file
View file

@ -1,3 +1,4 @@
# $NetBSD: kill,v 1.7 1995/05/11 21:31:10 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,7 +34,6 @@
# SUCH DAMAGE.
#
# @(#)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.
@ -44,6 +48,3 @@ kill() {
done
/bin/kill $args
}
#
# $PchId: kill,v 1.2 2006/03/29 10:43:18 philip Exp $

9
minix/commands/ash/funcs/login → bin/sh/funcs/login Executable file → Normal file
View file

@ -1,3 +1,4 @@
# $NetBSD: login,v 1.7 1995/05/11 21:31:11 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,10 +34,6 @@
# SUCH DAMAGE.
#
# @(#)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 $

View file

@ -1,3 +1,4 @@
# $NetBSD: newgrp,v 1.7 1995/05/11 21:31:12 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,9 +34,5 @@
# SUCH DAMAGE.
#
# @(#)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 $

9
minix/commands/ash/funcs/popd → bin/sh/funcs/popd Executable file → Normal file
View file

@ -1,3 +1,4 @@
# $NetBSD: popd,v 1.7 1995/05/11 21:31:13 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,7 +34,6 @@
# SUCH DAMAGE.
#
# @(#)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
@ -68,6 +72,3 @@ dirs () {
echo "`pwd` $DSTACK"
return 0
}
#
# $PchId: popd,v 1.2 2006/03/29 10:43:18 philip Exp $

9
minix/commands/ash/funcs/pushd → bin/sh/funcs/pushd Executable file → Normal file
View file

@ -1,3 +1,4 @@
# $NetBSD: pushd,v 1.7 1995/05/11 21:31:15 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,7 +34,6 @@
# SUCH DAMAGE.
#
# @(#)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
@ -68,6 +72,3 @@ dirs () {
echo "`pwd` $DSTACK"
return 0
}
#
# $PchId: pushd,v 1.2 2006/03/29 10:43:18 philip Exp $

View file

@ -1,3 +1,4 @@
# $NetBSD: suspend,v 1.7 1995/05/11 21:31:17 christos Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -12,6 +13,10 @@
# 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.
@ -29,13 +34,9 @@
# SUCH DAMAGE.
#
# @(#)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 $

View file

@ -1,3 +1,5 @@
/* $NetBSD: histedit.c,v 1.45 2012/03/20 18:42:29 matt Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,20 +32,17 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)histedit.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: histedit.c,v 1.45 2012/03/20 18:42:29 matt Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
*/
#include <limits.h>
#ifndef NO_PATHS_H
#include <sys/param.h>
#include <paths.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@ -54,14 +53,13 @@ __FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $
#include "parser.h"
#include "var.h"
#include "options.h"
#include "builtins.h"
#include "main.h"
#include "output.h"
#include "mystring.h"
#include "builtins.h"
#if !defined(NO_HISTORY)
#include "myhistedit.h"
#include "complete.h"
#include "error.h"
#ifndef SMALL
#include "eval.h"
#include "memalloc.h"
@ -71,11 +69,14 @@ __FBSDID("$FreeBSD: src/bin/sh/histedit.c,v 1.26 2004/04/06 20:06:51 markm Exp $
History *hist; /* history cookie */
EditLine *el; /* editline cookie */
int displayhist;
static FILE *el_in, *el_out, *el_err;
static FILE *el_in, *el_out;
unsigned char _el_fn_complete(EditLine *, int);
STATIC char *fc_replace(const char *, char *, char *);
STATIC int not_fcnumber(char *);
STATIC int str_to_event(char *, int);
STATIC const char *fc_replace(const char *, char *, char *);
#ifdef DEBUG
extern FILE *tracefile;
#endif
/*
* Set history and editing status. Called whenever the status may
@ -84,10 +85,11 @@ STATIC int str_to_event(char *, int);
void
histedit(void)
{
FILE *el_err;
#define editing (Eflag || Vflag)
if (iflag) {
if (iflag == 1) {
if (!hist) {
/*
* turn history on
@ -105,20 +107,37 @@ histedit(void)
/*
* turn editing on
*/
char *term, *shname;
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)
if (el_in == NULL || el_out == NULL)
goto bad;
el = el_init(arg0, el_in, el_out, el_err);
el_err = el_out;
#if DEBUG
if (tracefile)
el_err = tracefile;
#endif
term = lookupvar("TERM");
if (term)
setenv("TERM", term, 1);
else
unsetenv("TERM");
shname = arg0;
if (shname[0] == '-')
shname++;
el = el_init(shname, el_in, el_out, el_err);
if (el != NULL) {
if (hist)
el_set(el, EL_HIST, history, hist);
el_set(el, EL_PROMPT, getprompt);
el_set(el, EL_SIGNAL, 1);
el_set(el, EL_ADDFN, "rl-complete",
"ReadLine compatible completion function",
_el_fn_complete);
} else {
bad:
out2str("sh: can't initialize editing\n");
@ -131,27 +150,13 @@ bad:
INTON;
}
if (el) {
el_source(el, NULL);
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);
el_set(el, EL_BIND, "^I",
tabcomplete ? "rl-complete" : "ed-insert", NULL);
}
} else {
INTOFF;
@ -169,8 +174,7 @@ bad:
void
sethistsize(hs)
const char *hs;
sethistsize(const char *hs)
{
int histsize;
HistEvent he;
@ -180,40 +184,63 @@ sethistsize(hs)
(histsize = atoi(hs)) < 0)
histsize = 100;
history(hist, &he, H_SETSIZE, histsize);
history(hist, &he, H_SETUNIQUE, 1);
}
}
void
setterm(const char *term)
{
if (el != NULL && term != NULL)
if (el_set(el, EL_TERMINAL, term) != 0) {
outfmt(out2, "sh: Can't set terminal type %s\n", term);
outfmt(out2, "sh: Using dumb terminal settings.\n");
}
}
int
inputrc(int argc, char **argv)
{
if (argc != 2) {
out2str("usage: inputrc file\n");
return 1;
}
if (el != NULL) {
if (el_source(el, argv[1])) {
out2str("inputrc: failed\n");
return 1;
} else
return 0;
} else {
out2str("sh: inputrc ignored, not editing\n");
return 1;
}
}
/*
* This command is provided since POSIX decided to standardize
* the Korn shell fc command. Oh well...
*/
int
histcmd(int argc, char **argv)
{
int ch;
char *editor = NULL;
const char * volatile editor = NULL;
HistEvent he;
int lflg = 0, nflg = 0, rflg = 0, sflg = 0;
int lflg = 0;
volatile int nflg = 0, rflg = 0, sflg = 0;
int i, retval;
char *firststr, *laststr;
const char *firststr, *laststr;
int first, last, direction;
char *pat = NULL, *repl;
char *pat = NULL, *repl; /* ksh "fc old=new" crap */
static int active = 0;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
char editfile[PATH_MAX];
char editfile[MAXPATHLEN + 1];
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;
repl = NULL; /* XXX gcc4 */
efp = NULL; /* XXX gcc4 */
#endif
if (hist == NULL)
@ -223,12 +250,11 @@ histcmd(int argc, char **argv)
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;
editor = optionarg;
break;
case 'l':
lflg = 1;
@ -244,9 +270,11 @@ histcmd(int argc, char **argv)
break;
case ':':
error("option -%c expects argument", optopt);
/* NOTREACHED */
case '?':
default:
error("unknown option: -%c", optopt);
/* NOTREACHED */
}
argc -= optind, argv += optind;
@ -260,6 +288,7 @@ histcmd(int argc, char **argv)
* Catch interrupts to reset active counter and
* cleanup temp files.
*/
savehandler = handler;
if (setjmp(jmploc.loc)) {
active = 0;
if (*editfile)
@ -267,7 +296,6 @@ histcmd(int argc, char **argv)
handler = savehandler;
longjmp(handler->loc, 1);
}
savehandler = handler;
handler = &jmploc;
if (++active > MAXHISTLOOPS) {
active = 0;
@ -298,6 +326,13 @@ histcmd(int argc, char **argv)
*repl++ = '\0';
argc--, argv++;
}
/*
* If -s is specified, accept only one operand
*/
if (sflg && argc >= 2)
error("too many args");
/*
* determine [first] and [last]
*/
@ -316,6 +351,7 @@ histcmd(int argc, char **argv)
break;
default:
error("too many args");
/* NOTREACHED */
}
/*
* Turn into event numbers.
@ -341,7 +377,7 @@ histcmd(int argc, char **argv)
if (editor) {
int fd;
INTOFF; /* easier */
sprintf(editfile, "%s/_shXXXXXX", _PATH_TMP);
snprintf(editfile, sizeof(editfile), "%s_shXXXXXX", _PATH_TMP);
if ((fd = mkstemp(editfile)) < 0)
error("can't create temporary file %s", editfile);
if ((efp = fdopen(fd, "w")) == NULL) {
@ -366,34 +402,29 @@ histcmd(int argc, char **argv)
out1fmt("%5d ", he.num);
out1str(he.str);
} else {
char *s = pat ?
fc_replace(he.str, pat, repl) : (char *)he.str;
const char *s = pat ?
fc_replace(he.str, pat, repl) : he.str;
if (sflg) {
if (displayhist) {
out2str(s);
}
evalstring(s);
evalstring(strcpy(stalloc(strlen(s) + 1), s), 0);
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);
}
break;
} else
fputs(s, efp);
}
/*
* At end? (if we were to loose last, we'd sure be
* At end? (if we were to lose last, we'd sure be
* messed up).
*/
if (he.num == last)
@ -405,7 +436,7 @@ histcmd(int argc, char **argv)
fclose(efp);
editcmd = stalloc(strlen(editor) + strlen(editfile) + 2);
sprintf(editcmd, "%s %s", editor, editfile);
evalstring(editcmd); /* XXX - should use no JC command */
evalstring(editcmd, 0); /* XXX - should use no JC command */
INTON;
readcmdfile(editfile); /* XXX - should read back - quick tst */
unlink(editfile);
@ -418,7 +449,7 @@ histcmd(int argc, char **argv)
return 0;
}
STATIC char *
STATIC const char *
fc_replace(const char *s, char *p, char *r)
{
char *dest;
@ -440,21 +471,21 @@ fc_replace(const char *s, char *p, char *r)
return (dest);
}
STATIC int
int
not_fcnumber(char *s)
{
if (s == NULL)
return (0);
if (*s == '-')
s++;
return 0;
if (*s == '-')
s++;
return (!is_number(s));
}
STATIC int
str_to_event(char *str, int last)
int
str_to_event(const char *str, int last)
{
HistEvent he;
char *s = str;
const char *s = str;
int relative = 0;
int i, retval;
@ -481,7 +512,8 @@ str_to_event(char *str, int last)
* the notion of first and last is
* backwards to that of the history package
*/
retval = history(hist, &he, last ? H_FIRST : H_LAST);
retval = history(hist, &he,
last ? H_FIRST : H_LAST);
}
}
if (retval == -1)
@ -497,37 +529,17 @@ str_to_event(char *str, int last)
}
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);
/* NOTREACHED */
}
int
bindcmd(int argc, char **argv)
inputrc(int argc, char **argv)
{
error("not compiled with line editing support");
return (0);
error("not compiled with history support");
/* NOTREACHED */
}
#endif /* !NO_HISTORY */
/*
* $PchId: histedit.c,v 1.6 2006/04/10 14:52:58 philip Exp $
*/
#endif

View file

@ -1,3 +1,5 @@
/* $NetBSD: init.h,v 1.10 2003/08/07 09:05:32 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,13 +32,8 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
void init(void);
void reset(void);
void initshellproc(void);
/*
* $PchId: init.h,v 1.3 2006/03/30 14:31:06 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: input.c,v 1.46 2013/10/30 08:38:40 mrg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,24 +32,22 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
#else
__RCSID("$NetBSD: input.c,v 1.46 2013/10/30 08:38:40 mrg Exp $");
#endif
#endif /* not lint */
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
*/
#include <sys/types.h>
#include <stdio.h> /* defines BUFSIZ */
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
/*
* This file implements the input routines used by the parser.
@ -64,10 +64,6 @@ __FBSDID("$FreeBSD: src/bin/sh/input.c,v 1.22 2004/04/06 20:06:51 markm Exp $");
#include "alias.h"
#include "parser.h"
#include "myhistedit.h"
#include "redir.h"
#include "trap.h"
static void popstring(void);
#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */
@ -91,7 +87,7 @@ struct parsefile {
int linno; /* current line */
int fd; /* file descriptor (or -1 if string) */
int nleft; /* number of chars left in this line */
int lleft; /* number of lines left in this buffer */
int lleft; /* number of chars left in this buffer */
char *nextc; /* next char in buffer */
char *buf; /* input buffer */
struct strpush *strpush; /* for pushing strings at this level */
@ -100,27 +96,24 @@ struct parsefile {
int plinno = 1; /* input line number */
MKINIT int parsenleft; /* copy of parsefile->nleft */
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 */
STATIC struct parsefile *parsefile = &basepf; /* current input file */
MKINIT char basebuf[BUFSIZ]; /* buffer for top level input file */
struct parsefile *parsefile = &basepf; /* current input file */
int init_editline = 0; /* editline library initialized? */
int whichprompt; /* -1 == PSE, 1 == PS1, 2 == PS2 */
EditLine *el; /* cookie for editline package */
int whichprompt; /* 1 == PS1, 2 == PS2 */
STATIC void pushfile(void);
static int preadfd(void);
#ifdef mkinit
INCLUDE <stdio.h>
INCLUDE "input.h"
INCLUDE "error.h"
INIT {
extern char basebuf[];
basepf.nextc = basepf.buf = basebuf;
}
@ -180,35 +173,40 @@ static int
preadfd(void)
{
int nr;
parsenextc = parsefile->buf;
char *buf = parsefile->buf;
parsenextc = buf;
#if !defined(NO_HISTORY)
if (el != NULL && gotwinch) {
gotwinch = 0;
el_resize(el);
}
#endif
retry:
#ifndef NO_HISTORY
#ifndef SMALL
if (parsefile->fd == 0 && el) {
const char *rl_cp;
static const char *rl_cp;
static int el_len;
rl_cp = el_gets(el, &nr);
if (rl_cp == NULL)
nr = 0;
rl_cp = el_gets(el, &el_len);
if (rl_cp == NULL)
nr = el_len == 0 ? 0 : -1;
else {
/* XXX - BUFSIZE should redesign so not necessary */
(void) strcpy(parsenextc, rl_cp);
nr = el_len;
if (nr > BUFSIZ - 8)
nr = BUFSIZ - 8;
memcpy(buf, rl_cp, nr);
if (nr != el_len) {
el_len -= nr;
rl_cp += nr;
} else
rl_cp = 0;
}
} else
#endif
nr = read(parsefile->fd, parsenextc, BUFSIZ - 1);
nr = read(parsefile->fd, buf, BUFSIZ - 8);
if (nr <= 0) {
if (nr < 0) {
if (errno == EINTR)
goto retry;
#ifdef EWOULDBLOCK
if (parsefile->fd == 0 && errno == EWOULDBLOCK) {
int flags = fcntl(0, F_GETFL, 0);
if (flags >= 0 && flags & O_NONBLOCK) {
@ -219,7 +217,6 @@ retry:
}
}
}
#endif /* EWOULDBLOCK */
}
nr = -1;
}
@ -232,7 +229,7 @@ retry:
* 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.
* 3) If the is more stuff in this buffer, use it else call read to fill it.
* 4) Process input up to the next newline, deleting nul characters.
*/
@ -241,7 +238,9 @@ preadbuffer(void)
{
char *p, *q;
int more;
#ifndef SMALL
int something;
#endif
char savec;
if (parsefile->strpush) {
@ -265,7 +264,9 @@ again:
q = p = parsenextc;
/* delete nul characters */
#ifndef SMALL
something = 0;
#endif
for (more = 1; more;) {
switch (*p) {
case '\0':
@ -282,7 +283,9 @@ again:
break;
default:
#ifndef SMALL
something = 1;
#endif
break;
}
@ -300,11 +303,11 @@ check:
savec = *q;
*q = '\0';
#if !defined(NO_HISTORY)
#ifndef SMALL
if (parsefile->fd == 0 && hist && something) {
HistEvent he;
INTOFF;
history(hist, &he, whichprompt == 1 ? H_ENTER : H_ADD,
history(hist, &he, whichprompt == 1? H_ENTER : H_APPEND,
parsenextc);
INTON;
}
@ -342,7 +345,7 @@ pushstring(char *s, int len, void *ap)
struct strpush *sp;
INTOFF;
/*dbgprintf("*** calling pushstring: %s, %d\n", s, len);*/
/*debugprintf("*** calling pushstring: %s, %d\n", s, len);*/
if (parsefile->strpush) {
sp = ckmalloc(sizeof (struct strpush));
sp->prev = parsefile->strpush;
@ -360,7 +363,7 @@ pushstring(char *s, int len, void *ap)
INTON;
}
static void
void
popstring(void)
{
struct strpush *sp = parsefile->strpush;
@ -369,7 +372,7 @@ popstring(void)
parsenextc = sp->prevstring;
parsenleft = sp->prevnleft;
parselleft = sp->prevlleft;
/*dbgprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
/*debugprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/
if (sp->ap)
sp->ap->flag &= ~ALIASINUSE;
parsefile->strpush = sp->prev;
@ -384,27 +387,32 @@ popstring(void)
*/
void
setinputfile(char *fname, int push)
setinputfile(const char *fname, int push)
{
unsigned char magic[4];
int fd;
int fd2;
struct stat statbuf;
int saved_errno;
INTOFF;
if ((fd = open(fname, O_RDONLY)) < 0)
error("Can't open %s: %s", fname, strerror(errno));
if (fstat(fd, &statbuf) < 0) {
saved_errno = errno;
close(fd);
error("Can't stat %s: %s", fname, strerror(saved_errno));
}
if (!S_ISREG(statbuf.st_mode)) {
close(fd);
error("Can't open %s: %s", fname, strerror(ENOEXEC));
error("Can't open %s", fname);
/* Since the message "Syntax error: "(" unexpected" is not very
* helpful, we check if the file starts with the ELF magic to
* avoid that message. The first lseek tries to make sure that
* we can later rewind the file.
*/
if (lseek(fd, 0, SEEK_SET) == 0) {
if (read(fd, magic, 4) == 4) {
if (memcmp(magic, "\177ELF", 4) == 0)
error("Cannot execute ELF binary %s", fname);
}
if (lseek(fd, 0, SEEK_SET) != 0)
error("Cannot rewind the file %s", fname);
}
if (fd < 10) {
fd2 = fcntl(fd, F_DUPFD, 10);
fd2 = copyfd(fd, 10, 0);
close(fd);
if (fd2 < 0)
error("Out of file descriptors");
@ -423,7 +431,7 @@ setinputfile(char *fname, int push)
void
setinputfd(int fd, int push)
{
(void)fcntl(fd, F_SETFD, FD_CLOEXEC);
(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
if (push) {
pushfile();
parsefile->buf = ckmalloc(BUFSIZ);
@ -518,18 +526,25 @@ popallfiles(void)
/*
* Close the file(s) that the shell is reading commands from. Called
* after a fork is done.
*
* Takes one arg, vfork, which tells it to not modify its global vars
* as it is still running in the parent.
*
* This code is (probably) unnecessary as the 'close on exec' flag is
* set and should be enough. In the vfork case it is definitely wrong
* to close the fds as another fork() may be done later to feed data
* from a 'here' document into a pipe and we don't want to close the
* pipe!
*/
void
closescript(void)
closescript(int vforked)
{
if (vforked)
return;
popallfiles();
if (parsefile->fd > 0) {
close(parsefile->fd);
parsefile->fd = 0;
}
}
/*
* $PchId: input.c,v 1.7 2006/05/29 13:09:38 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: input.h,v 1.15 2003/08/07 09:05:33 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 */
@ -50,15 +51,12 @@ int pgetc(void);
int preadbuffer(void);
void pungetc(void);
void pushstring(char *, int, void *);
void setinputfile(char *, int);
void popstring(void);
void setinputfile(const char *, int);
void setinputfd(int, int);
void setinputstring(char *, int);
void popfile(void);
void popallfiles(void);
void closescript(void);
void closescript(int);
#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer())
/*
* $PchId: input.h,v 1.3 2006/03/30 13:49:37 philip Exp $
*/

1527
bin/sh/jobs.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
/* $NetBSD: jobs.h,v 1.20 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,15 +32,24 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
#include "output.h"
/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */
#define FORK_FG 0
#define FORK_BG 1
#define FORK_NOJOB 2
#include <signal.h> /* for sig_atomic_t */
/* mode flags for showjob(s) */
#define SHOW_PGID 0x01 /* only show pgid - for jobs -p */
#define SHOW_MULTILINE 0x02 /* one line per process */
#define SHOW_PID 0x04 /* include process pid */
#define SHOW_CHANGED 0x08 /* only jobs whose state has changed */
#define SHOW_SIGNALLED 0x10 /* only if stopped/exited on signal */
#define SHOW_ISSIG 0x20 /* job was signalled */
#define SHOW_NO_FREE 0x40 /* do not free job */
/*
* A job structure contains information about a job. A job is either a
@ -46,57 +57,45 @@
* latter case, pidlist will be non-NULL, and will point to a -1 terminated
* array of pids.
*/
#define MAXCMDTEXT 200
struct procstat {
pid_t pid; /* process id */
int status; /* status flags (defined above) */
char *cmd; /* text of command being run */
pid_t pid; /* process id */
int status; /* last process status from wait() */
char cmd[MAXCMDTEXT];/* text of command being run */
};
/* states */
#define JOBSTOPPED 1 /* all procs are stopped */
#define JOBDONE 2 /* all procs are completed */
struct job {
struct procstat ps0; /* status of process */
struct procstat *ps; /* status or processes when more than one */
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 */
int nprocs; /* number of processes */
pid_t pgrp; /* process group of this job */
char state;
#define JOBRUNNING 0 /* at least one proc running */
#define JOBSTOPPED 1 /* all procs are stopped */
#define JOBDONE 2 /* all procs are completed */
char used; /* true if this entry is in used */
char changed; /* true if status has changed */
#if JOBS
char jobctl; /* job running under job control */
struct job *next; /* job used after this one */
char jobctl; /* job running under job control */
int prev_job; /* previous job index */
#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? */
void setjobctl(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 **);
void showjobs(struct output *, int);
struct job *makejob(union node *, int);
pid_t forkshell(struct job *, union node *, int);
int waitforjob(struct job *, int *);
int forkshell(struct job *, union node *, int);
void forkchild(struct job *, union node *, int, int);
int forkparent(struct job *, union node *, int, pid_t);
int waitforjob(struct job *);
int stoppedjobs(void);
char *commandtext(union node *);
void commandtext(struct procstat *, union node *);
int getjobpgrp(const char *);
#if ! JOBS
#define setjobctl(on) /* do nothing */
#endif
/*
* $PchId: jobs.h,v 1.4 2006/03/30 12:07:24 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: machdep.h,v 1.11 2003/08/07 09:05:33 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,11 +15,7 @@
* 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
* 3. 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.
*
@ -41,15 +39,9 @@
* in some way. The following macro will get this right on many machines.
*/
#ifndef ALIGN
union align {
int i;
char *cp;
};
#define ALIGN(nbytes) (((nbytes) + sizeof(union align) - 1) & ~(sizeof(union align) - 1))
#endif
#define SHELL_SIZE (sizeof(union {int i; char *cp; double d; }) - 1)
/*
* $PchId: machdep.h,v 1.2 2001/05/15 16:36:26 philip Exp $
* It appears that grabstackstr() will barf with such alignments
* because stalloc() will return a string allocated in a new stackblock.
*/
#define SHELL_ALIGN(nbytes) (((nbytes) + SHELL_SIZE) & ~SHELL_SIZE)

View file

@ -1,3 +1,5 @@
/* $NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,19 +32,21 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)mail.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: mail.c,v 1.16 2003/08/07 09:05:33 agc Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__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?)
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "shell.h"
#include "exec.h" /* defines padvance() */
@ -51,9 +55,6 @@ __FBSDID("$FreeBSD: src/bin/sh/mail.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
#include "memalloc.h"
#include "error.h"
#include "mail.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#define MAXMBOXES 10
@ -74,7 +75,7 @@ void
chkmail(int silent)
{
int i;
char *mpath;
const char *mpath;
char *p;
char *q;
struct stackmark smark;
@ -85,7 +86,7 @@ chkmail(int silent)
if (nmboxes == 0)
return;
setstackmark(&smark);
mpath = mpathset()? mpathval() : mailval();
mpath = mpathset() ? mpathval() : mailval();
for (i = 0 ; i < nmboxes ; i++) {
p = padvance(&mpath, nullstr);
if (p == NULL)
@ -100,7 +101,7 @@ chkmail(int silent)
if (stat(p, &statb) < 0)
statb.st_mtime = 0;
if (statb.st_mtime > mailtime[i] && ! silent) {
out2str(pathopt? pathopt : "you have mail");
out2str(pathopt ? pathopt : "you have mail");
out2c('\n');
}
mailtime[i] = statb.st_mtime;
@ -108,7 +109,7 @@ chkmail(int silent)
if (stat(p, &statb) < 0)
statb.st_size = 0;
if (statb.st_size > mailtime[i] && ! silent) {
out2str(pathopt? pathopt : "you have mail");
out2str(pathopt ? pathopt : "you have mail");
out2c('\n');
}
mailtime[i] = statb.st_size;
@ -117,7 +118,3 @@ chkmail(int silent)
nmboxes = i;
popstackmark(&smark);
}
/*
* $PchId: mail.c,v 1.5 2006/05/22 12:02:37 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: mail.h,v 1.10 2003/08/07 09:05:34 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,11 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
void chkmail(int);
/*
* $PchId: mail.h,v 1.3 2006/03/30 11:53:44 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: main.c,v 1.57 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,34 +32,35 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
static char const copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
__COPYRIGHT("@(#) Copyright (c) 1991, 1993\
The Regents of the University of California. All rights reserved.");
#endif /* not lint */
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95";
static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
#else
__RCSID("$NetBSD: main.c,v 1.57 2011/06/18 21:18:46 christos Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
*/
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <locale.h>
#include <errno.h>
#include <fcntl.h>
#include "shell.h"
#include "main.h"
#include "mail.h"
#include "options.h"
#include "builtins.h"
#include "output.h"
#include "parser.h"
#include "nodes.h"
@ -74,13 +77,20 @@ __FBSDID("$FreeBSD: src/bin/sh/main.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
#include "mystring.h"
#include "exec.h"
#include "cd.h"
#include "builtins.h"
#define PROFILE 0
int rootpid;
int rootshell;
int posix;
#if PROFILE
short profile_buf[16384];
extern int etext();
#endif
STATIC void read_profile(char *);
STATIC void read_profile(const char *);
STATIC char *find_dot_file(char *);
int main(int, char **);
/*
* Main routine. We initialize things, parse the arguments, execute
@ -91,14 +101,19 @@ STATIC char *find_dot_file(char *);
*/
int
main(int argc, char *argv[])
main(int argc, char **argv)
{
struct jmploc jmploc;
struct stackmark smark;
volatile int state;
char *shinit;
(void) setlocale(LC_ALL, "");
setlocale(LC_ALL, "");
posix = getenv("POSIXLY_CORRECT") != NULL;
#if PROFILE
monitor(4, etext, profile_buf, sizeof profile_buf, 50);
#endif
state = 0;
if (setjmp(jmploc.loc)) {
/*
@ -127,11 +142,15 @@ main(int argc, char *argv[])
}
if (exception != EXSHELLPROC) {
if (state == 0 || iflag == 0 || ! rootshell)
exitshell(exitstatus);
if (state == 0 || iflag == 0 || ! rootshell)
exitshell(exitstatus);
}
reset();
if (exception == EXINT) {
if (exception == EXINT
#if ATTY
&& (! attyset() || equal(termval(), "emacs"))
#endif
) {
out2c('\n');
flushout(&errout);
}
@ -147,30 +166,30 @@ main(int argc, char *argv[])
goto state4;
}
handler = &jmploc;
#if DEBUG
#ifdef DEBUG
#if DEBUG == 2
debug = 1;
#endif
opentrace();
trputs("Shell args: "); trargs(argv);
#endif
rootpid = getpid();
rootshell = 1;
init();
initpwd();
setstackmark(&smark);
procargs(argc, argv);
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 (privileged == 0)
read_profile(".profile");
else
read_profile("/etc/suid_profile");
read_profile(".profile");
}
state2:
state = 3;
if (!privileged && iflag) {
if ((iflag || !posix) &&
getuid() == geteuid() && getgid() == getegid()) {
if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
state = 3;
read_profile(shinit);
@ -178,16 +197,33 @@ state2:
}
state3:
state = 4;
if (minusc) {
evalstring(minusc);
if (sflag == 0 || minusc) {
static int sigs[] = {
SIGINT, SIGQUIT, SIGHUP,
#ifdef SIGTSTP
SIGTSTP,
#endif
SIGPIPE
};
#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
size_t i;
for (i = 0; i < SIGSSIZE; i++)
setsignal(sigs[i], 0);
}
if (minusc)
evalstring(minusc, 0);
if (sflag || minusc == NULL) {
state4: /* XXX ??? - why isn't this before the "if" statement */
cmdloop(1);
}
#if PROFILE
monitor(0);
#endif
exitshell(exitstatus);
/*NOTREACHED*/
return 0;
/* NOTREACHED */
}
@ -210,11 +246,11 @@ cmdloop(int top)
if (pendingsigs)
dotrap();
inter = 0;
if (iflag && top) {
inter++;
showjobs(1, 0, 0);
if (iflag == 1 && top) {
inter = 1;
showjobs(out2, SHOW_CHANGED);
chkmail(0);
flushout(&output);
flushout(&errout);
}
n = parsecmd(inter);
/* showtree(n); DEBUG */
@ -249,9 +285,11 @@ cmdloop(int top)
*/
STATIC void
read_profile(char *name)
read_profile(const char *name)
{
int fd;
int xflag_set = 0;
int vflag_set = 0;
INTOFF;
if ((fd = open(name, O_RDONLY)) >= 0)
@ -259,7 +297,20 @@ read_profile(char *name)
INTON;
if (fd < 0)
return;
/* -q turns off -x and -v just when executing init files */
if (qflag) {
if (xflag)
xflag = 0, xflag_set = 1;
if (vflag)
vflag = 0, vflag_set = 1;
}
cmdloop(0);
if (qflag) {
if (xflag_set)
xflag = 1;
if (vflag_set)
vflag = 1;
}
popfile();
}
@ -278,7 +329,7 @@ readcmdfile(char *name)
if ((fd = open(name, O_RDONLY)) >= 0)
setinputfd(fd, 1);
else
error("Can't open %s: %s", name, strerror(errno));
error("Can't open %s", name);
INTON;
cmdloop(0);
popfile();
@ -295,40 +346,46 @@ readcmdfile(char *name)
STATIC char *
find_dot_file(char *basename)
{
static char localname[FILENAME_MAX+1];
char *fullname;
char *path = pathval();
const char *path = pathval();
struct stat statb;
/* don't try this for absolute or relative paths */
if( strchr(basename, '/'))
if (strchr(basename, '/'))
return basename;
while ((fullname = padvance(&path, basename)) != NULL) {
strcpy(localname, fullname);
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
/*
* Don't bother freeing here, since it will
* be freed by the caller.
*/
return fullname;
}
stunalloc(fullname);
if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
return localname;
}
return basename;
/* not found in the PATH */
error("%s: not found", basename);
/* NOTREACHED */
}
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 */
char *fullname = find_dot_file(argv[1]);
char *fullname;
struct stackmark smark;
setstackmark(&smark);
fullname = find_dot_file(argv[1]);
setinputfile(fullname, 1);
commandname = fullname;
cmdloop(0);
popfile();
popstackmark(&smark);
}
return exitstatus;
}
@ -337,19 +394,10 @@ dotcmd(int argc, 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;
/* NOTREACHED */
}
/*
* $PchId: main.c,v 1.5 2006/05/22 12:03:02 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: main.h,v 1.11 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 */
@ -38,9 +39,3 @@ extern int rootshell; /* true if we aren't a child of the main shell */
void readcmdfile(char *);
void cmdloop(int);
int dotcmd(int, char **);
int exitcmd(int, char **);
/*
* $PchId: main.h,v 1.3 2006/03/30 11:43:59 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,36 +32,36 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: memalloc.c,v 1.29 2008/02/15 17:26:06 matt Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/memalloc.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
*/
#include <stdlib.h>
#include <unistd.h>
#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 <stdlib.h>
#include <unistd.h>
/*
* Like malloc, but returns an error when out of space.
*/
pointer
ckmalloc(int nbytes)
ckmalloc(size_t nbytes)
{
pointer p;
if ((p = malloc(nbytes)) == NULL)
p = malloc(nbytes);
if (p == NULL)
error("Out of space");
return p;
}
@ -72,7 +74,8 @@ ckmalloc(int nbytes)
pointer
ckrealloc(pointer p, int nbytes)
{
if ((p = realloc(p, nbytes)) == NULL)
p = realloc(p, nbytes);
if (p == NULL)
error("Out of space");
return p;
}
@ -98,56 +101,46 @@ savestr(const char *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 496 was chosen because with 16-byte alignment the total size
* for the allocated block is 512.
* The size 504 was chosen because the Ultrix malloc handles that size
* well.
*/
#define MINSIZE 496 /* minimum size of a block. */
#define MINSIZE 504 /* minimum size of a block */
struct stack_block {
struct stack_block *prev;
/* Data follows */
char space[MINSIZE];
};
#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
STATIC struct stack_block *stackp;
STATIC struct stackmark *markp;
char *stacknxt;
int stacknleft;
struct stack_block stackbase;
struct stack_block *stackp = &stackbase;
struct stackmark *markp;
char *stacknxt = stackbase.space;
int stacknleft = MINSIZE;
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(int nbytes)
{
char *p;
nbytes = ALIGN(nbytes);
if (nbytes > stacknleft)
stnewblock(nbytes);
nbytes = SHELL_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;
}
p = stacknxt;
stacknxt += nbytes;
stacknleft -= nbytes;
@ -159,7 +152,7 @@ void
stunalloc(pointer p)
{
if (p == NULL) { /*DEBUG */
write(STDERR_FILENO, "stunalloc\n", 10);
write(2, "stunalloc\n", 10);
abort();
}
stacknleft += stacknxt - (char *)p;
@ -210,32 +203,27 @@ popstackmark(struct stackmark *mark)
void
growstackblock(void)
{
char *p;
int newlen;
char *oldspace;
int oldlen;
struct stack_block *sp;
struct stack_block *oldstackp;
struct stackmark *xmark;
int newlen = SHELL_ALIGN(stacknleft * 2 + 100);
newlen = (stacknleft == 0) ? MINSIZE : stacknleft * 2 + 100;
newlen = ALIGN(newlen);
oldspace = stacknxt;
oldlen = stacknleft;
if (stacknxt == stackp->space && stackp != &stackbase) {
struct stack_block *oldstackp;
struct stackmark *xmark;
struct stack_block *sp;
if (stackp != NULL && stacknxt == SPACE(stackp)) {
INTOFF;
oldstackp = stackp;
stackp = oldstackp->prev;
sp = ckrealloc((pointer)oldstackp, newlen);
sp = stackp;
stackp = sp->prev;
sp = ckrealloc((pointer)sp,
sizeof(struct stack_block) - MINSIZE + newlen);
sp->prev = stackp;
stackp = sp;
stacknxt = SPACE(sp);
stacknleft = newlen - (stacknxt - (char*)sp);
stacknxt = sp->space;
stacknleft = newlen;
/*
* Stack marks pointing to the start of the old block
* must be relocated to point to the new block
* must be relocated to point to the new block
*/
xmark = markp;
while (xmark != NULL && xmark->stackp == oldstackp) {
@ -246,27 +234,26 @@ growstackblock(void)
}
INTON;
} else {
p = stalloc(newlen);
if (oldlen != 0)
memcpy(p, oldspace, oldlen);
stunalloc(p);
char *oldspace = stacknxt;
int oldlen = stacknleft;
char *p = stalloc(newlen);
(void)memcpy(p, oldspace, oldlen);
stacknxt = p; /* free the space */
stacknleft += newlen; /* we just allocated */
}
}
void
grabstackblock(int len)
{
len = ALIGN(len);
len = SHELL_ALIGN(len);
stacknxt += len;
stacknleft -= len;
}
/*
* The following routines are somewhat easier to use that the above.
* The following routines are somewhat easier to use than the above.
* The user declares a variable of type STACKSTR, which may be declared
* to be a register. The macro STARTSTACKSTR initializes things. Then
* the user uses the macro STPUTC to add characters to the string. In
@ -283,13 +270,10 @@ grabstackblock(int len)
* is space for at least one character.
*/
char *
growstackstr(void)
{
int len;
len = stackblocksize();
int len = stackblocksize();
if (herefd >= 0 && len >= 1024) {
xwrite(herefd, stackblock(), len);
sstrnleft = len - 1;
@ -300,7 +284,6 @@ growstackstr(void)
return stackblock() + len;
}
/*
* Called from CHECKSTRSPACE.
*/
@ -308,24 +291,17 @@ growstackstr(void)
char *
makestrspace(void)
{
int len;
len = stackblocksize() - sstrnleft;
int len = stackblocksize() - sstrnleft;
growstackblock();
sstrnleft = stackblocksize() - len;
return stackblock() + len;
}
void
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 $
*/
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: memalloc.h,v 1.15 2008/02/15 17:26:06 matt Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,14 +32,13 @@
* SUCH DAMAGE.
*
* @(#)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;
struct stackmark *marknext;
};
@ -46,7 +47,7 @@ extern int stacknleft;
extern int sstrnleft;
extern int herefd;
pointer ckmalloc(int);
pointer ckmalloc(size_t);
pointer ckrealloc(pointer, int);
char *savestr(const char *);
pointer stalloc(int);
@ -74,7 +75,3 @@ void ungrabstackstr(char *, char *);
#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 $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: miscbltin.c,v 1.42 2012/06/11 18:28:10 njoly Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,32 +32,28 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)miscbltin.c 8.4 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: miscbltin.c,v 1.42 2012/06/11 18:28:10 njoly Exp $");
#endif
#endif /* not lint */
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp $");
*/
/*
* Miscellaneous builtins.
* Miscelaneous builtins.
*/
#include <sys/types.h>
#include <sys/types.h> /* quad_t */
#include <sys/param.h> /* BSD4_4 */
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/select.h>
#include <time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include "shell.h"
#include "options.h"
@ -63,159 +61,148 @@ __FBSDID("$FreeBSD: src/bin/sh/miscbltin.c,v 1.30 2004/04/06 20:06:51 markm Exp
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include "builtins.h"
#include "mystring.h"
#undef rflag
#undef eflag
/*
* The read builtin. The -r option causes backslashes to be treated like
* ordinary characters.
* The read builtin.
* Backslahes escape the next char unless -r is specified.
*
* This uses unbuffered input, which may be avoidable in some cases.
*
* Note that if IFS=' :' then read x y should work so that:
* 'a b' x='a', y='b'
* ' a b ' x='a', y='b'
* ':b' x='', y='b'
* ':' x='', y=''
* '::' x='', y=''
* ': :' x='', y=''
* ':::' x='', y='::'
* ':b c:' x='', y='b c:'
*/
int
readcmd(int argc __unused, char **argv __unused)
readcmd(int argc, char **argv)
{
char **ap;
int backslash;
char c;
int rflag;
char *prompt;
char *ifs;
const char *ifs;
char *p;
int startword;
int status;
int i;
struct timeval tv;
char *tvptr;
#ifndef __minix
fd_set ifds;
struct termios told, tnew;
int tsaved;
#endif
int is_ifs;
int saveall = 0;
rflag = 0;
prompt = NULL;
tv.tv_sec = -1;
tv.tv_usec = 0;
while ((i = nextopt("erp:t:")) != '\0') {
switch(i) {
case 'p':
prompt = shoptarg;
break;
case 'e':
break;
case 'r':
while ((i = nextopt("p:r")) != '\0') {
if (i == 'p')
prompt = optionarg;
else
rflag = 1;
break;
case 't':
tv.tv_sec = strtol(shoptarg, &tvptr, 0);
if (tvptr == shoptarg)
error("timeout value");
switch(*tvptr) {
case 0:
case 's':
break;
case 'h':
tv.tv_sec *= 60;
/* FALLTHROUGH */
case 'm':
tv.tv_sec *= 60;
break;
default:
error("timeout unit");
}
break;
}
}
if (prompt && isatty(0)) {
out2str(prompt);
flushall();
}
if (*(ap = argptr) == NULL)
error("arg count");
if ((ifs = bltinlookup("IFS", 1)) == NULL)
ifs = 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
}
if ((ifs = bltinlookup("IFS", 1)) == NULL)
ifs = " \t\n";
status = 0;
startword = 1;
backslash = 0;
startword = 2;
STARTSTACKSTR(p);
for (;;) {
if (read(STDIN_FILENO, &c, 1) != 1) {
if (read(0, &c, 1) != 1) {
status = 1;
break;
}
if (c == '\0')
continue;
if (backslash) {
backslash = 0;
if (c == '\\' && !rflag) {
if (read(0, &c, 1) != 1) {
status = 1;
break;
}
if (c != '\n')
STPUTC(c, p);
continue;
}
if (!rflag && c == '\\') {
backslash++;
continue;
}
if (c == '\n')
break;
if (startword && *ifs == ' ' && strchr(ifs, c)) {
if (strchr(ifs, c))
is_ifs = strchr(" \t\n", c) ? 1 : 2;
else
is_ifs = 0;
if (startword != 0) {
if (is_ifs == 1) {
/* Ignore leading IFS whitespace */
if (saveall)
STPUTC(c, p);
continue;
}
if (is_ifs == 2 && startword == 1) {
/* Only one non-whitespace IFS per word */
startword = 2;
if (saveall)
STPUTC(c, p);
continue;
}
}
if (is_ifs == 0) {
/* append this character to the current variable */
startword = 0;
if (saveall)
/* Not just a spare terminator */
saveall++;
STPUTC(c, p);
continue;
}
startword = 0;
if (backslash && c == '\\') {
if (read(STDIN_FILENO, &c, 1) != 1) {
status = 1;
break;
}
STPUTC(c, p);
} else if (ap[1] != NULL && strchr(ifs, c) != NULL) {
STACKSTRNUL(p);
setvar(*ap, stackblock(), 0);
ap++;
startword = 1;
STARTSTACKSTR(p);
} else {
/* end of variable... */
startword = is_ifs;
if (ap[1] == NULL) {
/* Last variable needs all IFS chars */
saveall++;
STPUTC(c, p);
continue;
}
STACKSTRNUL(p);
setvar(*ap, stackblock(), 0);
ap++;
STARTSTACKSTR(p);
}
STACKSTRNUL(p);
/* Remove trailing IFS chars */
for (; stackblock() <= --p; *p = 0) {
if (!strchr(ifs, *p))
break;
if (strchr(" \t\n", *p))
/* Always remove whitespace */
continue;
if (saveall > 1)
/* Don't remove non-whitespace unless it was naked */
break;
}
setvar(*ap, stackblock(), 0);
/* Set any remaining args to "" */
while (*++ap != NULL)
setvar(*ap, nullstr, 0);
return status;
@ -224,7 +211,7 @@ readcmd(int argc __unused, char **argv __unused)
int
umaskcmd(int argc __unused, char **argv)
umaskcmd(int argc, char **argv)
{
char *ap;
int mask;
@ -276,7 +263,7 @@ umaskcmd(int argc __unused, char **argv)
out1fmt("%.4o\n", mask);
}
} else {
if (isdigit(*ap)) {
if (isdigit((unsigned char)*ap)) {
mask = 0;
do {
if (*ap >= '8' || *ap < '0')
@ -286,44 +273,23 @@ umaskcmd(int argc __unused, char **argv)
umask(mask);
} else {
void *set;
if ((set = setmode (ap)) == 0)
error("Illegal number: %s", ap);
mask = getmode (set, ~mask & 0777);
INTOFF;
if ((set = setmode(ap)) != 0) {
mask = getmode(set, ~mask & 0777);
ckfree(set);
}
INTON;
if (!set)
error("Cannot set mode `%s' (%s)", ap,
strerror(errno));
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
*
@ -336,7 +302,7 @@ const struct rlimit *rlp;
struct limits {
const char *name;
const char *units;
const char *unit;
int cmd;
int factor; /* multiply by to get rlim_{cur,max} values */
char option;
@ -344,49 +310,52 @@ struct limits {
static const struct limits limits[] = {
#ifdef RLIMIT_CPU
{ "cpu time", "seconds", RLIMIT_CPU, 1, 't' },
{ "time", "seconds", RLIMIT_CPU, 1, 't' },
#endif
#ifdef RLIMIT_FSIZE
{ "file size", "512-blocks", RLIMIT_FSIZE, 512, 'f' },
{ "file", "blocks", RLIMIT_FSIZE, 512, 'f' },
#endif
#ifdef RLIMIT_DATA
{ "data seg size", "kbytes", RLIMIT_DATA, 1024, 'd' },
{ "data", "kbytes", RLIMIT_DATA, 1024, 'd' },
#endif
#ifdef RLIMIT_STACK
{ "stack size", "kbytes", RLIMIT_STACK, 1024, 's' },
{ "stack", "kbytes", RLIMIT_STACK, 1024, 's' },
#endif
#ifdef RLIMIT_CORE
{ "core file size", "512-blocks", RLIMIT_CORE, 512, 'c' },
{ "coredump", "blocks", RLIMIT_CORE, 512, 'c' },
#endif
#ifdef RLIMIT_RSS
{ "max memory size", "kbytes", RLIMIT_RSS, 1024, 'm' },
{ "memory", "kbytes", RLIMIT_RSS, 1024, 'm' },
#endif
#ifdef RLIMIT_MEMLOCK
{ "locked memory", "kbytes", RLIMIT_MEMLOCK, 1024, 'l' },
{ "locked memory","kbytes", RLIMIT_MEMLOCK, 1024, 'l' },
#endif
#ifdef RLIMIT_NTHR
{ "thread", "threads", RLIMIT_NTHR, 1, 'r' },
#endif
#ifdef RLIMIT_NPROC
{ "max user processes", (char *)0, RLIMIT_NPROC, 1, 'u' },
{ "process", "processes", RLIMIT_NPROC, 1, 'p' },
#endif
#ifdef RLIMIT_NOFILE
{ "open files", (char *)0, RLIMIT_NOFILE, 1, 'n' },
{ "nofiles", "descriptors", RLIMIT_NOFILE, 1, 'n' },
#endif
#ifdef RLIMIT_VMEM
{ "virtual mem size", "kbytes", RLIMIT_VMEM, 1024, 'v' },
{ "vmemory", "kbytes", RLIMIT_VMEM, 1024, 'v' },
#endif
#ifdef RLIMIT_SWAP
{ "swap limit", "kbytes", RLIMIT_SWAP, 1024, 'w' },
{ "swap", "kbytes", RLIMIT_SWAP, 1024, 'w' },
#endif
#ifdef RLIMIT_SBSIZE
{ "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' },
{ "sbsize", "bytes", RLIMIT_SBSIZE, 1, 'b' },
#endif
{ (char *) 0, (char *)0, 0, 0, '\0' }
{ NULL, NULL, 0, 0, '\0' }
};
int
ulimitcmd(int argc __unused, char **argv __unused)
ulimitcmd(int argc, char **argv)
{
int c;
intmax_t val = 0;
rlim_t val = 0;
enum { SOFT = 0x1, HARD = 0x2 }
how = SOFT | HARD;
const struct limits *l;
@ -395,7 +364,7 @@ ulimitcmd(int argc __unused, char **argv __unused)
struct rlimit limit;
what = 'f';
while ((optc = nextopt("HSatfdsmcnuvlb")) != '\0')
while ((optc = nextopt("HSabtfdscmlrpnv")) != '\0')
switch (optc) {
case 'H':
how = HARD;
@ -424,56 +393,48 @@ ulimitcmd(int argc __unused, char **argv __unused)
if (strcmp(p, "unlimited") == 0)
val = RLIM_INFINITY;
else {
val = 0;
val = (rlim_t) 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));
for (l = limits; l->name; l++) {
getrlimit(l->cmd, &limit);
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);
out1fmt("%-13s (-%c %-11s) ", l->name, l->option,
l->unit);
if (val == RLIM_INFINITY)
out1fmt("unlimited\n");
else
{
val /= l->factor;
out1fmt("%jd\n", (intmax_t)val);
#ifdef BSD4_4
out1fmt("%lld\n", (long long) val);
#else
out1fmt("%ld\n", (long) val);
#endif
}
}
return 0;
}
if (getrlimit(l->cmd, &limit) < 0)
error("can't get limit: %s", strerror(errno));
getrlimit(l->cmd, &limit);
if (set) {
if (how & SOFT)
limit.rlim_cur = val;
if (how & HARD)
limit.rlim_max = val;
if (how & SOFT)
limit.rlim_cur = val;
if (setrlimit(l->cmd, &limit) < 0)
error("bad limit: %s", strerror(errno));
error("error setting limit (%s)", strerror(errno));
} else {
if (how & SOFT)
val = limit.rlim_cur;
@ -485,12 +446,12 @@ ulimitcmd(int argc __unused, char **argv __unused)
else
{
val /= l->factor;
out1fmt("%jd\n", (intmax_t)val);
#ifdef BSD4_4
out1fmt("%lld\n", (long long) val);
#else
out1fmt("%ld\n", (long) val);
#endif
}
}
return 0;
}
/*
* $PchId: miscbltin.c,v 1.7 2006/05/23 11:59:08 philip Exp $
*/

31
bin/sh/miscbltin.h Normal file
View file

@ -0,0 +1,31 @@
/* $NetBSD: miscbltin.h,v 1.3 2003/08/21 17:57:53 christos Exp $ */
/*
* Copyright (c) 1997 Christos Zoulas. 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
*/
int readcmd(int, char **);
int umaskcmd(int, char **);
int ulimitcmd(int, char **);

128
minix/commands/ash/mkbuiltins.sh → bin/sh/mkbuiltins Executable file → Normal file
View file

@ -1,4 +1,5 @@
#!/bin/sh -
# $NetBSD: mkbuiltins,v 1.22 2009/10/06 19:56:58 apb Exp $
#
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
@ -14,7 +15,7 @@
# 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
# 3. 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.
#
@ -31,68 +32,105 @@
# SUCH DAMAGE.
#
# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95
# $FreeBSD: src/bin/sh/mkbuiltins,v 1.13 2004/04/06 20:06:51 markm Exp $
#temp=`/usr/bin/mktemp -t ka`
temp=/tmp/mkb$$
havehist=1
if [ "X$1" = "X-h" ]; then
if [ x"$1" = x"-h" ]; then
havehist=0
shift
fi
shell=$1
builtins=$2
objdir=$3
havejobs=0
if [ "X$1" = "X-j" ]; then
havejobs=0
shift
elif grep '^#define[ ]*JOBS[ ]*1' $2 > /dev/null
then havejobs=1
if grep '^#define JOBS[ ]*1' ${shell} > /dev/null
then
havejobs=1
fi
objdir=$1
exec > ${objdir}/builtins.c
cat <<\!
/*
exec <$builtins 3> ${objdir}/builtins.c 4> ${objdir}/builtins.h
echo '/*
* This file was generated by the mkbuiltins program.
*/
#include <stdlib.h>
#include "shell.h"
#include "builtins.h"
!
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[]) (int, char **) = {'
awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp
echo '};
const struct builtincmd builtincmd[] = {
' >&3
const struct builtincmd builtincmd[] = {'
awk '{ for (i = 2 ; i <= NF ; i++) {
printf "\t{ \"%s\", %d },\n", $i, NR-1
}}' $temp
echo ' { NULL, 0 }
};'
exec > ${objdir}/builtins.h
cat <<\!
/*
echo '/*
* This file was generated by the mkbuiltins program.
*/
!
tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp |
awk '{ printf "#define %s %d\n", $1, NR-1}'
echo '
#include <sys/cdefs.h>
struct builtincmd {
char *name;
int code;
const char *name;
int (*builtin)(int, char **);
};
extern int (*const builtinfunc[]) (int, char **);
extern const struct builtincmd builtincmd[];'
awk '{ printf "int %s (int, char **);\n", $1 }' < $temp
rm -f $temp
extern const struct builtincmd builtincmd[];
extern const struct builtincmd splbltincmd[];
#
# $PchId: mkbuiltins,v 1.6 2006/05/22 12:42:58 philip Exp $
' >&4
specials=
while read line
do
set -- $line
[ -z "$1" ] && continue
case "$1" in
\#if*|\#def*|\#end*)
echo $line >&3
echo $line >&4
continue
;;
\#*)
continue
;;
esac
func=$1
shift
[ x"$1" = x'-j' ] && {
[ $havejobs = 0 ] && continue
shift
}
[ x"$1" = x'-h' ] && {
[ $havehist = 0 ] && continue
shift
}
echo 'int '"$func"'(int, char **);' >&4
while
[ $# != 0 ] && [ x"$1" != x'#' ]
do
[ x"$1" = x'-s' ] && {
specials="$specials $2 $func"
shift 2
continue;
}
[ x"$1" = x'-u' ] && shift
echo ' { "'$1'", '"$func"' },' >&3
shift
done
done
echo ' { 0, 0 },' >&3
echo '};' >&3
echo >&3
echo 'const struct builtincmd splbltincmd[] = {' >&3
set -- $specials
while
[ $# != 0 ]
do
echo ' { "'$1'", '"$2"' },' >&3
shift 2
done
echo ' { 0, 0 },' >&3
echo "};" >&3

170
bin/sh/mkinit.sh Executable file
View file

@ -0,0 +1,170 @@
#! /bin/sh
# $NetBSD: mkinit.sh,v 1.5 2008/10/23 20:21:57 apb Exp $
# Copyright (c) 2003 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by David Laight.
#
# 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.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
srcs="$*"
nl='
'
openparen='('
backslash='\'
includes=' "shell.h" "mystring.h" "init.h" '
defines=
decles=
event_init=
event_reset=
event_shellproc=
for src in $srcs; do
exec <$src
decnl="$nl"
while IFS=; read -r line; do
[ "$line" = x ]
case "$line " in
INIT["{ "]* ) event=init;;
RESET["{ "]* ) event=reset;;
SHELLPROC["{ "]* ) event=shellproc;;
INCLUDE[\ \ ]* )
IFS=' '
set -- $line
# ignore duplicates
[ "${includes}" != "${includes%* $2 }" ] && continue
includes="$includes$2 "
continue
;;
MKINIT\ )
# struct declaration
decles="$decles$nl"
while
read -r line
decles="${decles}${line}${nl}"
[ "$line" != "};" ]
do
:
done
decnl="$nl"
continue
;;
MKINIT["{ "]* )
# strip initialiser
def=${line#MKINIT}
comment="${def#*;}"
def="${def%;$comment}"
def="${def%%=*}"
def="${def% }"
decles="${decles}${decnl}extern${def};${comment}${nl}"
decnl=
continue
;;
\#define[\ \ ]* )
IFS=' '
set -- $line
# Ignore those with arguments
[ "$2" = "${2##*$openparen}" ] || continue
# and multiline definitions
[ "$line" = "${line%$backslash}" ] || continue
defines="${defines}#undef $2${nl}${line}${nl}"
continue
;;
* ) continue;;
esac
# code for events
ev="${nl} /* from $src: */${nl} {${nl}"
# Indent the text by an extra <tab>
while
read -r line
[ "$line" != "}" ]
do
[ -n "$line" -a "$line" = "${line###}" ] &&
line=" $line"
ev="${ev}${line}${nl}"
done
ev="${ev} }${nl}"
eval event_$event=\"\$event_$event\$ev\"
done
done
exec >init.c.tmp
echo "/*"
echo " * This file was generated by the mkinit program."
echo " */"
echo
IFS=' '
for f in $includes; do
echo "#include $f"
done
echo
echo
echo
echo "$defines"
echo
echo "$decles"
echo
echo
echo "/*"
echo " * Initialization code."
echo " */"
echo
echo "void"
echo "init(void)"
echo "{"
echo "${event_init}"
echo "}"
echo
echo
echo
echo "/*"
echo " * This routine is called when an error or an interrupt occurs in an"
echo " * interactive shell and control is returned to the main command loop."
echo " */"
echo
echo "void"
echo "reset(void)"
echo "{"
echo "${event_reset}"
echo "}"
echo
echo
echo
echo "/*"
echo " * This routine is called to initialize the shell to run a shell procedure."
echo " */"
echo
echo "void"
echo "initshellproc(void)"
echo "{"
echo "${event_shellproc}"
echo "}"
exec >&-
mv init.c.tmp init.c

214
bin/sh/mknodes.sh Executable file
View file

@ -0,0 +1,214 @@
#! /bin/sh
# $NetBSD: mknodes.sh,v 1.2 2008/04/29 06:53:00 martin Exp $
# Copyright (c) 2003 The NetBSD Foundation, Inc.
# All rights reserved.
#
# This code is derived from software contributed to The NetBSD Foundation
# by David Laight.
#
# 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.
#
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
nodetypes=$1
nodes_pat=$2
objdir="$3"
exec <$nodetypes
exec >$objdir/nodes.h.tmp
echo "/*"
echo " * This file was generated by mknodes.sh"
echo " */"
echo
tagno=0
while IFS=; read -r line; do
line="${line%%#*}"
IFS=' '
set -- $line
IFS=
[ -z "$2" ] && continue
case "$line" in
[" "]* )
IFS=' '
[ $field = 0 ] && struct_list="$struct_list $struct"
eval field_${struct}_$field=\"\$*\"
eval numfld_$struct=\$field
field=$(($field + 1))
;;
* )
define=$1
struct=$2
echo "#define $define $tagno"
tagno=$(($tagno + 1))
eval define_$struct=\"\$define_$struct \$define\"
struct_define="$struct_define $struct"
field=0
;;
esac
done
echo
IFS=' '
for struct in $struct_list; do
echo
echo
echo "struct $struct {"
field=0
while
eval line=\"\$field_${struct}_$field\"
field=$(($field + 1))
[ -n "$line" ]
do
IFS=' '
set -- $line
name=$1
case $2 in
nodeptr ) type="union node *";;
nodelist ) type="struct nodelist *";;
string ) type="char *";;
int ) type="int ";;
* ) name=; shift 2; type="$*";;
esac
echo " $type$name;"
done
echo "};"
done
echo
echo
echo "union node {"
echo " int type;"
for struct in $struct_list; do
echo " struct $struct $struct;"
done
echo "};"
echo
echo
echo "struct nodelist {"
echo " struct nodelist *next;"
echo " union node *n;"
echo "};"
echo
echo
echo "union node *copyfunc(union node *);"
echo "void freefunc(union node *);"
mv $objdir/nodes.h.tmp $objdir/nodes.h || exit 1
exec <$nodes_pat
exec >$objdir/nodes.c.tmp
echo "/*"
echo " * This file was generated by mknodes.sh"
echo " */"
echo
while IFS=; read -r line; do
IFS=' '
set -- $line
IFS=
case "$1" in
'%SIZES' )
echo "static const short nodesize[$tagno] = {"
IFS=' '
for struct in $struct_define; do
echo " SHELL_ALIGN(sizeof (struct $struct)),"
done
echo "};"
;;
'%CALCSIZE' )
echo " if (n == NULL)"
echo " return;"
echo " funcblocksize += nodesize[n->type];"
echo " switch (n->type) {"
IFS=' '
for struct in $struct_list; do
eval defines=\"\$define_$struct\"
for define in $defines; do
echo " case $define:"
done
eval field=\$numfld_$struct
while
[ $field != 0 ]
do
eval line=\"\$field_${struct}_$field\"
field=$(($field - 1))
IFS=' '
set -- $line
name=$1
cl=")"
case $2 in
nodeptr ) fn=calcsize;;
nodelist ) fn=sizenodelist;;
string ) fn="funcstringsize += strlen"
cl=") + 1";;
* ) continue;;
esac
echo " ${fn}(n->$struct.$name${cl};"
done
echo " break;"
done
echo " };"
;;
'%COPY' )
echo " if (n == NULL)"
echo " return NULL;"
echo " new = funcblock;"
echo " funcblock = (char *) funcblock + nodesize[n->type];"
echo " switch (n->type) {"
IFS=' '
for struct in $struct_list; do
eval defines=\"\$define_$struct\"
for define in $defines; do
echo " case $define:"
done
eval field=\$numfld_$struct
while
[ $field != 0 ]
do
eval line=\"\$field_${struct}_$field\"
field=$(($field - 1))
IFS=' '
set -- $line
name=$1
case $2 in
nodeptr ) fn="copynode(";;
nodelist ) fn="copynodelist(";;
string ) fn="nodesavestr(";;
int ) fn=;;
* ) continue;;
esac
f="$struct.$name"
echo " new->$f = ${fn}n->$f${fn:+)};"
done
echo " break;"
done
echo " };"
echo " new->type = n->type;"
;;
* ) echo "$line";;
esac
done
mv $objdir/nodes.c.tmp $objdir/nodes.c || exit 1

59
minix/commands/ash/mktokens.sh → bin/sh/mktokens Executable file → Normal file
View file

@ -1,4 +1,5 @@
#!/bin/sh -
# $NetBSD: mktokens,v 1.12 2008/10/25 22:18:15 apb Exp $
#
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
@ -14,7 +15,7 @@
# 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
# 3. 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.
#
@ -31,17 +32,15 @@
# SUCH DAMAGE.
#
# @(#)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)
: ${AWK:=awk}
: ${SED:=sed}
# The following is a list of tokens. The second column is nonzero if the
# token marks the end of a list. The third column is the name to print in
# error messages.
#temp=`/usr/bin/mktemp -t ka`
temp=/tmp/mkt$$
cat > $temp <<\!
cat > /tmp/ka$$ <<\!
TEOF 1 end of file
TNL 0 newline
TSEMI 0 ";"
@ -71,54 +70,26 @@ TCASE 0 "case"
TESAC 1 "esac"
TNOT 0 "!"
!
nl=`wc -l $temp`
nl=`wc -l /tmp/ka$$`
exec > token.h
i=0
while read line
do
set -$- $line
echo "#define $1 $i"
i=`expr $i + 1`
done <$temp
${AWK} '{print "#define " $1 " " NR-1}' /tmp/ka$$
echo '
/* Array indicating which tokens mark the end of a list */
const char tokendlist[] = {'
while read line
do
set -$- $line
echo " $2,"
done <$temp
${AWK} '{print "\t" $2 ","}' /tmp/ka$$
echo '};
const char *const tokname[] = {'
sed -e 's/"/\\"/g' \
${SED} -e 's/"/\\"/g' \
-e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \
$temp
/tmp/ka$$
echo '};
'
i=0
go=
sed 's/"//g' $temp |
while read line
do
set -$- $line
if [ "$1" = TIF ]
then
echo "#define KWDOFFSET $i"
echo
echo "const char *const parsekwd[] = {"
go=true
fi
if [ "$go" ]
then
echo " \"$3\","
fi
i=`expr $i + 1`
done
${SED} 's/"//g' /tmp/ka$$ | ${AWK} '
/TIF/{print "#define KWDOFFSET " NR-1; print "";
print "const char *const parsekwd[] = {"}
/TIF/,/neverfound/{print " \"" $3 "\","}'
echo ' 0
};'
rm $temp
#
# $PchId: mktokens,v 1.5 2006/05/22 12:43:35 philip Exp $
rm /tmp/ka$$

View file

@ -1,3 +1,5 @@
/* $NetBSD: myhistedit.h,v 1.11 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
@ -10,7 +12,7 @@
* 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
* 3. 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.
*
@ -27,7 +29,6 @@
* SUCH DAMAGE.
*
* @(#)myhistedit.h 8.2 (Berkeley) 5/4/95
* $FreeBSD: src/bin/sh/myhistedit.h,v 1.10 2004/04/06 20:06:51 markm Exp $
*/
#include <histedit.h>
@ -38,13 +39,8 @@ 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 $
*/
void setterm(const char *);
int inputrc(int, char **);
int not_fcnumber(char *);
int str_to_event(const char *, int);

View file

@ -1,3 +1,5 @@
/* $NetBSD: mystring.c,v 1.17 2013/04/28 17:01:28 dholland Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,15 +32,14 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)mystring.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: mystring.c,v 1.17 2013/04/28 17:01:28 dholland Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $");
*/
/*
* String functions.
@ -57,7 +58,7 @@ __FBSDID("$FreeBSD: src/bin/sh/mystring.c,v 1.13 2004/04/06 20:06:51 markm Exp $
#include "mystring.h"
char nullstr[1]; /* zero length string */
const char nullstr[1]; /* zero length string */
/*
* equal - #defined in mystring.h
@ -109,8 +110,9 @@ prefix(const char *pfx, const char *string)
int
number(const char *s)
{
if (! is_number(s))
error("Illegal number: %s", (char *)s);
error("Illegal number: %s", s);
return atoi(s);
}
@ -129,7 +131,3 @@ is_number(const char *p)
} while (*++p != '\0');
return 1;
}
/*
* $PchId: mystring.c,v 1.4 2006/05/22 12:21:53 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: mystring.h,v 1.11 2003/08/07 09:05:35 agc Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
#include <string.h>
@ -42,7 +43,3 @@ int is_number(const char *);
#define equal(s1, s2) (strcmp(s1, s2) == 0)
#define scopy(s1, s2) ((void)strcpy(s2, s1))
/*
* $PchId: mystring.h,v 1.3 2006/03/29 15:49:08 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: nodes.c.pat,v 1.13 2012/03/20 18:42:29 matt Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 <stdlib.h>
@ -41,17 +42,14 @@
#include "shell.h"
#include "nodes.h"
#include "memalloc.h"
#include "machdep.h"
#include "mystring.h"
#ifndef __minix
#include <sys/param.h>
#endif
#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 */
int funcblocksize; /* size of structures in function */
int funcstringsize; /* size of strings in node */
pointer funcblock; /* block to allocate function from */
char *funcstring; /* block to allocate strings from */
%SIZES
@ -77,7 +75,7 @@ copyfunc(union node *n)
funcstringsize = 0;
calcsize(n);
funcblock = ckmalloc(funcblocksize + funcstringsize);
funcstring = (char *)funcblock + funcblocksize;
funcstring = (char *) funcblock + funcblocksize;
return copynode(n);
}
@ -95,7 +93,7 @@ STATIC void
sizenodelist(struct nodelist *lp)
{
while (lp) {
funcblocksize += ALIGN(sizeof(struct nodelist));
funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
calcsize(lp->n);
lp = lp->next;
}
@ -122,7 +120,8 @@ copynodelist(struct nodelist *lp)
lpp = &start;
while (lp) {
*lpp = funcblock;
funcblock = (char *)funcblock + ALIGN(sizeof(struct nodelist));
funcblock = (char *) funcblock +
SHELL_ALIGN(sizeof(struct nodelist));
(*lpp)->n = copynode(lp->n);
lp = lp->next;
lpp = &(*lpp)->next;
@ -136,11 +135,11 @@ copynodelist(struct nodelist *lp)
STATIC char *
nodesavestr(char *s)
{
char *p = s;
char *q = funcstring;
register char *p = s;
register char *q = funcstring;
char *rtn = funcstring;
while ((*q++ = *p++) != '\0')
while ((*q++ = *p++) != 0)
continue;
funcstring = q;
return rtn;
@ -158,7 +157,3 @@ freefunc(union node *n)
if (n)
ckfree(n);
}
/*
* $PchId: nodes.c.pat,v 1.5 2006/05/22 12:43:57 philip Exp $
*/

View file

@ -1,4 +1,4 @@
#
# $NetBSD: nodetypes,v 1.13 2009/05/26 07:30:51 joerg Exp $
# Copyright (c) 1991, 1993
# The Regents of the University of California. All rights reserved.
#
@ -13,7 +13,7 @@
# 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
# 3. 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.
#
@ -30,7 +30,6 @@
# SUCH DAMAGE.
#
# @(#)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
@ -65,7 +64,7 @@ NPIPE npipe # a pipeline
backgnd int # set to run pipeline in background
cmdlist nodelist # the commands in the pipeline
NREDIR nredir # redirection (of a compex command)
NREDIR nredir # redirection (of a complex command)
type int
n nodeptr # the command
redirect nodeptr # list of file redirections
@ -113,10 +112,10 @@ NARG narg # represents a word
backquote nodelist # list of commands in back quotes
NTO nfile # fd> fname
NCLOBBER 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
@ -140,8 +139,5 @@ NXHERE nhere # fd<<!
doc nodeptr # input to command (NARG node)
NNOT nnot # ! command (actually pipeline)
type int
com nodeptr
#
# $PchId: nodetypes,v 1.3 2006/03/29 15:43:35 philip Exp $
type int
com nodeptr

View file

@ -1,3 +1,5 @@
/* $NetBSD: options.c,v 1.43 2012/03/20 18:42:29 matt Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,15 +32,14 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: options.c,v 1.43 2012/03/20 18:42:29 matt Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
*/
#include <signal.h>
#include <unistd.h>
@ -48,6 +49,7 @@ __FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"
#define DEFINE_OPTIONS
#include "options.h"
#undef DEFINE_OPTIONS
#include "builtins.h"
#include "nodes.h" /* for other header files */
#include "eval.h"
#include "jobs.h"
@ -58,17 +60,16 @@ __FBSDID("$FreeBSD: src/bin/sh/options.c,v 1.21 2004/04/06 20:06:51 markm Exp $"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include "builtins.h"
#if !defined(NO_HISTORY)
#ifndef SMALL
#include "myhistedit.h"
#endif
#include "show.h"
char *arg0; /* value of $0 */
struct shparam shellparam; /* current positional parameters */
char **argptr; /* argument list for builtin commands */
char *shoptarg; /* set by nextopt (like getopt) */
char *optionarg; /* set by nextopt (like getopt) */
char *optptr; /* used by nextopt */
int editable; /* isatty(0) && isatty(1) */
char *minusc; /* argument to -c option */
@ -86,33 +87,43 @@ STATIC int getopts(char *, char *, char **, char ***, char **);
void
procargs(int argc, char **argv)
{
int i;
size_t i;
argptr = argv;
if (argc > 0)
argptr++;
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 (iflag == 1 && sflag == 2)
iflag = 2;
if (mflag == 2)
mflag = iflag;
for (i = 0; i < NOPTS; i++)
if (optlist[i].val == 2)
optlist[i].val = 0;
#if DEBUG == 2
debug = 1;
#endif
arg0 = argv[0];
if (sflag == 0 && minusc == NULL) {
commandname = arg0 = *argptr++;
setinputfile(commandname, 0);
commandname = argv[0];
arg0 = *argptr++;
setinputfile(arg0, 0);
commandname = arg0;
}
/* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */
if (argptr && minusc && *argptr)
arg0 = *argptr++;
if (minusc != NULL) {
if (argptr == NULL || *argptr == NULL)
error("Bad -c option");
minusc = *argptr++;
if (*argptr != 0)
arg0 = *argptr++;
}
shellparam.p = argptr;
shellparam.reset = 1;
@ -121,9 +132,6 @@ procargs(int argc, char **argv)
shellparam.nparam++;
argptr++;
}
#ifdef __minix
if(!Eflag && !Vflag) Eflag = 1;
#endif
optschanged();
}
@ -132,7 +140,7 @@ void
optschanged(void)
{
setinteractive(iflag);
#if !defined(NO_HISTORY)
#ifndef SMALL
histedit();
#endif
setjobctl(mflag);
@ -146,6 +154,7 @@ optschanged(void)
STATIC void
options(int cmdline)
{
static char empty[] = "";
char *p;
int val;
int c;
@ -175,65 +184,62 @@ options(int cmdline)
}
while ((c = *p++) != '\0') {
if (c == 'c' && cmdline) {
char *q;
#ifdef NOHACK /* removing this code allows sh -ce 'foo' for compat */
if (*p == '\0')
#endif
q = *argptr++;
if (q == NULL || minusc != NULL)
error("Bad -c option");
minusc = q;
#ifdef NOHACK
break;
#endif
/* command is after shell args*/
minusc = empty;
} 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);
}
}
}
}
static void
set_opt_val(size_t i, int val)
{
size_t j;
int flag;
if (val && (flag = optlist[i].opt_set)) {
/* some options (eg vi/emacs) are mutually exclusive */
for (j = 0; j < NOPTS; j++)
if (optlist[j].opt_set == flag)
optlist[j].val = 0;
}
optlist[i].val = val;
#ifdef DEBUG
if (&optlist[i].val == &debug)
opentrace();
#endif
}
STATIC void
minus_o(char *name, int val)
{
int doneset, i;
size_t i;
if (name == NULL) {
if (val) {
/* "Pretty" output. */
out1str("Current option settings\n");
for (i = 0; i < NOPTS; i++)
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');
out1str("set");
for (i = 0; i < NOPTS; i++) {
out1fmt(" %co %s",
"+-"[optlist[i].val], optlist[i].name);
}
out1str("\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);
set_opt_val(i, val);
return;
}
error("Illegal option -o %s", name);
@ -244,21 +250,15 @@ minus_o(char *name, int val)
STATIC void
setoption(int flag, int val)
{
int i;
size_t i;
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;
}
set_opt_val( i, val );
return;
}
error("Illegal option -%c", flag);
/* NOTREACHED */
}
@ -269,7 +269,7 @@ INCLUDE "options.h"
SHELLPROC {
int i;
for (i = 0; i < NOPTS; i++)
for (i = 0; optlist[i].name; i++)
optlist[i].val = 0;
optschanged();
@ -288,7 +288,8 @@ setparam(char **argv)
char **ap;
int nparam;
for (nparam = 0 ; argv[nparam] ; nparam++);
for (nparam = 0 ; argv[nparam] ; nparam++)
continue;
ap = newparam = ckmalloc((nparam + 1) * sizeof *ap);
while (*argv) {
*ap++ = savestr(*argv++);
@ -307,7 +308,7 @@ setparam(char **argv)
*/
void
freeparam(struct shparam *param)
freeparam(volatile struct shparam *param)
{
char **ap;
@ -358,7 +359,7 @@ int
setcmd(int argc, char **argv)
{
if (argc == 1)
return showvarscmd(argc, argv);
return showvars(0, 0, 1);
INTOFF;
options(0);
optschanged();
@ -389,7 +390,7 @@ getoptsreset(const char *value)
int
getoptscmd(int argc, char **argv)
{
char **optbase = NULL;
char **optbase;
if (argc < 3)
error("usage: getopts optstring var [arg]");
@ -409,17 +410,16 @@ getoptscmd(int argc, char **argv)
}
STATIC int
getopts(char *optstr, char *optvar, char **optfirst, char ***optnext,
char **optptr)
getopts(char *optstr, char *optvar, char **optfirst, char ***optnext, char **optpptr)
{
char *p, *q;
char c = '?';
int done = 0;
int ind = 0;
int err = 0;
char s[10];
char s[12];
if ((p = *optptr) == NULL || *p == '\0') {
if ((p = *optpptr) == NULL || *p == '\0') {
/* Current word is done, advance */
if (*optnext == NULL)
return 1;
@ -444,10 +444,9 @@ atend:
s[0] = c;
s[1] = '\0';
err |= setvarsafe("OPTARG", s, 0);
}
else {
out1fmt("Illegal option -%c\n", c);
(void) unsetvar("OPTARG");
} else {
outfmt(&errout, "Illegal option -%c\n", c);
(void) unsetvar("OPTARG", 0);
}
c = '?';
goto bad;
@ -463,10 +462,9 @@ atend:
s[1] = '\0';
err |= setvarsafe("OPTARG", s, 0);
c = ':';
}
else {
out1fmt("No arg for -%c option\n", c);
(void) unsetvar("OPTARG");
} else {
outfmt(&errout, "No arg for -%c option\n", c);
(void) unsetvar("OPTARG", 0);
c = '?';
}
goto bad;
@ -474,11 +472,10 @@ atend:
if (p == **optnext)
(*optnext)++;
setvarsafe("OPTARG", p, 0);
err |= setvarsafe("OPTARG", p, 0);
p = NULL;
}
else
setvarsafe("OPTARG", "", 0);
} else
err |= setvarsafe("OPTARG", "", 0);
ind = *optnext - optfirst + 1;
goto out;
@ -487,7 +484,7 @@ bad:
*optnext = NULL;
p = NULL;
out:
*optptr = p;
*optpptr = p;
fmtstr(s, sizeof(s), "%d", ind);
err |= setvarsafe("OPTIND", s, VNOFUNC);
s[0] = c;
@ -495,7 +492,7 @@ out:
err |= setvarsafe(optvar, s, 0);
if (err) {
*optnext = NULL;
*optptr = NULL;
*optpptr = NULL;
flushall();
exraise(EXERROR);
}
@ -514,9 +511,10 @@ out:
*/
int
nextopt(char *optstring)
nextopt(const char *optstring)
{
char *p, *q;
char *p;
const char *q;
char c;
if ((p = optptr) == NULL || *p == '\0') {
@ -537,13 +535,9 @@ nextopt(char *optstring)
if (*++q == ':') {
if (*p == '\0' && (p = *argptr++) == NULL)
error("No arg for -%c option", c);
shoptarg = p;
optionarg = p;
p = NULL;
}
optptr = p;
return c;
}
/*
* $PchId: options.c,v 1.6 2006/05/29 13:09:12 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: options.h,v 1.20 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 {
@ -43,57 +44,74 @@ struct shparam {
};
#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 18
struct optent {
const char *name;
const char letter;
char val;
const char *name; /* for set -o <name> */
const char letter; /* set [+/-]<letter> and $- */
const char opt_set; /* mutually exclusive option set */
unsigned char val; /* value of <letter>flag */
};
/* Those marked [U] are required by posix, but have no effect! */
#ifdef DEFINE_OPTIONS
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 },
};
#define DEF_OPTS(name, letter, opt_set) {name, letter, opt_set, 0},
struct optent optlist[] = {
#else
extern struct optent optlist[NOPTS];
#define DEF_OPTS(name, letter, opt_set)
#endif
#define DEF_OPT(name,letter) DEF_OPTS(name, letter, 0)
DEF_OPT( "errexit", 'e' ) /* exit on error */
#define eflag optlist[0].val
DEF_OPT( "noglob", 'f' ) /* no pathname expansion */
#define fflag optlist[1].val
DEF_OPT( "ignoreeof", 'I' ) /* do not exit on EOF */
#define Iflag optlist[2].val
DEF_OPT( "interactive",'i' ) /* interactive shell */
#define iflag optlist[3].val
DEF_OPT( "monitor", 'm' ) /* job control */
#define mflag optlist[4].val
DEF_OPT( "noexec", 'n' ) /* [U] do not exec commands */
#define nflag optlist[5].val
DEF_OPT( "stdin", 's' ) /* read from stdin */
#define sflag optlist[6].val
DEF_OPT( "xtrace", 'x' ) /* trace after expansion */
#define xflag optlist[7].val
DEF_OPT( "verbose", 'v' ) /* trace read input */
#define vflag optlist[8].val
DEF_OPTS( "vi", 'V', 'V' ) /* vi style editing */
#define Vflag optlist[9].val
DEF_OPTS( "emacs", 'E', 'V' ) /* emacs style editing */
#define Eflag optlist[10].val
DEF_OPT( "noclobber", 'C' ) /* do not overwrite files with > */
#define Cflag optlist[11].val
DEF_OPT( "allexport", 'a' ) /* export all variables */
#define aflag optlist[12].val
DEF_OPT( "notify", 'b' ) /* [U] report completion of background jobs */
#define bflag optlist[13].val
DEF_OPT( "nounset", 'u' ) /* error expansion of unset variables */
#define uflag optlist[14].val
DEF_OPT( "quietprofile", 'q' )
#define qflag optlist[15].val
DEF_OPT( "nolog", 0 ) /* [U] no functon defs in command history */
#define nolog optlist[16].val
DEF_OPT( "cdprint", 0 ) /* always print result of cd */
#define cdprint optlist[17].val
DEF_OPT( "tabcomplete", 0 ) /* <tab> causes filename expansion */
#define tabcomplete optlist[18].val
#ifdef DEBUG
DEF_OPT( "debug", 0 ) /* enable debug prints */
#define debug optlist[19].val
#endif
#ifdef DEFINE_OPTIONS
{ 0, 0, 0, 0 },
};
#define NOPTS (sizeof optlist / sizeof optlist[0] - 1)
int sizeof_optlist = sizeof optlist;
#else
extern struct optent optlist[];
extern int sizeof_optlist;
#endif
@ -101,20 +119,12 @@ 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 *shoptarg; /* set by nextopt */
extern char *optionarg; /* set by nextopt */
extern char *optptr; /* used by nextopt */
extern int editable; /* isatty(0) && isatty(1) */
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 *);
void freeparam(volatile struct shparam *);
int nextopt(const char *);
void getoptsreset(const char *);
/*
* $PchId: options.h,v 1.5 2006/05/29 13:08:45 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: output.c,v 1.33 2010/08/30 06:27:14 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,9 +32,12 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: output.c,v 1.33 2010/08/30 06:27:14 christos Exp $");
#endif
#endif /* not lint */
@ -47,28 +52,26 @@ static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 5/31/93";
* Our output routines may be smaller than the stdio routines.
*/
#include <sys/types.h> /* quad_t */
#include <sys/param.h> /* BSD4_4 */
#include <sys/ioctl.h>
#include <stdio.h> /* defines BUFSIZ */
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include "shell.h"
#include "syntax.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "var.h"
#ifdef __STDC__
#include "stdarg.h"
#else
#include <varargs.h>
#endif
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define OUTBUFSIZ BUFSIZ
#define BLOCK_OUT -2 /* output to a fixed block of memory */
#define MEM_OUT -3 /* output to dynamically allocated memory */
#define OUTPUT_ERR 01 /* error occurred on output */
struct output output = {NULL, 0, NULL, OUTBUFSIZ, 1, 0};
@ -102,11 +105,8 @@ RESET {
*/
void
open_mem(block, length, file)
char *block;
int length;
struct output *file;
{
open_mem(char *block, int length, struct output *file)
{
file->nextc = block;
file->nleft = --length;
file->fd = BLOCK_OUT;
@ -116,16 +116,9 @@ open_mem(block, length, file)
void
out1str(p)
const char *p;
{
outstr(p, out1);
}
void
out1qstr(const char *p)
out1str(const char *p)
{
outqstr(p, out1);
outstr(p, out1);
}
@ -137,43 +130,49 @@ out2str(const char *p)
void
outstr(p, file)
register const char *p;
register struct output *file;
{
outstr(const char *p, 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)
out2shstr(const char *p)
{
char ch;
outshstr(p, out2);
}
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);
void
outshstr(const char *p, struct output *file)
{
static const char norm_chars [] \
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/-=";
int need_q = p[0] == 0 || p[strspn(p, norm_chars)] != 0;
char c;
if (need_q)
outc('\'', file);
while (c = *p++, c != 0){
if (c != '\''){
outc(c, file);
}else{
outc('\'', file);
outc('\\', file);
outc(c, file);
outc('\'', file);
}
}
out1c('\'');
if (need_q)
outc('\'', file);
if (file == out2)
flushout(file);
}
@ -181,9 +180,8 @@ char out_junk[16];
void
emptyoutbuf(dest)
struct output *dest;
{
emptyoutbuf(struct output *dest)
{
int offset;
if (dest->fd == BLOCK_OUT) {
@ -212,16 +210,16 @@ emptyoutbuf(dest)
void
flushall() {
flushall(void)
{
flushout(&output);
flushout(&errout);
}
void
flushout(dest)
struct output *dest;
{
flushout(struct output *dest)
{
if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
return;
@ -233,7 +231,8 @@ flushout(dest)
void
freestdout() {
freestdout(void)
{
INTOFF;
if (output.buf) {
ckfree(output.buf);
@ -244,7 +243,6 @@ freestdout() {
}
#ifdef __STDC__
void
outfmt(struct output *file, const char *fmt, ...)
{
@ -266,8 +264,9 @@ out1fmt(const char *fmt, ...)
va_end(ap);
}
#ifdef DEBUG
void
dbgprintf(const char *fmt, ...)
debugprintf(const char *fmt, ...)
{
va_list ap;
@ -276,9 +275,10 @@ dbgprintf(const char *fmt, ...)
va_end(ap);
flushout(out2);
}
#endif
void
fmtstr(char *outbuf, int length, const char *fmt, ...)
fmtstr(char *outbuf, size_t length, const char *fmt, ...)
{
va_list ap;
struct output strout;
@ -295,82 +295,11 @@ fmtstr(char *outbuf, int length, const char *fmt, ...)
va_end(ap);
}
#else /* not __STDC__ */
void
outfmt(va_alist)
va_dcl
{
va_list ap;
struct output *file;
char *fmt;
va_start(ap);
file = va_arg(ap, struct output *);
fmt = va_arg(ap, char *);
doformat(file, fmt, ap);
va_end(ap);
}
void
out1fmt(va_alist)
va_dcl
{
va_list ap;
char *fmt;
va_start(ap);
fmt = va_arg(ap, char *);
doformat(out1, fmt, ap);
va_end(ap);
}
void
dbgprintf(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)
va_dcl
{
va_list ap;
struct output strout;
char *outbuf;
int length;
char *fmt;
va_start(ap);
outbuf = va_arg(ap, char *);
length = va_arg(ap, int);
fmt = va_arg(ap, char *);
strout.nextc = outbuf;
strout.nleft = length;
strout.fd = BLOCK_OUT;
strout.flags = 0;
doformat(&strout, fmt, ap);
outc('\0', &strout);
if (strout.flags & OUTPUT_ERR)
outbuf[length - 1] = '\0';
}
#endif /* __STDC__ */
/*
* Formatted output. This routine handles a subset of the printf formats:
* - Formats supported: d, u, o, X, s, and c.
* - Formats supported: d, u, o, p, X, s, and c.
* - The x format is also accepted but is treated like X.
* - The l modifier is accepted.
* - The l, ll and q modifiers are accepted.
* - The - and # flags are accepted; # only works with the o format.
* - Width and precision may be specified with any format except c.
* - An * may be given for the width or precision.
@ -381,27 +310,40 @@ fmtstr(va_alist)
#define TEMPSIZE 24
#ifdef __STDC__
static const char digit[16] = "0123456789ABCDEF";
#else
static const char digit[17] = "0123456789ABCDEF";
#ifdef BSD4_4
#define HAVE_VASPRINTF 1
#endif
void
doformat(struct output *dest, const char *f, va_list ap)
{
register char c;
#if HAVE_VASPRINTF
char *s;
vasprintf(&s, f, ap);
if (s == NULL)
error("Could not allocate formatted output buffer");
outstr(s, dest);
free(s);
#else /* !HAVE_VASPRINTF */
static const char digit[] = "0123456789ABCDEF";
char c;
char temp[TEMPSIZE];
int flushleft;
int sharp;
int width;
int prec;
int islong;
int isquad;
char *p;
int sign;
#ifdef BSD4_4
quad_t l;
u_quad_t num;
#else
long l;
unsigned long num;
u_long num;
#endif
unsigned base;
int len;
int size;
@ -417,6 +359,7 @@ doformat(struct output *dest, const char *f, va_list ap)
width = 0;
prec = -1;
islong = 0;
isquad = 0;
for (;;) {
if (*f == '-')
flushleft++;
@ -446,11 +389,23 @@ doformat(struct output *dest, const char *f, va_list ap)
}
}
if (*f == 'l') {
islong++;
f++;
if (*f == 'l') {
isquad++;
f++;
} else
islong++;
} else if (*f == 'q') {
isquad++;
f++;
}
switch (*f) {
case 'd':
#ifdef BSD4_4
if (isquad)
l = va_arg(ap, quad_t);
else
#endif
if (islong)
l = va_arg(ap, long);
else
@ -469,12 +424,21 @@ doformat(struct output *dest, const char *f, va_list ap)
case 'o':
base = 8;
goto uns_number;
case 'p':
outc('0', dest);
outc('x', dest);
/*FALLTHROUGH*/
case 'x':
/* we don't implement 'x'; treat like 'X' */
case 'X':
base = 16;
uns_number: /* an unsigned number */
sign = 0;
#ifdef BSD4_4
if (isquad)
num = va_arg(ap, u_quad_t);
else
#endif
if (islong)
num = va_arg(ap, unsigned long);
else
@ -542,6 +506,7 @@ number: /* process a number */
}
f++;
}
#endif /* !HAVE_VASPRINTF */
}
@ -551,11 +516,8 @@ number: /* process a number */
*/
int
xwrite(fd, buf, nbytes)
int fd;
char *buf;
int nbytes;
{
xwrite(int fd, char *buf, int nbytes)
{
int ntry;
int i;
int n;
@ -578,6 +540,17 @@ xwrite(fd, buf, nbytes)
}
}
/*
* $PchId: output.c,v 1.6 2006/05/22 12:46:03 philip Exp $
* Version of ioctl that retries after a signal is caught.
* XXX unused function
*/
int
xioctl(int fd, unsigned long request, char *arg)
{
int i;
while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
return i;
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: output.h,v 1.24 2012/03/15 02:02:20 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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
@ -46,41 +47,38 @@ struct output {
short flags;
};
/* flags for ->flags */
#define OUTPUT_ERR 01 /* error occurred on output */
extern struct output output;
extern struct output errout;
extern struct output memout;
extern struct output *out1;
extern struct output *out2;
#ifndef __printflike
#define __printflike(a,b)
#endif
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 out2shstr(const char *);
void outshstr(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 dbgprintf(const char *, ...) __printflike(1, 2);
void fmtstr(char *, int, const char *, ...) __printflike(3, 4);
#ifdef DEBUG
void debugprintf(const char *, ...) __printflike(1, 2);
#endif
void fmtstr(char *, size_t, const char *, ...) __printflike(3, 4);
void doformat(struct output *, const char *, va_list) __printflike(2, 0);
int xwrite(int, char *, int);
int xioctl(int, unsigned long, char *);
#define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
#define out1c(c) outc(c, out1);
#define out2c(c) outc(c, out2);
#define out1c(c) outc(c, out1)
#define out2c(c) outc(c, out2)
#define OUTPUT_INCL
#endif
/*
* $PchId: output.h,v 1.5 2006/05/23 12:04:54 philip Exp $
*/

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
/* $NetBSD: parser.h,v 1.18 2013/10/02 19:52:58 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,24 +32,28 @@
* SUCH DAMAGE.
*
* @(#)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 */
#define CTLESC '\201'
#define CTLVAR '\202'
#define CTL_FIRST '\201' /* first 'special' character */
#define CTLESC '\201' /* escape next character */
#define CTLVAR '\202' /* variable defn */
#define CTLENDVAR '\203'
#define CTLBACKQ '\204'
#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
/* CTLBACKQ | CTLQUOTE == '\205' */
#define CTLARI '\206'
#define CTLARI '\206' /* arithmetic expression */
#define CTLENDARI '\207'
#define CTLQUOTEMARK '\210'
#define CTLQUOTEEND '\211' /* only inside ${...} */
#define CTL_LAST '\211' /* last 'special' character */
/* variable substitution byte (follows CTLVAR) */
#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 */
#define VSTYPE 0x0f /* type of variable substitution */
#define VSNUL 0x10 /* colon--treat the empty string as unset */
#define VSLINENO 0x20 /* expansion of $LINENO, the line number
follows immediately */
#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */
/* values of VSTYPE field */
#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
@ -75,8 +81,4 @@ extern int whichprompt; /* 1 == PS1, 2 == PS2 */
union node *parsecmd(int);
void fixredir(union node *, const char *, int);
int goodname(char *);
char *getprompt(void *);
/*
* $PchId: parser.h,v 1.3 2006/03/29 14:33:35 philip Exp $
*/
const char *getprompt(void *);

View file

@ -1,3 +1,5 @@
/* $NetBSD: redir.c,v 1.35 2013/06/27 23:22:04 yamt Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,18 +32,17 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: redir.c,v 1.35 2013/06/27 23:22:04 yamt Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h> /* PIPE_BUF */
#include <signal.h>
#include <string.h>
#include <fcntl.h>
@ -53,25 +54,31 @@ __FBSDID("$FreeBSD: src/bin/sh/redir.c,v 1.26 2004/04/06 20:06:51 markm Exp $");
* Code for dealing with input/output redirection.
*/
#include "main.h"
#include "shell.h"
#include "nodes.h"
#include "jobs.h"
#include "options.h"
#include "expand.h"
#include "redir.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "options.h"
#define EMPTY -2 /* marks an unused slot in redirtab */
#define PIPESIZE 4096 /* amount of buffering in a pipe */
#define CLOSED -1 /* fd was not open before redir */
#ifndef PIPE_BUF
# define PIPESIZE 4096 /* amount of buffering in a pipe */
#else
# define PIPESIZE PIPE_BUF
#endif
MKINIT
struct redirtab {
struct redirtab *next;
int renamed[10];
short renamed[10];
};
@ -82,10 +89,10 @@ MKINIT struct redirtab *redirlist;
* background commands, where we want to redirect fd0 to /dev/null only
* if it hasn't already been redirected.
*/
STATIC int fd0_redirected = 0;
int fd0_redirected = 0;
STATIC void openredirect(union node *, char[10 ]);
STATIC int openhere(union node *);
STATIC void openredirect(union node *, char[10], int);
STATIC int openhere(const union node *);
/*
@ -103,13 +110,15 @@ redirect(union node *redir, int flags)
struct redirtab *sv = NULL;
int i;
int fd;
int try;
char memory[10]; /* file descriptors to write to memory */
for (i = 10 ; --i >= 0 ; )
memory[i] = 0;
memory[1] = flags & REDIR_BACKQ;
if (flags & REDIR_PUSH) {
/* We don't have to worry about REDIR_VFORK here, as
* flags & REDIR_PUSH is never true if REDIR_VFORK is set.
*/
sv = ckmalloc(sizeof (struct redirtab));
for (i = 0 ; i < 10 ; i++)
sv->renamed[i] = EMPTY;
@ -118,38 +127,32 @@ redirect(union node *redir, int 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;
again:
if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
switch (errno) {
case EBADF:
if (!try) {
openredirect(n, memory);
try++;
goto again;
}
/* FALLTHROUGH*/
i = CLOSED;
break;
default:
INTON;
error("%d: %s", fd, strerror(errno));
break;
/* NOTREACHED */
}
}
if (!try) {
sv->renamed[fd] = i;
}
} else
(void)fcntl(i, F_SETFD, FD_CLOEXEC);
sv->renamed[fd] = i;
INTON;
} else {
close(fd);
}
if (fd == 0)
fd0_redirected++;
if (!try)
openredirect(n, memory);
if (fd == 0)
fd0_redirected++;
openredirect(n, memory, flags);
}
if (memory[1])
out1 = &memout;
@ -159,15 +162,12 @@ again:
STATIC void
openredirect(union node *redir, char memory[10])
openredirect(union node *redir, char memory[10], int flags)
{
struct stat sb;
int fd = redir->nfile.fd;
char *fname;
int f;
/* Assume redirection succeeds. */
{ extern int exitstatus; exitstatus = 0; }
int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags;
/*
* We suppress interrupts so that we won't leave open file
@ -179,56 +179,64 @@ openredirect(union node *redir, char memory[10])
switch (redir->nfile.type) {
case NFROM:
fname = redir->nfile.expfname;
if ((f = open(fname, O_RDONLY)) < 0)
error("cannot open %s: %s", fname, strerror(errno));
movefd:
if (f != fd) {
dup2(f, fd);
close(f);
}
if (flags & REDIR_VFORK)
eflags = O_NONBLOCK;
else
eflags = 0;
if ((f = open(fname, O_RDONLY|eflags)) < 0)
goto eopen;
if (eflags)
(void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags);
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;
if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
goto ecreate;
break;
case NTO:
fname = redir->nfile.expfname;
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, strerror(errno));
goto movefd;
if (Cflag)
oflags |= O_EXCL;
/* FALLTHROUGH */
case NCLOBBER:
fname = redir->nfile.expfname;
if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
error("cannot create %s: %s", fname, strerror(errno));
goto movefd;
if ((f = open(fname, oflags, 0666)) < 0)
goto ecreate;
break;
case NAPPEND:
fname = redir->nfile.expfname;
if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
error("cannot create %s: %s", fname, strerror(errno));
goto movefd;
goto ecreate;
break;
case NTOFD:
case NFROMFD:
if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
if (memory[redir->ndup.dupfd])
memory[fd] = 1;
else
dup2(redir->ndup.dupfd, fd);
} else {
close(fd);
copyfd(redir->ndup.dupfd, fd, 1);
}
break;
INTON;
return;
case NHERE:
case NXHERE:
f = openhere(redir);
goto movefd;
break;
default:
abort();
}
if (f != fd) {
copyfd(f, fd, 1);
close(f);
}
INTON;
return;
ecreate:
exerrno = 1;
error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
eopen:
exerrno = 1;
error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
}
@ -239,13 +247,13 @@ movefd:
*/
STATIC int
openhere(union node *redir)
openhere(const union node *redir)
{
int pip[2];
int len = 0;
if (pipe(pip) < 0)
error("Pipe call failed: %s", strerror(errno));
error("Pipe call failed");
if (redir->type == NHERE) {
len = strlen(redir->nhere.doc->narg.text);
if (len <= PIPESIZE) {
@ -253,12 +261,14 @@ openhere(union node *redir)
goto out;
}
}
if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
if (forkshell(NULL, NULL, FORK_NOJOB) == 0) {
close(pip[0]);
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);
@ -287,11 +297,10 @@ popredir(void)
if (rp->renamed[i] != EMPTY) {
if (i == 0)
fd0_redirected--;
close(i);
if (rp->renamed[i] >= 0) {
dup2(rp->renamed[i], i);
copyfd(rp->renamed[i], i, 1);
close(rp->renamed[i]);
} else {
close(i);
}
}
}
@ -315,15 +324,14 @@ RESET {
}
SHELLPROC {
clearredir();
clearredir(0);
}
#endif
/* Return true if fd 0 has already been redirected at least once. */
int
fd0_redirected_p(void)
{
fd0_redirected_p (void) {
return fd0_redirected != 0;
}
@ -332,7 +340,7 @@ fd0_redirected_p(void)
*/
void
clearredir(void)
clearredir(int vforked)
{
struct redirtab *rp;
int i;
@ -342,11 +350,34 @@ clearredir(void)
if (rp->renamed[i] >= 0) {
close(rp->renamed[i]);
}
rp->renamed[i] = EMPTY;
if (!vforked)
rp->renamed[i] = EMPTY;
}
}
}
/*
* $PchId: redir.c,v 1.5 2006/05/22 12:27:37 philip Exp $
* Copy a file descriptor to be >= to. Returns -1
* if the source file descriptor is closed, EMPTY if there are no unused
* file descriptors left.
*/
int
copyfd(int from, int to, int equal)
{
int newfd;
if (equal)
newfd = dup2(from, to);
else
newfd = fcntl(from, F_DUPFD, to);
if (newfd < 0) {
if (errno == EMFILE)
return EMPTY;
else
error("%d: %s", from, strerror(errno));
}
return newfd;
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: redir.h,v 1.16 2011/02/17 15:13:49 pooka Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,20 +32,17 @@
* SUCH DAMAGE.
*
* @(#)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 */
#define REDIR_VFORK 04 /* running under vfork(2), be careful */
union node;
void redirect(union node *, int);
void popredir(void);
int fd0_redirected_p(void);
void clearredir(void);
void clearredir(int);
int copyfd(int, int, int);
/*
* $PchId: redir.h,v 1.3 2006/03/29 14:13:34 philip Exp $
*/

2002
bin/sh/sh.1 Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,5 @@
/* $NetBSD: shell.h,v 1.18 2013/04/28 17:01:28 dholland Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,57 +32,58 @@
* SUCH DAMAGE.
*
* @(#)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 <sys/types.h> /* 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.
* TILDE -> 1 if you want the shell to expand ~logname.
* USEGETPW -> 1 if getpwnam() must be used to look up a name.
* READLINE -> 1 if line editing by readline() should be enabled.
* SHORTNAMES -> 1 if your linker cannot handle long names.
* define BSD if you are running 4.2 BSD or later.
* define SYSV if you are running under System V.
* define DEBUG=1 to compile in debugging (set global "debug" to turn on)
* define DEBUG=1 to compile in debugging ('set -o debug' to turn on)
* define DEBUG=2 to compile in and turn on debugging.
* define DO_SHAREDVFORK to indicate that vfork(2) shares its address
* with its parent.
*
* When debugging is on, debugging info will be written to $HOME/trace and
* When debugging is on, debugging info will be written to ./trace and
* a quit signal will generate a core dump.
*/
#ifndef JOBS
#define JOBS 1
#endif
#include <sys/param.h>
#if defined(__minix)
#define JOBS 0
#else
#define JOBS 1
#endif /* defined(__minix) */
#ifndef BSD
#define BSD 1
#endif
#ifndef DEBUG
#define DEBUG 0
#endif
#define POSIX 1
/*
* 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)
#ifndef DO_SHAREDVFORK
#if !defined(__minix)
#if __NetBSD_Version__ >= 104000000
#define DO_SHAREDVFORK
#endif
#endif /* !defined(__minix) */
#endif
typedef void *pointer;
#define STATIC static
#define MKINIT /* empty */
#ifndef NULL
#define NULL (void *)0
#endif
#define STATIC /* empty */
#define MKINIT /* empty */
extern char nullstr[1]; /* null string */
#include <sys/cdefs.h>
#if DEBUG
#define TRACE(param) sh_trace param
extern const char nullstr[1]; /* null string */
#ifdef DEBUG
#define TRACE(param) trace param
#define TRACEV(param) tracev param
#else
#define TRACE(param)
#define TRACEV(param)
#endif
/*
* $PchId: shell.h,v 1.7 2006/05/22 12:47:00 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: show.c,v 1.28 2011/08/23 10:01:32 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,39 +32,37 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: show.c,v 1.28 2011/08/23 10:01:32 christos Exp $");
#endif
#endif /* not lint */
/*
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/show.c,v 1.21 2004/04/06 20:06:51 markm Exp $");
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "shell.h"
#include "parser.h"
#include "nodes.h"
#include "mystring.h"
#include "show.h"
#include "options.h"
#if DEBUG
static void trputc(int c);
#ifdef DEBUG
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);
static void
void
showtree(union node *n)
{
trputs("showtree called\n");
@ -74,7 +74,7 @@ static void
shtree(union node *n, int ind, char *pfx, FILE *fp)
{
struct nodelist *lp;
char *s;
const char *s;
if (n == NULL)
return;
@ -126,7 +126,7 @@ shcmd(union node *cmd, FILE *fp)
{
union node *np;
int first;
char *s;
const char *s;
int dftfd;
first = 1;
@ -141,22 +141,19 @@ shcmd(union node *cmd, FILE *fp)
putchar(' ');
switch (np->nfile.type) {
case NTO: s = ">"; dftfd = 1; break;
case NCLOBBER: 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;
case NFROMTO: 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) {
if (np->ndup.dupfd >= 0)
fprintf(fp, "%d", np->ndup.dupfd);
else
fprintf(fp, "-");
fprintf(fp, "%d", np->ndup.dupfd);
} else {
sharg(np->nfile.fname, fp);
}
@ -175,7 +172,6 @@ sharg(union node *arg, FILE *fp)
if (arg->type != NARG) {
printf("<node type %d>\n", arg->type);
fflush(stdout);
abort();
}
bqlist = arg->narg.backquote;
@ -262,6 +258,8 @@ indent(int amount, char *pfx, FILE *fp)
putc('\t', fp);
}
}
#endif
/*
@ -271,46 +269,52 @@ indent(int amount, char *pfx, FILE *fp)
FILE *tracefile;
#if DEBUG == 2
int debug = 1;
#else
int debug = 0;
#endif
static void
#ifdef DEBUG
void
trputc(int c)
{
if (tracefile == NULL)
if (debug != 1 || !tracefile)
return;
putc(c, tracefile);
if (c == '\n')
fflush(tracefile);
}
#endif
void
sh_trace(const char *fmt, ...)
trace(const char *fmt, ...)
{
#ifdef DEBUG
va_list va;
if (debug != 1 || !tracefile)
return;
va_start(va, fmt);
if (tracefile != NULL) {
(void) vfprintf(tracefile, fmt, va);
if (strchr(fmt, '\n'))
(void) fflush(tracefile);
}
(void) vfprintf(tracefile, fmt, va);
va_end(va);
#endif
}
void
tracev(const char *fmt, va_list va)
{
#ifdef DEBUG
va_list ap;
if (debug != 1 || !tracefile)
return;
va_copy(ap, va);
(void) vfprintf(tracefile, fmt, ap);
va_end(ap);
#endif
}
#ifdef DEBUG
void
trputs(char *s)
trputs(const char *s)
{
if (tracefile == NULL)
if (debug != 1 || !tracefile)
return;
fputs(s, tracefile);
if (strchr(s, '\n'))
fflush(tracefile);
}
@ -320,7 +324,7 @@ trstring(char *s)
char *p;
char c;
if (tracefile == NULL)
if (debug != 1 || !tracefile)
return;
putc('"', tracefile);
for (p = s ; *p ; p++) {
@ -352,12 +356,14 @@ backslash: putc('\\', tracefile);
}
putc('"', tracefile);
}
#endif
void
trargs(char **ap)
{
if (tracefile == NULL)
#ifdef DEBUG
if (debug != 1 || !tracefile)
return;
while (*ap) {
trstring(*ap++);
@ -366,18 +372,25 @@ trargs(char **ap)
else
putc('\n', tracefile);
}
fflush(tracefile);
#endif
}
#ifdef DEBUG
void
opentrace(void)
{
char s[100];
#ifdef O_APPEND
int flags;
#endif
if (!debug)
if (debug != 1) {
if (tracefile)
fflush(tracefile);
/* leave open because libedit might be using it */
return;
}
#ifdef not_this_way
{
char *p;
@ -391,19 +404,27 @@ opentrace(void)
strcat(s, "/trace");
}
#else
scopy("./trace", s);
snprintf(s, sizeof(s), "./trace.%d", (int)getpid());
#endif /* not_this_way */
if ((tracefile = fopen(s, "a")) == NULL) {
fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno));
return;
if (tracefile) {
if (!freopen(s, "a", tracefile)) {
fprintf(stderr, "Can't re-open %s\n", s);
tracefile = NULL;
debug = 0;
return;
}
} else {
if ((tracefile = fopen(s, "a")) == NULL) {
fprintf(stderr, "Can't open %s\n", s);
debug = 0;
return;
}
}
#ifdef O_APPEND
if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0)
fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND);
#endif
setlinebuf(tracefile);
fputs("\nTracing started.\n", tracefile);
fflush(tracefile);
}
#endif /* DEBUG */
/*
* $PchId: show.c,v 1.6 2006/05/22 12:27:51 philip Exp $
*/

View file

@ -1,3 +1,5 @@
/* $NetBSD: show.h,v 1.7 2003/08/07 09:05:38 agc Exp $ */
/*-
* Copyright (c) 1995
* The Regents of the University of California. All rights reserved.
@ -10,7 +12,7 @@
* 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
* 3. 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.
*
@ -27,16 +29,17 @@
* 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 *, ...);
#include <stdarg.h>
union node;
void showtree(union node *);
void trace(const char *, ...);
void tracev(const char *, va_list);
void trargs(char **);
void trputs(char *);
#ifdef DEBUG
void trputc(int);
void trputs(const char *);
void opentrace(void);
#endif
/*
* $PchId: show.h,v 1.4 2006/03/29 13:28:45 philip Exp $
*/

105
bin/sh/syntax.c Normal file
View file

@ -0,0 +1,105 @@
/* $NetBSD: syntax.c,v 1.3 2012/03/28 20:11:25 christos Exp $ */
#include <sys/cdefs.h>
__RCSID("$NetBSD: syntax.c,v 1.3 2012/03/28 20:11:25 christos Exp $");
#include <limits.h>
#include "shell.h"
#include "syntax.h"
#include "parser.h"
#if CWORD != 0
#error initialisation assumes 'CWORD' is zero
#endif
#define ndx(ch) (ch + 1 - CHAR_MIN)
#define set(ch, val) [ndx(ch)] = val,
#define set_range(s, e, val) [ndx(s) ... ndx(e)] = val,
/* syntax table used when not in quotes */
const char basesyntax[257] = { CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\\', CBACK)
set('\'', CSQUOTE)
set('"', CDQUOTE)
set('`', CBQUOTE)
set('$', CVAR)
set('}', CENDVAR)
set('<', CSPCL)
set('>', CSPCL)
set('(', CSPCL)
set(')', CSPCL)
set(';', CSPCL)
set('&', CSPCL)
set('|', CSPCL)
set(' ', CSPCL)
set('\t', CSPCL)
};
/* syntax table used when in double quotes */
const char dqsyntax[257] = { CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\\', CBACK)
set('"', CDQUOTE)
set('`', CBQUOTE)
set('$', CVAR)
set('}', CENDVAR)
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
set('!', CCTL)
set('*', CCTL)
set('?', CCTL)
set('[', CCTL)
set('=', CCTL)
set('~', CCTL)
set(':', CCTL)
set('/', CCTL)
set('-', CCTL)
};
/* syntax table used when in single quotes */
const char sqsyntax[257] = { CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\'', CSQUOTE)
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
set('!', CCTL)
set('*', CCTL)
set('?', CCTL)
set('[', CCTL)
set('=', CCTL)
set('~', CCTL)
set(':', CCTL)
set('/', CCTL)
set('-', CCTL)
};
/* syntax table used when in arithmetic */
const char arisyntax[257] = { CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\\', CBACK)
set('`', CBQUOTE)
set('\'', CSQUOTE)
set('"', CDQUOTE)
set('$', CVAR)
set('}', CENDVAR)
set('(', CLP)
set(')', CRP)
};
/* character classification table */
const char is_type[257] = { 0,
set_range('0', '9', ISDIGIT)
set_range('a', 'z', ISLOWER)
set_range('A', 'Z', ISUPPER)
set('_', ISUNDER)
set('#', ISSPECL)
set('?', ISSPECL)
set('$', ISSPECL)
set('!', ISSPECL)
set('-', ISSPECL)
set('*', ISSPECL)
set('@', ISSPECL)
};

83
bin/sh/syntax.h Normal file
View file

@ -0,0 +1,83 @@
/* $NetBSD: syntax.h,v 1.2 2004/01/17 17:38:12 dsl Exp $ */
/*-
* 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. 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.
*/
#include <sys/cdefs.h>
#include <ctype.h>
/* Syntax classes */
#define CWORD 0 /* character is nothing special */
#define CNL 1 /* newline character */
#define CBACK 2 /* a backslash character */
#define CSQUOTE 3 /* single quote */
#define CDQUOTE 4 /* double quote */
#define CBQUOTE 5 /* backwards single quote */
#define CVAR 6 /* a dollar sign */
#define CENDVAR 7 /* a '}' character */
#define CLP 8 /* a left paren in arithmetic */
#define CRP 9 /* a right paren in arithmetic */
#define CEOF 10 /* end of file */
#define CCTL 11 /* like CWORD, except it must be escaped */
#define CSPCL 12 /* these terminate a word */
/* Syntax classes for is_ functions */
#define ISDIGIT 01 /* a digit */
#define ISUPPER 02 /* an upper case letter */
#define ISLOWER 04 /* a lower case letter */
#define ISUNDER 010 /* an underscore */
#define ISSPECL 020 /* the name of a special parameter */
#define PEOF (CHAR_MIN - 1)
#define SYNBASE (-PEOF)
/* XXX UPEOF is CHAR_MAX, so is a valid 'char' value... */
#define UPEOF ((char)PEOF)
#define BASESYNTAX (basesyntax + SYNBASE)
#define DQSYNTAX (dqsyntax + SYNBASE)
#define SQSYNTAX (sqsyntax + SYNBASE)
#define ARISYNTAX (arisyntax + SYNBASE)
/* These defines assume that the digits are contiguous */
#define is_digit(c) ((unsigned)((c) - '0') <= 9)
#define is_alpha(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && isalpha((unsigned char)(c)))
#define is_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalpha((unsigned char)(c))))
#define is_in_name(c) (((char)(c)) != UPEOF && ((c) < CTL_FIRST || (c) > CTL_LAST) && ((c) == '_' || isalnum((unsigned char)(c))))
#define is_special(c) ((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))
#define digit_val(c) ((c) - '0')
extern const char basesyntax[];
extern const char dqsyntax[];
extern const char sqsyntax[];
extern const char arisyntax[];
extern const char is_type[];

475
bin/sh/trap.c Normal file
View file

@ -0,0 +1,475 @@
/* $NetBSD: trap.c,v 1.35 2011/06/18 21:18:46 christos Exp $ */
/*-
* 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. 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.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)trap.c 8.5 (Berkeley) 6/5/95";
#else
__RCSID("$NetBSD: trap.c,v 1.35 2011/06/18 21:18:46 christos Exp $");
#endif
#endif /* not lint */
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#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 "builtins.h"
#include "syntax.h"
#include "output.h"
#include "memalloc.h"
#include "error.h"
#include "trap.h"
#include "mystring.h"
#include "var.h"
/*
* Sigmode records the current value of the signal handlers for the various
* modes. A value of zero means that the current handler is not known.
* S_HARD_IGN indicates that the signal was ignored on entry to the shell,
*/
#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_RESET 5 /* temporary - to reset a hard ignored sig */
char *trap[NSIG+1]; /* trap handler commands */
MKINIT char sigmode[NSIG]; /* current value of signal */
volatile char gotsig[NSIG]; /* indicates specified signal received */
int pendingsigs; /* indicates some signal received */
static int getsigaction(int, sig_t *);
/*
* return the signal number described by `p' (as a number or a name)
* or -1 if it isn't one
*/
static int
signame_to_signum(const char *p)
{
int i;
if (is_number(p))
return number(p);
if (strcasecmp(p, "exit") == 0 )
return 0;
if (strncasecmp(p, "sig", 3) == 0)
p += 3;
for (i = 0; i < NSIG; ++i)
if (strcasecmp (p, sys_signame[i]) == 0)
return i;
return -1;
}
/*
* Print a list of valid signal names
*/
static void
printsignals(void)
{
int n;
out1str("EXIT ");
for (n = 1; n < NSIG; n++) {
out1fmt("%s", sys_signame[n]);
if ((n == NSIG/2) || n == (NSIG - 1))
out1str("\n");
else
out1c(' ');
}
}
/*
* The trap builtin.
*/
int
trapcmd(int argc, char **argv)
{
char *action;
char **ap;
int signo;
if (argc <= 1) {
for (signo = 0 ; signo <= NSIG ; signo++)
if (trap[signo] != NULL) {
out1fmt("trap -- ");
print_quoted(trap[signo]);
out1fmt(" %s\n",
(signo) ? sys_signame[signo] : "EXIT");
}
return 0;
}
ap = argv + 1;
action = NULL;
if (strcmp(*ap, "--") == 0)
if (*++ap == NULL)
return 0;
if (signame_to_signum(*ap) == -1) {
if ((*ap)[0] == '-') {
if ((*ap)[1] == '\0')
ap++;
else if ((*ap)[1] == 'l' && (*ap)[2] == '\0') {
printsignals();
return 0;
}
else
error("bad option %s\n", *ap);
}
else
action = *ap++;
}
while (*ap) {
if (is_number(*ap))
signo = number(*ap);
else
signo = signame_to_signum(*ap);
if (signo < 0 || signo > NSIG)
error("%s: bad trap", *ap);
INTOFF;
if (action)
action = savestr(action);
if (trap[signo])
ckfree(trap[signo]);
trap[signo] = action;
if (signo != 0)
setsignal(signo, 0);
INTON;
ap++;
}
return 0;
}
/*
* Clear traps on a fork or vfork.
* Takes one arg vfork, to tell it to not be destructive of
* the parents variables.
*/
void
clear_traps(int vforked)
{
char **tp;
for (tp = trap ; tp <= &trap[NSIG] ; tp++) {
if (*tp && **tp) { /* trap not NULL or SIG_IGN */
INTOFF;
if (!vforked) {
ckfree(*tp);
*tp = NULL;
}
if (tp != &trap[0])
setsignal(tp - trap, vforked);
INTON;
}
}
}
/*
* Set the signal handler for the specified signal. The routine figures
* out what it should be set to.
*/
sig_t
setsignal(int signo, int vforked)
{
int action;
sig_t sigact = SIG_DFL, sig;
char *t, tsig;
if ((t = trap[signo]) == NULL)
action = S_DFL;
else if (*t != '\0')
action = S_CATCH;
else
action = S_IGN;
if (rootshell && !vforked && action == S_DFL) {
switch (signo) {
case SIGINT:
if (iflag || minusc || sflag == 0)
action = S_CATCH;
break;
case SIGQUIT:
#ifdef DEBUG
if (debug)
break;
#endif
/* FALLTHROUGH */
case SIGTERM:
if (iflag)
action = S_IGN;
break;
#if JOBS
case SIGTSTP:
case SIGTTOU:
if (mflag)
action = S_IGN;
break;
#endif
}
}
t = &sigmode[signo - 1];
tsig = *t;
if (tsig == 0) {
/*
* current setting unknown
*/
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 0;
}
if (sigact == SIG_IGN) {
/*
* POSIX 3.14.13 states that non-interactive shells
* should ignore trap commands for signals that were
* ignored upon entry, and leaves the behavior
* unspecified for interactive shells. On interactive
* shells, or if job control is on, and we have a job
* control related signal, we allow the trap to work.
*
* This change allows us to be POSIX compliant, and
* at the same time override the default behavior if
* we need to by setting the interactive flag.
*/
if ((mflag && (signo == SIGTSTP ||
signo == SIGTTIN || signo == SIGTTOU)) || iflag) {
tsig = S_IGN;
} else
tsig = S_HARD_IGN;
} else {
tsig = S_RESET; /* force to be set */
}
}
if (tsig == S_HARD_IGN || tsig == action)
return 0;
switch (action) {
case S_DFL: sigact = SIG_DFL; break;
case S_CATCH: sigact = onsig; break;
case S_IGN: sigact = SIG_IGN; break;
}
sig = signal(signo, sigact);
if (sig != SIG_ERR) {
sigset_t ss;
if (!vforked)
*t = action;
if (action == S_CATCH)
(void)siginterrupt(signo, 1);
/*
* If our parent accidentally blocked signals for
* us make sure we unblock them
*/
(void)sigemptyset(&ss);
(void)sigaddset(&ss, signo);
(void)sigprocmask(SIG_UNBLOCK, &ss, NULL);
}
return sig;
}
/*
* 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(int signo, int vforked)
{
if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) {
signal(signo, SIG_IGN);
}
if (!vforked)
sigmode[signo - 1] = S_HARD_IGN;
}
#ifdef mkinit
INCLUDE <signal.h>
INCLUDE "trap.h"
SHELLPROC {
char *sm;
clear_traps(0);
for (sm = sigmode ; sm < sigmode + NSIG ; sm++) {
if (*sm == S_IGN)
*sm = S_HARD_IGN;
}
}
#endif
/*
* Signal handler.
*/
void
onsig(int signo)
{
signal(signo, onsig);
if (signo == SIGINT && trap[SIGINT] == NULL) {
onint();
return;
}
gotsig[signo - 1] = 1;
pendingsigs++;
}
/*
* Called to execute a trap. Perhaps we should avoid entering new trap
* handlers while we are executing a trap handler.
*/
void
dotrap(void)
{
int i;
int savestatus;
for (;;) {
for (i = 1 ; ; i++) {
if (gotsig[i - 1])
break;
if (i >= NSIG)
goto done;
}
gotsig[i - 1] = 0;
savestatus=exitstatus;
evalstring(trap[i], 0);
exitstatus=savestatus;
}
done:
pendingsigs = 0;
}
/*
* Controls whether the shell is interactive or not.
*/
void
setinteractive(int on)
{
static int is_interactive;
if (on == is_interactive)
return;
setsignal(SIGINT, 0);
setsignal(SIGQUIT, 0);
setsignal(SIGTERM, 0);
is_interactive = on;
}
/*
* Called to exit the shell.
*/
void
exitshell(int status)
{
struct jmploc loc1, loc2;
char *p;
TRACE(("pid %d, exitshell(%d)\n", getpid(), status));
if (setjmp(loc1.loc)) {
goto l1;
}
if (setjmp(loc2.loc)) {
goto l2;
}
handler = &loc1;
if ((p = trap[0]) != NULL && *p != '\0') {
trap[0] = NULL;
evalstring(p, 0);
}
l1: handler = &loc2; /* probably unnecessary */
flushall();
#if JOBS
setjobctl(0);
#endif
l2: _exit(status);
/* NOTREACHED */
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: trap.h,v 1.20 2012/03/15 02:02:20 joerg Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,23 +32,14 @@
* SUCH DAMAGE.
*
* @(#)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;
int trapcmd(int, char **);
void clear_traps(void);
void setsignal(int);
void ignoresig(int);
void clear_traps(int);
sig_t setsignal(int, int);
void ignoresig(int, int);
void onsig(int);
void dotrap(void);
void setinteractive(int);
void exitshell(int);
char *strsiglist(int);
/*
* $PchId: trap.h,v 1.6 2006/05/22 12:48:30 philip Exp $
*/
void exitshell(int) __dead;

View file

@ -1,3 +1,5 @@
/* $NetBSD: var.c,v 1.43 2013/11/01 16:49:02 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,28 +32,25 @@
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: var.c,v 1.43 2013/11/01 16:49:02 christos Exp $");
#endif
#endif /* not lint */
#include <sys/cdefs.h>
/*
__FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
*/
#include <unistd.h>
#include <stdlib.h>
#ifndef NO_PATHS_H
#include <string.h>
#include <paths.h>
#endif
#include <limits.h>
/*
* Shell variables.
*/
#include <locale.h>
#include "shell.h"
#include "output.h"
#include "expand.h"
@ -60,49 +59,57 @@ __FBSDID("$FreeBSD: src/bin/sh/var.c,v 1.26.2.1 2004/09/30 04:41:55 des Exp $");
#include "exec.h"
#include "syntax.h"
#include "options.h"
#include "builtins.h"
#include "mail.h"
#include "var.h"
#include "memalloc.h"
#include "error.h"
#include "mystring.h"
#include "parser.h"
#if !defined(NO_HISTORY)
#include "show.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
#include "builtins.h"
#ifndef _PATH_DEFPATH
#define _PATH_DEFPATH "/usr/bin:/bin"
#endif
#ifdef SMALL
#define VTABSIZE 39
#else
#define VTABSIZE 517
#endif
struct varinit {
struct var *var;
int flags;
char *text;
const char *text;
void (*func)(const char *);
};
struct localvar *localvars;
#ifndef NO_HISTORY
#if ATTY
struct var vatty;
#endif
#ifndef SMALL
struct var vhistsize;
struct var vterm;
#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 vps4;
struct var vvers;
STATIC struct var voptind;
struct var voptind;
STATIC const struct varinit varinit[] = {
#if !defined(NO_HISTORY)
const struct varinit varinit[] = {
#if ATTY
{ &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=",
NULL },
#endif
#ifndef SMALL
{ &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=",
sethistsize },
#endif
@ -114,26 +121,27 @@ STATIC const struct varinit varinit[] = {
NULL },
{ &vpath, VSTRFIXED|VTEXTFIXED, "PATH=" _PATH_DEFPATH,
changepath },
{ &vppid, VSTRFIXED|VTEXTFIXED|VUNSET, "PPID=",
NULL },
/*
* vps1 depends on uid
*/
{ &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ",
NULL },
{ &vpse, VSTRFIXED|VTEXTFIXED|VUNSET, "PSE=",
{ &vps4, VSTRFIXED|VTEXTFIXED, "PS4=+ ",
NULL },
{ &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1",
#ifndef SMALL
{ &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=",
setterm },
#endif
{ &voptind, VSTRFIXED|VTEXTFIXED|VNOFUNC, "OPTIND=1",
getoptsreset },
{ NULL, 0, NULL,
NULL }
};
STATIC struct var *vartab[VTABSIZE];
struct var *vartab[VTABSIZE];
STATIC struct var **hashvar(char *);
STATIC int varequal(char *, char *);
STATIC int localevar(char *);
STATIC int strequal(const char *, const char *);
STATIC struct var *find_var(const char *, struct var ***, int *);
/*
* Initialize the varable symbol tables and import the environment
@ -141,9 +149,9 @@ STATIC int localevar(char *);
#ifdef mkinit
INCLUDE "var.h"
MKINIT char **environ;
INIT {
char **envp;
extern char **environ;
initvar();
for (envp = environ ; *envp ; envp++) {
@ -163,35 +171,28 @@ INIT {
void
initvar(void)
{
char ppid[20];
const struct varinit *ip;
struct var *vp;
struct var **vpp;
for (ip = varinit ; (vp = ip->var) != NULL ; ip++) {
if ((vp->flags & VEXPORT) == 0) {
vpp = hashvar(ip->text);
vp->next = *vpp;
*vpp = vp;
vp->text = ip->text;
vp->flags = ip->flags;
vp->func = ip->func;
}
if (find_var(ip->text, &vpp, &vp->name_len) != NULL)
continue;
vp->next = *vpp;
*vpp = vp;
vp->text = strdup(ip->text);
vp->flags = ip->flags;
vp->func = ip->func;
}
/*
* PS1 depends on uid
*/
if ((vps1.flags & VEXPORT) == 0) {
vpp = hashvar("PS1=");
if (find_var("PS1", &vpp, &vps1.name_len) == NULL) {
vps1.next = *vpp;
*vpp = &vps1;
vps1.text = geteuid() ? "PS1=$ " : "PS1=# ";
vps1.text = strdup(geteuid() ? "PS1=$ " : "PS1=# ");
vps1.flags = VSTRFIXED|VTEXTFIXED;
}
if ((vppid.flags & VEXPORT) == 0) {
fmtstr(ppid, sizeof(ppid), "%d", (int)getppid());
setvarsafe("PPID", ppid, 0);
}
}
/*
@ -199,15 +200,11 @@ initvar(void)
*/
int
setvarsafe(char *name, char *val, int flags)
setvarsafe(const char *name, const char *val, int flags)
{
struct jmploc jmploc;
struct jmploc *volatile savehandler = handler;
int err = 0;
#if __GNUC__
/* Avoid longjmp clobbering */
(void) &err;
#endif
int volatile err = 0;
if (setjmp(jmploc.loc))
err = 1;
@ -220,14 +217,16 @@ setvarsafe(char *name, char *val, int flags)
}
/*
* Set the value of a variable. The flags argument is tored with the
* Set the value of a variable. The flags argument is ored with the
* flags of the variable. If val is NULL, the variable is unset.
*/
void
setvar(char *name, char *val, int flags)
setvar(const char *name, const char *val, int flags)
{
char *p, *q;
const char *p;
const char *q;
char *d;
int len;
int namelen;
char *nameeq;
@ -255,37 +254,18 @@ setvar(char *name, char *val, int flags)
} else {
len += strlen(val);
}
p = nameeq = ckmalloc(len);
d = nameeq = ckmalloc(len);
q = name;
while (--namelen >= 0)
*p++ = *q++;
*p++ = '=';
*p = '\0';
*d++ = *q++;
*d++ = '=';
*d = '\0';
if (val)
scopy(val, p);
scopy(val, d);
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
@ -298,56 +278,47 @@ void
setvareq(char *s, int flags)
{
struct var *vp, **vpp;
int len;
int nlen;
if (aflag)
flags |= VEXPORT;
vpp = hashvar(s);
for (vp = *vpp ; vp ; vp = vp->next) {
if (varequal(s, vp->text)) {
if (vp->flags & VREADONLY) {
len = strchr(s, '=') - s;
error("%.*s: is read only", len, s);
}
INTOFF;
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 |= 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;
vp = find_var(s, &vpp, &nlen);
if (vp != NULL) {
if (vp->flags & VREADONLY)
error("%.*s: is read only", vp->name_len, s);
if (flags & VNOSET)
return;
}
INTOFF;
if (vp->func && (flags & VNOFUNC) == 0)
(*vp->func)(s + vp->name_len + 1);
if ((vp->flags & (VTEXTFIXED|VSTACK)) == 0)
ckfree(vp->text);
vp->flags &= ~(VTEXTFIXED|VSTACK|VUNSET);
vp->flags |= flags & ~VNOFUNC;
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);
INTON;
return;
}
/* not found */
if (flags & VNOSET)
return;
vp = ckmalloc(sizeof (*vp));
vp->flags = flags;
vp->flags = flags & ~VNOFUNC;
vp->text = s;
vp->name_len = nlen;
vp->next = *vpp;
vp->func = NULL;
INTOFF;
*vpp = vp;
if ((vp->flags & VEXPORT) && localevar(s)) {
putenv(s);
(void) setlocale(LC_ALL, "");
}
INTON;
}
@ -357,17 +328,25 @@ setvareq(char *s, int flags)
*/
void
listsetvar(struct strlist *list)
listsetvar(struct strlist *list, int flags)
{
struct strlist *lp;
INTOFF;
for (lp = list ; lp ; lp = lp->next) {
setvareq(savestr(lp->text), 0);
setvareq(savestr(lp->text), flags);
}
INTON;
}
void
listmklocal(struct strlist *list, int flags)
{
struct strlist *lp;
for (lp = list ; lp ; lp = lp->next)
mklocal(lp->text, flags);
}
/*
@ -375,18 +354,14 @@ listsetvar(struct strlist *list)
*/
char *
lookupvar(char *name)
lookupvar(const char *name)
{
struct var *v;
for (v = *hashvar(name) ; v ; v = v->next) {
if (varequal(v->text, name)) {
if (v->flags & VUNSET)
return NULL;
return strchr(v->text, '=') + 1;
}
}
return NULL;
v = find_var(name, NULL, NULL);
if (v == NULL || v->flags & VUNSET)
return NULL;
return v->text + v->name_len + 1;
}
@ -398,24 +373,21 @@ lookupvar(char *name)
*/
char *
bltinlookup(char *name, int doall)
bltinlookup(const char *name, int doall)
{
struct strlist *sp;
struct var *v;
for (sp = cmdenviron ; sp ; sp = sp->next) {
if (varequal(sp->text, name))
if (strequal(sp->text, name))
return strchr(sp->text, '=') + 1;
}
for (v = *hashvar(name) ; v ; v = v->next) {
if (varequal(v->text, name)) {
if ((v->flags & VUNSET)
|| (!doall && (v->flags & VEXPORT) == 0))
return NULL;
return strchr(v->text, '=') + 1;
}
}
return NULL;
v = find_var(name, NULL, NULL);
if (v == NULL || v->flags & VUNSET || (!doall && !(v->flags & VEXPORT)))
return NULL;
return v->text + v->name_len + 1;
}
@ -431,7 +403,8 @@ environment(void)
int nenv;
struct var **vpp;
struct var *vp;
char **env, **ep;
char **env;
char **ep;
nenv = 0;
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
@ -457,6 +430,8 @@ environment(void)
*/
#ifdef mkinit
void shprocvar(void);
SHELLPROC {
shprocvar();
}
@ -496,24 +471,94 @@ shprocvar(void)
* any variables.
*/
void
print_quoted(const char *p)
{
const char *q;
if (strcspn(p, "|&;<>()$`\\\"' \t\n*?[]#~=%") == strlen(p)) {
out1fmt("%s", p);
return;
}
while (*p) {
if (*p == '\'') {
out1fmt("\\'");
p++;
continue;
}
q = strchr(p, '\'');
if (!q) {
out1fmt("'%s'", p );
return;
}
out1fmt("'%.*s'", (int)(q - p), p );
p = q;
}
}
static int
sort_var(const void *v_v1, const void *v_v2)
{
const struct var * const *v1 = v_v1;
const struct var * const *v2 = v_v2;
/* XXX Will anyone notice we include the '=' of the shorter name? */
return strcoll((*v1)->text, (*v2)->text);
}
/*
* POSIX requires that 'set' (but not export or readonly) output the
* variables in lexicographic order - by the locale's collating order (sigh).
* Maybe we could keep them in an ordered balanced binary tree
* instead of hashed lists.
* For now just roll 'em through qsort for printing...
*/
int
showvarscmd(int argc __unused, char **argv __unused)
showvars(const char *name, int flag, int show_value)
{
struct var **vpp;
struct var *vp;
const char *s;
const char *p;
static struct var **list; /* static in case we are interrupted */
static int list_len;
int count = 0;
if (!list) {
list_len = 32;
list = ckmalloc(list_len * sizeof *list);
}
for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) {
for (vp = *vpp ; vp ; vp = vp->next) {
if (vp->flags & VUNSET)
if (flag && !(vp->flags & flag))
continue;
for (s = vp->text; *s != '='; s++)
out1c(*s);
out1c('=');
out1qstr(s + 1);
out1c('\n');
if (vp->flags & VUNSET && !(show_value & 2))
continue;
if (count >= list_len) {
list = ckrealloc(list,
(list_len << 1) * sizeof *list);
list_len <<= 1;
}
list[count++] = vp;
}
}
qsort(list, count, sizeof *list, sort_var);
for (vpp = list; count--; vpp++) {
vp = *vpp;
if (name)
out1fmt("%s ", name);
for (p = vp->text ; *p != '=' ; p++)
out1c(*p);
if (!(vp->flags & VUNSET) && show_value) {
out1fmt("=");
print_quoted(++p);
}
out1c('\n');
}
return 0;
}
@ -526,71 +571,29 @@ showvarscmd(int argc __unused, char **argv __unused)
int
exportcmd(int argc, char **argv)
{
struct var **vpp;
struct var *vp;
char *name;
char *p;
char *cmdname;
int ch, values;
const char *p;
int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT;
int pflag;
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);
}
pflag = nextopt("p") == 'p' ? 3 : 0;
if (argc <= 1 || pflag) {
showvars( pflag ? argv[0] : 0, flag, pflag );
return 0;
}
argc -= optind;
argv += optind;
listsetvar(cmdenviron);
if (argc != 0) {
while ((name = *argptr++) != NULL) {
if ((p = strchr(name, '=')) != NULL) {
p++;
} else {
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;
}
}
}
setvar(name, p, flag);
found:;
}
} else {
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');
}
while ((name = *argptr++) != NULL) {
if ((p = strchr(name, '=')) != NULL) {
p++;
} else {
vp = find_var(name, NULL, NULL);
if (vp != NULL) {
vp->flags |= flag;
continue;
}
}
setvar(name, p, flag);
}
return 0;
}
@ -601,28 +604,28 @@ found:;
*/
int
localcmd(int argc __unused, char **argv __unused)
localcmd(int argc, char **argv)
{
char *name;
if (! in_function())
error("Not in a function");
while ((name = *argptr++) != NULL) {
mklocal(name);
mklocal(name, 0);
}
return 0;
}
/*
* Make a variable a local variable. When a variable is made local, it's
* Make a variable a local variable. When a variable is made local, its
* value and flags are saved in a localvar structure. The saved values
* will be restored when the shell function returns. We handle the name
* "-" as a special case.
*/
void
mklocal(char *name)
mklocal(const char *name, int flags)
{
struct localvar *lvp;
struct var **vpp;
@ -631,17 +634,17 @@ mklocal(char *name)
INTOFF;
lvp = ckmalloc(sizeof (struct localvar));
if (name[0] == '-' && name[1] == '\0') {
lvp->text = ckmalloc(sizeof optlist);
memcpy(lvp->text, optlist, sizeof optlist);
char *p;
p = ckmalloc(sizeof_optlist);
lvp->text = memcpy(p, optlist, sizeof_optlist);
vp = NULL;
} else {
vpp = hashvar(name);
for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next);
vp = find_var(name, &vpp, NULL);
if (vp == NULL) {
if (strchr(name, '='))
setvareq(savestr(name), VSTRFIXED);
setvareq(savestr(name), VSTRFIXED|flags);
else
setvar(name, NULL, VSTRFIXED);
setvar(name, NULL, VSTRFIXED|flags);
vp = *vpp; /* the new variable */
lvp->text = NULL;
lvp->flags = VUNSET;
@ -649,8 +652,8 @@ mklocal(char *name)
lvp->text = vp->text;
lvp->flags = vp->flags;
vp->flags |= VSTRFIXED|VTEXTFIXED;
if (strchr(name, '='))
setvareq(savestr(name), 0);
if (name[vp->name_len] == '=')
setvareq(savestr(name), flags);
}
}
lvp->vp = vp;
@ -673,12 +676,15 @@ poplocalvars(void)
while ((lvp = localvars) != NULL) {
localvars = lvp->next;
vp = lvp->vp;
TRACE(("poplocalvar %s", vp ? vp->text : "-"));
if (vp == NULL) { /* $- saved */
memcpy(optlist, lvp->text, sizeof optlist);
memcpy(optlist, lvp->text, sizeof_optlist);
ckfree(lvp->text);
} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
(void)unsetvar(vp->text);
(void)unsetvar(vp->text, 0);
} else {
if (vp->func && (vp->flags & VNOFUNC) == 0)
(*vp->func)(lvp->text + vp->name_len + 1);
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
vp->flags = lvp->flags;
@ -709,7 +715,7 @@ setvarcmd(int argc, char **argv)
*/
int
unsetcmd(int argc __unused, char **argv __unused)
unsetcmd(int argc, char **argv)
{
char **ap;
int i;
@ -717,11 +723,11 @@ unsetcmd(int argc __unused, char **argv __unused)
int flg_var = 0;
int ret = 0;
while ((i = nextopt("vf")) != '\0') {
while ((i = nextopt("evf")) != '\0') {
if (i == 'f')
flg_func = 1;
else
flg_var = 1;
flg_var = i;
}
if (flg_func == 0 && flg_var == 0)
flg_var = 1;
@ -730,7 +736,7 @@ unsetcmd(int argc __unused, char **argv __unused)
if (flg_func)
ret |= unsetfunc(*ap);
if (flg_var)
ret |= unsetvar(*ap);
ret |= unsetvar(*ap, flg_var == 'e');
}
return ret;
}
@ -741,58 +747,38 @@ unsetcmd(int argc __unused, char **argv __unused)
*/
int
unsetvar(char *s)
unsetvar(const char *s, int unexport)
{
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')
setvar(s, nullstr, 0);
if ((vp->flags & VEXPORT) && localevar(vp->text)) {
unsetenv(s);
setlocale(LC_ALL, "");
}
vp->flags &= ~VEXPORT;
vp->flags |= VUNSET;
if ((vp->flags & VSTRFIXED) == 0) {
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
*vpp = vp->next;
ckfree(vp);
}
INTON;
return (0);
vp = find_var(s, &vpp, NULL);
if (vp == NULL)
return 0;
if (vp->flags & VREADONLY)
return 1;
INTOFF;
if (unexport) {
vp->flags &= ~VEXPORT;
} else {
if (vp->text[vp->name_len + 1] != '\0')
setvar(s, nullstr, 0);
vp->flags &= ~VEXPORT;
vp->flags |= VUNSET;
if ((vp->flags & VSTRFIXED) == 0) {
if ((vp->flags & VTEXTFIXED) == 0)
ckfree(vp->text);
*vpp = vp->next;
ckfree(vp);
}
}
return (0);
INTON;
return 0;
}
/*
* Find the appropriate entry in the hash table from the name.
*/
STATIC struct var **
hashvar(char *p)
{
unsigned int hashval;
hashval = ((unsigned char) *p) << 4;
while (*p && *p != '=')
hashval += (unsigned char) *p++;
return &vartab[hashval % VTABSIZE];
}
/*
* Returns true if the two strings specify the same varable. The first
* variable name is terminated by '='; the second may be terminated by
@ -800,7 +786,7 @@ hashvar(char *p)
*/
STATIC int
varequal(char *p, char *q)
strequal(const char *p, const char *q)
{
while (*p == *q++) {
if (*p++ == '=')
@ -812,5 +798,39 @@ varequal(char *p, char *q)
}
/*
* $PchId: var.c,v 1.5 2006/05/22 12:28:49 philip Exp $
* Search for a variable.
* 'name' may be terminated by '=' or a NUL.
* vppp is set to the pointer to vp, or the list head if vp isn't found
* lenp is set to the number of charactets in 'name'
*/
STATIC struct var *
find_var(const char *name, struct var ***vppp, int *lenp)
{
unsigned int hashval;
int len;
struct var *vp, **vpp;
const char *p = name;
hashval = 0;
while (*p && *p != '=')
hashval = 2 * hashval + (unsigned char)*p++;
len = p - name;
if (lenp)
*lenp = len;
vpp = &vartab[hashval % VTABSIZE];
if (vppp)
*vppp = vpp;
for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) {
if (vp->name_len != len)
continue;
if (memcmp(vp->text, name, len) != 0)
continue;
if (vppp)
*vppp = vpp;
return vp;
}
return NULL;
}

View file

@ -1,3 +1,5 @@
/* $NetBSD: var.h,v 1.25 2011/06/18 21:18:46 christos Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
@ -13,7 +15,7 @@
* 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
* 3. 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.
*
@ -30,7 +32,6 @@
* SUCH DAMAGE.
*
* @(#)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 $
*/
/*
@ -40,17 +41,19 @@
/* flags */
#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 VSTRFIXED 0x04 /* variable struct is statically allocated */
#define VTEXTFIXED 0x08 /* text is statically 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 */
#define VNOSET 0x80 /* do not set variable - just readonly test */
struct var {
struct var *next; /* next entry in hash list */
int flags; /* flags are defined above */
char *text; /* name=value */
int name_len; /* length of name */
void (*func)(const char *);
/* function to be called when */
/* the variable gets set/unset */
@ -65,17 +68,21 @@ struct localvar {
};
struct localvar *localvars;
extern 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;
#ifndef NO_HISTORY
extern struct var vps4;
#ifndef SMALL
extern struct var vterm;
extern struct var vtermcap;
extern struct var vhistsize;
#endif
@ -92,33 +99,31 @@ extern struct var vhistsize;
#define pathval() (vpath.text + 5)
#define ps1val() (vps1.text + 4)
#define ps2val() (vps2.text + 4)
#define pseval() (vpse.text + 4)
#define ps4val() (vps4.text + 4)
#define optindval() (voptind.text + 7)
#ifndef NO_HISTORY
#ifndef SMALL
#define histsizeval() (vhistsize.text + 9)
#define termval() (vterm.text + 5)
#endif
#if ATTY
#define attyset() ((vatty.flags & VUNSET) == 0)
#endif
#define mpathset() ((vmpath.flags & VUNSET) == 0)
void initvar(void);
void setvar(char *, char *, int);
void setvar(const char *, const char *, int);
void setvareq(char *, int);
struct strlist;
void listsetvar(struct strlist *);
char *lookupvar(char *);
char *bltinlookup(char *, int);
void listsetvar(struct strlist *, int);
char *lookupvar(const char *);
char *bltinlookup(const char *, int);
char **environment(void);
void shprocvar(void);
int showvarscmd(int, char **);
int exportcmd(int, char **);
int localcmd(int, char **);
void mklocal(char *);
int showvars(const char *, int, int);
void mklocal(const char *, int);
void listmklocal(struct strlist *, int);
void poplocalvars(void);
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 $
*/
int unsetvar(const char *, int);
int setvarsafe(const char *, const char *, int);
void print_quoted(const char *);

View file

@ -2214,14 +2214,14 @@
./usr/Makefile minix-sys
./usr/man minix-sys
./usr/man/man1 minix-sys
./usr/man/man1/..1 minix-sys
./usr/man/man1/..1 minix-sys obsolete
./usr/man/man1/[.1 minix-sys
./usr/man/man1/addr2line.1 minix-sys binutils
./usr/man/man1/apropos.1 minix-sys
./usr/man/man1/ar.1 minix-sys binutils
./usr/man/man1/as.1 minix-sys binutils
./usr/man/man1/asa.1 minix-sys
./usr/man/man1/ash.1 minix-sys
./usr/man/man1/ash.1 minix-sys obsolete
./usr/man/man1/at.1 minix-sys
./usr/man/man1/atf2kyua.1 minix-sys kyua
./usr/man/man1/atf-check.1 minix-sys atf
@ -2235,7 +2235,7 @@
./usr/man/man1/banner.1 minix-sys
./usr/man/man1/basename.1 minix-sys
./usr/man/man1/bdes.1 minix-sys
./usr/man/man1/break.1 minix-sys
./usr/man/man1/break.1 minix-sys obsolete
./usr/man/man1/bsdtar.1 minix-sys
./usr/man/man1/bsfilt.1 minix-sys
./usr/man/man1/bunzip2.1 minix-sys
@ -2245,12 +2245,12 @@
./usr/man/man1/c++.1 minix-sys gcccmds
./usr/man/man1/cal.1 minix-sys
./usr/man/man1/calendar.1 minix-sys
./usr/man/man1/case.1 minix-sys
./usr/man/man1/case.1 minix-sys obsolete
./usr/man/man1/cat.1 minix-sys
./usr/man/man1/cawf.1 minix-sys
./usr/man/man1/cc.1 minix-sys gcccmds
./usr/man/man1/cccp.1 minix-sys gcccmds
./usr/man/man1/cd.1 minix-sys
./usr/man/man1/cd.1 minix-sys obsolete
./usr/man/man1/c++filt.1 minix-sys binutils
./usr/man/man1/checknr.1 minix-sys
./usr/man/man1/chfn.1 minix-sys
@ -2268,9 +2268,9 @@
./usr/man/man1/colrm.1 minix-sys
./usr/man/man1/column.1 minix-sys
./usr/man/man1/comm.1 minix-sys
./usr/man/man1/command.1 minix-sys
./usr/man/man1/command.1 minix-sys obsolete
./usr/man/man1/compress.1 minix-sys
./usr/man/man1/continue.1 minix-sys
./usr/man/man1/continue.1 minix-sys obsolete
./usr/man/man1/cp.1 minix-sys
./usr/man/man1/cpio.1 minix-sys
./usr/man/man1/cpp.1 minix-sys gcccmds
@ -2296,12 +2296,12 @@
./usr/man/man1/eject.1 minix-sys
./usr/man/man1/elfedit.1 minix-sys binutils
./usr/man/man1/env.1 minix-sys
./usr/man/man1/eval.1 minix-sys
./usr/man/man1/eval.1 minix-sys obsolete
./usr/man/man1/ex.1 minix-sys
./usr/man/man1/exec.1 minix-sys
./usr/man/man1/exit.1 minix-sys
./usr/man/man1/exec.1 minix-sys obsolete
./usr/man/man1/exit.1 minix-sys obsolete
./usr/man/man1/expand.1 minix-sys
./usr/man/man1/export.1 minix-sys
./usr/man/man1/export.1 minix-sys obsolete
./usr/man/man1/expr.1 minix-sys
./usr/man/man1/false.1 minix-sys
./usr/man/man1/fetch.1 minix-sys
@ -2312,7 +2312,7 @@
./usr/man/man1/flex.1 minix-sys
./usr/man/man1/flexdoc.1 minix-sys
./usr/man/man1/fold.1 minix-sys
./usr/man/man1/for.1 minix-sys
./usr/man/man1/for.1 minix-sys obsolete
./usr/man/man1/format.1 minix-sys
./usr/man/man1/fpr.1 minix-sys
./usr/man/man1/from.1 minix-sys
@ -2325,7 +2325,7 @@
./usr/man/man1/gcpp.1 minix-sys gcccmds
./usr/man/man1/genassym.1 minix-sys
./usr/man/man1/getopt.1 minix-sys
./usr/man/man1/getopts.1 minix-sys
./usr/man/man1/getopts.1 minix-sys obsolete
./usr/man/man1/gprof.1 minix-sys binutils
./usr/man/man1/grep.1 minix-sys
./usr/man/man1/groups.1 minix-sys
@ -2333,14 +2333,14 @@
./usr/man/man1/gzcat.1 minix-sys
./usr/man/man1/gzexe.1 minix-sys
./usr/man/man1/gzip.1 minix-sys
./usr/man/man1/hash.1 minix-sys
./usr/man/man1/hash.1 minix-sys obsolete
./usr/man/man1/head.1 minix-sys
./usr/man/man1/hexdump.1 minix-sys
./usr/man/man1/host.1 minix-sys
./usr/man/man1/hostaddr.1 minix-sys
./usr/man/man1/hostname.1 minix-sys
./usr/man/man1/id.1 minix-sys
./usr/man/man1/if.1 minix-sys
./usr/man/man1/if.1 minix-sys obsolete
./usr/man/man1/ifdef.1 minix-sys
./usr/man/man1/indent.1 minix-sys
./usr/man/man1/info.1 minix-sys
@ -2351,7 +2351,7 @@
./usr/man/man1/isodir.1 minix-sys
./usr/man/man1/isoinfo.1 minix-sys
./usr/man/man1/isoread.1 minix-sys
./usr/man/man1/jobs.1 minix-sys
./usr/man/man1/jobs.1 minix-sys obsolete
./usr/man/man1/join.1 minix-sys
./usr/man/man1/jot.1 minix-sys
./usr/man/man1/kill.1 minix-sys
@ -2384,7 +2384,7 @@
./usr/man/man1/ln.1 minix-sys
./usr/man/man1/loadfont.1 minix-sys
./usr/man/man1/loadkeys.1 minix-sys
./usr/man/man1/local.1 minix-sys
./usr/man/man1/local.1 minix-sys obsolete
./usr/man/man1/lock.1 minix-sys
./usr/man/man1/logger.1 minix-sys
./usr/man/man1/login.1 minix-sys
@ -2454,13 +2454,13 @@
./usr/man/man1/pwhash.1 minix-sys
./usr/man/man1/ranlib.1 minix-sys binutils
./usr/man/man1/rcp.1 minix-sys
./usr/man/man1/read.1 minix-sys
./usr/man/man1/read.1 minix-sys obsolete
./usr/man/man1/readelf.1 minix-sys binutils
./usr/man/man1/readlink.1 minix-sys
./usr/man/man1/readonly.1 minix-sys
./usr/man/man1/readonly.1 minix-sys obsolete
./usr/man/man1/recwave.1 minix-sys
./usr/man/man1/remsync.1 minix-sys
./usr/man/man1/return.1 minix-sys
./usr/man/man1/return.1 minix-sys obsolete
./usr/man/man1/rev.1 minix-sys
./usr/man/man1/rget.1 minix-sys
./usr/man/man1/rlogin.1 minix-sys
@ -2472,12 +2472,12 @@
./usr/man/man1/sdiff.1 minix-sys
./usr/man/man1/sed.1 minix-sys
./usr/man/man1/seq.1 minix-sys
./usr/man/man1/set.1 minix-sys
./usr/man/man1/setvar.1 minix-sys
./usr/man/man1/set.1 minix-sys obsolete
./usr/man/man1/setvar.1 minix-sys obsolete
./usr/man/man1/sh.1 minix-sys
./usr/man/man1/sha1.1 minix-sys
./usr/man/man1/shar.1 minix-sys
./usr/man/man1/shift.1 minix-sys
./usr/man/man1/shift.1 minix-sys obsolete
./usr/man/man1/shlock.1 minix-sys
./usr/man/man1/shuffle.1 minix-sys
./usr/man/man1/size.1 minix-sys binutils
@ -2514,13 +2514,13 @@
./usr/man/man1/touch.1 minix-sys
./usr/man/man1/tput.1 minix-sys
./usr/man/man1/tr.1 minix-sys
./usr/man/man1/trap.1 minix-sys
./usr/man/man1/trap.1 minix-sys obsolete
./usr/man/man1/true.1 minix-sys
./usr/man/man1/truncate.1 minix-sys
./usr/man/man1/tsort.1 minix-sys
./usr/man/man1/tty.1 minix-sys
./usr/man/man1/ul.1 minix-sys
./usr/man/man1/umask.1 minix-sys
./usr/man/man1/umask.1 minix-sys obsolete
./usr/man/man1/umount.1 minix-sys
./usr/man/man1/uname.1 minix-sys
./usr/man/man1/uncompress.1 minix-sys
@ -2530,7 +2530,7 @@
./usr/man/man1/uniq.1 minix-sys
./usr/man/man1/units.1 minix-sys
./usr/man/man1/unlzma.1 minix-sys
./usr/man/man1/unset.1 minix-sys
./usr/man/man1/unset.1 minix-sys obsolete
./usr/man/man1/unvis.1 minix-sys
./usr/man/man1/unxz.1 minix-sys
./usr/man/man1/unzip.1 minix-sys
@ -2544,7 +2544,7 @@
./usr/man/man1/vis.1 minix-sys
./usr/man/man1/vol.1 minix-sys
./usr/man/man1/w.1 minix-sys
./usr/man/man1/wait.1 minix-sys
./usr/man/man1/wait.1 minix-sys obsolete
./usr/man/man1/wall.1 minix-sys
./usr/man/man1/wc.1 minix-sys
./usr/man/man1/what.1 minix-sys
@ -5249,6 +5249,15 @@
./usr/share/doc/psd/19.curses/twinkle1.c minix-sys
./usr/share/doc/psd/19.curses/twinkle2.c minix-sys
./usr/share/doc/psd/19.curses/win_st.c minix-sys
./usr/share/doc/usd minix-sys
./usr/share/doc/usd/03.shell minix-sys
./usr/share/doc/usd/03.shell/Makefile minix-sys
./usr/share/doc/usd/03.shell/Rv7man minix-sys
./usr/share/doc/usd/03.shell/t1 minix-sys
./usr/share/doc/usd/03.shell/t2 minix-sys
./usr/share/doc/usd/03.shell/t3 minix-sys
./usr/share/doc/usd/03.shell/t4 minix-sys
./usr/share/doc/usd/03.shell/t.mac minix-sys
./usr/share/examples minix-sys atf
./usr/share/examples/atf minix-sys atf
./usr/share/examples/atf/atf-run.hooks minix-sys atf,!kyua

View file

@ -114,6 +114,8 @@
./usr/share/doc/html/bzip2
./usr/share/doc/psd
./usr/share/doc/psd/19.curses
./usr/share/doc/usd
./usr/share/doc/usd/03.shell
./usr/share/info
./usr/share/games
./usr/share/games/fortune

View file

@ -2,6 +2,7 @@
# Activate emacs keybindings and command line history support
set -o emacs
set -o tabcomplete
# Set the default path
PATH=/usr/local/bin:/usr/pkg/bin:/usr/bin:/bin:/usr/games

View file

@ -2,7 +2,7 @@
.include <bsd.own.mk>
SUBDIR= add_route arp ash at backup btrace \
SUBDIR= add_route arp at backup btrace \
cawf cdprobe \
ci cleantmp cmp co \
compress crc cron crontab \

View file

@ -1,101 +0,0 @@
# Makefile for ash.
.include <bsd.own.mk>
PROG= sh
BINDIR= /bin
MAN=
# Enable this line to disable command line editing
#EDIT=-DNO_HISTORY
# Enable this line if your system does not have a <paths.h>
#NO_PATHS_H=-DNO_PATHS_H
# Enable this if you don't want job control
NO_JOBS=-DJOBS=0
MKB_NO_JOBS=-j
SRCS= alias.c arith.y arith_lex.l cd.c complete.c eval.c exec.c expand.c \
histedit.c input.c jobs.c mail.c main.c memalloc.c miscbltin.c \
mystring.c options.c output.c parser.c redir.c show.c \
trap.c var.c setmode.c
.include "${.CURDIR}/bltin/Makefile.inc"
GENSRCS= builtins.c init.c nodes.c syntax.c operators.c signames.c
GENHDRS= builtins.h nodes.h syntax.h token.h operators.h signames.h
SRCS+= ${GENSRCS}
CLEANFILES+=${GENSRCS} ${GENHDRS}
DPADD+= ${LIBL} ${LIBEDIT}
LDADD+= -ll -ledit
CPPFLAGS+= -DSHELL
CPPFLAGS+=${EDIT} ${NO_PATHS_H} ${NO_JOBS}
CPPFLAGS+= -I. -I${.CURDIR}
# A. Generate C tools used to build ash
.for tool in init nodes signames syntax
${.OBJDIR}/mk${tool}: ${.CURDIR}/mk${tool}.c
${HOST_CC} ${HOST_CFLAGS} ${HOST_CPPFLAGS} ${.ALLSRC} -o ${.TARGET}
CLEANFILES+= ${.OBJDIR}/mk${tool}
.endfor
# B. Generates C sources from C tools
NODES_ARGS:= ${.CURDIR}/nodetypes ${.CURDIR}/nodes.c.pat
INIT_ARGS:= alias.c eval.c exec.c input.c jobs.c options.c parser.c \
redir.c trap.c var.c
.for tool in nodes signames syntax
${tool}.c ${tool}.h: ${.OBJDIR}/mk${tool}
${.OBJDIR}/mk${tool} ${${tool:tu}_ARGS}
.endfor
init.c: ${.OBJDIR}/mkinit \
alias.c eval.c exec.c input.c jobs.c options.c parser.c \
redir.c trap.c var.c
${.OBJDIR}/mkinit ${.ALLSRC:S,^${.OBJDIR}/mkinit$,,}
# C. Generates C sources from shell scripts
token.h:
${.CURDIR}/mktokens.sh
builtins.c builtins.h:
${.CURDIR}/mkbuiltins.sh ${MKB_NO_JOBS} . ${.CURDIR}/shell.h ${.CURDIR}/builtins.def
operators.c operators.h:
${.CURDIR}/bltin/mkexpr.sh ${.CURDIR}/bltin/unary_op ${.CURDIR}/bltin/binary_op
# D. Generates sources from yacc/lex
LFLAGS= -8 # 8-bit lex scanner for arithmetic
YFLAGS:= -d
CLEANFILES+= arith.h arith.y.o
parser.c: token.h
y.tab.h: arith.y
arith.h: y.tab.h
arith_lex.l: arith.h
# Explicit dependencies to ensure creation when needed
# LSC FIXME Under MINIX, the build system curiously needs more help.
# is it because of the missing order tools?
expand.c: arith.h
trap.c: signames.h
cd.c complete.c eval.c exec.c expand.c jobs.c main.c options.c parser.c redir.c show.c trap.c var.c: nodes.h
eval.c exec.c expand.c input.c input.h jobs.c mystring.c output.c parser.c trap.c var.c: syntax.h
cd.c eval.c exec.c histedit.cjobs.c main.c miscbltin.c options.c trap.c var.c: builtins.h
# LSC: Seems that this file is implicitly taken into account by NetBSD's make,
# still seems to be ignored / not found currently.
# It's a sad story, as it has default rules to manage yacc / lex files. So for
# a happy ending here it is explicitly included:
.include <sys.mk>
.include <bsd.prog.mk>

View file

@ -1,360 +0,0 @@
%{
/*-
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD: src/bin/sh/arith.y,v 1.19 2004/05/24 10:11:31 stefanf Exp $");
*/
#include <limits.h>
#include <stdio.h>
#include "shell.h"
#include "expand.h"
#include "var.h"
%}
%union {
arith_t l_value;
char* s_value;
}
%token <l_value> ARITH_NUM ARITH_LPAREN ARITH_RPAREN
%token <s_value> ARITH_VAR
%type <l_value> 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"
#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 <stdio.h>
main(int argc, char *argv[])
{
printf("%d\n", exp(argv[1]));
}
error(char *s)
{
fprintf(stderr, "exp: %s\n", s);
exit(1);
}
#endif

View file

@ -1,12 +0,0 @@
/*
arith_lex.h
Created: July 1995 by Philip Homburg <philip@cs.vu.nl>
*/
int yylex(void);
void arith_lex_reset(void);
/*
* $PchId: arith_lex.h,v 1.1 2001/05/18 19:57:55 philip Exp $
*/

View file

@ -1,40 +0,0 @@
ASH GENERAL PUBLIC LICENSE
1. You may copy and distribute ash code or code derived from it in
source or object form, provided that you conspicuously and appropriately
publish on each copy a valid copyright notice "Copyright 1989 by Kenneth
Almquist." (or with whatever year is appropriate); keep intact the
notices on all files that refer to this License Agreement and to the
absence of any warranty; and give any other recipients of the ash program
a copy of this License Agreement along with the program.
2. You may not copy, sublicense, distribute or transfer ash except as
expressly provided under this License Agreement. Any attempt otherwise
to copy, sublicense, distribute or transfer ash is void and your rights
to use ash under this License agreement shall be automatically terminated.
However, parties who have received computer software programs from you
with this License Agreement will not have their licenses terminated so
long as such parties remain in full compliance.
NO WARRANTY
Because ash is licensed free of charge, I provide absolutely no
warranty, to the extent permitted by applicable state law. Except
when otherwise stated in writing, Kenneth Almquist and/or other
parties provide ash "as is" without warranty of any kind, either
expressed or implied, including, but not limited to, the implied
warranties of merchantability and fitness for a particular purpose.
The entire risk as to the quality and performance of the program is
with you. Should the ash program prove defective, you assume the cost
of all necessary servicing, repair or correction.
In no event unless required by applicable law will Kenneth Almquist
and/or any other party who may modify and redistribute ash as permitted
above, be liable to you for damages, including any lost profits, lost
monies, or other special, incidental or consequential damages arising
out of the use or inability to use (including but not limited to loss
of data or data being rendered inaccurate or losses sustained by third
parties or a failure of the program to operate with programs provided
by other parties) the program, even if you have been advised of the
possibility of such damages, or for any claim by any other party.

View file

@ -1,7 +0,0 @@
.PATH: ${.CURDIR}/bltin
SRCS+= echo.c error.c expr.c regexp.c
# LSC Again nbmake seems dumber on MINIX...
expr.c: operators.h

View file

@ -1,27 +0,0 @@
# List of binary operators used by test/expr.
#
# Copyright 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.
OR1 -o 1
OR2 | 1
AND1 -a 2
AND2 & 2
STREQ = 4 OP_STRING
STRNE != 4 OP_STRING
NEWER -newer 4 OP_STRING
NEWER -nt 4 OP_STRING
OLDER -ot 4 OP_STRING
EQ -eq 4 OP_INT
NE -ne 4 OP_INT
GT -gt 4 OP_INT
LT -lt 4 OP_INT
LE -le 4 OP_INT
GE -ge 4 OP_INT
PLUS + 5 OP_INT
MINUS - 5 OP_INT
TIMES * 6 OP_INT
DIVIDE / 6 OP_INT
REM % 6 OP_INT
MATCHPAT : 7 OP_STRING

View file

@ -1,88 +0,0 @@
/*
* Copy the files given as arguments to the standard output. The file
* name "-" refers to the standard input.
*
* 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.
*/
#define main catfcmd
#include "bltin.h"
#include "../error.h"
#include <sys/param.h>
#include <fcntl.h>
#ifdef SBUFSIZE
#define BUFSIZE() SBUFSIZE
#else
#ifdef MAXBSIZE
#define BUFSIZE() MAXBSIZE
#else
#define BUFSIZE() BSIZE
#endif
#endif
main(argc, argv) char **argv; {
char *filename;
char *buf = stalloc(BUFSIZE());
int fd;
int i;
#ifdef SHELL
volatile int input;
struct jmploc jmploc;
struct jmploc *volatile savehandler;
#endif
INITARGS(argv);
#ifdef SHELL
input = -1;
if (setjmp(jmploc.loc)) {
close(input);
handler = savehandler;
longjmp(handler, 1);
}
savehandler = handler;
handler = &jmploc;
#endif
while ((filename = *++argv) != NULL) {
if (filename[0] == '-' && filename[1] == '\0') {
fd = 0;
} else {
#ifdef SHELL
INTOFF;
if ((fd = open(filename, O_RDONLY)) < 0)
error("Can't open %s", filename);
input = fd;
INTON;
#else
if ((fd = open(filename, O_RDONLY)) < 0) {
fprintf(stderr, "catf: Can't open %s\n", filename);
exit(2);
}
#endif
}
while ((i = read(fd, buf, BUFSIZE())) > 0) {
#ifdef SHELL
if (out1 == &memout) {
register char *p;
for (p = buf ; --i >= 0 ; p++) {
outc(*p, &memout);
}
} else {
write(1, buf, i);
}
#else
write(1, buf, i);
#endif
}
if (fd != 0)
close(fd);
}
#ifdef SHELL
handler = savehandler;
#endif
}

View file

@ -1,23 +0,0 @@
/*
* 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 <stdio.h>
char *commandname;
void
#ifdef __STDC__
error(char *msg, ...) {
#else
error(msg)
char *msg;
{
#endif
fprintf(stderr, "%s: %s\n", commandname, msg);
exit(2);
}

View file

@ -1,482 +0,0 @@
/*
* The expr and test commands.
*
* 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 "bltin.h"
#include "operators.h"
#include <regex.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#define STACKSIZE 12
#define NESTINCR 16
/* data types */
#define STRING 0
#define INTEGER 1
#define BOOLEAN 2
/*
* This structure hold a value. The type keyword specifies the type of
* the value, and the union u holds the value. The value of a boolean
* is stored in u.num (1 = TRUE, 0 = FALSE).
*/
struct value {
int type;
union {
char *string;
long num;
} u;
};
struct operator {
short op; /* which operator */
short pri; /* priority of operator */
};
struct filestat {
char *name; /* name of file */
int rcode; /* return code from stat */
struct stat stat; /* status info on file */
};
extern char *match_begin[10]; /* matched string */
extern short match_length[10]; /* defined in regexp.c */
extern short number_parens; /* number of \( \) pairs */
#ifdef __STDC__
static int expr_is_false(struct value *);
static void expr_operator(int, struct value *, struct filestat *);
static int lookup_op(char *, char *const*);
#else
static int expr_is_false();
static void expr_operator();
static int lookup_op();
#endif
int exprcmd(argc, argv) int argc; char **argv; {
char **ap;
char *opname;
char c;
char *p;
int print;
int nest; /* parenthises nesting */
int op;
int pri;
int skipping;
int binary;
struct operator opstack[STACKSIZE];
struct operator *opsp;
struct value valstack[STACKSIZE + 1];
struct value *valsp;
struct filestat fs;
INITARGS(argv);
c = **argv;
print = 1;
if (c == 't')
print = 0;
else if (c == '[') {
if (! equal(argv[argc - 1], "]"))
error("missing ]");
argv[argc - 1] = NULL;
print = 0;
}
ap = argv + 1;
fs.name = NULL;
/*
* We use operator precedence parsing, evaluating the expression
* as we parse it. Parentheses are handled by bumping up the
* priority of operators using the variable "nest." We use the
* variable "skipping" to turn off evaluation temporarily for the
* short circuit boolean operators. (It is important do the short
* circuit evaluation because under NFS a stat operation can take
* infinitely long.)
*/
nest = 0;
skipping = 0;
opsp = opstack + STACKSIZE;
valsp = valstack;
if (*ap == NULL) {
valstack[0].type = BOOLEAN;
valstack[0].u.num = 0;
goto done;
}
for (;;) {
opname = *ap++;
if (opname == NULL)
syntax: error("syntax error");
if (opname[0] == '(' && opname[1] == '\0') {
nest += NESTINCR;
continue;
} else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
if (opsp == &opstack[0])
overflow: error("Expression too complex");
--opsp;
opsp->op = op;
opsp->pri = op_priority[op] + nest;
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++;
}
for (;;) {
opname = *ap++;
if (opname == NULL) {
if (nest != 0)
goto syntax;
pri = 0;
break;
}
if (opname[0] != ')' || opname[1] != '\0') {
if ((op = lookup_op(opname, binary_op)) < 0)
goto syntax;
op += FIRST_BINARY_OP;
pri = op_priority[op] + nest;
break;
}
if ((nest -= NESTINCR) < 0)
goto syntax;
}
while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
binary = opsp->op;
for (;;) {
valsp--;
c = op_argflag[opsp->op];
if (c == OP_INT) {
if (valsp->type == STRING)
valsp->u.num = atol(valsp->u.string);
valsp->type = INTEGER;
} else if (c >= OP_STRING) { /* OP_STRING or OP_FILE */
if (valsp->type == INTEGER) {
p = stalloc(32);
#ifdef SHELL
fmtstr(p, 32, "%ld", valsp->u.num);
#else
sprintf(p, "%d", valsp->u.num);
#endif
valsp->u.string = p;
} else if (valsp->type == BOOLEAN) {
if (valsp->u.num)
valsp->u.string = "true";
else
valsp->u.string = "";
}
valsp->type = STRING;
if (c == OP_FILE
&& (fs.name == NULL
|| ! equal(fs.name, valsp->u.string))) {
fs.name = valsp->u.string;
fs.rcode = stat(valsp->u.string, &fs.stat);
}
}
if (binary < FIRST_BINARY_OP)
break;
binary = 0;
}
if (! skipping)
expr_operator(opsp->op, valsp, &fs);
else if (opsp->op == AND1 || opsp->op == OR1)
skipping--;
valsp++; /* push value */
opsp++; /* pop operator */
}
if (opname == NULL)
break;
if (opsp == &opstack[0])
goto overflow;
if (op == AND1 || op == AND2) {
op = AND1;
if (skipping || expr_is_false(valsp - 1))
skipping++;
}
if (op == OR1 || op == OR2) {
op = OR1;
if (skipping || ! expr_is_false(valsp - 1))
skipping++;
}
opsp--;
opsp->op = op;
opsp->pri = pri;
}
done:
if (print) {
if (valstack[0].type == STRING)
printf("%s\n", valstack[0].u.string);
else if (valstack[0].type == INTEGER)
printf("%ld\n", valstack[0].u.num);
else if (valstack[0].u.num != 0)
printf("true\n");
}
return expr_is_false(&valstack[0]);
}
static int
expr_is_false(val)
struct value *val;
{
if (val->type == STRING) {
if (val->u.string[0] == '\0')
return 1;
} else { /* INTEGER or BOOLEAN */
if (val->u.num == 0)
return 1;
}
return 0;
}
/*
* Execute an operator. Op is the operator. Sp is the stack pointer;
* sp[0] refers to the first operand, sp[1] refers to the second operand
* (if any), and the result is placed in sp[0]. The operands are converted
* to the type expected by the operator before expr_operator is called.
* Fs is a pointer to a structure which holds the value of the last call
* to stat, to avoid repeated stat calls on the same file.
*/
static void
expr_operator(op, sp, fs)
int op;
struct value *sp;
struct filestat *fs;
{
int i, r;
struct stat st1, st2;
regex_t pat;
regmatch_t rm[2];
switch (op) {
case NOT:
sp->u.num = expr_is_false(sp);
sp->type = BOOLEAN;
break;
case EXISTS:
if (fs->rcode >= 0) goto true;
goto false;
case ISREAD:
i = 04;
goto permission;
case ISWRITE:
i = 02;
goto permission;
case ISEXEC:
i = 01;
permission:
if (fs->stat.st_uid == geteuid())
i <<= 6;
else if (fs->stat.st_gid == getegid())
i <<= 3;
goto filebit; /* true if (stat.st_mode & i) != 0 */
case ISFILE:
i = S_IFREG;
goto filetype;
case ISDIR:
i = S_IFDIR;
goto filetype;
case ISCHAR:
i = S_IFCHR;
goto filetype;
case ISBLOCK:
i = S_IFBLK;
goto filetype;
case ISFIFO:
#ifdef S_IFIFO
i = S_IFIFO;
goto filetype;
#else
goto false;
#endif
filetype:
if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
true:
sp->u.num = 1;
} else {
false:
sp->u.num = 0;
}
sp->type = BOOLEAN;
break;
case ISSETUID:
i = S_ISUID;
goto filebit;
case ISSETGID:
i = S_ISGID;
goto filebit;
case ISSTICKY:
i = S_ISVTX;
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 OLDER:
case NEWER:
if (stat(sp->u.string, &st1) != 0) {
sp->u.num = 0;
} else if (stat((sp + 1)->u.string, &st2) != 0) {
sp->u.num = 1;
} else {
int isnewer = st1.st_mtime >= st2.st_mtime;
if(op == NEWER)
sp->u.num = isnewer;
else
sp->u.num = !isnewer;
}
sp->type = INTEGER;
break;
case ISTTY:
sp->u.num = isatty(sp->u.num);
sp->type = BOOLEAN;
break;
case NULSTR:
if (sp->u.string[0] == '\0')
goto true;
goto false;
case STRLEN:
sp->u.num = strlen(sp->u.string);
sp->type = INTEGER;
break;
case OR1:
case AND1:
/*
* These operators are mostly handled by the parser. If we
* get here it means that both operands were evaluated, so
* the value is the value of the second operand.
*/
*sp = *(sp + 1);
break;
case STREQ:
case STRNE:
i = 0;
if (equal(sp->u.string, (sp + 1)->u.string))
i++;
if (op == STRNE)
i = 1 - i;
sp->u.num = i;
sp->type = BOOLEAN;
break;
case EQ:
if (sp->u.num == (sp + 1)->u.num)
goto true;
goto false;
case NE:
if (sp->u.num != (sp + 1)->u.num)
goto true;
goto false;
case GT:
if (sp->u.num > (sp + 1)->u.num)
goto true;
goto false;
case LT:
if (sp->u.num < (sp + 1)->u.num)
goto true;
goto false;
case LE:
if (sp->u.num <= (sp + 1)->u.num)
goto true;
goto false;
case GE:
if (sp->u.num >= (sp + 1)->u.num)
goto true;
goto false;
case PLUS:
sp->u.num += (sp + 1)->u.num;
break;
case MINUS:
sp->u.num -= (sp + 1)->u.num;
break;
case TIMES:
sp->u.num *= (sp + 1)->u.num;
break;
case DIVIDE:
if ((sp + 1)->u.num == 0)
error("Division by zero");
sp->u.num /= (sp + 1)->u.num;
break;
case REM:
if ((sp + 1)->u.num == 0)
error("Division by zero");
sp->u.num %= (sp + 1)->u.num;
break;
case MATCHPAT:
{
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 = rm[0].rm_eo;
sp->type = INTEGER;
}
} else {
if (pat.re_nsub > 0) {
sp->u.string[0] = '\0';
} else {
sp->u.num = 0;
sp->type = INTEGER;
}
}
}
break;
}
}
static int
lookup_op(name, table)
char *name;
char *const*table;
{
register char *const*tp;
register char const *p;
char c = name[1];
for (tp = table ; (p = *tp) != NULL ; tp++) {
if (p[1] == c && equal(p, name))
return tp - table;
}
return -1;
}

View file

@ -1,27 +0,0 @@
/*
* The line command. Reads one line from the standard input and writes it
* to the standard output.
*
* 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.
*/
#define main linecmd
#include "bltin.h"
main(argc, argv) char **argv; {
char c;
for (;;) {
if (read(0, &c, 1) != 1) {
putchar('\n');
return 1;
}
putchar(c);
if (c == '\n')
return 0;
}
}

View file

@ -1,71 +0,0 @@
# 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.
LIBFILES=catfcmd.o echocmd.o exprcmd.o linecmd.o nlechocmd.o\
operators.o regexp.o
DEBUG=-g
CFLAGS=$(DEBUG)
#CC=gcc
all:$P bltinlib.a catf echo expr line nlecho true umask
bltinlib.a:$P $(LIBFILES)
ar rc $@ $(LIBFILES)
catf: catf.c bltin.h ../shell.h ../error.h error.o stalloc.o
$(CC) $(CFLAGS) -o $@ catf.c error.o stalloc.o
catfcmd.o: catf.c bltin.h ../shell.h ../error.h
$(CC) -DSHELL $(CFLAGS) -c catf.c
mv catf.o $@
expr: expr.c bltin.h ../shell.h operators.h operators.o regexp.o error.o stalloc.o
$(CC) $(CFLAGS) -o $@ expr.c operators.o regexp.o error.o stalloc.o
-rm -f test '['
ln expr test
ln expr '['
exprcmd.o: expr.c bltin.h ../shell.h operators.h
$(CC) -DSHELL $(CFLAGS) -c expr.c
mv expr.o $@
operators.c operators.h: unary_op binary_op mkexpr
./mkexpr
operators.o: ../shell.h operators.h
regexp.o: bltin.h ../shell.h
echo: echo.c bltin.h ../shell.h
$(CC) $(CFLAGS) -o $@ echo.c
echocmd.o: echo.c bltin.h ../shell.h
$(CC) -DSHELL $(CFLAGS) -c echo.c
mv echo.o $@
line: line.c bltin.h ../shell.h
$(CC) $(CFLAGS) -o $@ line.c
linecmd.o: line.c bltin.h ../shell.h
$(CC) -DSHELL $(CFLAGS) -c line.c
mv line.o $@
nlecho: nlecho.c bltin.h ../shell.h
$(CC) $(CFLAGS) -o $@ nlecho.c
nlechocmd.o: nlecho.c bltin.h ../shell.h
$(CC) -DSHELL $(CFLAGS) -c nlecho.c
mv nlecho.o $@
umask: umask.c bltin.h
$(CC) $(CFLAGS) -o $@ umask.c
true:
> :
chmod 755 :
rm -f true
ln : true
stalloc.o: ../shell.h

View file

@ -1,75 +0,0 @@
#!/bin/sh
# Copyright 1989 by Kenneth Almquist. All rights reserved.
#
# This file is part of ash. Ash is distributed under the terms specified
# by the Ash General Public License. See the file named LICENSE.
# All calls to awk removed, because Minix bawk is deficient. (kjb)
if [ $# -ne 2 ]
then
echo "Usage: $0 <unary_op> <binary_op>" >&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
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 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 */
extern char *const unary_op[];
extern char *const binary_op[];
extern const char op_priority[];
extern const char op_argflag[];'
exec > operators.c
echo '/*
* Operators used in the expr/test command.
*/
#include <stddef.h>
#include "shell.h"
#include "operators.h"
char *const unary_op[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
' "$unary_op"
echo ' NULL
};
char *const binary_op[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* \([^ ][^ ]*\).*/ "\1",/
' "$binary_op"
echo ' NULL
};
const char op_priority[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\).*/ \1,/
' "$unary_op" "$binary_op"
echo '};
const char op_argflag[] = {'
sed -e '/^[^#]/!d
s/[ ][ ]*/ /g
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]*$/& 0/
s/^[^ ][^ ]* [^ ][^ ]* [^ ][^ ]* \([^ ][^ ]*\)/ \1,/
' "$unary_op" "$binary_op"
echo '};'

View file

@ -1,8 +0,0 @@
/*
myregexp.h
Created: July 1995 by Philip Homburg <philip@cs.vu.nl>
*/
char *re_compile(char *pattern);
int re_match(char *pattern, char *string);

View file

@ -1,25 +0,0 @@
/*
* Echo the command argument to the standard output, one line at a time.
* This command is useful for debugging th shell and whenever you what
* to output strings literally.
*
* 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.
*/
#define main nlechocmd
#include "bltin.h"
main(argc, argv) char **argv; {
register char **ap;
for (ap = argv + 1 ; *ap ; ap++) {
fputs(*ap, stdout);
putchar('\n');
}
return 0;
}

View file

@ -1,301 +0,0 @@
/*
* Regular expression matching for expr(1). Bugs: The upper bound of
* a range specified by the \{ feature cannot be zero.
*
* 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 "bltin.h"
#include "myregexp.h"
#include <stdlib.h>
#define RE_END 0 /* end of regular expression */
#define RE_LITERAL 1 /* normal character follows */
#define RE_DOT 2 /* "." */
#define RE_CCL 3 /* "[...]" */
#define RE_NCCL 4 /* "[^...]" */
#define RE_LP 5 /* "\(" */
#define RE_RP 6 /* "\)" */
#define RE_MATCHED 7 /* "\digit" */
#define RE_EOS 8 /* "$" matches end of string */
#define RE_STAR 9 /* "*" */
#define RE_RANGE 10 /* "\{num,num\}" */
char *match_begin[10];
short match_length[10];
short number_parens;
static int match(char *pattern, char *string);
char *
re_compile(pattern)
char *pattern;
{
register char *p;
register char c;
char *comp;
register char *q;
char *begin;
char *endp;
register int len;
int first;
int type;
char *stackp;
char stack[10];
int paren_num;
int i;
p = pattern;
if (*p == '^')
p++;
comp = q = malloc(2 * strlen(p) + 1);
begin = q;
stackp = stack;
paren_num = 0;
for (;;) {
switch (c = *p++) {
case '\0':
*q = '\0';
goto out;
case '.':
*q++ = RE_DOT;
len = 1;
break;
case '[':
begin = q;
*q = RE_CCL;
if (*p == '^') {
*q = RE_NCCL;
p++;
}
q++;
first = 1;
while (*p != ']' || first == 1) {
if (p[1] == '-' && p[2] != ']') {
*q++ = '-';
*q++ = p[0];
*q++ = p[2];
p += 3;
} else if (*p == '-') {
*q++ = '-';
*q++ = '-';
*q++ = '-';
p++;
} else {
*q++ = *p++;
}
first = 0;
}
p++;
*q++ = '\0';
len = q - begin;
break;
case '$':
if (*p != '\0')
goto dft;
*q++ = RE_EOS;
break;
case '*':
if (len == 0)
goto dft;
type = RE_STAR;
range:
i = (type == RE_RANGE)? 3 : 1;
endp = q + i;
begin = q - len;
do {
--q;
*(q + i) = *q;
} while (--len > 0);
q = begin;
*q++ = type;
if (type == RE_RANGE) {
i = 0;
while ((unsigned)(*p - '0') <= 9)
i = 10 * i + (*p++ - '0');
*q++ = i;
if (*p != ',') {
*q++ = i;
} else {
p++;
i = 0;
while ((unsigned)(*p - '0') <= 9)
i = 10 * i + (*p++ - '0');
*q++ = i;
}
if (*p != '\\' || *++p != '}')
error("RE error");
p++;
}
q = endp;
break;
case '\\':
if ((c = *p++) == '(') {
if (++paren_num > 9)
error("RE error");
*q++ = RE_LP;
*q++ = paren_num;
*stackp++ = paren_num;
len = 0;
} else if (c == ')') {
if (stackp == stack)
error("RE error");
*q++ = RE_RP;
*q++ = *--stackp;
len = 0;
} else if (c == '{') {
type = RE_RANGE;
goto range;
} else if ((unsigned)(c - '1') < 9) {
/* should check validity here */
*q++ = RE_MATCHED;
*q++ = c - '0';
len = 2;
} else {
goto dft;
}
break;
default:
dft: *q++ = RE_LITERAL;
*q++ = c;
len = 2;
break;
}
}
out:
if (stackp != stack)
error("RE error");
number_parens = paren_num;
return comp;
}
int
re_match(pattern, string)
char *pattern;
char *string;
{
char **pp;
match_begin[0] = string;
for (pp = &match_begin[1] ; pp <= &match_begin[9] ; pp++)
*pp = 0;
return match(pattern, string);
}
static
match(pattern, string)
char *pattern;
char *string;
{
register char *p, *q;
int counting;
int low, high, count;
char *curpat;
char *start_count;
int negate;
int found;
char *r;
int len;
char c;
p = pattern;
q = string;
counting = 0;
for (;;) {
if (counting) {
if (++count > high)
goto bad;
p = curpat;
}
switch (*p++) {
case RE_END:
match_length[0] = q - match_begin[0];
return 1;
case RE_LITERAL:
if (*q++ != *p++)
goto bad;
break;
case RE_DOT:
if (*q++ == '\0')
goto bad;
break;
case RE_CCL:
negate = 0;
goto ccl;
case RE_NCCL:
negate = 1;
ccl:
found = 0;
c = *q++;
while (*p) {
if (*p == '-') {
if (c >= *++p && c <= *++p)
found = 1;
} else {
if (c == *p)
found = 1;
}
p++;
}
p++;
if (found == negate)
goto bad;
break;
case RE_LP:
match_begin[*p++] = q;
break;
case RE_RP:
match_length[*p] = q - match_begin[*p];
p++;
break;
case RE_MATCHED:
r = match_begin[*p];
len = match_length[*p++];
while (--len >= 0) {
if (*q++ != *r++)
goto bad;
}
break;
case RE_EOS:
if (*q != '\0')
goto bad;
break;
case RE_STAR:
low = 0;
high = 32767;
goto range;
case RE_RANGE:
low = *p++;
high = *p++;
if (high == 0)
high = 32767;
range:
curpat = p;
start_count = q;
count = 0;
counting++;
break;
}
}
bad:
if (! counting)
return 0;
len = 1;
if (*curpat == RE_MATCHED)
len = match_length[curpat[1]];
while (--count >= low) {
if (match(p, start_count + count * len))
return 1;
}
return 0;
}

View file

@ -1,21 +0,0 @@
/*
* 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"
void error();
pointer malloc();
pointer
stalloc(nbytes) {
register pointer p;
if ((p = malloc(nbytes)) == NULL)
error("Out of space");
return p;
}

View file

@ -1,19 +0,0 @@
/*
* 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 <stdio.h>
main(argc, argv) char **argv; {
int mask;
if (argc > 1) {
fprintf(stderr, "umask: only builtin version of umask can set value\n");
exit(2);
}
printf("%.4o\n", umask(0));
return 0;
}

View file

@ -1,24 +0,0 @@
# List of unary operators used by test/expr.
#
# 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.
NOT ! 3
EXISTS -e 12 OP_FILE
ISREAD -r 12 OP_FILE
ISWRITE -w 12 OP_FILE
ISEXEC -x 12 OP_FILE
ISFILE -f 12 OP_FILE
ISDIR -d 12 OP_FILE
ISCHAR -c 12 OP_FILE
ISBLOCK -b 12 OP_FILE
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
ISTTY -t 12 OP_INT
NULSTR -z 12 OP_STRING
STRLEN -n 12 OP_STRING

Some files were not shown because too many files have changed in this diff Show more