diff options
Diffstat (limited to 'release/picobsd/tinyware')
106 files changed, 24002 insertions, 0 deletions
diff --git a/release/picobsd/tinyware/aps/Makefile b/release/picobsd/tinyware/aps/Makefile new file mode 100644 index 0000000..b76b456 --- /dev/null +++ b/release/picobsd/tinyware/aps/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile,v 1.1.1.1 1998/07/14 07:30:52 abial Exp $ +# +PROG=ps +SRCS+=main.c +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/aps/README b/release/picobsd/tinyware/aps/README new file mode 100644 index 0000000..2664c44 --- /dev/null +++ b/release/picobsd/tinyware/aps/README @@ -0,0 +1,19 @@ +1998.07.12 + +This is a small 'ps' replacement, which uses information available via +procfs(5) interface. It's primitive, but gives you the most important +informations, i.e. how many processes are running and on which vty, and the +pid number to kill some of them. :-) + +When I have some time, I'll add usual switches and other functions that normal +'ps' has... + +Also, what I'm now inclined to think is that it should be reworked to use +more general (and less complicated) sysctl(3). + +<abial@nask.pl> + +(As of 1998.07.31 this program is no longer used in PicoBSD. See sps(1) in +TinyWare collection). + +$Id: README,v 1.2 1998/07/31 20:57:42 abial Exp $ diff --git a/release/picobsd/tinyware/aps/main.c b/release/picobsd/tinyware/aps/main.c new file mode 100644 index 0000000..bbd2cce --- /dev/null +++ b/release/picobsd/tinyware/aps/main.c @@ -0,0 +1,101 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: main.c,v 1.1.1.1 1998/07/14 07:30:53 abial Exp $ + * + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> + +/* + * Ok, I could extract almost anything from /proc, but I'm too lazy... + * I think it will suffice for now. + */ + +int +main(int argc, char *argv[]) +{ + DIR *d; + struct dirent *e; + FILE *fd; + char buf[100]; + char *tok, *sep=" ", *sep1=","; + char *name, *pid, *ppid, *uid, *gid; + char *pgid, *sid, *tty, *cred; + char *major, *minor; + char con[10]; + + d=opendir("/proc"); + printf(" PID PPID TTY COMMAND\n"); + while((e=readdir(d))!=NULL) { + /* Skip '.' and '..' */ + if(e->d_name[0]=='.') continue; + /* Skip 'curproc' - it's us */ + if(e->d_name[0]=='c') continue; + sprintf(buf,"/proc/%s/status",e->d_name); + fd=fopen(buf,"r"); + fgets(buf,99,fd); + fclose(fd); + name=strtok(buf,sep); + pid=strtok(NULL,sep); + ppid=strtok(NULL,sep); + pgid=strtok(NULL,sep); + sid=strtok(NULL,sep); + tty=strtok(NULL,sep); + tok=strtok(NULL,sep); /* flags */ + tok=strtok(NULL,sep); /* start */ + tok=strtok(NULL,sep); /* user time */ + tok=strtok(NULL,sep); /* system time */ + tok=strtok(NULL,sep); /* wchan */ + cred=strtok(NULL,sep); /* credentials */ + major=strtok(tty,sep1); + minor=strtok(NULL,sep1); + if(strcmp(minor,"-1")==0) { + minor="?"; + } + if(strcmp(major,"-1")==0) { + major="?"; + } else if(strcmp(major,"12")==0) { + major="v"; + } else if(strcmp(major,"0")==0) { + major="con"; + minor="-"; + } else if(strcmp(major,"5")==0) { + major="p"; + } else major="x"; + if((strcmp(major,"v")==0) && (strcmp(minor,"255")==0)) { + major="con"; + minor="-"; + } + sprintf(con,"%s%s",major,minor); + printf("%5s %5s %4s (%s)\n",pid,ppid,con,name); + + } + closedir(d); + exit(0); +} diff --git a/release/picobsd/tinyware/ash/Makefile b/release/picobsd/tinyware/ash/Makefile new file mode 100644 index 0000000..f8032aa --- /dev/null +++ b/release/picobsd/tinyware/ash/Makefile @@ -0,0 +1,44 @@ +# $NetBSD: Makefile,v 1.33 1997/07/04 21:40:55 christos Exp $ +# @(#)Makefile 8.4 (Berkeley) 5/5/95 + +WARNS= 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 +GENSRCS=arith.c arith_lex.c builtins.c builtins.h init.c nodes.c nodes.h \ + syntax.c syntax.h token.h +SRCS= ${SHSRCS} ${GENSRCS} + +LDADD+= -ll -ledit -ltermcap +DPADD+= ${LIBL} ${LIBEDIT} ${LIBTERMCAP} + +LFLAGS= -8 # 8-bit lex scanner for arithmetic + +CFLAGS+=-DSHELL -I. -I${.CURDIR} + + +.PATH: ${.CURDIR}/bltin ${.CURDIR}/../../usr.bin/printf + +CLEANFILES+= mkinit mknodes mksyntax +CLEANFILES+= mkinit.o mknodes.o mksyntax.o +CLEANFILES+= ${GENSRCS} y.tab.h + +token.h: mktokens + sh ${.CURDIR}/mktokens + +builtins.c builtins.h: mkbuiltins builtins.def + cd ${.CURDIR}; sh mkbuiltins ${.OBJDIR} + +init.c: mkinit ${SHSRCS} + ./mkinit ${.ALLSRC:S/^mkinit$//} + +nodes.c nodes.h: mknodes nodetypes nodes.c.pat + ./mknodes ${.CURDIR}/nodetypes ${.CURDIR}/nodes.c.pat + +syntax.c syntax.h: mksyntax + ./mksyntax + +.include <bsd.prog.mk> + +${OBJS}: builtins.h nodes.h syntax.h token.h diff --git a/release/picobsd/tinyware/ash/TOUR b/release/picobsd/tinyware/ash/TOUR new file mode 100644 index 0000000..f5c00c4 --- /dev/null +++ b/release/picobsd/tinyware/ash/TOUR @@ -0,0 +1,357 @@ +# $NetBSD: TOUR,v 1.8 1996/10/16 14:24:56 christos Exp $ +# @(#)TOUR 8.1 (Berkeley) 5/31/93 + +NOTE -- This is the original TOUR paper distributed with ash and +does not represent the current state of the shell. It is provided anyway +since it provides helpful information for how the shell is structured, +but be warned that things have changed -- the current shell is +still under development. + +================================================================ + + A Tour through Ash + + Copyright 1989 by Kenneth Almquist. + + +DIRECTORIES: The subdirectory bltin contains commands which can +be compiled stand-alone. The rest of the source is in the main +ash directory. + +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 + ------- ------------ --------- + mkbuiltins builtins builtins.h builtins.c + mkinit *.c init.c + mknodes nodetypes nodes.h nodes.c + mksignames - signames.h signames.c + mksyntax - syntax.h syntax.c + mktokens - token.h + bltin/mkexpr unary_op binary_op operators.h operators.c + +There are undoubtedly too many of these. Mkinit searches all the +C source files for entries looking like: + + INIT { + x = 1; /* executed during initialization */ + } + + RESET { + x = 2; /* executed when the shell does a longjmp + back to the main command loop */ + } + + SHELLPROC { + x = 3; /* executed when the shell runs a shell procedure */ + } + +It pulls this code out into routines which are when particular +events occur. The intent is to improve modularity by isolating +the information about which modules need to be explicitly +initialized/reset within the modules themselves. + +Mkinit recognizes several constructs for placing declarations in +the init.c file. + INCLUDE "file.h" +includes a file. The storage class MKINIT makes a declaration +available in the init.c file, for example: + MKINIT int funcnest; /* depth of function calls */ +MKINIT alone on a line introduces a structure or union declara- +tion: + MKINIT + struct redirtab { + short renamed[10]; + }; +Preprocessor #define statements are copied to init.c without any +special action to request this. + +INDENTATION: The ash source is indented in multiples of six +spaces. The only study that I have heard of on the subject con- +cluded that the optimal amount to indent is in the range of four +to six spaces. I use six spaces since it is not too big a jump +from the widely used eight spaces. If you really hate six space +indentation, use the adjind (source included) program to change +it to something else. + +EXCEPTIONS: Code for dealing with exceptions appears in +exceptions.c. The C language doesn't include exception handling, +so I implement it using setjmp and longjmp. The global variable +exception contains the type of exception. EXERROR is raised by +calling error. EXINT is an interrupt. EXSHELLPROC is an excep- +tion which is raised when a shell procedure is invoked. The pur- +pose of EXSHELLPROC is to perform the cleanup actions associated +with other exceptions. After these cleanup actions, the shell +can interpret a shell procedure itself without exec'ing a new +copy of the shell. + +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 +of INTOFF and the execution of INTON, interrupt signals will be +held for later delivery. INTOFF and INTON can be nested. + +MEMALLOC.C: Memalloc.c defines versions of malloc and realloc +which call error when there is no memory left. It also defines a +stack oriented memory allocation scheme. Allocating off a stack +is probably more efficient than allocation using malloc, but the +big advantage is that when an exception occurs all we have to do +to free up the memory in use at the time of the exception is to +restore the stack pointer. The stack is implemented using a +linked list of blocks. + +STPUTC: If the stack were contiguous, it would be easy to store +strings on the stack without knowing in advance how long the +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 +operations, but grow the stack if you run off the end: + STARTSTACKSTR(p); + STPUTC(c, p); /* repeated as many times as needed */ + grabstackstr(p); + +We now start a top-down look at the code: + +MAIN.C: The main routine performs some initialization, executes +the user's profile if necessary, and calls cmdloop. Cmdloop is +repeatedly parses and executes commands. + +OPTIONS.C: This file contains the option processing code. It is +called from main to parse the shell arguments when the shell is +invoked, and it also contains the set builtin. The -i and -j op- +tions (the latter turns on job control) require changes in signal +handling. The routines setjobctl (in jobs.c) and setinteractive +(in trap.c) are called to handle changes to these options. + +PARSING: The parser code is all in parser.c. A recursive des- +cent parser is used. Syntax tables (generated by mksyntax) are +used to classify characters during lexical analysis. There are +three tables: one for normal use, one for use when inside single +quotes, and one for use when inside double quotes. The tables +are machine dependent because they are indexed by character vari- +ables and the range of a char varies from machine to machine. + +PARSE OUTPUT: The output of the parser consists of a tree of +nodes. The various types of nodes are defined in the file node- +types. + +Nodes of type NARG are used to represent both words and the con- +tents of here documents. An early version of ash kept the con- +tents of here documents in temporary files, but keeping here do- +cuments in memory typically results in significantly better per- +formance. It would have been nice to make it an option to use +temporary files for here documents, for the benefit of small +machines, but the code to keep track of when to delete the tem- +porary files was complex and I never fixed all the bugs in it. +(AT&T has been maintaining the Bourne shell for more than ten +years, and to the best of my knowledge they still haven't gotten +it to handle temporary files correctly in obscure cases.) + +The text field of a NARG structure points to the text of the +word. The text consists of ordinary characters and a number of +special codes defined in parser.h. The special codes are: + + CTLVAR Variable substitution + CTLENDVAR End of variable substitution + CTLBACKQ Command substitution + CTLBACKQ|CTLQUOTE Command substitution inside double quotes + CTLESC Escape next character + +A variable substitution contains the following elements: + + CTLVAR type name '=' [ alternative-text CTLENDVAR ] + +The type field is a single character specifying the type of sub- +stitution. The possible types are: + + VSNORMAL $var + VSMINUS ${var-text} + VSMINUS|VSNUL ${var:-text} + VSPLUS ${var+text} + VSPLUS|VSNUL ${var:+text} + VSQUESTION ${var?text} + VSQUESTION|VSNUL ${var:?text} + VSASSIGN ${var=text} + VSASSIGN|VSNUL ${var=text} + +In addition, the type field will have the VSQUOTE flag set if the +variable is enclosed in double quotes. The name of the variable +comes next, terminated by an equals sign. If the type is not +VSNORMAL, then the text field in the substitution follows, ter- +minated by a CTLENDVAR byte. + +Commands in back quotes are parsed and stored in a linked list. +The locations of these commands in the string are indicated by +CTLBACKQ and CTLBACKQ+CTLQUOTE characters, depending upon whether +the back quotes were enclosed in double quotes. + +The character CTLESC escapes the next character, so that in case +any of the CTL characters mentioned above appear in the input, +they can be passed through transparently. CTLESC is also used to +escape '*', '?', '[', and '!' characters which were quoted by the +user and thus should not be used for file name generation. + +CTLESC characters have proved to be particularly tricky to get +right. In the case of here documents which are not subject to +variable and command substitution, the parser doesn't insert any +CTLESC characters to begin with (so the contents of the text +field can be written without any processing). Other here docu- +ments, and words which are not subject to splitting and file name +generation, have the CTLESC characters removed during the vari- +able and command substitution phase. Words which are subject +splitting and file name generation have the CTLESC characters re- +moved as part of the file name phase. + +EXECUTION: Command execution is handled by the following files: + eval.c The top level routines. + redir.c Code to handle redirection of input and output. + jobs.c Code to handle forking, waiting, and job control. + exec.c Code to to path searches and the actual exec sys call. + expand.c Code to evaluate arguments. + var.c Maintains the variable symbol table. Called from expand.c. + +EVAL.C: Evaltree recursively executes a parse tree. The exit +status is returned in the global variable exitstatus. The alter- +native entry evalbackcmd is called to evaluate commands in back +quotes. It saves the result in memory if the command is a buil- +tin; otherwise it forks off a child to execute the command and +connects the standard output of the child to a pipe. + +JOBS.C: To create a process, you call makejob to return a job +structure, and then call forkshell (passing the job structure as +an argument) to create the process. Waitforjob waits for a job +to complete. These routines take care of process groups if job +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- +cated to. + +EXEC.C: The routine find_command locates a command, and enters +the command in the hash table if it is not already there. The +third argument specifies whether it is to print an error message +if the command is not found. (When a pipeline is set up, +find_command is called for all the commands in the pipeline be- +fore any forking is done, so to get the commands into the hash +table of the parent process. But to make command hashing as +transparent as possible, we silently ignore errors at that point +and only print error messages if the command cannot be found +later.) + +The routine shellexec is the interface to the exec system call. + +EXPAND.C: Arguments are processed in three passes. The first +(performed by the routine argstr) performs variable and command +substitution. The second (ifsbreakup) performs word splitting +and the third (expandmeta) performs file name generation. If the +"/u" directory is simulated, then when "/u/username" is replaced +by the user's home directory, the flag "didudir" is set. This +tells the cd command that it should print out the directory name, +just as it would if the "/u" directory were implemented using +symbolic links. + +VAR.C: Variables are stored in a hash table. Probably we should +switch to extensible hashing. The variable name is stored in the +same string as the value (using the format "name=value") so that +no string copying is needed to create the environment of a com- +mand. Variables which the shell references internally are preal- +located so that the shell can reference the values of these vari- +ables without doing a lookup. + +When a program is run, the code in eval.c sticks any environment +variables which precede the command (as in "PATH=xxx command") in +the variable table as the simplest way to strip duplicates, and +then calls "environment" to get the value of the environment. +There are two consequences of this. First, if an assignment to +PATH precedes the command, the value of PATH before the assign- +ment must be remembered and passed to shellexec. Second, if the +program turns out to be a shell procedure, the strings from the +environment variables which preceded the command must be pulled +out of the table and replaced with strings obtained from malloc, +since the former will automatically be freed when the stack (see +the entry on memalloc.c) is emptied. + +BUILTIN COMMANDS: The procedures for handling these are scat- +tered throughout the code, depending on which location appears +most appropriate. They can be recognized because their names al- +ways end in "cmd". The mapping from names to procedures is +specified in the file builtins, which is processed by the mkbuil- +tins command. + +A builtin command is invoked with argc and argv set up like a +normal program. A builtin command is allowed to overwrite its +arguments. Builtin routines can call nextopt to do option pars- +ing. This is kind of like getopt, but you don't pass argc and +argv to it. Builtin routines can also call error. This routine +normally terminates the shell (or returns to the main command +loop if the shell is interactive), but when called from a builtin +command it causes the builtin command to terminate with an exit +status of 2. + +The directory bltins contains commands which can be compiled in- +dependently but can also be built into the shell for efficiency +reasons. The makefile in this directory compiles these programs +in the normal fashion (so that they can be run regardless of +whether the invoker is ash), but also creates a library named +bltinlib.a which can be linked with ash. The header file bltin.h +takes care of most of the differences between the ash and the +stand-alone environment. The user should call the main routine +"main", and #define main to be the name of the routine to use +when the program is linked into ash. This #define should appear +before bltin.h is included; bltin.h will #undef main if the pro- +gram is to be compiled stand-alone. + +CD.C: This file defines the cd and pwd builtins. The pwd com- +mand runs /bin/pwd the first time it is invoked (unless the user +has already done a cd to an absolute pathname), but then +remembers the current directory and updates it when the cd com- +mand is run, so subsequent pwd commands run very fast. The main +complication in the cd command is in the docd command, which +resolves symbolic links into actual names and informs the user +where the user ended up if he crossed a symbolic link. + +SIGNALS: Trap.c implements the trap command. The routine set- +signal figures out what action should be taken when a signal is +received and invokes the signal system call to set the signal ac- +tion appropriately. When a signal that a user has set a trap for +is caught, the routine "onsig" sets a flag. The routine dotrap +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- +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- +tin command appears in backquotes, to allow its output to be col- +lected without doing any I/O through the UNIX operating system. +The variables out1 and out2 normally point to output and errout, +respectively, but they are set to point to memout when appropri- +ate inside backquotes. + +INPUT: The basic input routine is pgetc, which reads from the +current input file. There is a stack of input files; the current +input file is the top file on this stack. The code allows the +input to come from a string rather than a file. (This is for the +-c option and the "." and eval builtin commands.) The global +variable plinno is saved and restored when files are pushed and +popped from the stack. The parser routines store the number of +the current line in this variable. + +DEBUGGING: If DEBUG is defined in shell.h, then the shell will +write debugging information to the file $HOME/trace. Most of +this is done using the TRACE macro, which takes a set of printf +arguments inside two sets of parenthesis. Example: +"TRACE(("n=%d0, n))". The double parenthesis are necessary be- +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. diff --git a/release/picobsd/tinyware/ash/alias.c b/release/picobsd/tinyware/ash/alias.c new file mode 100644 index 0000000..80626cd --- /dev/null +++ b/release/picobsd/tinyware/ash/alias.c @@ -0,0 +1,267 @@ +/* $NetBSD: alias.c,v 1.9 1997/07/04 21:01:48 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.9 1997/07/04 21:01:48 christos Exp $"); +#endif +#endif /* not lint */ + +#include <stdlib.h> +#include "shell.h" +#include "input.h" +#include "output.h" +#include "error.h" +#include "memalloc.h" +#include "mystring.h" +#include "alias.h" +#include "options.h" /* XXX for argptr (should remove?) */ + +#define ATABSIZE 39 + +struct alias *atab[ATABSIZE]; + +STATIC void setalias __P((char *, char *)); +STATIC int unalias __P((char *)); +STATIC struct alias **hashalias __P((char *)); + +STATIC +void +setalias(name, val) + char *name, *val; +{ + struct alias *ap, **app; + + app = hashalias(name); + for (ap = *app; ap; ap = ap->next) { + if (equal(name, ap->name)) { + INTOFF; + ckfree(ap->val); + ap->val = savestr(val); + INTON; + return; + } + } + /* not found */ + INTOFF; + ap = ckmalloc(sizeof (struct alias)); + ap->name = savestr(name); + /* + * XXX - HACK: in order that the parser will not finish reading the + * alias value off the input before processing the next alias, we + * dummy up an extra space at the end of the alias. This is a crock + * and should be re-thought. The idea (if you feel inclined to help) + * is to avoid alias recursions. The mechanism used is: when + * expanding an alias, the value of the alias is pushed back on the + * input as a string and a pointer to the alias is stored with the + * string. The alias is marked as being in use. When the input + * routine finishes reading the string, it 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 + * H A C K is that we add a little fluff after the alias value + * so that the string will not be exhausted. This is a good + * idea ------- ***NOT*** + */ +#ifdef notyet + ap->val = savestr(val); +#else /* hack */ + { + int len = strlen(val); + ap->val = ckmalloc(len + 2); + memcpy(ap->val, val, len); + ap->val[len] = ' '; /* fluff */ + ap->val[len+1] = '\0'; + } +#endif + ap->next = *app; + *app = ap; + INTON; +} + +STATIC int +unalias(name) + char *name; + { + struct alias *ap, **app; + + app = hashalias(name); + + for (ap = *app; ap; app = &(ap->next), ap = ap->next) { + if (equal(name, ap->name)) { + /* + * if the alias is currently in use (i.e. its + * buffer is being used by the input routine) we + * just null out the name instead of freeing it. + * We could clear it out later, but this situation + * is so rare that it hardly seems worth it. + */ + if (ap->flag & ALIASINUSE) + *ap->name = '\0'; + else { + INTOFF; + *app = ap->next; + ckfree(ap->name); + ckfree(ap->val); + ckfree(ap); + INTON; + } + return (0); + } + } + + return (1); +} + +#ifdef mkinit +MKINIT void rmaliases __P((void)); + +SHELLPROC { + rmaliases(); +} +#endif + +void +rmaliases() { + struct alias *ap, *tmp; + int i; + + INTOFF; + for (i = 0; i < ATABSIZE; i++) { + ap = atab[i]; + atab[i] = NULL; + while (ap) { + ckfree(ap->name); + ckfree(ap->val); + tmp = ap; + ap = ap->next; + ckfree(tmp); + } + } + INTON; +} + +struct alias * +lookupalias(name, check) + char *name; + int check; +{ + struct alias *ap = *hashalias(name); + + for (; ap; ap = ap->next) { + if (equal(name, ap->name)) { + if (check && (ap->flag & ALIASINUSE)) + return (NULL); + return (ap); + } + } + + return (NULL); +} + +/* + * TODO - sort output + */ +int +aliascmd(argc, argv) + int argc; + char **argv; +{ + char *n, *v; + int ret = 0; + struct alias *ap; + + if (argc == 1) { + int i; + + for (i = 0; i < ATABSIZE; i++) + for (ap = atab[i]; ap; ap = ap->next) { + if (*ap->name != '\0') + out1fmt("alias %s=%s\n", ap->name, ap->val); + } + return (0); + } + while ((n = *++argv) != NULL) { + if ((v = strchr(n+1, '=')) == NULL) /* n+1: funny ksh stuff */ + if ((ap = lookupalias(n, 0)) == NULL) { + outfmt(out2, "alias: %s not found\n", n); + ret = 1; + } else + out1fmt("alias %s=%s\n", n, ap->val); + else { + *v++ = '\0'; + setalias(n, v); + } + } + + return (ret); +} + +int +unaliascmd(argc, argv) + int argc; + char **argv; +{ + int i; + + while ((i = nextopt("a")) != '\0') { + if (i == 'a') { + rmaliases(); + return (0); + } + } + for (i = 0; *argptr; argptr++) + i = unalias(*argptr); + + return (i); +} + +STATIC struct alias ** +hashalias(p) + char *p; + { + unsigned int hashval; + + hashval = *p << 4; + while (*p) + hashval+= *p++; + return &atab[hashval % ATABSIZE]; +} diff --git a/release/picobsd/tinyware/ash/alias.h b/release/picobsd/tinyware/ash/alias.h new file mode 100644 index 0000000..85bdbad --- /dev/null +++ b/release/picobsd/tinyware/ash/alias.h @@ -0,0 +1,53 @@ +/* $NetBSD: alias.h,v 1.4 1995/05/11 21:28:42 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)alias.h 8.2 (Berkeley) 5/4/95 + */ + +#define ALIASINUSE 1 + +struct alias { + struct alias *next; + char *name; + char *val; + int flag; +}; + +struct alias *lookupalias __P((char *, int)); +int aliascmd __P((int, char **)); +int unaliascmd __P((int, char **)); +void rmaliases __P((void)); diff --git a/release/picobsd/tinyware/ash/arith.h b/release/picobsd/tinyware/ash/arith.h new file mode 100644 index 0000000..d40e14b --- /dev/null +++ b/release/picobsd/tinyware/ash/arith.h @@ -0,0 +1,41 @@ +/* $NetBSD: arith.h,v 1.2 1997/07/04 21:01:49 christos Exp $ */ + +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)arith.h 1.1 (Berkeley) 5/4/95 + */ + +int arith __P((char *)); +int expcmd __P((int , char **)); +void arith_lex_reset __P((void)); +int yylex __P((void)); diff --git a/release/picobsd/tinyware/ash/arith.y b/release/picobsd/tinyware/ash/arith.y new file mode 100644 index 0000000..9785014 --- /dev/null +++ b/release/picobsd/tinyware/ash/arith.y @@ -0,0 +1,201 @@ +%{ +/* $NetBSD: arith.y,v 1.8 1997/07/04 21:01:50 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.8 1997/07/04 21:01:50 christos Exp $"); +#endif +#endif /* not lint */ + +#include "arith.h" +#include "shell.h" +#include "error.h" +#include "output.h" +#include "memalloc.h" + +char *arith_buf, *arith_startbuf; + +void yyerror __P((char *)); +int yyparse __P((void)); +#ifdef TESTARITH +int main __P((int , char *[])); +int error __P((char *)); +#endif + +int +arith(s) + char *s; +{ + long result; + + arith_buf = arith_startbuf = s; + + INTOFF; + result = yyparse(); + arith_lex_reset(); /* reprime lex */ + INTON; + + return (result); +} + + +/* + * The exp(1) builtin. + */ +int +expcmd(argc, argv) + 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("%d\n", i); + return (! i); +} + +/*************************/ +#ifdef TEST_ARITH +#include <stdio.h> +main(argc, argv) + char *argv[]; +{ + printf("%d\n", exp(argv[1])); +} +error(s) + char *s; +{ + fprintf(stderr, "exp: %s\n", s); + exit(1); +} +#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 = { + 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 + ; +%% +void +yyerror(s) + char *s; +{ + + yyerrok; + yyclearin; + arith_lex_reset(); /* reprime lex */ + error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); +} diff --git a/release/picobsd/tinyware/ash/arith_lex.l b/release/picobsd/tinyware/ash/arith_lex.l new file mode 100644 index 0000000..e3c18c6 --- /dev/null +++ b/release/picobsd/tinyware/ash/arith_lex.l @@ -0,0 +1,93 @@ +%{ +/* $NetBSD: arith_lex.l,v 1.7 1997/07/04 21:01:51 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.7 1997/07/04 21:01:51 christos Exp $"); +#endif +#endif /* not lint */ + +#include <unistd.h> +#include "y.tab.h" +#include "error.h" +#include "arith.h" + +extern yylval; +extern char *arith_buf, *arith_startbuf; +#undef YY_INPUT +#define YY_INPUT(buf,result,max) \ + result = (*buf = *arith_buf++) ? 1 : YY_NULL; +#define YY_NO_UNPUT +%} + +%% +[ \t\n] { ; } +[0-9]+ { yylval = atol(yytext); return(ARITH_NUM); } +"(" { 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\"\n", arith_startbuf); } +%% + +void +arith_lex_reset() { + YY_NEW_FILE; +} diff --git a/release/picobsd/tinyware/ash/bltin/bltin.h b/release/picobsd/tinyware/ash/bltin/bltin.h new file mode 100644 index 0000000..991de81 --- /dev/null +++ b/release/picobsd/tinyware/ash/bltin/bltin.h @@ -0,0 +1,78 @@ +/* $NetBSD: bltin.h,v 1.9 1997/07/04 21:02:29 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)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. + */ + +#include "../shell.h" +#include "../mystring.h" +#ifdef SHELL +#include "../output.h" +#define stdout out1 +#define stderr out2 +#define printf out1fmt +#define putc(c, file) outc(c, file) +#define putchar(c) out1c(c) +#define fprintf outfmt +#define fputs outstr +#define fflush flushout +#define INITARGS(argv) +#define warnx(a, b, c) { \ + char buf[64]; \ + (void)snprintf(buf, sizeof(buf), a, b, c); \ + error("%s", buf); \ +} + +#else +#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 + +pointer stalloc __P((int)); +void error __P((char *, ...)); +int echocmd __P((int, char **)); + + +extern char *commandname; diff --git a/release/picobsd/tinyware/ash/bltin/echo.1 b/release/picobsd/tinyware/ash/bltin/echo.1 new file mode 100644 index 0000000..202ad6f --- /dev/null +++ b/release/picobsd/tinyware/ash/bltin/echo.1 @@ -0,0 +1,113 @@ +.\" $NetBSD: echo.1,v 1.8 1996/10/16 15:27:03 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. +.\" 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. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)echo.1 8.1 (Berkeley) 5/31/93 +.\" +.Dd May 31, 1993 +.Dt ECHO 1 +.Os BSD 4.4 +.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 >&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. diff --git a/release/picobsd/tinyware/ash/bltin/echo.c b/release/picobsd/tinyware/ash/bltin/echo.c new file mode 100644 index 0000000..726346e --- /dev/null +++ b/release/picobsd/tinyware/ash/bltin/echo.c @@ -0,0 +1,107 @@ +/* $NetBSD: echo.c,v 1.8 1996/11/02 18:26:06 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)echo.c 8.1 (Berkeley) 5/31/93 + */ + +/* + * Echo command. + */ + +#define main echocmd + +#include "bltin.h" + +/* #define eflag 1 */ + +int +main(argc, argv) char **argv; { + register char **ap; + register char *p; + register char c; + int count; + int nflag = 0; +#ifndef eflag + int eflag = 0; +#endif + + ap = argv; + if (argc) + ap++; + if ((p = *ap) != NULL) { + if (equal(p, "-n")) { + nflag++; + ap++; + } else if (equal(p, "-e")) { +#ifndef eflag + eflag++; +#endif + ap++; + } + } + while ((p = *ap++) != NULL) { + while ((c = *p++) != '\0') { + if (c == '\\' && eflag) { + switch (*p++) { + case 'b': c = '\b'; break; + case 'c': return 0; /* exit */ + case 'f': c = '\f'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 't': c = '\t'; break; + case 'v': c = '\v'; break; + case '\\': break; /* c = '\\' */ + case '0': + c = 0; + count = 3; + while (--count >= 0 && (unsigned)(*p - '0') < 8) + c = (c << 3) + (*p++ - '0'); + break; + default: + p--; + break; + } + } + putchar(c); + } + if (*ap) + putchar(' '); + } + if (! nflag) + putchar('\n'); + return 0; +} diff --git a/release/picobsd/tinyware/ash/builtins.def b/release/picobsd/tinyware/ash/builtins.def new file mode 100644 index 0000000..61ec759 --- /dev/null +++ b/release/picobsd/tinyware/ash/builtins.def @@ -0,0 +1,92 @@ +#!/bin/sh - +# $NetBSD: builtins.def,v 1.14 1997/03/14 01:42:18 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. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)builtins.def 8.4 (Berkeley) 5/4/95 + +# +# 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 SMALL compile-time symbol. The rest of the line +# specifies the command name or names used to run the command. The entry +# for bltincmd, which is run when the user does not specify a command, must +# come first. +# +# NOTE: bltincmd must come first! + +bltincmd command +#alloccmd alloc +bgcmd -j bg +breakcmd break continue +#catfcmd catf +cdcmd cd chdir +dotcmd . +echocmd echo +evalcmd eval +execcmd exec +exitcmd exit +expcmd exp let +exportcmd export readonly +#exprcmd expr test [ +falsecmd false +histcmd -h fc +fgcmd -j fg +getoptscmd getopts +hashcmd hash +jobidcmd jobid +jobscmd jobs +#linecmd line +localcmd local +#nlechocmd nlecho +#printfcmd printf +pwdcmd pwd +readcmd read +returncmd return +setcmd set +setvarcmd setvar +shiftcmd shift +trapcmd trap +truecmd : true +typecmd type +umaskcmd umask +unaliascmd unalias +unsetcmd unset +waitcmd wait +#foocmd foo +aliascmd alias +ulimitcmd ulimit diff --git a/release/picobsd/tinyware/ash/cd.c b/release/picobsd/tinyware/ash/cd.c new file mode 100644 index 0000000..b029045 --- /dev/null +++ b/release/picobsd/tinyware/ash/cd.c @@ -0,0 +1,383 @@ +/* $NetBSD: cd.c,v 1.23 1997/07/04 20:59:40 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.23 1997/07/04 20:59:40 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +/* + * The cd and pwd commands. + */ + +#include "shell.h" +#include "var.h" +#include "nodes.h" /* for jobs.h */ +#include "jobs.h" +#include "options.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "exec.h" +#include "redir.h" +#include "mystring.h" +#include "show.h" +#include "cd.h" + +STATIC int docd __P((char *, int)); +STATIC char *getcomponent __P((void)); +STATIC void updatepwd __P((char *)); + +char *curdir = NULL; /* current working directory */ +char *prevdir; /* previous working directory */ +STATIC char *cdcomppath; + +int +cdcmd(argc, argv) + int argc; + char **argv; +{ + char *dest; + char *path; + char *p; + struct stat statb; + int print = 0; + + nextopt(nullstr); + if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME", 1)) == NULL) + error("HOME not set"); + if (*dest == '\0') + dest = "."; + if (dest[0] == '-' && dest[1] == '\0') { + dest = prevdir ? prevdir : curdir; + print = 1; + if (dest) + print = 1; + else + dest = "."; + } + if (*dest == '/' || (path = bltinlookup("CDPATH", 1)) == NULL) + path = nullstr; + while ((p = padvance(&path, dest)) != NULL) { + if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { + if (!print) { + /* + * XXX - rethink + */ + if (p[0] == '.' && p[1] == '/') + p += 2; + print = strcmp(p, dest); + } + if (docd(p, print) >= 0) + return 0; + + } + } + error("can't cd to %s", dest); + /*NOTREACHED*/ + return 0; +} + + +/* + * Actually do the chdir. In an interactive shell, print the + * directory name if "print" is nonzero. + */ + +STATIC int +docd(dest, print) + char *dest; + int print; +{ + char *p; + char *q; + char *component; + struct stat statb; + 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() + * next time we get the value of the current directory. + */ + badstat = 0; + cdcomppath = stalloc(strlen(dest) + 1); + scopy(dest, cdcomppath); + STARTSTACKSTR(p); + if (*dest == '/') { + STPUTC('/', p); + cdcomppath++; + } + first = 1; + while ((q = getcomponent()) != NULL) { + if (q[0] == '\0' || (q[0] == '.' && q[1] == '\0')) + continue; + if (! first) + STPUTC('/', p); + first = 0; + component = q; + while (*q) + STPUTC(*q++, p); + if (equal(component, "..")) + continue; + STACKSTRNUL(p); + if ((lstat(stackblock(), &statb) < 0) + || (S_ISLNK(statb.st_mode))) { + /* print = 1; */ + badstat = 1; + break; + } + } + + INTOFF; + if (chdir(dest) < 0) { + INTON; + return -1; + } + updatepwd(badstat ? NULL : dest); + INTON; + if (print && iflag && curdir) + out1fmt("%s\n", curdir); + 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() { + char *p; + char *start; + + if ((p = cdcomppath) == NULL) + return NULL; + start = cdcomppath; + while (*p != '/' && *p != '\0') + p++; + if (*p == '\0') { + cdcomppath = NULL; + } else { + *p++ = '\0'; + cdcomppath = p; + } + return start; +} + + + +/* + * 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 void +updatepwd(dir) + char *dir; + { + char *new; + char *p; + + hashcd(); /* update command hash table */ + + /* + * If our argument is NULL, we don't know the current directory + * any more because we traversed a symbolic link or something + * we couldn't stat(). + */ + if (dir == NULL) { + if (prevdir) + ckfree(prevdir); + INTOFF; + prevdir = curdir; + curdir = NULL; + getpwd(); + INTON; + return; + } + + cdcomppath = stalloc(strlen(dir) + 1); + scopy(dir, cdcomppath); + STARTSTACKSTR(new); + if (*dir != '/') { + if (curdir == NULL) + return; + p = curdir; + while (*p) + STPUTC(*p++, new); + if (p[-1] == '/') + STUNPUTC(new); + } + while ((p = getcomponent()) != NULL) { + if (equal(p, "..")) { + while (new > stackblock() && (STUNPUTC(new), *new) != '/'); + } else if (*p != '\0' && ! equal(p, ".")) { + STPUTC('/', new); + while (*p) + STPUTC(*p++, new); + } + } + if (new == stackblock()) + STPUTC('/', new); + STACKSTRNUL(new); + INTOFF; + if (prevdir) + ckfree(prevdir); + prevdir = curdir; + curdir = savestr(stackblock()); + setvar("PWD", curdir, VEXPORT|VTEXTFIXED); + INTON; +} + + + +int +pwdcmd(argc, argv) + int argc; + char **argv; +{ + getpwd(); + out1str(curdir); + out1c('\n'); + return 0; +} + + + + +#define MAXPWD 256 + +/* + * Find out what the current directory is. If we already know the current + * directory, this routine returns immediately. + */ +void +getpwd() +{ + char buf[MAXPWD]; + + if (curdir) + return; + /* + * 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) + + if (getcwd(buf, sizeof(buf)) == NULL) { + char *pwd = getenv("PWD"); + struct stat stdot, stpwd; + + if (pwd && *pwd == '/' && stat(".", &stdot) != -1 && + stat(pwd, &stpwd) != -1 && + stdot.st_dev == stpwd.st_dev && + stdot.st_ino == stpwd.st_ino) { + curdir = savestr(pwd); + return; + } + error("getcwd() failed: %s", strerror(errno)); + } + curdir = savestr(buf); +#else + { + char *p; + int i; + int status; + struct job *jp; + int pip[2]; + + INTOFF; + if (pipe(pip) < 0) + error("Pipe call failed"); + jp = makejob((union node *)NULL, 1); + if (forkshell(jp, (union node *)NULL, FORK_NOJOB) == 0) { + (void) close(pip[0]); + if (pip[1] != 1) { + close(1); + copyfd(pip[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 = buf; + while ((i = read(pip[0], p, buf + 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 == buf || p[-1] != '\n') + error("pwd command failed"); + p[-1] = '\0'; + } + curdir = savestr(buf); + INTON; +#endif +} diff --git a/release/picobsd/tinyware/ash/cd.h b/release/picobsd/tinyware/ash/cd.h new file mode 100644 index 0000000..29937c1 --- /dev/null +++ b/release/picobsd/tinyware/ash/cd.h @@ -0,0 +1,39 @@ +/* $NetBSD: cd.h,v 1.2 1997/07/04 21:01:52 christos Exp $ */ + +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +void getpwd __P((void)); +int cdcmd __P((int, char **)); +int pwdcmd __P((int, char **)); diff --git a/release/picobsd/tinyware/ash/error.c b/release/picobsd/tinyware/ash/error.c new file mode 100644 index 0000000..22e44d2 --- /dev/null +++ b/release/picobsd/tinyware/ash/error.c @@ -0,0 +1,291 @@ +/* $NetBSD: error.c,v 1.17 1997/07/04 21:01:54 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.17 1997/07/04 21:01:54 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Errors and exceptions. + */ + +#include "shell.h" +#include "main.h" +#include "options.h" +#include "output.h" +#include "error.h" +#include "show.h" +#include <signal.h> +#include <unistd.h> +#include <errno.h> + + +/* + * Code to handle exceptions in C. + */ + +struct jmploc *handler; +int exception; +volatile int suppressint; +volatile int intpending; +char *commandname; + + +static void exverror __P((int, char *, va_list)) __attribute__((__noreturn__)); + +/* + * 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(e) + 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() { + sigset_t sigset; + + if (suppressint) { + intpending++; + return; + } + intpending = 0; + sigemptyset(&sigset); + sigprocmask(SIG_SETMASK, &sigset, NULL); + if (rootshell && iflag) + exraise(EXINT); + else + _exit(128 + SIGINT); +} + + +/* + * Exverror is called to raise the error exception. If the first argument + * is not NULL then error prints an error message using printf style + * formatting. It then raises the error exception. + */ +static void +exverror(cond, msg, ap) + int cond; + char *msg; + va_list ap; +{ + CLEAR_PENDING_INT; + INTOFF; + +#ifdef DEBUG + if (msg) + TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); + else + TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid())); +#endif + if (msg) { + if (commandname) + outfmt(&errout, "%s: ", commandname); + doformat(&errout, msg, ap); + out2c('\n'); + } + flushall(); + exraise(cond); +} + + +#ifdef __STDC__ +void +error(char *msg, ...) +#else +void +error(va_alist) + va_dcl +#endif +{ +#ifndef __STDC__ + char *msg; +#endif + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); +#else + va_start(ap); + msg = va_arg(ap, char *); +#endif + exverror(EXERROR, msg, ap); + va_end(ap); +} + + +#ifdef __STDC__ +void +exerror(int cond, char *msg, ...) +#else +void +exerror(va_alist) + va_dcl +#endif +{ +#ifndef __STDC__ + int cond; + char *msg; +#endif + va_list ap; +#ifdef __STDC__ + va_start(ap, msg); +#else + va_start(ap); + cond = va_arg(ap, int); + msg = va_arg(ap, char *); +#endif + exverror(cond, msg, ap); + va_end(ap); +} + + + +/* + * Table of error messages. + */ + +struct errname { + short errcode; /* error number */ + short action; /* operation which encountered the error */ + char *msg; /* text describing the error */ +}; + + +#define ALL (E_OPEN|E_CREAT|E_EXEC) + +STATIC const struct errname errormsg[] = { + { EINTR, ALL, "interrupted" }, + { EACCES, ALL, "permission denied" }, + { EIO, ALL, "I/O error" }, + { ENOENT, E_OPEN, "no such file" }, + { ENOENT, E_CREAT,"directory nonexistent" }, + { ENOENT, E_EXEC, "not found" }, + { ENOTDIR, E_OPEN, "no such file" }, + { ENOTDIR, E_CREAT,"directory nonexistent" }, + { ENOTDIR, E_EXEC, "not found" }, + { EISDIR, ALL, "is a directory" }, +#ifdef notdef + { 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 SYSV + { EAGAIN, E_EXEC, "not enough memory" }, +#endif + { ENOMEM, ALL, "not enough memory" }, +#ifdef ENOLINK + { ENOLINK, ALL, "remote access failed" }, +#endif +#ifdef EMULTIHOP + { EMULTIHOP, ALL, "remote access failed" }, +#endif +#ifdef ECOMM + { ECOMM, ALL, "remote access failed" }, +#endif +#ifdef ESTALE + { ESTALE, ALL, "remote access failed" }, +#endif +#ifdef ETIMEDOUT + { ETIMEDOUT, ALL, "remote access failed" }, +#endif +#ifdef ELOOP + { ELOOP, ALL, "symbolic link loop" }, +#endif + { E2BIG, E_EXEC, "argument list too long" }, +#ifdef ELIBACC + { ELIBACC, E_EXEC, "shared library missing" }, +#endif + { 0, 0, NULL }, +}; + + +/* + * Return a string describing an error. The returned string may be a + * pointer to a static buffer that will be overwritten on the next call. + * Action describes the operation that got the error. + */ + +char * +errmsg(e, action) + 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; +} diff --git a/release/picobsd/tinyware/ash/error.h b/release/picobsd/tinyware/ash/error.h new file mode 100644 index 0000000..d54ce6a --- /dev/null +++ b/release/picobsd/tinyware/ash/error.h @@ -0,0 +1,108 @@ +/* $NetBSD: error.h,v 1.10 1997/07/04 21:01:55 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)error.h 8.2 (Berkeley) 5/4/95 + */ + +/* + * Types of operations (passed to the errmsg routine). + */ + +#define E_OPEN 01 /* opening a file */ +#define E_CREAT 02 /* creating a file */ +#define E_EXEC 04 /* executing a program */ + + +/* + * We enclose jmp_buf in a structure so that we can declare pointers to + * jump locations. The global variable handler contains the location to + * jump to when an exception occurs, and the global variable exception + * contains a code identifying the exeception. To implement nested + * 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> + +struct jmploc { + jmp_buf loc; +}; + +extern struct jmploc *handler; +extern int exception; + +/* exceptions */ +#define EXINT 0 /* SIGINT received */ +#define EXERROR 1 /* a generic error */ +#define EXSHELLPROC 2 /* execute a shell procedure */ +#define EXEXEC 3 /* command execution failed */ + + +/* + * These macros allow the user to suspend the handling of interrupt signals + * over a period of time. This is similar to SIGHOLD to or sigblock, but + * much more efficient and portable. (But hacking the kernel is so much + * more fun than worrying about efficiency and portability. :-)) + */ + +extern volatile int suppressint; +extern volatile int intpending; +extern char *commandname; /* name of command--printed on error */ + +#define INTOFF suppressint++ +#define INTON { if (--suppressint == 0 && intpending) onint(); } +#define FORCEINTON {suppressint = 0; if (intpending) onint();} +#define CLEAR_PENDING_INT intpending = 0 +#define int_pending() intpending + +void exraise __P((int)) __attribute__((__noreturn__)); +void onint __P((void)); +void error __P((char *, ...)) __attribute__((__noreturn__)); +void exerror __P((int, char *, ...)); +char *errmsg __P((int, int)); + + +/* + * BSD setjmp saves the signal mask, which violates ANSI C and takes time, + * so we use _setjmp instead. + */ + +#ifdef BSD +#define setjmp(jmploc) _setjmp(jmploc) +#define longjmp(jmploc, val) _longjmp(jmploc, val) +#endif diff --git a/release/picobsd/tinyware/ash/eval.c b/release/picobsd/tinyware/ash/eval.c new file mode 100644 index 0000000..8f69649 --- /dev/null +++ b/release/picobsd/tinyware/ash/eval.c @@ -0,0 +1,1012 @@ +/* $NetBSD: eval.c,v 1.36 1997/07/04 21:01:56 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95"; +#else +__RCSID("$NetBSD: eval.c,v 1.36 1997/07/04 21:01:56 christos Exp $"); +#endif +#endif /* not lint */ + +#include <signal.h> +#include <unistd.h> + +/* + * Evaluate a command. + */ + +#include "shell.h" +#include "nodes.h" +#include "syntax.h" +#include "expand.h" +#include "parser.h" +#include "jobs.h" +#include "eval.h" +#include "builtins.h" +#include "options.h" +#include "exec.h" +#include "redir.h" +#include "input.h" +#include "output.h" +#include "trap.h" +#include "var.h" +#include "memalloc.h" +#include "error.h" +#include "show.h" +#include "mystring.h" +#ifndef SMALL +#include "myhistedit.h" +#endif + + +/* flags in argument to evaltree */ +#define EV_EXIT 01 /* exit after evaluating tree */ +#define EV_TESTED 02 /* exit status is checked; ignore -e flag */ +#define EV_BACKCMD 04 /* command executing within back quotes */ + +MKINIT int evalskip; /* set if we are skipping commands */ +STATIC int skipcount; /* number of levels to skip */ +MKINIT int loopnest; /* current loop nesting level */ +int funcnest; /* depth of function calls */ + + +char *commandname; +struct strlist *cmdenviron; +int exitstatus; /* exit status of last command */ +int oexitstatus; /* saved exit status */ + + +STATIC void evalloop __P((union node *)); +STATIC void evalfor __P((union node *)); +STATIC void evalcase __P((union node *, int)); +STATIC void evalsubshell __P((union node *, int)); +STATIC void expredir __P((union node *)); +STATIC void evalpipe __P((union node *)); +STATIC void evalcommand __P((union node *, int, struct backcmd *)); +STATIC void prehash __P((union node *)); + + +/* + * Called to reset things after an exception. + */ + +#ifdef mkinit +INCLUDE "eval.h" + +RESET { + evalskip = 0; + loopnest = 0; + funcnest = 0; +} + +SHELLPROC { + exitstatus = 0; +} +#endif + + + +/* + * The eval commmand. + */ + +int +evalcmd(argc, argv) + int argc; + char **argv; +{ + char *p; + char *concat; + char **ap; + + if (argc > 1) { + p = argv[1]; + if (argc > 2) { + STARTSTACKSTR(concat); + ap = argv + 2; + for (;;) { + while (*p) + STPUTC(*p++, concat); + if ((p = *ap++) == NULL) + break; + STPUTC(' ', concat); + } + STPUTC('\0', concat); + p = grabstackstr(concat); + } + evalstring(p); + } + return exitstatus; +} + + +/* + * Execute a command or commands contained in a string. + */ + +void +evalstring(s) + char *s; + { + union node *n; + struct stackmark smark; + + setstackmark(&smark); + setinputstring(s, 1); + while ((n = parsecmd(0)) != NEOF) { + evaltree(n, 0); + popstackmark(&smark); + } + popfile(); + popstackmark(&smark); +} + + + +/* + * Evaluate a parse tree. The value is left in the global variable + * exitstatus. + */ + +void +evaltree(n, flags) + union node *n; + int flags; +{ + if (n == NULL) { + TRACE(("evaltree(NULL) called\n")); + exitstatus = 0; + goto out; + } +#ifndef SMALL + displayhist = 1; /* show history substitutions done with fc */ +#endif + TRACE(("evaltree(0x%lx: %d) called\n", (long)n, n->type)); + switch (n->type) { + case NSEMI: + evaltree(n->nbinary.ch1, 0); + if (evalskip) + goto out; + evaltree(n->nbinary.ch2, flags); + break; + case NAND: + evaltree(n->nbinary.ch1, EV_TESTED); + if (evalskip || exitstatus != 0) { + /* don't bomb out on "set -e; false && true" */ + flags |= EV_TESTED; + goto out; + } + evaltree(n->nbinary.ch2, flags); + break; + case NOR: + evaltree(n->nbinary.ch1, EV_TESTED); + if (evalskip || exitstatus == 0) + goto out; + evaltree(n->nbinary.ch2, flags); + break; + case NREDIR: + expredir(n->nredir.redirect); + redirect(n->nredir.redirect, REDIR_PUSH); + evaltree(n->nredir.n, flags); + popredir(); + break; + case NSUBSHELL: + evalsubshell(n, flags); + break; + case NBACKGND: + evalsubshell(n, flags); + break; + case NIF: { + evaltree(n->nif.test, EV_TESTED); + if (evalskip) + goto out; + if (exitstatus == 0) + evaltree(n->nif.ifpart, flags); + else if (n->nif.elsepart) + evaltree(n->nif.elsepart, flags); + else + exitstatus = 0; + break; + } + case NWHILE: + case NUNTIL: + evalloop(n); + break; + case NFOR: + evalfor(n); + break; + case NCASE: + evalcase(n, flags); + break; + case NDEFUN: + defun(n->narg.text, n->narg.next); + exitstatus = 0; + break; + case NNOT: + evaltree(n->nnot.com, EV_TESTED); + exitstatus = !exitstatus; + break; + + case NPIPE: + evalpipe(n); + break; + case NCMD: + evalcommand(n, flags, (struct backcmd *)NULL); + break; + default: + out1fmt("Node type = %d\n", n->type); + flushout(&output); + break; + } +out: + if (pendingsigs) + dotrap(); + if ((flags & EV_EXIT) || (eflag && exitstatus && !(flags & EV_TESTED))) + exitshell(exitstatus); +} + + +STATIC void +evalloop(n) + union node *n; +{ + int status; + + loopnest++; + status = 0; + for (;;) { + evaltree(n->nbinary.ch1, EV_TESTED); + if (evalskip) { +skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { + evalskip = 0; + continue; + } + if (evalskip == SKIPBREAK && --skipcount <= 0) + evalskip = 0; + break; + } + if (n->type == NWHILE) { + if (exitstatus != 0) + break; + } else { + if (exitstatus == 0) + break; + } + evaltree(n->nbinary.ch2, 0); + status = exitstatus; + if (evalskip) + goto skipping; + } + loopnest--; + exitstatus = status; +} + + + +STATIC void +evalfor(n) + union node *n; +{ + struct arglist arglist; + union node *argp; + struct strlist *sp; + struct stackmark smark; + + setstackmark(&smark); + arglist.lastp = &arglist.list; + for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { + oexitstatus = exitstatus; + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); + if (evalskip) + goto out; + } + *arglist.lastp = NULL; + + exitstatus = 0; + loopnest++; + for (sp = arglist.list ; sp ; sp = sp->next) { + setvar(n->nfor.var, sp->text, 0); + evaltree(n->nfor.body, 0); + if (evalskip) { + if (evalskip == SKIPCONT && --skipcount <= 0) { + evalskip = 0; + continue; + } + if (evalskip == SKIPBREAK && --skipcount <= 0) + evalskip = 0; + break; + } + } + loopnest--; +out: + popstackmark(&smark); +} + + + +STATIC void +evalcase(n, flags) + union node *n; + int flags; +{ + union node *cp; + union node *patp; + struct arglist arglist; + struct stackmark smark; + + setstackmark(&smark); + arglist.lastp = &arglist.list; + oexitstatus = exitstatus; + expandarg(n->ncase.expr, &arglist, EXP_TILDE); + for (cp = n->ncase.cases ; cp && evalskip == 0 ; cp = cp->nclist.next) { + for (patp = cp->nclist.pattern ; patp ; patp = patp->narg.next) { + if (casematch(patp, arglist.list->text)) { + if (evalskip == 0) { + evaltree(cp->nclist.body, flags); + } + goto out; + } + } + } +out: + popstackmark(&smark); +} + + + +/* + * Kick off a subshell to evaluate a tree. + */ + +STATIC void +evalsubshell(n, flags) + union node *n; + int flags; +{ + struct job *jp; + int backgnd = (n->type == NBACKGND); + + expredir(n->nredir.redirect); + jp = makejob(n, 1); + if (forkshell(jp, n, backgnd) == 0) { + if (backgnd) + flags &=~ EV_TESTED; + redirect(n->nredir.redirect, 0); + evaltree(n->nredir.n, flags | EV_EXIT); /* never returns */ + } + if (! backgnd) { + INTOFF; + exitstatus = waitforjob(jp); + INTON; + } +} + + + +/* + * Compute the names of the files in a redirection list. + */ + +STATIC void +expredir(n) + union node *n; +{ + union node *redir; + + for (redir = n ; redir ; redir = redir->nfile.next) { + struct arglist fn; + fn.lastp = &fn.list; + oexitstatus = exitstatus; + switch (redir->type) { + case NFROM: + case NTO: + case NAPPEND: + expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); + redir->nfile.expfname = fn.list->text; + break; + case NFROMFD: + case NTOFD: + if (redir->ndup.vname) { + expandarg(redir->ndup.vname, &fn, EXP_FULL | EXP_TILDE); + fixredir(redir, fn.list->text, 1); + } + break; + } + } +} + + + +/* + * Evaluate a pipeline. All the processes in the pipeline are children + * of the process creating the pipeline. (This differs from some versions + * of the shell, which make the last process in a pipeline the parent + * of all the rest.) + */ + +STATIC void +evalpipe(n) + union node *n; +{ + struct job *jp; + struct nodelist *lp; + int pipelen; + int prevfd; + int pip[2]; + + TRACE(("evalpipe(0x%lx) called\n", (long)n)); + pipelen = 0; + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) + pipelen++; + INTOFF; + jp = makejob(n, pipelen); + prevfd = -1; + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { + prehash(lp->n); + pip[1] = -1; + if (lp->next) { + if (pipe(pip) < 0) { + close(prevfd); + error("Pipe call failed"); + } + } + if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { + INTON; + if (prevfd > 0) { + close(0); + copyfd(prevfd, 0); + close(prevfd); + } + if (pip[1] >= 0) { + close(pip[0]); + if (pip[1] != 1) { + close(1); + copyfd(pip[1], 1); + close(pip[1]); + } + } + evaltree(lp->n, EV_EXIT); + } + if (prevfd >= 0) + close(prevfd); + prevfd = pip[0]; + close(pip[1]); + } + INTON; + if (n->npipe.backgnd == 0) { + INTOFF; + exitstatus = waitforjob(jp); + TRACE(("evalpipe: job done exit status %d\n", exitstatus)); + INTON; + } +} + + + +/* + * Execute a command inside back quotes. If it's a builtin command, we + * want to save its output in a block obtained from malloc. Otherwise + * we fork off a subprocess and get the output of the command via a pipe. + * Should be called with interrupts off. + */ + +void +evalbackcmd(n, result) + union node *n; + struct backcmd *result; +{ + int pip[2]; + struct job *jp; + struct stackmark smark; /* unnecessary */ + + setstackmark(&smark); + result->fd = -1; + result->buf = NULL; + result->nleft = 0; + result->jp = NULL; + if (n == NULL) { + exitstatus = 0; + goto out; + } + if (n->type == NCMD) { + exitstatus = oexitstatus; + evalcommand(n, EV_BACKCMD, result); + } else { + exitstatus = 0; + if (pipe(pip) < 0) + error("Pipe call failed"); + jp = makejob(n, 1); + if (forkshell(jp, n, FORK_NOJOB) == 0) { + FORCEINTON; + close(pip[0]); + if (pip[1] != 1) { + close(1); + copyfd(pip[1], 1); + close(pip[1]); + } + evaltree(n, EV_EXIT); + } + close(pip[1]); + result->fd = pip[0]; + result->jp = jp; + } +out: + popstackmark(&smark); + TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", + result->fd, result->buf, result->nleft, result->jp)); +} + + + +/* + * Execute a simple command. + */ + +STATIC void +evalcommand(cmd, flags, backcmd) + union node *cmd; + int flags; + struct backcmd *backcmd; +{ + struct stackmark smark; + union node *argp; + struct arglist arglist; + struct arglist varlist; + char **argv; + int argc; + char **envp; + int varflag; + struct strlist *sp; + int mode; + int pip[2]; + struct cmdentry cmdentry; + struct job *jp; + struct jmploc jmploc; + struct jmploc *volatile savehandler; + char *volatile savecmdname; + volatile struct shparam saveparam; + struct localvar *volatile savelocalvars; + volatile int e; + char *lastarg; +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &argv; + (void) &argc; + (void) &lastarg; + (void) &flags; +#endif + + /* First expand the arguments. */ + TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); + setstackmark(&smark); + arglist.lastp = &arglist.list; + varlist.lastp = &varlist.list; + varflag = 1; + oexitstatus = exitstatus; + exitstatus = 0; + for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { + char *p = argp->narg.text; + if (varflag && is_name(*p)) { + do { + p++; + } while (is_in_name(*p)); + if (*p == '=') { + expandarg(argp, &varlist, EXP_VARTILDE); + continue; + } + } + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); + varflag = 0; + } + *arglist.lastp = NULL; + *varlist.lastp = NULL; + expredir(cmd->ncmd.redirect); + argc = 0; + for (sp = arglist.list ; sp ; sp = sp->next) + argc++; + argv = stalloc(sizeof (char *) * (argc + 1)); + + for (sp = arglist.list ; sp ; sp = sp->next) { + TRACE(("evalcommand arg: %s\n", sp->text)); + *argv++ = sp->text; + } + *argv = NULL; + lastarg = NULL; + if (iflag && funcnest == 0 && argc > 0) + lastarg = argv[-1]; + argv -= argc; + + /* Print the command if xflag is set. */ + if (xflag) { + outc('+', &errout); + for (sp = varlist.list ; sp ; sp = sp->next) { + outc(' ', &errout); + out2str(sp->text); + } + for (sp = arglist.list ; sp ; sp = sp->next) { + outc(' ', &errout); + out2str(sp->text); + } + outc('\n', &errout); + flushout(&errout); + } + + /* Now locate the command. */ + if (argc == 0) { + cmdentry.cmdtype = CMDBUILTIN; + cmdentry.u.index = BLTINCMD; + } else { + static const char PATH[] = "PATH="; + char *path = pathval(); + + /* + * Modify the command lookup path, if a PATH= assignment + * is present + */ + for (sp = varlist.list ; sp ; sp = sp->next) + if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) + path = sp->text + sizeof(PATH) - 1; + + find_command(argv[0], &cmdentry, 1, path); + if (cmdentry.cmdtype == CMDUNKNOWN) { /* command not found */ + exitstatus = 127; + flushout(&errout); + return; + } + /* implement the bltin builtin here */ + if (cmdentry.cmdtype == CMDBUILTIN && cmdentry.u.index == BLTINCMD) { + for (;;) { + argv++; + if (--argc == 0) + break; + if ((cmdentry.u.index = find_builtin(*argv)) < 0) { + outfmt(&errout, "%s: not found\n", *argv); + exitstatus = 127; + flushout(&errout); + return; + } + if (cmdentry.u.index != BLTINCMD) + break; + } + } + } + + /* Fork off a child process if necessary. */ + if (cmd->ncmd.backgnd + || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) + || ((flags & EV_BACKCMD) != 0 + && (cmdentry.cmdtype != CMDBUILTIN + || cmdentry.u.index == DOTCMD + || cmdentry.u.index == EVALCMD))) { + jp = makejob(cmd, 1); + mode = cmd->ncmd.backgnd; + if (flags & EV_BACKCMD) { + mode = FORK_NOJOB; + if (pipe(pip) < 0) + error("Pipe call failed"); + } + if (forkshell(jp, cmd, mode) != 0) + goto parent; /* at end of routine */ + if (flags & EV_BACKCMD) { + FORCEINTON; + close(pip[0]); + if (pip[1] != 1) { + close(1); + copyfd(pip[1], 1); + close(pip[1]); + } + } + flags |= EV_EXIT; + } + + /* This is the child process if a fork occurred. */ + /* Execute the command. */ + if (cmdentry.cmdtype == CMDFUNCTION) { +#ifdef DEBUG + trputs("Shell function: "); trargs(argv); +#endif + redirect(cmd->ncmd.redirect, REDIR_PUSH); + saveparam = shellparam; + shellparam.malloc = 0; + shellparam.reset = 1; + shellparam.nparam = argc - 1; + shellparam.p = argv + 1; + shellparam.optnext = NULL; + INTOFF; + savelocalvars = localvars; + localvars = NULL; + INTON; + if (setjmp(jmploc.loc)) { + if (exception == EXSHELLPROC) + freeparam((struct shparam *)&saveparam); + else { + freeparam(&shellparam); + shellparam = saveparam; + } + poplocalvars(); + localvars = savelocalvars; + handler = savehandler; + longjmp(handler->loc, 1); + } + savehandler = handler; + handler = &jmploc; + for (sp = varlist.list ; sp ; sp = sp->next) + mklocal(sp->text); + funcnest++; + evaltree(cmdentry.u.func, 0); + funcnest--; + INTOFF; + poplocalvars(); + localvars = savelocalvars; + freeparam(&shellparam); + shellparam = saveparam; + handler = savehandler; + popredir(); + INTON; + if (evalskip == SKIPFUNC) { + evalskip = 0; + skipcount = 0; + } + if (flags & EV_EXIT) + exitshell(exitstatus); + } else if (cmdentry.cmdtype == CMDBUILTIN) { +#ifdef DEBUG + trputs("builtin command: "); trargs(argv); +#endif + mode = (cmdentry.u.index == EXECCMD)? 0 : REDIR_PUSH; + if (flags == EV_BACKCMD) { + memout.nleft = 0; + memout.nextc = memout.buf; + memout.bufsize = 64; + mode |= REDIR_BACKQ; + } + redirect(cmd->ncmd.redirect, mode); + savecmdname = commandname; + cmdenviron = varlist.list; + e = -1; + if (setjmp(jmploc.loc)) { + e = exception; + exitstatus = (e == EXINT)? SIGINT+128 : 2; + goto cmddone; + } + savehandler = handler; + handler = &jmploc; + commandname = argv[0]; + argptr = argv + 1; + optptr = NULL; /* initialize nextopt */ + exitstatus = (*builtinfunc[cmdentry.u.index])(argc, argv); + flushall(); +cmddone: + out1 = &output; + out2 = &errout; + freestdout(); + if (e != EXSHELLPROC) { + commandname = savecmdname; + if (flags & EV_EXIT) { + exitshell(exitstatus); + } + } + handler = savehandler; + if (e != -1) { + if ((e != EXERROR && e != EXEXEC) + || cmdentry.u.index == BLTINCMD + || cmdentry.u.index == DOTCMD + || cmdentry.u.index == EVALCMD +#ifndef SMALL + || cmdentry.u.index == HISTCMD +#endif + || cmdentry.u.index == EXECCMD) + exraise(e); + FORCEINTON; + } + if (cmdentry.u.index != EXECCMD) + popredir(); + if (flags == EV_BACKCMD) { + backcmd->buf = memout.buf; + backcmd->nleft = memout.nextc - memout.buf; + memout.buf = NULL; + } + } else { +#ifdef DEBUG + trputs("normal command: "); trargs(argv); +#endif + clearredir(); + redirect(cmd->ncmd.redirect, 0); + for (sp = varlist.list ; sp ; sp = sp->next) + setvareq(sp->text, VEXPORT|VSTACK); + envp = environment(); + shellexec(argv, envp, pathval(), cmdentry.u.index); + /*NOTREACHED*/ + } + goto out; + +parent: /* parent process gets here (if we forked) */ + if (mode == 0) { /* argument to fork */ + INTOFF; + exitstatus = waitforjob(jp); + INTON; + } else if (mode == 2) { + backcmd->fd = pip[0]; + close(pip[1]); + backcmd->jp = jp; + } + +out: + if (lastarg) + setvar("_", lastarg, 0); + popstackmark(&smark); +} + + + +/* + * Search for a command. This is called before we fork so that the + * location of the command will be available in the parent as well as + * the child. The check for "goodname" is an overly conservative + * check that the name will not be subject to expansion. + */ + +STATIC void +prehash(n) + union node *n; +{ + struct cmdentry entry; + + if (n->type == NCMD && n->ncmd.args) + if (goodname(n->ncmd.args->narg.text)) + find_command(n->ncmd.args->narg.text, &entry, 0, + pathval()); +} + + + +/* + * Builtin commands. Builtin commands whose functions are closely + * tied to evaluation are implemented here. + */ + +/* + * No command given, or a bltin command with no arguments. Set the + * specified variables. + */ + +int +bltincmd(argc, argv) + int argc; + char **argv; +{ + listsetvar(cmdenviron); + /* + * Preserve exitstatus of a previous possible redirection + * as POSIX mandates + */ + return exitstatus; +} + + +/* + * Handle break and continue commands. Break, continue, and return are + * all handled by setting the evalskip flag. The evaluation routines + * above all check this flag, and if it is set they start skipping + * commands rather than executing them. The variable skipcount is + * the number of loops to break/continue, or the number of function + * levels to return. (The latter is always 1.) It should probably + * be an error to break out of more loops than exist, but it isn't + * in the standard shell so we don't make it one here. + */ + +int +breakcmd(argc, argv) + int argc; + char **argv; +{ + int n = argc > 1 ? number(argv[1]) : 1; + + if (n > loopnest) + n = loopnest; + if (n > 0) { + evalskip = (**argv == 'c')? SKIPCONT : SKIPBREAK; + skipcount = n; + } + return 0; +} + + +/* + * The return command. + */ + +int +returncmd(argc, argv) + int argc; + char **argv; +{ + int ret = argc > 1 ? number(argv[1]) : oexitstatus; + + if (funcnest) { + evalskip = SKIPFUNC; + skipcount = 1; + return ret; + } + else { + /* Do what ksh does; skip the rest of the file */ + evalskip = SKIPFILE; + skipcount = 1; + return ret; + } +} + + +int +falsecmd(argc, argv) + int argc; + char **argv; +{ + return 1; +} + + +int +truecmd(argc, argv) + int argc; + char **argv; +{ + return 0; +} + + +int +execcmd(argc, argv) + int argc; + char **argv; +{ + if (argc > 1) { + struct strlist *sp; + + iflag = 0; /* exit on error */ + mflag = 0; + optschanged(); + for (sp = cmdenviron; sp ; sp = sp->next) + setvareq(sp->text, VEXPORT|VSTACK); + shellexec(argv + 1, environment(), pathval(), 0); + + } + return 0; +} diff --git a/release/picobsd/tinyware/ash/eval.h b/release/picobsd/tinyware/ash/eval.h new file mode 100644 index 0000000..58b0580 --- /dev/null +++ b/release/picobsd/tinyware/ash/eval.h @@ -0,0 +1,74 @@ +/* $NetBSD: eval.h,v 1.9 1995/09/11 17:05:43 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)eval.h 8.2 (Berkeley) 5/4/95 + */ + +extern char *commandname; /* currently executing command */ +extern int exitstatus; /* exit status of last command */ +extern struct strlist *cmdenviron; /* environment for builtin command */ + + +struct backcmd { /* result of evalbackcmd */ + int fd; /* file descriptor to read from */ + char *buf; /* buffer */ + int nleft; /* number of chars in buffer */ + struct job *jp; /* job structure for command */ +}; + +int evalcmd __P((int, char **)); +void evalstring __P((char *)); +union node; /* BLETCH for ansi C */ +void evaltree __P((union node *, int)); +void evalbackcmd __P((union node *, struct backcmd *)); +int bltincmd __P((int, char **)); +int breakcmd __P((int, char **)); +int returncmd __P((int, char **)); +int falsecmd __P((int, char **)); +int truecmd __P((int, char **)); +int execcmd __P((int, char **)); + +/* in_function returns nonzero if we are currently evaluating a function */ +#define in_function() funcnest +extern int funcnest; +extern int evalskip; + +/* reasons for skipping commands (see comment on breakcmd routine) */ +#define SKIPBREAK 1 +#define SKIPCONT 2 +#define SKIPFUNC 3 +#define SKIPFILE 4 diff --git a/release/picobsd/tinyware/ash/exec.c b/release/picobsd/tinyware/ash/exec.c new file mode 100644 index 0000000..b04653d --- /dev/null +++ b/release/picobsd/tinyware/ash/exec.c @@ -0,0 +1,921 @@ +/* $NetBSD: exec.c,v 1.23 1997/07/04 21:01:59 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.23 1997/07/04 21:01:59 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <stdlib.h> + +/* + * When commands are first encountered, they are entered in a hash table. + * This ensures that a full path search will not have to be done for them + * on each invocation. + * + * We should investigate converting to a linear search, even though that + * would make the command name "hash" a misnomer. + */ + +#include "shell.h" +#include "main.h" +#include "nodes.h" +#include "parser.h" +#include "redir.h" +#include "eval.h" +#include "exec.h" +#include "builtins.h" +#include "var.h" +#include "options.h" +#include "input.h" +#include "output.h" +#include "syntax.h" +#include "memalloc.h" +#include "error.h" +#include "init.h" +#include "mystring.h" +#include "show.h" +#include "jobs.h" +#include "alias.h" + + +#define CMDTABLESIZE 31 /* should be prime */ +#define ARB 1 /* actual size determined at run time */ + + + +struct tblentry { + struct tblentry *next; /* next entry in hash chain */ + union param param; /* definition of builtin function */ + short cmdtype; /* index identifying command */ + char rehash; /* if set, cd done since entry created */ + char cmdname[ARB]; /* name of command */ +}; + + +STATIC struct tblentry *cmdtable[CMDTABLESIZE]; +STATIC int builtinloc = -1; /* index in path of %builtin, or -1 */ +int exerrno = 0; /* Last exec error */ + + +STATIC void tryexec __P((char *, char **, char **)); +STATIC void execinterp __P((char **, char **)); +STATIC void printentry __P((struct tblentry *, int)); +STATIC void clearcmdentry __P((int)); +STATIC struct tblentry *cmdlookup __P((char *, int)); +STATIC void delete_cmd_entry __P((void)); + + + +/* + * Exec a program. Never returns. If you change this routine, you may + * have to change the find_command routine as well. + */ + +void +shellexec(argv, envp, path, index) + char **argv, **envp; + char *path; + int index; +{ + char *cmdname; + int e; + + if (strchr(argv[0], '/') != NULL) { + tryexec(argv[0], argv, envp); + e = errno; + } else { + e = ENOENT; + while ((cmdname = padvance(&path, argv[0])) != NULL) { + if (--index < 0 && pathopt == NULL) { + tryexec(cmdname, argv, envp); + if (errno != ENOENT && errno != ENOTDIR) + e = errno; + } + stunalloc(cmdname); + } + } + + /* Map to POSIX errors */ + switch (e) { + case EACCES: + exerrno = 126; + break; + case ENOENT: + exerrno = 127; + break; + default: + exerrno = 2; + break; + } + exerror(EXEXEC, "%s: %s", argv[0], errmsg(e, E_EXEC)); +} + + +STATIC void +tryexec(cmd, argv, envp) + char *cmd; + char **argv; + char **envp; + { + 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) { + 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(argv, envp) + char **argv, **envp; + { + int n; + char *inp; + char *outp; + char c; + char *p; + char **ap; + char *newargs[NEWARGS]; + int i; + char **ap2; + char **new; + + n = parsenleft - 2; + inp = parsenextc + 2; + ap = newargs; + for (;;) { + while (--n >= 0 && (*inp == ' ' || *inp == '\t')) + inp++; + if (n < 0) + goto bad; + if ((c = *inp++) == '\n') + break; + if (ap == &newargs[NEWARGS]) +bad: error("Bad #! line"); + STARTSTACKSTR(outp); + do { + STPUTC(c, outp); + } while (--n >= 0 && (c = *inp++) != ' ' && c != '\t' && c != '\n'); + STPUTC('\0', outp); + n++, inp--; + *ap++ = grabstackstr(outp); + } + if (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); +} +#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 + * this value as it proceeds. Successive calls to padvance will return + * the possible path expansions in sequence. If an option (indicated by + * a percent sign) appears in the path entry then the global variable + * pathopt will be set to point to it; otherwise pathopt will be set to + * NULL. + */ + +char *pathopt; + +char * +padvance(path, name) + char **path; + char *name; + { + char *p, *q; + char *start; + int len; + + if (*path == NULL) + return NULL; + start = *path; + for (p = start ; *p && *p != ':' && *p != '%' ; p++); + len = p - start + strlen(name) + 2; /* "2" is for '/' and '\0' */ + while (stackblocksize() < len) + growstackblock(); + q = stackblock(); + if (p != start) { + memcpy(q, start, p - start); + q += p - start; + *q++ = '/'; + } + strcpy(q, name); + pathopt = NULL; + if (*p == '%') { + pathopt = ++p; + while (*p && *p != ':') p++; + } + if (*p == ':') + *path = p + 1; + else + *path = NULL; + return stalloc(len); +} + + + +/*** Command hashing code ***/ + + +int +hashcmd(argc, argv) + int argc; + char **argv; +{ + struct tblentry **pp; + struct tblentry *cmdp; + int c; + int verbose; + struct cmdentry entry; + char *name; + + verbose = 0; + while ((c = nextopt("rv")) != '\0') { + if (c == 'r') { + clearcmdentry(0); + } else if (c == 'v') { + verbose++; + } + } + if (*argptr == NULL) { + for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + printentry(cmdp, verbose); + } + } + return 0; + } + while ((name = *argptr) != NULL) { + if ((cmdp = cmdlookup(name, 0)) != NULL + && (cmdp->cmdtype == CMDNORMAL + || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0))) + delete_cmd_entry(); + find_command(name, &entry, 1, pathval()); + if (verbose) { + if (entry.cmdtype != CMDUNKNOWN) { /* if no error msg */ + cmdp = cmdlookup(name, 0); + printentry(cmdp, verbose); + } + flushall(); + } + argptr++; + } + return 0; +} + + +STATIC void +printentry(cmdp, verbose) + struct tblentry *cmdp; + int verbose; + { + int index; + char *path; + char *name; + + if (cmdp->cmdtype == CMDNORMAL) { + index = cmdp->param.index; + path = pathval(); + do { + name = padvance(&path, cmdp->cmdname); + stunalloc(name); + } while (--index >= 0); + out1str(name); + } else if (cmdp->cmdtype == CMDBUILTIN) { + out1fmt("builtin %s", cmdp->cmdname); + } else if (cmdp->cmdtype == CMDFUNCTION) { + out1fmt("function %s", cmdp->cmdname); + if (verbose) { + INTOFF; + name = commandtext(cmdp->param.func); + out1c(' '); + out1str(name); + ckfree(name); + INTON; + } +#ifdef DEBUG + } else { + error("internal error: cmdtype %d", cmdp->cmdtype); +#endif + } + if (cmdp->rehash) + out1c('*'); + out1c('\n'); +} + + + +/* + * Resolve a command name. If you change this routine, you may have to + * change the shellexec routine as well. + */ + +void +find_command(name, entry, printerr, path) + char *name; + struct cmdentry *entry; + int printerr; + char *path; +{ + struct tblentry *cmdp; + int index; + int prev; + char *fullname; + struct stat statb; + int e; + int i; + + /* If name contains a slash, don't use the hash table */ + if (strchr(name, '/') != NULL) { + 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 %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; + } + + /* We have to search path. */ + prev = -1; /* where to start */ + if (cmdp) { /* doing a rehash */ + if (cmdp->cmdtype == CMDBUILTIN) + prev = builtinloc; + else + prev = cmdp->param.index; + } + + e = ENOENT; + index = -1; +loop: + while ((fullname = padvance(&path, name)) != NULL) { + stunalloc(fullname); + index++; + if (pathopt) { + if (prefix("builtin", pathopt)) { + if ((i = find_builtin(name)) < 0) + goto loop; + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDBUILTIN; + cmdp->param.index = i; + INTON; + goto success; + } else if (prefix("func", pathopt)) { + /* handled below */ + } else { + goto loop; /* ignore unimplemented options */ + } + } + /* if rehash, don't redo absolute path names */ + if (fullname[0] == '/' && index <= prev) { + if (index < prev) + goto loop; + TRACE(("searchexec \"%s\": no change\n", name)); + goto success; + } + while (stat(fullname, &statb) < 0) { +#ifdef SYSV + if (errno == EINTR) + continue; +#endif + if (errno != ENOENT && errno != ENOTDIR) + e = errno; + goto loop; + } + e = EACCES; /* if we fail, this will be the error */ + if (!S_ISREG(statb.st_mode)) + goto loop; + if (pathopt) { /* this is a %func directory */ + stalloc(strlen(fullname) + 1); + readcmdfile(fullname); + if ((cmdp = cmdlookup(name, 0)) == NULL || cmdp->cmdtype != CMDFUNCTION) + error("%s not defined in %s", name, fullname); + stunalloc(fullname); + goto success; + } +#ifdef notdef + if (statb.st_uid == geteuid()) { + if ((statb.st_mode & 0100) == 0) + goto loop; + } else if (statb.st_gid == getegid()) { + if ((statb.st_mode & 010) == 0) + goto loop; + } else { + if ((statb.st_mode & 01) == 0) + goto loop; + } +#endif + TRACE(("searchexec \"%s\" returns \"%s\"\n", name, fullname)); + INTOFF; + cmdp = cmdlookup(name, 1); + cmdp->cmdtype = CMDNORMAL; + cmdp->param.index = index; + INTON; + goto success; + } + + /* We failed. If there was an entry for this command, delete it */ + if (cmdp) + delete_cmd_entry(); + if (printerr) + outfmt(out2, "%s: %s\n", name, errmsg(e, E_EXEC)); + entry->cmdtype = CMDUNKNOWN; + return; + +success: + cmdp->rehash = 0; + entry->cmdtype = cmdp->cmdtype; + entry->u = cmdp->param; +} + + + +/* + * Search the table of builtin commands. + */ + +int +find_builtin(name) + char *name; +{ + const struct builtincmd *bp; + + for (bp = builtincmd ; bp->name ; bp++) { + if (*bp->name == *name && equal(bp->name, name)) + return bp->code; + } + return -1; +} + + + +/* + * Called when a cd is done. Marks all commands so the next time they + * are executed they will be rehashed. + */ + +void +hashcd() { + struct tblentry **pp; + struct tblentry *cmdp; + + for (pp = cmdtable ; pp < &cmdtable[CMDTABLESIZE] ; pp++) { + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + if (cmdp->cmdtype == CMDNORMAL + || (cmdp->cmdtype == CMDBUILTIN && builtinloc >= 0)) + cmdp->rehash = 1; + } + } +} + + + +/* + * 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. + */ + +void +changepath(newval) + const char *newval; +{ + const char *old, *new; + int index; + int firstchange; + int bltin; + + old = pathval(); + new = newval; + firstchange = 9999; /* assume no change */ + index = 0; + bltin = -1; + for (;;) { + if (*old != *new) { + firstchange = index; + if ((*old == '\0' && *new == ':') + || (*old == ':' && *new == '\0')) + firstchange++; + old = new; /* ignore subsequent differences */ + } + if (*new == '\0') + break; + if (*new == '%' && bltin < 0 && prefix("builtin", new + 1)) + bltin = index; + if (*new == ':') { + index++; + } + new++, old++; + } + if (builtinloc < 0 && bltin >= 0) + builtinloc = bltin; /* zap builtins */ + if (builtinloc >= 0 && bltin < 0) + firstchange = 0; + clearcmdentry(firstchange); + builtinloc = bltin; +} + + +/* + * Clear out command entries. The argument specifies the first entry in + * PATH which has changed. + */ + +STATIC void +clearcmdentry(firstchange) + int firstchange; +{ + struct tblentry **tblp; + struct tblentry **pp; + struct tblentry *cmdp; + + INTOFF; + for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { + pp = tblp; + while ((cmdp = *pp) != NULL) { + if ((cmdp->cmdtype == CMDNORMAL && + cmdp->param.index >= firstchange) + || (cmdp->cmdtype == CMDBUILTIN && + builtinloc >= firstchange)) { + *pp = cmdp->next; + ckfree(cmdp); + } else { + pp = &cmdp->next; + } + } + } + INTON; +} + + +/* + * Delete all functions. + */ + +#ifdef mkinit +MKINIT void deletefuncs __P((void)); + +SHELLPROC { + deletefuncs(); +} +#endif + +void +deletefuncs() { + struct tblentry **tblp; + struct tblentry **pp; + struct tblentry *cmdp; + + INTOFF; + for (tblp = cmdtable ; tblp < &cmdtable[CMDTABLESIZE] ; tblp++) { + pp = tblp; + while ((cmdp = *pp) != NULL) { + if (cmdp->cmdtype == CMDFUNCTION) { + *pp = cmdp->next; + freefunc(cmdp->param.func); + ckfree(cmdp); + } else { + pp = &cmdp->next; + } + } + } + INTON; +} + + + +/* + * Locate a command in the command hash table. If "add" is nonzero, + * add the command to the table if it is not already present. The + * variable "lastcmdentry" is set to point to the address of the link + * pointing to the entry, so that delete_cmd_entry can delete the + * entry. + */ + +struct tblentry **lastcmdentry; + + +STATIC struct tblentry * +cmdlookup(name, add) + char *name; + int add; +{ + int hashval; + char *p; + struct tblentry *cmdp; + struct tblentry **pp; + + p = name; + hashval = *p << 4; + while (*p) + hashval += *p++; + hashval &= 0x7FFF; + pp = &cmdtable[hashval % CMDTABLESIZE]; + for (cmdp = *pp ; cmdp ; cmdp = cmdp->next) { + if (equal(cmdp->cmdname, name)) + break; + pp = &cmdp->next; + } + if (add && cmdp == NULL) { + INTOFF; + cmdp = *pp = ckmalloc(sizeof (struct tblentry) - ARB + + strlen(name) + 1); + cmdp->next = NULL; + cmdp->cmdtype = CMDUNKNOWN; + cmdp->rehash = 0; + strcpy(cmdp->cmdname, name); + INTON; + } + lastcmdentry = pp; + return cmdp; +} + +/* + * Delete the command entry returned on the last lookup. + */ + +STATIC void +delete_cmd_entry() { + struct tblentry *cmdp; + + INTOFF; + cmdp = *lastcmdentry; + *lastcmdentry = cmdp->next; + ckfree(cmdp); + INTON; +} + + + +#ifdef notdef +void +getcmdentry(name, entry) + char *name; + struct cmdentry *entry; + { + struct tblentry *cmdp = cmdlookup(name, 0); + + if (cmdp) { + entry->u = cmdp->param; + entry->cmdtype = cmdp->cmdtype; + } else { + entry->cmdtype = CMDUNKNOWN; + entry->u.index = 0; + } +} +#endif + + +/* + * Add a new command entry, replacing any existing command entry for + * the same name. + */ + +void +addcmdentry(name, entry) + char *name; + struct cmdentry *entry; + { + struct tblentry *cmdp; + + INTOFF; + cmdp = cmdlookup(name, 1); + if (cmdp->cmdtype == CMDFUNCTION) { + freefunc(cmdp->param.func); + } + cmdp->cmdtype = entry->cmdtype; + cmdp->param = entry->u; + INTON; +} + + +/* + * Define a shell function. + */ + +void +defun(name, func) + char *name; + union node *func; + { + struct cmdentry entry; + + INTOFF; + entry.cmdtype = CMDFUNCTION; + entry.u.func = copyfunc(func); + addcmdentry(name, &entry); + INTON; +} + + +/* + * Delete a function if it exists. + */ + +int +unsetfunc(name) + char *name; + { + struct tblentry *cmdp; + + if ((cmdp = cmdlookup(name, 0)) != NULL && cmdp->cmdtype == CMDFUNCTION) { + freefunc(cmdp->param.func); + delete_cmd_entry(); + return (0); + } + return (1); +} + +/* + * Locate and print what a word is... + */ + +int +typecmd(argc, argv) + int argc; + char **argv; +{ + struct cmdentry entry; + struct tblentry *cmdp; + char **pp; + struct alias *ap; + int i; + int error = 0; + extern char *const parsekwd[]; + + for (i = 1; i < argc; i++) { + out1str(argv[i]); + /* First look at the keywords */ + for (pp = (char **)parsekwd; *pp; pp++) + if (**pp == *argv[i] && equal(*pp, argv[i])) + break; + + if (*pp) { + out1str(" is a shell keyword\n"); + continue; + } + + /* Then look at the aliases */ + if ((ap = lookupalias(argv[i], 1)) != NULL) { + out1fmt(" is an alias for %s\n", ap->val); + continue; + } + + /* Then check if it is a tracked alias */ + if ((cmdp = cmdlookup(argv[i], 0)) != NULL) { + entry.cmdtype = cmdp->cmdtype; + entry.u = cmdp->param; + } + else { + /* Finally use brute force */ + find_command(argv[i], &entry, 0, pathval()); + } + + switch (entry.cmdtype) { + case CMDNORMAL: { + int j = entry.u.index; + char *path = pathval(), *name; + do { + name = padvance(&path, argv[i]); + stunalloc(name); + } while (--j >= 0); + out1fmt(" is%s %s\n", + cmdp ? " a tracked alias for" : "", name); + break; + } + case CMDFUNCTION: + out1str(" is a shell function\n"); + break; + + case CMDBUILTIN: + out1str(" is a shell builtin\n"); + break; + + default: + out1str(" not found\n"); + error |= 127; + break; + } + } + return error; +} diff --git a/release/picobsd/tinyware/ash/exec.h b/release/picobsd/tinyware/ash/exec.h new file mode 100644 index 0000000..9c03616 --- /dev/null +++ b/release/picobsd/tinyware/ash/exec.h @@ -0,0 +1,72 @@ +/* $NetBSD: exec.h,v 1.12 1997/02/06 23:24:53 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)exec.h 8.3 (Berkeley) 6/8/95 + */ + +/* 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 */ + + +struct cmdentry { + int cmdtype; + union param { + int index; + union node *func; + } u; +}; + + +extern char *pathopt; /* set by padvance */ +extern int exerrno; /* last exec error */ + +void shellexec __P((char **, char **, char *, int)); +char *padvance __P((char **, char *)); +int hashcmd __P((int, char **)); +void find_command __P((char *, struct cmdentry *, int, char *)); +int find_builtin __P((char *)); +void hashcd __P((void)); +void changepath __P((const char *)); +void deletefuncs __P((void)); +void getcmdentry __P((char *, struct cmdentry *)); +void addcmdentry __P((char *, struct cmdentry *)); +void defun __P((char *, union node *)); +int unsetfunc __P((char *)); +int typecmd __P((int, char **)); diff --git a/release/picobsd/tinyware/ash/expand.c b/release/picobsd/tinyware/ash/expand.c new file mode 100644 index 0000000..9d444d0 --- /dev/null +++ b/release/picobsd/tinyware/ash/expand.c @@ -0,0 +1,1385 @@ +/* $NetBSD: expand.c,v 1.31 1997/07/07 20:41:10 phil 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)expand.c 8.5 (Berkeley) 5/15/95"; +#else +__RCSID("$NetBSD: expand.c,v 1.31 1997/07/07 20:41:10 phil Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <errno.h> +#include <dirent.h> +#include <unistd.h> +#include <pwd.h> +#include <stdlib.h> + +/* + * Routines to expand arguments to commands. We have to deal with + * backquotes, shell variables, and file metacharacters. + */ + +#include "shell.h" +#include "main.h" +#include "nodes.h" +#include "eval.h" +#include "expand.h" +#include "syntax.h" +#include "parser.h" +#include "jobs.h" +#include "options.h" +#include "var.h" +#include "input.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "mystring.h" +#include "arith.h" +#include "show.h" + +/* + * Structure specifying which parts of the string should be searched + * for IFS characters. + */ + +struct ifsregion { + struct ifsregion *next; /* next region in list */ + int begoff; /* offset of start of region */ + int endoff; /* offset of end of region */ + int nulonly; /* search for nul bytes only */ +}; + + +char *expdest; /* output of current string */ +struct nodelist *argbackq; /* list of back quote expressions */ +struct ifsregion ifsfirst; /* first struct in list of ifs regions */ +struct ifsregion *ifslastp; /* last struct in list */ +struct arglist exparg; /* holds expanded arg list */ + +STATIC void argstr __P((char *, int)); +STATIC char *exptilde __P((char *, int)); +STATIC void expbackq __P((union node *, int, int)); +STATIC int subevalvar __P((char *, char *, int, int, int, int)); +STATIC char *evalvar __P((char *, int)); +STATIC int varisset __P((char *, int)); +STATIC void varvalue __P((char *, int, int)); +STATIC void recordregion __P((int, int, int)); +STATIC void ifsbreakup __P((char *, struct arglist *)); +STATIC void expandmeta __P((struct strlist *, int)); +STATIC void expmeta __P((char *, char *)); +STATIC void addfname __P((char *)); +STATIC struct strlist *expsort __P((struct strlist *)); +STATIC struct strlist *msort __P((struct strlist *, int)); +STATIC int pmatch __P((char *, char *)); +STATIC char *cvtnum __P((int, char *)); + +/* + * Expand shell variables and backquotes inside a here document. + */ + +void +expandhere(arg, fd) + union node *arg; /* the document */ + int fd; /* where to write the expanded version */ + { + herefd = fd; + expandarg(arg, (struct arglist *)NULL, 0); + xwrite(fd, stackblock(), expdest - stackblock()); +} + + +/* + * Perform variable substitution and command substitution on an argument, + * placing the resulting list of arguments in arglist. If EXP_FULL is true, + * perform splitting and file name expansion. When arglist is NULL, perform + * here document expansion. + */ + +void +expandarg(arg, arglist, flag) + union node *arg; + struct arglist *arglist; + int flag; +{ + struct strlist *sp; + char *p; + + argbackq = arg->narg.backquote; + STARTSTACKSTR(expdest); + ifsfirst.next = NULL; + ifslastp = NULL; + argstr(arg->narg.text, flag); + if (arglist == NULL) { + return; /* here document expanded */ + } + STPUTC('\0', expdest); + p = grabstackstr(expdest); + exparg.lastp = &exparg.list; + /* + * TODO - EXP_REDIR + */ + if (flag & EXP_FULL) { + ifsbreakup(p, &exparg); + *exparg.lastp = NULL; + exparg.lastp = &exparg.list; + expandmeta(exparg.list, flag); + } else { + if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ + rmescapes(p); + sp = (struct strlist *)stalloc(sizeof (struct strlist)); + sp->text = p; + *exparg.lastp = sp; + exparg.lastp = &sp->next; + } + while (ifsfirst.next != NULL) { + struct ifsregion *ifsp; + INTOFF; + ifsp = ifsfirst.next->next; + ckfree(ifsfirst.next); + ifsfirst.next = ifsp; + INTON; + } + *exparg.lastp = NULL; + if (exparg.list) { + *arglist->lastp = exparg.list; + arglist->lastp = exparg.lastp; + } +} + + + +/* + * Perform variable and command substitution. If EXP_FULL is set, output CTLESC + * characters to allow for further processing. Otherwise treat + * $@ like $* since no splitting will be performed. + */ + +STATIC void +argstr(p, flag) + char *p; + int flag; +{ + char c; + int quotes = flag & (EXP_FULL | EXP_CASE); /* do CTLESC */ + int firsteq = 1; + + if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE))) + p = exptilde(p, flag); + for (;;) { + switch (c = *p++) { + case '\0': + case CTLENDVAR: /* ??? */ + goto breakloop; + case CTLESC: + if (quotes) + STPUTC(c, expdest); + c = *p++; + STPUTC(c, expdest); + break; + case CTLVAR: + p = evalvar(p, flag); + break; + case CTLBACKQ: + case CTLBACKQ|CTLQUOTE: + expbackq(argbackq->n, c & CTLQUOTE, flag); + argbackq = argbackq->next; + break; + case CTLENDARI: + expari(flag); + break; + case ':': + case '=': + /* + * sort of a hack - expand tildes in variable + * assignments (after the first '=' and after ':'s). + */ + STPUTC(c, expdest); + if (flag & EXP_VARTILDE && *p == '~') { + if (c == '=') { + if (firsteq) + firsteq = 0; + else + break; + } + p = exptilde(p, flag); + } + break; + default: + STPUTC(c, expdest); + } + } +breakloop:; +} + +STATIC char * +exptilde(p, flag) + char *p; + int flag; +{ + char c, *startp = p; + struct passwd *pw; + char *home; + int quotes = flag & (EXP_FULL | EXP_CASE); + + while ((c = *p) != '\0') { + switch(c) { + case CTLESC: + return (startp); + case ':': + if (flag & EXP_VARTILDE) + goto done; + break; + case '/': + goto done; + } + p++; + } +done: + *p = '\0'; + if (*(startp+1) == '\0') { + if ((home = lookupvar("HOME")) == NULL) + goto lose; + } else { + if ((pw = getpwnam(startp+1)) == NULL) + goto lose; + home = pw->pw_dir; + } + if (*home == '\0') + goto lose; + *p = c; + while ((c = *home++) != '\0') { + if (quotes && SQSYNTAX[c] == CCTL) + STPUTC(CTLESC, expdest); + STPUTC(c, expdest); + } + return (p); +lose: + *p = c; + return (startp); +} + + +/* + * Expand arithmetic expression. Backup to start of expression, + * evaluate, place result in (backed up) result, adjust string position. + */ +void +expari(flag) + int flag; +{ + char *p, *start; + int result; + int quotes = flag & (EXP_FULL | EXP_CASE); + + while (ifsfirst.next != NULL) { + struct ifsregion *ifsp; + INTOFF; + ifsp = ifsfirst.next->next; + ckfree(ifsfirst.next); + ifsfirst.next = ifsp; + INTON; + } + ifslastp = NULL; + + /* + * This routine is slightly over-compilcated for + * efficiency. First we make sure there is + * enough space for the result, which may be bigger + * than the expression if we add exponentation. Next we + * scan backwards looking for the start of arithmetic. If the + * next previous character is a CTLESC character, then we + * have to rescan starting from the beginning since CTLESC + * characters have to be processed left to right. + */ + CHECKSTRSPACE(8, expdest); + USTPUTC('\0', expdest); + start = stackblock(); + p = expdest; + while (*p != CTLARI && p >= start) + --p; + if (*p != CTLARI) + error("missing CTLARI (shouldn't happen)"); + if (p > start && *(p-1) == CTLESC) + for (p = start; *p != CTLARI; p++) + if (*p == CTLESC) + p++; + if (quotes) + rmescapes(p+1); + result = arith(p+1); + fmtstr(p, 10, "%d", result); + + while (*p++) + ; + + result = expdest - p + 1; + STADJUST(-result, expdest); +} + + +/* + * Expand stuff in backwards quotes. + */ + +STATIC void +expbackq(cmd, quoted, flag) + union node *cmd; + int quoted; + int flag; +{ + struct backcmd in; + int i; + char buf[128]; + char *p; + char *dest = expdest; + struct ifsregion saveifs, *savelastp; + struct nodelist *saveargbackq; + char lastc; + int startloc = dest - stackblock(); + char const *syntax = quoted? DQSYNTAX : BASESYNTAX; + int saveherefd; + int quotes = flag & (EXP_FULL | EXP_CASE); + + INTOFF; + saveifs = ifsfirst; + savelastp = ifslastp; + saveargbackq = argbackq; + saveherefd = herefd; + herefd = -1; + p = grabstackstr(dest); + evalbackcmd(cmd, &in); + ungrabstackstr(p, dest); + ifsfirst = saveifs; + ifslastp = savelastp; + argbackq = saveargbackq; + herefd = saveherefd; + + p = in.buf; + lastc = '\0'; + for (;;) { + if (--in.nleft < 0) { + if (in.fd < 0) + break; + while ((i = read(in.fd, buf, sizeof buf)) < 0 && errno == EINTR); + TRACE(("expbackq: read returns %d\n", i)); + if (i <= 0) + break; + p = buf; + in.nleft = i - 1; + } + lastc = *p++; + if (lastc != '\0') { + if (quotes && syntax[lastc] == CCTL) + STPUTC(CTLESC, dest); + STPUTC(lastc, dest); + } + } + + /* Eat all trailing newlines */ + for (p--; lastc == '\n'; lastc = *--p) + STUNPUTC(dest); + + if (in.fd >= 0) + close(in.fd); + if (in.buf) + ckfree(in.buf); + if (in.jp) + exitstatus = waitforjob(in.jp); + if (quoted == 0) + recordregion(startloc, dest - stackblock(), 0); + TRACE(("evalbackq: size=%d: \"%.*s\"\n", + (dest - stackblock()) - startloc, + (dest - stackblock()) - startloc, + stackblock() + startloc)); + expdest = dest; + INTON; +} + + + +STATIC int +subevalvar(p, str, strloc, subtype, startloc, varflags) + char *p; + char *str; + int strloc; + int subtype; + int startloc; + int varflags; +{ + char *startp; + char *loc = NULL; + int c = 0; + int saveherefd = herefd; + struct nodelist *saveargbackq = argbackq; + int amount; + + herefd = -1; + argstr(p, 0); + STACKSTRNUL(expdest); + herefd = saveherefd; + argbackq = saveargbackq; + startp = stackblock() + startloc; + if (str == NULL) + str = stackblock() + strloc; + + switch (subtype) { + case VSASSIGN: + setvar(str, startp, 0); + amount = startp - expdest; + STADJUST(amount, expdest); + varflags &= ~VSNUL; + if (c != 0) + *loc = c; + return 1; + + case VSQUESTION: + if (*p != CTLENDVAR) { + outfmt(&errout, "%s\n", startp); + error((char *)NULL); + } + error("%.*s: parameter %snot set", p - str - 1, + str, (varflags & VSNUL) ? "null or " + : nullstr); + return 0; + + case VSTRIMLEFT: + for (loc = startp; loc < str; loc++) { + c = *loc; + *loc = '\0'; + if (patmatch(str, startp)) { + *loc = c; + goto recordleft; + } + *loc = c; + } + return 0; + + case VSTRIMLEFTMAX: + for (loc = str - 1; loc >= startp; loc--) { + c = *loc; + *loc = '\0'; + if (patmatch(str, startp)) { + *loc = c; + goto recordleft; + } + *loc = c; + } + return 0; + + case VSTRIMRIGHT: + for (loc = str - 1; loc >= startp; loc--) { + if (patmatch(str, loc)) { + amount = loc - expdest; + STADJUST(amount, expdest); + return 1; + } + } + return 0; + + case VSTRIMRIGHTMAX: + for (loc = startp; loc < str - 1; loc++) { + if (patmatch(str, loc)) { + amount = loc - expdest; + STADJUST(amount, expdest); + return 1; + } + } + return 0; + + + default: + abort(); + } + +recordleft: + amount = ((str - 1) - (loc - startp)) - expdest; + STADJUST(amount, expdest); + while (loc != str - 1) + *startp++ = *loc++; + return 1; +} + + +/* + * Expand a variable, and return a pointer to the next character in the + * input string. + */ + +STATIC char * +evalvar(p, flag) + char *p; + int flag; +{ + int subtype; + int varflags; + char *var; + char *val; + char *pat; + int c; + int set; + int special; + int startloc; + int varlen; + int easy; + int quotes = flag & (EXP_FULL | EXP_CASE); + + varflags = *p++; + subtype = varflags & VSTYPE; + var = p; + special = 0; + if (! is_name(*p)) + special = 1; + p = strchr(p, '=') + 1; +again: /* jump here after setting a variable with ${var=text} */ + if (special) { + set = varisset(var, varflags & VSNUL); + val = NULL; + } else { + val = lookupvar(var); + if (val == NULL || ((varflags & VSNUL) && val[0] == '\0')) { + val = NULL; + set = 0; + } else + set = 1; + } + varlen = 0; + startloc = expdest - stackblock(); + if (set && subtype != VSPLUS) { + /* insert the value of the variable */ + if (special) { + varvalue(var, varflags & VSQUOTE, flag & EXP_FULL); + if (subtype == VSLENGTH) { + varlen = expdest - stackblock() - startloc; + STADJUST(-varlen, expdest); + } + } else { + char const *syntax = (varflags & VSQUOTE) ? DQSYNTAX + : BASESYNTAX; + + if (subtype == VSLENGTH) { + for (;*val; val++) + varlen++; + } + else { + while (*val) { + if (quotes && syntax[*val] == CCTL) + STPUTC(CTLESC, expdest); + STPUTC(*val++, expdest); + } + + } + } + } + + if (subtype == VSPLUS) + set = ! set; + + easy = ((varflags & VSQUOTE) == 0 || + (*var == '@' && shellparam.nparam != 1)); + + + switch (subtype) { + case VSLENGTH: + expdest = cvtnum(varlen, expdest); + goto record; + + case VSNORMAL: + if (!easy) + break; +record: + recordregion(startloc, expdest - stackblock(), + varflags & VSQUOTE); + break; + + case VSPLUS: + case VSMINUS: + if (!set) { + argstr(p, flag); + break; + } + if (easy) + goto record; + break; + + case VSTRIMLEFT: + case VSTRIMLEFTMAX: + case VSTRIMRIGHT: + case VSTRIMRIGHTMAX: + if (!set) + break; + /* + * Terminate the string and start recording the pattern + * right after it + */ + STPUTC('\0', expdest); + pat = expdest; + if (subevalvar(p, NULL, expdest - stackblock(), subtype, + startloc, varflags)) + goto record; + else { + int amount = (expdest - pat) + 1; + STADJUST(-amount, expdest); + } + break; + + case VSASSIGN: + case VSQUESTION: + if (!set) { + if (subevalvar(p, var, 0, subtype, startloc, varflags)) { + varflags &= ~VSNUL; + goto again; + } + break; + } + if (easy) + goto record; + break; + + default: + abort(); + } + + if (subtype != VSNORMAL) { /* skip to end of alternative */ + int nesting = 1; + for (;;) { + if ((c = *p++) == CTLESC) + p++; + else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { + if (set) + argbackq = argbackq->next; + } else if (c == CTLVAR) { + if ((*p++ & VSTYPE) != VSNORMAL) + nesting++; + } else if (c == CTLENDVAR) { + if (--nesting == 0) + break; + } + } + } + return p; +} + + + +/* + * Test whether a specialized variable is set. + */ + +STATIC int +varisset(name, nulok) + char *name; + int nulok; +{ + if (*name == '!') + return backgndpid != -1; + else if (*name == '@' || *name == '*') { + if (*shellparam.p == NULL) + return 0; + + if (nulok) { + char **av; + + for (av = shellparam.p; *av; av++) + if (**av != '\0') + return 1; + return 0; + } + } else if (is_digit(*name)) { + char *ap; + int num = atoi(name); + + if (num > shellparam.nparam) + return 0; + + if (num == 0) + ap = arg0; + else + ap = shellparam.p[num - 1]; + + if (nulok && (ap == NULL || *ap == '\0')) + return 0; + } + return 1; +} + + + +/* + * Add the value of a specialized variable to the stack string. + */ + +STATIC void +varvalue(name, quoted, allow_split) + char *name; + int quoted; + int allow_split; +{ + int num; + char *p; + int i; + extern int oexitstatus; + char sep; + char **ap; + char const *syntax; + +#define STRTODEST(p) \ + do {\ + if (allow_split) { \ + syntax = quoted? DQSYNTAX : BASESYNTAX; \ + while (*p) { \ + if (syntax[*p] == CCTL) \ + STPUTC(CTLESC, expdest); \ + STPUTC(*p++, expdest); \ + } \ + } else \ + while (*p) \ + STPUTC(*p++, expdest); \ + } while (0) + + + switch (*name) { + case '$': + num = rootpid; + goto numvar; + case '?': + num = oexitstatus; + goto numvar; + case '#': + num = shellparam.nparam; + goto numvar; + case '!': + num = backgndpid; +numvar: + expdest = cvtnum(num, expdest); + break; + case '-': + for (i = 0 ; i < NOPTS ; i++) { + if (optlist[i].val) + STPUTC(optlist[i].letter, expdest); + } + break; + case '@': + if (allow_split) { + sep = '\0'; + goto allargs; + } + /* fall through */ + case '*': + sep = ((p=bltinlookup("IFS", 1)) == NULL || p[0] == '\0') + ? ' ' : p[0]; + +allargs: + for (ap = shellparam.p ; (p = *ap++) != NULL ; ) { + STRTODEST(p); + if (*ap) + STPUTC(sep, expdest); + } + break; + case '0': + p = arg0; + STRTODEST(p); + break; + default: + if (is_digit(*name)) { + num = atoi(name); + if (num > 0 && num <= shellparam.nparam) { + p = shellparam.p[num - 1]; + STRTODEST(p); + } + } + break; + } +} + + + +/* + * Record the the fact that we have to scan this region of the + * string for IFS characters. + */ + +STATIC void +recordregion(start, end, nulonly) + int start; + int end; + int nulonly; +{ + struct ifsregion *ifsp; + + if (ifslastp == NULL) { + ifsp = &ifsfirst; + } else { + ifsp = (struct ifsregion *)ckmalloc(sizeof (struct ifsregion)); + ifslastp->next = ifsp; + } + ifslastp = ifsp; + ifslastp->next = NULL; + ifslastp->begoff = start; + ifslastp->endoff = end; + ifslastp->nulonly = nulonly; +} + + + +/* + * Break the argument string into pieces based upon IFS and add the + * strings to the argument list. The regions of the string to be + * searched for IFS characters have been stored by recordregion. + */ +STATIC void +ifsbreakup(string, arglist) + char *string; + struct arglist *arglist; + { + struct ifsregion *ifsp; + struct strlist *sp; + char *start; + char *p; + char *q; + char *ifs; + int ifsspc; + + + start = string; + if (ifslastp != NULL) { + ifsp = &ifsfirst; + do { + p = string + ifsp->begoff; + ifs = ifsp->nulonly? nullstr : ifsval(); + ifsspc = strchr(ifs, ' ') != NULL; + while (p < string + ifsp->endoff) { + q = p; + if (*p == CTLESC) + p++; + if (strchr(ifs, *p++)) { + if (q > start || !ifsspc) { + *q = '\0'; + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; + } + if (ifsspc) { + for (;;) { + if (p >= string + ifsp->endoff) + break; + q = p; + if (*p == CTLESC) + p++; + if (strchr(ifs, *p++) == NULL) { + p = q; + break; + } + } + } + start = p; + } + } + } while ((ifsp = ifsp->next) != NULL); + if (*start || (!ifsspc && start > string)) { + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; + } + } else { + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = start; + *arglist->lastp = sp; + arglist->lastp = &sp->next; + } +} + + + +/* + * Expand shell metacharacters. At this point, the only control characters + * should be escapes. The results are stored in the list exparg. + */ + +char *expdir; + + +STATIC void +expandmeta(str, flag) + struct strlist *str; + int flag; +{ + char *p; + struct strlist **savelastp; + struct strlist *sp; + char c; + /* TODO - EXP_REDIR */ + + while (str) { + if (fflag) + goto nometa; + p = str->text; + for (;;) { /* fast check for meta chars */ + if ((c = *p++) == '\0') + goto nometa; + if (c == '*' || c == '?' || c == '[' || c == '!') + break; + } + savelastp = exparg.lastp; + INTOFF; + if (expdir == NULL) { + int i = strlen(str->text); + expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ + } + + expmeta(expdir, str->text); + ckfree(expdir); + expdir = NULL; + INTON; + if (exparg.lastp == savelastp) { + /* + * no matches + */ +nometa: + *exparg.lastp = str; + rmescapes(str->text); + exparg.lastp = &str->next; + } else { + *exparg.lastp = NULL; + *savelastp = sp = expsort(*savelastp); + while (sp->next != NULL) + sp = sp->next; + exparg.lastp = &sp->next; + } + str = str->next; + } +} + + +/* + * Do metacharacter (i.e. *, ?, [...]) expansion. + */ + +STATIC void +expmeta(enddir, name) + char *enddir; + char *name; + { + char *p; + char *q; + char *start; + char *endname; + int metaflag; + struct stat statb; + DIR *dirp; + struct dirent *dp; + int atend; + int matchdot; + + metaflag = 0; + start = name; + for (p = name ; ; p++) { + if (*p == '*' || *p == '?') + metaflag = 1; + else if (*p == '[') { + q = p + 1; + if (*q == '!') + q++; + for (;;) { + if (*q == CTLESC) + q++; + if (*q == '/' || *q == '\0') + break; + if (*++q == ']') { + metaflag = 1; + break; + } + } + } else if (*p == '!' && p[1] == '!' && (p == name || p[-1] == '/')) { + metaflag = 1; + } else if (*p == '\0') + break; + else if (*p == CTLESC) + p++; + if (*p == '/') { + if (metaflag) + break; + start = p + 1; + } + } + if (metaflag == 0) { /* we've reached the end of the file name */ + if (enddir != expdir) + metaflag++; + for (p = name ; ; p++) { + if (*p == CTLESC) + p++; + *enddir++ = *p; + if (*p == '\0') + break; + } + if (metaflag == 0 || stat(expdir, &statb) >= 0) + addfname(expdir); + return; + } + endname = p; + if (start != name) { + p = name; + while (p < start) { + if (*p == CTLESC) + p++; + *enddir++ = *p++; + } + } + if (enddir == expdir) { + p = "."; + } else if (enddir == expdir + 1 && *expdir == '/') { + p = "/"; + } else { + p = expdir; + enddir[-1] = '\0'; + } + if ((dirp = opendir(p)) == NULL) + return; + if (enddir != expdir) + enddir[-1] = '/'; + if (*endname == 0) { + atend = 1; + } else { + atend = 0; + *endname++ = '\0'; + } + matchdot = 0; + if (start[0] == '.' || (start[0] == CTLESC && start[1] == '.')) + matchdot++; + while (! int_pending() && (dp = readdir(dirp)) != NULL) { + if (dp->d_name[0] == '.' && ! matchdot) + continue; + if (patmatch(start, dp->d_name)) { + if (atend) { + scopy(dp->d_name, enddir); + addfname(expdir); + } else { + char *q; + for (p = enddir, q = dp->d_name; + (*p++ = *q++) != '\0';) + continue; + p[-1] = '/'; + expmeta(p, endname); + } + } + } + closedir(dirp); + if (! atend) + endname[-1] = '/'; +} + + +/* + * Add a file name to the list. + */ + +STATIC void +addfname(name) + char *name; + { + char *p; + struct strlist *sp; + + p = stalloc(strlen(name) + 1); + scopy(name, p); + sp = (struct strlist *)stalloc(sizeof *sp); + sp->text = p; + *exparg.lastp = sp; + exparg.lastp = &sp->next; +} + + +/* + * Sort the results of file name expansion. It calculates the number of + * strings to sort and then calls msort (short for merge sort) to do the + * work. + */ + +STATIC struct strlist * +expsort(str) + struct strlist *str; + { + int len; + struct strlist *sp; + + len = 0; + for (sp = str ; sp ; sp = sp->next) + len++; + return msort(str, len); +} + + +STATIC struct strlist * +msort(list, len) + struct strlist *list; + int len; +{ + struct strlist *p, *q = NULL; + struct strlist **lpp; + int half; + int n; + + if (len <= 1) + return list; + half = len >> 1; + p = list; + for (n = half ; --n >= 0 ; ) { + q = p; + p = p->next; + } + q->next = NULL; /* terminate first half of list */ + q = msort(list, half); /* sort first half of list */ + p = msort(p, len - half); /* sort second half */ + lpp = &list; + for (;;) { + if (strcmp(p->text, q->text) < 0) { + *lpp = p; + lpp = &p->next; + if ((p = *lpp) == NULL) { + *lpp = q; + break; + } + } else { + *lpp = q; + lpp = &q->next; + if ((q = *lpp) == NULL) { + *lpp = p; + break; + } + } + } + return list; +} + + + +/* + * Returns true if the pattern matches the string. + */ + +int +patmatch(pattern, string) + char *pattern; + char *string; + { +#ifdef notdef + if (pattern[0] == '!' && pattern[1] == '!') + return 1 - pmatch(pattern + 2, string); + else +#endif + return pmatch(pattern, string); +} + + +STATIC int +pmatch(pattern, string) + char *pattern; + char *string; + { + char *p, *q; + char c; + + p = pattern; + q = string; + for (;;) { + switch (c = *p++) { + case '\0': + goto breakloop; + case CTLESC: + if (*q++ != *p++) + return 0; + break; + case '?': + if (*q++ == '\0') + return 0; + break; + case '*': + c = *p; + if (c != CTLESC && c != '?' && c != '*' && c != '[') { + while (*q != c) { + if (*q == '\0') + return 0; + q++; + } + } + do { + if (pmatch(p, q)) + return 1; + } while (*q++ != '\0'); + return 0; + case '[': { + char *endp; + int invert, found; + char chr; + + endp = p; + if (*endp == '!') + endp++; + for (;;) { + if (*endp == '\0') + goto dft; /* no matching ] */ + if (*endp == CTLESC) + endp++; + if (*++endp == ']') + break; + } + invert = 0; + if (*p == '!') { + invert++; + p++; + } + found = 0; + chr = *q++; + if (chr == '\0') + return 0; + c = *p++; + do { + if (c == CTLESC) + c = *p++; + if (*p == '-' && p[1] != ']') { + p++; + if (*p == CTLESC) + p++; + if (chr >= c && chr <= *p) + found = 1; + p++; + } else { + if (chr == c) + found = 1; + } + } while ((c = *p++) != ']'); + if (found == invert) + return 0; + break; + } +dft: default: + if (*q++ != c) + return 0; + break; + } + } +breakloop: + if (*q != '\0') + return 0; + return 1; +} + + + +/* + * Remove any CTLESC characters from a string. + */ + +void +rmescapes(str) + char *str; + { + char *p, *q; + + p = str; + while (*p != CTLESC) { + if (*p++ == '\0') + return; + } + q = p; + while (*p) { + if (*p == CTLESC) + p++; + *q++ = *p++; + } + *q = '\0'; +} + + + +/* + * See if a pattern matches in a case statement. + */ + +int +casematch(pattern, val) + union node *pattern; + char *val; + { + struct stackmark smark; + int result; + char *p; + + setstackmark(&smark); + argbackq = pattern->narg.backquote; + STARTSTACKSTR(expdest); + ifslastp = NULL; + argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); + STPUTC('\0', expdest); + p = grabstackstr(expdest); + result = patmatch(p, val); + popstackmark(&smark); + return result; +} + +/* + * Our own itoa(). + */ + +STATIC char * +cvtnum(num, buf) + int num; + char *buf; + { + char temp[32]; + int neg = num < 0; + char *p = temp + 31; + + temp[31] = '\0'; + + do { + *--p = num % 10 + '0'; + } while ((num /= 10) != 0); + + if (neg) + *--p = '-'; + + while (*p) + STPUTC(*p++, buf); + return buf; +} diff --git a/release/picobsd/tinyware/ash/expand.h b/release/picobsd/tinyware/ash/expand.h new file mode 100644 index 0000000..a4dde98 --- /dev/null +++ b/release/picobsd/tinyware/ash/expand.h @@ -0,0 +1,68 @@ +/* $NetBSD: expand.h,v 1.8 1995/05/11 21:29:08 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)expand.h 8.2 (Berkeley) 5/4/95 + */ + +struct strlist { + struct strlist *next; + char *text; +}; + + +struct arglist { + struct strlist *list; + struct strlist **lastp; +}; + +/* + * expandarg() flags + */ +#define EXP_FULL 0x1 /* perform word splitting & file globbing */ +#define EXP_TILDE 0x2 /* do normal tilde expansion */ +#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ +#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ +#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ + + +union node; +void expandhere __P((union node *, int)); +void expandarg __P((union node *, struct arglist *, int)); +void expari __P((int)); +int patmatch __P((char *, char *)); +void rmescapes __P((char *)); +int casematch __P((union node *, char *)); diff --git a/release/picobsd/tinyware/ash/funcs/cmv b/release/picobsd/tinyware/ash/funcs/cmv new file mode 100644 index 0000000..667f846 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/cmv @@ -0,0 +1,50 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)cmv 8.2 (Berkeley) 5/4/95 + +# Conditional move--don't replace an existing file. + +cmv() { + if test $# != 2 + then echo "cmv: arg count" + return 2 + fi + if test -f "$2" -o -w "$2" + then echo "$2 exists" + return 2 + fi + /bin/mv "$1" "$2" +} diff --git a/release/picobsd/tinyware/ash/funcs/dirs b/release/picobsd/tinyware/ash/funcs/dirs new file mode 100644 index 0000000..68bb317 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/dirs @@ -0,0 +1,74 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)dirs 8.2 (Berkeley) 5/4/95 + +# pushd, popd, and dirs --- written by Chris Bertin +# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris +# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW + +pushd () { + SAVE=`pwd` + if [ "$1" = "" ] + then if [ "$DSTACK" = "" ] + then echo "pushd: directory stack empty." + return 1 + fi + set $DSTACK + cd $1 || return + shift 1 + DSTACK="$*" + else cd $1 > /dev/null || return + fi + DSTACK="$SAVE $DSTACK" + dirs +} + +popd () { + if [ "$DSTACK" = "" ] + then echo "popd: directory stack empty." + return 1 + fi + set $DSTACK + cd $1 + shift + DSTACK=$* + dirs +} + +dirs () { + echo "`pwd` $DSTACK" + return 0 +} diff --git a/release/picobsd/tinyware/ash/funcs/kill b/release/picobsd/tinyware/ash/funcs/kill new file mode 100644 index 0000000..75b0180 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/kill @@ -0,0 +1,50 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)kill 8.2 (Berkeley) 5/4/95 + +# Convert job names to process ids and then run /bin/kill. + +kill() { + local args x + args= + for x in "$@" + do case $x in + %*) x=`jobid "$x"` ;; + esac + args="$args $x" + done + /bin/kill $args +} diff --git a/release/picobsd/tinyware/ash/funcs/login b/release/picobsd/tinyware/ash/funcs/login new file mode 100644 index 0000000..7ae08b2 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/login @@ -0,0 +1,39 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)login 8.2 (Berkeley) 5/4/95 + +# replaces the login builtin in the BSD shell +login () exec login "$@" diff --git a/release/picobsd/tinyware/ash/funcs/newgrp b/release/picobsd/tinyware/ash/funcs/newgrp new file mode 100644 index 0000000..796a4f1 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/newgrp @@ -0,0 +1,38 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)newgrp 8.2 (Berkeley) 5/4/95 + +newgrp() exec newgrp "$@" diff --git a/release/picobsd/tinyware/ash/funcs/popd b/release/picobsd/tinyware/ash/funcs/popd new file mode 100644 index 0000000..b2b65d5 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/popd @@ -0,0 +1,74 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)popd 8.2 (Berkeley) 5/4/95 + +# pushd, popd, and dirs --- written by Chris Bertin +# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris +# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW + +pushd () { + SAVE=`pwd` + if [ "$1" = "" ] + then if [ "$DSTACK" = "" ] + then echo "pushd: directory stack empty." + return 1 + fi + set $DSTACK + cd $1 || return + shift 1 + DSTACK="$*" + else cd $1 > /dev/null || return + fi + DSTACK="$SAVE $DSTACK" + dirs +} + +popd () { + if [ "$DSTACK" = "" ] + then echo "popd: directory stack empty." + return 1 + fi + set $DSTACK + cd $1 + shift + DSTACK=$* + dirs +} + +dirs () { + echo "`pwd` $DSTACK" + return 0 +} diff --git a/release/picobsd/tinyware/ash/funcs/pushd b/release/picobsd/tinyware/ash/funcs/pushd new file mode 100644 index 0000000..b393038 --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/pushd @@ -0,0 +1,74 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)pushd 8.2 (Berkeley) 5/4/95 + +# pushd, popd, and dirs --- written by Chris Bertin +# Pixel Computer Inc. ...!wjh12!pixel!pixutl!chris +# as modified by Patrick Elam of GTRI and Kenneth Almquist at UW + +pushd () { + SAVE=`pwd` + if [ "$1" = "" ] + then if [ "$DSTACK" = "" ] + then echo "pushd: directory stack empty." + return 1 + fi + set $DSTACK + cd $1 || return + shift 1 + DSTACK="$*" + else cd $1 > /dev/null || return + fi + DSTACK="$SAVE $DSTACK" + dirs +} + +popd () { + if [ "$DSTACK" = "" ] + then echo "popd: directory stack empty." + return 1 + fi + set $DSTACK + cd $1 + shift + DSTACK=$* + dirs +} + +dirs () { + echo "`pwd` $DSTACK" + return 0 +} diff --git a/release/picobsd/tinyware/ash/funcs/suspend b/release/picobsd/tinyware/ash/funcs/suspend new file mode 100644 index 0000000..8a4197d --- /dev/null +++ b/release/picobsd/tinyware/ash/funcs/suspend @@ -0,0 +1,42 @@ +# $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. +# +# This code is derived from software contributed to Berkeley by +# Kenneth Almquist. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)suspend 8.2 (Berkeley) 5/4/95 + +suspend() { + local - + set +j + kill -TSTP 0 +} diff --git a/release/picobsd/tinyware/ash/histedit.c b/release/picobsd/tinyware/ash/histedit.c new file mode 100644 index 0000000..73883c6 --- /dev/null +++ b/release/picobsd/tinyware/ash/histedit.c @@ -0,0 +1,501 @@ +/* $NetBSD: histedit.c,v 1.14 1997/07/04 21:02:02 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.14 1997/07/04 21:02:02 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/param.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +/* + * Editline and history functions (and glue). + */ +#include "shell.h" +#include "parser.h" +#include "var.h" +#include "options.h" +#include "main.h" +#include "output.h" +#include "mystring.h" +#ifndef SMALL +#include "myhistedit.h" +#include "error.h" +#include "eval.h" +#include "memalloc.h" + +#define MAXHISTLOOPS 4 /* max recursions through fc */ +#define DEFEDITOR "ed" /* default editor *should* be $EDITOR */ + +History *hist; /* history cookie */ +EditLine *el; /* editline cookie */ +int displayhist; +static FILE *el_in, *el_out; + +STATIC char *fc_replace __P((const char *, char *, char *)); + +/* + * Set history and editing status. Called whenever the status may + * have changed (figures out what to do). + */ +void +histedit() +{ + +#define editing (Eflag || Vflag) + + if (iflag) { + if (!hist) { + /* + * turn history on + */ + INTOFF; + hist = history_init(); + INTON; + + if (hist != NULL) + sethistsize(histsizeval()); + else + out2str("sh: can't initialize history\n"); + } + if (editing && !el && isatty(0)) { /* && isatty(2) ??? */ + /* + * turn editing on + */ + INTOFF; + if (el_in == NULL) + el_in = fdopen(0, "r"); + if (el_out == NULL) + el_out = fdopen(2, "w"); + if (el_in == NULL || el_out == NULL) + goto bad; + el = el_init(arg0, el_in, el_out); + if (el != NULL) { + if (hist) + el_set(el, EL_HIST, history, hist); + el_set(el, EL_PROMPT, getprompt); + } else { +bad: + out2str("sh: can't initialize editing\n"); + } + INTON; + } else if (!editing && el) { + INTOFF; + el_end(el); + el = NULL; + INTON; + } + if (el) { + if (Vflag) + el_set(el, EL_EDITOR, "vi"); + else if (Eflag) + el_set(el, EL_EDITOR, "emacs"); + } + } else { + INTOFF; + if (el) { /* no editing if not interactive */ + el_end(el); + el = NULL; + } + if (hist) { + history_end(hist); + hist = NULL; + } + INTON; + } +} + + +void +sethistsize(hs) + const char *hs; +{ + int histsize; + + if (hist != NULL) { + if (hs == NULL || *hs == '\0' || + (histsize = atoi(hs)) < 0) + histsize = 100; + history(hist, H_EVENT, histsize); + } +} + +void +setterm(term) + 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"); + } +} + +/* + * This command is provided since POSIX decided to standardize + * the Korn shell fc command. Oh well... + */ +int +histcmd(argc, argv) + int argc; + char **argv; +{ + extern char *optarg; + extern int optind, optopt, optreset; + int ch; + char *editor = NULL; + const HistEvent *he; + int lflg = 0, nflg = 0, rflg = 0, sflg = 0; + int i; + char *firststr, *laststr; + int first, last, direction; + char *pat = NULL, *repl; /* ksh "fc old=new" crap */ + static int active = 0; + struct jmploc jmploc; + struct jmploc *volatile savehandler; + char editfile[MAXPATHLEN + 1]; + FILE *efp; +#ifdef __GNUC__ + /* Avoid longjmp clobbering */ + (void) &editor; + (void) &lflg; + (void) &nflg; + (void) &rflg; + (void) &sflg; + (void) &firststr; + (void) &laststr; + (void) &pat; + (void) &repl; + (void) &efp; + (void) &argc; + (void) &argv; +#endif + + if (hist == NULL) + error("history not active"); + + if (argc == 1) + error("missing history argument"); + + optreset = 1; optind = 1; /* initialize getopt */ + while (not_fcnumber(argv[optind]) && + (ch = getopt(argc, argv, ":e:lnrs")) != EOF) + switch ((char)ch) { + case 'e': + editor = optarg; + break; + case 'l': + lflg = 1; + break; + case 'n': + nflg = 1; + break; + case 'r': + rflg = 1; + break; + case 's': + sflg = 1; + break; + case ':': + error("option -%c expects argument", optopt); + case '?': + default: + error("unknown option: -%c", optopt); + } + argc -= optind, argv += optind; + + /* + * If executing... + */ + if (lflg == 0 || editor || sflg) { + lflg = 0; /* ignore */ + editfile[0] = '\0'; + /* + * Catch interrupts to reset active counter and + * cleanup temp files. + */ + if (setjmp(jmploc.loc)) { + active = 0; + if (*editfile) + unlink(editfile); + handler = savehandler; + longjmp(handler->loc, 1); + } + savehandler = handler; + handler = &jmploc; + if (++active > MAXHISTLOOPS) { + active = 0; + displayhist = 0; + error("called recursively too many times"); + } + /* + * Set editor. + */ + if (sflg == 0) { + if (editor == NULL && + (editor = bltinlookup("FCEDIT", 1)) == NULL && + (editor = bltinlookup("EDITOR", 1)) == NULL) + editor = DEFEDITOR; + if (editor[0] == '-' && editor[1] == '\0') { + sflg = 1; /* no edit */ + editor = NULL; + } + } + } + + /* + * If executing, parse [old=new] now + */ + if (lflg == 0 && argc > 0 && + ((repl = strchr(argv[0], '=')) != NULL)) { + pat = argv[0]; + *repl++ = '\0'; + argc--, argv++; + } + /* + * determine [first] and [last] + */ + switch (argc) { + case 0: + firststr = lflg ? "-16" : "-1"; + laststr = "-1"; + break; + case 1: + firststr = argv[0]; + laststr = lflg ? "-1" : argv[0]; + break; + case 2: + firststr = argv[0]; + laststr = argv[1]; + break; + default: + error("too many args"); + } + /* + * Turn into event numbers. + */ + first = str_to_event(firststr, 0); + last = str_to_event(laststr, 1); + + if (rflg) { + i = last; + last = first; + first = i; + } + /* + * XXX - this should not depend on the event numbers + * always increasing. Add sequence numbers or offset + * to the history element in next (diskbased) release. + */ + direction = first < last ? H_PREV : H_NEXT; + + /* + * If editing, grab a temp file. + */ + if (editor) { + int fd; + INTOFF; /* easier */ + sprintf(editfile, "%s/_shXXXXXX", _PATH_TMP); + if ((fd = mkstemp(editfile)) < 0) + error("can't create temporary file %s", editfile); + if ((efp = fdopen(fd, "w")) == NULL) { + close(fd); + error("can't allocate stdio buffer for temp"); + } + } + + /* + * Loop through selected history events. If listing or executing, + * do it now. Otherwise, put into temp file and call the editor + * after. + * + * The history interface needs rethinking, as the following + * convolutions will demonstrate. + */ + history(hist, H_FIRST); + he = history(hist, H_NEXT_EVENT, first); + for (;he != NULL; he = history(hist, direction)) { + if (lflg) { + if (!nflg) + out1fmt("%5d ", he->num); + out1str(he->str); + } else { + char *s = pat ? + fc_replace(he->str, pat, repl) : (char *)he->str; + + if (sflg) { + if (displayhist) { + out2str(s); + } + evalstring(s); + if (displayhist && hist) { + /* + * XXX what about recursive and + * relative histnums. + */ + history(hist, H_ENTER, s); + } + } else + fputs(s, efp); + } + /* + * At end? (if we were to loose last, we'd sure be + * messed up). + */ + if (he->num == last) + break; + } + if (editor) { + char *editcmd; + + fclose(efp); + editcmd = stalloc(strlen(editor) + strlen(editfile) + 2); + sprintf(editcmd, "%s %s", editor, editfile); + evalstring(editcmd); /* XXX - should use no JC command */ + INTON; + readcmdfile(editfile); /* XXX - should read back - quick tst */ + unlink(editfile); + } + + if (lflg == 0 && active > 0) + --active; + if (displayhist) + displayhist = 0; + return 0; +} + +STATIC char * +fc_replace(s, p, r) + const char *s; + char *p, *r; +{ + char *dest; + int plen = strlen(p); + + STARTSTACKSTR(dest); + while (*s) { + if (*s == *p && strncmp(s, p, plen) == 0) { + while (*r) + STPUTC(*r++, dest); + s += plen; + *p = '\0'; /* so no more matches */ + } else + STPUTC(*s++, dest); + } + STACKSTRNUL(dest); + dest = grabstackstr(dest); + + return (dest); +} + +int +not_fcnumber(s) + char *s; +{ + if (s == NULL) + return 0; + if (*s == '-') + s++; + return (!is_number(s)); +} + +int +str_to_event(str, last) + char *str; + int last; +{ + const HistEvent *he; + char *s = str; + int relative = 0; + int i; + + he = history(hist, H_FIRST); + switch (*s) { + case '-': + relative = 1; + /*FALLTHROUGH*/ + case '+': + s++; + } + if (is_number(s)) { + i = atoi(s); + if (relative) { + while (he != NULL && i--) { + he = history(hist, H_NEXT); + } + if (he == NULL) + he = history(hist, H_LAST); + } else { + he = history(hist, H_NEXT_EVENT, i); + if (he == NULL) { + /* + * the notion of first and last is + * backwards to that of the history package + */ + he = history(hist, last ? H_FIRST : H_LAST); + } + } + if (he == NULL) + error("history number %s not found (internal error)", + str); + } else { + /* + * pattern + */ + he = history(hist, H_PREV_STR, str); + if (he == NULL) + error("history pattern not found: %s", str); + } + return (he->num); +} +#else +int +histcmd(argc, argv) + int argc; + char **argv; +{ + error("not compiled with history support"); +} +#endif diff --git a/release/picobsd/tinyware/ash/init.h b/release/picobsd/tinyware/ash/init.h new file mode 100644 index 0000000..3252aec --- /dev/null +++ b/release/picobsd/tinyware/ash/init.h @@ -0,0 +1,43 @@ +/* $NetBSD: init.h,v 1.8 1995/05/11 21:29:14 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)init.h 8.2 (Berkeley) 5/4/95 + */ + +void init __P((void)); +void reset __P((void)); +void initshellproc __P((void)); diff --git a/release/picobsd/tinyware/ash/input.c b/release/picobsd/tinyware/ash/input.c new file mode 100644 index 0000000..84c5fb8 --- /dev/null +++ b/release/picobsd/tinyware/ash/input.c @@ -0,0 +1,516 @@ +/* $NetBSD: input.c,v 1.27 1997/07/04 21:02:03 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.27 1997/07/04 21:02:03 christos Exp $"); +#endif +#endif /* not lint */ + +#include <stdio.h> /* defines BUFSIZ */ +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + +/* + * This file implements the input routines used by the parser. + */ + +#include "shell.h" +#include "redir.h" +#include "syntax.h" +#include "input.h" +#include "output.h" +#include "options.h" +#include "memalloc.h" +#include "error.h" +#include "alias.h" +#include "parser.h" +#include "myhistedit.h" + +#define EOF_NLEFT -99 /* value of parsenleft when EOF pushed back */ + +MKINIT +struct strpush { + struct strpush *prev; /* preceding string on stack */ + char *prevstring; + int prevnleft; + int prevlleft; + struct alias *ap; /* if push was associated with an alias */ +}; + +/* + * The parsefile structure pointed to by the global variable parsefile + * contains information about the current file being read. + */ + +MKINIT +struct parsefile { + struct parsefile *prev; /* preceding file on stack */ + int linno; /* current line */ + int fd; /* file descriptor (or -1 if string) */ + int nleft; /* number of chars left in this line */ + 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 */ + struct strpush basestrpush; /* so pushing one is fast */ +}; + + +int plinno = 1; /* input line number */ +MKINIT int parsenleft; /* copy of parsefile->nleft */ +MKINIT int parselleft; /* copy of parsefile->lleft */ +char *parsenextc; /* copy of parsefile->nextc */ +MKINIT struct parsefile basepf; /* top level input file */ +char basebuf[BUFSIZ]; /* buffer for top level input file */ +struct parsefile *parsefile = &basepf; /* current input file */ +int init_editline = 0; /* editline library initialized? */ +int whichprompt; /* 1 == PS1, 2 == PS2 */ + +EditLine *el; /* cookie for editline package */ + +STATIC void pushfile __P((void)); +static int preadfd __P((void)); + +#ifdef mkinit +INCLUDE "input.h" +INCLUDE "error.h" + +INIT { + extern char basebuf[]; + + basepf.nextc = basepf.buf = basebuf; +} + +RESET { + if (exception != EXSHELLPROC) + parselleft = parsenleft = 0; /* clear input buffer */ + popallfiles(); +} + +SHELLPROC { + popallfiles(); +} +#endif + + +/* + * Read a line from the script. + */ + +char * +pfgets(line, len) + char *line; + int len; +{ + char *p = line; + int nleft = len; + int c; + + while (--nleft > 0) { + c = pgetc_macro(); + if (c == PEOF) { + if (p == line) + return NULL; + break; + } + *p++ = c; + if (c == '\n') + break; + } + *p = '\0'; + return line; +} + + + +/* + * Read a character from the script, returning PEOF on end of file. + * Nul characters in the input are silently discarded. + */ + +int +pgetc() +{ + return pgetc_macro(); +} + + +static int +preadfd() +{ + int nr; + parsenextc = parsefile->buf; + +retry: +#ifndef SMALL + if (parsefile->fd == 0 && el) { + const char *rl_cp; + + rl_cp = el_gets(el, &nr); + if (rl_cp == NULL) + nr = 0; + else { + /* XXX - BUFSIZE should redesign so not necessary */ + (void) strcpy(parsenextc, rl_cp); + } + } else +#endif + nr = read(parsefile->fd, parsenextc, BUFSIZ - 1); + + + if (nr <= 0) { + if (nr < 0) { + if (errno == EINTR) + goto retry; + if (parsefile->fd == 0 && errno == EWOULDBLOCK) { + int flags = fcntl(0, F_GETFL, 0); + if (flags >= 0 && flags & O_NONBLOCK) { + flags &=~ O_NONBLOCK; + if (fcntl(0, F_SETFL, flags) >= 0) { + out2str("sh: turning off NDELAY mode\n"); + goto retry; + } + } + } + } + nr = -1; + } + return nr; +} + +/* + * Refill the input buffer and return the next input character: + * + * 1) If a string was pushed back on the input, pop it; + * 2) If an EOF was pushed back (parsenleft == EOF_NLEFT) or we are reading + * from a string so we can't refill the buffer, return EOF. + * 3) If 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. + */ + +int +preadbuffer() +{ + char *p, *q; + int more; + int something; + extern EditLine *el; + char savec; + + if (parsefile->strpush) { + popstring(); + if (--parsenleft >= 0) + return (*parsenextc++); + } + if (parsenleft == EOF_NLEFT || parsefile->buf == NULL) + return PEOF; + flushout(&output); + flushout(&errout); + +again: + if (parselleft <= 0) { + if ((parselleft = preadfd()) == -1) { + parselleft = parsenleft = EOF_NLEFT; + return PEOF; + } + } + + q = p = parsenextc; + + /* delete nul characters */ + something = 0; + for (more = 1; more;) { + switch (*p) { + case '\0': + p++; /* Skip nul */ + goto check; + + case '\t': + case ' ': + break; + + case '\n': + parsenleft = q - parsenextc; + more = 0; /* Stop processing here */ + break; + + default: + something = 1; + break; + } + + *q++ = *p++; +check: + if (--parselleft <= 0) { + parsenleft = q - parsenextc - 1; + if (parsenleft < 0) + goto again; + *q = '\0'; + more = 0; + } + } + + savec = *q; + *q = '\0'; + +#ifndef SMALL + if (parsefile->fd == 0 && hist && something) { + INTOFF; + history(hist, whichprompt == 1 ? H_ENTER : H_ADD, parsenextc); + INTON; + } +#endif + + if (vflag) { + out2str(parsenextc); + flushout(out2); + } + + *q = savec; + + return *parsenextc++; +} + +/* + * Undo the last call to pgetc. Only one character may be pushed back. + * PEOF may be pushed back. + */ + +void +pungetc() { + parsenleft++; + parsenextc--; +} + +/* + * Push a string back onto the input at this current parsefile level. + * We handle aliases this way. + */ +void +pushstring(s, len, ap) + char *s; + int len; + void *ap; + { + struct strpush *sp; + + INTOFF; +/*dprintf("*** calling pushstring: %s, %d\n", s, len);*/ + if (parsefile->strpush) { + sp = ckmalloc(sizeof (struct strpush)); + sp->prev = parsefile->strpush; + parsefile->strpush = sp; + } else + sp = parsefile->strpush = &(parsefile->basestrpush); + sp->prevstring = parsenextc; + sp->prevnleft = parsenleft; + sp->prevlleft = parselleft; + sp->ap = (struct alias *)ap; + if (ap) + ((struct alias *)ap)->flag |= ALIASINUSE; + parsenextc = s; + parsenleft = len; + INTON; +} + +void +popstring() +{ + struct strpush *sp = parsefile->strpush; + + INTOFF; + parsenextc = sp->prevstring; + parsenleft = sp->prevnleft; + parselleft = sp->prevlleft; +/*dprintf("*** calling popstring: restoring to '%s'\n", parsenextc);*/ + if (sp->ap) + sp->ap->flag &= ~ALIASINUSE; + parsefile->strpush = sp->prev; + if (sp != &(parsefile->basestrpush)) + ckfree(sp); + INTON; +} + +/* + * Set the input to take input from a file. If push is set, push the + * old input onto the stack first. + */ + +void +setinputfile(fname, push) + char *fname; + int push; +{ + int fd; + int fd2; + + INTOFF; + if ((fd = open(fname, O_RDONLY)) < 0) + error("Can't open %s", fname); + if (fd < 10) { + fd2 = copyfd(fd, 10); + close(fd); + if (fd2 < 0) + error("Out of file descriptors"); + fd = fd2; + } + setinputfd(fd, push); + INTON; +} + + +/* + * Like setinputfile, but takes an open file descriptor. Call this with + * interrupts off. + */ + +void +setinputfd(fd, push) + int fd, push; +{ + (void) fcntl(fd, F_SETFD, FD_CLOEXEC); + if (push) { + pushfile(); + parsefile->buf = ckmalloc(BUFSIZ); + } + if (parsefile->fd > 0) + close(parsefile->fd); + parsefile->fd = fd; + if (parsefile->buf == NULL) + parsefile->buf = ckmalloc(BUFSIZ); + parselleft = parsenleft = 0; + plinno = 1; +} + + +/* + * Like setinputfile, but takes input from a string. + */ + +void +setinputstring(string, push) + char *string; + int push; + { + INTOFF; + if (push) + pushfile(); + parsenextc = string; + parselleft = parsenleft = strlen(string); + parsefile->buf = NULL; + plinno = 1; + INTON; +} + + + +/* + * To handle the "." command, a stack of input files is used. Pushfile + * adds a new entry to the stack and popfile restores the previous level. + */ + +STATIC void +pushfile() { + struct parsefile *pf; + + parsefile->nleft = parsenleft; + parsefile->lleft = parselleft; + parsefile->nextc = parsenextc; + parsefile->linno = plinno; + pf = (struct parsefile *)ckmalloc(sizeof (struct parsefile)); + pf->prev = parsefile; + pf->fd = -1; + pf->strpush = NULL; + pf->basestrpush.prev = NULL; + parsefile = pf; +} + + +void +popfile() { + struct parsefile *pf = parsefile; + + INTOFF; + if (pf->fd >= 0) + close(pf->fd); + if (pf->buf) + ckfree(pf->buf); + while (pf->strpush) + popstring(); + parsefile = pf->prev; + ckfree(pf); + parsenleft = parsefile->nleft; + parselleft = parsefile->lleft; + parsenextc = parsefile->nextc; + plinno = parsefile->linno; + INTON; +} + + +/* + * Return to top level. + */ + +void +popallfiles() { + while (parsefile != &basepf) + popfile(); +} + + + +/* + * Close the file(s) that the shell is reading commands from. Called + * after a fork is done. + */ + +void +closescript() { + popallfiles(); + if (parsefile->fd > 0) { + close(parsefile->fd); + parsefile->fd = 0; + } +} diff --git a/release/picobsd/tinyware/ash/input.h b/release/picobsd/tinyware/ash/input.h new file mode 100644 index 0000000..99a5a2c --- /dev/null +++ b/release/picobsd/tinyware/ash/input.h @@ -0,0 +1,66 @@ +/* $NetBSD: input.h,v 1.9 1996/10/16 15:45:09 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)input.h 8.2 (Berkeley) 5/4/95 + */ + +/* PEOF (the end of file marker) is defined in syntax.h */ + +/* + * The input line number. Input.c just defines this variable, and saves + * and restores it when files are pushed and popped. The user of this + * package must set its value. + */ +extern int plinno; +extern int parsenleft; /* number of characters left in input buffer */ +extern char *parsenextc; /* next character in input buffer */ +extern int init_editline; /* 0 == not setup, 1 == OK, -1 == failed */ + +char *pfgets __P((char *, int)); +int pgetc __P((void)); +int preadbuffer __P((void)); +void pungetc __P((void)); +void pushstring __P((char *, int, void *)); +void popstring __P((void)); +void setinputfile __P((char *, int)); +void setinputfd __P((int, int)); +void setinputstring __P((char *, int)); +void popfile __P((void)); +void popallfiles __P((void)); +void closescript __P((void)); + +#define pgetc_macro() (--parsenleft >= 0? *parsenextc++ : preadbuffer()) diff --git a/release/picobsd/tinyware/ash/jobs.c b/release/picobsd/tinyware/ash/jobs.c new file mode 100644 index 0000000..885fa9e --- /dev/null +++ b/release/picobsd/tinyware/ash/jobs.c @@ -0,0 +1,1115 @@ +/* $NetBSD: jobs.c,v 1.22 1997/07/04 21:02:04 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)jobs.c 8.5 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: jobs.c,v 1.22 1997/07/04 21:02:04 christos Exp $"); +#endif +#endif /* not lint */ + +#include <fcntl.h> +#include <signal.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/param.h> +#ifdef BSD +#include <sys/wait.h> +#include <sys/time.h> +#include <sys/resource.h> +#endif +#include <sys/ioctl.h> + +#include "shell.h" +#if JOBS +#if OLD_TTY_DRIVER +#include "sgtty.h" +#else +#include <termios.h> +#endif +#undef CEOF /* syntax.h redefines this */ +#endif +#include "redir.h" +#include "show.h" +#include "main.h" +#include "parser.h" +#include "nodes.h" +#include "jobs.h" +#include "options.h" +#include "trap.h" +#include "syntax.h" +#include "input.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "mystring.h" + + +struct job *jobtab; /* array of jobs */ +int njobs; /* size of array */ +MKINIT short backgndpid = -1; /* pid of last background process */ +#if JOBS +int initialpgrp; /* pgrp of shell on invocation */ +short curjob; /* current job */ +#endif + +STATIC void restartjob __P((struct job *)); +STATIC void freejob __P((struct job *)); +STATIC struct job *getjob __P((char *)); +STATIC int dowait __P((int, struct job *)); +STATIC int onsigchild __P((void)); +STATIC int waitproc __P((int, int *)); +STATIC void cmdtxt __P((union node *)); +STATIC void cmdputs __P((char *)); + + +/* + * Turn job control on and off. + * + * Note: This code assumes that the third arg to ioctl is a character + * pointer, which is true on Berkeley systems but not System V. Since + * System V doesn't have job control yet, this isn't a problem now. + */ + +MKINIT int jobctl; + +void +setjobctl(on) + int on; +{ +#ifdef OLD_TTY_DRIVER + int ldisc; +#endif + + if (on == jobctl || rootshell == 0) + return; + if (on) { + do { /* while we are in the background */ +#ifdef OLD_TTY_DRIVER + if (ioctl(2, TIOCGPGRP, (char *)&initialpgrp) < 0) { +#else + initialpgrp = tcgetpgrp(2); + if (initialpgrp < 0) { +#endif + out2str("sh: can't access tty; job control turned off\n"); + mflag = 0; + return; + } + if (initialpgrp == -1) + initialpgrp = getpgrp(); + else if (initialpgrp != getpgrp()) { + killpg(initialpgrp, SIGTTIN); + continue; + } + } while (0); +#ifdef OLD_TTY_DRIVER + if (ioctl(2, TIOCGETD, (char *)&ldisc) < 0 || ldisc != NTTYDISC) { + out2str("sh: need new tty driver to run job control; job control turned off\n"); + mflag = 0; + return; + } +#endif + setsignal(SIGTSTP); + setsignal(SIGTTOU); + setsignal(SIGTTIN); + setpgid(0, rootpid); +#ifdef OLD_TTY_DRIVER + ioctl(2, TIOCSPGRP, (char *)&rootpid); +#else + tcsetpgrp(2, rootpid); +#endif + } else { /* turning job control off */ + setpgid(0, initialpgrp); +#ifdef OLD_TTY_DRIVER + ioctl(2, TIOCSPGRP, (char *)&initialpgrp); +#else + tcsetpgrp(2, initialpgrp); +#endif + setsignal(SIGTSTP); + setsignal(SIGTTOU); + setsignal(SIGTTIN); + } + jobctl = on; +} + + +#ifdef mkinit +INCLUDE <stdlib.h> + +SHELLPROC { + backgndpid = -1; +#if JOBS + jobctl = 0; +#endif +} + +#endif + + + +#if JOBS +int +fgcmd(argc, argv) + int argc; + char **argv; +{ + struct job *jp; + int pgrp; + int status; + + jp = getjob(argv[1]); + if (jp->jobctl == 0) + error("job not created under job control"); + pgrp = jp->ps[0].pid; +#ifdef OLD_TTY_DRIVER + ioctl(2, TIOCSPGRP, (char *)&pgrp); +#else + tcsetpgrp(2, pgrp); +#endif + restartjob(jp); + INTOFF; + status = waitforjob(jp); + INTON; + return status; +} + + +int +bgcmd(argc, argv) + int argc; + char **argv; +{ + struct job *jp; + + do { + jp = getjob(*++argv); + if (jp->jobctl == 0) + error("job not created under job control"); + restartjob(jp); + } while (--argc > 1); + return 0; +} + + +STATIC void +restartjob(jp) + struct job *jp; +{ + struct procstat *ps; + int i; + + if (jp->state == JOBDONE) + return; + INTOFF; + killpg(jp->ps[0].pid, SIGCONT); + for (ps = jp->ps, i = jp->nprocs ; --i >= 0 ; ps++) { + if ((ps->status & 0377) == 0177) { + ps->status = -1; + jp->state = 0; + } + } + INTON; +} +#endif + + +int +jobscmd(argc, argv) + int argc; + char **argv; +{ + showjobs(0); + return 0; +} + + +/* + * Print a list of jobs. If "change" is nonzero, only print jobs whose + * statuses have changed since the last call to showjobs. + * + * If the shell is interrupted in the process of creating a job, the + * result may be a job structure containing zero processes. Such structures + * will be freed here. + */ + +void +showjobs(change) + int change; +{ + int jobno; + int procno; + int i; + struct job *jp; + struct procstat *ps; + int col; + char s[64]; + + TRACE(("showjobs(%d) called\n", change)); + while (dowait(0, (struct job *)NULL) > 0); + for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { + if (! jp->used) + continue; + if (jp->nprocs == 0) { + freejob(jp); + continue; + } + if (change && ! jp->changed) + continue; + procno = jp->nprocs; + for (ps = jp->ps ; ; ps++) { /* for each process */ + if (ps == jp->ps) + fmtstr(s, 64, "[%d] %d ", jobno, ps->pid); + else + fmtstr(s, 64, " %d ", ps->pid); + out1str(s); + col = strlen(s); + s[0] = '\0'; + if (ps->status == -1) { + /* don't print anything */ + } else if ((ps->status & 0xFF) == 0) { + fmtstr(s, 64, "Exit %d", ps->status >> 8); + } else { + i = ps->status; +#if JOBS + if ((i & 0xFF) == 0177) + i >>= 8; +#endif + if ((i & 0x7F) < NSIG && sys_siglist[i & 0x7F]) + scopy(sys_siglist[i & 0x7F], s); + else + fmtstr(s, 64, "Signal %d", i & 0x7F); + if (i & 0x80) + strcat(s, " (core dumped)"); + } + out1str(s); + col += strlen(s); + do { + out1c(' '); + col++; + } while (col < 30); + out1str(ps->cmd); + out1c('\n'); + if (--procno <= 0) + break; + } + jp->changed = 0; + if (jp->state == JOBDONE) { + freejob(jp); + } + } +} + + +/* + * Mark a job structure as unused. + */ + +STATIC void +freejob(jp) + struct job *jp; + { + struct procstat *ps; + int i; + + INTOFF; + for (i = jp->nprocs, ps = jp->ps ; --i >= 0 ; ps++) { + if (ps->cmd != nullstr) + ckfree(ps->cmd); + } + if (jp->ps != &jp->ps0) + ckfree(jp->ps); + jp->used = 0; +#if JOBS + if (curjob == jp - jobtab + 1) + curjob = 0; +#endif + INTON; +} + + + +int +waitcmd(argc, argv) + int argc; + char **argv; +{ + struct job *job; + int status; + struct job *jp; + + if (argc > 1) { + job = getjob(argv[1]); + } else { + job = NULL; + } + for (;;) { /* loop until process terminated or stopped */ + if (job != NULL) { + if (job->state) { + status = job->ps[job->nprocs - 1].status; + if ((status & 0xFF) == 0) + status = status >> 8 & 0xFF; +#if JOBS + else if ((status & 0xFF) == 0177) + status = (status >> 8 & 0x7F) + 128; +#endif + else + status = (status & 0x7F) + 128; + if (! iflag) + freejob(job); + return status; + } + } else { + for (jp = jobtab ; ; jp++) { + if (jp >= jobtab + njobs) { /* no running procs */ + return 0; + } + if (jp->used && jp->state == 0) + break; + } + } + dowait(1, (struct job *)NULL); + } +} + + + +int +jobidcmd(argc, argv) + int argc; + char **argv; +{ + struct job *jp; + int i; + + jp = getjob(argv[1]); + for (i = 0 ; i < jp->nprocs ; ) { + out1fmt("%d", jp->ps[i].pid); + out1c(++i < jp->nprocs? ' ' : '\n'); + } + return 0; +} + + + +/* + * Convert a job name to a job structure. + */ + +STATIC struct job * +getjob(name) + char *name; + { + int jobno; + struct job *jp; + int pid; + int i; + + if (name == NULL) { +#if JOBS +currentjob: + if ((jobno = curjob) == 0 || jobtab[jobno - 1].used == 0) + error("No current job"); + return &jobtab[jobno - 1]; +#else + error("No current job"); +#endif + } else if (name[0] == '%') { + if (is_digit(name[1])) { + jobno = number(name + 1); + if (jobno > 0 && jobno <= njobs + && jobtab[jobno - 1].used != 0) + return &jobtab[jobno - 1]; +#if JOBS + } else if (name[1] == '%' && name[2] == '\0') { + goto currentjob; +#endif + } else { + struct job *found = NULL; + for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { + if (jp->used && jp->nprocs > 0 + && prefix(name + 1, jp->ps[0].cmd)) { + if (found) + error("%s: ambiguous", name); + found = jp; + } + } + if (found) + return found; + } + } else if (is_number(name)) { + pid = number(name); + for (jp = jobtab, i = njobs ; --i >= 0 ; jp++) { + if (jp->used && jp->nprocs > 0 + && jp->ps[jp->nprocs - 1].pid == pid) + return jp; + } + } + error("No such job: %s", name); + /*NOTREACHED*/ + return NULL; +} + + + +/* + * Return a new job structure, + */ + +struct job * +makejob(node, nprocs) + union node *node; + int nprocs; +{ + int i; + struct job *jp; + + for (i = njobs, jp = jobtab ; ; jp++) { + if (--i < 0) { + INTOFF; + if (njobs == 0) { + jobtab = ckmalloc(4 * sizeof jobtab[0]); + } else { + jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); + memcpy(jp, jobtab, njobs * sizeof jp[0]); + /* Relocate `ps' pointers */ + for (i = 0; i < njobs; i++) + if (jp[i].ps == &jobtab[i].ps0) + jp[i].ps = &jp[i].ps0; + ckfree(jobtab); + jobtab = jp; + } + jp = jobtab + njobs; + for (i = 4 ; --i >= 0 ; jobtab[njobs++].used = 0); + INTON; + break; + } + if (jp->used == 0) + break; + } + INTOFF; + jp->state = 0; + jp->used = 1; + jp->changed = 0; + jp->nprocs = 0; +#if JOBS + jp->jobctl = jobctl; +#endif + if (nprocs > 1) { + jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); + } else { + jp->ps = &jp->ps0; + } + INTON; + TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, + jp - jobtab + 1)); + return jp; +} + + +/* + * Fork of a subshell. If we are doing job control, give the subshell its + * own process group. Jp is a job structure that the job is to be added to. + * N is the command that will be evaluated by the child. Both jp and n may + * be NULL. The mode parameter can be one of the following: + * FORK_FG - Fork off a foreground process. + * FORK_BG - Fork off a background process. + * FORK_NOJOB - Like FORK_FG, but don't give the process its own + * process group even if job control is on. + * + * When job control is turned off, background processes have their standard + * input redirected to /dev/null (except for the second and later processes + * in a pipeline). + */ + +int +forkshell(jp, n, mode) + union node *n; + struct job *jp; + int mode; +{ + int pid; + int pgrp; + + TRACE(("forkshell(%%%d, 0x%lx, %d) called\n", jp - jobtab, (long)n, + mode)); + INTOFF; + pid = fork(); + if (pid == -1) { + TRACE(("Fork failed, errno=%d\n", errno)); + INTON; + error("Cannot fork"); + } + if (pid == 0) { + struct job *p; + int wasroot; + int i; + + TRACE(("Child shell %d\n", getpid())); + wasroot = rootshell; + rootshell = 0; + for (i = njobs, p = jobtab ; --i >= 0 ; p++) + if (p->used) + freejob(p); + closescript(); + INTON; + clear_traps(); +#if JOBS + jobctl = 0; /* do job control only in root shell */ + if (wasroot && mode != FORK_NOJOB && mflag) { + if (jp == NULL || jp->nprocs == 0) + pgrp = getpid(); + else + pgrp = jp->ps[0].pid; + setpgid(0, pgrp); + if (mode == FORK_FG) { + /*** this causes superfluous TIOCSPGRPS ***/ +#ifdef OLD_TTY_DRIVER + if (ioctl(2, TIOCSPGRP, (char *)&pgrp) < 0) + error("TIOCSPGRP failed, errno=%d", errno); +#else + if (tcsetpgrp(2, pgrp) < 0) + error("tcsetpgrp failed, errno=%d", errno); +#endif + } + setsignal(SIGTSTP); + setsignal(SIGTTOU); + } else if (mode == FORK_BG) { + ignoresig(SIGINT); + ignoresig(SIGQUIT); + if ((jp == NULL || jp->nprocs == 0) && + ! fd0_redirected_p ()) { + close(0); + if (open("/dev/null", O_RDONLY) != 0) + error("Can't open /dev/null"); + } + } +#else + if (mode == FORK_BG) { + ignoresig(SIGINT); + ignoresig(SIGQUIT); + if ((jp == NULL || jp->nprocs == 0) && + ! fd0_redirected_p ()) { + close(0); + if (open("/dev/null", O_RDONLY) != 0) + error("Can't open /dev/null"); + } + } +#endif + if (wasroot && iflag) { + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); + } + return pid; + } + if (rootshell && mode != FORK_NOJOB && mflag) { + if (jp == NULL || jp->nprocs == 0) + pgrp = pid; + else + pgrp = jp->ps[0].pid; + setpgid(pid, pgrp); + } + if (mode == FORK_BG) + backgndpid = pid; /* set $! */ + if (jp) { + struct procstat *ps = &jp->ps[jp->nprocs++]; + ps->pid = pid; + ps->status = -1; + ps->cmd = nullstr; + if (iflag && rootshell && n) + ps->cmd = commandtext(n); + } + INTON; + TRACE(("In parent shell: child = %d\n", pid)); + return pid; +} + + + +/* + * Wait for job to finish. + * + * Under job control we have the problem that while a child process is + * running interrupts generated by the user are sent to the child but not + * to the shell. This means that an infinite loop started by an inter- + * active user may be hard to kill. With job control turned off, an + * interactive user may place an interactive program inside a loop. If + * the interactive program catches interrupts, the user doesn't want + * these interrupts to also abort the loop. The approach we take here + * is to have the shell ignore interrupt signals while waiting for a + * forground process to terminate, and then send itself an interrupt + * signal if the child process was terminated by an interrupt signal. + * Unfortunately, some programs want to do a bit of cleanup and then + * exit on interrupt; unless these processes terminate themselves by + * sending a signal to themselves (instead of calling exit) they will + * confuse this approach. + */ + +int +waitforjob(jp) + struct job *jp; + { +#if JOBS + int mypgrp = getpgrp(); +#endif + int status; + int st; + + INTOFF; + TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); + while (jp->state == 0) { + dowait(1, jp); + } +#if JOBS + if (jp->jobctl) { +#ifdef OLD_TTY_DRIVER + if (ioctl(2, TIOCSPGRP, (char *)&mypgrp) < 0) + error("TIOCSPGRP failed, errno=%d\n", errno); +#else + if (tcsetpgrp(2, mypgrp) < 0) + error("tcsetpgrp failed, errno=%d\n", errno); +#endif + } + if (jp->state == JOBSTOPPED) + curjob = jp - jobtab + 1; +#endif + status = jp->ps[jp->nprocs - 1].status; + /* convert to 8 bits */ + if ((status & 0xFF) == 0) + st = status >> 8 & 0xFF; +#if JOBS + else if ((status & 0xFF) == 0177) + st = (status >> 8 & 0x7F) + 128; +#endif + else + st = (status & 0x7F) + 128; + if (! JOBS || jp->state == JOBDONE) + freejob(jp); + CLEAR_PENDING_INT; + if ((status & 0x7F) == SIGINT) + kill(getpid(), SIGINT); + INTON; + return st; +} + + + +/* + * Wait for a process to terminate. + */ + +STATIC int +dowait(block, job) + int block; + struct job *job; +{ + int pid; + int status; + struct procstat *sp; + struct job *jp; + struct job *thisjob; + int done; + int stopped; + int core; + + TRACE(("dowait(%d) called\n", block)); + do { + pid = waitproc(block, &status); + TRACE(("wait returns %d, status=%d\n", pid, status)); + } while (pid == -1 && errno == EINTR); + if (pid <= 0) + return pid; + INTOFF; + thisjob = NULL; + for (jp = jobtab ; jp < jobtab + njobs ; jp++) { + if (jp->used) { + done = 1; + stopped = 1; + for (sp = jp->ps ; sp < jp->ps + jp->nprocs ; sp++) { + if (sp->pid == -1) + continue; + if (sp->pid == pid) { + TRACE(("Changin status of proc %d from 0x%x to 0x%x\n", pid, sp->status, status)); + sp->status = status; + thisjob = jp; + } + if (sp->status == -1) + stopped = 0; + else if ((sp->status & 0377) == 0177) + done = 0; + } + if (stopped) { /* stopped or done */ + int state = done? JOBDONE : JOBSTOPPED; + if (jp->state != state) { + TRACE(("Job %d: changing state from %d to %d\n", jp - jobtab + 1, jp->state, state)); + jp->state = state; +#if JOBS + if (done && curjob == jp - jobtab + 1) + curjob = 0; /* no current job */ +#endif + } + } + } + } + INTON; + if (! rootshell || ! iflag || (job && thisjob == job)) { +#if JOBS + if ((status & 0xFF) == 0177) + status >>= 8; +#endif + core = status & 0x80; + status &= 0x7F; + if (status != 0 && status != SIGINT && status != SIGPIPE) { + if (thisjob != job) + outfmt(out2, "%d: ", pid); +#if JOBS + if (status == SIGTSTP && rootshell && iflag) + outfmt(out2, "%%%d ", job - jobtab + 1); +#endif + if (status < NSIG && sys_siglist[status]) + out2str(sys_siglist[status]); + else + outfmt(out2, "Signal %d", status); + if (core) + out2str(" - core dumped"); + out2c('\n'); + flushout(&errout); + } else { + TRACE(("Not printing status: status=%d\n", status)); + } + } else { + TRACE(("Not printing status, rootshell=%d, job=0x%x\n", rootshell, job)); + if (thisjob) + thisjob->changed = 1; + } + return pid; +} + + + +/* + * Do a wait system call. If job control is compiled in, we accept + * stopped processes. If block is zero, we return a value of zero + * rather than blocking. + * + * System V doesn't have a non-blocking wait system call. It does + * have a SIGCLD signal that is sent to a process when one of it's + * children dies. The obvious way to use SIGCLD would be to install + * a handler for SIGCLD which simply bumped a counter when a SIGCLD + * was received, and have waitproc bump another counter when it got + * the status of a process. Waitproc would then know that a wait + * system call would not block if the two counters were different. + * This approach doesn't work because if a process has children that + * have not been waited for, System V will send it a SIGCLD when it + * installs a signal handler for SIGCLD. What this means is that when + * a child exits, the shell will be sent SIGCLD signals continuously + * until is runs out of stack space, unless it does a wait call before + * restoring the signal handler. The code below takes advantage of + * this (mis)feature by installing a signal handler for SIGCLD and + * then checking to see whether it was called. If there are any + * children to be waited for, it will be. + * + * If neither SYSV nor BSD is defined, we don't implement nonblocking + * waits at all. In this case, the user will not be informed when + * a background process until the next time she runs a real program + * (as opposed to running a builtin command or just typing return), + * and the jobs command may give out of date information. + */ + +#ifdef SYSV +STATIC int gotsigchild; + +STATIC int onsigchild() { + gotsigchild = 1; +} +#endif + + +STATIC int +waitproc(block, status) + int block; + int *status; +{ +#ifdef BSD + int flags; + +#if JOBS + flags = WUNTRACED; +#else + flags = 0; +#endif + if (block == 0) + flags |= WNOHANG; + return wait3(status, flags, (struct rusage *)NULL); +#else +#ifdef SYSV + int (*save)(); + + if (block == 0) { + gotsigchild = 0; + save = signal(SIGCLD, onsigchild); + signal(SIGCLD, save); + if (gotsigchild == 0) + return 0; + } + return wait(status); +#else + if (block == 0) + return 0; + return wait(status); +#endif +#endif +} + +/* + * return 1 if there are stopped jobs, otherwise 0 + */ +int job_warning = 0; +int +stoppedjobs() +{ + int jobno; + struct job *jp; + + if (job_warning) + return (0); + for (jobno = 1, jp = jobtab; jobno <= njobs; jobno++, jp++) { + if (jp->used == 0) + continue; + if (jp->state == JOBSTOPPED) { + out2str("You have stopped jobs.\n"); + job_warning = 2; + return (1); + } + } + + return (0); +} + +/* + * Return a string identifying a command (to be printed by the + * jobs command. + */ + +STATIC char *cmdnextc; +STATIC int cmdnleft; +#define MAXCMDTEXT 200 + +char * +commandtext(n) + union node *n; + { + char *name; + + cmdnextc = name = ckmalloc(MAXCMDTEXT); + cmdnleft = MAXCMDTEXT - 4; + cmdtxt(n); + *cmdnextc = '\0'; + return name; +} + + +STATIC void +cmdtxt(n) + union node *n; + { + union node *np; + struct nodelist *lp; + char *p; + int i; + char s[2]; + + if (n == NULL) + return; + switch (n->type) { + case NSEMI: + cmdtxt(n->nbinary.ch1); + cmdputs("; "); + cmdtxt(n->nbinary.ch2); + break; + case NAND: + cmdtxt(n->nbinary.ch1); + cmdputs(" && "); + cmdtxt(n->nbinary.ch2); + break; + case NOR: + cmdtxt(n->nbinary.ch1); + cmdputs(" || "); + cmdtxt(n->nbinary.ch2); + break; + case NPIPE: + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { + cmdtxt(lp->n); + if (lp->next) + cmdputs(" | "); + } + break; + case NSUBSHELL: + cmdputs("("); + cmdtxt(n->nredir.n); + cmdputs(")"); + break; + case NREDIR: + case NBACKGND: + cmdtxt(n->nredir.n); + break; + case NIF: + cmdputs("if "); + cmdtxt(n->nif.test); + cmdputs("; then "); + cmdtxt(n->nif.ifpart); + cmdputs("..."); + break; + case NWHILE: + cmdputs("while "); + goto until; + case NUNTIL: + cmdputs("until "); +until: + cmdtxt(n->nbinary.ch1); + cmdputs("; do "); + cmdtxt(n->nbinary.ch2); + cmdputs("; done"); + break; + case NFOR: + cmdputs("for "); + cmdputs(n->nfor.var); + cmdputs(" in ..."); + break; + case NCASE: + cmdputs("case "); + cmdputs(n->ncase.expr->narg.text); + cmdputs(" in ..."); + break; + case NDEFUN: + cmdputs(n->narg.text); + cmdputs("() ..."); + break; + case NCMD: + for (np = n->ncmd.args ; np ; np = np->narg.next) { + cmdtxt(np); + if (np->narg.next) + cmdputs(" "); + } + for (np = n->ncmd.redirect ; np ; np = np->nfile.next) { + cmdputs(" "); + cmdtxt(np); + } + break; + case NARG: + cmdputs(n->narg.text); + break; + case NTO: + p = ">"; i = 1; goto redir; + case NAPPEND: + p = ">>"; i = 1; goto redir; + case NTOFD: + p = ">&"; i = 1; goto redir; + case NFROM: + p = "<"; i = 0; goto redir; + case NFROMFD: + p = "<&"; i = 0; goto redir; +redir: + if (n->nfile.fd != i) { + s[0] = n->nfile.fd + '0'; + s[1] = '\0'; + cmdputs(s); + } + cmdputs(p); + if (n->type == NTOFD || n->type == NFROMFD) { + s[0] = n->ndup.dupfd + '0'; + s[1] = '\0'; + cmdputs(s); + } else { + cmdtxt(n->nfile.fname); + } + break; + case NHERE: + case NXHERE: + cmdputs("<<..."); + break; + default: + cmdputs("???"); + break; + } +} + + + +STATIC void +cmdputs(s) + char *s; + { + char *p, *q; + char c; + int subtype = 0; + + if (cmdnleft <= 0) + return; + p = s; + q = cmdnextc; + while ((c = *p++) != '\0') { + if (c == CTLESC) + *q++ = *p++; + else if (c == CTLVAR) { + *q++ = '$'; + if (--cmdnleft > 0) + *q++ = '{'; + subtype = *p++; + } else if (c == '=' && subtype != 0) { + *q++ = "}-+?="[(subtype & VSTYPE) - VSNORMAL]; + subtype = 0; + } else if (c == CTLENDVAR) { + *q++ = '}'; + } else if (c == CTLBACKQ || c == CTLBACKQ+CTLQUOTE) + cmdnleft++; /* ignore it */ + else + *q++ = c; + if (--cmdnleft <= 0) { + *q++ = '.'; + *q++ = '.'; + *q++ = '.'; + break; + } + } + cmdnextc = q; +} diff --git a/release/picobsd/tinyware/ash/jobs.h b/release/picobsd/tinyware/ash/jobs.h new file mode 100644 index 0000000..940286f --- /dev/null +++ b/release/picobsd/tinyware/ash/jobs.h @@ -0,0 +1,97 @@ +/* $NetBSD: jobs.h,v 1.8 1995/05/11 21:29:19 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)jobs.h 8.2 (Berkeley) 5/4/95 + */ + +/* Mode argument to forkshell. Don't change FORK_FG or FORK_BG. */ +#define FORK_FG 0 +#define FORK_BG 1 +#define FORK_NOJOB 2 + + +/* + * A job structure contains information about a job. A job is either a + * single process or a set of processes contained in a pipeline. In the + * latter case, pidlist will be non-NULL, and will point to a -1 terminated + * array of pids. + */ + +struct procstat { + short pid; /* process id */ + short status; /* status flags (defined above) */ + char *cmd; /* 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 */ + short 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 */ +#if JOBS + char jobctl; /* job running under job control */ +#endif +}; + +extern short backgndpid; /* pid of last background process */ +extern int job_warning; /* user was warned about stopped jobs */ + +void setjobctl __P((int)); +int fgcmd __P((int, char **)); +int bgcmd __P((int, char **)); +int jobscmd __P((int, char **)); +void showjobs __P((int)); +int waitcmd __P((int, char **)); +int jobidcmd __P((int, char **)); +struct job *makejob __P((union node *, int)); +int forkshell __P((struct job *, union node *, int)); +int waitforjob __P((struct job *)); +int stoppedjobs __P((void)); +char *commandtext __P((union node *)); + +#if ! JOBS +#define setjobctl(on) /* do nothing */ +#endif diff --git a/release/picobsd/tinyware/ash/machdep.h b/release/picobsd/tinyware/ash/machdep.h new file mode 100644 index 0000000..c9452eb --- /dev/null +++ b/release/picobsd/tinyware/ash/machdep.h @@ -0,0 +1,53 @@ +/* $NetBSD: machdep.h,v 1.8 1995/05/11 21:29:21 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)machdep.h 8.2 (Berkeley) 5/4/95 + */ + +/* + * Most machines require the value returned from malloc to be aligned + * 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 diff --git a/release/picobsd/tinyware/ash/mail.c b/release/picobsd/tinyware/ash/mail.c new file mode 100644 index 0000000..6b6b81d --- /dev/null +++ b/release/picobsd/tinyware/ash/mail.c @@ -0,0 +1,124 @@ +/* $NetBSD: mail.c,v 1.11 1997/07/04 21:02:06 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.11 1997/07/04 21:02:06 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Routines to check for mail. (Perhaps make part of main.c?) + */ + +#include "shell.h" +#include "exec.h" /* defines padvance() */ +#include "var.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "mail.h" +#include <sys/types.h> +#include <sys/stat.h> + + +#define MAXMBOXES 10 + + +STATIC int nmboxes; /* number of mailboxes */ +STATIC time_t mailtime[MAXMBOXES]; /* times of mailboxes */ + + + +/* + * Print appropriate message(s) if mail has arrived. If the argument is + * nozero, then the value of MAIL has changed, so we just update the + * values. + */ + +void +chkmail(silent) + int silent; +{ + int i; + char *mpath; + char *p; + char *q; + struct stackmark smark; + struct stat statb; + + if (silent) + nmboxes = 10; + if (nmboxes == 0) + return; + setstackmark(&smark); + mpath = mpathset()? mpathval() : mailval(); + for (i = 0 ; i < nmboxes ; i++) { + p = padvance(&mpath, nullstr); + if (p == NULL) + break; + if (*p == '\0') + continue; + for (q = p ; *q ; q++); + if (q[-1] != '/') + abort(); + q[-1] = '\0'; /* delete trailing '/' */ +#ifdef notdef /* this is what the System V shell claims to do (it lies) */ + if (stat(p, &statb) < 0) + statb.st_mtime = 0; + if (statb.st_mtime > mailtime[i] && ! silent) { + out2str(pathopt? pathopt : "you have mail"); + out2c('\n'); + } + mailtime[i] = statb.st_mtime; +#else /* this is what it should do */ + if (stat(p, &statb) < 0) + statb.st_size = 0; + if (statb.st_size > mailtime[i] && ! silent) { + out2str(pathopt? pathopt : "you have mail"); + out2c('\n'); + } + mailtime[i] = statb.st_size; +#endif + } + nmboxes = i; + popstackmark(&smark); +} diff --git a/release/picobsd/tinyware/ash/mail.h b/release/picobsd/tinyware/ash/mail.h new file mode 100644 index 0000000..e8df3cf --- /dev/null +++ b/release/picobsd/tinyware/ash/mail.h @@ -0,0 +1,41 @@ +/* $NetBSD: mail.h,v 1.8 1995/05/11 21:29:23 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mail.h 8.2 (Berkeley) 5/4/95 + */ + +void chkmail __P((int)); diff --git a/release/picobsd/tinyware/ash/main.c b/release/picobsd/tinyware/ash/main.c new file mode 100644 index 0000000..5bfbef3 --- /dev/null +++ b/release/picobsd/tinyware/ash/main.c @@ -0,0 +1,388 @@ +/* $NetBSD: main.c,v 1.26 1997/07/04 21:02:07 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95"; +#else +__RCSID("$NetBSD: main.c,v 1.26 1997/07/04 21:02:07 christos Exp $"); +#endif +#endif /* not lint */ + +#include <stdio.h> +#include <signal.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + + +#include "shell.h" +#include "main.h" +#include "mail.h" +#include "options.h" +#include "output.h" +#include "parser.h" +#include "nodes.h" +#include "expand.h" +#include "eval.h" +#include "jobs.h" +#include "input.h" +#include "trap.h" +#include "var.h" +#include "show.h" +#include "memalloc.h" +#include "error.h" +#include "init.h" +#include "mystring.h" +#include "exec.h" +#include "cd.h" + +#define PROFILE 0 + +int rootpid; +int rootshell; +STATIC union node *curcmd; +STATIC union node *prevcmd; +extern int errno; +#if PROFILE +short profile_buf[16384]; +extern int etext(); +#endif + +STATIC void read_profile __P((char *)); +STATIC char *find_dot_file __P((char *)); +int main __P((int, char **)); + +/* + * Main routine. We initialize things, parse the arguments, execute + * profiles if we're a login shell, and then call cmdloop to execute + * commands. The setjmp call sets up the location to jump to when an + * exception occurs. When an exception occurs the variable "state" + * is used to figure out how far we had gotten. + */ + +int +main(argc, argv) + int argc; + char **argv; +{ + struct jmploc jmploc; + struct stackmark smark; + volatile int state; + char *shinit; + +#if PROFILE + monitor(4, etext, profile_buf, sizeof profile_buf, 50); +#endif + state = 0; + if (setjmp(jmploc.loc)) { + /* + * When a shell procedure is executed, we raise the + * exception EXSHELLPROC to clean up before executing + * the shell procedure. + */ + switch (exception) { + case EXSHELLPROC: + rootpid = getpid(); + rootshell = 1; + minusc = NULL; + state = 3; + break; + + case EXEXEC: + exitstatus = exerrno; + break; + + case EXERROR: + exitstatus = 2; + break; + + default: + break; + } + + if (exception != EXSHELLPROC) { + if (state == 0 || iflag == 0 || ! rootshell) + exitshell(exitstatus); + } + reset(); + if (exception == EXINT +#if ATTY + && (! attyset() || equal(termval(), "emacs")) +#endif + ) { + out2c('\n'); + flushout(&errout); + } + popstackmark(&smark); + FORCEINTON; /* enable interrupts */ + if (state == 1) + goto state1; + else if (state == 2) + goto state2; + else if (state == 3) + goto state3; + else + goto state4; + } + handler = &jmploc; +#ifdef DEBUG + opentrace(); + trputs("Shell args: "); trargs(argv); +#endif + rootpid = getpid(); + rootshell = 1; + init(); + setstackmark(&smark); + procargs(argc, argv); + if (argv[0] && argv[0][0] == '-') { + state = 1; + read_profile("/etc/profile"); +state1: + state = 2; + read_profile(".profile"); + } +state2: + state = 3; + if (getuid() == geteuid() && getgid() == getegid()) { + if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { + state = 3; + read_profile(shinit); + } + } +state3: + state = 4; + if (minusc) { + evalstring(minusc); + } + 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; +} + + +/* + * Read and execute commands. "Top" is nonzero for the top level command + * loop; it turns on prompting if the shell is interactive. + */ + +void +cmdloop(top) + int top; +{ + union node *n; + struct stackmark smark; + int inter; + int numeof = 0; + + TRACE(("cmdloop(%d) called\n", top)); + setstackmark(&smark); + for (;;) { + if (pendingsigs) + dotrap(); + inter = 0; + if (iflag && top) { + inter++; + showjobs(1); + chkmail(0); + flushout(&output); + } + n = parsecmd(inter); + /* showtree(n); DEBUG */ + if (n == NEOF) { + if (!top || numeof >= 50) + break; + if (!stoppedjobs()) { + if (!Iflag) + break; + out2str("\nUse \"exit\" to leave shell.\n"); + } + numeof++; + } else if (n != NULL && nflag == 0) { + job_warning = (job_warning == 2) ? 1 : 0; + numeof = 0; + evaltree(n, 0); + } + popstackmark(&smark); + if (evalskip == SKIPFILE) { + evalskip = 0; + break; + } + } + popstackmark(&smark); /* unnecessary */ +} + + + +/* + * Read /etc/profile or .profile. Return on error. + */ + +STATIC void +read_profile(name) + char *name; + { + int fd; + + INTOFF; + if ((fd = open(name, O_RDONLY)) >= 0) + setinputfd(fd, 1); + INTON; + if (fd < 0) + return; + cmdloop(0); + popfile(); +} + + + +/* + * Read a file containing shell functions. + */ + +void +readcmdfile(name) + char *name; +{ + int fd; + + INTOFF; + if ((fd = open(name, O_RDONLY)) >= 0) + setinputfd(fd, 1); + else + error("Can't open %s", name); + INTON; + cmdloop(0); + popfile(); +} + + + +/* + * Take commands from a file. To be compatable we should do a path + * search for the file, which is necessary to find sub-commands. + */ + + +STATIC char * +find_dot_file(basename) + char *basename; +{ + static char localname[FILENAME_MAX+1]; + char *fullname; + char *path = pathval(); + struct stat statb; + + /* don't try this for absolute or relative paths */ + if( strchr(basename, '/')) + return basename; + + while ((fullname = padvance(&path, basename)) != NULL) { + strcpy(localname, fullname); + stunalloc(fullname); + if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) + return localname; + } + return basename; +} + +int +dotcmd(argc, argv) + 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]); + + setinputfile(fullname, 1); + commandname = fullname; + cmdloop(0); + popfile(); + } + return exitstatus; +} + + +int +exitcmd(argc, argv) + 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; +} + + +#ifdef notdef +/* + * Should never be called. + */ + +void +exit(exitstatus) { + _exit(exitstatus); +} +#endif diff --git a/release/picobsd/tinyware/ash/main.h b/release/picobsd/tinyware/ash/main.h new file mode 100644 index 0000000..bfe88be --- /dev/null +++ b/release/picobsd/tinyware/ash/main.h @@ -0,0 +1,47 @@ +/* $NetBSD: main.h,v 1.8 1995/05/11 21:29:27 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)main.h 8.2 (Berkeley) 5/4/95 + */ + +extern int rootpid; /* pid of main shell */ +extern int rootshell; /* true if we aren't a child of the main shell */ + +void readcmdfile __P((char *)); +void cmdloop __P((int)); +int dotcmd __P((int, char **)); +int exitcmd __P((int, char **)); diff --git a/release/picobsd/tinyware/ash/memalloc.c b/release/picobsd/tinyware/ash/memalloc.c new file mode 100644 index 0000000..6533d4c --- /dev/null +++ b/release/picobsd/tinyware/ash/memalloc.c @@ -0,0 +1,306 @@ +/* $NetBSD: memalloc.c,v 1.20 1997/07/04 21:02:08 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.20 1997/07/04 21:02:08 christos Exp $"); +#endif +#endif /* not lint */ + +#include "shell.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "machdep.h" +#include "mystring.h" +#include <stdlib.h> +#include <unistd.h> + +/* + * Like malloc, but returns an error when out of space. + */ + +pointer +ckmalloc(nbytes) + int nbytes; +{ + pointer p; + + if ((p = malloc(nbytes)) == NULL) + error("Out of space"); + return p; +} + + +/* + * Same for realloc. + */ + +pointer +ckrealloc(p, nbytes) + pointer p; + int nbytes; +{ + + if ((p = realloc(p, nbytes)) == NULL) + error("Out of space"); + return p; +} + + +/* + * Make a copy of a string in safe storage. + */ + +char * +savestr(s) + char *s; + { + char *p; + + p = ckmalloc(strlen(s) + 1); + scopy(s, p); + return p; +} + + +/* + * Parse trees for commands are allocated in lifo order, so we use a stack + * to make this more efficient, and also to avoid all sorts of exception + * handling code to handle interrupts in the middle of a parse. + * + * The size 504 was chosen because the Ultrix malloc handles that size + * well. + */ + +#define MINSIZE 504 /* minimum size of a block */ + + +struct stack_block { + struct stack_block *prev; + char space[MINSIZE]; +}; + +struct stack_block stackbase; +struct stack_block *stackp = &stackbase; +char *stacknxt = stackbase.space; +int stacknleft = MINSIZE; +int sstrnleft; +int herefd = -1; + + + +pointer +stalloc(nbytes) + int nbytes; +{ + char *p; + + nbytes = ALIGN(nbytes); + if (nbytes > stacknleft) { + int blocksize; + struct stack_block *sp; + + blocksize = nbytes; + if (blocksize < MINSIZE) + blocksize = MINSIZE; + INTOFF; + sp = ckmalloc(sizeof(struct stack_block) - MINSIZE + blocksize); + sp->prev = stackp; + stacknxt = sp->space; + stacknleft = blocksize; + stackp = sp; + INTON; + } + p = stacknxt; + stacknxt += nbytes; + stacknleft -= nbytes; + return p; +} + + +void +stunalloc(p) + pointer p; + { + if (p == NULL) { /*DEBUG */ + write(2, "stunalloc\n", 10); + abort(); + } + stacknleft += stacknxt - (char *)p; + stacknxt = p; +} + + + +void +setstackmark(mark) + struct stackmark *mark; + { + mark->stackp = stackp; + mark->stacknxt = stacknxt; + mark->stacknleft = stacknleft; +} + + +void +popstackmark(mark) + struct stackmark *mark; + { + struct stack_block *sp; + + INTOFF; + while (stackp != mark->stackp) { + sp = stackp; + stackp = sp->prev; + ckfree(sp); + } + stacknxt = mark->stacknxt; + stacknleft = mark->stacknleft; + INTON; +} + + +/* + * When the parser reads in a string, it wants to stick the string on the + * stack and only adjust the stack pointer when it knows how big the + * string is. Stackblock (defined in stack.h) returns a pointer to a block + * of space on top of the stack and stackblocklen returns the length of + * this block. Growstackblock will grow this space by at least one byte, + * possibly moving it (like realloc). Grabstackblock actually allocates the + * part of the block that has been used. + */ + +void +growstackblock() { + char *p; + int newlen = ALIGN(stacknleft * 2 + 100); + char *oldspace = stacknxt; + int oldlen = stacknleft; + struct stack_block *sp; + + if (stacknxt == stackp->space && stackp != &stackbase) { + INTOFF; + sp = stackp; + stackp = sp->prev; + sp = ckrealloc((pointer)sp, sizeof(struct stack_block) - MINSIZE + newlen); + sp->prev = stackp; + stackp = sp; + stacknxt = sp->space; + stacknleft = newlen; + INTON; + } else { + p = stalloc(newlen); + memcpy(p, oldspace, oldlen); + stacknxt = p; /* free the space */ + stacknleft += newlen; /* we just allocated */ + } +} + + + +void +grabstackblock(len) + int len; +{ + len = ALIGN(len); + stacknxt += len; + stacknleft -= len; +} + + + +/* + * The following routines are somewhat easier to use that 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 + * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is + * grown as necessary. When the user is done, she can just leave the + * string there and refer to it using stackblock(). Or she can allocate + * the space for it using grabstackstr(). If it is necessary to allow + * someone else to use the stack temporarily and then continue to grow + * the string, the user should use grabstack to allocate the space, and + * then call ungrabstr(p) to return to the previous mode of operation. + * + * USTPUTC is like STPUTC except that it doesn't check for overflow. + * CHECKSTACKSPACE can be called before USTPUTC to ensure that there + * is space for at least one character. + */ + + +char * +growstackstr() { + int len = stackblocksize(); + if (herefd >= 0 && len >= 1024) { + xwrite(herefd, stackblock(), len); + sstrnleft = len - 1; + return stackblock(); + } + growstackblock(); + sstrnleft = stackblocksize() - len - 1; + return stackblock() + len; +} + + +/* + * Called from CHECKSTRSPACE. + */ + +char * +makestrspace() { + int len = stackblocksize() - sstrnleft; + growstackblock(); + sstrnleft = stackblocksize() - len; + return stackblock() + len; +} + + + +void +ungrabstackstr(s, p) + char *s; + char *p; + { + stacknleft += stacknxt - s; + stacknxt = s; + sstrnleft = stacknleft - (p - s); +} diff --git a/release/picobsd/tinyware/ash/memalloc.h b/release/picobsd/tinyware/ash/memalloc.h new file mode 100644 index 0000000..eb0abe4 --- /dev/null +++ b/release/picobsd/tinyware/ash/memalloc.h @@ -0,0 +1,80 @@ +/* $NetBSD: memalloc.h,v 1.10 1995/05/11 21:29:31 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)memalloc.h 8.2 (Berkeley) 5/4/95 + */ + +struct stackmark { + struct stack_block *stackp; + char *stacknxt; + int stacknleft; +}; + + +extern char *stacknxt; +extern int stacknleft; +extern int sstrnleft; +extern int herefd; + +pointer ckmalloc __P((int)); +pointer ckrealloc __P((pointer, int)); +char *savestr __P((char *)); +pointer stalloc __P((int)); +void stunalloc __P((pointer)); +void setstackmark __P((struct stackmark *)); +void popstackmark __P((struct stackmark *)); +void growstackblock __P((void)); +void grabstackblock __P((int)); +char *growstackstr __P((void)); +char *makestrspace __P((void)); +void ungrabstackstr __P((char *, char *)); + + + +#define stackblock() stacknxt +#define stackblocksize() stacknleft +#define STARTSTACKSTR(p) p = stackblock(), sstrnleft = stackblocksize() +#define STPUTC(c, p) (--sstrnleft >= 0? (*p++ = (c)) : (p = growstackstr(), *p++ = (c))) +#define CHECKSTRSPACE(n, p) { if (sstrnleft < n) p = makestrspace(); } +#define USTPUTC(c, p) (--sstrnleft, *p++ = (c)) +#define STACKSTRNUL(p) (sstrnleft == 0? (p = growstackstr(), *p = '\0') : (*p = '\0')) +#define STUNPUTC(p) (++sstrnleft, --p) +#define STTOPC(p) p[-1] +#define STADJUST(amount, p) (p += (amount), sstrnleft -= (amount)) +#define grabstackstr(p) stalloc(stackblocksize() - sstrnleft) + +#define ckfree(p) free((pointer)(p)) diff --git a/release/picobsd/tinyware/ash/miscbltin.c b/release/picobsd/tinyware/ash/miscbltin.c new file mode 100644 index 0000000..51881dbb --- /dev/null +++ b/release/picobsd/tinyware/ash/miscbltin.c @@ -0,0 +1,402 @@ +/* $NetBSD: miscbltin.c,v 1.19 1997/07/04 21:02:09 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.19 1997/07/04 21:02:09 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Miscelaneous builtins. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#include <ctype.h> + +#include "shell.h" +#include "options.h" +#include "var.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "miscbltin.h" +#include "mystring.h" + +#undef eflag + +extern char **argptr; /* argument list for builtin command */ + + +/* + * The read builtin. The -e option causes backslashes to escape the + * following character. + * + * This uses unbuffered input, which may be avoidable in some cases. + */ + +int +readcmd(argc, argv) + int argc; + char **argv; +{ + char **ap; + int backslash; + char c; + int eflag; + char *prompt; + char *ifs; + char *p; + int startword; + int status; + int i; + + eflag = 0; + prompt = NULL; + while ((i = nextopt("ep:")) != '\0') { + if (i == 'p') + prompt = optarg; + else + eflag = 1; + } + if (prompt && isatty(0)) { + out2str(prompt); + flushall(); + } + if (*(ap = argptr) == NULL) + error("arg count"); + if ((ifs = bltinlookup("IFS", 1)) == NULL) + ifs = nullstr; + status = 0; + startword = 1; + backslash = 0; + STARTSTACKSTR(p); + for (;;) { + if (read(0, &c, 1) != 1) { + status = 1; + break; + } + if (c == '\0') + continue; + if (backslash) { + backslash = 0; + if (c != '\n') + STPUTC(c, p); + continue; + } + if (eflag && c == '\\') { + backslash++; + continue; + } + if (c == '\n') + break; + if (startword && *ifs == ' ' && strchr(ifs, c)) { + continue; + } + startword = 0; + if (backslash && c == '\\') { + if (read(0, &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 { + STPUTC(c, p); + } + } + STACKSTRNUL(p); + setvar(*ap, stackblock(), 0); + while (*++ap != NULL) + setvar(*ap, nullstr, 0); + return status; +} + + + +int +umaskcmd(argc, argv) + int argc; + char **argv; +{ + char *ap; + int mask; + int i; + int symbolic_mode = 0; + + while ((i = nextopt("S")) != '\0') { + symbolic_mode = 1; + } + + INTOFF; + mask = umask(0); + umask(mask); + INTON; + + if ((ap = *argptr) == NULL) { + if (symbolic_mode) { + char u[4], g[4], o[4]; + + i = 0; + if ((mask & S_IRUSR) == 0) + u[i++] = 'r'; + if ((mask & S_IWUSR) == 0) + u[i++] = 'w'; + if ((mask & S_IXUSR) == 0) + u[i++] = 'x'; + u[i] = '\0'; + + i = 0; + if ((mask & S_IRGRP) == 0) + g[i++] = 'r'; + if ((mask & S_IWGRP) == 0) + g[i++] = 'w'; + if ((mask & S_IXGRP) == 0) + g[i++] = 'x'; + g[i] = '\0'; + + i = 0; + if ((mask & S_IROTH) == 0) + o[i++] = 'r'; + if ((mask & S_IWOTH) == 0) + o[i++] = 'w'; + if ((mask & S_IXOTH) == 0) + o[i++] = 'x'; + o[i] = '\0'; + + out1fmt("u=%s,g=%s,o=%s\n", u, g, o); + } else { + out1fmt("%.4o\n", mask); + } + } else { + if (isdigit(*ap)) { + mask = 0; + do { + if (*ap >= '8' || *ap < '0') + error("Illegal number: %s", argv[1]); + mask = (mask << 3) + (*ap - '0'); + } while (*++ap != '\0'); + umask(mask); + } else { + void *set; + if ((set = setmode (ap)) == 0) + error("Illegal number: %s", ap); + + mask = getmode (set, ~mask & 0777); + umask(~mask & 0777); + } + } + return 0; +} + +/* + * ulimit builtin + * + * This code, originally by Doug Gwyn, Doug Kingston, Eric Gisin, and + * Michael Rendell was ripped from pdksh 5.0.8 and hacked for use with + * ash by J.T. Conklin. + * + * Public domain. + */ + +struct limits { + const char *name; + int cmd; + int factor; /* multiply by to get rlim_{cur,max} values */ + char option; +}; + +static const struct limits limits[] = { +#ifdef RLIMIT_CPU + { "time(seconds)", RLIMIT_CPU, 1, 't' }, +#endif +#ifdef RLIMIT_FSIZE + { "file(blocks)", RLIMIT_FSIZE, 512, 'f' }, +#endif +#ifdef RLIMIT_DATA + { "data(kbytes)", RLIMIT_DATA, 1024, 'd' }, +#endif +#ifdef RLIMIT_STACK + { "stack(kbytes)", RLIMIT_STACK, 1024, 's' }, +#endif +#ifdef RLIMIT_CORE + { "coredump(blocks)", RLIMIT_CORE, 512, 'c' }, +#endif +#ifdef RLIMIT_RSS + { "memory(kbytes)", RLIMIT_RSS, 1024, 'm' }, +#endif +#ifdef RLIMIT_MEMLOCK + { "locked memory(kbytes)", RLIMIT_MEMLOCK, 1024, 'l' }, +#endif +#ifdef RLIMIT_NPROC + { "process(processes)", RLIMIT_NPROC, 1, 'p' }, +#endif +#ifdef RLIMIT_NOFILE + { "nofiles(descriptors)", RLIMIT_NOFILE, 1, 'n' }, +#endif +#ifdef RLIMIT_VMEM + { "vmemory(kbytes)", RLIMIT_VMEM, 1024, 'v' }, +#endif +#ifdef RLIMIT_SWAP + { "swap(kbytes)", RLIMIT_SWAP, 1024, 'w' }, +#endif + { (char *) 0, 0, 0, '\0' } +}; + +int +ulimitcmd(argc, argv) + int argc; + char **argv; +{ + int c; + rlim_t val = 0; + enum { SOFT = 0x1, HARD = 0x2 } + how = SOFT | HARD; + const struct limits *l; + int set, all = 0; + int optc, what; + struct rlimit limit; + + what = 'f'; + while ((optc = nextopt("HSatfdsmcnpl")) != '\0') + switch (optc) { + case 'H': + how = HARD; + break; + case 'S': + how = SOFT; + break; + case 'a': + all = 1; + break; + default: + what = optc; + } + + for (l = limits; l->name && l->option != what; l++) + ; + if (!l->name) + error("ulimit: internal error (%c)\n", what); + + set = *argptr ? 1 : 0; + if (set) { + char *p = *argptr; + + if (all || argptr[1]) + error("ulimit: too many arguments\n"); + if (strcmp(p, "unlimited") == 0) + val = RLIM_INFINITY; + else { + val = (rlim_t) 0; + + while ((c = *p++) >= '0' && c <= '9') + { + val = (val * 10) + (long)(c - '0'); + if (val < (rlim_t) 0) + break; + } + if (c) + error("ulimit: bad number\n"); + val *= l->factor; + } + } + if (all) { + 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; + + out1fmt("%-20s ", l->name); + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; +#ifdef BSD4_4 + out1fmt("%qd\n", (quad_t) val); +#else + out1fmt("%ld\n", (long) val); +#endif + } + } + return 0; + } + + getrlimit(l->cmd, &limit); + if (set) { + if (how & SOFT) + limit.rlim_cur = val; + if (how & HARD) + limit.rlim_max = val; + if (setrlimit(l->cmd, &limit) < 0) + error("ulimit: bad limit\n"); + } else { + if (how & SOFT) + val = limit.rlim_cur; + else if (how & HARD) + val = limit.rlim_max; + + if (val == RLIM_INFINITY) + out1fmt("unlimited\n"); + else + { + val /= l->factor; +#ifdef BSD4_4 + out1fmt("%qd\n", (quad_t) val); +#else + out1fmt("%ld\n", (long) val); +#endif + } + } + return 0; +} diff --git a/release/picobsd/tinyware/ash/miscbltin.h b/release/picobsd/tinyware/ash/miscbltin.h new file mode 100644 index 0000000..105fa93 --- /dev/null +++ b/release/picobsd/tinyware/ash/miscbltin.h @@ -0,0 +1,34 @@ +/* $NetBSD: miscbltin.h,v 1.1 1997/07/04 21:02:10 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Christos Zoulas. + * 4. 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 __P((int, char **)); +int umaskcmd __P((int, char **)); +int ulimitcmd __P((int, char **)); diff --git a/release/picobsd/tinyware/ash/mkbuiltins b/release/picobsd/tinyware/ash/mkbuiltins new file mode 100644 index 0000000..61108f2 --- /dev/null +++ b/release/picobsd/tinyware/ash/mkbuiltins @@ -0,0 +1,94 @@ +#!/bin/sh - +# $NetBSD: mkbuiltins,v 1.13 1997/07/04 21:02:10 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. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)mkbuiltins 8.2 (Berkeley) 5/4/95 + +temp=/tmp/ka$$ +havejobs=0 +if grep '^#define JOBS[ ]*1' shell.h > /dev/null +then havejobs=1 +fi +havehist=1 +if [ "X$1" = "X-h" ]; then + havehist=0 + shift +fi +objdir=$1 +exec > ${objdir}/builtins.c +cat <<\! +/* + * This file was generated by the mkbuiltins program. + */ + +#include "shell.h" +#include "builtins.h" + +! +awk '/^[^#]/ {if(('$havejobs' || $2 != "-j") && ('$havehist' || $2 != "-h")) \ + print $0}' builtins.def | sed 's/-j//' > $temp +awk '{ printf "int %s __P((int, char **));\n", $1}' $temp +echo ' +int (*const builtinfunc[]) __P((int, char **)) = {' +awk '/^[^#]/ { printf "\t%s,\n", $1}' $temp +echo '}; + +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 <<\! +/* + * This file was generated by the mkbuiltins program. + */ + +#include <sys/cdefs.h> +! +tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ < $temp | + awk '{ printf "#define %s %d\n", $1, NR-1}' +echo ' +struct builtincmd { + char *name; + int code; +}; + +extern int (*const builtinfunc[]) __P((int, char **)); +extern const struct builtincmd builtincmd[];' +rm -f $temp diff --git a/release/picobsd/tinyware/ash/mkinit.c b/release/picobsd/tinyware/ash/mkinit.c new file mode 100644 index 0000000..c7ed764 --- /dev/null +++ b/release/picobsd/tinyware/ash/mkinit.c @@ -0,0 +1,523 @@ +/* $NetBSD: mkinit.c,v 1.17 1997/07/04 21:02:11 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)mkinit.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: mkinit.c,v 1.17 1997/07/04 21:02:11 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * This program scans all the source files for code to handle various + * special events and combines this code into one file. This (allegedly) + * improves the structure of the program since there is no need for + * anyone outside of a module to know that that module performs special + * operations on particular events. + * + * Usage: mkinit sourcefile... + */ + + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> + + +/* + * OUTFILE is the name of the output file. Output is initially written + * to the file OUTTEMP, which is then moved to OUTFILE. + */ + +#define OUTFILE "init.c" +#define OUTTEMP "init.c.new" + + +/* + * A text structure is basicly just a string that grows as more characters + * are added onto the end of it. It is implemented as a linked list of + * blocks of characters. The routines addstr and addchar append a string + * or a single character, respectively, to a text structure. Writetext + * writes the contents of a text structure to a file. + */ + +#define BLOCKSIZE 512 + +struct text { + char *nextc; + int nleft; + struct block *start; + struct block *last; +}; + +struct block { + struct block *next; + char text[BLOCKSIZE]; +}; + + +/* + * There is one event structure for each event that mkinit handles. + */ + +struct event { + char *name; /* name of event (e.g. INIT) */ + char *routine; /* name of routine called on event */ + char *comment; /* comment describing routine */ + struct text code; /* code for handling event */ +}; + + +char writer[] = "\ +/*\n\ + * This file was generated by the mkinit program.\n\ + */\n\ +\n"; + +char init[] = "\ +/*\n\ + * Initialization code.\n\ + */\n"; + +char reset[] = "\ +/*\n\ + * This routine is called when an error or an interrupt occurs in an\n\ + * interactive shell and control is returned to the main command loop.\n\ + */\n"; + +char shellproc[] = "\ +/*\n\ + * This routine is called to initialize the shell to run a shell procedure.\n\ + */\n"; + + +struct event event[] = { + {"INIT", "init", init}, + {"RESET", "reset", reset}, + {"SHELLPROC", "initshellproc", shellproc}, + {NULL, NULL} +}; + + +char *curfile; /* current file */ +int linno; /* current line */ +char *header_files[200]; /* list of header files */ +struct text defines; /* #define statements */ +struct text decls; /* declarations */ +int amiddecls; /* for formatting */ + + +void readfile __P((char *)); +int match __P((char *, char *)); +int gooddefine __P((char *)); +void doevent __P((struct event *, FILE *, char *)); +void doinclude __P((char *)); +void dodecl __P((char *, FILE *)); +void output __P((void)); +void addstr __P((char *, struct text *)); +void addchar __P((int, struct text *)); +void writetext __P((struct text *, FILE *)); +FILE *ckfopen __P((char *, char *)); +void *ckmalloc __P((int)); +char *savestr __P((char *)); +void error __P((char *)); +int main __P((int, char **)); + +#define equal(s1, s2) (strcmp(s1, s2) == 0) + +int +main(argc, argv) + int argc; + char **argv; +{ + char **ap; + + header_files[0] = "\"shell.h\""; + header_files[1] = "\"mystring.h\""; + header_files[2] = "\"init.h\""; + for (ap = argv + 1 ; *ap ; ap++) + readfile(*ap); + output(); + rename(OUTTEMP, OUTFILE); + exit(0); +} + + +/* + * Parse an input file. + */ + +void +readfile(fname) + char *fname; + { + FILE *fp; + char line[1024]; + struct event *ep; + + fp = ckfopen(fname, "r"); + curfile = fname; + linno = 0; + amiddecls = 0; + while (fgets(line, sizeof line, fp) != NULL) { + linno++; + for (ep = event ; ep->name ; ep++) { + if (line[0] == ep->name[0] && match(ep->name, line)) { + doevent(ep, fp, fname); + break; + } + } + if (line[0] == 'I' && match("INCLUDE", line)) + doinclude(line); + if (line[0] == 'M' && match("MKINIT", line)) + dodecl(line, fp); + if (line[0] == '#' && gooddefine(line)) + addstr(line, &defines); + if (line[0] == '#' && gooddefine(line)) { + char *cp; + char line2[1024]; + static const char undef[] = "#undef "; + + strcpy(line2, line); + memcpy(line2, undef, sizeof(undef) - 1); + cp = line2 + sizeof(undef) - 1; + while(*cp && (*cp == ' ' || *cp == '\t')) + cp++; + while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp++ = '\n'; *cp = '\0'; + addstr(line2, &defines); + addstr(line, &defines); + } + } + fclose(fp); +} + + +int +match(name, line) + char *name; + char *line; +{ + char *p, *q; + + p = name, q = line; + while (*p) { + if (*p++ != *q++) + return 0; + } + if (*q != '{' && *q != ' ' && *q != '\t' && *q != '\n') + return 0; + return 1; +} + + +int +gooddefine(line) + char *line; +{ + char *p; + + if (! match("#define", line)) + return 0; /* not a define */ + p = line + 7; + while (*p == ' ' || *p == '\t') + p++; + while (*p != ' ' && *p != '\t') { + if (*p == '(') + return 0; /* macro definition */ + p++; + } + while (*p != '\n' && *p != '\0') + p++; + if (p[-1] == '\\') + return 0; /* multi-line definition */ + return 1; +} + + +void +doevent(ep, fp, fname) + struct event *ep; + FILE *fp; + char *fname; + { + char line[1024]; + int indent; + char *p; + + sprintf(line, "\n /* from %s: */\n", fname); + addstr(line, &ep->code); + addstr(" {\n", &ep->code); + for (;;) { + linno++; + if (fgets(line, sizeof line, fp) == NULL) + error("Unexpected EOF"); + if (equal(line, "}\n")) + break; + indent = 6; + for (p = line ; *p == '\t' ; p++) + indent += 8; + for ( ; *p == ' ' ; p++) + indent++; + if (*p == '\n' || *p == '#') + indent = 0; + while (indent >= 8) { + addchar('\t', &ep->code); + indent -= 8; + } + while (indent > 0) { + addchar(' ', &ep->code); + indent--; + } + addstr(p, &ep->code); + } + addstr(" }\n", &ep->code); +} + + +void +doinclude(line) + char *line; + { + char *p; + char *name; + char **pp; + + for (p = line ; *p != '"' && *p != '<' && *p != '\0' ; p++); + if (*p == '\0') + error("Expecting '\"' or '<'"); + name = p; + while (*p != ' ' && *p != '\t' && *p != '\n') + p++; + if (p[-1] != '"' && p[-1] != '>') + error("Missing terminator"); + *p = '\0'; + + /* name now contains the name of the include file */ + for (pp = header_files ; *pp && ! equal(*pp, name) ; pp++); + if (*pp == NULL) + *pp = savestr(name); +} + + +void +dodecl(line1, fp) + char *line1; + FILE *fp; + { + char line[1024]; + char *p, *q; + + if (strcmp(line1, "MKINIT\n") == 0) { /* start of struct/union decl */ + addchar('\n', &decls); + do { + linno++; + if (fgets(line, sizeof line, fp) == NULL) + error("Unterminated structure declaration"); + addstr(line, &decls); + } while (line[0] != '}'); + amiddecls = 0; + } else { + if (! amiddecls) + addchar('\n', &decls); + q = NULL; + for (p = line1 + 6 ; *p && strchr("=/\n", *p) == NULL; p++) + continue; + if (*p == '=') { /* eliminate initialization */ + for (q = p ; *q && *q != ';' ; q++); + if (*q == '\0') + q = NULL; + else { + while (p[-1] == ' ') + p--; + *p = '\0'; + } + } + addstr("extern", &decls); + addstr(line1 + 6, &decls); + if (q != NULL) + addstr(q, &decls); + amiddecls = 1; + } +} + + + +/* + * Write the output to the file OUTTEMP. + */ + +void +output() { + FILE *fp; + char **pp; + struct event *ep; + + fp = ckfopen(OUTTEMP, "w"); + fputs(writer, fp); + for (pp = header_files ; *pp ; pp++) + fprintf(fp, "#include %s\n", *pp); + fputs("\n\n\n", fp); + writetext(&defines, fp); + fputs("\n\n", fp); + writetext(&decls, fp); + for (ep = event ; ep->name ; ep++) { + fputs("\n\n\n", fp); + fputs(ep->comment, fp); + fprintf(fp, "\nvoid\n%s() {\n", ep->routine); + writetext(&ep->code, fp); + fprintf(fp, "}\n"); + } + fclose(fp); +} + + +/* + * A text structure is simply a block of text that is kept in memory. + * Addstr appends a string to the text struct, and addchar appends a single + * character. + */ + +void +addstr(s, text) + char *s; + struct text *text; + { + while (*s) { + if (--text->nleft < 0) + addchar(*s++, text); + else + *text->nextc++ = *s++; + } +} + + +void +addchar(c, text) + int c; + struct text *text; +{ + struct block *bp; + + if (--text->nleft < 0) { + bp = ckmalloc(sizeof *bp); + if (text->start == NULL) + text->start = bp; + else + text->last->next = bp; + text->last = bp; + text->nextc = bp->text; + text->nleft = BLOCKSIZE - 1; + } + *text->nextc++ = c; +} + +/* + * Write the contents of a text structure to a file. + */ +void +writetext(text, fp) + struct text *text; + FILE *fp; + { + struct block *bp; + + if (text->start != NULL) { + for (bp = text->start ; bp != text->last ; bp = bp->next) + fwrite(bp->text, sizeof (char), BLOCKSIZE, fp); + fwrite(bp->text, sizeof (char), BLOCKSIZE - text->nleft, fp); + } +} + +FILE * +ckfopen(file, mode) + char *file; + char *mode; + { + FILE *fp; + + if ((fp = fopen(file, mode)) == NULL) { + fprintf(stderr, "Can't open %s\n", file); + exit(2); + } + return fp; +} + +void * +ckmalloc(nbytes) + int nbytes; +{ + char *p; + + if ((p = malloc(nbytes)) == NULL) + error("Out of space"); + return p; +} + +char * +savestr(s) + char *s; + { + char *p; + + p = ckmalloc(strlen(s) + 1); + strcpy(p, s); + return p; +} + +void +error(msg) + char *msg; + { + if (curfile != NULL) + fprintf(stderr, "%s:%d: ", curfile, linno); + fprintf(stderr, "%s\n", msg); + exit(2); +} diff --git a/release/picobsd/tinyware/ash/mknodes.c b/release/picobsd/tinyware/ash/mknodes.c new file mode 100644 index 0000000..9692a9a --- /dev/null +++ b/release/picobsd/tinyware/ash/mknodes.c @@ -0,0 +1,482 @@ +/* $NetBSD: mknodes.c,v 1.15 1997/07/04 21:02:12 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)mknodes.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: mknodes.c,v 1.15 1997/07/04 21:02:12 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * This program reads the nodetypes file and nodes.c.pat file. It generates + * the files nodes.h and nodes.c. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + + +#define MAXTYPES 50 /* max number of node types */ +#define MAXFIELDS 20 /* max fields in a structure */ +#define BUFLEN 100 /* size of character buffers */ + +/* field types */ +#define T_NODE 1 /* union node *field */ +#define T_NODELIST 2 /* struct nodelist *field */ +#define T_STRING 3 +#define T_INT 4 /* int field */ +#define T_OTHER 5 /* other */ +#define T_TEMP 6 /* don't copy this field */ + + +struct field { /* a structure field */ + char *name; /* name of field */ + int type; /* type of field */ + char *decl; /* declaration of field */ +}; + + +struct str { /* struct representing a node structure */ + char *tag; /* structure tag */ + int nfields; /* number of fields in the structure */ + struct field field[MAXFIELDS]; /* the fields of the structure */ + int done; /* set if fully parsed */ +}; + + +static int ntypes; /* number of node types */ +static char *nodename[MAXTYPES]; /* names of the nodes */ +static struct str *nodestr[MAXTYPES]; /* type of structure used by the node */ +static int nstr; /* number of structures */ +static struct str str[MAXTYPES]; /* the structures */ +static struct str *curstr; /* current structure */ +static FILE *infp = stdin; +static char line[1024]; +static int linno; +static char *linep; + +static void parsenode __P((void)); +static void parsefield __P((void)); +static void output __P((char *)); +static void outsizes __P((FILE *)); +static void outfunc __P((FILE *, int)); +static void indent __P((int, FILE *)); +static int nextfield __P((char *)); +static void skipbl __P((void)); +static int readline __P((void)); +static void error __P((const char *, ...)); +static char *savestr __P((const char *)); +int main __P((int, char **)); + + +int +main(argc, argv) + int argc; + char **argv; +{ + if (argc != 3) + error("usage: mknodes file"); + if ((infp = fopen(argv[1], "r")) == NULL) + error("Can't open %s", argv[1]); + while (readline()) { + if (line[0] == ' ' || line[0] == '\t') + parsefield(); + else if (line[0] != '\0') + parsenode(); + } + output(argv[2]); + exit(0); +} + + + +static void +parsenode() +{ + char name[BUFLEN]; + char tag[BUFLEN]; + struct str *sp; + + if (curstr && curstr->nfields > 0) + curstr->done = 1; + nextfield(name); + if (! nextfield(tag)) + error("Tag expected"); + if (*linep != '\0') + error("Garbage at end of line"); + nodename[ntypes] = savestr(name); + for (sp = str ; sp < str + nstr ; sp++) { + if (strcmp(sp->tag, tag) == 0) + break; + } + if (sp >= str + nstr) { + sp->tag = savestr(tag); + sp->nfields = 0; + curstr = sp; + nstr++; + } + nodestr[ntypes] = sp; + ntypes++; +} + + +static void +parsefield() +{ + char name[BUFLEN]; + char type[BUFLEN]; + char decl[2 * BUFLEN]; + struct field *fp; + + if (curstr == NULL || curstr->done) + error("No current structure to add field to"); + if (! nextfield(name)) + error("No field name"); + if (! nextfield(type)) + error("No field type"); + fp = &curstr->field[curstr->nfields]; + fp->name = savestr(name); + if (strcmp(type, "nodeptr") == 0) { + fp->type = T_NODE; + sprintf(decl, "union node *%s", name); + } else if (strcmp(type, "nodelist") == 0) { + fp->type = T_NODELIST; + sprintf(decl, "struct nodelist *%s", name); + } else if (strcmp(type, "string") == 0) { + fp->type = T_STRING; + sprintf(decl, "char *%s", name); + } else if (strcmp(type, "int") == 0) { + fp->type = T_INT; + sprintf(decl, "int %s", name); + } else if (strcmp(type, "other") == 0) { + fp->type = T_OTHER; + } else if (strcmp(type, "temp") == 0) { + fp->type = T_TEMP; + } else { + error("Unknown type %s", type); + } + if (fp->type == T_OTHER || fp->type == T_TEMP) { + skipbl(); + fp->decl = savestr(linep); + } else { + if (*linep) + error("Garbage at end of line"); + fp->decl = savestr(decl); + } + curstr->nfields++; +} + + +char writer[] = "\ +/*\n\ + * This file was generated by the mknodes program.\n\ + */\n\ +\n"; + +static void +output(file) + char *file; +{ + FILE *hfile; + FILE *cfile; + FILE *patfile; + int i; + struct str *sp; + struct field *fp; + char *p; + + if ((patfile = fopen(file, "r")) == NULL) + error("Can't open %s", file); + if ((hfile = fopen("nodes.h", "w")) == NULL) + error("Can't create nodes.h"); + if ((cfile = fopen("nodes.c", "w")) == NULL) + error("Can't create nodes.c"); + fputs(writer, hfile); + for (i = 0 ; i < ntypes ; i++) + fprintf(hfile, "#define %s %d\n", nodename[i], i); + fputs("\n\n\n", hfile); + for (sp = str ; sp < &str[nstr] ; sp++) { + fprintf(hfile, "struct %s {\n", sp->tag); + for (i = sp->nfields, fp = sp->field ; --i >= 0 ; fp++) { + fprintf(hfile, " %s;\n", fp->decl); + } + fputs("};\n\n\n", hfile); + } + fputs("union node {\n", hfile); + fprintf(hfile, " int type;\n"); + for (sp = str ; sp < &str[nstr] ; sp++) { + fprintf(hfile, " struct %s %s;\n", sp->tag, sp->tag); + } + fputs("};\n\n\n", hfile); + fputs("struct nodelist {\n", hfile); + fputs("\tstruct nodelist *next;\n", hfile); + fputs("\tunion node *n;\n", hfile); + fputs("};\n\n\n", hfile); + fputs("#ifdef __STDC__\n", hfile); + fputs("union node *copyfunc(union node *);\n", hfile); + fputs("void freefunc(union node *);\n", hfile); + fputs("#else\n", hfile); + fputs("union node *copyfunc();\n", hfile); + fputs("void freefunc();\n", hfile); + fputs("#endif\n", hfile); + + fputs(writer, cfile); + while (fgets(line, sizeof line, patfile) != NULL) { + for (p = line ; *p == ' ' || *p == '\t' ; p++); + if (strcmp(p, "%SIZES\n") == 0) + outsizes(cfile); + else if (strcmp(p, "%CALCSIZE\n") == 0) + outfunc(cfile, 1); + else if (strcmp(p, "%COPY\n") == 0) + outfunc(cfile, 0); + else + fputs(line, cfile); + } +} + + + +static void +outsizes(cfile) + FILE *cfile; +{ + int i; + + fprintf(cfile, "static const short nodesize[%d] = {\n", ntypes); + for (i = 0 ; i < ntypes ; i++) { + fprintf(cfile, " ALIGN(sizeof (struct %s)),\n", nodestr[i]->tag); + } + fprintf(cfile, "};\n"); +} + + +static void +outfunc(cfile, calcsize) + FILE *cfile; + int calcsize; +{ + struct str *sp; + struct field *fp; + int i; + + fputs(" if (n == NULL)\n", cfile); + if (calcsize) + fputs(" return;\n", cfile); + else + fputs(" return NULL;\n", cfile); + if (calcsize) + fputs(" funcblocksize += nodesize[n->type];\n", cfile); + else { + fputs(" new = funcblock;\n", cfile); + fputs(" funcblock = (char *) funcblock + nodesize[n->type];\n", cfile); + } + fputs(" switch (n->type) {\n", cfile); + for (sp = str ; sp < &str[nstr] ; sp++) { + for (i = 0 ; i < ntypes ; i++) { + if (nodestr[i] == sp) + fprintf(cfile, " case %s:\n", nodename[i]); + } + for (i = sp->nfields ; --i >= 1 ; ) { + fp = &sp->field[i]; + switch (fp->type) { + case T_NODE: + if (calcsize) { + indent(12, cfile); + fprintf(cfile, "calcsize(n->%s.%s);\n", + sp->tag, fp->name); + } else { + indent(12, cfile); + fprintf(cfile, "new->%s.%s = copynode(n->%s.%s);\n", + sp->tag, fp->name, sp->tag, fp->name); + } + break; + case T_NODELIST: + if (calcsize) { + indent(12, cfile); + fprintf(cfile, "sizenodelist(n->%s.%s);\n", + sp->tag, fp->name); + } else { + indent(12, cfile); + fprintf(cfile, "new->%s.%s = copynodelist(n->%s.%s);\n", + sp->tag, fp->name, sp->tag, fp->name); + } + break; + case T_STRING: + if (calcsize) { + indent(12, cfile); + fprintf(cfile, "funcstringsize += strlen(n->%s.%s) + 1;\n", + sp->tag, fp->name); + } else { + indent(12, cfile); + fprintf(cfile, "new->%s.%s = nodesavestr(n->%s.%s);\n", + sp->tag, fp->name, sp->tag, fp->name); + } + break; + case T_INT: + case T_OTHER: + if (! calcsize) { + indent(12, cfile); + fprintf(cfile, "new->%s.%s = n->%s.%s;\n", + sp->tag, fp->name, sp->tag, fp->name); + } + break; + } + } + indent(12, cfile); + fputs("break;\n", cfile); + } + fputs(" };\n", cfile); + if (! calcsize) + fputs(" new->type = n->type;\n", cfile); +} + + +static void +indent(amount, fp) + int amount; + FILE *fp; +{ + while (amount >= 8) { + putc('\t', fp); + amount -= 8; + } + while (--amount >= 0) { + putc(' ', fp); + } +} + + +static int +nextfield(buf) + char *buf; +{ + char *p, *q; + + p = linep; + while (*p == ' ' || *p == '\t') + p++; + q = buf; + while (*p != ' ' && *p != '\t' && *p != '\0') + *q++ = *p++; + *q = '\0'; + linep = p; + return (q > buf); +} + + +static void +skipbl() +{ + while (*linep == ' ' || *linep == '\t') + linep++; +} + + +static int +readline() +{ + char *p; + + if (fgets(line, 1024, infp) == NULL) + return 0; + for (p = line ; *p != '#' && *p != '\n' && *p != '\0' ; p++); + while (p > line && (p[-1] == ' ' || p[-1] == '\t')) + p--; + *p = '\0'; + linep = line; + linno++; + if (p - line > BUFLEN) + error("Line too long"); + return 1; +} + + + +static void +#ifdef __STDC__ +error(const char *msg, ...) +#else +error(va_alist) + va_dcl +#endif +{ + va_list va; +#ifdef __STDC__ + va_start(va, msg); +#else + char *msg; + va_start(va); + msg = va_arg(va, char *); +#endif + + (void) fprintf(stderr, "line %d: ", linno); + (void) vfprintf(stderr, msg, va); + (void) fputc('\n', stderr); + + va_end(va); + + exit(2); +} + + + +static char * +savestr(s) + const char *s; +{ + char *p; + + if ((p = malloc(strlen(s) + 1)) == NULL) + error("Out of space"); + (void) strcpy(p, s); + return p; +} diff --git a/release/picobsd/tinyware/ash/mksyntax.c b/release/picobsd/tinyware/ash/mksyntax.c new file mode 100644 index 0000000..3030dda --- /dev/null +++ b/release/picobsd/tinyware/ash/mksyntax.c @@ -0,0 +1,407 @@ +/* $NetBSD: mksyntax.c,v 1.15 1997/07/05 21:25:09 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\ + The Regents of the University of California. All rights reserved.\n"); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)mksyntax.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: mksyntax.c,v 1.15 1997/07/05 21:25:09 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * This program creates syntax.h and syntax.c. + */ + +#include <stdio.h> +#include <string.h> +#include "parser.h" + + +struct synclass { + char *name; + char *comment; +}; + +/* Syntax classes */ +struct synclass synclass[] = { + { "CWORD", "character is nothing special" }, + { "CNL", "newline character" }, + { "CBACK", "a backslash character" }, + { "CSQUOTE", "single quote" }, + { "CDQUOTE", "double quote" }, + { "CENDQUOTE", "a terminating quote" }, + { "CBQUOTE", "backwards single quote" }, + { "CVAR", "a dollar sign" }, + { "CENDVAR", "a '}' character" }, + { "CLP", "a left paren in arithmetic" }, + { "CRP", "a right paren in arithmetic" }, + { "CEOF", "end of file" }, + { "CCTL", "like CWORD, except it must be escaped" }, + { "CSPCL", "these terminate a word" }, + { NULL, NULL } +}; + + +/* + * Syntax classes for is_ functions. Warning: if you add new classes + * you may have to change the definition of the is_in_name macro. + */ +struct synclass is_entry[] = { + { "ISDIGIT", "a digit" }, + { "ISUPPER", "an upper case letter" }, + { "ISLOWER", "a lower case letter" }, + { "ISUNDER", "an underscore" }, + { "ISSPECL", "the name of a special parameter" }, + { NULL, NULL } +}; + +static char writer[] = "\ +/*\n\ + * This file was generated by the mksyntax program.\n\ + */\n\ +\n"; + + +static FILE *cfile; +static FILE *hfile; +static char *syntax[513]; +static int base; +static int size; /* number of values which a char variable can have */ +static int nbits; /* number of bits in a character */ +static int digit_contig;/* true if digits are contiguous */ + +static void filltable __P((char *)); +static void init __P((void)); +static void add __P((char *, char *)); +static void print __P((char *)); +static void output_type_macros __P((void)); +static void digit_convert __P((void)); +int main __P((int, char **)); + +int +main(argc, argv) + int argc; + char **argv; +{ + char c; + char d; + int sign; + int i; + char buf[80]; + int pos; + static char digit[] = "0123456789"; + + /* Create output files */ + if ((cfile = fopen("syntax.c", "w")) == NULL) { + perror("syntax.c"); + exit(2); + } + if ((hfile = fopen("syntax.h", "w")) == NULL) { + perror("syntax.h"); + exit(2); + } + fputs(writer, hfile); + fputs(writer, cfile); + + /* Determine the characteristics of chars. */ + c = -1; + if (c <= 0) + sign = 1; + else + sign = 0; + for (nbits = 1 ; ; nbits++) { + d = (1 << nbits) - 1; + if (d == c) + break; + } + printf("%s %d bit chars\n", sign? "signed" : "unsigned", nbits); + if (nbits > 9) { + fputs("Characters can't have more than 9 bits\n", stderr); + exit(2); + } + size = (1 << nbits) + 1; + base = 1; + if (sign) + base += 1 << (nbits - 1); + digit_contig = 1; + for (i = 0 ; i < 10 ; i++) { + if (digit[i] != '0' + i) + digit_contig = 0; + } + + fputs("#include <sys/cdefs.h>\n", hfile); + fputs("#include <ctype.h>\n", hfile); + + /* Generate the #define statements in the header file */ + fputs("/* Syntax classes */\n", hfile); + for (i = 0 ; synclass[i].name ; i++) { + sprintf(buf, "#define %s %d", synclass[i].name, i); + fputs(buf, hfile); + for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07) + putc('\t', hfile); + fprintf(hfile, "/* %s */\n", synclass[i].comment); + } + putc('\n', hfile); + fputs("/* Syntax classes for is_ functions */\n", hfile); + for (i = 0 ; is_entry[i].name ; i++) { + sprintf(buf, "#define %s %#o", is_entry[i].name, 1 << i); + fputs(buf, hfile); + for (pos = strlen(buf) ; pos < 32 ; pos = (pos + 8) & ~07) + putc('\t', hfile); + fprintf(hfile, "/* %s */\n", is_entry[i].comment); + } + putc('\n', hfile); + fprintf(hfile, "#define SYNBASE %d\n", base); + fprintf(hfile, "#define PEOF %d\n\n", -base); + if (sign) + fprintf(hfile, "#define UPEOF %d\n\n", -base); + else + fprintf(hfile, "#define UPEOF ((unsigned char) %d)\n\n", -base); + putc('\n', hfile); + fputs("#define BASESYNTAX (basesyntax + SYNBASE)\n", hfile); + fputs("#define DQSYNTAX (dqsyntax + SYNBASE)\n", hfile); + fputs("#define SQSYNTAX (sqsyntax + SYNBASE)\n", hfile); + fputs("#define ARISYNTAX (arisyntax + SYNBASE)\n", hfile); + putc('\n', hfile); + output_type_macros(); /* is_digit, etc. */ + putc('\n', hfile); + + /* Generate the syntax tables. */ + fputs("#include \"shell.h\"\n", cfile); + fputs("#include \"syntax.h\"\n\n", cfile); + init(); + fputs("/* syntax table used when not in quotes */\n", cfile); + add("\n", "CNL"); + add("\\", "CBACK"); + add("'", "CSQUOTE"); + add("\"", "CDQUOTE"); + add("`", "CBQUOTE"); + add("$", "CVAR"); + add("}", "CENDVAR"); + add("<>();&| \t", "CSPCL"); + print("basesyntax"); + init(); + fputs("\n/* syntax table used when in double quotes */\n", cfile); + add("\n", "CNL"); + add("\\", "CBACK"); + add("\"", "CENDQUOTE"); + add("`", "CBQUOTE"); + add("$", "CVAR"); + add("}", "CENDVAR"); + /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ + add("!*?[=~:/-", "CCTL"); + print("dqsyntax"); + init(); + fputs("\n/* syntax table used when in single quotes */\n", cfile); + add("\n", "CNL"); + add("'", "CENDQUOTE"); + /* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */ + add("!*?[=~:/-", "CCTL"); + print("sqsyntax"); + init(); + fputs("\n/* syntax table used when in arithmetic */\n", cfile); + add("\n", "CNL"); + add("\\", "CBACK"); + add("`", "CBQUOTE"); + add("'", "CSQUOTE"); + add("\"", "CDQUOTE"); + add("$", "CVAR"); + add("}", "CENDVAR"); + add("(", "CLP"); + add(")", "CRP"); + print("arisyntax"); + filltable("0"); + fputs("\n/* character classification table */\n", cfile); + add("0123456789", "ISDIGIT"); + add("abcdefghijklmnopqrstucvwxyz", "ISLOWER"); + add("ABCDEFGHIJKLMNOPQRSTUCVWXYZ", "ISUPPER"); + add("_", "ISUNDER"); + add("#?$!-*@", "ISSPECL"); + print("is_type"); + if (! digit_contig) + digit_convert(); + exit(0); +} + + + +/* + * Clear the syntax table. + */ + +static void +filltable(dftval) + char *dftval; +{ + int i; + + for (i = 0 ; i < size ; i++) + syntax[i] = dftval; +} + + +/* + * Initialize the syntax table with default values. + */ + +static void +init() +{ + filltable("CWORD"); + syntax[0] = "CEOF"; + syntax[base + CTLESC] = "CCTL"; + syntax[base + CTLVAR] = "CCTL"; + syntax[base + CTLENDVAR] = "CCTL"; + syntax[base + CTLBACKQ] = "CCTL"; + syntax[base + CTLBACKQ + CTLQUOTE] = "CCTL"; + syntax[base + CTLARI] = "CCTL"; + syntax[base + CTLENDARI] = "CCTL"; +} + + +/* + * Add entries to the syntax table. + */ + +static void +add(p, type) + char *p, *type; +{ + while (*p) + syntax[*p++ + base] = type; +} + + + +/* + * Output the syntax table. + */ + +static void +print(name) + char *name; +{ + int i; + int col; + + fprintf(hfile, "extern const char %s[];\n", name); + fprintf(cfile, "const char %s[%d] = {\n", name, size); + col = 0; + for (i = 0 ; i < size ; i++) { + if (i == 0) { + fputs(" ", cfile); + } else if ((i & 03) == 0) { + fputs(",\n ", cfile); + col = 0; + } else { + putc(',', cfile); + while (++col < 9 * (i & 03)) + putc(' ', cfile); + } + fputs(syntax[i], cfile); + col += strlen(syntax[i]); + } + fputs("\n};\n", cfile); +} + + + +/* + * Output character classification macros (e.g. is_digit). If digits are + * contiguous, we can test for them quickly. + */ + +static char *macro[] = { + "#define is_digit(c)\t((is_type+SYNBASE)[c] & ISDIGIT)", + "#define is_alpha(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && isalpha((unsigned char) (c)))", + "#define is_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalpha((unsigned char) (c))))", + "#define is_in_name(c)\t((c) != UPEOF && ((c) < CTLESC || (c) > CTLENDARI) && ((c) == '_' || isalnum((unsigned char) (c))))", + "#define is_special(c)\t((is_type+SYNBASE)[c] & (ISSPECL|ISDIGIT))", + NULL +}; + +static void +output_type_macros() +{ + char **pp; + + if (digit_contig) + macro[0] = "#define is_digit(c)\t((unsigned)((c) - '0') <= 9)"; + for (pp = macro ; *pp ; pp++) + fprintf(hfile, "%s\n", *pp); + if (digit_contig) + fputs("#define digit_val(c)\t((c) - '0')\n", hfile); + else + fputs("#define digit_val(c)\t(digit_value[c])\n", hfile); +} + + + +/* + * Output digit conversion table (if digits are not contiguous). + */ + +static void +digit_convert() +{ + int maxdigit; + static char digit[] = "0123456789"; + char *p; + int i; + + maxdigit = 0; + for (p = digit ; *p ; p++) + if (*p > maxdigit) + maxdigit = *p; + fputs("extern const char digit_value[];\n", hfile); + fputs("\n\nconst char digit_value[] = {\n", cfile); + for (i = 0 ; i <= maxdigit ; i++) { + for (p = digit ; *p && *p != i ; p++); + if (*p == '\0') + p = digit; + fprintf(cfile, " %d,\n", p - digit); + } + fputs("};\n", cfile); +} diff --git a/release/picobsd/tinyware/ash/mktokens b/release/picobsd/tinyware/ash/mktokens new file mode 100644 index 0000000..b7c9e19 --- /dev/null +++ b/release/picobsd/tinyware/ash/mktokens @@ -0,0 +1,95 @@ +#!/bin/sh - +# $NetBSD: mktokens,v 1.8 1996/10/16 14:47:49 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. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)mktokens 8.1 (Berkeley) 5/31/93 + +# 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. + +cat > /tmp/ka$$ <<\! +TEOF 1 end of file +TNL 0 newline +TSEMI 0 ";" +TBACKGND 0 "&" +TAND 0 "&&" +TOR 0 "||" +TPIPE 0 "|" +TLP 0 "(" +TRP 1 ")" +TENDCASE 1 ";;" +TENDBQUOTE 1 "`" +TREDIR 0 redirection +TWORD 0 word +TIF 0 "if" +TTHEN 1 "then" +TELSE 1 "else" +TELIF 1 "elif" +TFI 1 "fi" +TWHILE 0 "while" +TUNTIL 0 "until" +TFOR 0 "for" +TDO 1 "do" +TDONE 1 "done" +TBEGIN 0 "{" +TEND 1 "}" +TCASE 0 "case" +TESAC 1 "esac" +TNOT 0 "!" +! +nl=`wc -l /tmp/ka$$` +exec > token.h +awk '{print "#define " $1 " " NR-1}' /tmp/ka$$ +echo ' +/* Array indicating which tokens mark the end of a list */ +const char tokendlist[] = {' +awk '{print "\t" $2 ","}' /tmp/ka$$ +echo '}; + +char *const tokname[] = {' +sed -e 's/"/\\"/g' \ + -e 's/[^ ]*[ ][ ]*[^ ]*[ ][ ]*\(.*\)/ "\1",/' \ + /tmp/ka$$ +echo '}; +' +sed 's/"//g' /tmp/ka$$ | awk ' +/TIF/{print "#define KWDOFFSET " NR-1; print ""; print "char *const parsekwd[] = {"} +/TIF/,/neverfound/{print " \"" $3 "\","}' +echo ' 0 +};' + +rm /tmp/ka$$ diff --git a/release/picobsd/tinyware/ash/myhistedit.h b/release/picobsd/tinyware/ash/myhistedit.h new file mode 100644 index 0000000..257b4a2 --- /dev/null +++ b/release/picobsd/tinyware/ash/myhistedit.h @@ -0,0 +1,50 @@ +/* $NetBSD: myhistedit.h,v 1.6 1997/04/11 22:45:40 christos Exp $ */ + +/*- + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)myhistedit.h 8.2 (Berkeley) 5/4/95 + */ + +#include <histedit.h> + +extern History *hist; +extern EditLine *el; +extern int displayhist; + +void histedit __P((void)); +void sethistsize __P((const char *)); +void setterm __P((const char *)); +int histcmd __P((int, char **)); +int not_fcnumber __P((char *)); +int str_to_event __P((char *, int)); + diff --git a/release/picobsd/tinyware/ash/mystring.c b/release/picobsd/tinyware/ash/mystring.c new file mode 100644 index 0000000..2ca62bd --- /dev/null +++ b/release/picobsd/tinyware/ash/mystring.c @@ -0,0 +1,144 @@ +/* $NetBSD: mystring.c,v 1.13 1997/07/04 21:02:15 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.13 1997/07/04 21:02:15 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * String functions. + * + * equal(s1, s2) Return true if strings are equal. + * scopy(from, to) Copy a string. + * scopyn(from, to, n) Like scopy, but checks for overflow. + * number(s) Convert a string of digits to an integer. + * is_number(s) Return true if s is a string of digits. + */ + +#include <stdlib.h> +#include "shell.h" +#include "syntax.h" +#include "error.h" +#include "mystring.h" + + +char nullstr[1]; /* zero length string */ + +/* + * equal - #defined in mystring.h + */ + +/* + * scopy - #defined in mystring.h + */ + + +/* + * scopyn - copy a string from "from" to "to", truncating the string + * if necessary. "To" is always nul terminated, even if + * truncation is performed. "Size" is the size of "to". + */ + +void +scopyn(from, to, size) + char const *from; + char *to; + int size; + { + + while (--size > 0) { + if ((*to++ = *from++) == '\0') + return; + } + *to = '\0'; +} + + +/* + * prefix -- see if pfx is a prefix of string. + */ + +int +prefix(pfx, string) + char const *pfx; + char const *string; + { + while (*pfx) { + if (*pfx++ != *string++) + return 0; + } + return 1; +} + + +/* + * Convert a string of digits to an integer, printing an error message on + * failure. + */ + +int +number(s) + const char *s; + { + + if (! is_number(s)) + error("Illegal number: %s", (char *)s); + return atoi(s); +} + + + +/* + * Check for a valid number. This should be elsewhere. + */ + +int +is_number(p) + const char *p; + { + do { + if (! is_digit(*p)) + return 0; + } while (*++p != '\0'); + return 1; +} diff --git a/release/picobsd/tinyware/ash/mystring.h b/release/picobsd/tinyware/ash/mystring.h new file mode 100644 index 0000000..50e6741 --- /dev/null +++ b/release/picobsd/tinyware/ash/mystring.h @@ -0,0 +1,49 @@ +/* $NetBSD: mystring.h,v 1.9 1995/05/11 21:29:42 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mystring.h 8.2 (Berkeley) 5/4/95 + */ + +#include <string.h> + +void scopyn __P((const char *, char *, int)); +int prefix __P((const char *, const char *)); +int number __P((const char *)); +int is_number __P((const char *)); + +#define equal(s1, s2) (strcmp(s1, s2) == 0) +#define scopy(s1, s2) ((void)strcpy(s2, s1)) diff --git a/release/picobsd/tinyware/ash/nodes.c.pat b/release/picobsd/tinyware/ash/nodes.c.pat new file mode 100644 index 0000000..3b6c875 --- /dev/null +++ b/release/picobsd/tinyware/ash/nodes.c.pat @@ -0,0 +1,169 @@ +/* $NetBSD: nodes.c.pat,v 1.8 1997/04/11 23:03:09 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)nodes.c.pat 8.2 (Berkeley) 5/4/95 + */ + +#include <stdlib.h> +/* + * Routine for dealing with parsed shell commands. + */ + +#include "shell.h" +#include "nodes.h" +#include "memalloc.h" +#include "machdep.h" +#include "mystring.h" + + +int funcblocksize; /* size of structures in function */ +int funcstringsize; /* size of strings in node */ +pointer funcblock; /* block to allocate function from */ +char *funcstring; /* block to allocate strings from */ + +%SIZES + + +STATIC void calcsize __P((union node *)); +STATIC void sizenodelist __P((struct nodelist *)); +STATIC union node *copynode __P((union node *)); +STATIC struct nodelist *copynodelist __P((struct nodelist *)); +STATIC char *nodesavestr __P((char *)); + + + +/* + * Make a copy of a parse tree. + */ + +union node * +copyfunc(n) + union node *n; +{ + if (n == NULL) + return NULL; + funcblocksize = 0; + funcstringsize = 0; + calcsize(n); + funcblock = ckmalloc(funcblocksize + funcstringsize); + funcstring = (char *) funcblock + funcblocksize; + return copynode(n); +} + + + +STATIC void +calcsize(n) + union node *n; +{ + %CALCSIZE +} + + + +STATIC void +sizenodelist(lp) + struct nodelist *lp; +{ + while (lp) { + funcblocksize += ALIGN(sizeof(struct nodelist)); + calcsize(lp->n); + lp = lp->next; + } +} + + + +STATIC union node * +copynode(n) + union node *n; +{ + union node *new; + + %COPY + return new; +} + + +STATIC struct nodelist * +copynodelist(lp) + struct nodelist *lp; +{ + struct nodelist *start; + struct nodelist **lpp; + + lpp = &start; + while (lp) { + *lpp = funcblock; + funcblock = (char *) funcblock + ALIGN(sizeof(struct nodelist)); + (*lpp)->n = copynode(lp->n); + lp = lp->next; + lpp = &(*lpp)->next; + } + *lpp = NULL; + return start; +} + + + +STATIC char * +nodesavestr(s) + char *s; +{ + register char *p = s; + register char *q = funcstring; + char *rtn = funcstring; + + while ((*q++ = *p++) != '\0') + continue; + funcstring = q; + return rtn; +} + + + +/* + * Free a parse tree. + */ + +void +freefunc(n) + union node *n; +{ + if (n) + ckfree(n); +} diff --git a/release/picobsd/tinyware/ash/nodetypes b/release/picobsd/tinyware/ash/nodetypes new file mode 100644 index 0000000..cab5e02 --- /dev/null +++ b/release/picobsd/tinyware/ash/nodetypes @@ -0,0 +1,145 @@ +# $NetBSD: nodetypes,v 1.8 1995/05/11 21:29:44 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. All advertising materials mentioning features or use of this software +# must display the following acknowledgement: +# This product includes software developed by the University of +# California, Berkeley and its contributors. +# 4. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# @(#)nodetypes 8.2 (Berkeley) 5/4/95 + +# This file describes the nodes used in parse trees. Unindented lines +# contain a node type followed by a structure tag. Subsequent indented +# lines specify the fields of the structure. Several node types can share +# the same structure, in which case the fields of the structure should be +# specified only once. +# +# A field of a structure is described by the name of the field followed +# by a type. The currently implemented types are: +# nodeptr - a pointer to a node +# nodelist - a pointer to a list of nodes +# string - a pointer to a nul terminated string +# int - an integer +# other - any type that can be copied by assignment +# temp - a field that doesn't have to be copied when the node is copied +# The last two types should be followed by the text of a C declaration for +# the field. + +NSEMI nbinary # two commands separated by a semicolon + type int + ch1 nodeptr # the first child + ch2 nodeptr # the second child + +NCMD ncmd # a simple command + type int + backgnd int # set to run command in background + args nodeptr # the arguments + redirect nodeptr # list of file redirections + +NPIPE npipe # a pipeline + type int + backgnd int # set to run pipeline in background + cmdlist nodelist # the commands in the pipeline + +NREDIR nredir # redirection (of a compex command) + type int + n nodeptr # the command + redirect nodeptr # list of file redirections + +NBACKGND nredir # run command in background +NSUBSHELL nredir # run command in a subshell + +NAND nbinary # the && operator +NOR nbinary # the || operator + +NIF nif # the if statement. Elif clauses are handled + type int # using multiple if nodes. + test nodeptr # if test + ifpart nodeptr # then ifpart + elsepart nodeptr # else elsepart + +NWHILE nbinary # the while statement. First child is the test +NUNTIL nbinary # the until statement + +NFOR nfor # the for statement + type int + args nodeptr # for var in args + body nodeptr # do body; done + var string # the for variable + +NCASE ncase # a case statement + type int + expr nodeptr # the word to switch on + cases nodeptr # the list of cases (NCLIST nodes) + +NCLIST nclist # a case + type int + next nodeptr # the next case in list + pattern nodeptr # list of patterns for this case + body nodeptr # code to execute for this case + + +NDEFUN narg # define a function. The "next" field contains + # the body of the function. + +NARG narg # represents a word + type int + next nodeptr # next word in list + text string # the text of the word + backquote nodelist # list of commands in back quotes + +NTO nfile # fd> fname +NFROM nfile # fd< fname +NAPPEND nfile # fd>> fname + type int + next nodeptr # next redirection in list + fd int # file descriptor being redirected + fname nodeptr # file name, in a NARG node + expfname temp char *expfname # actual file name + +NTOFD ndup # fd<&dupfd +NFROMFD ndup # fd>&dupfd + type int + next nodeptr # next redirection in list + fd int # file descriptor being redirected + dupfd int # file descriptor to duplicate + vname nodeptr # file name if fd>&$var + + +NHERE nhere # fd<<\! +NXHERE nhere # fd<<! + type int + next nodeptr # next redirection in list + fd int # file descriptor being redirected + doc nodeptr # input to command (NARG node) + +NNOT nnot # ! command (actually pipeline) + type int + com nodeptr diff --git a/release/picobsd/tinyware/ash/options.c b/release/picobsd/tinyware/ash/options.c new file mode 100644 index 0000000..30acc3c --- /dev/null +++ b/release/picobsd/tinyware/ash/options.c @@ -0,0 +1,541 @@ +/* $NetBSD: options.c,v 1.25 1997/07/04 21:02:16 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.25 1997/07/04 21:02:16 christos Exp $"); +#endif +#endif /* not lint */ + +#include <signal.h> +#include <unistd.h> +#include <stdlib.h> + +#include "shell.h" +#define DEFINE_OPTIONS +#include "options.h" +#undef DEFINE_OPTIONS +#include "nodes.h" /* for other header files */ +#include "eval.h" +#include "jobs.h" +#include "input.h" +#include "output.h" +#include "trap.h" +#include "var.h" +#include "memalloc.h" +#include "error.h" +#include "mystring.h" +#ifndef SMALL +#include "myhistedit.h" +#endif + +char *arg0; /* value of $0 */ +struct shparam shellparam; /* current positional parameters */ +char **argptr; /* argument list for builtin commands */ +char *optarg; /* set by nextopt (like getopt) */ +char *optptr; /* used by nextopt */ + +char *minusc; /* argument to -c option */ + + +STATIC void options __P((int)); +STATIC void minus_o __P((char *, int)); +STATIC void setoption __P((int, int)); +STATIC int getopts __P((char *, char *, char **, char ***, char **)); + + +/* + * Process the shell command line arguments. + */ + +void +procargs(argc, argv) + int argc; + char **argv; +{ + int i; + + argptr = argv; + if (argc > 0) + argptr++; + for (i = 0; i < NOPTS; i++) + optlist[i].val = 2; + options(1); + if (*argptr == NULL && minusc == NULL) + sflag = 1; + if (iflag == 2 && sflag == 1 && isatty(0) && isatty(1)) + iflag = 1; + if (mflag == 2) + mflag = iflag; + for (i = 0; i < NOPTS; i++) + if (optlist[i].val == 2) + optlist[i].val = 0; + arg0 = argv[0]; + if (sflag == 0 && minusc == NULL) { + commandname = arg0 = *argptr++; + setinputfile(commandname, 0); + } + /* POSIX 1003.2: first arg after -c cmd is $0, remainder $1... */ + if (argptr && minusc && *argptr) + arg0 = *argptr++; + + shellparam.p = argptr; + shellparam.reset = 1; + /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ + while (*argptr) { + shellparam.nparam++; + argptr++; + } + optschanged(); +} + + +void +optschanged() +{ + setinteractive(iflag); +#ifndef SMALL + histedit(); +#endif + setjobctl(mflag); +} + +/* + * Process shell options. The global variable argptr contains a pointer + * to the argument list; we advance it past the options. + */ + +STATIC void +options(cmdline) + int cmdline; +{ + char *p; + int val; + int c; + + if (cmdline) + minusc = NULL; + while ((p = *argptr) != NULL) { + argptr++; + if ((c = *p++) == '-') { + val = 1; + if (p[0] == '\0' || (p[0] == '-' && p[1] == '\0')) { + if (!cmdline) { + /* "-" means turn off -x and -v */ + if (p[0] == '\0') + xflag = vflag = 0; + /* "--" means reset params */ + else if (*argptr == NULL) + setparam(argptr); + } + break; /* "-" or "--" terminates options */ + } + } else if (c == '+') { + val = 0; + } else { + argptr--; + break; + } + 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 + } else if (c == 'o') { + minus_o(*argptr, val); + if (*argptr) + argptr++; + } else { + setoption(c, val); + } + } + } +} + +STATIC void +minus_o(name, val) + char *name; + int val; +{ + int i; + + if (name == NULL) { + out1str("Current option settings\n"); + for (i = 0; i < NOPTS; i++) + out1fmt("%-16s%s\n", optlist[i].name, + optlist[i].val ? "on" : "off"); + } else { + for (i = 0; i < NOPTS; i++) + if (equal(name, optlist[i].name)) { + setoption(optlist[i].letter, val); + return; + } + error("Illegal option -o %s", name); + } +} + + +STATIC void +setoption(flag, val) + char flag; + int val; + { + int 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; + } + return; + } + error("Illegal option -%c", flag); +} + + + +#ifdef mkinit +INCLUDE "options.h" + +SHELLPROC { + int i; + + for (i = 0; i < NOPTS; i++) + optlist[i].val = 0; + optschanged(); + +} +#endif + + +/* + * Set the shell parameters. + */ + +void +setparam(argv) + char **argv; + { + char **newparam; + char **ap; + int nparam; + + for (nparam = 0 ; argv[nparam] ; nparam++); + ap = newparam = ckmalloc((nparam + 1) * sizeof *ap); + while (*argv) { + *ap++ = savestr(*argv++); + } + *ap = NULL; + freeparam(&shellparam); + shellparam.malloc = 1; + shellparam.nparam = nparam; + shellparam.p = newparam; + shellparam.optnext = NULL; +} + + +/* + * Free the list of positional parameters. + */ + +void +freeparam(param) + struct shparam *param; + { + char **ap; + + if (param->malloc) { + for (ap = param->p ; *ap ; ap++) + ckfree(*ap); + ckfree(param->p); + } +} + + + +/* + * The shift builtin command. + */ + +int +shiftcmd(argc, argv) + int argc; + char **argv; +{ + int n; + char **ap1, **ap2; + + n = 1; + if (argc > 1) + n = number(argv[1]); + if (n > shellparam.nparam) + error("can't shift that many"); + INTOFF; + shellparam.nparam -= n; + for (ap1 = shellparam.p ; --n >= 0 ; ap1++) { + if (shellparam.malloc) + ckfree(*ap1); + } + ap2 = shellparam.p; + while ((*ap2++ = *ap1++) != NULL); + shellparam.optnext = NULL; + INTON; + return 0; +} + + + +/* + * The set command builtin. + */ + +int +setcmd(argc, argv) + int argc; + char **argv; +{ + if (argc == 1) + return showvarscmd(argc, argv); + INTOFF; + options(0); + optschanged(); + if (*argptr != NULL) { + setparam(argptr); + } + INTON; + return 0; +} + + +void +getoptsreset(value) + const char *value; +{ + if (number(value) == 1) { + shellparam.optnext = NULL; + shellparam.reset = 1; + } +} + +/* + * The getopts builtin. Shellparam.optnext points to the next argument + * to be processed. Shellparam.optptr points to the next character to + * be processed in the current argument. If shellparam.optnext is NULL, + * then it's the first time getopts has been called. + */ + +int +getoptscmd(argc, argv) + int argc; + char **argv; +{ + char **optbase; + + if (argc < 3) + error("Usage: getopts optstring var [arg]"); + else if (argc == 3) + optbase = shellparam.p; + else + optbase = &argv[3]; + + if (shellparam.reset == 1) { + shellparam.optnext = optbase; + shellparam.optptr = NULL; + shellparam.reset = 0; + } + + return getopts(argv[1], argv[2], optbase, &shellparam.optnext, + &shellparam.optptr); +} + +STATIC int +getopts(optstr, optvar, optfirst, optnext, optptr) + char *optstr; + char *optvar; + char **optfirst; + char ***optnext; + char **optptr; +{ + char *p, *q; + char c = '?'; + int done = 0; + int ind = 0; + int err = 0; + char s[10]; + + if ((p = *optptr) == NULL || *p == '\0') { + /* Current word is done, advance */ + if (*optnext == NULL) + return 1; + p = **optnext; + if (p == NULL || *p != '-' || *++p == '\0') { +atend: + ind = *optnext - optfirst + 1; + *optnext = NULL; + p = NULL; + done = 1; + goto out; + } + (*optnext)++; + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + goto atend; + } + + c = *p++; + for (q = optstr; *q != c; ) { + if (*q == '\0') { + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; + err |= setvarsafe("OPTARG", s, 0); + } + else { + out1fmt("Illegal option -%c\n", c); + (void) unsetvar("OPTARG"); + } + c = '?'; + goto bad; + } + if (*++q == ':') + q++; + } + + if (*++q == ':') { + if (*p == '\0' && (p = **optnext) == NULL) { + if (optstr[0] == ':') { + s[0] = c; + s[1] = '\0'; + err |= setvarsafe("OPTARG", s, 0); + c = ':'; + } + else { + out1fmt("No arg for -%c option\n", c); + (void) unsetvar("OPTARG"); + c = '?'; + } + goto bad; + } + + if (p == **optnext) + (*optnext)++; + setvarsafe("OPTARG", p, 0); + p = NULL; + } + else + setvarsafe("OPTARG", "", 0); + ind = *optnext - optfirst + 1; + goto out; + +bad: + ind = 1; + *optnext = NULL; + p = NULL; +out: + *optptr = p; + fmtstr(s, sizeof(s), "%d", ind); + err |= setvarsafe("OPTIND", s, VNOFUNC); + s[0] = c; + s[1] = '\0'; + err |= setvarsafe(optvar, s, 0); + if (err) { + *optnext = NULL; + *optptr = NULL; + flushall(); + exraise(EXERROR); + } + return done; +} + +/* + * XXX - should get rid of. have all builtins use getopt(3). the + * library getopt must have the BSD extension static variable "optreset" + * otherwise it can't be used within the shell safely. + * + * Standard option processing (a la getopt) for builtin routines. The + * only argument that is passed to nextopt is the option string; the + * other arguments are unnecessary. It return the character, or '\0' on + * end of input. + */ + +int +nextopt(optstring) + char *optstring; + { + char *p, *q; + char c; + + if ((p = optptr) == NULL || *p == '\0') { + p = *argptr; + if (p == NULL || *p != '-' || *++p == '\0') + return '\0'; + argptr++; + if (p[0] == '-' && p[1] == '\0') /* check for "--" */ + return '\0'; + } + c = *p++; + for (q = optstring ; *q != c ; ) { + if (*q == '\0') + error("Illegal option -%c", c); + if (*++q == ':') + q++; + } + if (*++q == ':') { + if (*p == '\0' && (p = *argptr++) == NULL) + error("No arg for -%c option", c); + optarg = p; + p = NULL; + } + optptr = p; + return c; +} diff --git a/release/picobsd/tinyware/ash/options.h b/release/picobsd/tinyware/ash/options.h new file mode 100644 index 0000000..5651b8e --- /dev/null +++ b/release/picobsd/tinyware/ash/options.h @@ -0,0 +1,114 @@ +/* $NetBSD: options.h,v 1.11 1996/11/06 01:17:12 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)options.h 8.2 (Berkeley) 5/4/95 + */ + +struct shparam { + int nparam; /* # of positional parameters (without $0) */ + unsigned char malloc; /* if parameter list dynamically allocated */ + unsigned char reset; /* if getopts has been reset */ + char **p; /* parameter list */ + char **optnext; /* next parameter to be processed by getopts */ + char *optptr; /* used by getopts */ +}; + + + +#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 NOPTS 15 + +struct optent { + const char *name; + const char letter; + char val; +}; + +#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 }, +}; +#else +extern struct optent optlist[NOPTS]; +#endif + + +extern char *minusc; /* argument to -c option */ +extern char *arg0; /* $0 */ +extern struct shparam shellparam; /* $@ */ +extern char **argptr; /* argument list for builtin commands */ +extern char *optarg; /* set by nextopt */ +extern char *optptr; /* used by nextopt */ + +void procargs __P((int, char **)); +void optschanged __P((void)); +void setparam __P((char **)); +void freeparam __P((struct shparam *)); +int shiftcmd __P((int, char **)); +int setcmd __P((int, char **)); +int getoptscmd __P((int, char **)); +int nextopt __P((char *)); +void getoptsreset __P((const char *)); diff --git a/release/picobsd/tinyware/ash/output.c b/release/picobsd/tinyware/ash/output.c new file mode 100644 index 0000000..f390a2d --- /dev/null +++ b/release/picobsd/tinyware/ash/output.c @@ -0,0 +1,584 @@ +/* $NetBSD: output.c,v 1.19 1997/07/04 21:02:18 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: output.c,v 1.19 1997/07/04 21:02:18 christos Exp $"); +#endif +#endif /* not lint */ + +/* + * Shell output routines. We use our own output routines because: + * When a builtin command is interrupted we have to discard + * any pending output. + * When a builtin command appears in back quotes, we want to + * save the output of the command in a region obtained + * via malloc, rather than doing a fork and reading the + * output of the command via a pipe. + * Our output routines may be smaller than the stdio routines. + */ + +#include <sys/types.h> /* quad_t */ +#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" + + +#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}; +struct output errout = {NULL, 0, NULL, 100, 2, 0}; +struct output memout = {NULL, 0, NULL, 0, MEM_OUT, 0}; +struct output *out1 = &output; +struct output *out2 = &errout; + + + +#ifdef mkinit + +INCLUDE "output.h" +INCLUDE "memalloc.h" + +RESET { + out1 = &output; + out2 = &errout; + if (memout.buf != NULL) { + ckfree(memout.buf); + memout.buf = NULL; + } +} + +#endif + + +#ifdef notdef /* no longer used */ +/* + * Set up an output file to write to memory rather than a file. + */ + +void +open_mem(block, length, file) + char *block; + int length; + struct output *file; + { + file->nextc = block; + file->nleft = --length; + file->fd = BLOCK_OUT; + file->flags = 0; +} +#endif + + +void +out1str(p) + const char *p; + { + outstr(p, out1); +} + + +void +out2str(p) + const char *p; + { + outstr(p, out2); +} + + +void +outstr(p, file) + const char *p; + struct output *file; + { + while (*p) + outc(*p++, file); + if (file == out2) + flushout(file); +} + + +char out_junk[16]; + + +void +emptyoutbuf(dest) + struct output *dest; + { + int offset; + + if (dest->fd == BLOCK_OUT) { + dest->nextc = out_junk; + dest->nleft = sizeof out_junk; + dest->flags |= OUTPUT_ERR; + } else if (dest->buf == NULL) { + INTOFF; + dest->buf = ckmalloc(dest->bufsize); + dest->nextc = dest->buf; + dest->nleft = dest->bufsize; + INTON; + } else if (dest->fd == MEM_OUT) { + offset = dest->bufsize; + INTOFF; + dest->bufsize <<= 1; + dest->buf = ckrealloc(dest->buf, dest->bufsize); + dest->nleft = dest->bufsize - offset; + dest->nextc = dest->buf + offset; + INTON; + } else { + flushout(dest); + } + dest->nleft--; +} + + +void +flushall() { + flushout(&output); + flushout(&errout); +} + + +void +flushout(dest) + struct output *dest; + { + + if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0) + return; + if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0) + dest->flags |= OUTPUT_ERR; + dest->nextc = dest->buf; + dest->nleft = dest->bufsize; +} + + +void +freestdout() { + INTOFF; + if (output.buf) { + ckfree(output.buf); + output.buf = NULL; + output.nleft = 0; + } + INTON; +} + + +#ifdef __STDC__ +void +outfmt(struct output *file, char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + doformat(file, fmt, ap); + va_end(ap); +} + + +void +out1fmt(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + doformat(out1, fmt, ap); + va_end(ap); +} + +void +dprintf(char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + doformat(out2, fmt, ap); + va_end(ap); + flushout(out2); +} + +void +fmtstr(char *outbuf, int length, char *fmt, ...) { + va_list ap; + struct output strout; + + va_start(ap, fmt); + 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'; +} + +#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 +dprintf(va_alist) + va_dcl + { + va_list ap; + char *fmt; + + va_start(ap); + fmt = va_arg(ap, char *); + doformat(out2, fmt, ap); + va_end(ap); + flushout(out2); +} + +void +fmtstr(va_alist) + 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. + * - The x format is also accepted but is treated like X. + * - The l 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. + * - The obsolete practice of preceding the width with a zero to get + * zero padding is not supported; use the precision field. + * - A % may be printed by writing %% in the format string. + */ + +#define TEMPSIZE 24 + +static const char digit[] = "0123456789ABCDEF"; + + +void +doformat(dest, f, ap) + struct output *dest; + char *f; /* format string */ + va_list ap; + { + 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; + u_long num; +#endif + unsigned base; + int len; + int size; + int pad; + + while ((c = *f++) != '\0') { + if (c != '%') { + outc(c, dest); + continue; + } + flushleft = 0; + sharp = 0; + width = 0; + prec = -1; + islong = 0; + isquad = 0; + for (;;) { + if (*f == '-') + flushleft++; + else if (*f == '#') + sharp++; + else + break; + f++; + } + if (*f == '*') { + width = va_arg(ap, int); + f++; + } else { + while (is_digit(*f)) { + width = 10 * width + digit_val(*f++); + } + } + if (*f == '.') { + if (*++f == '*') { + prec = va_arg(ap, int); + f++; + } else { + prec = 0; + while (is_digit(*f)) { + prec = 10 * prec + digit_val(*f++); + } + } + } + if (*f == 'l') { + islong++; + f++; + } 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 + l = va_arg(ap, int); + sign = 0; + num = l; + if (l < 0) { + num = -l; + sign = 1; + } + base = 10; + goto number; + case 'u': + base = 10; + goto uns_number; + case 'o': + base = 8; + goto uns_number; + 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 + num = va_arg(ap, unsigned int); +number: /* process a number */ + p = temp + TEMPSIZE - 1; + *p = '\0'; + while (num) { + *--p = digit[num % base]; + num /= base; + } + len = (temp + TEMPSIZE - 1) - p; + if (prec < 0) + prec = 1; + if (sharp && *f == 'o' && prec <= len) + prec = len + 1; + pad = 0; + if (width) { + size = len; + if (size < prec) + size = prec; + size += sign; + pad = width - size; + if (flushleft == 0) { + while (--pad >= 0) + outc(' ', dest); + } + } + if (sign) + outc('-', dest); + prec -= len; + while (--prec >= 0) + outc('0', dest); + while (*p) + outc(*p++, dest); + while (--pad >= 0) + outc(' ', dest); + break; + case 's': + p = va_arg(ap, char *); + pad = 0; + if (width) { + len = strlen(p); + if (prec >= 0 && len > prec) + len = prec; + pad = width - len; + if (flushleft == 0) { + while (--pad >= 0) + outc(' ', dest); + } + } + prec++; + while (--prec != 0 && *p) + outc(*p++, dest); + while (--pad >= 0) + outc(' ', dest); + break; + case 'c': + c = va_arg(ap, int); + outc(c, dest); + break; + default: + outc(*f, dest); + break; + } + f++; + } +} + + + +/* + * Version of write which resumes after a signal is caught. + */ + +int +xwrite(fd, buf, nbytes) + int fd; + char *buf; + int nbytes; + { + int ntry; + int i; + int n; + + n = nbytes; + ntry = 0; + for (;;) { + i = write(fd, buf, n); + if (i > 0) { + if ((n -= i) <= 0) + return nbytes; + buf += i; + ntry = 0; + } else if (i == 0) { + if (++ntry > 10) + return nbytes - n; + } else if (errno != EINTR) { + return -1; + } + } +} + + +/* + * Version of ioctl that retries after a signal is caught. + * XXX unused function + */ + +int +xioctl(fd, request, arg) + int fd; + unsigned long request; + char * arg; +{ + int i; + + while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR); + return i; +} diff --git a/release/picobsd/tinyware/ash/output.h b/release/picobsd/tinyware/ash/output.h new file mode 100644 index 0000000..44e7b3d --- /dev/null +++ b/release/picobsd/tinyware/ash/output.h @@ -0,0 +1,85 @@ +/* $NetBSD: output.h,v 1.13 1997/04/11 23:08:40 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)output.h 8.2 (Berkeley) 5/4/95 + */ + +#ifndef OUTPUT_INCL + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +struct output { + char *nextc; + int nleft; + char *buf; + int bufsize; + short fd; + short flags; +}; + +extern struct output output; +extern struct output errout; +extern struct output memout; +extern struct output *out1; +extern struct output *out2; + +void open_mem __P((char *, int, struct output *)); +void out1str __P((const char *)); +void out2str __P((const char *)); +void outstr __P((const char *, struct output *)); +void emptyoutbuf __P((struct output *)); +void flushall __P((void)); +void flushout __P((struct output *)); +void freestdout __P((void)); +void outfmt __P((struct output *, char *, ...)); +void out1fmt __P((char *, ...)); +void dprintf __P((char *, ...)); +void fmtstr __P((char *, int, char *, ...)); +void doformat __P((struct output *, char *, va_list)); +int xwrite __P((int, char *, int)); +int xioctl __P((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 OUTPUT_INCL +#endif diff --git a/release/picobsd/tinyware/ash/parser.c b/release/picobsd/tinyware/ash/parser.c new file mode 100644 index 0000000..4727f0f --- /dev/null +++ b/release/picobsd/tinyware/ash/parser.c @@ -0,0 +1,1542 @@ +/* $NetBSD: parser.c,v 1.36 1997/07/04 21:02:19 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +#if 0 +static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95"; +#else +__RCSID("$NetBSD: parser.c,v 1.36 1997/07/04 21:02:19 christos Exp $"); +#endif +#endif /* not lint */ + +#include <stdlib.h> + +#include "shell.h" +#include "parser.h" +#include "nodes.h" +#include "expand.h" /* defines rmescapes() */ +#include "redir.h" /* defines copyfd() */ +#include "syntax.h" +#include "options.h" +#include "input.h" +#include "output.h" +#include "var.h" +#include "error.h" +#include "memalloc.h" +#include "mystring.h" +#include "alias.h" +#include "show.h" +#ifndef SMALL +#include "myhistedit.h" +#endif + +/* + * Shell command parser. + */ + +#define EOFMARKLEN 79 + +/* values returned by readtoken */ +#include "token.h" + + + +struct heredoc { + struct heredoc *next; /* next here document in list */ + union node *here; /* redirection node */ + char *eofmark; /* string indicating end of input */ + int striptabs; /* if set, strip leading tabs */ +}; + + + +struct heredoc *heredoclist; /* list of here documents to read */ +int parsebackquote; /* nonzero if we are inside backquotes */ +int doprompt; /* if set, prompt the user */ +int needprompt; /* true if interactive and at start of line */ +int lasttoken; /* last token read */ +MKINIT int tokpushback; /* last token pushed back */ +char *wordtext; /* text of last word returned by readtoken */ +MKINIT int checkkwd; /* 1 == check for kwds, 2 == also eat newlines */ +struct nodelist *backquotelist; +union node *redirnode; +struct heredoc *heredoc; +int quoteflag; /* set if (part of) last token was quoted */ +int startlinno; /* line # where last token started */ + + +#define GDB_HACK 1 /* avoid local declarations which gdb can't handle */ +#ifdef GDB_HACK +static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0'}; +static const char types[] = "}-+?="; +#endif + + +STATIC union node *list __P((int)); +STATIC union node *andor __P((void)); +STATIC union node *pipeline __P((void)); +STATIC union node *command __P((void)); +STATIC union node *simplecmd __P((union node **, union node *)); +STATIC union node *makename __P((void)); +STATIC void parsefname __P((void)); +STATIC void parseheredoc __P((void)); +STATIC int peektoken __P((void)); +STATIC int readtoken __P((void)); +STATIC int xxreadtoken __P((void)); +STATIC int readtoken1 __P((int, char const *, char *, int)); +STATIC int noexpand __P((char *)); +STATIC void synexpect __P((int)); +STATIC void synerror __P((char *)); +STATIC void setprompt __P((int)); + + +/* + * Read and parse a command. Returns NEOF on end of file. (NULL is a + * valid parse tree indicating a blank line.) + */ + +union node * +parsecmd(interact) + int interact; +{ + int t; + + doprompt = interact; + if (doprompt) + setprompt(1); + else + setprompt(0); + needprompt = 0; + t = readtoken(); + if (t == TEOF) + return NEOF; + if (t == TNL) + return NULL; + tokpushback++; + return list(1); +} + + +STATIC union node * +list(nlflag) + int nlflag; +{ + union node *n1, *n2, *n3; + int tok; + + checkkwd = 2; + if (nlflag == 0 && tokendlist[peektoken()]) + return NULL; + n1 = NULL; + for (;;) { + n2 = andor(); + tok = readtoken(); + if (tok == TBACKGND) { + if (n2->type == NCMD || n2->type == NPIPE) { + n2->ncmd.backgnd = 1; + } else if (n2->type == NREDIR) { + n2->type = NBACKGND; + } else { + n3 = (union node *)stalloc(sizeof (struct nredir)); + n3->type = NBACKGND; + n3->nredir.n = n2; + n3->nredir.redirect = NULL; + n2 = n3; + } + } + if (n1 == NULL) { + n1 = n2; + } + else { + n3 = (union node *)stalloc(sizeof (struct nbinary)); + n3->type = NSEMI; + n3->nbinary.ch1 = n1; + n3->nbinary.ch2 = n2; + n1 = n3; + } + switch (tok) { + case TBACKGND: + case TSEMI: + tok = readtoken(); + /* fall through */ + case TNL: + if (tok == TNL) { + parseheredoc(); + if (nlflag) + return n1; + } else { + tokpushback++; + } + checkkwd = 2; + if (tokendlist[peektoken()]) + return n1; + break; + case TEOF: + if (heredoclist) + parseheredoc(); + else + pungetc(); /* push back EOF on input */ + return n1; + default: + if (nlflag) + synexpect(-1); + tokpushback++; + return n1; + } + } +} + + + +STATIC union node * +andor() { + union node *n1, *n2, *n3; + int t; + + n1 = pipeline(); + for (;;) { + if ((t = readtoken()) == TAND) { + t = NAND; + } else if (t == TOR) { + t = NOR; + } else { + tokpushback++; + return n1; + } + n2 = pipeline(); + n3 = (union node *)stalloc(sizeof (struct nbinary)); + n3->type = t; + n3->nbinary.ch1 = n1; + n3->nbinary.ch2 = n2; + n1 = n3; + } +} + + + +STATIC union node * +pipeline() { + union node *n1, *pipenode; + struct nodelist *lp, *prev; + + TRACE(("pipeline: entered\n")); + n1 = command(); + if (readtoken() == TPIPE) { + pipenode = (union node *)stalloc(sizeof (struct npipe)); + pipenode->type = NPIPE; + pipenode->npipe.backgnd = 0; + lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + pipenode->npipe.cmdlist = lp; + lp->n = n1; + do { + prev = lp; + lp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + lp->n = command(); + prev->next = lp; + } while (readtoken() == TPIPE); + lp->next = NULL; + n1 = pipenode; + } + tokpushback++; + return n1; +} + + + +STATIC union node * +command() { + union node *n1, *n2; + union node *ap, **app; + union node *cp, **cpp; + union node *redir, **rpp; + int t, negate = 0; + + checkkwd = 2; + redir = NULL; + n1 = NULL; + rpp = &redir; + + /* Check for redirection which may precede command */ + while (readtoken() == TREDIR) { + *rpp = n2 = redirnode; + rpp = &n2->nfile.next; + parsefname(); + } + tokpushback++; + + while (readtoken() == TNOT) { + TRACE(("command: TNOT recognized\n")); + negate = !negate; + } + tokpushback++; + + switch (readtoken()) { + case TIF: + n1 = (union node *)stalloc(sizeof (struct nif)); + n1->type = NIF; + n1->nif.test = list(0); + if (readtoken() != TTHEN) + synexpect(TTHEN); + n1->nif.ifpart = list(0); + n2 = n1; + while (readtoken() == TELIF) { + n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif)); + n2 = n2->nif.elsepart; + n2->type = NIF; + n2->nif.test = list(0); + if (readtoken() != TTHEN) + synexpect(TTHEN); + n2->nif.ifpart = list(0); + } + if (lasttoken == TELSE) + n2->nif.elsepart = list(0); + else { + n2->nif.elsepart = NULL; + tokpushback++; + } + if (readtoken() != TFI) + synexpect(TFI); + checkkwd = 1; + break; + case TWHILE: + case TUNTIL: { + int got; + n1 = (union node *)stalloc(sizeof (struct nbinary)); + n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL; + n1->nbinary.ch1 = list(0); + if ((got=readtoken()) != TDO) { +TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); + synexpect(TDO); + } + n1->nbinary.ch2 = list(0); + if (readtoken() != TDONE) + synexpect(TDONE); + checkkwd = 1; + break; + } + case TFOR: + if (readtoken() != TWORD || quoteflag || ! goodname(wordtext)) + synerror("Bad for loop variable"); + n1 = (union node *)stalloc(sizeof (struct nfor)); + n1->type = NFOR; + n1->nfor.var = wordtext; + if (readtoken() == TWORD && ! quoteflag && equal(wordtext, "in")) { + app = ≈ + while (readtoken() == TWORD) { + n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; + n2->narg.text = wordtext; + n2->narg.backquote = backquotelist; + *app = n2; + app = &n2->narg.next; + } + *app = NULL; + n1->nfor.args = ap; + if (lasttoken != TNL && lasttoken != TSEMI) + synexpect(-1); + } else { +#ifndef GDB_HACK + static const char argvars[5] = {CTLVAR, VSNORMAL|VSQUOTE, + '@', '=', '\0'}; +#endif + n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; + n2->narg.text = (char *)argvars; + n2->narg.backquote = NULL; + n2->narg.next = NULL; + n1->nfor.args = n2; + /* + * Newline or semicolon here is optional (but note + * that the original Bourne shell only allowed NL). + */ + if (lasttoken != TNL && lasttoken != TSEMI) + tokpushback++; + } + checkkwd = 2; + if ((t = readtoken()) == TDO) + t = TDONE; + else if (t == TBEGIN) + t = TEND; + else + synexpect(-1); + n1->nfor.body = list(0); + if (readtoken() != t) + synexpect(t); + checkkwd = 1; + break; + case TCASE: + n1 = (union node *)stalloc(sizeof (struct ncase)); + n1->type = NCASE; + if (readtoken() != TWORD) + synexpect(TWORD); + n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); + n2->type = NARG; + n2->narg.text = wordtext; + n2->narg.backquote = backquotelist; + n2->narg.next = NULL; + while (readtoken() == TNL); + if (lasttoken != TWORD || ! equal(wordtext, "in")) + synerror("expecting \"in\""); + cpp = &n1->ncase.cases; + checkkwd = 2, readtoken(); + do { + *cpp = cp = (union node *)stalloc(sizeof (struct nclist)); + cp->type = NCLIST; + app = &cp->nclist.pattern; + for (;;) { + *app = ap = (union node *)stalloc(sizeof (struct narg)); + ap->type = NARG; + ap->narg.text = wordtext; + ap->narg.backquote = backquotelist; + if (checkkwd = 2, readtoken() != TPIPE) + break; + app = &ap->narg.next; + readtoken(); + } + ap->narg.next = NULL; + if (lasttoken != TRP) + synexpect(TRP); + cp->nclist.body = list(0); + + checkkwd = 2; + if ((t = readtoken()) != TESAC) { + if (t != TENDCASE) + synexpect(TENDCASE); + else + checkkwd = 2, readtoken(); + } + cpp = &cp->nclist.next; + } while(lasttoken != TESAC); + *cpp = NULL; + checkkwd = 1; + break; + case TLP: + n1 = (union node *)stalloc(sizeof (struct nredir)); + n1->type = NSUBSHELL; + n1->nredir.n = list(0); + n1->nredir.redirect = NULL; + if (readtoken() != TRP) + synexpect(TRP); + checkkwd = 1; + break; + case TBEGIN: + n1 = list(0); + if (readtoken() != TEND) + synexpect(TEND); + checkkwd = 1; + break; + /* Handle an empty command like other simple commands. */ + case TSEMI: + /* + * An empty command before a ; doesn't make much sense, and + * should certainly be disallowed in the case of `if ;'. + */ + if (!redir) + synexpect(-1); + case TAND: + case TOR: + case TNL: + case TEOF: + case TWORD: + case TRP: + tokpushback++; + n1 = simplecmd(rpp, redir); + goto checkneg; + default: + synexpect(-1); + } + + /* Now check for redirection which may follow command */ + while (readtoken() == TREDIR) { + *rpp = n2 = redirnode; + rpp = &n2->nfile.next; + parsefname(); + } + tokpushback++; + *rpp = NULL; + if (redir) { + if (n1->type != NSUBSHELL) { + n2 = (union node *)stalloc(sizeof (struct nredir)); + n2->type = NREDIR; + n2->nredir.n = n1; + n1 = n2; + } + n1->nredir.redirect = redir; + } + +checkneg: + if (negate) { + n2 = (union node *)stalloc(sizeof (struct nnot)); + n2->type = NNOT; + n2->nnot.com = n1; + return n2; + } + else + return n1; +} + + +STATIC union node * +simplecmd(rpp, redir) + union node **rpp, *redir; + { + union node *args, **app; + union node **orig_rpp = rpp; + union node *n = NULL, *n2; + int negate = 0; + + /* If we don't have any redirections already, then we must reset */ + /* rpp to be the address of the local redir variable. */ + if (redir == 0) + rpp = &redir; + + args = NULL; + app = &args; + /* + * We save the incoming value, because we need this for shell + * functions. There can not be a redirect or an argument between + * the function name and the open parenthesis. + */ + orig_rpp = rpp; + + while (readtoken() == TNOT) { + TRACE(("command: TNOT recognized\n")); + negate = !negate; + } + tokpushback++; + + for (;;) { + if (readtoken() == TWORD) { + n = (union node *)stalloc(sizeof (struct narg)); + n->type = NARG; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + *app = n; + app = &n->narg.next; + } else if (lasttoken == TREDIR) { + *rpp = n = redirnode; + rpp = &n->nfile.next; + parsefname(); /* read name of redirection file */ + } else if (lasttoken == TLP && app == &args->narg.next + && rpp == orig_rpp) { + /* We have a function */ + if (readtoken() != TRP) + synexpect(TRP); +#ifdef notdef + if (! goodname(n->narg.text)) + synerror("Bad function name"); +#endif + n->type = NDEFUN; + n->narg.next = command(); + goto checkneg; + } else { + tokpushback++; + break; + } + } + *app = NULL; + *rpp = NULL; + n = (union node *)stalloc(sizeof (struct ncmd)); + n->type = NCMD; + n->ncmd.backgnd = 0; + n->ncmd.args = args; + n->ncmd.redirect = redir; + +checkneg: + if (negate) { + n2 = (union node *)stalloc(sizeof (struct nnot)); + n2->type = NNOT; + n2->nnot.com = n; + return n2; + } + else + return n; +} + +STATIC union node * +makename() { + union node *n; + + n = (union node *)stalloc(sizeof (struct narg)); + n->type = NARG; + n->narg.next = NULL; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + return n; +} + +void fixredir(n, text, err) + union node *n; + const char *text; + int err; + { + TRACE(("Fix redir %s %d\n", text, err)); + if (!err) + n->ndup.vname = NULL; + + if (is_digit(text[0]) && text[1] == '\0') + n->ndup.dupfd = digit_val(text[0]); + else if (text[0] == '-' && text[1] == '\0') + n->ndup.dupfd = -1; + else { + + if (err) + synerror("Bad fd number"); + else + n->ndup.vname = makename(); + } +} + + +STATIC void +parsefname() { + union node *n = redirnode; + + if (readtoken() != TWORD) + synexpect(-1); + if (n->type == NHERE) { + struct heredoc *here = heredoc; + struct heredoc *p; + int i; + + if (quoteflag == 0) + n->type = NXHERE; + TRACE(("Here document %d\n", n->type)); + if (here->striptabs) { + while (*wordtext == '\t') + wordtext++; + } + if (! noexpand(wordtext) || (i = strlen(wordtext)) == 0 || i > EOFMARKLEN) + synerror("Illegal eof marker for << redirection"); + rmescapes(wordtext); + here->eofmark = wordtext; + here->next = NULL; + if (heredoclist == NULL) + heredoclist = here; + else { + for (p = heredoclist ; p->next ; p = p->next); + p->next = here; + } + } else if (n->type == NTOFD || n->type == NFROMFD) { + fixredir(n, wordtext, 0); + } else { + n->nfile.fname = makename(); + } +} + + +/* + * Input any here documents. + */ + +STATIC void +parseheredoc() { + struct heredoc *here; + union node *n; + + while (heredoclist) { + here = heredoclist; + heredoclist = here->next; + if (needprompt) { + setprompt(2); + needprompt = 0; + } + readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, + here->eofmark, here->striptabs); + n = (union node *)stalloc(sizeof (struct narg)); + n->narg.type = NARG; + n->narg.next = NULL; + n->narg.text = wordtext; + n->narg.backquote = backquotelist; + here->here->nhere.doc = n; + } +} + +STATIC int +peektoken() { + int t; + + t = readtoken(); + tokpushback++; + return (t); +} + +STATIC int +readtoken() { + int t; + int savecheckkwd = checkkwd; + struct alias *ap; +#ifdef DEBUG + int alreadyseen = tokpushback; +#endif + + top: + t = xxreadtoken(); + + if (checkkwd) { + /* + * eat newlines + */ + if (checkkwd == 2) { + checkkwd = 0; + while (t == TNL) { + parseheredoc(); + t = xxreadtoken(); + } + } else + checkkwd = 0; + /* + * check for keywords and aliases + */ + if (t == TWORD && !quoteflag) + { + char * const *pp; + + for (pp = (char **)parsekwd; *pp; pp++) { + if (**pp == *wordtext && equal(*pp, wordtext)) + { + lasttoken = t = pp - parsekwd + KWDOFFSET; + TRACE(("keyword %s recognized\n", tokname[t])); + goto out; + } + } + if ((ap = lookupalias(wordtext, 1)) != NULL) { + pushstring(ap->val, strlen(ap->val), ap); + checkkwd = savecheckkwd; + goto top; + } + } +out: + checkkwd = (t == TNOT) ? savecheckkwd : 0; + } +#ifdef DEBUG + if (!alreadyseen) + TRACE(("token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); + else + TRACE(("reread token %s %s\n", tokname[t], t == TWORD ? wordtext : "")); +#endif + return (t); +} + + +/* + * Read the next input token. + * If the token is a word, we set backquotelist to the list of cmds in + * backquotes. We set quoteflag to true if any part of the word was + * quoted. + * If the token is TREDIR, then we set redirnode to a structure containing + * the redirection. + * In all cases, the variable startlinno is set to the number of the line + * on which the token starts. + * + * [Change comment: here documents and internal procedures] + * [Readtoken shouldn't have any arguments. Perhaps we should make the + * word parsing code into a separate routine. In this case, readtoken + * doesn't need to have any internal procedures, but parseword does. + * We could also make parseoperator in essence the main routine, and + * have parseword (readtoken1?) handle both words and redirection.] + */ + +#define RETURN(token) return lasttoken = token + +STATIC int +xxreadtoken() { + int c; + + if (tokpushback) { + tokpushback = 0; + return lasttoken; + } + if (needprompt) { + setprompt(2); + needprompt = 0; + } + startlinno = plinno; + for (;;) { /* until token or start of word found */ + c = pgetc_macro(); + if (c == ' ' || c == '\t') + continue; /* quick check for white space first */ + switch (c) { + case ' ': case '\t': + continue; + case '#': + while ((c = pgetc()) != '\n' && c != PEOF); + pungetc(); + continue; + case '\\': + if (pgetc() == '\n') { + startlinno = ++plinno; + if (doprompt) + setprompt(2); + else + setprompt(0); + continue; + } + pungetc(); + goto breakloop; + case '\n': + plinno++; + needprompt = doprompt; + RETURN(TNL); + case PEOF: + RETURN(TEOF); + case '&': + if (pgetc() == '&') + RETURN(TAND); + pungetc(); + RETURN(TBACKGND); + case '|': + if (pgetc() == '|') + RETURN(TOR); + pungetc(); + RETURN(TPIPE); + case ';': + if (pgetc() == ';') + RETURN(TENDCASE); + pungetc(); + RETURN(TSEMI); + case '(': + RETURN(TLP); + case ')': + RETURN(TRP); + default: + goto breakloop; + } + } +breakloop: + return readtoken1(c, BASESYNTAX, (char *)NULL, 0); +#undef RETURN +} + + + +/* + * If eofmark is NULL, read a word or a redirection symbol. If eofmark + * is not NULL, read a here document. In the latter case, eofmark is the + * word which marks the end of the document and striptabs is true if + * leading tabs should be stripped from the document. The argument firstc + * is the first character of the input token or document. + * + * Because C does not have internal subroutines, I have simulated them + * using goto's to implement the subroutine linkage. The following macros + * will run code that appears at the end of readtoken1. + */ + +#define CHECKEND() {goto checkend; checkend_return:;} +#define PARSEREDIR() {goto parseredir; parseredir_return:;} +#define PARSESUB() {goto parsesub; parsesub_return:;} +#define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} +#define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} +#define PARSEARITH() {goto parsearith; parsearith_return:;} + +STATIC int +readtoken1(firstc, syntax, eofmark, striptabs) + int firstc; + char const *syntax; + char *eofmark; + int striptabs; + { + int c = firstc; + char *out; + int len; + char line[EOFMARKLEN + 1]; + struct nodelist *bqlist; + int quotef; + int dblquote; + int varnest; /* levels of variables expansion */ + int arinest; /* levels of arithmetic expansion */ + int parenlevel; /* levels of parens in arithmetic */ + int oldstyle; + char const *prevsyntax; /* syntax before arithmetic */ +#if __GNUC__ + /* Avoid longjmp clobbering */ + (void) &out; + (void) "ef; + (void) &dblquote; + (void) &varnest; + (void) &arinest; + (void) &parenlevel; + (void) &oldstyle; + (void) &prevsyntax; + (void) &syntax; +#endif + + startlinno = plinno; + dblquote = 0; + if (syntax == DQSYNTAX) + dblquote = 1; + quotef = 0; + bqlist = NULL; + varnest = 0; + arinest = 0; + parenlevel = 0; + + STARTSTACKSTR(out); + loop: { /* for each line, until end of word */ +#if ATTY + if (c == '\034' && doprompt + && attyset() && ! equal(termval(), "emacs")) { + attyline(); + if (syntax == BASESYNTAX) + return readtoken(); + c = pgetc(); + goto loop; + } +#endif + CHECKEND(); /* set c to PEOF if at end of here document */ + for (;;) { /* until end of line or end of word */ + CHECKSTRSPACE(3, out); /* permit 3 calls to USTPUTC */ + switch(syntax[c]) { + case CNL: /* '\n' */ + if (syntax == BASESYNTAX) + goto endword; /* exit outer loop */ + USTPUTC(c, out); + plinno++; + if (doprompt) + setprompt(2); + else + setprompt(0); + c = pgetc(); + goto loop; /* continue outer loop */ + case CWORD: + USTPUTC(c, out); + break; + case CCTL: + if (eofmark == NULL || dblquote) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + break; + case CBACK: /* backslash */ + c = pgetc(); + if (c == PEOF) { + USTPUTC('\\', out); + pungetc(); + } else if (c == '\n') { + if (doprompt) + setprompt(2); + else + setprompt(0); + } else { + if (dblquote && c != '\\' && c != '`' && c != '$' + && (c != '"' || eofmark != NULL)) + USTPUTC('\\', out); + if (SQSYNTAX[c] == CCTL) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + quotef++; + } + break; + case CSQUOTE: + syntax = SQSYNTAX; + break; + case CDQUOTE: + syntax = DQSYNTAX; + dblquote = 1; + break; + case CENDQUOTE: + if (eofmark) { + USTPUTC(c, out); + } else { + if (arinest) + syntax = ARISYNTAX; + else + syntax = BASESYNTAX; + quotef++; + dblquote = 0; + } + break; + case CVAR: /* '$' */ + PARSESUB(); /* parse substitution */ + break; + case CENDVAR: /* '}' */ + if (varnest > 0) { + varnest--; + USTPUTC(CTLENDVAR, out); + } else { + USTPUTC(c, out); + } + break; + case CLP: /* '(' in arithmetic */ + parenlevel++; + USTPUTC(c, out); + break; + case CRP: /* ')' in arithmetic */ + if (parenlevel > 0) { + USTPUTC(c, out); + --parenlevel; + } else { + if (pgetc() == ')') { + if (--arinest == 0) { + USTPUTC(CTLENDARI, out); + syntax = prevsyntax; + } else + USTPUTC(')', out); + } else { + /* + * unbalanced parens + * (don't 2nd guess - no error) + */ + pungetc(); + USTPUTC(')', out); + } + } + break; + case CBQUOTE: /* '`' */ + PARSEBACKQOLD(); + break; + case CEOF: + goto endword; /* exit outer loop */ + default: + if (varnest == 0) + goto endword; /* exit outer loop */ + USTPUTC(c, out); + } + c = pgetc_macro(); + } + } +endword: + if (syntax == ARISYNTAX) + synerror("Missing '))'"); + if (syntax != BASESYNTAX && ! parsebackquote && eofmark == NULL) + synerror("Unterminated quoted string"); + if (varnest != 0) { + startlinno = plinno; + synerror("Missing '}'"); + } + USTPUTC('\0', out); + len = out - stackblock(); + out = stackblock(); + if (eofmark == NULL) { + if ((c == '>' || c == '<') + && quotef == 0 + && len <= 2 + && (*out == '\0' || is_digit(*out))) { + PARSEREDIR(); + return lasttoken = TREDIR; + } else { + pungetc(); + } + } + quoteflag = quotef; + backquotelist = bqlist; + grabstackblock(len); + wordtext = out; + return lasttoken = TWORD; +/* end of readtoken routine */ + + + +/* + * Check to see whether we are at the end of the here document. When this + * is called, c is set to the first character of the next input line. If + * we are at the end of the here document, this routine sets the c to PEOF. + */ + +checkend: { + if (eofmark) { + if (striptabs) { + while (c == '\t') + c = pgetc(); + } + if (c == *eofmark) { + if (pfgets(line, sizeof line) != NULL) { + char *p, *q; + + p = line; + for (q = eofmark + 1 ; *q && *p == *q ; p++, q++); + if (*p == '\n' && *q == '\0') { + c = PEOF; + plinno++; + needprompt = doprompt; + } else { + pushstring(line, strlen(line), NULL); + } + } + } + } + goto checkend_return; +} + + +/* + * Parse a redirection operator. The variable "out" points to a string + * specifying the fd to be redirected. The variable "c" contains the + * first character of the redirection operator. + */ + +parseredir: { + char fd = *out; + union node *np; + + np = (union node *)stalloc(sizeof (struct nfile)); + if (c == '>') { + np->nfile.fd = 1; + c = pgetc(); + if (c == '>') + np->type = NAPPEND; + else if (c == '&') + np->type = NTOFD; + else { + np->type = NTO; + pungetc(); + } + } else { /* c == '<' */ + np->nfile.fd = 0; + c = pgetc(); + if (c == '<') { + if (sizeof (struct nfile) != sizeof (struct nhere)) { + np = (union node *)stalloc(sizeof (struct nhere)); + np->nfile.fd = 0; + } + np->type = NHERE; + heredoc = (struct heredoc *)stalloc(sizeof (struct heredoc)); + heredoc->here = np; + if ((c = pgetc()) == '-') { + heredoc->striptabs = 1; + } else { + heredoc->striptabs = 0; + pungetc(); + } + } else if (c == '&') + np->type = NFROMFD; + else { + np->type = NFROM; + pungetc(); + } + } + if (fd != '\0') + np->nfile.fd = digit_val(fd); + redirnode = np; + goto parseredir_return; +} + + +/* + * Parse a substitution. At this point, we have read the dollar sign + * and nothing else. + */ + +parsesub: { + int subtype; + int typeloc; + int flags; + char *p; +#ifndef GDB_HACK + static const char types[] = "}-+?="; +#endif + + c = pgetc(); + if (c != '(' && c != '{' && !is_name(c) && !is_special(c)) { + USTPUTC('$', out); + pungetc(); + } else if (c == '(') { /* $(command) or $((arith)) */ + if (pgetc() == '(') { + PARSEARITH(); + } else { + pungetc(); + PARSEBACKQNEW(); + } + } else { + USTPUTC(CTLVAR, out); + typeloc = out - stackblock(); + USTPUTC(VSNORMAL, out); + subtype = VSNORMAL; + if (c == '{') { + c = pgetc(); + if (c == '#') { + if ((c = pgetc()) == '}') + c = '#'; + else + subtype = VSLENGTH; + } + else + subtype = 0; + } + if (is_name(c)) { + do { + STPUTC(c, out); + c = pgetc(); + } while (is_in_name(c)); + } else if (is_digit(c)) { + do { + USTPUTC(c, out); + c = pgetc(); + } while (is_digit(c)); + } + else if (is_special(c)) { + USTPUTC(c, out); + c = pgetc(); + } + else +badsub: synerror("Bad substitution"); + + STPUTC('=', out); + flags = 0; + if (subtype == 0) { + switch (c) { + case ':': + flags = VSNUL; + c = pgetc(); + /*FALLTHROUGH*/ + default: + p = strchr(types, c); + if (p == NULL) + goto badsub; + subtype = p - types + VSNORMAL; + break; + case '%': + case '#': + { + int cc = c; + subtype = c == '#' ? VSTRIMLEFT : + VSTRIMRIGHT; + c = pgetc(); + if (c == cc) + subtype++; + else + pungetc(); + break; + } + } + } else { + pungetc(); + } + if (dblquote || arinest) + flags |= VSQUOTE; + *(stackblock() + typeloc) = subtype | flags; + if (subtype != VSNORMAL) + varnest++; + } + goto parsesub_return; +} + + +/* + * Called to parse command substitutions. Newstyle is set if the command + * is enclosed inside $(...); nlpp is a pointer to the head of the linked + * list of commands (passed by reference), and savelen is the number of + * characters on the top of the stack which must be preserved. + */ + +parsebackq: { + struct nodelist **nlpp; + int savepbq; + union node *n; + char *volatile str; + struct jmploc jmploc; + struct jmploc *volatile savehandler; + int savelen; + int saveprompt; +#ifdef __GNUC__ + (void) &saveprompt; +#endif + + savepbq = parsebackquote; + if (setjmp(jmploc.loc)) { + if (str) + ckfree(str); + parsebackquote = 0; + handler = savehandler; + longjmp(handler->loc, 1); + } + INTOFF; + str = NULL; + savelen = out - stackblock(); + if (savelen > 0) { + str = ckmalloc(savelen); + memcpy(str, stackblock(), savelen); + } + savehandler = handler; + handler = &jmploc; + INTON; + if (oldstyle) { + /* We must read until the closing backquote, giving special + treatment to some slashes, and then push the string and + reread it as input, interpreting it normally. */ + char *out; + int c; + int savelen; + char *str; + + + STARTSTACKSTR(out); + for (;;) { + if (needprompt) { + setprompt(2); + needprompt = 0; + } + switch (c = pgetc()) { + case '`': + goto done; + + case '\\': + if ((c = pgetc()) == '\n') { + plinno++; + if (doprompt) + setprompt(2); + else + setprompt(0); + /* + * If eating a newline, avoid putting + * the newline into the new character + * stream (via the STPUTC after the + * switch). + */ + continue; + } + if (c != '\\' && c != '`' && c != '$' + && (!dblquote || c != '"')) + STPUTC('\\', out); + break; + + case '\n': + plinno++; + needprompt = doprompt; + break; + + case PEOF: + startlinno = plinno; + synerror("EOF in backquote substitution"); + break; + + default: + break; + } + STPUTC(c, out); + } +done: + STPUTC('\0', out); + savelen = out - stackblock(); + if (savelen > 0) { + str = ckmalloc(savelen); + memcpy(str, stackblock(), savelen); + setinputstring(str, 1); + } + } + nlpp = &bqlist; + while (*nlpp) + nlpp = &(*nlpp)->next; + *nlpp = (struct nodelist *)stalloc(sizeof (struct nodelist)); + (*nlpp)->next = NULL; + parsebackquote = oldstyle; + + if (oldstyle) { + saveprompt = doprompt; + doprompt = 0; + } + + n = list(0); + + if (oldstyle) + doprompt = saveprompt; + else { + if (readtoken() != TRP) + synexpect(TRP); + } + + (*nlpp)->n = n; + if (oldstyle) { + /* + * Start reading from old file again, ignoring any pushed back + * tokens left from the backquote parsing + */ + popfile(); + tokpushback = 0; + } + while (stackblocksize() <= savelen) + growstackblock(); + STARTSTACKSTR(out); + if (str) { + memcpy(out, str, savelen); + STADJUST(savelen, out); + INTOFF; + ckfree(str); + str = NULL; + INTON; + } + parsebackquote = savepbq; + handler = savehandler; + if (arinest || dblquote) + USTPUTC(CTLBACKQ | CTLQUOTE, out); + else + USTPUTC(CTLBACKQ, out); + if (oldstyle) + goto parsebackq_oldreturn; + else + goto parsebackq_newreturn; +} + +/* + * Parse an arithmetic expansion (indicate start of one and set state) + */ +parsearith: { + + if (++arinest == 1) { + prevsyntax = syntax; + syntax = ARISYNTAX; + USTPUTC(CTLARI, out); + } else { + /* + * we collapse embedded arithmetic expansion to + * parenthesis, which should be equivalent + */ + USTPUTC('(', out); + } + goto parsearith_return; +} + +} /* end of readtoken */ + + + +#ifdef mkinit +RESET { + tokpushback = 0; + checkkwd = 0; +} +#endif + +/* + * Returns true if the text contains nothing to expand (no dollar signs + * or backquotes). + */ + +STATIC int +noexpand(text) + char *text; + { + char *p; + char c; + + p = text; + while ((c = *p++) != '\0') { + if (c == CTLESC) + p++; + else if (BASESYNTAX[c] == CCTL) + return 0; + } + return 1; +} + + +/* + * Return true if the argument is a legal variable name (a letter or + * underscore followed by zero or more letters, underscores, and digits). + */ + +int +goodname(name) + char *name; + { + char *p; + + p = name; + if (! is_name(*p)) + return 0; + while (*++p) { + if (! is_in_name(*p)) + return 0; + } + return 1; +} + + +/* + * Called when an unexpected token is read during the parse. The argument + * is the token that is expected, or -1 if more than one type of token can + * occur at this point. + */ + +STATIC void +synexpect(token) + int token; +{ + char msg[64]; + + if (token >= 0) { + fmtstr(msg, 64, "%s unexpected (expecting %s)", + tokname[lasttoken], tokname[token]); + } else { + fmtstr(msg, 64, "%s unexpected", tokname[lasttoken]); + } + synerror(msg); +} + + +STATIC void +synerror(msg) + char *msg; + { + if (commandname) + outfmt(&errout, "%s: %d: ", commandname, startlinno); + outfmt(&errout, "Syntax error: %s\n", msg); + error((char *)NULL); +} + +STATIC void +setprompt(which) + int which; + { + whichprompt = which; + +#ifndef SMALL + if (!el) +#endif + out2str(getprompt(NULL)); +} + +/* + * called by editline -- any expansions to the prompt + * should be added here. + */ +char * +getprompt(unused) + void *unused; + { + switch (whichprompt) { + case 0: + return ""; + case 1: + return ps1val(); + case 2: + return ps2val(); + default: + return "<internal prompt error>"; + } +} diff --git a/release/picobsd/tinyware/ash/parser.h b/release/picobsd/tinyware/ash/parser.h new file mode 100644 index 0000000..8d47413 --- /dev/null +++ b/release/picobsd/tinyware/ash/parser.h @@ -0,0 +1,82 @@ +/* $NetBSD: parser.h,v 1.11 1996/10/16 15:45:15 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)parser.h 8.3 (Berkeley) 5/4/95 + */ + +/* control characters in argument strings */ +#define CTLESC '\201' +#define CTLVAR '\202' +#define CTLENDVAR '\203' +#define CTLBACKQ '\204' +#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ +/* CTLBACKQ | CTLQUOTE == '\205' */ +#define CTLARI '\206' +#define CTLENDARI '\207' + +/* 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 */ + +/* values of VSTYPE field */ +#define VSNORMAL 0x1 /* normal variable: $var or ${var} */ +#define VSMINUS 0x2 /* ${var-text} */ +#define VSPLUS 0x3 /* ${var+text} */ +#define VSQUESTION 0x4 /* ${var?message} */ +#define VSASSIGN 0x5 /* ${var=text} */ +#define VSTRIMLEFT 0x6 /* ${var#pattern} */ +#define VSTRIMLEFTMAX 0x7 /* ${var##pattern} */ +#define VSTRIMRIGHT 0x8 /* ${var%pattern} */ +#define VSTRIMRIGHTMAX 0x9 /* ${var%%pattern} */ +#define VSLENGTH 0xa /* ${#var} */ + + +/* + * NEOF is returned by parsecmd when it encounters an end of file. It + * must be distinct from NULL, so we use the address of a variable that + * happens to be handy. + */ +extern int tokpushback; +#define NEOF ((union node *)&tokpushback) +extern int whichprompt; /* 1 == PS1, 2 == PS2 */ + + +union node *parsecmd __P((int)); +void fixredir __P((union node *, const char *, int)); +int goodname __P((char *)); +char *getprompt __P((void *)); diff --git a/release/picobsd/tinyware/ash/redir.c b/release/picobsd/tinyware/ash/redir.c new file mode 100644 index 0000000..ae9116a --- /dev/null +++ b/release/picobsd/tinyware/ash/redir.c @@ -0,0 +1,375 @@ +/* $NetBSD: redir.c,v 1.16 1997/07/04 21:02:21 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.16 1997/07/04 21:02:21 christos Exp $"); +#endif +#endif /* not lint */ + +#include <sys/types.h> +#include <signal.h> +#include <string.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> + +/* + * Code for dealing with input/output redirection. + */ + +#include "shell.h" +#include "nodes.h" +#include "jobs.h" +#include "expand.h" +#include "redir.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" + + +#define EMPTY -2 /* marks an unused slot in redirtab */ +#define PIPESIZE 4096 /* amount of buffering in a pipe */ + + +MKINIT +struct redirtab { + struct redirtab *next; + short renamed[10]; +}; + + +MKINIT struct redirtab *redirlist; + +/* + * We keep track of whether or not fd0 has been redirected. This is for + * background commands, where we want to redirect fd0 to /dev/null only + * if it hasn't already been redirected. +*/ +int fd0_redirected = 0; + +STATIC void openredirect __P((union node *, char[10 ])); +STATIC int openhere __P((union node *)); + + +/* + * Process a list of redirection commands. If the REDIR_PUSH flag is set, + * old file descriptors are stashed away so that the redirection can be + * undone by calling popredir. If the REDIR_BACKQ flag is set, then the + * standard output, and the standard error if it becomes a duplicate of + * stdout, is saved in memory. + */ + +void +redirect(redir, flags) + union node *redir; + int flags; + { + union node *n; + 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) { + sv = ckmalloc(sizeof (struct redirtab)); + for (i = 0 ; i < 10 ; i++) + sv->renamed[i] = EMPTY; + sv->next = redirlist; + redirlist = sv; + } + 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*/ + default: + INTON; + error("%d: %s", fd, strerror(errno)); + break; + } + } + if (!try) { + sv->renamed[fd] = i; + close(fd); + } + INTON; + } else { + close(fd); + } + if (fd == 0) + fd0_redirected++; + if (!try) + openredirect(n, memory); + } + if (memory[1]) + out1 = &memout; + if (memory[2]) + out2 = &memout; +} + + +STATIC void +openredirect(redir, memory) + union node *redir; + char memory[10]; + { + int fd = redir->nfile.fd; + char *fname; + int f; + + /* + * We suppress interrupts so that we won't leave open file + * descriptors around. This may not be such a good idea because + * an open of a device or a fifo can block indefinitely. + */ + INTOFF; + memory[fd] = 0; + switch (redir->nfile.type) { + case NFROM: + fname = redir->nfile.expfname; + if ((f = open(fname, O_RDONLY)) < 0) + error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); +movefd: + if (f != fd) { + copyfd(f, fd); + close(f); + } + break; + case NTO: + fname = redir->nfile.expfname; +#ifdef O_CREAT + if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) + error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +#else + if ((f = creat(fname, 0666)) < 0) + error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +#endif + goto movefd; + case NAPPEND: + fname = redir->nfile.expfname; +#ifdef O_APPEND + if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) + error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); +#else + if ((f = open(fname, O_WRONLY)) < 0 + && (f = creat(fname, 0666)) < 0) + error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); + lseek(f, (off_t)0, 2); +#endif + goto movefd; + case NTOFD: + case NFROMFD: + if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ + if (memory[redir->ndup.dupfd]) + memory[fd] = 1; + else + copyfd(redir->ndup.dupfd, fd); + } + break; + case NHERE: + case NXHERE: + f = openhere(redir); + goto movefd; + default: + abort(); + } + INTON; +} + + +/* + * Handle here documents. Normally we fork off a process to write the + * data to a pipe. If the document is short, we can stuff the data in + * the pipe without forking. + */ + +STATIC int +openhere(redir) + union node *redir; + { + int pip[2]; + int len = 0; + + if (pipe(pip) < 0) + error("Pipe call failed"); + if (redir->type == NHERE) { + len = strlen(redir->nhere.doc->narg.text); + if (len <= PIPESIZE) { + xwrite(pip[1], redir->nhere.doc->narg.text, len); + goto out; + } + } + if (forkshell((struct job *)NULL, (union node *)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); + else + expandhere(redir->nhere.doc, pip[1]); + _exit(0); + } +out: + close(pip[1]); + return pip[0]; +} + + + +/* + * Undo the effects of the last redirection. + */ + +void +popredir() { + struct redirtab *rp = redirlist; + int i; + + for (i = 0 ; i < 10 ; i++) { + if (rp->renamed[i] != EMPTY) { + if (i == 0) + fd0_redirected--; + close(i); + if (rp->renamed[i] >= 0) { + copyfd(rp->renamed[i], i); + close(rp->renamed[i]); + } + } + } + INTOFF; + redirlist = rp->next; + ckfree(rp); + INTON; +} + +/* + * Undo all redirections. Called on error or interrupt. + */ + +#ifdef mkinit + +INCLUDE "redir.h" + +RESET { + while (redirlist) + popredir(); +} + +SHELLPROC { + clearredir(); +} + +#endif + +/* Return true if fd 0 has already been redirected at least once. */ +int +fd0_redirected_p () { + return fd0_redirected != 0; +} + +/* + * Discard all saved file descriptors. + */ + +void +clearredir() { + struct redirtab *rp; + int i; + + for (rp = redirlist ; rp ; rp = rp->next) { + for (i = 0 ; i < 10 ; i++) { + if (rp->renamed[i] >= 0) { + close(rp->renamed[i]); + } + rp->renamed[i] = EMPTY; + } + } +} + + + +/* + * 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(from, to) + int from; + int to; +{ + int newfd; + + newfd = fcntl(from, F_DUPFD, to); + if (newfd < 0) { + if (errno == EMFILE) + return EMPTY; + else + error("%d: %s", from, strerror(errno)); + } + return newfd; +} diff --git a/release/picobsd/tinyware/ash/redir.h b/release/picobsd/tinyware/ash/redir.h new file mode 100644 index 0000000..44eecc7 --- /dev/null +++ b/release/picobsd/tinyware/ash/redir.h @@ -0,0 +1,51 @@ +/* $NetBSD: redir.h,v 1.10 1996/10/16 15:45:18 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)redir.h 8.2 (Berkeley) 5/4/95 + */ + +/* flags passed to redirect */ +#define REDIR_PUSH 01 /* save previous values of file descriptors */ +#define REDIR_BACKQ 02 /* save the command output in memory */ + +union node; +void redirect __P((union node *, int)); +void popredir __P((void)); +int fd0_redirected_p __P((void)); +void clearredir __P((void)); +int copyfd __P((int, int)); + diff --git a/release/picobsd/tinyware/ash/sh.1 b/release/picobsd/tinyware/ash/sh.1 new file mode 100644 index 0000000..281bb3c --- /dev/null +++ b/release/picobsd/tinyware/ash/sh.1 @@ -0,0 +1,1450 @@ +.\" $NetBSD: sh.1,v 1.20 1997/05/23 19:40:30 cjs 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. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)sh.1 8.6 (Berkeley) 5/4/95 +.\" +.na +.TH SH 1 +.SH NAME +sh \- command interpreter (shell) +.SH SYNOPSIS +sh [-/+aCefnuvxIimsVEb] [-/+o longname] [arg ...] +.SH DESCRIPTION +.LP +Sh is the standard command interpreter for the system. +The current version of sh is in the process of being changed to +conform with the POSIX 1003.2 and 1003.2a specifications for +the shell. This version has many features which make it appear +similar in some respects to the Korn shell, but it is not a Korn +shell clone (run GNU's bash if you want that). Only features +designated by POSIX, plus a few Berkeley extensions, are being +incorporated into this shell. We expect POSIX conformance by the +time 4.4 BSD is released. +This man page is not intended to be a tutorial or a complete +specification of the shell. +.sp 2 +.B Overview +.sp +.LP +The shell is a command that reads lines from +either a file or the terminal, interprets them, and +generally executes other commands. It is the program that is running +when a user logs into the system (although a user can select +a different shell with the chsh(1) command). +The shell +implements a language that has flow control constructs, +a macro facility that provides a variety of features in +addition to data storage, along with built in history and line +editing capabilities. It incorporates many features to +aid interactive use and has the advantage that the interpretative +language is common to both interactive and non-interactive +use (shell scripts). That is, commands can be typed directly +to the running shell or can be put into a file and the file +can be executed directly by the shell. +.sp 2 +.B Invocation +.sp +.LP +If no args are present and if the standard input of the shell +is connected to a terminal (or if the -i flag is set), the shell +is considered an interactive shell. An interactive shell +generally prompts before each command and handles programming +and command errors differently (as described below). +When first starting, the shell inspects argument 0, and +if it begins with a dash '-', the shell is also considered +a login shell. This is normally done automatically by the system +when the user first logs in. A login shell first reads commands +from the files /etc/profile and .profile if they exist. +If the environment variable ENV is set on entry to a shell, +or is set in the .profile of a login shell, the shell next reads +commands from the file named in ENV. Therefore, a user should +place commands that are to be executed only at login time in +the .profile file, and commands that are executed for every +shell inside the ENV file. To set the ENV variable to some +file, place the following line in your .profile of your home +directory +.nf + + ENV=$HOME/.shinit; export ENV + +.fi +substituting for ``.shinit'' any filename you wish. +Since the ENV file is read for +every invocation of the shell, including shell scripts and +non-interactive shells, the following paradigm is useful +for restricting commands in the ENV file to interactive invocations. +Place commands within the ``case'' and ``esac'' below (these +commands are described later): +.nf + + case $- in *i*) + # commands for interactive use only + ... + esac + +.fi +If command line arguments besides the options have been +specified, then the shell treats the first argument as the +name of a file from which to read commands (a shell script), and +the remaining arguments are set as the positional parameters +of the shell ($1, $2, etc). Otherwise, the shell reads commands +from its standard input. +.sp 2 +.B Argument List Processing +.sp +.LP +All of the single letter options have a corresponding name +that can be used as an argument to the '-o' option. The +set -o name is provided next to the single letter option in +the description below. +Specifying a dash ``-'' turns the option on, while using a plus ``+'' +disables the option. +The following options can be set from the command line or +with the set(1) builtin (described later). +.TP +-a allexport +Export all variables assigned to. +(UNIMPLEMENTED for 4.4alpha) +.TP +-C noclobber +Don't overwrite existing files with ``>''. +(UNIMPLEMENTED for 4.4alpha) +.TP +-e errexit +If not interactive, exit immediately if any +untested command fails. +The exit status of a command is considered to be +explicitly tested if the command is used to control +an if, elif, while, or until; or if the command is the left +hand operand of an ``&&'' or ``||'' operator. + +.TP +-f noglob +Disable pathname expansion. +.TP +-n noexec +If not interactive, read commands but do not +execute them. This is useful for checking the +syntax of shell scripts. +.TP +-u nounset +Write a message to standard error when attempting +to expand a variable that is not set, and if the +shell is not interactive, exit immediately. +(UNIMPLEMENTED for 4.4alpha) +.TP +-v verbose +The shell writes its input to standard error +as it is read. Useful for debugging. +.TP +-x xtrace +Write each command to standard error (preceded +by a '+ ') before it is executed. Useful for +debugging. +.TP +-I ignoreeof +Ignore EOF's from input when interactive. +.TP +-i interactive +Force the shell to behave interactively. +.TP +-m monitor +Turn on job control (set automatically when +interactive). +.TP +-s stdin +Read commands from standard input (set automatically +if no file arguments are present). This option has +no effect when set after the shell has already started +running (i.e. with set(1)). +.TP +-V vi +Enable the built-in vi(1) command line editor (disables +-E if it has been set). +.TP +-E emacs +Enable the built-in emacs(1) command line editor (disables +-V if it has been set). +.TP +-b notify +Enable asynchronous notification of background job +completion. +(UNIMPLEMENTED for 4.4alpha) +.LP +.sp 2 +.B Lexical Structure +.sp +.LP +The shell reads input in terms of lines from a file and breaks +it up into words at whitespace (blanks and tabs), and at +certain sequences of +characters that are special to the shell called ``operators''. +There are two types of operators: control operators and +redirection operators (their meaning is discussed later). +Following is a list of operators: +.nf +.sp +Control operators: & && ( ) ; ;; | || <newline> +.sp +Redirection operator: < > >| << >> <& >& <<- <> +.sp +.fi +.sp 2 +.B Quoting +.sp +.LP +Quoting is used to remove the special meaning of certain characters +or words to the shell, such as operators, whitespace, or +keywords. There are three types of quoting: matched single quotes, +matched double quotes, and backslash. +.sp 2 +.B Backslash +.sp +.LP +A backslash preserves the literal meaning of the following +character, with the exception of <newline>. A backslash preceding +a <newline> is treated as a line continuation. +.sp 2 +.B Single Quotes +.sp +.LP +Enclosing characters in single quotes preserves the literal +meaning of all the characters (except single quotes, making +it impossible to put single-quotes in a single-quoted string). +.sp 2 +.B Double Quotes +.sp +.LP +Enclosing characters within double quotes preserves the literal +meaning of all characters except dollarsign ($), backquote (`), +and backslash (\\). The backslash inside double quotes is +historically weird, and serves to quote only the following +characters: $ ` " \\ <newline>. +Otherwise it remains literal. +.sp 2 +.B Reserved Words +.sp +.LP +Reserved words are words that have special meaning to the +shell and are recognized at the beginning of a line and +after a control operator. The following are reserved words: +.nf + + ! elif fi while case + else for then { } + do done until if esac + +.fi +Their meaning is discussed later. +.sp 2 +.B Aliases +.sp +.LP +An alias is a name and corresponding value set using the alias(1) +builtin command. Whenever a reserved word may occur (see above), +and after checking for reserved words, the shell +checks the word to see if it matches an alias. If it does, +it replaces it in the input stream with its value. For example, +if there is an alias called ``lf'' with the value ``ls -F'', +then the input +.nf + + lf foobar <return> + + would become + + ls -F foobar <return> + +.fi +.LP +Aliases provide a convenient way for naive users to +create shorthands for commands without having to learn how +to create functions with arguments. They can also be +used to create lexically obscure code. This use is discouraged. +.sp 2 +.B Commands +.sp +.LP +The shell interprets the words it reads according to a +language, the specification of which is outside the scope +of this man page (refer to the BNF in the POSIX 1003.2 +document). Essentially though, a line is read and if +the first word of the line (or after a control operator) +is not a reserved word, then the shell has recognized a +simple command. Otherwise, a complex command or some +other special construct may have been recognized. +.sp 2 +.B Simple Commands +.sp +.LP +If a simple command has been recognized, the shell performs +the following actions: +.sp +1) Leading words of the form ``name=value'' are +stripped off and assigned to the environment of +the simple command. Redirection operators and +their arguments (as described below) are stripped +off and saved for processing. +.sp +2) The remaining words are expanded as described in +the section called ``Expansions'', and the +first remaining word is considered the command +name and the command is located. The remaining +words are considered the arguments of the command. +If no command name resulted, then the ``name=value'' +variable assignments recognized in 1) affect the +current shell. +.sp +3) Redirections are performed as described in +the next section. +.sp 2 +.B Redirections +.sp +.LP +Redirections are used to change where a command reads its input +or sends its output. In general, redirections open, close, or +duplicate an existing reference to a file. The overall format +used for redirection is: +.nf + + [n] redir-op file + +.fi +where redir-op is one of the redirection operators mentioned +previously. Following is a list of the possible redirections. +The [n] is an optional number, as in '3' (not '[3]'), that +refers to a file descriptor. +.TP +[n]> file +Redirect standard output (or n) to file. +.TP +[n]>| file +Same, but override the -C option. +.TP +[n]>> file +Append standard output (or n) to file. +.TP +[n]< file +Redirect standard input (or n) from file. +.TP +[n1]<&n2 +Duplicate standard input (or n1) from +file descriptor n2. +.TP +[n]<&- +Close standard input (or n). +.TP +[n1]>&n2 +Duplicate standard output (or n) from +n2. +.TP +[n]>&- +Close standard output (or n). +.TP +[n]<> file +Open file for reading and writing on +standard input (or n). +.LP +The following redirection is often called a ``here-document''. +.nf + + [n]<< delimiter + here-doc-text... + delimiter + +.fi +All the text on successive lines up to the delimiter is +saved away and made available to the command on standard +input, or file descriptor n if it is specified. If the delimiter +as specified on the initial line is quoted, then the here-doc-text +is treated literally, otherwise the text is subjected to +parameter expansion, command substitution, and arithmetic +expansion (as described in the section on ``Expansions''). If +the operator is ``<<-'' instead of ``<<'', then leading tabs +in the here-doc-text are stripped. +.sp 2 +.B Search and Execution +.sp +.LP +There are three types of commands: shell functions, +builtin commands, and normal programs -- and the +command is searched for (by name) in that order. They +each are executed in a different way. +.LP +When a shell function is executed, all of the shell positional +parameters (except $0, which remains unchanged) are +set to the arguments of the shell function. +The variables which are explicitly placed in the environment of +the command (by placing assignments to them before the +function name) are made local to the function and are set +to the values given. Then the command given in the function +definition is executed. The positional parameters are +restored to their original values when the command completes. +This all occurs within the current shell. +.LP +Shell builtins are executed internally to the shell, without +spawning a new process. +.LP +Otherwise, if the command name doesn't match a function +or builtin, the command is searched for as a normal +program in the filesystem (as described in the next section). +When a normal program is executed, the shell runs the program, +passing the arguments and the environment to the +program. If the program is not a normal executable file +(i.e., if it does not begin with the "magic number" +whose ASCII representation is "#!", so execve(2) returns +ENOEXEC then) the shell +will interpret the program in a subshell. The child shell will +reinitialize itself in this case, so that the effect will +be as if a new shell had been invoked to handle the ad-hoc shell +script, except that the location of hashed commands located in +the parent shell will be remembered by the child. +.LP +Note that previous versions of this document +and the source code itself misleadingly and sporadically +refer to a shell script without a magic number +as a "shell procedure". +.sp 2 +.B Path Search +.sp +.LP +When locating a command, the shell first looks to see if +it has a shell function by that name. Then it looks for a +builtin command by that name. If a builtin command is not found, +one of two things happen: +.sp +1) Command names containing a slash are simply executed without +performing any searches. +.sp +2) The shell searches each entry in PATH in turn for the command. +The value of the PATH variable should be a series of +entries separated by colons. Each entry consists of a +directory name. +The current directory +may be indicated implicitly by an empty directory name, +or explicitly by a single period. +.sp 2 +.B Command Exit Status +.sp +.LP +Each command has an exit status that can influence the behavior +of other shell commands. The paradigm is that a command exits +with zero for normal or success, and non-zero for failure, +error, or a false indication. The man page for each command +should indicate the various exit codes and what they mean. +Additionally, the builtin commands return exit codes, as does +an executed shell function. +.sp 2 +.B Complex Commands +.sp +.LP +Complex commands are combinations of simple commands +with control operators or reserved words, together creating a larger complex +command. More generally, a command is one of the following: +.nf + + - simple command + + - pipeline + + - list or compound-list + + - compound command + + - function definition + +.fi +.LP +Unless otherwise stated, the exit status of a command is +that of the last simple command executed by the command. +.sp 2 +.B Pipelines +.sp +.LP +A pipeline is a sequence of one or more commands separated +by the control operator |. The standard output of all but +the last command is connected to the standard input +of the next command. The standard output of the last +command is inherited from the shell, as usual. +.LP +The format for a pipeline is: +.nf + +[!] command1 [ | command2 ...] + +.fi +.LP +The standard output of command1 is connected to the standard +input of command2. The standard input, standard output, or +both of a command is considered to be assigned by the +pipeline before any redirection specified by redirection +operators that are part of the command. +.LP +If the pipeline is not in the background (discussed later), +the shell waits for all commands to complete. +.LP +If the reserved word ! does not precede the pipeline, the +exit status is the exit status of the last command specified +in the pipeline. Otherwise, the exit status is the logical +NOT of the exit status of the last command. That is, if +the last command returns zero, the exit status is 1; if +the last command returns greater than zero, the exit status +is zero. +.LP +Because pipeline assignment of standard input or standard +output or both takes place before redirection, it can be +modified by redirection. For example: +.nf + +$ command1 2>&1 | command2 + +.fi +sends both the standard output and standard error of command1 +to the standard input of command2. +.LP +A ; or <newline> terminator causes the preceding +AND-OR-list (described next) to be executed sequentially; a & causes +asynchronous execution of the preceding AND-OR-list. +.LP +Note that unlike some other shells, each process in the +pipeline is a child of the invoking shell (unless it +is a shell builtin, in which case it executes in the +current shell -- but any effect it has on the +environment is wiped). +.sp 2 +.B Background Commands -- & +.sp +.LP +If a command is terminated by the control operator ampersand +(&), the shell executes the command asynchronously -- that is, +the shell does not wait for +the command to finish before executing the next command. +.LP +The format for running a command in background is: +.nf + +command1 & [command2 & ...] + +.fi +If the shell is not interactive, the standard input of an +asynchronous command is set to /dev/null. +.sp 2 +.B Lists -- Generally Speaking +.sp +.LP +A list is a sequence of zero or more commands separated by +newlines, semicolons, or ampersands, +and optionally terminated by one of these three characters. +The commands in a +list are executed in the order they are written. +If command is followed by an ampersand, the shell starts the +command and immediately proceed onto the next command; +otherwise it waits for the command to terminate before +proceeding to the next one. +.sp 2 +.B Short-Circuit List Operators +.sp +.LP +``&&'' and ``||'' are AND-OR list operators. ``&&'' executes +the first command, and then executes the second command +iff the exit status of the first command is zero. ``||'' +is similar, but executes the second command iff the exit +status of the first command is nonzero. ``&&'' and ``||'' +both have the same priority. +.sp 2 +.B Flow-Control Constructs -- if, while, for, case +.sp +.LP +The syntax of the if command is +.nf + + if list + then list + [ elif list + then list ] ... + [ else list ] + fi + +.fi +The syntax of the while command is +.nf + + while list + do list + done + +.fi +The two lists are executed repeatedly while the exit status of the +first list is zero. The until command is similar, but has the word +until in place of while, which causes it to +repeat until the exit status of the first list is zero. +.LP +The syntax of the for command is +.nf + + for variable in word... + do list + done + +.fi +The words are expanded, and then the list is executed +repeatedly with the variable set to each word in turn. do +and done may be replaced with ``{'' and ``}''. +.LP +The syntax of the break and continue command is +.nf + + break [ num ] + continue [ num ] + +.fi +Break terminates the num innermost for or while loops. +Continue continues with the next iteration of the innermost loop. +These are implemented as builtin commands. +.LP +The syntax of the case command is +.nf + + case word in + pattern) list ;; + ... + esac + +.fi +.LP +The pattern can actually be one or more patterns (see Shell +Patterns described later), separated by ``|'' characters. +.sp 2 +.B Grouping Commands Together +.sp +.LP +Commands may be grouped by writing either +.nf + + (list) + +.fi +or +.nf + + { list; } + +.fi +The first of these executes the commands in a subshell. +Builtin commands grouped into a (list) will not affect +the current shell. +The second form does not fork another shell so is +slightly more efficient. +Grouping commands together this way allows you to +redirect their output as though they were one program: +.nf + + { echo -n "hello"; echo " world" } > greeting + +.fi +.sp 2 +.B Functions +.sp +.LP +The syntax of a function definition is +.nf + + name ( ) command + +.fi +.LP +A function definition is an executable statement; when +executed it installs a function named name and returns an +exit status of zero. The command is normally a list +enclosed between ``{'' and ``}''. +.LP +Variables may be declared to be local to a function by +using a local command. This should appear as the first +statement of a function, and the syntax is +.nf + + local [ variable | - ] ... + +.fi +Local is implemented as a builtin command. +.LP +When a variable is made local, it inherits the initial +value and exported and readonly flags from the variable +with the same name in the surrounding scope, if there is +one. Otherwise, the variable is initially unset. The shell +uses dynamic scoping, so that if you make the variable x +local to function f, which then calls function g, references +to the variable x made inside g will refer to the +variable x declared inside f, not to the global variable +named x. +.LP +The only special parameter than can be made local is +``-''. Making ``-'' local any shell options that are +changed via the set command inside the function to be +restored to their original values when the function +returns. +.LP +The syntax of the return command is +.nf + + return [ exitstatus ] + +.fi +It terminates the currently executing function. Return is +implemented as a builtin command. +.sp 2 +.B Variables and Parameters +.sp +.LP +The shell maintains a set of parameters. A parameter +denoted by a name is called a variable. When starting up, +the shell turns all the environment variables into shell +variables. New variables can be set using the form +.nf + + name=value + +.fi +.LP +Variables set by the user must have a name consisting solely +of alphabetics, numerics, and underscores - the first of which +must not be numeric. A parameter can also be denoted by a number +or a special character as explained below. +.sp 2 +.B Positional Parameters +.sp +.LP +A positional parameter is a parameter denoted by a number (n > 0). +The shell sets these initially to the values of its command +line arguments that follow the name of the shell script. +The set(1) builtin can also be used to set or reset them. +.sp 2 +.B Special Parameters +.sp +.LP +A special parameter is a parameter denoted by one of the following +special characters. The value of the parameter is listed +next to its character. +.TP +* +Expands to the positional parameters, starting from one. When +the expansion occurs within a double-quoted string +it expands to a single field with the value of each parameter +separated by the first character of the IFS variable, or by a +<space> if IFS is unset. +.TP +@ +Expands to the positional parameters, starting from one. When +the expansion occurs within double-quotes, each positional +parameter expands as a separate argument. +If there are no positional parameters, the +expansion of @ generates zero arguments, even when @ is +double-quoted. What this basically means, for example, is +if $1 is ``abc'' and $2 is ``def ghi'', then "$@" expands to +the two arguments: + +"abc" "def ghi" +.TP +# +Expands to the number of positional parameters. +.TP +? +Expands to the exit status of the most recent pipeline. +.TP +- (Hyphen) +Expands to the current option flags (the single-letter +option names concatenated into a string) as specified on +invocation, by the set builtin command, or implicitly +by the shell. +.TP +$ +Expands to the process ID of the invoked shell. A subshell +retains the same value of $ as its parent. +.TP +! +Expands to the process ID of the most recent background +command executed from the current shell. For a +pipeline, the process ID is that of the last command in the +pipeline. +.TP +0 (Zero.) +Expands to the name of the shell or shell script. +.LP +.sp 2 +.B Word Expansions +.sp +.LP +This clause describes the various expansions that are +performed on words. Not all expansions are performed on +every word, as explained later. +.LP +Tilde expansions, parameter expansions, command substitutions, +arithmetic expansions, and quote removals that occur within +a single word expand to a single field. It is only field +splitting or pathname expansion that can create multiple +fields from a single word. The single exception to this +rule is the expansion of the special parameter @ within +double-quotes, as was described above. +.LP +The order of word expansion is: +.LP +(1) Tilde Expansion, Parameter Expansion, Command Substitution, +Arithmetic Expansion (these all occur at the same time). +.LP +(2) Field Splitting is performed on fields +generated by step (1) unless the IFS variable is null. +.LP +(3) Pathname Expansion (unless set -f is in effect). +.LP +(4) Quote Removal. +.LP +The $ character is used to introduce parameter expansion, command +substitution, or arithmetic evaluation. +.sp 2 +.B Tilde Expansion (substituting a user's home directory) +.sp +.LP +A word beginning with an unquoted tilde character (~) is +subjected to tilde expansion. All the characters up to +a slash (/) or the end of the word are treated as a username +and are replaced with the user's home directory. If the +username is missing (as in ~/foobar), the tilde is replaced +with the value of the HOME variable (the current user's +home directory). + +.sp 2 +.B Parameter Expansion +.sp +.LP +The format for parameter expansion is as follows: +.nf + + ${expression} + +.fi +where expression consists of all characters until the matching }. Any } +escaped by a backslash or within a quoted string, and characters in +embedded arithmetic expansions, command substitutions, and variable +expansions, are not examined in determining the matching }. +.LP +The simplest form for parameter expansion is: +.nf + + ${parameter} + +.fi +The value, if any, of parameter is substituted. +.LP +The parameter name or symbol can be enclosed in braces, which are +optional except for positional parameters with more than one digit or +when parameter is followed by a character that could be interpreted as +part of the name. +If a parameter expansion occurs inside +double-quotes: +.LP +1) Pathname expansion is not performed on the results of the +expansion. +.LP +2) Field splitting is not performed on the results of the +expansion, with the exception of @. +.LP +In addition, a parameter expansion can be modified by using one of the +following formats. +.sp +.TP +${parameter:-word} +Use Default Values. If parameter is unset or +null, the expansion of word is +substituted; otherwise, the value of +parameter is substituted. +.TP +${parameter:=word} +Assign Default Values. If parameter is unset +or null, the expansion of word is +assigned to parameter. In all cases, the +final value of parameter is +substituted. Only variables, not positional +parameters or special parameters, can be +assigned in this way. +.TP +${parameter:?[word]} +Indicate Error if Null or Unset. If +parameter is unset or null, the expansion of +word (or a message indicating it is unset if +word is omitted) is written to standard +error and the shell exits with a nonzero +exit status. Otherwise, the value of +parameter is substituted. An +interactive shell need not exit. +.TP +${parameter:+word} +Use Alternative Value. If parameter is unset +or null, null is substituted; +otherwise, the expansion of word is +substituted. +.LP +In the parameter expansions shown previously, use of the colon in the +format results in a test for a parameter that is unset or null; omission +of the colon results in a test for a parameter that is only unset. +.TP +${#parameter} +String Length. The length in characters of +the value of parameter. +.LP +The following four varieties of parameter expansion provide for substring +processing. In each case, pattern matching notation (see Shell Patterns), +rather +than regular expression notation, is used to evaluate the patterns. +If parameter is * or @, the result of the expansion is unspecified. +Enclosing the full parameter expansion string in double-quotes does not +cause the following four varieties of pattern characters to be quoted, +whereas quoting characters within the braces has this effect. +.TP +${parameter%word} +Remove Smallest Suffix Pattern. The word +is expanded to produce a pattern. The +parameter expansion then results in +parameter, with the smallest portion of the +suffix matched by the pattern deleted. +.TP +${parameter%%word} +Remove Largest Suffix Pattern. The word +is expanded to produce a pattern. The +parameter expansion then results in +parameter, with the largest portion of the +suffix matched by the pattern deleted. +.TP +${parameter#word} +Remove Smallest Prefix Pattern. The word +is expanded to produce a pattern. The +parameter expansion then results in +parameter, with the smallest portion of the +prefix matched by the pattern deleted. +.TP +${parameter##word} +Remove Largest Prefix Pattern. The word +is expanded to produce a pattern. The +parameter expansion then results in +parameter, with the largest portion of the +prefix matched by the pattern deleted. +.LP +.sp 2 +.B Command Substitution +.sp +.LP +Command substitution allows the output of a command to be substituted in +place of the command name itself. Command substitution occurs when +the command is enclosed as follows: +.nf + + $(command) + +.fi +or (``backquoted'' version): +.nf + + `command` + +.fi +.LP +The shell expands the command substitution by executing command in a +subshell environment and replacing the command substitution +with the +standard output of the command, removing sequences of one or more +<newline>s at the end of the substitution. (Embedded <newline>s before +the end of the output are not removed; however, during field +splitting, they may be translated into <space>s, depending on the value +of IFS and quoting that is in effect.) + +.sp 2 +.B Arithmetic Expansion +.sp +.LP +Arithmetic expansion provides a mechanism for evaluating an arithmetic +expression and substituting its value. The format for arithmetic +expansion is as follows: +.nf + + $((expression)) + +.fi +The expression is treated as if it were in double-quotes, except +that a double-quote inside the expression is not treated specially. The +shell expands all tokens in the expression for parameter expansion, +command substitution, and quote removal. +.LP +Next, the shell treats this as an arithmetic expression and +substitutes the value of the expression. + +.sp 2 +.B White Space Splitting (Field Splitting) +.sp +.LP +After parameter expansion, command substitution, and +arithmetic expansion the shell scans the results of +expansions and substitutions that did not occur in double-quotes for +field splitting and multiple fields can result. +.LP +The shell treats each character of the IFS as a delimiter and use +the delimiters to split the results of parameter expansion and command +substitution into fields. + +.sp 2 +.B Pathname Expansion (File Name Generation) +.sp +.LP +Unless the -f flag is set, file name generation is performed +after word splitting is complete. Each word is +viewed as a series of patterns, separated by slashes. The +process of expansion replaces the word with the names of +all existing files whose names can be formed by replacing +each pattern with a string that matches the specified pattern. +There are two restrictions on this: first, a pattern cannot match +a string containing a slash, and second, +a pattern cannot match a string starting with a period +unless the first character of the pattern is a period. +The next section describes the patterns used for both +Pathname Expansion and the case(1) command. + +.sp 2 +.B Shell Patterns +.sp +.LP +A pattern consists of normal characters, which match themselves, +and meta-characters. The meta-characters are +``!'', ``*'', ``?'', and ``[''. These characters lose +their special meanings if they are quoted. When command +or variable substitution is performed and the dollar sign +or back quotes are not double quoted, the value of the +variable or the output of the command is scanned for these +characters and they are turned into meta-characters. +.LP +An asterisk (``*'') matches any string of characters. A +question mark matches any single character. A left +bracket (``['') introduces a character class. The end of +the character class is indicated by a ``]''; if the ``]'' +is missing then the ``['' matches a ``['' rather than +introducing a character class. A character class matches +any of the characters between the square brackets. A +range of characters may be specified using a minus sign. +The character class may be complemented by making an +exclamation point the first character of the character +class. +.LP +To include a ``]'' in a character class, make it the first +character listed (after the ``!'', if any). To include a +minus sign, make it the first or last character listed + +.sp 2 +.B Builtins +.sp +.LP +This section lists the builtin commands which +are builtin because they need to perform some operation +that can't be performed by a separate process. In addition to +these, there are several other commands that may +be builtin for efficiency (e.g. printf(1), echo(1), test(1), +etc). +.TP +: +A null command that returns a 0 (true) exit value. +.TP +\&. file +The commands in the specified file are read and executed by the shell. +.TP +alias [ name[=string] ... ] +If name=string is specified, the shell defines the +alias ``name'' with value ``string''. If just ``name'' +is specified, the value of the alias ``name'' is printed. +With no arguments, the alias builtin prints the +names and values of all defined aliases (see unalias). +.TP +bg [ job ] ... +Continue the specified jobs (or the current job if no +jobs are given) in the background. +.TP +command command arg... +Execute the specified builtin command. (This is useful when you +have a shell function with the same name +as a builtin command.) +.TP +cd [ directory ] +Switch to the specified directory (default $HOME). +If the an entry for CDPATH appears in the environment +of the cd command or the shell variable CDPATH is set +and the directory name does not begin with a slash, +then the directories listed in CDPATH will be +searched for the specified directory. The format of +CDPATH is the same as that of PATH. In an interactive shell, +the cd command will print out the name of +the directory that it actually switched to if this is +different from the name that the user gave. These +may be different either because the CDPATH mechanism +was used or because a symbolic link was crossed. +.TP +eval string... +Concatenate all the arguments with spaces. Then +re-parse and execute the command. +.TP +exec [ command arg... ] +Unless command is omitted, the shell process is +replaced with the specified program (which must be a +real program, not a shell builtin or function). Any +redirections on the exec command are marked as permanent, +so that they are not undone when the exec command finishes. +.TP +exit [ exitstatus ] +Terminate the shell process. If exitstatus is given +it is used as the exit status of the shell; otherwise +the exit status of the preceding command is used. +.TP +export name... +The specified names are exported so that they will +appear in the environment of subsequent commands. +The only way to un-export a variable is to unset it. +The shell allows the value of a variable to be set at the +same time it is exported by writing +.nf + + export name=value + +.fi +With no arguments the export command lists the names +of all exported variables. +.TP +fc [-e editor] [first [last]] +.TP +fc -l [-nr] [first [last]] +.TP +fc -s [old=new] [first] +The fc builtin lists, or edits and re-executes, commands +previously entered to an interactive shell. +.RS +.5i +.TP 2 +-e editor +Use the editor named by editor to edit the commands. The +editor string is a command name, subject to search via the +PATH variable. The value in the FCEDIT variable +is used as a default when -e is not specified. If +FCEDIT is null or unset, the value of the EDITOR +variable is used. If EDITOR is null or unset, +ed(1) is used as the editor. +.TP 2 +-l (ell) +List the commands rather than invoking +an editor on them. The commands are written in the +sequence indicated by the first and last operands, as +affected by -r, with each command preceded by the command +number. +.TP 2 +-n +Suppress command numbers when listing with -l. +.TP 2 +-r +Reverse the order of the commands listed (with -l) or +edited (with neither -l nor -s). +.TP 2 +-s +Re-execute the command without invoking an editor. +.TP 2 +first +.TP 2 +last +Select the commands to list or edit. The number of +previous commands that can be accessed are determined +by the value of the HISTSIZE variable. The value of first +or last or both are one of the following: +.TP 2 +[+]number +A positive number representing a command +number; command numbers can be displayed +with the -l option. +.TP 2 +-number +A negative decimal number representing the +command that was executed number of +commands previously. For example, -1 is +the immediately previous command. +.TP 2 +string +A string indicating the most recently +entered command that begins with that +string. If the old=new operand is not also +specified with -s, the string form of the +first operand cannot contain an embedded +equal sign. +.TP +The following environment variables affect the execution of fc: +.TP 2 +FCEDIT +Name of the editor to use. +.TP 2 +HISTSIZE +The number of previous commands that are accessable. +.RE +.TP +fg [ job ] +Move the specified job or the current job to the +foreground. +.TP +getopts optstring var +The POSIX getopts command. +The getopts command deprecates the older getopt command. +The first argument should be a series of letters, each possibly +followed by a colon which indicates that the option takes an argument. +The specified variable is set to the parsed option. The index of +the next argument is placed into the shell variable OPTIND. +If an option takes an argument, it is placed into the shell variable +OPTARG. If an invalid option is encountered, var is set to '?'. +It returns a false value (1) when it encounters the end of the options. +.TP +hash -rv command... +The shell maintains a hash table which remembers the +locations of commands. With no arguments whatsoever, +the hash command prints out the contents of this +table. Entries which have not been looked at since +the last cd command are marked with an asterisk; it +is possible for these entries to be invalid. +.sp +With arguments, the hash command removes the specified commands +from the hash table (unless they are +functions) and then locates them. With the -v +option, hash prints the locations of the commands as +it finds them. The -r option causes the hash command +to delete all the entries in the hash table except +for functions. +.TP +jobid [ job ] +Print the process id's of the processes in the job. +If the job argument is omitted, use the current job. +.TP +jobs +This command lists out all the background processes +which are children of the current shell process. +.TP +pwd +Print the current directory. The builtin command may +differ from the program of the same name because the +builtin command remembers what the current directory +is rather than recomputing it each time. This makes +it faster. However, if the current directory is +renamed, the builtin version of pwd will continue to +print the old name for the directory. +.TP +read [ -p prompt ] [ -e ] variable... +The prompt is printed if the -p option is specified +and the standard input is a terminal. Then a line is +read from the standard input. The trailing newline +is deleted from the line and the line is split as +described in the section on word splitting above, and +the pieces are assigned to the variables in order. +If there are more pieces than variables, the remaining +pieces (along with the characters in IFS that +separated them) are assigned to the last variable. +If there are more variables than pieces, the remaining +variables are assigned the null string. +.sp +The -e option causes any backslashes in the input to +be treated specially. If a backslash is followed by +a newline, the backslash and the newline will be +deleted. If a backslash is followed by any other +character, the backslash will be deleted and the following +character will be treated as though it were +not in IFS, even if it is. +.TP +readonly name... +The specified names are marked as read only, so that +they cannot be subsequently modified or unset. The shell +allows the value of a variable to be set at the same +time it is marked read only by writing +.TP +readonly name=value +With no arguments the readonly command lists the +names of all read only variables. +.TP +set [ { -options | +options | -- } ] arg... +The set command performs three different functions. +.sp +With no arguments, it lists the values of all shell +variables. +.sp +If options are given, it sets the specified option +flags, or clears them as described in the section +called ``Argument List Processing''. +.sp +The third use of the set command is to set the values +of the shell's positional parameters to the specified +args. To change the positional parameters without +changing any options, use ``--'' as the first argument +to set. If no args are present, the set command +will clear all the positional parameters (equivalent +to executing ``shift $#''. +.TP +setvar variable value +Assigns value to variable. (In general it is better +to write variable=value rather than using setvar. +Setvar is intended to be used in functions that +assign values to variables whose names are passed as +parameters.) +.TP +shift [ n ] +Shift the positional parameters n times. A shift +sets the value of $1 to the value of $2, the value of +$2 to the value of $3, and so on, decreasing the +value of $# by one. If there are zero positional +parameters, shifting doesn't do anything. +.TP +trap [ action ] signal... +Cause the shell to parse and execute action when any +of the specified signals are received. The signals +are specified by signal number. Action may be null +or omitted; the former causes the specified signal to +be ignored and the latter causes the default action +to be taken. When the shell forks off a subshell, it +resets trapped (but not ignored) signals to the +default action. The trap command has no effect on +signals that were ignored on entry to the shell. +.TP +type [name]... +Interpret each name as a command and print the +resolution of the command search. Possible resolutions are: +shell keyword, alias, shell builtin, command, tracked alias +and not found. For aliases the alias expansion is printed; +for commands and tracked aliases the complete pathname of +the command is printed. +.TP +ulimit [ -H | -S ] [ -a | -tfdscmlpn [ value ] ] +Inquire about or set the hard or soft limits on processes or +set new limits. +The choice between hard limit (which no process is allowed to +violate, and which may not be raised once it has been lowered) +and soft limit (which causes processes to be signalled but not +necessarily killed, and which may be raised) is made with these flags: +.RS +.5i +.TP 2 +-H set or inquire about hard limits +.TP 2 +-S set or inquire about soft limits +If neither -H nor -S +is specified, the soft limit is displayed or both limits are set. +If both are specified, the last one wins. +.LP 2 +The limit to be interrogated or set, then, is chosen by specifying +any one of these flags: +.TP 2 +-a +show all the current limits +.TP 2 +-t +show or set the limit on CPU time (in seconds) +.TP 2 +-f +show or set the limit on the largest file that can be created +(in 512-byte blocks) +.TP 2 +-d +show or set the limit on the data segment size of a process (in kilobytes) +.TP 2 +-s +show or set the limit on the stack size of a process (in kilobytes) +.TP 2 +-c +show or set the limit on the largest core dump size that can be produced +(in 512-byte blocks) +.TP 2 +-m +show or set the limit on the total physical memory that can be +in use by a process (in kilobytes) +.TP 2 +-l +show or set the limit on how much memory a process can lock with +.Xr mlock 2 +(in kilobytes) +.TP 2 +-p +show or set the limit on the number of processes this user can +have at one time +.TP 2 +-n +show or set the limit on the number files a process can have open at once +.LP 2 +If none of these is specified, it is the limit on file size +that is shown or set. +If value is specified, the limit is set to that number; +otherwise the current limit is displayed. +.RE +.TP +umask [ mask ] +Set the value of umask (see umask(2)) to the specified +octal value. If the argument is omitted, the +umask value is printed. +.TP +unalias [-a] [name] +If ``name'' is specified, the shell removes that alias. +If ``-a'' is specified, all aliases are removed. +.TP +unset name... +The specified variables and functions are unset and +unexported. If a given name corresponds to both a +variable and a function, both the variable and the +function are unset. +.TP +wait [ job ] +Wait for the specified job to complete and return the +exit status of the last process in the job. If the +argument is omitted, wait for all jobs to complete +and the return an exit status of zero. +.LP +.sp 2 +.B Command Line Editing +.sp +.LP +When sh is being used interactively from a terminal, the current command +and the command history (see fc in Builtins) can be edited using vi-mode +command-line editing. This mode uses commands, described below, similar +to a subset of those described in the vi man page. +The command set -o vi enables vi-mode editing and place sh into vi +insert mode. +With vi-mode enabled, sh can be switched between insert mode and command +mode. The editor is not described in full here, but will be in a later +document. It's similar to vi: typing <ESC> will throw you into +command VI command mode. Hitting <return> while in command mode +will pass the line to the shell. +.SH HISTORY +A +.I sh +command appeared in +Version 1 AT&T UNIX. +It was, however, unmaintainable so we wrote this one. diff --git a/release/picobsd/tinyware/ash/shell.h b/release/picobsd/tinyware/ash/shell.h new file mode 100644 index 0000000..95012d1e --- /dev/null +++ b/release/picobsd/tinyware/ash/shell.h @@ -0,0 +1,83 @@ +/* $NetBSD: shell.h,v 1.10 1996/10/16 15:21:49 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)shell.h 8.2 (Berkeley) 5/4/95 + */ + +/* + * The follow should be set to reflect the type of system you have: + * JOBS -> 1 if you have Berkeley job control, 0 otherwise. + * 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=2 to compile in and turn on debugging. + * + * When debugging is on, debugging info will be written to $HOME/trace and + * a quit signal will generate a core dump. + */ + + +#define JOBS 1 +#ifndef BSD +#define BSD 1 +#endif + +#ifdef __STDC__ +typedef void *pointer; +#ifndef NULL +#define NULL (void *)0 +#endif +#else /* not __STDC__ */ +typedef char *pointer; +#ifndef NULL +#define NULL 0 +#endif +#endif /* not __STDC__ */ +#define STATIC /* empty */ +#define MKINIT /* empty */ + +#include <sys/cdefs.h> + +extern char nullstr[1]; /* null string */ + + +#ifdef DEBUG +#define TRACE(param) trace param +#else +#define TRACE(param) +#endif diff --git a/release/picobsd/tinyware/ash/show.c b/release/picobsd/tinyware/ash/show.c new file mode 100644 index 0000000..4316645 --- /dev/null +++ b/release/picobsd/tinyware/ash/show.c @@ -0,0 +1,446 @@ +/* $NetBSD: show.c,v 1.15 1997/07/04 21:02:22 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.15 1997/07/04 21:02:22 christos Exp $"); +#endif +#endif /* not lint */ + +#include <stdio.h> +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#include "shell.h" +#include "parser.h" +#include "nodes.h" +#include "mystring.h" +#include "show.h" + + +#ifdef DEBUG +static void shtree __P((union node *, int, char *, FILE*)); +static void shcmd __P((union node *, FILE *)); +static void sharg __P((union node *, FILE *)); +static void indent __P((int, char *, FILE *)); +static void trstring __P((char *)); + + +void +showtree(n) + union node *n; +{ + trputs("showtree called\n"); + shtree(n, 1, NULL, stdout); +} + + +static void +shtree(n, ind, pfx, fp) + union node *n; + int ind; + char *pfx; + FILE *fp; +{ + struct nodelist *lp; + char *s; + + if (n == NULL) + return; + + indent(ind, pfx, fp); + switch(n->type) { + case NSEMI: + s = "; "; + goto binop; + case NAND: + s = " && "; + goto binop; + case NOR: + s = " || "; +binop: + shtree(n->nbinary.ch1, ind, NULL, fp); + /* if (ind < 0) */ + fputs(s, fp); + shtree(n->nbinary.ch2, ind, NULL, fp); + break; + case NCMD: + shcmd(n, fp); + if (ind >= 0) + putc('\n', fp); + break; + case NPIPE: + for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { + shcmd(lp->n, fp); + if (lp->next) + fputs(" | ", fp); + } + if (n->npipe.backgnd) + fputs(" &", fp); + if (ind >= 0) + putc('\n', fp); + break; + default: + fprintf(fp, "<node type %d>", n->type); + if (ind >= 0) + putc('\n', fp); + break; + } +} + + + +static void +shcmd(cmd, fp) + union node *cmd; + FILE *fp; +{ + union node *np; + int first; + char *s; + int dftfd; + + first = 1; + for (np = cmd->ncmd.args ; np ; np = np->narg.next) { + if (! first) + putchar(' '); + sharg(np, fp); + first = 0; + } + for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { + if (! first) + putchar(' '); + switch (np->nfile.type) { + case NTO: s = ">"; dftfd = 1; break; + case NAPPEND: s = ">>"; dftfd = 1; break; + case NTOFD: s = ">&"; dftfd = 1; break; + case NFROM: s = "<"; dftfd = 0; break; + case NFROMFD: s = "<&"; dftfd = 0; break; + default: s = "*error*"; dftfd = 0; break; + } + if (np->nfile.fd != dftfd) + fprintf(fp, "%d", np->nfile.fd); + fputs(s, fp); + if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { + fprintf(fp, "%d", np->ndup.dupfd); + } else { + sharg(np->nfile.fname, fp); + } + first = 0; + } +} + + + +static void +sharg(arg, fp) + union node *arg; + FILE *fp; + { + char *p; + struct nodelist *bqlist; + int subtype; + + if (arg->type != NARG) { + printf("<node type %d>\n", arg->type); + fflush(stdout); + abort(); + } + bqlist = arg->narg.backquote; + for (p = arg->narg.text ; *p ; p++) { + switch (*p) { + case CTLESC: + putc(*++p, fp); + break; + case CTLVAR: + putc('$', fp); + putc('{', fp); + subtype = *++p; + if (subtype == VSLENGTH) + putc('#', fp); + + while (*p != '=') + putc(*p++, fp); + + if (subtype & VSNUL) + putc(':', fp); + + switch (subtype & VSTYPE) { + case VSNORMAL: + putc('}', fp); + break; + case VSMINUS: + putc('-', fp); + break; + case VSPLUS: + putc('+', fp); + break; + case VSQUESTION: + putc('?', fp); + break; + case VSASSIGN: + putc('=', fp); + break; + case VSTRIMLEFT: + putc('#', fp); + break; + case VSTRIMLEFTMAX: + putc('#', fp); + putc('#', fp); + break; + case VSTRIMRIGHT: + putc('%', fp); + break; + case VSTRIMRIGHTMAX: + putc('%', fp); + putc('%', fp); + break; + case VSLENGTH: + break; + default: + printf("<subtype %d>", subtype); + } + break; + case CTLENDVAR: + putc('}', fp); + break; + case CTLBACKQ: + case CTLBACKQ|CTLQUOTE: + putc('$', fp); + putc('(', fp); + shtree(bqlist->n, -1, NULL, fp); + putc(')', fp); + break; + default: + putc(*p, fp); + break; + } + } +} + + +static void +indent(amount, pfx, fp) + int amount; + char *pfx; + FILE *fp; +{ + int i; + + for (i = 0 ; i < amount ; i++) { + if (pfx && i == amount - 1) + fputs(pfx, fp); + putc('\t', fp); + } +} +#endif + + + +/* + * Debugging stuff. + */ + + +FILE *tracefile; + +#if DEBUG == 2 +int debug = 1; +#else +int debug = 0; +#endif + + +#ifdef DEBUG +void +trputc(c) + int c; +{ + if (tracefile == NULL) + return; + putc(c, tracefile); + if (c == '\n') + fflush(tracefile); +} +#endif + +void +#ifdef __STDC__ +trace(const char *fmt, ...) +#else +trace(va_alist) + va_dcl +#endif +{ +#ifdef DEBUG + va_list va; +#ifdef __STDC__ + va_start(va, fmt); +#else + char *fmt; + va_start(va); + fmt = va_arg(va, char *); +#endif + if (tracefile != NULL) { + (void) vfprintf(tracefile, fmt, va); + if (strchr(fmt, '\n')) + (void) fflush(tracefile); + } + va_end(va); +#endif +} + + +#ifdef DEBUG +void +trputs(s) + char *s; +{ + if (tracefile == NULL) + return; + fputs(s, tracefile); + if (strchr(s, '\n')) + fflush(tracefile); +} + + +static void +trstring(s) + char *s; +{ + char *p; + char c; + + if (tracefile == NULL) + return; + putc('"', tracefile); + for (p = s ; *p ; p++) { + switch (*p) { + case '\n': c = 'n'; goto backslash; + case '\t': c = 't'; goto backslash; + case '\r': c = 'r'; goto backslash; + case '"': c = '"'; goto backslash; + case '\\': c = '\\'; goto backslash; + case CTLESC: c = 'e'; goto backslash; + case CTLVAR: c = 'v'; goto backslash; + case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; + case CTLBACKQ: c = 'q'; goto backslash; + case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; +backslash: putc('\\', tracefile); + putc(c, tracefile); + break; + default: + if (*p >= ' ' && *p <= '~') + putc(*p, tracefile); + else { + putc('\\', tracefile); + putc(*p >> 6 & 03, tracefile); + putc(*p >> 3 & 07, tracefile); + putc(*p & 07, tracefile); + } + break; + } + } + putc('"', tracefile); +} +#endif + + +void +trargs(ap) + char **ap; +{ +#ifdef DEBUG + if (tracefile == NULL) + return; + while (*ap) { + trstring(*ap++); + if (*ap) + putc(' ', tracefile); + else + putc('\n', tracefile); + } + fflush(tracefile); +#endif +} + + +#ifdef DEBUG +void +opentrace() { + char s[100]; + char *getenv(); +#ifdef O_APPEND + int flags; +#endif + + if (!debug) + return; +#ifdef not_this_way + { + char *p; + if ((p = getenv("HOME")) == NULL) { + if (geteuid() == 0) + p = "/"; + else + p = "/tmp"; + } + scopy(p, s); + strcat(s, "/trace"); + } +#else + scopy("./trace", s); +#endif /* not_this_way */ + if ((tracefile = fopen(s, "a")) == NULL) { + fprintf(stderr, "Can't open %s\n", s); + return; + } +#ifdef O_APPEND + if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) + fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); +#endif + fputs("\nTracing started.\n", tracefile); + fflush(tracefile); +} +#endif /* DEBUG */ diff --git a/release/picobsd/tinyware/ash/show.h b/release/picobsd/tinyware/ash/show.h new file mode 100644 index 0000000..03a6f6e --- /dev/null +++ b/release/picobsd/tinyware/ash/show.h @@ -0,0 +1,46 @@ +/* $NetBSD: show.h,v 1.3 1997/04/11 22:58:40 christos Exp $ */ + +/*- + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)show.h 1.1 (Berkeley) 5/4/95 + */ + +union node; +void showtree __P((union node *)); +void trace __P((const char *, ...)); +void trargs __P((char **)); +#ifdef DEBUG +void trputc __P((int)); +void trputs __P((char *)); +void opentrace __P((void)); +#endif diff --git a/release/picobsd/tinyware/ash/trap.c b/release/picobsd/tinyware/ash/trap.c new file mode 100644 index 0000000..dc5e1c8 --- /dev/null +++ b/release/picobsd/tinyware/ash/trap.c @@ -0,0 +1,383 @@ +/* $NetBSD: trap.c,v 1.17 1997/07/04 21:02:24 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.17 1997/07/04 21:02:24 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 "syntax.h" +#include "output.h" +#include "memalloc.h" +#include "error.h" +#include "trap.h" +#include "mystring.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 */ + + +extern char nullstr[1]; /* null string */ + +char *trap[NSIG+1]; /* trap handler commands */ +MKINIT char sigmode[NSIG]; /* current value of signal */ +char gotsig[NSIG]; /* indicates specified signal received */ +int pendingsigs; /* indicates some signal received */ + +static int getsigaction __P((int, sig_t *)); + +/* + * The trap builtin. + */ + +int +trapcmd(argc, argv) + int argc; + char **argv; +{ + char *action; + char **ap; + int signo; + + if (argc <= 1) { + for (signo = 0 ; signo <= NSIG ; signo++) { + if (trap[signo] != NULL) + out1fmt("%d: %s\n", signo, trap[signo]); + } + return 0; + } + ap = argv + 1; + if (is_number(*ap)) + action = NULL; + else + action = *ap++; + while (*ap) { + if ((signo = number(*ap)) < 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); + INTON; + ap++; + } + return 0; +} + + + +/* + * Clear traps on a fork. + */ + +void +clear_traps() { + char **tp; + + for (tp = trap ; tp <= &trap[NSIG] ; tp++) { + if (*tp && **tp) { /* trap not NULL or SIG_IGN */ + INTOFF; + ckfree(*tp); + *tp = NULL; + if (tp != &trap[0]) + setsignal(tp - trap); + INTON; + } + } +} + + + +/* + * Set the signal handler for the specified signal. The routine figures + * out what it should be set to. + */ + +long +setsignal(signo) + int signo; +{ + int action; + sig_t sigact = SIG_DFL; + char *t; + + if ((t = trap[signo]) == NULL) + action = S_DFL; + else if (*t != '\0') + action = S_CATCH; + else + action = S_IGN; + if (rootshell && action == S_DFL) { + switch (signo) { + case SIGINT: + if (iflag) + action = S_CATCH; + break; + case SIGQUIT: +#ifdef DEBUG + { + extern int 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]; + if (*t == 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) { + if (mflag && (signo == SIGTSTP || + signo == SIGTTIN || signo == SIGTTOU)) { + *t = S_IGN; /* don't hard ignore these */ + } else + *t = S_HARD_IGN; + } else { + *t = S_RESET; /* force to be set */ + } + } + if (*t == S_HARD_IGN || *t == 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; + } + *t = action; + return (long)signal(signo, sigact); +} + +/* + * Return the current setting for sig w/o changing it. + */ +static int +getsigaction(signo, sigact) + int signo; + sig_t *sigact; +{ + struct sigaction sa; + + if (sigaction(signo, (struct sigaction *)0, &sa) == -1) + return 0; + *sigact = (sig_t) sa.sa_handler; + return 1; +} + +/* + * Ignore a signal. + */ + +void +ignoresig(signo) + int signo; +{ + if (sigmode[signo - 1] != S_IGN && sigmode[signo - 1] != S_HARD_IGN) { + signal(signo, SIG_IGN); + } + sigmode[signo - 1] = S_HARD_IGN; +} + + +#ifdef mkinit +INCLUDE <signal.h> +INCLUDE "trap.h" + +SHELLPROC { + char *sm; + + clear_traps(); + for (sm = sigmode ; sm < sigmode + NSIG ; sm++) { + if (*sm == S_IGN) + *sm = S_HARD_IGN; + } +} +#endif + + + +/* + * Signal handler. + */ + +void +onsig(signo) + 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() { + 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]); + exitstatus=savestatus; + } +done: + pendingsigs = 0; +} + + + +/* + * Controls whether the shell is interactive or not. + */ + + +void +setinteractive(on) + int on; +{ + static int is_interactive; + + if (on == is_interactive) + return; + setsignal(SIGINT); + setsignal(SIGQUIT); + setsignal(SIGTERM); + is_interactive = on; +} + + + +/* + * Called to exit the shell. + */ + +void +exitshell(status) + int status; +{ + struct jmploc loc1, loc2; + char *p; + + TRACE(("exitshell(%d) pid=%d\n", status, getpid())); + if (setjmp(loc1.loc)) { + goto l1; + } + if (setjmp(loc2.loc)) { + goto l2; + } + handler = &loc1; + if ((p = trap[0]) != NULL && *p != '\0') { + trap[0] = NULL; + evalstring(p); + } +l1: handler = &loc2; /* probably unnecessary */ + flushall(); +#if JOBS + setjobctl(0); +#endif +l2: _exit(status); +} diff --git a/release/picobsd/tinyware/ash/trap.h b/release/picobsd/tinyware/ash/trap.h new file mode 100644 index 0000000..00ea79c --- /dev/null +++ b/release/picobsd/tinyware/ash/trap.h @@ -0,0 +1,50 @@ +/* $NetBSD: trap.h,v 1.11 1996/10/16 15:45:20 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)trap.h 8.3 (Berkeley) 6/5/95 + */ + +extern int pendingsigs; + +int trapcmd __P((int, char **)); +void clear_traps __P((void)); +long setsignal __P((int)); +void ignoresig __P((int)); +void onsig __P((int)); +void dotrap __P((void)); +void setinteractive __P((int)); +void exitshell __P((int)); diff --git a/release/picobsd/tinyware/ash/var.c b/release/picobsd/tinyware/ash/var.c new file mode 100644 index 0000000..7b8a1e7 --- /dev/null +++ b/release/picobsd/tinyware/ash/var.c @@ -0,0 +1,754 @@ +/* $NetBSD: var.c,v 1.19 1997/07/04 21:02:25 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#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.19 1997/07/04 21:02:25 christos Exp $"); +#endif +#endif /* not lint */ + +#include <unistd.h> +#include <stdlib.h> + +/* + * Shell variables. + */ + +#include "shell.h" +#include "output.h" +#include "expand.h" +#include "nodes.h" /* for other headers */ +#include "eval.h" /* defines cmdenviron */ +#include "exec.h" +#include "syntax.h" +#include "options.h" +#include "mail.h" +#include "var.h" +#include "memalloc.h" +#include "error.h" +#include "mystring.h" +#include "parser.h" +#ifndef SMALL +#include "myhistedit.h" +#endif + + +#define VTABSIZE 39 + + +struct varinit { + struct var *var; + int flags; + char *text; + void (*func) __P((const char *)); +}; + + +#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 vps1; +struct var vps2; +struct var vvers; +struct var voptind; + +const struct varinit varinit[] = { +#if ATTY + { &vatty, VSTRFIXED|VTEXTFIXED|VUNSET, "ATTY=", + NULL }, +#endif +#ifndef SMALL + { &vhistsize, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE=", + sethistsize }, +#endif + { &vifs, VSTRFIXED|VTEXTFIXED, "IFS= \t\n", + NULL }, + { &vmail, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL=", + NULL }, + { &vmpath, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH=", + NULL }, + { &vpath, VSTRFIXED|VTEXTFIXED, "PATH=/bin:/usr/bin", + changepath }, + /* + * vps1 depends on uid + */ + { &vps2, VSTRFIXED|VTEXTFIXED, "PS2=> ", + NULL }, +#ifndef SMALL + { &vterm, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM=", + setterm }, +#endif + { &voptind, VSTRFIXED|VTEXTFIXED, "OPTIND=1", + getoptsreset }, + { NULL, 0, NULL, + NULL } +}; + +struct var *vartab[VTABSIZE]; + +STATIC struct var **hashvar __P((char *)); +STATIC int varequal __P((char *, char *)); + +/* + * Initialize the varable symbol tables and import the environment + */ + +#ifdef mkinit +INCLUDE "var.h" +INIT { + char **envp; + extern char **environ; + + initvar(); + for (envp = environ ; *envp ; envp++) { + if (strchr(*envp, '=')) { + setvareq(*envp, VEXPORT|VTEXTFIXED); + } + } +} +#endif + + +/* + * This routine initializes the builtin variables. It is called when the + * shell is initialized and again when a shell procedure is spawned. + */ + +void +initvar() { + 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; + } + } + /* + * PS1 depends on uid + */ + if ((vps1.flags & VEXPORT) == 0) { + vpp = hashvar("PS1="); + vps1.next = *vpp; + *vpp = &vps1; + vps1.text = geteuid() ? "PS1=$ " : "PS1=# "; + vps1.flags = VSTRFIXED|VTEXTFIXED; + } +} + +/* + * Safe version of setvar, returns 1 on success 0 on failure. + */ + +int +setvarsafe(name, val, flags) + char *name, *val; + int flags; +{ + struct jmploc jmploc; + struct jmploc *volatile savehandler = handler; + int err = 0; +#ifdef __GNUC__ + (void) &err; +#endif + + if (setjmp(jmploc.loc)) + err = 1; + else { + handler = &jmploc; + setvar(name, val, flags); + } + handler = savehandler; + return err; +} + +/* + * Set the value of a variable. The flags argument is ored with the + * flags of the variable. If val is NULL, the variable is unset. + */ + +void +setvar(name, val, flags) + char *name, *val; + int flags; +{ + char *p, *q; + int len; + int namelen; + char *nameeq; + int isbad; + + isbad = 0; + p = name; + if (! is_name(*p)) + isbad = 1; + p++; + for (;;) { + if (! is_in_name(*p)) { + if (*p == '\0' || *p == '=') + break; + isbad = 1; + } + p++; + } + namelen = p - name; + if (isbad) + error("%.*s: bad variable name", namelen, name); + len = namelen + 2; /* 2 is space for '=' and '\0' */ + if (val == NULL) { + flags |= VUNSET; + } else { + len += strlen(val); + } + p = nameeq = ckmalloc(len); + q = name; + while (--namelen >= 0) + *p++ = *q++; + *p++ = '='; + *p = '\0'; + if (val) + scopy(val, p); + setvareq(nameeq, flags); +} + + + +/* + * Same as setvar except that the variable and value are passed in + * the first argument as name=value. Since the first argument will + * be actually stored in the table, it should not be a string that + * will go away. + */ + +void +setvareq(s, flags) + char *s; + int flags; +{ + struct var *vp, **vpp; + + vpp = hashvar(s); + for (vp = *vpp ; vp ; vp = vp->next) { + if (varequal(s, vp->text)) { + if (vp->flags & VREADONLY) { + size_t 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); + INTON; + return; + } + } + /* not found */ + vp = ckmalloc(sizeof (*vp)); + vp->flags = flags; + vp->text = s; + vp->next = *vpp; + vp->func = NULL; + *vpp = vp; +} + + + +/* + * Process a linked list of variable assignments. + */ + +void +listsetvar(list) + struct strlist *list; + { + struct strlist *lp; + + INTOFF; + for (lp = list ; lp ; lp = lp->next) { + setvareq(savestr(lp->text), 0); + } + INTON; +} + + + +/* + * Find the value of a variable. Returns NULL if not set. + */ + +char * +lookupvar(name) + 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; +} + + + +/* + * Search the environment of a builtin command. If the second argument + * is nonzero, return the value of a variable even if it hasn't been + * exported. + */ + +char * +bltinlookup(name, doall) + char *name; + int doall; +{ + struct strlist *sp; + struct var *v; + + for (sp = cmdenviron ; sp ; sp = sp->next) { + if (varequal(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; +} + + + +/* + * Generate a list of exported variables. This routine is used to construct + * the third argument to execve when executing a program. + */ + +char ** +environment() { + int nenv; + struct var **vpp; + struct var *vp; + char **env, **ep; + + nenv = 0; + for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { + for (vp = *vpp ; vp ; vp = vp->next) + if (vp->flags & VEXPORT) + nenv++; + } + ep = env = stalloc((nenv + 1) * sizeof *env); + for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { + for (vp = *vpp ; vp ; vp = vp->next) + if (vp->flags & VEXPORT) + *ep++ = vp->text; + } + *ep = NULL; + return env; +} + + +/* + * Called when a shell procedure is invoked to clear out nonexported + * variables. It is also necessary to reallocate variables of with + * VSTACK set since these are currently allocated on the stack. + */ + +#ifdef mkinit +MKINIT void shprocvar __P((void)); + +SHELLPROC { + shprocvar(); +} +#endif + +void +shprocvar() { + struct var **vpp; + struct var *vp, **prev; + + for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { + for (prev = vpp ; (vp = *prev) != NULL ; ) { + if ((vp->flags & VEXPORT) == 0) { + *prev = vp->next; + if ((vp->flags & VTEXTFIXED) == 0) + ckfree(vp->text); + if ((vp->flags & VSTRFIXED) == 0) + ckfree(vp); + } else { + if (vp->flags & VSTACK) { + vp->text = savestr(vp->text); + vp->flags &=~ VSTACK; + } + prev = &vp->next; + } + } + } + initvar(); +} + + + +/* + * Command to list all variables which are set. Currently this command + * is invoked from the set command when the set command is called without + * any variables. + */ + +int +showvarscmd(argc, argv) + int argc; + char **argv; +{ + struct var **vpp; + struct var *vp; + + for (vpp = vartab ; vpp < vartab + VTABSIZE ; vpp++) { + for (vp = *vpp ; vp ; vp = vp->next) { + if ((vp->flags & VUNSET) == 0) + out1fmt("%s\n", vp->text); + } + } + return 0; +} + + + +/* + * The export and readonly commands. + */ + +int +exportcmd(argc, argv) + int argc; + char **argv; +{ + struct var **vpp; + struct var *vp; + char *name; + char *p; + int flag = argv[0][0] == 'r'? VREADONLY : VEXPORT; + + listsetvar(cmdenviron); + if (argc > 1) { + 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; + 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) { + for (p = vp->text ; *p != '=' ; p++) + out1c(*p); + out1c('\n'); + } + } + } + } + return 0; +} + + +/* + * The "local" command. + */ + +int +localcmd(argc, argv) + int argc; + char **argv; +{ + char *name; + + if (! in_function()) + error("Not in a function"); + while ((name = *argptr++) != NULL) { + mklocal(name); + } + return 0; +} + + +/* + * Make a variable a local variable. When a variable is made local, it's + * 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(name) + char *name; + { + struct localvar *lvp; + struct var **vpp; + struct var *vp; + + INTOFF; + lvp = ckmalloc(sizeof (struct localvar)); + if (name[0] == '-' && name[1] == '\0') { + lvp->text = ckmalloc(sizeof optlist); + memcpy(lvp->text, optlist, sizeof optlist); + vp = NULL; + } else { + vpp = hashvar(name); + for (vp = *vpp ; vp && ! varequal(vp->text, name) ; vp = vp->next); + if (vp == NULL) { + if (strchr(name, '=')) + setvareq(savestr(name), VSTRFIXED); + else + setvar(name, NULL, VSTRFIXED); + vp = *vpp; /* the new variable */ + lvp->text = NULL; + lvp->flags = VUNSET; + } else { + lvp->text = vp->text; + lvp->flags = vp->flags; + vp->flags |= VSTRFIXED|VTEXTFIXED; + if (strchr(name, '=')) + setvareq(savestr(name), 0); + } + } + lvp->vp = vp; + lvp->next = localvars; + localvars = lvp; + INTON; +} + + +/* + * Called after a function returns. + */ + +void +poplocalvars() { + struct localvar *lvp; + struct var *vp; + + while ((lvp = localvars) != NULL) { + localvars = lvp->next; + vp = lvp->vp; + if (vp == NULL) { /* $- saved */ + memcpy(optlist, lvp->text, sizeof optlist); + ckfree(lvp->text); + } else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) { + (void)unsetvar(vp->text); + } else { + if ((vp->flags & VTEXTFIXED) == 0) + ckfree(vp->text); + vp->flags = lvp->flags; + vp->text = lvp->text; + } + ckfree(lvp); + } +} + + +int +setvarcmd(argc, argv) + int argc; + char **argv; +{ + if (argc <= 2) + return unsetcmd(argc, argv); + else if (argc == 3) + setvar(argv[1], argv[2], 0); + else + error("List assignment not implemented"); + return 0; +} + + +/* + * The unset builtin command. We unset the function before we unset the + * variable to allow a function to be unset when there is a readonly variable + * with the same name. + */ + +int +unsetcmd(argc, argv) + int argc; + char **argv; +{ + char **ap; + int i; + int flg_func = 0; + int flg_var = 0; + int ret = 0; + + while ((i = nextopt("vf")) != '\0') { + if (i == 'f') + flg_func = 1; + else + flg_var = 1; + } + if (flg_func == 0 && flg_var == 0) + flg_var = 1; + + for (ap = argptr; *ap ; ap++) { + if (flg_func) + ret |= unsetfunc(*ap); + if (flg_var) + ret |= unsetvar(*ap); + } + return ret; +} + + +/* + * Unset the specified variable. + */ + +int +unsetvar(s) + char *s; + { + struct var **vpp; + struct var *vp; + + vpp = hashvar(s); + for (vp = *vpp ; vp ; vpp = &vp->next, vp = *vpp) { + if (varequal(vp->text, s)) { + if (vp->flags & VREADONLY) + return (1); + INTOFF; + if (*(strchr(vp->text, '=') + 1) != '\0') + 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); + } + INTON; + return (0); + } + } + + return (1); +} + + + +/* + * Find the appropriate entry in the hash table from the name. + */ + +STATIC struct var ** +hashvar(p) + 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 + * either '=' or '\0'. + */ + +STATIC int +varequal(p, q) + char *p, *q; + { + while (*p == *q++) { + if (*p++ == '=') + return 1; + } + if (*p == '=' && *(q - 1) == '\0') + return 1; + return 0; +} diff --git a/release/picobsd/tinyware/ash/var.h b/release/picobsd/tinyware/ash/var.h new file mode 100644 index 0000000..15805ce --- /dev/null +++ b/release/picobsd/tinyware/ash/var.h @@ -0,0 +1,130 @@ +/* $NetBSD: var.h,v 1.14 1997/04/11 22:45:40 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)var.h 8.2 (Berkeley) 5/4/95 + */ + +/* + * Shell variables. + */ + +/* 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 VSTACK 0x10 /* text is allocated on the stack */ +#define VUNSET 0x20 /* the variable is not set */ +#define VNOFUNC 0x40 /* don't call the callback function */ + + +struct var { + struct var *next; /* next entry in hash list */ + int flags; /* flags are defined above */ + char *text; /* name=value */ + void (*func) __P((const char *)); + /* function to be called when */ + /* the variable gets set/unset */ +}; + + +struct localvar { + struct localvar *next; /* next local variable in list */ + struct var *vp; /* the variable that was made local */ + int flags; /* saved flags */ + char *text; /* saved text */ +}; + + +struct localvar *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 vps1; +extern struct var vps2; +#ifndef SMALL +extern struct var vterm; +extern struct var vtermcap; +extern struct var vhistsize; +#endif + +/* + * The following macros access the values of the above variables. + * They have to skip over the name. They return the null string + * for unset variables. + */ + +#define ifsval() (vifs.text + 4) +#define mailval() (vmail.text + 5) +#define mpathval() (vmpath.text + 9) +#define pathval() (vpath.text + 5) +#define ps1val() (vps1.text + 4) +#define ps2val() (vps2.text + 4) +#define optindval() (voptind.text + 7) +#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 __P((void)); +void setvar __P((char *, char *, int)); +void setvareq __P((char *, int)); +struct strlist; +void listsetvar __P((struct strlist *)); +char *lookupvar __P((char *)); +char *bltinlookup __P((char *, int)); +char **environment __P((void)); +void shprocvar __P((void)); +int showvarscmd __P((int, char **)); +int exportcmd __P((int, char **)); +int localcmd __P((int, char **)); +void mklocal __P((char *)); +void poplocalvars __P((void)); +int setvarcmd __P((int, char **)); +int unsetcmd __P((int, char **)); +int unsetvar __P((char *)); +int setvarsafe __P((char *, char *, int)); diff --git a/release/picobsd/tinyware/help/Makefile b/release/picobsd/tinyware/help/Makefile new file mode 100644 index 0000000..0b56779 --- /dev/null +++ b/release/picobsd/tinyware/help/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile,v 1.1.1.1 1998/07/14 07:30:53 abial Exp $ +# +PROG=help +SRCS+=help.c +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/help/README b/release/picobsd/tinyware/help/README new file mode 100644 index 0000000..8b86ba1 --- /dev/null +++ b/release/picobsd/tinyware/help/README @@ -0,0 +1,8 @@ +1998.02.20 + +This is work in progress. Eventually I'll prepare the help system for newbies, +and these files are just the beginning of it... + +<abial@nask.pl> + +$Id: README,v 1.1.1.1 1998/07/14 07:30:53 abial Exp $ diff --git a/release/picobsd/tinyware/help/help.c b/release/picobsd/tinyware/help/help.c new file mode 100644 index 0000000..fda11a6 --- /dev/null +++ b/release/picobsd/tinyware/help/help.c @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: help.c,v 1.1.1.1 1998/07/14 07:30:53 abial Exp $ + * + */ + + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <dirent.h> + +void +display(char *fname) +{ + FILE *fd; + DIR *dirp; + struct dirent *d; + char buf[100],junk[5],c, *dot; + int i; + + snprintf(buf,99,"/help/%s.hlp",fname); + if((fd=fopen(buf,"r"))==NULL) { + printf("No help available for '%s'.\n",fname); + exit(1); + } + printf("\n"); + i=0; + while(!feof(fd)) { + if(fgets(buf,99,fd)==NULL) continue; + if(i<23) { + printf("%s",buf); + i++; + } else { + printf("[7mPress Enter to continue[m"); + fgets(junk,5,stdin); + printf("%s",buf); + i=0; + } + } + printf("\n"); + i=0; + if(strcmp(fname,"help")==0) { + printf("The following help items are available:\n\n"); + dirp=opendir("/help/."); + while((d=readdir(dirp))!=NULL) { + if(d->d_name[0]=='.') continue; + if((dot=strchr(d->d_name,'.'))!=NULL) { + *dot='\0'; + } + printf("%-13s",d->d_name); + i++; + if(i>5) { + printf("\n"); + i=0; + } + } + closedir(dirp); + printf("\n"); + } + return; +} + + +int +main(int argc, char *argv[]) +{ + if(argc==1) { + display("help"); + } else { + display(argv[1]); + } + exit(0); +} diff --git a/release/picobsd/tinyware/kget/Makefile b/release/picobsd/tinyware/kget/Makefile new file mode 100644 index 0000000..a8029c0 --- /dev/null +++ b/release/picobsd/tinyware/kget/Makefile @@ -0,0 +1,11 @@ +# $Id: Makefile,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ +# +PROG=kget +CFLAGS+= -I/usr/src/sys -DUC_PRIVATE -DKERN_NO_SYMBOLS +SRCS= uc_isa.c uc_kmem.c uc_list.c uc_main.c uc_main.h \ + uc_eisa.c uc_pci.c uc_scsi.c +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/kget/README b/release/picobsd/tinyware/kget/README new file mode 100644 index 0000000..2acc5ea5 --- /dev/null +++ b/release/picobsd/tinyware/kget/README @@ -0,0 +1,47 @@ +1998.06.29 + +What is it? +----------- + +This utility is taken almost in its entirety from /stand/sysinstall. It allows +to gather device configuration which possibly was changed in userconfig (-c) +session, and to save it to /kernel.config file on startup floppy, so that when +user boots next time, the settings will automatically be changed. + +How can I use it? +----------------- + +The best way is to call it from /etc/rc in such phase when the startup floppy +is mounted, and redirect its output to /kernel.config on the floppy. + +NOTE: You need first to create symbols' list, using 'dumpnlist' utility, and +place it in /stand/symbols. + +Usage is straightforward: + + kget -incore|kernel_name output_filename [vanilla] + +In simplest form you can do + + kget -incore - + +to list current in core parameters, or + + kget kernel_file - + +to see settings of another kernel. + +or + + kget -incore - /stand/vanilla + +to produce list of changes from 'vanilla' configuration. You can redirect this +list to /kernel.config file with no changes - it already contains required +keywords. + +Credits go to Jordan K. Hubbard for 95% of this code. The rest is mine :-) + +Andrzej Bialecki +<abial@nask.pl> + +$Id: README,v 1.2 1998/08/11 06:53:21 abial Exp $ diff --git a/release/picobsd/tinyware/kget/kget.h b/release/picobsd/tinyware/kget/kget.h new file mode 100644 index 0000000..fc88782 --- /dev/null +++ b/release/picobsd/tinyware/kget/kget.h @@ -0,0 +1,2 @@ +#define SAFE_STRCPY strcpy +#define msgDebug printf diff --git a/release/picobsd/tinyware/kget/uc_eisa.c b/release/picobsd/tinyware/kget/uc_eisa.c new file mode 100644 index 0000000..aed003e --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_eisa.c @@ -0,0 +1,166 @@ +/*************************************************** + * file: userconfig/uc_eisa.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_eisa.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <nlist.h> +#include <i386/eisa/eisaconf.h> + +#include "uc_main.h" + +struct eisa_device_node { + struct eisa_device dev; + struct eisa_device_node *next; +}; + +/* module prototypes */ +static void eisa_fill_in(struct kernel *, struct uc_eisa *, struct eisa_device_node *); + +void +get_eisa_info(struct kernel *kp){ + int i, total; + u_int *ls; + struct eisa_driver *ed; + struct uc_eisa *ep, *epc; + char *name; + + if(kp->nl[EISA_SET].n_value || kp->nl[EISA_LIST].n_value) { + ep=epc=(struct uc_eisa *)malloc(sizeof(struct uc_eisa)); + if(!kp->incore) { + if(kp->nl[EISA_SET].n_value) { + u_int ndev; + ls=(u_int *)kv_to_u(kp, kp->nl[EISA_SET].n_value, sizeof(u_int)*10); /* XXX, size? */ + ndev=ls[0]; + for(i=1;i<(ndev+1);i++){ + ep=(struct uc_eisa *)realloc(ep, sizeof(struct uc_eisa)*i); + epc = ep+(i-1); + ed=(struct eisa_driver *)kv_to_u(kp, ls[i], sizeof(struct eisa_driver)); + name=(char *)kv_to_u(kp, (u_int)ed->name, 10); /* XXX, size? */ + asprintf(&epc->device, "%s", name); + asprintf(&epc->full_name, "?"); + } + ep=(struct uc_eisa *)realloc(ep, sizeof(struct uc_eisa)*i); + epc = ep+(i-1); + bzero(epc, sizeof(struct uc_eisa)); + kp->eisa_devp=ep; + } else { /* not incore and no symbol, we have no EISA devs... */ + kp->eisa_devp=(struct uc_eisa *)0; + } + } else { + /* if we're incore, we can get data from _eisa_dev_list, */ + /* which should be much more useful, but I'll need a machine */ + /* to test :( */ + if(kp->nl[EISA_LIST].n_value) { + u_int t; + struct eisa_device_node *edn; + + t=kv_dref_p(kp, kp->nl[EISA_LIST].n_value); + total=0; + while(t) { + edn=(struct eisa_device_node *) + kv_to_u(kp, t,sizeof(struct eisa_device_node)); + ep=(struct uc_eisa *)realloc(ep, sizeof(struct uc_eisa)*(total+1)); + epc=ep+total; + eisa_fill_in(kp, epc, edn); + t=(u_int)edn->next; + free(edn); + total++; + } + + ep=(struct uc_eisa *)realloc(ep, sizeof(struct uc_eisa)*(total+1)); + epc=ep+total; + bzero(epc, sizeof(struct uc_eisa)); + kp->eisa_devp=ep; + } else { + kp->eisa_devp=(struct uc_eisa *)0; + } + } + } else { + kp->eisa_devp=(struct uc_eisa *)0; + } +} + +struct list * +get_eisa_devlist(struct kernel *kp){ + struct list *dl; + struct uc_eisa *kdp; + + dl=list_new(); + + for(kdp=kp->eisa_devp; kdp->device; kdp++){ + list_append(dl, kdp->device); + } + return(dl); +} + + +struct list * +get_eisa_device(struct uc_eisa *ep){ + struct list *list; + list=list_new(); + + list_append(list, ep->device); + list_append(list, ep->full_name); + + return(list); +} + + +static void +eisa_fill_in(struct kernel *kp, struct uc_eisa *epc, struct eisa_device_node *edn){ + struct eisa_driver *edrv; + char *n; + + edrv=(struct eisa_driver *)kv_to_u(kp, (u_int)edn->dev.driver, + sizeof(struct eisa_driver)); + + n=(char *)kv_to_u(kp, (u_int)edrv->name, 20); + asprintf(&epc->device, "%s%d", n, edn->dev.unit); + free(n); + + n=(char *)kv_to_u(kp, (u_int)edn->dev.full_name, 40); /*XXX*/ + asprintf(&epc->full_name, "%s", n); + free(n); + free(edrv); +} + +void +eisa_free(struct kernel *kp, int writeback){ + struct uc_eisa *ep; + + for(ep=kp->eisa_devp;ep->device;ep++){ + free(ep->device); + free(ep->full_name); + } + free(kp->eisa_devp); + kp->eisa_devp=0; +} + +/* end of userconfig/uc_eisa.c */ diff --git a/release/picobsd/tinyware/kget/uc_isa.c b/release/picobsd/tinyware/kget/uc_isa.c new file mode 100644 index 0000000..b65e8d9 --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_isa.c @@ -0,0 +1,214 @@ +/*************************************************** + * file: userconfig/uc_isa.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_isa.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <nlist.h> +#include <i386/isa/isa_device.h> + +#include "uc_main.h" + +void +get_isa_info(struct kernel *kp){ + int total, i, j; + struct uc_isa *idp; + struct isa_device *p, *isa_dp; + struct isa_driver *drv; + char *name; + + if(kp->nl[ISA_BIOTAB].n_value || kp->nl[ISA_TTYTAB].n_value || kp->nl[ISA_NETTAB].n_value || + kp->nl[ISA_NULLTAB].n_value || kp->nl[ISA_WDCTAB].n_value || kp->nl[ISA_FDCTAB].n_value) { + + idp = kp->isa_devp = (struct uc_isa *)malloc(sizeof(struct uc_isa)); + total=0; /* a running total of the number of isa devices */ + + for (i=0; i<6; i++) { /* the isa devices */ + if(kp->nl[i].n_value) { + p = isa_dp = (struct isa_device *)kv_to_u(kp, kp->nl[i].n_value, /* XXX size? */ + sizeof(struct isa_device)*30); + /* build the device list */ + /* `total' keeps a running total of all the devices found */ + for (j=0; p->id_id; j++, p++, total++) { + kp->isa_devp = (struct uc_isa *)realloc(kp->isa_devp, + sizeof(struct uc_isa)*(total+1)); + idp=kp->isa_devp+total; + + drv=(struct isa_driver *)kv_to_u(kp, (u_int)p->id_driver, sizeof(struct isa_driver)); + name=(char *)kv_to_u(kp, (u_int)drv->name, 64); + + if (i==ISA_WDCTAB || i==ISA_FDCTAB) { /* special case the disk devices */ + char n[10]; + strncpy(n, name, 10); + n[strlen(n)-1]=0; /* chop off the trailing 'c' */ + asprintf(&idp->device, "%s%d", n, j); + } else { + asprintf(&idp->device, "%s%d", name, p->id_unit); + } + idp->port=p->id_iobase; + idp->irq=p->id_irq; + idp->drq=p->id_drq; + idp->iomem=(u_int)p->id_maddr & 0xFFFFFF; /* kludge to get pa from kva */ + idp->iosize=p->id_msize; + idp->flags=p->id_flags; + idp->alive=p->id_alive; + idp->enabled=p->id_enabled; + idp->modified=0; + if(!kp->incore){ + idp->idp=p; + } else { + free(name); + free(drv); + } + } + if(kp->incore){ + free(isa_dp); + } + } + } + + idp=kp->isa_devp+total; + bzero(idp, sizeof(struct uc_isa)); + } else { + kp->isa_devp=0; + } +} + + +struct list * +get_isa_devlist(struct kernel *kp){ + struct list *dl; + struct uc_isa *kdp; + + dl=list_new(); + + for(kdp=kp->isa_devp; kdp->device; kdp++){ + list_append(dl, kdp->device); + } + return(dl); +} + + +struct list * +get_isa_device(struct uc_isa *ip){ + struct list *list; + char *tmp; + + list=list_new(); + + asprintf(&tmp, "%s", ip->device ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "0x%04x", ip->port ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", ip->irq>0 ? ffs(ip->irq)-1 : ip->irq); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", ip->drq ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "0x%08x", ip->iomem ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "0x%x", ip->iosize ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "0x%x", ip->flags ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", ip->alive ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", ip->enabled ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", ip->modified ); + list_append(list, tmp); + free(tmp); + + return(list); +} + +int +isa_setdev(struct kernel *kp, struct list *list){ + int r=1, irq; + struct uc_isa *ip; + + if(kp->isa_devp) + for(ip=kp->isa_devp;ip->device;ip++){ + if(strcmp(list->av[0], ip->device)==0){ + ip->modified=1; + ip->port = strtol(list->av[1], (char **)NULL, 0); + irq=strtol(list->av[2], (char **)NULL, 0); + ip->irq= irq > 0 ? 1 << (irq) : irq; + ip->drq = strtol(list->av[3], (char **)NULL, 0); + ip->iomem = strtol(list->av[4], (char **)NULL, 0); + ip->iosize = strtol(list->av[5], (char **)NULL, 0); + ip->flags = strtol(list->av[6], (char **)NULL, 0); + ip->enabled = strtol(list->av[8], (char **)NULL, 0); + r=0; + break; + } + } + return(r); +} + +void +isa_free(struct kernel *kp, int writeback){ + struct uc_isa *ip; + for(ip=kp->isa_devp; ip->device; ip++){ + if((!kp->incore) && ip->modified && writeback) { + /* save any changes */ + ip->idp->id_iobase=ip->port; + ip->idp->id_irq = ip->irq; + ip->idp->id_drq = ip->drq; + ip->idp->id_maddr = (caddr_t)ip->iomem; + ip->idp->id_msize = ip->iosize; + ip->idp->id_flags = ip->flags; + ip->idp->id_enabled = ip->enabled; + } + /* and, be free... */ + free(ip->device); + } + /* and free the whole ball of wax */ + free(kp->isa_devp); + kp->isa_devp=0; +} + +/* end of userconfig/uc_isa.c */ diff --git a/release/picobsd/tinyware/kget/uc_kmem.c b/release/picobsd/tinyware/kget/uc_kmem.c new file mode 100644 index 0000000..38651e8 --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_kmem.c @@ -0,0 +1,87 @@ +/*************************************************** + * file: userconfig/uc_kmem.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_kmem.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <unistd.h> +#include <a.out.h> + +#include <stdio.h> + +#include "uc_main.h" + +/* translate a kv pointer to user space */ +/* malloc()-ing if we aren't mmaped */ +u_int +kv_to_u(struct kernel *kp, u_int adr, u_int size){ + u_int tadr; + if(!kp->incore){ + struct exec *ep; + ep=(struct exec *)kp->core; + tadr=(u_int)((adr - ep->a_entry + (N_DATOFF(*ep) - ep->a_text))+kp->core); + } else { + caddr_t ptr; + ptr = malloc(size); + lseek(kp->fd, adr, SEEK_SET); + read(kp->fd, ptr, size); + tadr=(u_int)ptr; + } + return(tadr); +} + +/* dereference a pointer to kernel space */ +u_int +kv_dref_p(struct kernel *kp, u_int adr){ + u_int tadr; + if(!kp->incore){ + struct exec *ep; + ep=(struct exec *)kp->core; + tadr=*(u_int*)((adr - ep->a_entry + (N_DATOFF(*ep) - ep->a_text))+kp->core); + } else { + lseek(kp->fd, adr, SEEK_SET); + read(kp->fd, &tadr, sizeof(tadr)); + } + return(tadr); +} + +/* deref a pointer to kernel text */ +u_int +kv_dref_t(struct kernel *kp, u_int adr){ + u_int tadr; + if(!kp->incore){ + struct exec *ep; + ep=(struct exec *)kp->core; + tadr=*(u_int*)((adr - ep->a_entry) + N_TXTOFF(*ep) + (u_int)kp->core); + } else { + lseek(kp->fd, adr, SEEK_SET); + read(kp->fd, &tadr, sizeof(tadr)); + } + return(tadr); +} + +/* end of userconfig/uc_kmem.c */ diff --git a/release/picobsd/tinyware/kget/uc_list.c b/release/picobsd/tinyware/kget/uc_list.c new file mode 100644 index 0000000..d0e5ac6 --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_list.c @@ -0,0 +1,76 @@ +/*************************************************** + * file: userconfig/uc_isa.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_list.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <nlist.h> +#include "uc_main.h" + +struct list * +list_new(void){ + struct list *rv; + rv=(struct list *)malloc(sizeof(struct list)); + rv->ac=0; + rv->av=(char **)0; + return(rv); +} + +void +list_append(struct list *list , char *item){ + + if(list->ac==0) { + list->av=(char **)malloc(sizeof(char *)*(list->ac+1)); + } else { + list->av=(char **)realloc(list->av, sizeof(char *)*(list->ac+1)); + } + asprintf(list->av+list->ac, "%s", item); + list->ac++; +} + +void +list_print(struct list *list, char *separator){ + int i; + for(i=0; i<list->ac; i++) + printf("%s%s", list->av[i], separator); +} + +void +list_destroy(struct list *list){ + int i; + for(i=0;i<list->ac;i++){ + free(list->av[i]); + list->av[i]=0; + } + free(list->av); + list->av=0; + free(list); +} + +/* end of userconfig/uc_list.c */ diff --git a/release/picobsd/tinyware/kget/uc_main.c b/release/picobsd/tinyware/kget/uc_main.c new file mode 100644 index 0000000..011f9df --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_main.c @@ -0,0 +1,466 @@ +/*************************************************** + * file: userconfig/uc_main.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * library functions for userconfig library + * + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <paths.h> +#include <sys/mman.h> +#include <nlist.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "uc_main.h" +#include "kget.h" + +FILE *f_out; + +static struct nlist _nl[] = { + {"_isa_devtab_bio"}, + {"_isa_devtab_tty"}, + {"_isa_devtab_net"}, + {"_isa_devtab_null"}, + {"_isa_biotab_wdc"}, + {"_isa_biotab_fdc"}, + {"_eisadriver_set"}, + {"_eisa_dev_list"}, + {"_pcidevice_set"}, + {"_device_list"}, + {"_scbusses"}, + {"_scsi_cinit"}, + {"_scsi_dinit"}, + {"_scsi_tinit"}, + {""}, +}; + +int +isDebug() { + return(0); +} + +struct list * +vc_getdev(char *vanilla) +{ + FILE *fd; + struct list *dl; + char buf[100]; + + fd=fopen(vanilla,"r"); + if(fd==NULL) { + printf("no such file: %s\n",vanilla); + exit(2); + } + dl=list_new(); + while(!feof(fd)) { + buf[0]='\0'; + if(fgets(buf,99,fd)==NULL) continue; + buf[strlen(buf)-1]='\0'; + list_append(dl,buf); + } + fclose(fd); + return(dl); +} + +void +process(struct list *d, struct list *v, int flag) +{ + int i,idx,found; + int len; + char *tok,*sep=" "; + char *parm[]= {"<devname>", + "port", + "irq", + "drq", + "iomem", + "iosize", + "flags", + "<alive>", + "<enabled>", + "<modified>"}; + + if(!flag) { + fprintf(f_out,"%s",d->av[0]); + for(i=1;i<d->ac;i++) { + fprintf(f_out," %s",d->av[i]); + } + fprintf(f_out,"\n"); + return; + } + found=0; + for(i=0;i<v->ac;i++) { + if(strncmp(d->av[0],v->av[i],strlen(d->av[0]))!=0) continue; + found++; + break; + } + if(!found) { + printf("\nWhoa!\n"); + printf("Couldn't find device %s in 'vanilla' list!\n", + d->av[0]); + printf("It seems that kernel image and 'vanilla' list are out of sync...\n"); + exit(2); + } + idx=i; + if(strcmp(d->av[8],"0")==0) { /* disable and return */ + fprintf(f_out,"disable %s\n",d->av[0]); + return; + } + tok=strtok(v->av[idx],sep); /* discard <name> */ + for(i=1;i<d->ac;i++) { + tok=strtok(NULL,sep); /* get next param from string */ + if(tok==NULL) { + fprintf(stderr,"Hmmm... strange error, please report!\n"); + fprintf(stderr,"Include the 'kget -incore' output and the device name (%s)\n",d->av[0]); + exit(10); + } + if(strcmp(d->av[i],tok)!=0) { /* changed */ + switch(i) { + case 7: /* alive */ + break; + case 8: /* enable/disable */ + if(strcmp(d->av[i],"0")==0) { /* disable */ + fprintf(f_out,"disable %s\n",d->av[0]); + return; + } else { + fprintf(f_out,"enable %s\n",d->av[0]); + } + break; + case 2: /* special case for npx */ + if(strcmp(d->av[0],"npx0")==0) continue; + /* FALLTHROUGH */ + default: + fprintf(f_out,"%s %s %s\n",parm[i],d->av[0],d->av[i]); + break; + } + } + } + return; +} + +int main(int argc, char *argv[]) +{ + struct kernel *core; + struct list *c_isa, *c_dev,*v_isa; + int d,j,cnt=0; + int diff=0; + char buf[100]; + + if(argc<3) { + printf("Usage: %s name|-incore -|filename [vanilla]\n",argv[0]); + exit(1); + } + if(argc>3) { + v_isa=vc_getdev(argv[3]); + diff++; + } + core=uc_open(argv[1]); + c_isa=uc_getdev(core,"-isa"); + if(c_isa==NULL) { + printf("no symbols in kernel?\n"); + exit(2); + } + if(strcmp(argv[2],"-")==NULL) { + f_out=stdout; + } else { + f_out=fopen(argv[2],"w"); + if(f_out==NULL) f_out=stdout; + } + if(diff) fprintf(f_out,"USERCONFIG\n"); + for(d=0;d<c_isa->ac;d++) { + c_dev=uc_getdev(core,c_isa->av[d]); + process(c_dev,v_isa,diff); + } + if(diff) fprintf(f_out,"quit\n"); + uc_close(core,0); + exit(0); +} + +struct kernel * +uc_open(char *name){ + int kd, flags, incore; + struct kernel *kern; + struct stat sb; + char kname[80]; + int size, i = 0; + struct nlist *nl = _nl; + + if (strcmp(name, "-incore") == 0) + incore = 1; + else + incore = 0; + + if (incore || (strcmp(name,"-bootfile") == 0)) + SAFE_STRCPY(kname, getbootfile()); + else + SAFE_STRCPY(kname, name); + + if (isDebug()) + msgDebug("uc_open: kernel name is %s, incore = %d\n", kname, incore); + kern = (struct kernel *)malloc(sizeof(struct kernel)); + +#ifdef KERN_NO_SYMBOLS + if (incore) { + FILE *fp; + + fp = fopen("/stand/symbols", "r"); + if (!fp) { + msgDebug("Couldn't open /stand/symbols file! Punting.\n"); + free(kern); + return NULL; + } + if (fscanf(fp, "%d\n", &size) != 1) { + msgDebug("Unable to get # of name list entries from symbol file.\n"); + free(kern); + return NULL; + } + else if (isDebug()) + msgDebug("uc_open: opened /stand/symbols file, reading %d entries.\n", size); + + + kern->nl = nl = (struct nlist *)malloc((size + 1) * sizeof(struct nlist)); + bzero(nl, (size + 1) * sizeof(struct nlist)); + for (i = 0; i < size; i++) { + char *cp, name[255]; + int c1; + unsigned int uc1; + short d1; + unsigned long v1; + + if (fgets(name, 255, fp) == NULL) { + msgDebug("Can't get name field for entry %d\n", i); + free(kern); + return NULL; + } + if ((cp = index(name, '\n')) != NULL) + *cp = '\0'; + nl[i].n_name = strdup(name); + if (fscanf(fp, "%u %d %hd %ld\n", &uc1, &c1, &d1, &v1) == 4) { + nl[i].n_type = (unsigned char)uc1; + nl[i].n_other = (char)c1; + nl[i].n_desc = d1; + nl[i].n_value = v1; + if (isDebug()) + msgDebug("uc_open: for entry %d, decoded: \"%s\", %u %d %hd %ld\n", i, nl[i].n_name, nl[i].n_type, nl[i].n_other, nl[i].n_desc, nl[i].n_value); + } + } + nl[i].n_name = ""; + fclose(fp); + i = 0; + } + else +#endif + i = nlist(kname, nl); + if (i == -1) { + msgDebug("uc_open: kernel %s does not contain symbols.\n", kname); + free(kern); + return NULL; + } +#ifdef KERN_NO_SYMBOLS + if (!incore) { +#else + { +#endif + kern->nl=(struct nlist *)malloc(sizeof(_nl)); + bcopy(_nl, kern->nl, sizeof(_nl)); + } + + if (incore) { + if (isDebug()) + msgDebug("uc_open: attempting to open /dev/kmem for incore.\n"); + if ((kd = open("/dev/kmem", O_RDONLY)) < 0) { + free(kern); + msgDebug("uc_open: Unable to open /dev/kmem.\n"); + return NULL; + } + kern->core = (caddr_t)NULL; + kern->incore = 1; + kern->size = 0; + } + else { + if (stat(kname, &sb) < 0) { + free(kern); + msgDebug("uc_open: Unable to stat %s.\n", kname); + return NULL; + } + kern->size = sb.st_size; + flags = sb.st_flags; + + if (chflags(kname, 0) < 0) { + free(kern); + msgDebug("uc_open: Unable to chflags %s.\n", kname); + return NULL; + } + + if (isDebug()) + msgDebug("uc_open: attempting to open %s\n", kname); + if ((kd = open(kname, O_RDWR, 0644)) < 0) { + free(kern); + msgDebug("uc_open: Unable to open %s.\n", kname); + return NULL; + } + + fchflags(kd, flags); + + if (isDebug()) + msgDebug("uc_open: attempting to mmap %d bytes\n", sb.st_size); + kern->core = mmap((caddr_t)0, sb.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, kd, 0); + kern->incore = 0; + if (kern->core == MAP_FAILED) { + free(kern); + msgDebug("uc_open: Unable to mmap from %s.\n", kname); + return NULL; + } + } + + kern->fd = kd; + get_isa_info(kern); + if (isDebug()) + msgDebug("uc_open: got isa information\n"); + + get_pci_info(kern); + if (isDebug()) + msgDebug("uc_open: got pci information\n"); + + get_eisa_info(kern); + if (isDebug()) + msgDebug("uc_open: got eisa information\n"); +#ifdef USE_SCSI + get_scsi_info(kern); + if (isDebug()) + msgDebug("uc_open: got scsi information\n"); +#else + kern->scsi_devp=(struct uc_scsi*)NULL; + kern->scsibus_devp=(struct uc_scsibus*)NULL; +#endif + return kern; +} + +int +uc_close(struct kernel *kern, int writeback) +{ + if (kern->isa_devp) + isa_free(kern, writeback); + + if (kern->eisa_devp) + eisa_free(kern, writeback); /* `writeback' isn't really useful here */ + + if (kern->pci_devp) + pci_free(kern, writeback); /* or here */ + + if (kern->scsi_devp) + scsi_free(kern, writeback); + + if (!kern->incore) + munmap(kern->core, kern->size); + + close(kern->fd); + free(kern->nl); + free(kern); + + return 0; +} + +struct list * +uc_getdev(struct kernel *kern, char *dev) +{ + struct list *list = (struct list *)0; + + if (*dev == '-') { /* asked for -isa, -eisa, -pci, -scsi, -all */ + if (strcmp(dev, "-all") == 0) { + list = list_new(); + if (kern->isa_devp) + list_append(list, "isa"); + + if (kern->eisa_devp) + list_append(list, "eisa"); + + if (kern->pci_devp) + list_append(list, "pci"); + + if (kern->scsi_devp) + list_append(list, "scsi"); + + } + else if (strcmp(dev, "-isa") == 0) + list = get_isa_devlist(kern); + else if (strcmp(dev, "-eisa") == 0) + list = get_eisa_devlist(kern); + else if (strcmp(dev, "-pci") == 0) + list = get_pci_devlist(kern); + else if (strcmp(dev, "-scsi") == 0) + list = get_scsi_devlist(kern); + } + else { + /* we gotta figure out which real device to report */ + struct uc_isa *ip; + struct uc_scsi *sp; + struct uc_pci *pp; + struct uc_eisa *ep; + + if (kern->isa_devp) { + for (ip = kern->isa_devp; ip->device; ip++) { + if (strcmp(dev, ip->device) == 0) { + list = get_isa_device(ip); + goto end; + } + } + } + + if (kern->scsi_devp) { + for (sp = kern->scsi_devp; sp->device; sp++) { + if (strcmp(dev, sp->device) == 0) { + list = get_scsi_device(sp); + goto end; + } + } + } + + if (kern->pci_devp) { + for(pp = kern->pci_devp; pp->device; pp++) { + if (strcmp(dev, pp->device) == 0) { + list = get_pci_device(pp); + goto end; + } + } + } + + if (kern->eisa_devp) { + for (ep = kern->eisa_devp; ep->device; ep++) { + if (strcmp(dev, ep->device) == 0) { + list = get_eisa_device(ep); + goto end; + } + } + } + } +end: + return(list); +} diff --git a/release/picobsd/tinyware/kget/uc_main.h b/release/picobsd/tinyware/kget/uc_main.h new file mode 100644 index 0000000..4f7662e --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_main.h @@ -0,0 +1,167 @@ +/*************************************************** + * file: userconfig/uc_main.h + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_main.h,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#define ISA_BIOTAB 0 +#define ISA_TTYTAB 1 +#define ISA_NETTAB 2 +#define ISA_NULLTAB 3 +#define ISA_WDCTAB 4 +#define ISA_FDCTAB 5 +#define EISA_SET 6 +#define EISA_LIST 7 +#define PCI_SET 8 +#define SCSI_LIST 9 +#define SCSI_BUSSES 10 +#define SCSI_CINIT 11 +#define SCSI_DINIT 12 +#define SCSI_TINIT 13 +/* symbols + the null terminator */ +#define NSYMBOLS 15 + +struct kernel { + int fd; /* file descriptor for the kernel image, either a binary or /dev/kmem */ + caddr_t core; /* either the mmap()ed kernel image, or a scratch area */ + u_int size; /* size of the object at ->core */ + int incore; /* true if the kernel is running */ +#ifdef UC_PRIVATE + struct nlist *nl; /* the symbol table */ +#else + void *nl; +#endif + struct uc_isa *isa_devp; /* pointer to the isa devices (if any) */ + struct uc_eisa *eisa_devp; /* pointer to the eisa devices (if any) */ + struct uc_pci *pci_devp; /* pointer to the pci devices (if any) */ + struct uc_scsi *scsi_devp; /* pointer to the scsi devices (if any) */ + struct uc_scsibus *scsibus_devp; /* internal pointer to scsibus wirings */ +}; + +struct uc_isa { + char *device; + u_short port; + u_short irq; + short drq; + u_int iomem; + int iosize; + int flags; + int alive; + int enabled; +#ifdef UC_PRIVATE + struct isa_device *idp; +#else + void *idp; +#endif + int modified; +}; + +struct uc_pci { + char *device; +}; + +struct uc_eisa { + char *device; + char *full_name; +}; + +struct uc_scsibus { + int bus_no; + int unit; + char *driver; +#ifdef UC_PRIVATE + struct scsi_ctlr_config *config; +#else + void *config; +#endif +}; + +struct uc_scsi { + char *device; + char *adapter; + u_short target; + u_short lun; + char *desc; +#ifdef UC_PRIVATE + struct scsi_device_config *config; +#else + void *config; +#endif + int modified; +}; + +/* nearly everything useful returns a list */ + +struct list { + int ac; + char **av; +}; + +/* prototypes */ + +/* uc_main.c */ +/* these are really the only public ones */ +struct kernel *uc_open(char *name); +int uc_close(struct kernel *kern, int writeback); +struct list *uc_getdev(struct kernel *kern, char *dev); + +/* uc_isa.c */ +void get_isa_info(struct kernel *kp); +struct list *get_isa_devlist(struct kernel *kp); +struct list *get_isa_device(struct uc_isa *ip); +int isa_setdev(struct kernel *kp, struct list *list); +void isa_free(struct kernel *kp, int writeback); + +/* uc_eisa.c */ +void get_eisa_info(struct kernel *kp); +struct list *get_eisa_devlist(struct kernel *kp); +struct list *get_eisa_device(struct uc_eisa *ep); +void eisa_free(struct kernel *kp, int writeback); + +/* uc_pci.c */ +void get_pci_info(struct kernel *kp); +struct list *get_pci_devlist(struct kernel *kp); +struct list *get_pci_device(struct uc_pci *pp); +void pci_free(struct kernel *kp, int writeback); + +/* uc_scsi.c */ +void get_scsi_info(struct kernel *kp); +struct list *get_scsi_devlist(struct kernel *kp); +struct list *get_scsi_device(struct uc_scsi *sp); +int scsi_setdev(struct kernel *kp, struct list *list); +void scsi_free(struct kernel *kp, int writeback); + +/* uc_kmem.c */ +u_int kv_to_u(struct kernel *kp, u_int adr, u_int size); +u_int kv_dref_p(struct kernel *kp, u_int adr); +u_int kv_dref_t(struct kernel *kp, u_int adr); + +/* uc_list.c */ +struct list *list_new(void); +void list_append(struct list *list, char *item); +void list_print(struct list *list, char *separator); +void list_destroy(struct list *list); + +/* end of userconfig/uc_main.h */ diff --git a/release/picobsd/tinyware/kget/uc_pci.c b/release/picobsd/tinyware/kget/uc_pci.c new file mode 100644 index 0000000..ca60790 --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_pci.c @@ -0,0 +1,122 @@ +/*************************************************** + * file: userconfig/uc_pci.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_pci.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <nlist.h> +#include <pci/pcivar.h> + +#include "uc_main.h" + +void +get_pci_info(struct kernel *kp){ + int i, total; + u_int *ls, ndev; + struct pci_device *pd; + struct uc_pci *pp,*ppc; + char *name; + + if(kp->nl[PCI_SET].n_value){ + pp = ppc = (struct uc_pci *)malloc(sizeof(struct uc_pci)); + ls=(u_int *)kv_to_u(kp, kp->nl[PCI_SET].n_value, sizeof(u_int)*30); /* XXX, size? */ + ndev=ls[0]; + total=0; + for(i=1;i<(ndev+1);i++){ + pp=(struct uc_pci *)realloc(pp, sizeof(struct uc_pci)*(total+1)); + ppc = pp+(total); + pd=(struct pci_device *)kv_to_u(kp, ls[i], sizeof(struct pci_device)); + /* don't try to dereference a null pointer */ + name=pd->pd_name ? (char *)kv_to_u(kp, (u_int)pd->pd_name, 10) : + pd->pd_name; /* XXX, size? */ + if(kp->incore){ + int u, k; + /* incore, we can get unit numbers */ + + u=kv_dref_p(kp, (u_int)pd->pd_count); + for(k=0;k<u;k++,total++){ + pp=(struct uc_pci *)realloc(pp, sizeof(struct uc_pci)*(total+1)); + ppc = pp+(total); + asprintf(&ppc->device, "%s%d", name, k); + } + free(pd); + if(name) + free(name); + } else { + asprintf(&ppc->device, "%s?", name); + total++; + } + } + pp=(struct uc_pci *)realloc(pp, sizeof(struct uc_pci)*(total+1)); + ppc = pp+(total); + bzero(ppc, sizeof(struct uc_pci)); + kp->pci_devp=pp; + } else { + kp->pci_devp=(struct uc_pci *)0; + } +} + + +struct list * +get_pci_devlist(struct kernel *kp){ + struct list *dl; + struct uc_pci *kdp; + + dl=list_new(); + + for(kdp=kp->pci_devp; kdp->device; kdp++){ + list_append(dl, kdp->device); + } + return(dl); +} + + +struct list * +get_pci_device(struct uc_pci *pp){ + struct list *list; + list=list_new(); + + list_append(list, pp->device); + + return(list); +} + +void +pci_free(struct kernel *kp, int writeback){ + struct uc_pci *pp; + + for(pp=kp->pci_devp;pp->device;pp++){ + free(pp->device); + } + free(kp->pci_devp); + kp->pci_devp=0; + +} + +/* end of userconfig/uc_pci.c */ diff --git a/release/picobsd/tinyware/kget/uc_scsi.c b/release/picobsd/tinyware/kget/uc_scsi.c new file mode 100644 index 0000000..5a539b0 --- /dev/null +++ b/release/picobsd/tinyware/kget/uc_scsi.c @@ -0,0 +1,477 @@ +/*************************************************** + * file: userconfig/uc_scsi.c + * + * Copyright (c) 1996 Eric L. Hernes (erich@rrnet.com) + * 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. The name of the author may not be used to endorse or promote products + * derived from this software withough 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. + * + * $Id: uc_scsi.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <nlist.h> +#include <scsi/scsiconf.h> + +#include "uc_main.h" + +/* this stuff is hidden under an #ifdef KERNEL in scsiconf.h */ +#define SCCONF_UNSPEC 255 +#define SCCONF_ANY 254 + +struct scsi_ctlr_config { + int scbus; + char *driver; + int unit; + int bus; +}; + +struct scsi_device_config { + char *name; /* SCSI device name (sd, st, etc) */ + int unit; /* desired device unit */ + int cunit; /* Controller unit */ + int target; /* SCSI ID (target) */ + int lun; /* SCSI lun */ + int flags; /* Flags from config */ +}; + +/* module prototypes */ +static void get_sl_info(struct kernel *kp, struct uc_scsi *spc, + struct scsi_link *sl); + +void +get_scsi_info(struct kernel *kp){ + int i, j, k; + + if(kp->incore){ + if (kp->nl[SCSI_BUSSES].n_value) { + u_int *es, *sba; + struct scsibus_data *sbd; + int nsbd, nscsibus, total; + struct uc_scsi *sp, *spc; + struct uc_scsibus *sbp, *sbpc; + struct scsi_link *s_l; + u_int *slp; + char *temp; + struct scsi_device *sdev; + u_int t; + char name[10]; + + sp=(struct uc_scsi*)malloc(sizeof(struct uc_scsi)); + total=0; + sbp=(struct uc_scsibus*)malloc(sizeof(struct uc_scsibus)); + nscsibus=0; + + es=(u_int *)kv_to_u(kp, kv_dref_p(kp,kp->nl[SCSI_BUSSES].n_value), + sizeof(u_int)*2); + nsbd=es[0]; + sba=(u_int *)kv_to_u(kp, es[1], sizeof(u_int)*nsbd); + free(es); + + for(i=0;i<nsbd;i++){ + if(sba[i]){ + /* first grab the adapter info */ + sbd=(struct scsibus_data *)kv_to_u(kp, sba[i], + sizeof(struct scsibus_data)); + sbp=(struct uc_scsibus *)realloc(sbp, sizeof(struct uc_scsibus)* + (nscsibus+1)); + + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + s_l=(struct scsi_link*)kv_to_u(kp, (u_int)sbd->adapter_link, + sizeof(struct scsi_link)); + get_sl_info(kp, spc, s_l); + free(s_l); + + sbpc=sbp+nscsibus; + sbpc->bus_no=nscsibus; + nscsibus++; + sscanf(spc->device, "%[a-z]%d", name, &sbpc->unit); + asprintf(&sbpc->driver, "%s", name); + + total++; + t=kv_dref_p(kp, (u_int)sbd->sc_link); + t=(u_int)sbd->sc_link; + for(j=0;j<8;j++) { + slp=(u_int *)kv_to_u(kp, t+(j*8*sizeof(u_int)), /* XXX */ + (sizeof(u_int)*sbd->maxlun)); + for(k=0;k<sbd->maxlun && slp[k]; k++){ + struct scsi_link *slt; + sp=(struct uc_scsi*)realloc(sp, + (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + slt=(struct scsi_link*)kv_to_u(kp, slp[k], + sizeof(struct scsi_link)); + get_sl_info(kp, spc, slt); + free(slt); + spc->config=(struct scsi_device_config *)0; + total++; + } + free(slp); + } + free(sbd); + } + } + /* now stuff in the list of drivers configured in the system */ + t=kv_dref_p(kp, kp->nl[SCSI_LIST].n_value); + while(t) { + sdev=(struct scsi_device*)kv_to_u(kp, t, sizeof(struct scsi_device)); + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + total++; + temp=(char *)kv_to_u(kp, (u_int)sdev->name, 10); + asprintf(&spc->device, "%s*", temp); + free(temp); + asprintf(&spc->adapter, "any"); + + spc->target=SCCONF_ANY; + spc->lun=SCCONF_ANY; + + temp=(char *)kv_to_u(kp, (u_int)sdev->desc, 20); + asprintf(&spc->desc, "%s", temp); + free(temp); + + spc->config=(struct scsi_device_config *)0; + + t=(u_int)sdev->next; + free(sdev); + } + /* slap on the terminators */ + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + bzero(spc, sizeof(struct uc_scsi)); + + sbp=(struct uc_scsibus *)realloc(sbp, sizeof(struct uc_scsibus)* + (nscsibus+1)); + sbpc=sbp+nscsibus; + bzero(sbpc, sizeof(struct uc_scsibus)); + + kp->scsi_devp=sp; + kp->scsibus_devp=sbp; + } else { /* no symbol, and incore, no scsi */ + kp->scsi_devp=(struct uc_scsi *)0; + kp->scsibus_devp=(struct uc_scsibus *)0; + } + } else { /* on disk */ + + if (kp->nl[SCSI_CINIT].n_value || kp->nl[SCSI_DINIT].n_value || + kp->nl[SCSI_TINIT].n_value) { + int total=0; + struct uc_scsi *sp, *spc; + struct scsi_ctlr_config *sctl_c; + struct scsi_device_config *sdev_c; + struct scsi_device *sdev; + + struct uc_scsibus *uc_scbus, *uc_scbusc; + + u_int t, ctrl_total; + char *temp; + u_int initp; + + spc=sp=(struct uc_scsi*)malloc(sizeof(struct uc_scsi)); + total=0; + ctrl_total=0; + uc_scbus = NULL; /* Just prevent unused warning */ + + /* static kernel, we'll first get the wired controllers/devices */ + if((t=kp->nl[SCSI_CINIT].n_value)){ + /* get controller info*/ + sctl_c=(struct scsi_ctlr_config*)kv_to_u(kp, t, sizeof(struct scsi_ctlr_config)); + uc_scbus=(struct uc_scsibus*)malloc(sizeof(struct uc_scsibus)); + + while(sctl_c->driver){ + + /* remember the bus info, for later */ + uc_scbus=(struct uc_scsibus*)realloc(uc_scbus, sizeof(struct uc_scsibus)*(ctrl_total+1)); + uc_scbusc=uc_scbus+ctrl_total; + uc_scbusc->bus_no=sctl_c->scbus; + temp=(char *)kv_to_u(kp, (u_int)sctl_c->driver, 20); + uc_scbusc->driver=temp; + uc_scbusc->unit=sctl_c->unit; + uc_scbusc->config=sctl_c; + + sp=(struct uc_scsi*)realloc(sp,sizeof(struct uc_scsi)*(total+1)); + spc=sp+total; + asprintf(&spc->device, "%s%d", temp, sctl_c->unit); + asprintf(&spc->adapter, "%s%d", temp, sctl_c->unit); + spc->target=0; + spc->lun=0; + spc->modified=0; + asprintf(&spc->desc, "%s", temp); + total++; + ctrl_total++; + sctl_c++; + } + } + + if((t=kp->nl[SCSI_DINIT].n_value)){ + /* get wired device info */ + sdev_c=(struct scsi_device_config*)kv_to_u(kp, t, sizeof(struct scsi_device_config)); + while(sdev_c->name){ + sp=(struct uc_scsi*)realloc(sp, sizeof(struct uc_scsi)*(total+1)); + spc=sp+total; + temp=(char*)kv_to_u(kp, (u_int)sdev_c->name, 10); + asprintf(&spc->device, "%s%d", temp, sdev_c->unit); + /* figure out controller */ + if(sdev_c->cunit == SCCONF_ANY){ + asprintf(&spc->adapter, "any"); + } else { + if(ctrl_total){ + for(i=0;i<ctrl_total;i++){ + if(sdev_c->cunit==uc_scbus[i].bus_no){ + asprintf(&spc->adapter, "%s%d", + uc_scbus[i].driver, uc_scbus[i].unit); + break; + } + } + if(i==ctrl_total) { /* made it through the whole list */ + asprintf(&spc->adapter, "any?"); + } + } else { + asprintf(&spc->adapter, "any?"); + } + } + spc->target= sdev_c->target; + spc->lun= sdev_c->lun; + spc->desc=(char *)0; /* filled in later */ + spc->config=sdev_c; + spc->modified=0; + sdev_c++; + total++; + } + } + kp->scsibus_devp=uc_scbus; + + if((t=kp->nl[SCSI_TINIT].n_value)) { + /* WARNING: This is teetering on the brink of stupid. + + this ugly little hack only works because the + <scsi driver>init routines are macro-generated, + so the offset of the device pointers will be + the same (hopefully). + */ + + while((initp=kv_dref_p(kp,t))) { + u_int tadr; + u_int sl; + + t+=4; + tadr=kv_dref_t(kp, initp+4); /* offset in *.text* */ + sdev=(struct scsi_device*)kv_to_u(kp, tadr, sizeof(struct scsi_device)); + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + total++; + temp=(char *)kv_to_u(kp, (u_int)sdev->name, 10); + asprintf(&spc->device, "%s*", temp); + + asprintf(&spc->adapter, "any"); + + spc->target=SCCONF_ANY; + spc->lun=SCCONF_ANY; + spc->modified=0; + temp=(char *)kv_to_u(kp, (u_int)sdev->desc, 20); + asprintf(&spc->desc, "%s", temp); + /* now try to fill in any device descriptions from above */ + sl=strlen(spc->device)-1; + for(i=0;i<(total-1);i++){ /* don't look at this device */ + struct uc_scsi *usp; + + usp=sp+i; + if(strncmp(usp->device, spc->device, sl)==0 && usp->desc==0) { + asprintf(&usp->desc, "%s", spc->desc); + } + } + } + if(total){ + sp=(struct uc_scsi*)realloc(sp, (sizeof(struct uc_scsi)*(total+1))); + spc=sp+total; + bzero(spc, sizeof(struct uc_scsi)); + kp->scsi_devp=sp; + } else { + free(sp); + kp->scsi_devp=(struct uc_scsi *)0; + } + } + } else { + kp->scsi_devp=(struct uc_scsi *)0; + } + } +} + +struct list * +get_scsi_devlist(struct kernel *kp){ + struct list *dl; + struct uc_scsi *kdp; + + dl=list_new(); + + for(kdp=kp->scsi_devp; kdp->device; kdp++){ + list_append(dl, kdp->device); + } + + return(dl); +} + +struct list * +get_scsi_device(struct uc_scsi *sp){ + struct list *list; + char *tmp; + + list=list_new(); + + list_append(list, sp->device); + list_append(list, sp->adapter); + + asprintf(&tmp, "%d", sp->target ); + list_append(list, tmp); + free(tmp); + + asprintf(&tmp, "%d", sp->lun ); + list_append(list, tmp); + free(tmp); + + list_append(list, sp->desc); + + return(list); +} + +/* given a scsi_link and a uc_scsi pointer, fill it in */ +static void +get_sl_info(struct kernel *kp, struct uc_scsi *spc, struct scsi_link *sl){ + + struct scsi_adapter *sadp; + struct scsi_device *sdev; + char *temp; + + sadp=(struct scsi_adapter*)kv_to_u(kp, (u_int)sl->adapter, + sizeof(struct scsi_adapter)); + + sdev=(struct scsi_device*)kv_to_u(kp, (u_int)sl->device, + sizeof(struct scsi_device)); + + temp=(char *)kv_to_u(kp, (u_int)sdev->name, 20); + asprintf(&spc->device, "%s%d", temp, sl->dev_unit); + free(temp); + temp=(char *)kv_to_u(kp, (u_int)sadp->name, 20); + asprintf(&spc->adapter, "%s%d", temp, sl->adapter_unit); + free(temp); + spc->target = sl->target; + spc->lun = sl->lun; + + temp=(char *)kv_to_u(kp, (u_int)sdev->desc, 30); + asprintf(&spc->desc, "%s", temp); + free(temp); + +} + +int +scsi_setdev(struct kernel *kp, struct list *list){ + int r=1, bus_valid=0; + struct uc_scsi *sp; + struct uc_scsibus *sbp; + char *t; + + if(kp->scsi_devp) + for(sp=kp->scsi_devp;sp->device;sp++){ + if(strcmp(list->av[0], sp->device)==0){ + for(sbp=kp->scsibus_devp;sbp->driver; sbp++){ + asprintf(&t, "%s%d", sbp->driver, sbp->unit); + if(strcmp(list->av[1], t)==0) { + bus_valid=1; + } + free(t); + } + if(bus_valid){ + sp->modified=1; + free(sp->adapter); + asprintf(&sp->adapter, "%s", list->av[1]); + sp->target = strtol(list->av[2], (char **)NULL, 0); + sp->lun = strtol(list->av[3], (char **)NULL, 0); + r=0; + goto done; + } else { + r=2; + } + } + } +done: + return(r); +} + +void +scsi_free(struct kernel *kp, int writeback){ + struct uc_scsi *sp; + struct uc_scsibus *sbp; + char *t; + int scbus, i; + + for(sp=kp->scsi_devp; sp->device; sp++){ + if((!kp->incore) && sp->modified && writeback) { + /* save info */ + + /* I'm not sure this is necessary */ +#if 0 + sscanf(sp->device, "%[a-z]%d", name, &unit); + sp->config->unit= unit; +#endif + + /* figger out the controller, which may have changed */ + scbus=-1; + for(sbp=kp->scsibus_devp, i=0;sbp->driver; sbp++,i++){ + asprintf(&t, "%s%d", sbp->driver, sbp->unit); + if(strcmp(sp->adapter, t)==0) { + scbus=i; + } + free(t); + } + + /* if we fell through, don't change anything */ + if(scbus!=-1){ + sp->config->cunit= scbus; + } + + sp->config->target= sp->target; + sp->config->lun= sp->lun; + /* sp->config->flags= ; XXX this should be here*/ + + } + free(sp->device); + free(sp->adapter); + free(sp->desc); + } + free(kp->scsi_devp); + kp->scsi_devp=(struct uc_scsi *)0; + /* now free the bus info */ + if(kp->incore){ + for(sbp=kp->scsibus_devp;sbp->driver; sbp++){ +/* fprintf(stderr, "sbp: 0x%x free(0x%x)\n", sbp, sbp->driver);*/ + free(sbp->driver); + } + } + + if (kp->scsibus_devp) + free(kp->scsibus_devp); + kp->scsibus_devp=(struct uc_scsibus *)0; +} + +/* end of userconfig/uc_scsi.c */ diff --git a/release/picobsd/tinyware/ns/Makefile b/release/picobsd/tinyware/ns/Makefile new file mode 100644 index 0000000..b75d813 --- /dev/null +++ b/release/picobsd/tinyware/ns/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile,v 1.1 1998/08/01 18:26:02 abial Exp $ +# +PROG=ns +SRCS= ns.c +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/ns/README b/release/picobsd/tinyware/ns/README new file mode 100644 index 0000000..d81bcd7 --- /dev/null +++ b/release/picobsd/tinyware/ns/README @@ -0,0 +1,41 @@ +Warsaw, 1998.07.20 + + Small replacement for netstat + ----------------------------- + +This program implements some basic functionality subset of normal netstat - +it can display the routing table and protocol statistics. + +Large part of the code dealing with retrieving the routing table via sysctl(3) +was taken from code examples written by Richard Stevens to accompany his +excellent book. + +Usage +----- + + ns [-r] [-s [-p ip|tcp|udp|icmp]] + +where + + -r print routing table (default) + -s print protocol statistics + Options: + -p proto display only statistics related to this + protocol, where 'proto' is one of: + - ip + - tcp + - udp + - icmp + +Bugs +---- + +* The link layer information is still missing. +* 'ns' doesn't resolve IP adresses to names +* well, real netstat provides _much_ more information... but this one needs + to be small, right? :-) + +Andrzej Bialecki +<abial@nask.pl> + +$Id: README,v 1.1 1998/08/19 17:21:50 abial Exp $ diff --git a/release/picobsd/tinyware/ns/ns.c b/release/picobsd/tinyware/ns/ns.c new file mode 100644 index 0000000..6ec15d3 --- /dev/null +++ b/release/picobsd/tinyware/ns/ns.c @@ -0,0 +1,628 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: ns.c,v 1.2 1998/08/09 18:52:07 abial Exp $ + */ + + +/* + * Small replacement for netstat. Uses only sysctl(3) to get the info. + */ + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <err.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/sysctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in_systm.h> +#include <netinet/in.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp_var.h> +#include <netinet/ip_var.h> +#include <netinet/tcp.h> +#include <netinet/tcp_timer.h> +#include <netinet/tcp_var.h> +#include <netinet/udp.h> +#include <netinet/udp_var.h> +#include <net/route.h> +#include <net/if_dl.h> +#include <sys/un.h> + +char *progname; +int rflag=1; /* print routing by default */ +int sflag=0; +int pflag=0; + +extern char *optarg; +extern int optind; + +void +usage() +{ + fprintf(stderr,"\n%s [-r | -s] [-p proto]\n",progname); + fprintf(stderr," proto: {ip|tcp|udp|icmp}\n\n"); +} + +int if_num; + +/* + * The following parts related to retrieving the routing table and + * interface information, were borrowed from R. Stevens' code examples + * accompanying his excellent book. Thanks! + */ + +char * +sock_ntop(const struct sockaddr *sa, size_t salen) +{ + char portstr[7]; + static char str[128]; /* Unix domain is largest */ + + switch (sa->sa_family) { + case 255: { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + int i; + + i=0; + while(sin->sin_addr.s_addr & (0x800000>>i)) i++; + sprintf(str,"/%d",i); + return(str); + } + case AF_UNSPEC: + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *) sa; + + if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str)) == NULL) + return(NULL); + if (ntohs(sin->sin_port)!=0) { + snprintf(portstr, sizeof(portstr), ".%d", ntohs(sin->sin_port)); + strcat(str, portstr); + } + if(strcmp(str,"0.0.0.0")==0) sprintf(str,"default"); + return(str); + } + case AF_UNIX: { + struct sockaddr_un *unp = (struct sockaddr_un *) sa; + + /* OK to have no pathname bound to the socket: happens on + every connect() unless client calls bind() first. */ + if (unp->sun_path[0] == 0) + strcpy(str, "(no pathname bound)"); + else + snprintf(str, sizeof(str), "%s", unp->sun_path); + return(str); + } + case AF_LINK: { + struct sockaddr_dl *sdl = (struct sockaddr_dl *) sa; + + if (sdl->sdl_nlen > 0) + snprintf(str, sizeof(str), "%*s", + sdl->sdl_nlen, &sdl->sdl_data[0]); + else + snprintf(str, sizeof(str), "link#%d", sdl->sdl_index); + return(str); + } + default: + snprintf(str, sizeof(str), "sock_ntop: unknown AF_xxx: %d, len %d", + sa->sa_family, salen); + return(str); + } + return (NULL); +} + +char * +Sock_ntop(const struct sockaddr *sa, size_t salen) +{ + char *ptr; + + if ( (ptr = sock_ntop(sa, salen)) == NULL) + err(1,"sock_ntop error"); /* inet_ntop() sets errno */ + return(ptr); +} + + +#define ROUNDUP(a,size) (((a) & ((size)-1))?(1+((a)|((size)-1))):(a)) + +#define NEXT_SA(ap) ap=(struct sockaddr *) \ + ((caddr_t)ap+(ap->sa_len?ROUNDUP(ap->sa_len,sizeof(u_long)):\ + sizeof(u_long))) + +void +get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) +{ + int i; + + for(i=0;i<RTAX_MAX;i++) { + if(addrs &(1<<i)) { + rti_info[i]=sa; + NEXT_SA(sa); + } else + rti_info[i]=NULL; + } +} + +void +get_flags(char *buf, int flags) +{ + if(flags & 0x1) { + strcat(buf,"U"); + } + if(flags & 0x2) { + strcat(buf,"G"); + } + if(flags & 0x4) { + strcat(buf,"H"); + } + if(flags & 0x8) { + strcat(buf,"r"); + } + if(flags & 0x10) { + strcat(buf,"d"); + } + /* + if(flags & 0x20) { + strcat(buf,"mod,"); + } + */ + if(flags & 0x100) { + strcat(buf,"C"); + } + if(flags & 0x400) { + strcat(buf,"L"); + } + if(flags & 0x800) { + strcat(buf,"S"); + } + if(flags & 0x10000) { + strcat(buf,"c"); + } + if(flags & 0x20000) { + strcat(buf,"W"); + } + /* + if(flags & 0x200000) { + strcat(buf,",LOC"); + } + */ + if(flags & 0x400000) { + strcat(buf,"b"); + } + /* + if(flags & 0x800000) { + strcat(buf,",MCA"); + } + */ +} + +int +routing(char *proto) +{ + int mib[6],i=0,rt_len,if_len; + char *rt_buf,*if_buf,*next,*lim; + struct rt_msghdr *rtm; + struct if_msghdr *ifm,**ifm_table; + struct ifa_msghdr *ifam; + struct sockaddr *sa,*sa1,*rti_info[RTAX_MAX],**if_table; + struct rt_metrics rm; + char fbuf[50]; + + /* Get the routing table */ + mib[0]=CTL_NET; + mib[1]=PF_ROUTE; + mib[2]=0; + mib[3]=0; + mib[4]=NET_RT_DUMP; + mib[5]=0; + /* Estimate the size of table */ + if(sysctl(mib,6,NULL,&rt_len,NULL,0)==-1) { + perror("sysctl size"); + exit(-1); + } + if((rt_buf=(char *)malloc(rt_len))==NULL) { + perror("malloc"); + exit(-1); + } + /* Now get it. */ + if(sysctl(mib,6,rt_buf,&rt_len,NULL,0)==-1) { + perror("sysctl get"); + exit(-1); + } + /* Get the interfaces table */ + mib[0]=CTL_NET; + mib[1]=PF_ROUTE; + mib[2]=0; + mib[3]=0; + mib[4]=NET_RT_IFLIST; + mib[5]=0; + /* Estimate the size of table */ + if(sysctl(mib,6,NULL,&if_len,NULL,0)==-1) { + perror("sysctl size"); + exit(-1); + } + if((if_buf=(char *)malloc(if_len))==NULL) { + perror("malloc"); + exit(-1); + } + /* Now get it. */ + if(sysctl(mib,6,if_buf,&if_len,NULL,0)==-1) { + perror("sysctl get"); + exit(-1); + } + lim=if_buf+if_len; + i=0; + for(next=if_buf,i=0;next<lim;next+=ifm->ifm_msglen) { + ifm=(struct if_msghdr *)next; + i++; + } + if_num=i; + if_table=(struct sockaddr **)malloc(i*sizeof(struct sockaddr)); + ifm_table=(struct if_msghdr **)malloc(i*sizeof(struct if_msghdr)); + memset(ifm_table,0,sizeof(ifm_table)); + i=0; + for(next=if_buf;next<lim;next+=ifm->ifm_msglen) { + ifm=(struct if_msghdr *)next; + if_table[i]=(struct sockaddr *)(ifm+1); + ifm_table[i]=ifm; + i++; + } + /* Now dump the routing table */ + printf("\nRouting table:\n"); + printf("--------------\n"); + printf("Destination Gateway Flags Netif Use\n"); + lim=rt_buf+rt_len; + for(next=rt_buf;next<lim;next+=rtm->rtm_msglen) { + rtm=(struct rt_msghdr *)next; + sa=(struct sockaddr *)(rtm+1); + get_rtaddrs(rtm->rtm_addrs,sa,rti_info); + if(rtm->rtm_flags & RTF_WASCLONED) { + if((rtm->rtm_flags & RTF_LLINFO)==0)continue; + } + if((sa=rti_info[RTAX_DST])!=NULL) { + sprintf(fbuf,"%s",sock_ntop(sa,sa->sa_len)); + if(((sa1=rti_info[RTAX_NETMASK])!=NULL) && sa1->sa_family==255) { + strcat(fbuf,sock_ntop(sa1,sa1->sa_len)); + } + printf("%-19s",fbuf); + } + if((sa=rti_info[RTAX_GATEWAY])!=NULL) { + printf("%-19s",sock_ntop(sa,sa->sa_len)); + } + memset(fbuf,0,sizeof(fbuf)); + get_flags(fbuf,rtm->rtm_flags); + printf("%-10s",fbuf); + for(i=0;i<if_num;i++) { + ifm=ifm_table[i]; + if((ifm->ifm_index==rtm->rtm_index) && + (ifm->ifm_data.ifi_type>0)) { + sa=if_table[i]; + break; + } + } + if(ifm->ifm_type==RTM_IFINFO) { + get_rtaddrs(ifm->ifm_addrs,sa,rti_info); + printf(" %s",Sock_ntop(sa,sa->sa_len)); + } else if(ifm->ifm_type==RTM_NEWADDR) { + ifam=(struct ifa_msghdr *)ifm_table[rtm->rtm_index-1]; + sa=(struct sockaddr *)(ifam+1); + get_rtaddrs(ifam->ifam_addrs,sa,rti_info); + printf(" %s",Sock_ntop(sa,sa->sa_len)); + } + printf(" %u",rtm->rtm_use); + printf("\n"); + } + return(0); + +} + +print_ip_stats() +{ + int mib[4],len; + struct ipstat s; + + mib[0]=CTL_NET; + mib[1]=PF_INET; + mib[2]=IPPROTO_IP; + mib[3]=IPCTL_STATS; + len=sizeof(struct ipstat); + if(sysctl(mib,4,&s,&len,NULL,0)<0) { + perror("sysctl"); + return(-1); + } + printf("\nIP statistics:\n"); + printf("--------------\n"); + printf(" %10lu total packets received\n",s.ips_total); + printf("* Packets ok:\n"); + printf(" %10lu fragments received\n",s.ips_fragments); + printf(" %10lu forwarded\n",s.ips_forward); + printf(" %10lu fast forwarded\n",s.ips_fastforward); + printf(" %10lu forwarded on same net (redirect)\n",s.ips_redirectsent); + printf(" %10lu delivered to upper level\n",s.ips_delivered); + printf(" %10lu total ip packets generated here\n",s.ips_localout); + printf(" %10lu total packets reassembled ok\n",s.ips_reassembled); + printf(" %10lu total datagrams successfully fragmented\n",s.ips_fragmented); + printf(" %10lu output fragments created\n",s.ips_ofragments); + printf(" %10lu total raw IP packets generated\n",s.ips_rawout); + printf("\n* Bad packets:\n"); + printf(" %10lu bad checksum\n",s.ips_badsum); + printf(" %10lu too short\n",s.ips_tooshort); + printf(" %10lu not enough data (too small)\n",s.ips_toosmall); + printf(" %10lu more data than declared in header\n",s.ips_badhlen); + printf(" %10lu less data than declared in header\n",s.ips_badlen); + printf(" %10lu fragments dropped (dups, no mbuf)\n",s.ips_fragdropped); + printf(" %10lu fragments timed out in reassembly\n",s.ips_fragtimeout); + printf(" %10lu received for unreachable dest.\n",s.ips_cantforward); + printf(" %10lu unknown or unsupported protocol\n",s.ips_noproto); + printf(" %10lu lost due to no bufs etc.\n",s.ips_odropped); + printf(" %10lu couldn't fragment (DF set, etc.)\n",s.ips_cantfrag); + printf(" %10lu error in IP options processing\n",s.ips_badoptions); + printf(" %10lu dropped due to no route\n",s.ips_noroute); + printf(" %10lu bad IP version\n",s.ips_badvers); + printf(" %10lu too long (more than max IP size)\n",s.ips_toolong); + printf(" %10lu multicast for unregistered groups\n",s.ips_notmember); +} + +print_tcp_stats() +{ + int mib[4],len; + struct tcpstat s; + + mib[0]=CTL_NET; + mib[1]=PF_INET; + mib[2]=IPPROTO_TCP; + mib[3]=TCPCTL_STATS; + len=sizeof(struct tcpstat); + if(sysctl(mib,4,&s,&len,NULL,0)<0) { + perror("sysctl"); + return(-1); + } + printf("\nTCP statistics:\n"); + printf("---------------\n"); + printf("* Connections:\n"); + printf(" %10lu initiated\n",s.tcps_connattempt); + printf(" %10lu accepted\n",s.tcps_accepts); + printf(" %10lu established\n",s.tcps_connects); + printf(" %10lu dropped\n",s.tcps_drops); + printf(" %10lu embryonic connections dropped\n",s.tcps_conndrops); + printf(" %10lu closed (includes dropped)\n",s.tcps_closed); + printf(" %10lu segments where we tried to get RTT\n",s.tcps_segstimed); + printf(" %10lu times RTT successfully updated\n",s.tcps_rttupdated); + printf(" %10lu delayed ACKs sent\n",s.tcps_delack); + printf(" %10lu dropped in rxmt timeout\n",s.tcps_timeoutdrop); + printf(" %10lu retrasmit timeouts\n",s.tcps_rexmttimeo); + printf(" %10lu persist timeouts\n",s.tcps_persisttimeo); + printf(" %10lu keepalive timeouts\n",s.tcps_keeptimeo); + printf(" %10lu keepalive probes sent\n",s.tcps_keepprobe); + printf(" %10lu dropped in keepalive\n",s.tcps_keepdrops); + + printf("* Packets sent:\n"); + printf(" %10lu total packets sent\n",s.tcps_sndtotal); + printf(" %10lu data packets sent\n",s.tcps_sndpack); + printf(" %10lu data bytes sent\n",s.tcps_sndbyte); + printf(" %10lu data packets retransmitted\n",s.tcps_sndrexmitpack); + printf(" %10lu data bytes retransmitted\n",s.tcps_sndrexmitbyte); + printf(" %10lu ACK-only packets sent\n",s.tcps_sndacks); + printf(" %10lu window probes sent\n",s.tcps_sndprobe); + printf(" %10lu URG-only packets sent\n",s.tcps_sndurg); + printf(" %10lu window update-only packets sent\n",s.tcps_sndwinup); + printf(" %10lu control (SYN,FIN,RST) packets sent\n",s.tcps_sndctrl); + printf("* Packets received:\n"); + printf(" %10lu total packets received\n",s.tcps_rcvtotal); + printf(" %10lu packets in sequence\n",s.tcps_rcvpack); + printf(" %10lu bytes in sequence\n",s.tcps_rcvbyte); + printf(" %10lu packets with bad checksum\n",s.tcps_rcvbadsum); + printf(" %10lu packets with bad offset\n",s.tcps_rcvbadoff); + printf(" %10lu packets too short\n",s.tcps_rcvshort); + printf(" %10lu duplicate-only packets\n",s.tcps_rcvduppack); + printf(" %10lu duplicate-only bytes\n",s.tcps_rcvdupbyte); + printf(" %10lu packets with some duplicate data\n",s.tcps_rcvpartduppack); + printf(" %10lu duplicate bytes in partially dup. packets\n",s.tcps_rcvpartdupbyte); + printf(" %10lu out-of-order packets\n",s.tcps_rcvoopack); + printf(" %10lu out-of-order bytes\n",s.tcps_rcvoobyte); + printf(" %10lu packets with data after window\n",s.tcps_rcvpackafterwin); + printf(" %10lu bytes received after window\n",s.tcps_rcvbyteafterwin); + printf(" %10lu packets received after 'close'\n",s.tcps_rcvafterclose); + printf(" %10lu window probe packets\n",s.tcps_rcvwinprobe); + printf(" %10lu duplicate ACKs\n",s.tcps_rcvdupack); + printf(" %10lu ACKs for unsent data\n",s.tcps_rcvacktoomuch); + printf(" %10lu ACK packets\n",s.tcps_rcvackpack); + printf(" %10lu bytes ACKed by received ACKs\n",s.tcps_rcvackbyte); + printf(" %10lu window update packets\n",s.tcps_rcvwinupd); + printf(" %10lu segments dropped due to PAWS\n",s.tcps_pawsdrop); + printf(" %10lu times header predict ok for ACKs\n",s.tcps_predack); + printf(" %10lu times header predict ok for data packets\n",s.tcps_preddat); + printf(" %10lu PCB cache misses\n",s.tcps_pcbcachemiss); + printf(" %10lu times cached RTT in route updated\n",s.tcps_cachedrtt); + printf(" %10lu times cached RTTVAR updated\n",s.tcps_cachedrttvar); + printf(" %10lu times ssthresh updated\n",s.tcps_cachedssthresh); + printf(" %10lu times RTT initialized from route\n",s.tcps_usedrtt); + printf(" %10lu times RTTVAR initialized from route\n",s.tcps_usedrttvar); + printf(" %10lu times ssthresh initialized from route\n",s.tcps_usedssthresh); + printf(" %10lu timeout in persist state\n",s.tcps_persistdrop); + printf(" %10lu bogus SYN, e.g. premature ACK\n",s.tcps_badsyn); + printf(" %10lu resends due to MTU discovery\n",s.tcps_mturesent); + printf(" %10lu listen queue overflows\n",s.tcps_listendrop); +} + +print_udp_stats() +{ + int mib[4],len; + struct udpstat s; + + mib[0]=CTL_NET; + mib[1]=PF_INET; + mib[2]=IPPROTO_UDP; + mib[3]=UDPCTL_STATS; + len=sizeof(struct udpstat); + if(sysctl(mib,4,&s,&len,NULL,0)<0) { + perror("sysctl"); + return(-1); + } + printf("\nUDP statistics:\n"); + printf("---------------\n"); + printf("* Packets received:\n"); + printf(" %10lu total input packets\n",s.udps_ipackets); + printf(" %10lu packets shorter than header (dropped)\n",s.udps_hdrops); + printf(" %10lu bad checksum\n",s.udps_badsum); + printf(" %10lu data length larger than packet\n",s.udps_badlen); + printf(" %10lu no socket on specified port\n",s.udps_noport); + printf(" %10lu of above, arrived as broadcast\n",s.udps_noportbcast); + printf(" %10lu not delivered, input socket full\n",s.udps_fullsock); + printf(" %10lu packets missing PCB cache\n",s.udpps_pcbcachemiss); + printf(" %10lu packets not for hashed PCBs\n",s.udpps_pcbhashmiss); + printf("* Packets sent:\n"); + printf(" %10lu total output packets\n",s.udps_opackets); + printf(" %10lu output packets on fast path\n",s.udps_fastout); +} + +char *icmp_names[]={ + "echo reply", + "#1", + "#2", + "destination unreachable", + "source quench", + "routing redirect", + "#6", + "#7", + "echo", + "router advertisement", + "router solicitation", + "time exceeded", + "parameter problem", + "time stamp", + "time stamp reply", + "information request", + "information request reply", + "address mask request", + "address mask reply", +}; + +print_icmp_stats() +{ + int mib[4],len,i; + struct icmpstat s; + + mib[0]=CTL_NET; + mib[1]=PF_INET; + mib[2]=IPPROTO_ICMP; + mib[3]=ICMPCTL_STATS; + len=sizeof(struct icmpstat); + if(sysctl(mib,4,&s,&len,NULL,0)<0) { + perror("sysctl"); + return(-1); + } + printf("\nICMP statistics:\n"); + printf("----------------\n"); + printf("* Output histogram:\n"); + for(i=0;i<(ICMP_MAXTYPE+1);i++) { + if(s.icps_outhist[i]>0) + printf("\t%10lu %s\n", + s.icps_outhist[i],icmp_names[i]); + } + printf("* Input histogram:\n"); + for(i=0;i<(ICMP_MAXTYPE+1);i++) { + if(s.icps_inhist[i]>0) + printf("\t%10lu %s\n", + s.icps_inhist[i],icmp_names[i]); + } + printf("* Other stats:\n"); + printf(" %10lu calls to icmp_error\n",s.icps_error); + printf(" %10lu no error 'cuz old ip too short\n",s.icps_oldshort); + printf(" %10lu no error 'cuz old was icmp\n",s.icps_oldicmp); + + printf(" %10lu icmp code out of range\n",s.icps_badcode); + printf(" %10lu packets shorter than min length\n",s.icps_tooshort); + printf(" %10lu bad checksum\n",s.icps_checksum); + printf(" %10lu calculated bound mismatch\n",s.icps_badlen); + printf(" %10lu number of responses\n",s.icps_reflect); + printf(" %10lu broad/multi-cast echo requests dropped\n",s.icps_bmcastecho); + printf(" %10lu broad/multi-cast timestamp requests dropped\n",s.icps_bmcasttstamp); +} + +int +stats(char *proto) +{ + if(pflag) { + if(proto==NULL) { + fprintf(stderr,"Option '-p' requires paramter.\n"); + usage(); + exit(-1); + } + if(strcmp(proto,"ip")==0) print_ip_stats(); + if(strcmp(proto,"icmp")==0) print_icmp_stats(); + if(strcmp(proto,"udp")==0) print_udp_stats(); + if(strcmp(proto,"tcp")==0) print_tcp_stats(); + return(0); + } + print_ip_stats(); + print_icmp_stats(); + print_udp_stats(); + print_tcp_stats(); + return(0); +} + +int +main(int argc, char *argv[]) +{ + char c; + char *proto=NULL; + + progname=argv[0]; + + while((c=getopt(argc,argv,"rsp:"))!=-1) { + switch(c) { + case 'r': + rflag++; + break; + case 's': + sflag++; + rflag=0; + break; + case 'p': + pflag++; + proto=optarg; + break; + case '?': + default: + usage(); + exit(0); + break; + } + } + argc-=optind; + if(argc>0) { + usage(); + exit(-1); + } + if(rflag) { + routing(proto); + } else { + stats(proto); + } + exit(0); +} diff --git a/release/picobsd/tinyware/oinit/Makefile b/release/picobsd/tinyware/oinit/Makefile new file mode 100644 index 0000000..92b7c54 --- /dev/null +++ b/release/picobsd/tinyware/oinit/Makefile @@ -0,0 +1,12 @@ +# $Id: Makefile,v 1.4 1998/08/09 18:50:45 abial Exp $ +# +PROG=oinit +#CFLAGS+=-DUSE_HISTORY +CFLAGS+=-DOINIT_RC=\"/etc/oinit.rc\" +#LDADD=-lutil -ledit -ltermcap +LDADD=-lutil +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/oinit/README b/release/picobsd/tinyware/oinit/README new file mode 100644 index 0000000..e14b0af --- /dev/null +++ b/release/picobsd/tinyware/oinit/README @@ -0,0 +1,123 @@ +Warsaw, 1998.07.07 + +This README shortly describes the features of "oinit" - a very simplistic +version of init(8) combined with a shell. + +Features +-------- + +* oinit is able to run system in multi- and single-user modes, +* it can be started on system with DEVFS/SLICE (i.e. empty /dev), +* provides minimalistic user interface, called "shell()", +* it can run the system startup script (/etc/rc), +* it can be compiled with -DOINIT_RC to use its own startup script + (*very* primitive, but doesn't require any real shell to run it!), +* doesn't require the whole chain of init->getty->login->shell to be run, +* it is extremely small, and is ideally suited for situations when + there is little memory. + +As an additional bonus you receive some obvious and some hidden bugs... :-)) +This code is at most alpha quality yet. + + +How it works +------------ + +Unlike normal init(8), it forks itself on given number of vty's immediately +providing shell() interface. Currently it doesn't require (and is unable to +perform) any authentication, but this is easy to add if needed. + +Standard version of FreeBSD kernel looks for /sbin/init first, and then +tries to execute it. If it fails, it tries to find: + /sbin/oinit + /sbin/init.bak + /stand/sysinstall + +So it is easy to make use of it even on standard system - just put it in +/sbin/oinit and rename /sbin/init to something else, e.g. /sbin/init.bak. + ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +!!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +Init (or oinit) plays crucial role in the system. If you plan to do any +changes to your system's init, make sure you have a boot floppy with working +version of statically compiled init(8) on it - you can very easily put your +system in unusable state when fiddling with it. ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +Shell() interface +----------------- + +It allows you to issue built-in and external commands. Built-in commands +are listed below. For each command there is short help available, with +example of usage. + + cd change working directory + pwd print working directory + set set environment variable (no expansion) + unset unset environment variable + env print all environment variables + echo echo arguments on stdout + exit exit from shell (oinit will start a new one after some delay) + . source-in a file with commands + ? help + +Any other command is passed to execvp(3) as it is. + +EXCEPTION: if you end the command line with a '&', the command is started +as daemon. This is NOT the same as in normal shell, where the '&' puts a +process in background. Here the newly started process is totally dissociated +from terminal. + +Prompt tells you: +* your `pwd` +* your PID +* and that you are root ('#'). + +WARNING: this pseudo-shell doesn't do any expansion whatsoever. + +To do list +---------- + +- oinit proper: + * fix signal handling and transitions, + * invent a one-file configuration database (combining as many files + from /etc as possible into one) able to properly handle inter- + dependencies in running various daemons, + * allow for interpreting of such database, and running various + programs ourselves (this would eventually allow to make /bin/sh + an option, not necessity), + * better hooks for incorporating other modules into oinit (see e.g. + the telnet() below), + * add optional authentication, + +- shell(): + * more built-ins: perhaps 'kill' and 'ps', + * variable expansion, + * globbing, + * conditionals, + * history? (it depends on how much memory it needs). + * programmatic hooks for easy customisation of user interface (like + hierarchy of commands and contexts), + * ... + +- implement as a routine (like shell()) a small remote login daemon telnet(), + as a built-in module to oinit. It would implement the simplest options of + normal telnet, and would itself handle authentication, passing control to + shell() on success. The authentication routine would be the same as for + checking console access. + +And allow me for a moment of day-dreaming: I'd like to rewrite oinit one day +to be a monolithic one-in-all application, non-forking but multithreaded... It +would contain all the modules, such as shell(), telnet(), ifconfig() etc... +started as threads, not separate processes. + +Credits +------- + +The overall framework was taken from FreeBSD /sbin/init. + +Andrzej Bialecki +<abial@nask.pl> + +$Id: README,v 1.5 1998/08/11 06:53:47 abial Exp $ diff --git a/release/picobsd/tinyware/oinit/oinit.c b/release/picobsd/tinyware/oinit/oinit.c new file mode 100644 index 0000000..8cadb87 --- /dev/null +++ b/release/picobsd/tinyware/oinit/oinit.c @@ -0,0 +1,924 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: oinit.c,v 1.8 1998/08/11 06:53:47 abial Exp $ + */ + +/* + * A primitive version of init(8) with simplistic user interface + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/reboot.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <ctype.h> +#include <err.h> + +#ifdef USE_HISTORY +#error "Not yet. But it's quite simple to add - patches are welcome!" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <libutil.h> +#include <paths.h> +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include <varargs.h> + +#define BUFSIZE 1024 +#define MAX_CONS 12 + +#define NONE 0 +#define SINGLE 1 +#define MULTI 2 +#define DEATH 3 + +#define FALSE 0 +#define TRUE 1 + +char cwd[BUFSIZE]; +char vty[]="0123456789abcdef"; +char *progname; +char *motd=NULL; +int ncons=MAX_CONS; +int Reboot=FALSE; +int transition=MULTI; +int prevtrans=SINGLE; +jmp_buf machine; + +char *trans[]={ "NONE", "SINGLE", "MULTI", "DEATH" }; + +extern char **environ; + +/* Struct for holding session state */ +struct sess { + char tty[11]; /* vty device path */ + pid_t pid; /* pid of process running on it */ + int (*func)(int argc, char **argv); + /* internal function to run on it (after forking) */ +} ttys[MAX_CONS]; + +/* Struct for built-in command */ +struct command { + char *cmd; /* command name */ + char *descr; /* command description */ + char *usage; /* usage */ + char *example; /* example of usage */ + int (*func)(char *); /* callback function */ +}; + +/* Prototypes */ +int cd __P((char *)); +int pwd __P((char *)); +int echo __P((char *)); +int xit __P((char *)); +int set __P((char *)); +int unset __P((char *)); +int env __P((char *)); +int help __P((char *)); +int sourcer __P((char *)); +void do_command __P((int shell, char *cmdline)); +void transition_handler __P((int)); + +/* Table of built-in functions */ +struct command bltins[]={ + {"cd","Change working directory","cd [dir]","cd /etc",cd}, + {"pwd","Print current directory","pwd","pwd",pwd}, + {"exit","Exit from shell()","exit","exit",xit}, + {"set","Set environment variable","set [VAR=value]","set TERM=cons25",set}, + {"unset","Unset environment variable","unset VAR","unset EDITOR",unset}, + {"echo","Echo arguments on stdout","echo arg1 arg2 ...","echo Hello World!",echo}, + {"env","Print all environment variables","env","env",env}, + {".","Source-in a file with commands",". filename",". /etc/rc",sourcer}, + {"?","Print this help :-)","? [command]","? set",help}, + {NULL,NULL,NULL,NULL,NULL} +}; + +/* + * Built-in 'cd <path>' handler + */ +int +cd(char *path) +{ + if(chdir(path)) return(-1); + getcwd(cwd,BUFSIZE); + return(0); +} + +/* + * Built-in 'pwd' handler + */ +int +pwd(char *dummy) +{ + + if(getcwd(cwd,BUFSIZE)==NULL) return(-1); + printf("%s\n",cwd); + return(0); +} + +/* + * Built-in 'exit' handler + */ +int +xit(char *dummy) +{ + _exit(0); +} + +/* + * Built-in 'echo' handler + */ +int +echo(char *args) +{ + int i=0,j; + int len; + char c; + int s_quote=0,d_quote=0; + int sep=0,no_lf=0; + + if(args==NULL) { + printf("\n"); + return; + } + len=strlen(args); + if(len>=2) { + if(args[0]=='-' && args[1]=='n') { + no_lf++; + i=2; + while(i<len && (args[i]==' ' || args[i]=='\t')) i++; + } + } + while(i<len) { + c=args[i]; + switch(c) { + case ' ': + case '\t': + if(s_quote||d_quote) { + putchar(c); + } else if(!sep) { + putchar(' '); + sep=1; + } + break; + case '\\': + i++; + c=args[i]; + switch(c) { + case 'n': + putchar('\n'); + break; + case 'b': + putchar('\b'); + break; + case 't': + putchar('\t'); + break; + case 'r': + putchar('\r'); + break; + default: + putchar(c); + break; + } + break; + case '"': + if(!d_quote) { + d_quote=1; + for(j=i+1;j<len;j++) { + if(args[j]=='\\') { + j++; + continue; + } + if(args[j]=='"') { + d_quote=2; + break; + } + } + if(d_quote!=2) { + printf("\necho(): unmatched \"\n"); + return; + } + } else d_quote=0; + break; + case '\'': + if(!s_quote) { + s_quote=1; + for(j=i+1;j<len;j++) { + if(args[j]=='\\') { + j++; + continue; + } + if(args[j]=='\'') { + s_quote=2; + break; + } + } + if(s_quote!=2) { + printf("\necho(): unmatched '\n"); + return; + } + } else s_quote=0; + break; + case '`': + printf("echo(): backquote not implemented yet!\n"); + break; + default: + sep=0; + putchar(c); + break; + } + i++; + } + if(!no_lf) putchar('\n'); + fflush(stdout); +} + +/* + * Built-in 'set VAR=value' handler + */ +int +set(char *var) +{ + int res; + + if(var==NULL) return(env(NULL)); + res=putenv(var); + if(res) printf("set: %s\n",strerror(errno)); + return(res); +} + +/* + * Built-in 'env' handler + */ +int +env(char *dummy) +{ + char **e; + + e=environ; + while(*e!=NULL) { + printf("%s\n",*e++); + } + return(0); +} + +/* + * Built-in 'unset VAR' handler + */ +int +unset(char *var) +{ + if(var==NULL) { + printf("%s: parameter required.\n",progname); + return(-1); + } + return(unsetenv(var)); +} + +/* + * Built-in '?' handler + */ +int +help(char *cmd) +{ + struct command *x; + int found=0; + + if(cmd==NULL) { + printf("\nBuilt-in commands:\n"); + printf("-------------------\n"); + x=bltins; + while(x->cmd!=NULL) { + printf("%s\t%s\n",x->cmd,x->descr); + x++; + } + printf("\nEnter '? <cmd>' for details.\n\n"); + return(0); + } else { + x=bltins; + while(x->cmd!=NULL) { + if(strcmp(x->cmd,cmd)==0) { + found++; + break; + } + x++; + } + if(found) { + printf("\n%s\t%s:\n",x->cmd,x->descr); + printf("\tUsage:\n\t\t%s\n",x->usage); + printf("\te.g:\n\t\t%s\n\n",x->example); + return(0); + } else { + printf("\n%s: no such command.\n\n",cmd); + return(-1); + } + } +} + +/* + * Signal handler for shell() + */ +void +shell_sig(int sig) +{ + switch(sig) { + case SIGINT: + case SIGQUIT: + case SIGTERM: + /* ignore ? */ + break; + default: + break; + } +} + +/* + * Built-in '.' handler (read-in and execute commands from file) + */ +int +sourcer(char *fname) +{ + FILE *fd; + char buf[512],*tok,*arg,**av; + int ac,len,f,res,i; + pid_t pid; + char *sep=" \t"; + + fd=fopen(fname,"r"); + if(fd==NULL) { + printf("Couldn't open file '%s'\n",fname); + return(-1); + } + while(!feof(fd)) { + memset(buf,0,512); + if(fgets(buf,512,fd)==NULL) continue; + if((*buf=='#') || (*buf=='\n')) continue; + len=strlen(buf); + buf[len-1]='\0'; + if(strncmp(buf,"ncons",5)==0) { + tok=strtok(buf,sep); + tok=strtok(NULL,sep); + ncons=atoi(tok); + if((ncons<1)||(ncons>MAX_CONS)) { + syslog(LOG_EMERG,"%s: bad ncons value; defaulting to %d\n",fname,MAX_CONS); + ncons=MAX_CONS; + } + continue; + } else if(strncmp(buf,"motd",4)==0) { + tok=strtok(buf,sep); + motd=strdup(strtok(NULL,sep)); + continue; + } else { + do_command(0,buf); + } + /* Next command, please. */ + } + fclose(fd); + syslog(LOG_EMERG,"Done with %s",fname); +} + +void +do_command(int shell, char *cmdline) +{ + char *tok,*c,*sep=" \t"; + char **av; + struct command *x; + int found,len; + int ac,i,f,res; + int bg=0; + pid_t pid; + + len=strlen(cmdline); + if(cmdline[len-1]=='&') { + bg++; + cmdline[len-1]='\0'; + len--; + } else bg=0; + tok=strtok(cmdline,sep); + x=bltins; + found=0; + while(x->cmd!=NULL) { + if(strcmp(x->cmd,tok)==0) { + found++; + break; + } + x++; + } + if(found) { + tok=cmdline+strlen(x->cmd)+1; + while(*tok && isblank(*tok) && (tok<(cmdline+len))) tok++; + if(*tok==NULL) tok=NULL; + x->func(tok); + return; + } + ac=0; + av=(char **)calloc(((len+1)/2+1),sizeof(char *)); + av[ac++]=tok; + while((av[ac++]=strtok(NULL,sep))!=NULL) + continue; + switch((pid=fork())) { + case 0: + if(shell) { + signal(SIGINT,SIG_DFL); + signal(SIGQUIT,SIG_DFL); + signal(SIGTERM,SIG_DFL); + signal(SIGHUP,SIG_DFL); + } else { + close(0); + close(1); + close(2); + f=open(_PATH_CONSOLE,O_RDWR); + dup2(f,0); + dup2(f,1); + dup2(f,2); + if(f>2) close(f); + } + if(bg) { + if(daemon(0,0)) { + printf("do_command(%s): failed to run bg: %s\n", + av[0],strerror(errno)); + _exit(100); + } + } + execvp(av[0],av); + /* Something went wrong... */ + printf("do_command(%s): %s\n",av[0],strerror(errno)); + _exit(100); + break; + case -1: + printf("do_command(): %s\n",strerror(errno)); + break; + default: + while(waitpid(pid,&res,0)!=pid) continue; + if(WEXITSTATUS(res)) { + printf("%s exited with status %d\n", + av[0],WEXITSTATUS(res)); + } + break; + } + free(av); + return; +} + +/* + * This is the user interface. This routine gets executed on each + * virtual console serviced by init. + * + * It works as normal shell does - for each external command it forks + * and execs, for each internal command just executes a function. + */ + +int +shell(int argc, char **argv) +{ + char buf[BUFSIZE]; + char *prompt=" # "; + int fd; + int res; + pid_t mypid; + + if(motd!=NULL) { + if((fd=open(motd,O_RDONLY))!=-1) { + do { + res=read(fd,buf,BUFSIZE); + res=write(1,buf,res); + } while(res>0); + close(fd); + } + } + + printf("\n\n+=========================================================+\n"); + printf("| Built-in shell() (enter '?' for short help on commands) |\n"); + printf("+=========================================================+\n\n"); + getcwd(cwd,BUFSIZE); + mypid=getpid(); + signal(SIGINT,shell_sig); + signal(SIGQUIT,shell_sig); + signal(SIGTERM,shell_sig); + while(!feof(stdin)) { + memset(buf,0,BUFSIZE); + printf("(%d)%s%s",mypid,cwd,prompt); + fflush(stdout); + if(fgets(buf,BUFSIZE-1,stdin)==NULL) continue; + buf[strlen(buf)-1]='\0'; + if(strlen(buf)==0) continue; + do_command(1,buf); + } + return(0); +} + +/* + * Stub for executing some external program on a console. This is called + * from previously forked copy of our process, so that exec is ok. + */ +int +external_cmd(int argc, char **argv) +{ + execvp(argv[0],argv); +} + +/* + * Acquire vty and properly attach ourselves to it. + * Also, build basic environment for running user interface. + */ + +int +start_session(int vty, int argc, char **argv) +{ + int fd; + char *t; + + close(0); + close(1); + close(2); + revoke(ttys[vty].tty); + fd=open(ttys[vty].tty,O_RDWR); + dup2(fd,0); + dup2(fd,1); + dup2(fd,2); + if(fd>2) close(fd); + login_tty(fd); + setpgid(0,getpid()); + putenv("TERM=cons25"); + putenv("HOME=/"); + putenv("PATH=/stand:/bin:/usr/bin:/sbin:."); + signal(SIGHUP,SIG_DFL); + signal(SIGINT,SIG_DFL); + signal(SIGQUIT,SIG_DFL); + signal(SIGTERM,SIG_DFL); + chdir("/"); + t=(char *)(rindex(ttys[vty].tty,'/')+1); + printf("\n\n\nStarting session on %s.\n",t); + ttys[vty].func(argc,argv); + _exit(0); +} + +/* + * Execute system startup script /etc/rc + * + * (Of course if you don't like it - I don't - you can run anything you + * want here. Perhaps it would be useful just to read some config DB and + * do these things ourselves, avoiding forking lots of shells and scripts.) + */ + +/* If OINIT_RC is defined, oinit will use it's own configuration file, + * /etc/oinit.rc. It's format is described below. Otherwise, it will use + * normal /etc/rc interpreted by Bourne shell. + */ +#ifndef OINIT_RC +void +runcom() +{ + char *argv[3]; + pid_t pid; + int st; + int fd; + + if((pid=fork())==0) { + /* child */ + close(0); + close(1); + close(2); + fd=open(_PATH_CONSOLE,O_RDWR); + dup2(fd,0); + dup2(fd,1); + dup2(fd,2); + if(fd>2) close(fd); + argv[0]="-sh"; + argv[1]="/etc/rc"; + argv[2]=0; + execvp("/bin/sh",argv); + printf("runcom(): %s\n",strerror(errno)); + _exit(1); + } + /* Wait for child to exit */ + while(pid!=waitpid(pid,(int *)0,0)) continue; + return; +} +#else +/* Alternative /etc/rc - default is /etc/oinit.rc. Its format is as follows: + * - each empty line or line beginning with a '#' is discarded + * - any other line must contain a keyword, or a (nonblocking) command to run. + * + * Thus far, the following keywords are defined: + * ncons <number> number of virtual consoles to open + * motd <pathname> full path to motd file + * + * Examples of commands to run: + * + * ifconfig lo0 inet 127.0.0.1 netmask 255.0.0.0 + * ifconfig ed0 inet 148.81.168.10 netmask 255.255.255.0 + * kbdcontrol -l /usr/share/syscons/my_map.kbd + */ +void +runcom(char *fname) +{ + sourcer(fname); +} +#endif + +int +run_multi() +{ + int i,j; + pid_t pid; + int found; + + /* Run /etc/rc if not in single user */ +#ifndef OINIT_RC + if(prevtrans==SINGLE) runcom(); +#else + if(prevtrans==SINGLE) runcom(OINIT_RC); +#endif + if(transition!=MULTI) return(-1); + + syslog(LOG_EMERG,"*** Starting multi-user mode ***"); + + /* Fork shell interface for each console */ + for(i=0;i<ncons;i++) { + if(ttys[i].pid==0) { + switch(pid=fork()) { + case 0: + start_session(i,0,NULL); + break; + case -1: + printf("%s: %s\n",progname,strerror(errno)); + break; + default: + ttys[i].pid=pid; + break; + } + } + } + /* Initialize any other services we'll use - most probably this will + * be a 'telnet' service (some day...). + */ + /* */ + + /* Emulate multi-user */ + while(transition==MULTI) { + /* XXX Modify this to allow for checking for the input on + * XXX listening sockets, and forking a 'telnet' service. + */ + /* */ + + /* Wait for any process to exit */ + pid=waitpid(-1,(int *)0,0); + if(pid==-1) continue; + found=0; + j=-1; + /* search if it's one of our sessions */ + for(i=0;i<ncons;i++) { + if(ttys[i].pid==pid) { + found++; + j=i; + ttys[j].pid=0; + break; + } + } + if(!found) { + /* Just collect the process's status */ + continue; + } else { + /* restart shell() on a console, if it died */ + if(transition!=MULTI) return(0); + switch(pid=fork()) { + case 0: + sleep(1); + start_session(j,0,NULL); + break; + case -1: + printf("%s: %s\n",progname,strerror(errno)); + break; + default: + ttys[j].pid=pid; + break; + } + } + } +} + +int clang; + +void +kill_timer(int sig) +{ + clang=1; +} + +kill_ttys() +{ +} + +/* + * Start a shell on ttyv0 (i.e. the console). + */ + +int +run_single() +{ + int i; + pid_t pid,wpid; + static int sigs[2]={SIGTERM,SIGKILL}; + + syslog(LOG_EMERG,"*** Starting single-user mode ***"); + /* Kill all existing sessions */ + syslog(LOG_EMERG,"Killing all existing sessions..."); + for(i=0;i<MAX_CONS;i++) { + kill(ttys[i].pid,SIGHUP); + ttys[i].pid=0; + } + for(i=0;i<2;i++) { + if(kill(-1,sigs[i])==-1 && errno==ESRCH) break; + clang=0; + alarm(10); + do { + pid=waitpid(-1,(int *)0,WUNTRACED); + if(errno==EINTR) continue; + else break; + } while (clang==0); + } + if(errno!=ECHILD) { + syslog(LOG_EMERG,"Some processes would not die; ps -axl advised"); + } + /* Single-user */ + switch(pid=fork()) { + case 0: + start_session(0,0,NULL); + break; + case -1: + printf("%s: %s\n",progname,strerror(errno)); + printf("The system is seriously hosed. I'm dying...\n"); + transition=DEATH; + return(-1); + break; + default: + do { + wpid=waitpid(pid,(int *)0,WUNTRACED); + } while(wpid!=pid && transition==SINGLE); + if(transition!=DEATH) { + prevtrans=transition; + transition=MULTI; + } + break; + } + return(0); +} + +/* + * Transition handler - installed as signal handler. + */ + +void +transition_handler(int sig) +{ + + switch(sig) { + case SIGHUP: + case SIGTERM: + prevtrans=transition; + transition=SINGLE; + syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]); + if(prevtrans!=transition) longjmp(machine,sig); + break; + case SIGINT: + case SIGQUIT: + prevtrans=transition; + transition=DEATH; + syslog(LOG_EMERG,"*** Going from %s -> %s\n",trans[prevtrans],trans[transition]); + if(prevtrans!=transition) longjmp(machine,sig); + break; + default: + syslog(LOG_EMERG,"pid=%d sig=%s (ignored)\n",getpid(),sys_siglist[sig]); + break; + } +} + +/* + * Change system state appropriately to the signals + */ + +int +transition_machine() +{ + int i; + + while(transition!=DEATH) { + switch(transition) { + case MULTI: + run_multi(); + break; + case SINGLE: + run_single(); + break; + } + } + syslog(LOG_EMERG,"Killing all existing sessions..."); + /* Kill all sessions */ + kill(-1,SIGKILL); + /* Be nice and wait for them */ + while(waitpid(-1,(int *)0,WNOHANG|WUNTRACED)>0) continue; + unmount("/",0); + reboot(RB_AUTOBOOT); + /* NOTREACHED */ +} + +int +main(int argc, char **argv) +{ + int devfs=0,c,i; + + /* These are copied from real init(8) */ + if(getuid()!=0) + errx(1,"%s",strerror(EPERM)); + openlog("init",LOG_CONS|LOG_ODELAY,LOG_AUTH); + if(setsid()<0) + warn("initial setsid() failed"); + if(setlogin("root")<0) + warn("setlogin() failed"); + + close(0); + close(1); + close(2); + chdir("/"); + + progname=rindex(argv[0],'/'); + if(progname==NULL) { + progname=argv[0]; + } else progname++; + + transition=MULTI; + + /* We must recognize the same options as real init does */ + while((c=getopt(argc,argv,"dsf"))!=-1) { + switch(c) { + case 'd': + devfs=1; + break; + case 's': + transition=SINGLE; + break; + case 'f': + break; + default: + printf("%s: unrecognized flag '-%c'\n",progname,c); + break; + } + } + if(devfs) + mount("devfs","/dev",MNT_NOEXEC|MNT_RDONLY,0); + + /* Fill in the sess structures. */ + /* XXX Really, should be filled basing on config file. */ + for(i=0;i<MAX_CONS;i++) { + sprintf(ttys[i].tty,"/dev/ttyv%c",vty[i]); + ttys[i].pid=0; + ttys[i].func=shell; + } + + getcwd(cwd,BUFSIZE); + + signal(SIGINT,transition_handler); + signal(SIGQUIT,transition_handler); + signal(SIGTERM,transition_handler); + signal(SIGHUP,transition_handler); + signal(SIGALRM,kill_timer); + + setjmp(machine); + transition_machine(transition); + /* NOTREACHED */ + exit(100); +} diff --git a/release/picobsd/tinyware/simple_httpd/README b/release/picobsd/tinyware/simple_httpd/README new file mode 100644 index 0000000..0f69f56 --- /dev/null +++ b/release/picobsd/tinyware/simple_httpd/README @@ -0,0 +1,6 @@ +Contributed by Marc Nicholas <marc@netstor.com> + +This is a simple, non-forking WWW server. It is free for non-commercial +use only - see the source code for info on commercial licensing. + +$Id: README,v 1.1 1998/08/19 16:24:06 abial Exp $ diff --git a/release/picobsd/tinyware/simple_httpd/simple_httpd.c b/release/picobsd/tinyware/simple_httpd/simple_httpd.c new file mode 100644 index 0000000..0a83f67 --- /dev/null +++ b/release/picobsd/tinyware/simple_httpd/simple_httpd.c @@ -0,0 +1,356 @@ +/* simpleHTTPd (C) 1998 netSTOR Technologies, Inc. ("netSTOR") + FreeBSD port and additional work by Marc Nicholas <marc@netstor.com> + Based on work by:- + Thierry Leconte & Yury Shimanovsky + My Russian webserver writing friends :-) + + This is an HTTP daemon that will serve up HTML, text files, JPEGs, + GIFs and do simple CGI work. + + You may use this code for non-commercial distribution only. Commercial + distribution requires the express, written permission of netSTOR. No + warranty is implied or given -- use at your own risk! +*/ + +/* + * $Id: simple_httpd.c,v 1.1 1998/08/19 16:24:06 abial Exp $ + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/types.h> +#include <time.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <fcntl.h> +#include <string.h> +#include <signal.h> +#include <sys/wait.h> + +int http_sock, con_sock; +int http_port = 80; +struct sockaddr_in source; +char homedir[100]; +char *adate(); +struct hostent *hst; + +void +init_servconnection(void) +{ + struct sockaddr_in server; + + /* Create a socket */ + http_sock = socket(AF_INET, SOCK_STREAM, 0); + if (http_sock < 0) { + perror("socket"); + exit(1); + } + server.sin_family = AF_INET; + server.sin_port = htons(http_port); + server.sin_addr.s_addr = INADDR_ANY; + if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) { + perror("bind socket"); + exit(1); + } + printf("simpleHTTPd running on %d port\n",http_port); +} + +attenteconnection(void) +{ + int lg; + + lg = sizeof(struct sockaddr_in); + + con_sock = accept(http_sock, (struct sockaddr *) & source, &lg); + if (con_sock <= 0) { + perror("accept"); + exit(1); + } +} + +outdate() +{ + time_t tl; + char buff[50]; + + tl = time(NULL); + strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl)); + write(con_sock, buff, strlen(buff)); +} + +char *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\ +This server is supports only GET and HEAD requests\n</BODY></HTML>\r\n", +"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"}; + +char *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\ +Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n", +"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"}; + +outerror(char **rep, int http1) /* Выдыча ошибки клиенту в html- виде */ +{ + + if (http1) { + write(con_sock, rep[1], strlen(rep[1])); + outdate(); + write(con_sock, "\r\n", 2); + } + write(con_sock, rep[0], strlen(rep[0])); +} + +char rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n"; + +traite_req() +{ + char buff[8192]; + int fd, lg, cmd, http1, i; + char *filename, *c; + struct stat statres; + char req[1024]; + char logfile[80]; + char msg[1024]; + char *p, + *par; + long addr; + FILE *log; + + lg = read(con_sock, req, 1024); + + if (p=strstr(req,"\n")) *p=0; + if (p=strstr(req,"\r")) *p=0; + + if (geteuid()) + { + strcpy(logfile,getenv("HOME")); + strcat(logfile,"/"); + strcat(logfile,"jhttp.log"); + } + else strcpy(logfile,"/usr/adm/jhttpd.log"); + + if ( access(logfile,W_OK)) + { + lg=creat (logfile,O_WRONLY); + chmod (logfile,00600); + close(lg); + } + + strcpy(buff,inet_ntoa(source.sin_addr)); + + addr=inet_addr(buff); + + strcpy(msg,adate()); + strcat(msg," "); + hst=gethostbyaddr((char*) &addr, 4, AF_INET); + if (hst) strcat(msg,hst->h_name); + strcat(msg," ("); + strcat(msg,buff); + strcat(msg,") "); + strcat(msg,req); + + log=fopen(logfile,"a"); + fprintf(log,"%s\n",msg); + fclose(log); + + c = strtok(req, " "); + if (c == NULL) { + outerror(rep_err_nget, 0); + goto error; + } + cmd = 0; + if (strncmp(c, "GET", 3) == 0) + cmd = 1; + if (strncmp(c, "HEAD", 4) == 0) { + cmd = 2; + } + + filename = strtok(NULL, " "); + + http1 = 0; + c = strtok(NULL, " "); + if (c != NULL && strncmp(c, "HTTP", 4) == 0) + http1 = 1; + + if (cmd == 0) { + outerror(rep_err_nget, http1); + goto error; + } + + if (filename == NULL || + strlen(filename)==1) filename="/index.html"; + + while (filename[0]== '/') filename++; + + /**/ + if (!strncmp(filename,"cgi-bin/",8)) + { + par=0; + if (par=strstr(filename,"?")) + { + *par=0; + par++; + } + if (access(filename,X_OK)) goto conti; + stat (filename,&statres); + if (setuid(statres.st_uid)) return(0); + if (seteuid(statres.st_uid)) return(0); + if (!fork()) + { + close(1); + dup(con_sock); + printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n"); + execlp (filename,filename,par,0); + } + wait(&i); + return(0); + } + conti: + if (filename == NULL) { + outerror(rep_err_acc, http1); + goto error; + } + /* interdit les .. dans le path */ + c = filename; + while (*c != '\0') + if (c[0] == '.' && c[1] == '.') { + outerror(rep_err_acc, http1); + goto error; + } else + c++; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + outerror(rep_err_acc, http1); + goto error; + } + if (fstat(fd, &statres) < 0) { + outerror(rep_err_acc, http1); + goto error; + } + if (!S_ISREG(statres.st_mode)) + { + outerror(rep_err_acc, http1); + goto error; + } + if (http1) { + char buff[50]; + time_t tl; + + write(con_sock, rep_head, strlen(rep_head)); + sprintf(buff, "Content-length: %d\r\n", statres.st_size); + write(con_sock, buff, strlen(buff)); + outdate(); + + if (strstr(filename,".")) + { + strcpy(buff,"Content-type: "); + strcat(buff,strstr(filename,".")+1); + strcat(buff,"\r\n"); + write(con_sock,buff,strlen(buff)); + } + + if (strstr(filename,".txt")) + { + strcpy(buff,"Content-type: text/plain\r\n"); + write(con_sock, buff, strlen(buff)); + } + + if (strstr(filename,".html") || + strstr(filename,".htm")) + { + strcpy(buff,"Content-type: text/html\r\n"); + write(con_sock, buff, strlen(buff)); + } + + if (strstr(filename,".gif")) + { + strcpy(buff,"Content-type: image/gif\r\n"); + write(con_sock, buff, strlen(buff)); + } + + if (strstr(filename,".jpg")) + { + strcpy(buff,"Content-type: image/jpeg\r\n"); + write(con_sock, buff, strlen(buff)); + } + + strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime)); + write(con_sock, buff, strlen(buff)); + } + if (cmd == 1) { + while (lg = read(fd, buff, 8192)) + write(con_sock, buff, lg); + } + +error: + close(fd); + close(con_sock); + +} + + +main(int argc, char **argv) +{ + int lg; + char hello[100]; + + if (argc<2 && geteuid()) + { + printf("Usage: simple_htppd <port>\n"); + exit(1); + } + + if (argc>=2) http_port = atoi(argv[1]); + + strcpy (homedir,getenv("HOME")); + if (!geteuid()) strcpy (homedir,"/httphome"); + else strcat (homedir,"/httphome"); + + strcpy(hello,homedir); + strcat(hello,"/0hello.html"); + + if (chdir(homedir)) + { + perror("chdir"); + puts(homedir); + exit(1); + } + init_servconnection(); + + if (fork()) exit(0); + + setpgrp(0,65534); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + + if (listen(http_sock,100) < 0) exit(1); + + label: + attenteconnection(); + if (fork()) + { + close(con_sock); + goto label; + } + alarm(1800); + traite_req(); + exit(0); +} + + + +char *adate() +{ + static char out[50]; + long now; + struct tm *t; + time(&now); + t = localtime(&now); + sprintf(out, "%02d:%02d:%02d %02d/%02d/%02d", + t->tm_hour, t->tm_min, t->tm_sec, + t->tm_mday, t->tm_mon+1, t->tm_year ); + return out; +} diff --git a/release/picobsd/tinyware/sps/Makefile b/release/picobsd/tinyware/sps/Makefile new file mode 100644 index 0000000..c8969bd --- /dev/null +++ b/release/picobsd/tinyware/sps/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile,v 1.1 1998/07/16 23:21:59 abial Exp $ +# +PROG=sps +SRCS= sps.c +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/sps/README b/release/picobsd/tinyware/sps/README new file mode 100644 index 0000000..94098e7 --- /dev/null +++ b/release/picobsd/tinyware/sps/README @@ -0,0 +1,17 @@ +1998.07.17 + +This is a small 'ps' replacement, which uses information available via +sysctl(3) interface (contrary to the 'aps', which requires you to mount +procfs(5) to be able to get exactly the same info, so I think that 'sps' +is superior solution). + +When I have some time, I'll add usual switches and other functions that normal +'ps' has... + +The most serious limitation of 'sps' is that it's unable to retrieve the whole +command line. + + +<abial@nask.pl> + +$Id: README,v 1.1 1998/07/16 23:21:59 abial Exp $ diff --git a/release/picobsd/tinyware/sps/sps.c b/release/picobsd/tinyware/sps/sps.c new file mode 100644 index 0000000..8685eae --- /dev/null +++ b/release/picobsd/tinyware/sps/sps.c @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: sps.c,v 1.2 1998/07/17 07:55:47 abial Exp $ + */ + +/* + * Small replacement for ps(1) - uses only sysctl(3) to retrieve info + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/stat.h> +#include <sys/proc.h> +#include <sys/user.h> + +char p_stat[]="?iRSTZ"; + +int +main(int argc, char *argv[]) +{ + int mib[3],i=0,num,len; + struct kinfo_proc kp,*t,*u; + char buf[20],vty[5],pst[5]; + int ma,mi; + + mib[0]=CTL_KERN; + mib[1]=KERN_PROC; + mib[2]=KERN_PROC_ALL; + if(sysctl(mib,3,NULL,&len,NULL,0)) { + perror("sysctl sizing"); + exit(1); + } + t=(struct kinfo_proc *)malloc(len); + if(sysctl(mib,3,t,&len,NULL,0)) { + perror("sysctl info"); + exit(1); + } + num=len / sizeof(struct kinfo_proc); + i=0; + printf("USERNAME PID PPID PRI NICE TTY STAT WCHAN COMMAND\n"); + while(i<num) { + u=(t+num-i-1); + ma=major(u->kp_eproc.e_tdev); + mi=minor(u->kp_eproc.e_tdev); + switch(ma) { + case 255: + strcpy(vty,"??"); + break; + case 12: + if(mi!=255) { + sprintf(vty,"v%d",mi); + break; + } + /* FALLTHROUGH */ + case 0: + strcpy(vty,"con"); + break; + case 5: + sprintf(vty,"p%d",mi); + break; + } + sprintf(pst,"%c",p_stat[u->kp_proc.p_stat]); + printf("%8s%5d%5d %3d %4d %3s %-4s %-7s (%s)\n", + u->kp_eproc.e_login, + u->kp_proc.p_pid, + u->kp_eproc.e_ppid, + u->kp_proc.p_priority, + u->kp_proc.p_nice, + vty, + pst, + u->kp_eproc.e_wmesg, + u->kp_proc.p_comm); + i++; + } + free(t); + exit(0); + +} diff --git a/release/picobsd/tinyware/view/Makefile b/release/picobsd/tinyware/view/Makefile new file mode 100644 index 0000000..a960fe3 --- /dev/null +++ b/release/picobsd/tinyware/view/Makefile @@ -0,0 +1,9 @@ +# $Id: Makefile,v 1.1 1998/08/19 06:13:34 abial Exp $ + +PROG=view +SRCS=view.c +CFLAGS+=-I/usr/local/include +LDADD+=-L/usr/local/lib -lpng -lvgl +NOMAN=yes + +.include <bsd.prog.mk> diff --git a/release/picobsd/tinyware/view/README b/release/picobsd/tinyware/view/README new file mode 100644 index 0000000..53ec9a0 --- /dev/null +++ b/release/picobsd/tinyware/view/README @@ -0,0 +1,86 @@ +Warsaw, 1998.08.18 + + VIEW - small PNG viewer + ----------------------- + +This program is intended to serve as a simple console viewer for PNG +graphics. It also features some scripting abilities, which allow you to +build simple presentation. + +In fact, using even this initial version I was able to build a nice +presentation of PicoBSD abilities which I used in real-life situation (you +can see for yourself one of the presentation's screens, fbsd.png). + +The audience was impressed :-), especially when I asked them politely what +are requirements and cost to make that kind of presentation using M$ +products... + +Simple Viewing +-------------- + +Usage is as follows: + + view [-g nnn.nnn] [-r x] filename.png + +where + -g nnn.nnn screen gamma (you can adjust how bright is the + picture) + -r x resolution: + 0 - 640x480x16 + 1 - 640x200x256 + 2 - 320x240x256 + +Under right mouse button you can find a simple menu, which tells you also +the hotkeys. You can shift, rotate and zoom the picture. + +Presentation +------------ + +Usage is as above, but the file you give as argument is a (unix) text file +of the following format: + + 1 VIEW SCRIPT + 2 5 + 3 welcome.png + 4 /home/clipart/logo.png + 5 /home/present/title.png + 6 /home/present/outline.png + 7 /home/present/end.png + +(of course without the line numbering or the leading space!). The line number +1 is magic, and must be present in order to recognize the file properly. + +The second line tells how many pictures consist the presentation. The +following lines tell the file names containing the images themselves. + +See the example in file picobsd.vu. + +Command line arguments (gamma and resolution) are as above. You can also use +the pop-up menu to adjust image parameters, as well as go forward or +backward in the presentation. + +Bugs, caveats, missing features +------------------------------- + +* there are some bugs in libvgl which require strange workarounds, and even + then it doesn't work quite right. See the source for the 'XXX' comments... + +* I didn't have time to add gamma adjustment to the pop-up menu. It's + simple, though, and I leave it as an exercise for the reader :-)) + +* it would be great if someone would add GIF and jpeg support. + +* the error checking is probably weak. A bad PNG file or script file will + probably cause a coredump. + +* pop-up menu facilities need more abstraction to be usable in other cases. + +Anyway, as it is even now it's quite usable. + +Have fun! + +Andrzej Bialecki + +<abial@nask.pl> + +$Id: README,v 1.2 1998/08/19 06:19:44 abial Exp $ diff --git a/release/picobsd/tinyware/view/fbsd.png b/release/picobsd/tinyware/view/fbsd.png Binary files differnew file mode 100644 index 0000000..0c5d3ed --- /dev/null +++ b/release/picobsd/tinyware/view/fbsd.png diff --git a/release/picobsd/tinyware/view/picobsd.vu b/release/picobsd/tinyware/view/picobsd.vu new file mode 100644 index 0000000..16a3630 --- /dev/null +++ b/release/picobsd/tinyware/view/picobsd.vu @@ -0,0 +1,9 @@ +VIEW SCRIPT +7 +/png/logo.png +/png/1.png +/png/2.png +/png/p1.png +/png/p2.png +/png/p3.png +/png/p4.png diff --git a/release/picobsd/tinyware/view/view.c b/release/picobsd/tinyware/view/view.c new file mode 100644 index 0000000..9285126 --- /dev/null +++ b/release/picobsd/tinyware/view/view.c @@ -0,0 +1,583 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: view.c,v 1.1 1998/08/19 06:13:35 abial Exp $ + */ + +/* + * Small PNG viewer with scripting abilities + */ + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <termios.h> +#include <sys/types.h> +#include <machine/console.h> +#include <machine/mouse.h> +#include <vgl.h> +#include <png.h> + +#define NUMBER 8 + +extern char *optarg; +extern int optind; + +/* Prototypes */ +int kbd_action __P((int x, int y, char hotkey)); + +struct action { + int zoom; + int rotate; + int Xshift,Yshift; +}; + +struct menu_item { + char *descr; + char hotkey; + int (*func)(int x, int y, char hotkey); +}; + +struct menu_item std_menu[]= { + {"q Quit",'q',kbd_action}, + {"n Next",'n',kbd_action}, + {"p Previous",'p',kbd_action}, + {"Z Zoom in",'Z',kbd_action}, + {"z Zoom out",'z',kbd_action}, + {"r Rotate",'r',kbd_action}, + {"R Refresh",'R',kbd_action}, + {"l Left",'l',kbd_action}, + {"h Right",'h',kbd_action}, + {"j Up",'j',kbd_action}, + {"k Down",'k',kbd_action}, + {NULL,0,NULL} +}; + +char *progname; +VGLBitmap pic,bkg; +struct action a; +byte pal_red[256]; +byte pal_green[256]; +byte pal_blue[256]; +byte pal_colors; +double screen_gamma; +int max_screen_colors=15; +int quit,changed; +char **pres; +int nimg=0; +int cur_img=0; +char act; +FILE *log; + +void +usage() +{ + fprintf(stderr,"\nVGL graphics viewer, 1.0 (c) Andrzej Bialecki.\n"); + fprintf(stderr,"\nUsage:\n"); + fprintf(stderr,"\t%s [-r n] [-g n.n] filename\n",progname); + fprintf(stderr,"\nwhere:\n"); + fprintf(stderr,"\t-r n\tchoose resolution:\n"); + fprintf(stderr,"\t\t0 - 640x480x16 (default)\n"); + fprintf(stderr,"\t\t1 - 640x200x256\n"); + fprintf(stderr,"\t\t2 - 320x240x256\n"); + fprintf(stderr,"\t-g n.n\tset screen gamma (1.3 by default)\n"); + fprintf(stderr,"\n"); +} + +int +pop_up(char *title,int x, int y) +{ + VGLBitmap sav,clr; + int x1,y1,width,height,i,j; + int last_pos,cur_pos,max_item; + char buttons; + char *t; + + sav.Type=VGLDisplay->Type; + clr.Type=VGLDisplay->Type; + width=0; + height=0; + max_item=0; + i=0; + while(std_menu[i].descr!=NULL) { + height++; + max_item++; + if(strlen(std_menu[i].descr)>width) width=strlen(std_menu[i].descr); + i++; + } + width=width*8+2; + height=height*9+4+8; + sav.Xsize=width; + sav.Ysize=height; + clr.Xsize=width; + clr.Ysize=height; + sav.Bitmap=(byte *)calloc(width*height,1); + clr.Bitmap=(byte *)calloc(width*height,1); + if(x>(VGLDisplay->Xsize-width)) x1=VGLDisplay->Xsize-width; + else x1=x; + if(y>(VGLDisplay->Ysize-height)) y1=VGLDisplay->Ysize-height; + else y1=y; + VGLMouseMode(VGL_MOUSEHIDE); + VGLBitmapCopy(VGLDisplay,x1,y1,&sav,0,0,width,height); + VGLFilledBox(VGLDisplay,x1,y1,x1+width-1,y1+height-1,pal_colors-1); + VGLBitmapString(VGLDisplay,x1+1,y1+1,title,0,pal_colors-1,0,0); + VGLLine(VGLDisplay,x1,y1+9,x1+width,y1+9,0); + i=0; + while(std_menu[i].descr!=NULL) { + VGLBitmapString(VGLDisplay,x1+1,y1+11+i*9,std_menu[i].descr,0,pal_colors-1,0,0); + i++; + } + last_pos=-1; + VGLMouseMode(VGL_MOUSESHOW); + do { + pause(); + VGLMouseStatus(&x,&y,&buttons); + cur_pos=(y-y1-11)/9; + if((cur_pos<0)||(cur_pos>max_item-1)) { + if(last_pos==-1) last_pos=0; + VGLBitmapString(VGLDisplay,x1+1,y1+11+last_pos*9,std_menu[last_pos].descr,0,pal_colors-1,0,0); + last_pos=-1; + } else if(last_pos!=cur_pos) { + if(last_pos==-1) last_pos=0; + VGLBitmapString(VGLDisplay,x1+1,y1+11+last_pos*9,std_menu[last_pos].descr,0,pal_colors-1,0,0); + VGLBitmapString(VGLDisplay,x1+1,y1+11+cur_pos*9,std_menu[cur_pos].descr,pal_colors/2+1,pal_colors-1,0,0); + last_pos=cur_pos; + } + } while (buttons & MOUSE_BUTTON3DOWN); + VGLMouseMode(VGL_MOUSEHIDE); + /* XXX Screws up totally when r==3. Libvgl bug! */ + VGLBitmapCopy(&clr,0,0,VGLDisplay,x1,y1,width,height); + VGLBitmapCopy(&sav,0,0,VGLDisplay,x1,y1,width,height); + VGLMouseMode(VGL_MOUSESHOW); + free(sav.Bitmap); + free(clr.Bitmap); + changed++; + if((cur_pos>=0) && (cur_pos<max_item)) { + std_menu[cur_pos].func(x,y,std_menu[cur_pos].hotkey); + } + changed++; + return(0); +} + +void +display( VGLBitmap *pic, + byte *red, + byte *green, + byte *blue, + struct action *e) +{ + VGLBitmap target; + int x,y,i=0,j=0; + + VGLMouseMode(VGL_MOUSEHIDE); + VGLRestorePalette(); + /* XXX Broken in r!=2. Libvgl bug. */ + //VGLClear(VGLDisplay,0); + VGLBitmapCopy(&bkg,0,0,VGLDisplay,0,0,bkg.Xsize,bkg.Ysize); + + if(e!=NULL) { + if(e->zoom!=1 || e->rotate) { + target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize*e->zoom*e->zoom,1); + if(e->rotate) { + target.Xsize=pic->Ysize*e->zoom; + target.Ysize=pic->Xsize*e->zoom; + } else { + target.Xsize=pic->Xsize*e->zoom; + target.Ysize=pic->Ysize*e->zoom; + } + target.Type=pic->Type; + for(x=0;x<pic->Xsize;x++) { + for(y=0;y<pic->Ysize;y++) { + for(i=0;i<e->zoom;i++) { + for(j=0;j<e->zoom;j++) { + if(e->rotate) { + VGLSetXY(&target,target.Xsize-(e->zoom*y+i),e->zoom*x+j,VGLGetXY(pic,x,y)); + } else { + VGLSetXY(&target,e->zoom*x+i,e->zoom*y+j,VGLGetXY(pic,x,y)); + } + } + } + } + } + } else { + target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize,sizeof(byte)); + target.Xsize=pic->Xsize; + target.Ysize=pic->Ysize; + target.Type=pic->Type; + VGLBitmapCopy(pic,0,0,&target,0,0,pic->Xsize,pic->Ysize); + } + } else { + target.Bitmap=(byte *)calloc(pic->Xsize*pic->Ysize,sizeof(byte)); + target.Xsize=pic->Xsize; + target.Ysize=pic->Ysize; + target.Type=pic->Type; + VGLBitmapCopy(pic,0,0,&target,0,0,pic->Xsize,pic->Ysize); + } + VGLSetPalette(red, green, blue); + if(e!=NULL) { + VGLBitmapCopy(&target,0,0,VGLDisplay,e->Xshift,e->Yshift,target.Xsize,target.Ysize); + } else { + VGLBitmapCopy(&target,0,0,VGLDisplay,0,0,target.Xsize,target.Ysize); + } + VGLMouseMode(VGL_MOUSESHOW); + free(target.Bitmap); +} + +int +png_load(char *filename) +{ + int i,j,k; + FILE *fd; + u_char header[NUMBER]; + png_structp png_ptr; + png_infop info_ptr,end_info; + png_uint_32 width,height; + int bit_depth,color_type,interlace_type; + int compression_type,filter_type; + int channels,rowbytes; + double gamma; + png_colorp palette; + int num_palette; + png_bytep *row_pointers; + char c; + int res=0; + + fd=fopen(filename,"rb"); + + if(fd==NULL) { + VGLEnd(); + perror("fopen"); + exit(1); + } + fread(header,1,NUMBER,fd); + if(!png_check_sig(header,NUMBER)) { + fprintf(stderr,"Not a PNG file.\n"); + return(-1); + } + png_ptr=png_create_read_struct(PNG_LIBPNG_VER_STRING,(void *)NULL, + NULL,NULL); + info_ptr=png_create_info_struct(png_ptr); + end_info=png_create_info_struct(png_ptr); + if(!png_ptr || !info_ptr || !end_info) { + VGLEnd(); + fprintf(stderr,"failed to allocate needed structs!\n"); + png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); + return(-1); + } + png_set_sig_bytes(png_ptr,NUMBER); + png_init_io(png_ptr,fd); + png_read_info(png_ptr,info_ptr); + png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth, + &color_type,&interlace_type,&compression_type,&filter_type); + png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette); + channels=png_get_channels(png_ptr,info_ptr); + rowbytes=png_get_rowbytes(png_ptr,info_ptr); + if(bit_depth==16) + png_set_strip_16(png_ptr); + if(color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + if(png_get_gAMA(png_ptr,info_ptr,&gamma)) + png_set_gamma(png_ptr,screen_gamma,gamma); + else + png_set_gamma(png_ptr,screen_gamma,0.45); + if(res==0) { + /* Dither */ + if(color_type & PNG_COLOR_MASK_COLOR) { + if(png_get_valid(png_ptr,info_ptr,PNG_INFO_PLTE)) { + png_uint_16p histogram; + png_get_hIST(png_ptr,info_ptr,&histogram); + png_set_dither(png_ptr,palette,num_palette,max_screen_colors,histogram,0); + } else { + png_color std_color_cube[16]={ + {0x00,0x00,0x00}, + {0x02,0x02,0x02}, + {0x04,0x04,0x04}, + {0x06,0x06,0x06}, + {0x08,0x08,0x08}, + {0x0a,0x0a,0x0a}, + {0x0c,0x0c,0x0c}, + {0x0e,0x0e,0x0e}, + {0x10,0x10,0x10}, + {0x12,0x12,0x12}, + {0x14,0x14,0x14}, + {0x16,0x16,0x16}, + {0x18,0x18,0x18}, + {0x1a,0x1a,0x1a}, + {0x1d,0x1d,0x1d}, + {0xff,0xff,0xff}, + }; + png_set_dither(png_ptr,std_color_cube,max_screen_colors,max_screen_colors,NULL,0); + } + } + } + png_set_packing(png_ptr); + if(png_get_valid(png_ptr,info_ptr,PNG_INFO_sBIT)) { + png_color_8p sig_bit; + + png_get_sBIT(png_ptr,info_ptr,&sig_bit); + png_set_shift(png_ptr,sig_bit); + } + png_read_update_info(png_ptr,info_ptr); + png_get_IHDR(png_ptr,info_ptr,&width,&height,&bit_depth, + &color_type,&interlace_type,&compression_type,&filter_type); + png_get_PLTE(png_ptr,info_ptr,&palette,&num_palette); + channels=png_get_channels(png_ptr,info_ptr); + rowbytes=png_get_rowbytes(png_ptr,info_ptr); + row_pointers=malloc(height*sizeof(png_bytep)); + for(i=0;i<height;i++) { + row_pointers[i]=malloc(rowbytes); + } + png_read_image(png_ptr,row_pointers); + png_read_end(png_ptr,end_info); + png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); + fclose(fd); + /* Set palette */ + if(res) k=2; + else k=2; + for(i=0;i<256;i++) { + pal_red[i]=255; + pal_green[i]=255; + pal_blue[i]=255; + } + for(i=0;i<num_palette;i++) { + pal_red[i]=(palette+i)->red>>k; + pal_green[i]=(palette+i)->green>>k; + pal_blue[i]=(palette+i)->blue>>k; + } + pal_colors=num_palette; + if(pic.Bitmap!=NULL) free(pic.Bitmap); + pic.Bitmap=(byte *)calloc(rowbytes*height,sizeof(byte)); + pic.Type=MEMBUF; + pic.Xsize=rowbytes; + pic.Ysize=height; + for(i=0;i<rowbytes;i++) { + for(j=0;j<height;j++) { + VGLSetXY(&pic, + i,j,row_pointers[j][i]); + } + } + a.zoom=1; + a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2; + a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2; + a.rotate=0; + return(0); +} + +void +kbd_handler(int sig) +{ + u_char buf[10]; + int res; + + res=read(0,&buf,10); + changed++; + act=buf[res-1]; +} + +int +kbd_action(int x, int y, char key) +{ + changed=0; + switch(key) { + case 'q': + quit=1; + break; + case 'Z': + a.zoom++; + changed++; + break; + case 'z': + a.zoom--; + if(a.zoom<1) a.zoom=1; + changed++; + break; + case 'l': + a.Xshift+=VGLDisplay->Xsize/5; + changed++; + break; + case 'h': + a.Xshift-=VGLDisplay->Xsize/5; + changed++; + break; + case 'k': + a.Yshift+=VGLDisplay->Ysize/5; + changed++; + break; + case 'j': + a.Yshift-=VGLDisplay->Ysize/5; + changed++; + break; + case 'R': + changed++; + break; + case 'r': + if(a.rotate) a.rotate=0; + else a.rotate=1; + changed++; + break; + case '\n': + case 'n': + if((nimg>0) && (cur_img<nimg-1)) { + cur_img++; + png_load(pres[cur_img]); + changed++; + } + break; + case 'p': + if((nimg>0) && (cur_img>0)) { + cur_img--; + png_load(pres[cur_img]); + changed++; + } + break; + } + act=0; +} + +int +main(int argc, char *argv[]) +{ + int i,j,k; + char c; + int res=0; + int x,y; + char buttons; + struct termios t_new,t_old; + FILE *fsc; + + char buf[100]; + + progname=argv[0]; + screen_gamma=1.5; + log=fopen("/png/view.log","w"); + while((c=getopt(argc,argv,"r:g:"))!=-1) { + switch(c) { + case 'r': + res=atoi(optarg); + if(res>0) max_screen_colors=256; + break; + case 'g': + screen_gamma=atof(optarg); + break; + case '?': + default: + usage(); + exit(0); + } + } + switch(res) { + case 0: + VGLInit(SW_CG640x480); + break; + case 1: + VGLInit(SW_VGA_CG320); + break; + case 2: + VGLInit(SW_VGA_MODEX); + break; + default: + fprintf(stderr,"No such resolution!\n"); + usage(); + exit(-1); + } + fprintf(log,"VGL initialised\n"); + VGLSavePalette(); + VGLMouseInit(VGL_MOUSEHIDE); + if(argc>optind) { + res=png_load(argv[optind]); + } else { + VGLEnd(); + usage(); + exit(0); + } + if(res) { + /* Hmm... Script? */ + fsc=fopen(argv[optind],"r"); + fprintf(log,"Trying script %s\n",argv[optind]); + fgets(buf,99,fsc); + if(strcmp("VIEW SCRIPT\n",buf)!=NULL) { + VGLEnd(); + usage(); + } + fgets(buf,99,fsc); + buf[strlen(buf)-1]='\0'; + nimg=atoi(buf); + if(nimg==0) { + VGLEnd(); + usage(); + } + pres=(char **)calloc(nimg,sizeof(char *)); + for(i=0;i<nimg;i++) { + fgets(buf,99,fsc); + buf[strlen(buf)-1]='\0'; + pres[i]=strdup(buf); + } + fclose(fsc); + cur_img=0; + fprintf(log,"Script with %d entries\n",nimg); + png_load(pres[cur_img]); + } + /* Prepare the keyboard */ + tcgetattr(0,&t_old); + memcpy(&t_new,&t_old,sizeof(struct termios)); + cfmakeraw(&t_new); + tcsetattr(0,TCSAFLUSH,&t_new); + fcntl(0,F_SETFL,O_ASYNC); + /* XXX VGLClear doesn't work.. :-(( Prepare a blank background */ + bkg.Bitmap=(byte *)calloc(VGLDisplay->Xsize*VGLDisplay->Ysize,1); + bkg.Xsize=VGLDisplay->Xsize; + bkg.Ysize=VGLDisplay->Ysize; + bkg.Type=VGLDisplay->Type; + signal(SIGIO,kbd_handler); + a.zoom=1; + a.Xshift=(VGLDisplay->Xsize-pic.Xsize)/2; + a.Yshift=(VGLDisplay->Ysize-pic.Ysize)/2; + a.rotate=0; + quit=0; + changed=0; + display(&pic,pal_red,pal_green,pal_blue,&a); + while(!quit) { + if(act) { + fprintf(log,"kbd_action(%c)\n",act); + kbd_action(x,y,act); + } + if(quit) break; + if(changed) { + fprintf(log,"changed, redisplaying\n"); + display(&pic,pal_red,pal_green,pal_blue,&a); + changed=0; + } + pause(); + VGLMouseStatus(&x,&y,&buttons); + if(buttons & MOUSE_BUTTON3DOWN) { + fprintf(log,"pop_up called\n"); + pop_up("View",x,y); + } + } + VGLEnd(); + fclose(log); + exit(0); +} diff --git a/release/picobsd/tinyware/vm/Makefile b/release/picobsd/tinyware/vm/Makefile new file mode 100644 index 0000000..9e64474 --- /dev/null +++ b/release/picobsd/tinyware/vm/Makefile @@ -0,0 +1,10 @@ +# $Id: Makefile,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ +# +PROG=vm +#CFLAGS+= +SRCS= vm.c +NOMAN=yes + +.include <bsd.prog.mk> + + diff --git a/release/picobsd/tinyware/vm/README b/release/picobsd/tinyware/vm/README new file mode 100644 index 0000000..ec70bc2 --- /dev/null +++ b/release/picobsd/tinyware/vm/README @@ -0,0 +1,10 @@ +1998.02.12 + +This is a small replacement for vmstat(8) program. It allows you to measure +current memory utilisation. The same info is available via sysctl(8) program, +but unfortunately this particular variable doesn't have its handler, and +consequently it is not displayed in stock version of sysctl(8). + +<abial@nask.pl> + +$Id: README,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ diff --git a/release/picobsd/tinyware/vm/vm.c b/release/picobsd/tinyware/vm/vm.c new file mode 100644 index 0000000..710cfb9 --- /dev/null +++ b/release/picobsd/tinyware/vm/vm.c @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 1998 Andrzej Bialecki + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $Id: vm.c,v 1.1.1.1 1998/07/14 07:30:54 abial Exp $ + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/vmmeter.h> +#include <vm/vm_param.h> + +int +main(int argc, char *argv[]) +{ + int mib[2],i=0,len; + struct vmtotal v; + + len=sizeof(struct vmtotal); + mib[0]=CTL_VM; + mib[1]=VM_METER; + for(;;) { + sysctl(mib,2,&v,&len,NULL,0); + if(i==0) { + printf(" procs kB virt mem real mem shared vm shared real free\n"); + printf(" r d p s tot act tot act tot act tot act\n"); + } + printf("%2hu%2hu%2hu%2hu",v.t_rq,v.t_dw,v.t_pw,v.t_sl); + printf("%7u%7u%7u%7u", + v.t_vm<<2,v.t_avm<<2,v.t_rm<<2,v.t_arm<<2); + printf("%7u%7u%7u%7u%7u\n", + v.t_vmshr<<2,v.t_avmshr<<2,v.t_rmshr<<2,v.t_armshr<<2,v.t_free<<2); + sleep(5); + i++; + if(i>22) i=0; + } + exit(0); + +} |