Import Lite2's src/bin. All files in src/bin are off the vendor branch,

so this doesn't change the active versions.
This commit is contained in:
Bruce Evans
1997-07-01 22:34:08 +00:00
parent 53bf4bb2cf
commit c46940197c
40 changed files with 22201 additions and 0 deletions
+120
View File
@@ -0,0 +1,120 @@
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)cat.1 8.3 (Berkeley) 5/2/95
.\"
.Dd May 2, 1995
.Dt CAT 1
.Os BSD 3
.Sh NAME
.Nm cat
.Nd concatenate and print files
.Sh SYNOPSIS
.Nm cat
.Op Fl benstuv
.Op Fl
.Op Ar
.Sh DESCRIPTION
The
.Nm cat
utility reads files sequentially, writing them to the standard output.
The
.Ar file
operands are processed in command line order.
A single dash represents the standard input.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl b
Implies the
.Fl n
option but doesn't number blank lines.
.It Fl e
Implies the
.Fl v
option, and displays a dollar sign
.Pq Ql \&$
at the end of each line
as well.
.It Fl n
Number the output lines, starting at 1.
.It Fl s
Squeeze multiple adjacent empty lines, causing the output to be
single spaced.
.It Fl t
Implies the
.Fl v
option, and displays tab characters as
.Ql ^I
as well.
.It Fl u
The
.Fl u
option guarantees that the output is unbuffered.
.It Fl v
Displays non-printing characters so they are visible.
Control characters print as
.Ql ^X
for control-X; the delete
character (octal 0177) prints as
.Ql ^?
Non-ascii characters (with the high bit set) are printed as
.Ql M-
(for meta) followed by the character for the low 7 bits.
.El
.Pp
The
.Nm cat
utility exits 0 on success, and >0 if an error occurs.
.Sh BUGS
Because of the shell language mechanism used to perform output
redirection, the command
.Dq Li cat file1 file 2 > file1
will cause the original data in file1 to be destroyed!
.Sh SEE ALSO
.Xr head 1 ,
.Xr more 1 ,
.Xr pr 1 ,
.Xr tail 1 ,
.Xr vis 1
.Rs
.%A Rob Pike
.%T "UNIX Style, or cat -v Considered Harmful"
.%J "USENIX Summer Conference Proceedings"
.%D 1983
.Re
.Sh HISTORY
A
.Nm
command appeared in Version 6 AT&T UNIX.
+252
View File
@@ -0,0 +1,252 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Kevin Fall.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int bflag, eflag, nflag, sflag, tflag, vflag;
int rval;
char *filename;
void cook_args __P((char *argv[]));
void cook_buf __P((FILE *));
void raw_args __P((char *argv[]));
void raw_cat __P((int));
int
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
int ch;
while ((ch = getopt(argc, argv, "benstuv")) != -1)
switch (ch) {
case 'b':
bflag = nflag = 1; /* -b implies -n */
break;
case 'e':
eflag = vflag = 1; /* -e implies -v */
break;
case 'n':
nflag = 1;
break;
case 's':
sflag = 1;
break;
case 't':
tflag = vflag = 1; /* -t implies -v */
break;
case 'u':
setbuf(stdout, (char *)NULL);
break;
case 'v':
vflag = 1;
break;
default:
case '?':
(void)fprintf(stderr,
"usage: cat [-benstuv] [-] [file ...]\n");
exit(1);
}
argv += optind;
if (bflag || eflag || nflag || sflag || tflag || vflag)
cook_args(argv);
else
raw_args(argv);
if (fclose(stdout))
err(1, "stdout");
exit(rval);
}
void
cook_args(argv)
char **argv;
{
register FILE *fp;
fp = stdin;
filename = "stdin";
do {
if (*argv) {
if (!strcmp(*argv, "-"))
fp = stdin;
else if ((fp = fopen(*argv, "r")) == NULL) {
warn("%s", *argv);
++argv;
continue;
}
filename = *argv++;
}
cook_buf(fp);
if (fp != stdin)
(void)fclose(fp);
} while (*argv);
}
void
cook_buf(fp)
register FILE *fp;
{
register int ch, gobble, line, prev;
line = gobble = 0;
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '\n') {
if (ch == '\n') {
if (sflag) {
if (!gobble && putchar(ch) == EOF)
break;
gobble = 1;
continue;
}
if (nflag && !bflag) {
(void)fprintf(stdout, "%6d\t", ++line);
if (ferror(stdout))
break;
}
} else if (nflag) {
(void)fprintf(stdout, "%6d\t", ++line);
if (ferror(stdout))
break;
}
}
gobble = 0;
if (ch == '\n') {
if (eflag)
if (putchar('$') == EOF)
break;
} else if (ch == '\t') {
if (tflag) {
if (putchar('^') == EOF || putchar('I') == EOF)
break;
continue;
}
} else if (vflag) {
if (!isascii(ch)) {
if (putchar('M') == EOF || putchar('-') == EOF)
break;
ch = toascii(ch);
}
if (iscntrl(ch)) {
if (putchar('^') == EOF ||
putchar(ch == '\177' ? '?' :
ch | 0100) == EOF)
break;
continue;
}
}
if (putchar(ch) == EOF)
break;
}
if (ferror(fp)) {
warn("%s", filename);
clearerr(fp);
}
if (ferror(stdout))
err(1, "stdout");
}
void
raw_args(argv)
char **argv;
{
register int fd;
fd = fileno(stdin);
filename = "stdin";
do {
if (*argv) {
if (!strcmp(*argv, "-"))
fd = fileno(stdin);
else if ((fd = open(*argv, O_RDONLY, 0)) < 0) {
warn("%s", *argv);
++argv;
continue;
}
filename = *argv++;
}
raw_cat(fd);
if (fd != fileno(stdin))
(void)close(fd);
} while (*argv);
}
void
raw_cat(rfd)
register int rfd;
{
register int nr, nw, off, wfd;
static int bsize;
static char *buf;
struct stat sbuf;
wfd = fileno(stdout);
if (buf == NULL) {
if (fstat(wfd, &sbuf))
err(1, "%s", filename);
bsize = MAX(sbuf.st_blksize, 1024);
if ((buf = malloc((u_int)bsize)) == NULL)
err(1, NULL);
}
while ((nr = read(rfd, buf, bsize)) > 0)
for (off = 0; nr; nr -= nw, off += nw)
if ((nw = write(wfd, buf + off, nr)) < 0)
err(1, "stdout");
if (nr < 0)
warn("%s", filename);
}
+448
View File
@@ -0,0 +1,448 @@
/*
* Copyright (c) 1988, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* David Hitz of Auspex Systems Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)cp.c 8.5 (Berkeley) 4/29/95";
#endif /* not lint */
/*
* Cp copies source files to target files.
*
* The global PATH_T structure "to" always contains the path to the
* current target file. Since fts(3) does not change directories,
* this path can be either absolute or dot-relative.
*
* The basic algorithm is to initialize "to" and use fts(3) to traverse
* the file hierarchy rooted in the argument list. A trivial case is the
* case of 'cp file1 file2'. The more interesting case is the case of
* 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
* path (relative to the root of the traversal) is appended to dir (stored
* in "to") to form the final target path.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
#define STRIP_TRAILING_SLASH(p) { \
while ((p).p_end > (p).p_path && (p).p_end[-1] == '/') \
*--(p).p_end = 0; \
}
PATH_T to = { to.p_path, "" };
uid_t myuid;
int Rflag, iflag, pflag, rflag;
int myumask;
enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
int copy __P((char *[], enum op, int));
int mastercmp __P((const FTSENT **, const FTSENT **));
int
main(argc, argv)
int argc;
char *argv[];
{
struct stat to_stat, tmp_stat;
enum op type;
int Hflag, Lflag, Pflag, ch, fts_options, r;
char *target;
Hflag = Lflag = Pflag = Rflag = 0;
while ((ch = getopt(argc, argv, "HLPRfipr")) != EOF)
switch (ch) {
case 'H':
Hflag = 1;
Lflag = Pflag = 0;
break;
case 'L':
Lflag = 1;
Hflag = Pflag = 0;
break;
case 'P':
Pflag = 1;
Hflag = Lflag = 0;
break;
case 'R':
Rflag = 1;
break;
case 'f':
iflag = 0;
break;
case 'i':
iflag = isatty(fileno(stdin));
break;
case 'p':
pflag = 1;
break;
case 'r':
rflag = 1;
break;
case '?':
default:
usage();
break;
}
argc -= optind;
argv += optind;
if (argc < 2)
usage();
fts_options = FTS_NOCHDIR | FTS_PHYSICAL;
if (rflag) {
if (Rflag)
errx(1,
"the -R and -r options may not be specified together.");
if (Hflag || Lflag || Pflag)
errx(1,
"the -H, -L, and -P options may not be specified with the -r option.");
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL;
}
if (Rflag) {
if (Hflag)
fts_options |= FTS_COMFOLLOW;
if (Lflag) {
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL;
}
} else {
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL;
}
myuid = getuid();
/* Copy the umask for explicit mode setting. */
myumask = umask(0);
(void)umask(myumask);
/* Save the target base in "to". */
target = argv[--argc];
if (strlen(target) > MAXPATHLEN)
errx(1, "%s: name too long", target);
(void)strcpy(to.p_path, target);
to.p_end = to.p_path + strlen(to.p_path);
if (to.p_path == to.p_end) {
*to.p_end++ = '.';
*to.p_end = 0;
}
STRIP_TRAILING_SLASH(to);
to.target_end = to.p_end;
/* Set end of argument list for fts(3). */
argv[argc] = NULL;
/*
* Cp has two distinct cases:
*
* cp [-R] source target
* cp [-R] source1 ... sourceN directory
*
* In both cases, source can be either a file or a directory.
*
* In (1), the target becomes a copy of the source. That is, if the
* source is a file, the target will be a file, and likewise for
* directories.
*
* In (2), the real target is not directory, but "directory/source".
*/
r = stat(to.p_path, &to_stat);
if (r == -1 && errno != ENOENT)
err(1, "%s", to.p_path);
if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
/*
* Case (1). Target is not a directory.
*/
if (argc > 1) {
usage();
exit(1);
}
/*
* Need to detect the case:
* cp -R dir foo
* Where dir is a directory and foo does not exist, where
* we want pathname concatenations turned on but not for
* the initial mkdir().
*/
if (r == -1) {
if (rflag || (Rflag && (Lflag || Hflag)))
stat(*argv, &tmp_stat);
else
lstat(*argv, &tmp_stat);
if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag))
type = DIR_TO_DNE;
else
type = FILE_TO_FILE;
} else
type = FILE_TO_FILE;
} else
/*
* Case (2). Target is a directory.
*/
type = FILE_TO_DIR;
exit (copy(argv, type, fts_options));
}
int
copy(argv, type, fts_options)
char *argv[];
enum op type;
int fts_options;
{
struct stat to_stat;
FTS *ftsp;
FTSENT *curr;
int base, dne, nlen, rval;
char *p;
if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL)
err(1, NULL);
for (rval = 0; (curr = fts_read(ftsp)) != NULL;) {
switch (curr->fts_info) {
case FTS_NS:
case FTS_ERR:
warnx("%s: %s",
curr->fts_path, strerror(curr->fts_errno));
rval = 1;
continue;
case FTS_DC: /* Warn, continue. */
warnx("%s: directory causes a cycle", curr->fts_path);
rval = 1;
continue;
case FTS_DP: /* Ignore, continue. */
continue;
}
/*
* If we are in case (2) or (3) above, we need to append the
* source name to the target name.
*/
if (type != FILE_TO_FILE) {
if ((curr->fts_namelen +
to.target_end - to.p_path + 1) > MAXPATHLEN) {
warnx("%s/%s: name too long (not copied)",
to.p_path, curr->fts_name);
rval = 1;
continue;
}
/*
* Need to remember the roots of traversals to create
* correct pathnames. If there's a directory being
* copied to a non-existent directory, e.g.
* cp -R a/dir noexist
* the resulting path name should be noexist/foo, not
* noexist/dir/foo (where foo is a file in dir), which
* is the case where the target exists.
*
* Also, check for "..". This is for correct path
* concatentation for paths ending in "..", e.g.
* cp -R .. /tmp
* Paths ending in ".." are changed to ".". This is
* tricky, but seems the easiest way to fix the problem.
*
* XXX
* Since the first level MUST be FTS_ROOTLEVEL, base
* is always initialized.
*/
if (curr->fts_level == FTS_ROOTLEVEL)
if (type != DIR_TO_DNE) {
p = strrchr(curr->fts_path, '/');
base = (p == NULL) ? 0 :
(int)(p - curr->fts_path + 1);
if (!strcmp(&curr->fts_path[base],
".."))
base += 1;
} else
base = curr->fts_pathlen;
if (to.target_end[-1] != '/') {
*to.target_end = '/';
*(to.target_end + 1) = 0;
}
p = &curr->fts_path[base];
nlen = curr->fts_pathlen - base;
(void)strncat(to.target_end + 1, p, nlen);
to.p_end = to.target_end + nlen + 1;
*to.p_end = 0;
STRIP_TRAILING_SLASH(to);
}
/* Not an error but need to remember it happened */
if (stat(to.p_path, &to_stat) == -1)
dne = 1;
else {
if (to_stat.st_dev == curr->fts_statp->st_dev &&
to_stat.st_ino == curr->fts_statp->st_ino) {
warnx("%s and %s are identical (not copied).",
to.p_path, curr->fts_path);
rval = 1;
if (S_ISDIR(curr->fts_statp->st_mode))
(void)fts_set(ftsp, curr, FTS_SKIP);
continue;
}
if (!S_ISDIR(curr->fts_statp->st_mode) &&
S_ISDIR(to_stat.st_mode)) {
warnx("cannot overwrite directory %s with non-directory %s",
to.p_path, curr->fts_path);
rval = 1;
continue;
}
dne = 0;
}
switch (curr->fts_statp->st_mode & S_IFMT) {
case S_IFLNK:
if (copy_link(curr, !dne))
rval = 1;
break;
case S_IFDIR:
if (!Rflag && !rflag) {
warnx("%s is a directory (not copied).",
curr->fts_path);
(void)fts_set(ftsp, curr, FTS_SKIP);
rval = 1;
break;
}
/*
* If the directory doesn't exist, create the new
* one with the from file mode plus owner RWX bits,
* modified by the umask. Trade-off between being
* able to write the directory (if from directory is
* 555) and not causing a permissions race. If the
* umask blocks owner writes, we fail..
*/
if (dne) {
if (mkdir(to.p_path,
curr->fts_statp->st_mode | S_IRWXU) < 0)
err(1, "%s", to.p_path);
} else if (!S_ISDIR(to_stat.st_mode)) {
errno = ENOTDIR;
err(1, "%s", to.p_path);
}
/*
* If not -p and directory didn't exist, set it to be
* the same as the from directory, umodified by the
* umask; arguably wrong, but it's been that way
* forever.
*/
if (pflag && setfile(curr->fts_statp, 0))
rval = 1;
else if (dne)
(void)chmod(to.p_path,
curr->fts_statp->st_mode);
break;
case S_IFBLK:
case S_IFCHR:
if (Rflag) {
if (copy_special(curr->fts_statp, !dne))
rval = 1;
} else
if (copy_file(curr, dne))
rval = 1;
break;
case S_IFIFO:
if (Rflag) {
if (copy_fifo(curr->fts_statp, !dne))
rval = 1;
} else
if (copy_file(curr, dne))
rval = 1;
break;
default:
if (copy_file(curr, dne))
rval = 1;
break;
}
}
if (errno)
err(1, "fts_read");
return (rval);
}
/*
* mastercmp --
* The comparison function for the copy order. The order is to copy
* non-directory files before directory files. The reason for this
* is because files tend to be in the same cylinder group as their
* parent directory, whereas directories tend not to be. Copying the
* files first reduces seeking.
*/
int
mastercmp(a, b)
const FTSENT **a, **b;
{
int a_info, b_info;
a_info = (*a)->fts_info;
if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR)
return (0);
b_info = (*b)->fts_info;
if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR)
return (0);
if (a_info == FTS_D)
return (-1);
if (b_info == FTS_D)
return (1);
return (0);
}
+44
View File
@@ -0,0 +1,44 @@
# @(#)Makefile 8.2 (Berkeley) 3/22/95
#
# C Shell with process control; VM/UNIX VAX Makefile
# Bill Joy UC Berkeley; Jim Kulp IIASA, Austria
#
# To profile, put -DPROF in DEFS and -pg in CFLAGS, and recompile.
PROG= csh
DFLAGS=-DBUILTIN -DFILEC -DNLS -DSHORT_STRINGS
#CFLAGS+=-g
#CFLAGS+=-Wall
CFLAGS+=-I${.CURDIR} -I. ${DFLAGS}
SRCS= alloc.c char.c const.c csh.c dir.c dol.c err.c exec.c exp.c file.c \
func.c glob.c hist.c init.c lex.c misc.c parse.c printf.c proc.c \
sem.c set.c str.c time.c
.PATH: ${.CURDIR}/../../usr.bin/printf
MAN1= csh.0
MLINKS= csh.1 limit.1 csh.1 alias.1 csh.1 bg.1 csh.1 dirs.1 csh.1 fg.1 \
csh.1 foreach.1 csh.1 history.1 csh.1 jobs.1 csh.1 popd.1 \
csh.1 pushd.1 csh.1 rehash.1 csh.1 repeat.1 csh.1 suspend.1 \
csh.1 stop.1 csh.1 source.1
CLEANFILES+=err.h const.h
const.h: err.h
err.h: err.c
@rm -f $@
@echo '/* Do not edit this file, make creates it. */' > $@
@echo '#ifndef _h_sh_err' >> $@
@echo '#define _h_sh_err' >> $@
egrep 'ERR_' ${.CURDIR}/$*.c | egrep '^#define' >> $@
@echo '#endif /* _h_sh_err */' >> $@
const.h: const.c
@rm -f $@
@echo '/* Do not edit this file, make creates it. */' > $@
${CC} -E ${CFLAGS} ${.CURDIR}/$*.c | egrep 'Char STR' | \
sed -e 's/Char \([a-zA-Z0-9_]*\)\(.*\)/extern Char \1[];/' | \
sort >> $@
.depend: const.h err.h
.include <bsd.prog.mk>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+651
View File
@@ -0,0 +1,651 @@
.\" Copyright (c) 1980, 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.
.\"
.\" @(#)csh.3 8.2 (Berkeley) 5/16/94
.\"
.nr H1 2
.NH
Shell control structures and command scripts
.NH 2
Introduction
.PP
It is possible to place commands in files and to cause shells to be
invoked to read and execute commands from these files,
which are called
.I "shell scripts."
We here detail those features of the shell useful to the writers of such
scripts.
.NH 2
Make
.PP
It is important to first note what shell scripts are
.I not
useful for.
There is a program called
.I make
which is very useful for maintaining a group of related files
or performing sets of operations on related files.
For instance a large program consisting of one or more files
can have its dependencies described in a
.I makefile
which contains definitions of the commands used to create these
different files when changes occur.
Definitions of the means for printing listings, cleaning up the directory
in which the files reside, and installing the resultant programs
are easily, and most appropriately placed in this
.I makefile.
This format is superior and preferable to maintaining a group of shell
procedures to maintain these files.
.PP
Similarly when working on a document a
.I makefile
may be created which defines how different versions of the document
are to be created and which options of
.I nroff
or
.I troff
are appropriate.
.NH 2
Invocation and the argv variable
.PP
A
.I csh
command script may be interpreted by saying
.DS
% csh script ...
.DE
where
.I script
is the name of the file containing a group of
.I csh
commands and
`\&...' is replaced by a sequence of arguments.
The shell places these arguments in the variable
.I argv
and then begins to read commands from the script.
These parameters are then available through the same mechanisms
which are used to reference any other shell variables.
.PP
If you make the file
`script'
executable by doing
.DS
chmod 755 script
.DE
and place a shell comment at the beginning of the shell script
(i.e. begin the file with a `#' character)
then a `/bin/csh' will automatically be invoked to execute `script' when
you type
.DS
script
.DE
If the file does not begin with a `#' then the standard shell
`/bin/sh' will be used to execute it.
This allows you to convert your older shell scripts to use
.I csh
at your convenience.
.NH 2
Variable substitution
.PP
After each input line is broken into words and history substitutions
are done on it, the input line is parsed into distinct commands.
Before each command is executed a mechanism know as
.I "variable substitution"
is done on these words.
Keyed by the character `$' this substitution replaces the names
of variables by their values.
Thus
.DS
echo $argv
.DE
when placed in a command script would cause the current value of the
variable
.I argv
to be echoed to the output of the shell script.
It is an error for
.I argv
to be unset at this point.
.PP
A number of notations are provided for accessing components and attributes
of variables.
The notation
.DS
$?name
.DE
expands to `1' if name is
.I set
or to `0'
if name is not
.I set.
It is the fundamental mechanism used for checking whether particular
variables have been assigned values.
All other forms of reference to undefined variables cause errors.
.PP
The notation
.DS
$#name
.DE
expands to the number of elements in the variable
.I name.
Thus
.DS
% set argv=(a b c)
% echo $?argv
1
% echo $#argv
3
% unset argv
% echo $?argv
0
% echo $argv
Undefined variable: argv.
%
.DE
.PP
It is also possible to access the components of a variable
which has several values.
Thus
.DS
$argv[1]
.DE
gives the first component of
.I argv
or in the example above `a'.
Similarly
.DS
$argv[$#argv]
.DE
would give `c',
and
.DS
$argv[1\-2]
.DE
would give `a b'. Other notations useful in shell scripts are
.DS
$\fIn\fR
.DE
where
.I n
is an integer as a shorthand for
.DS
$argv[\fIn\fR\|]
.DE
the
.I n\|th
parameter and
.DS
$*
.DE
which is a shorthand for
.DS
$argv
.DE
The form
.DS
$$
.DE
expands to the process number of the current shell.
Since this process number is unique in the system it can
be used in generation of unique temporary file names.
The form
.DS
$<
.DE
is quite special and is replaced by the next line of input read from
the shell's standard input (not the script it is reading). This is
useful for writing shell scripts that are interactive, reading
commands from the terminal, or even writing a shell script that
acts as a filter, reading lines from its input file. Thus the sequence
.DS
echo 'yes or no?\ec'
set a=($<)
.DE
would write out the prompt `yes or no?' without a newline and then
read the answer into the variable `a'. In this case `$#a' would be
`0' if either a blank line or end-of-file (^D) was typed.
.PP
One minor difference between `$\fIn\fR\|' and `$argv[\fIn\fR\|]'
should be noted here.
The form
`$argv[\fIn\fR\|]'
will yield an error if
.I n
is not in the range
`1\-$#argv'
while `$n'
will never yield an out of range subscript error.
This is for compatibility with the way older shells handled parameters.
.PP
Another important point is that it is never an error to give a subrange
of the form `n\-'; if there are less than
.I n
components of the given variable then no words are substituted.
A range of the form `m\-n' likewise returns an empty vector without giving
an error when \fIm\fR exceeds the number of elements of the given variable,
provided the subscript \fIn\fR is in range.
.NH 2
Expressions
.PP
In order for interesting shell scripts to be constructed it
must be possible to evaluate expressions in the shell based on the
values of variables.
In fact, all the arithmetic operations of the language C are available
in the shell
with the same precedence that they have in C.
In particular, the operations `==' and `!=' compare strings
and the operators `&&' and `|\|\||' implement the boolean and/or operations.
The special operators `=~' and `!~' are similar to `==' and `!=' except
that the string on the right side can have pattern matching characters
(like *, ? or []) and the test is whether the string on the left matches
the pattern on the right.
.PP
The shell also allows file enquiries of the form
.DS
\-? filename
.DE
where `?' is replace by a number of single characters.
For instance the expression primitive
.DS
\-e filename
.DE
tell whether the file
`filename'
exists.
Other primitives test for read, write and execute access to the file,
whether it is a directory, or has non-zero length.
.PP
It is possible to test whether a command terminates normally,
by a primitive of the
form `{ command }' which returns true, i.e. `1' if the command
succeeds exiting normally with exit status 0, or `0' if the command
terminates abnormally or with exit status non-zero.
If more detailed information about the execution status of a command
is required, it can be executed and the variable `$status' examined
in the next command.
Since `$status' is set by every command, it is very transient.
It can be saved if it is inconvenient to use it only in the single
immediately following command.
.PP
For a full list of expression components available see the manual
section for the shell.
.NH 2
Sample shell script
.PP
A sample shell script which makes use of the expression mechanism
of the shell and some of its control structure follows:
.DS
% cat copyc
#
# Copyc copies those C programs in the specified list
# to the directory ~/backup if they differ from the files
# already in ~/backup
#
.DE
.sp -1
.DS
set noglob
foreach i ($argv)
if ($i !~ *.c) continue # not a .c file so do nothing
if (! \-r ~/backup/$i:t) then
echo $i:t not in backup... not cp\e\'ed
continue
endif
cmp \-s $i ~/backup/$i:t # to set $status
if ($status != 0) then
echo new backup of $i
cp $i ~/backup/$i:t
endif
end
.DE
.PP
This script makes use of the
.I foreach
command, which causes the shell to execute the commands between the
.I foreach
and the matching
.I end
for each of the values given between `(' and `)' with the named
variable, in this case `i' set to successive values in the list.
Within this loop we may use the command
.I break
to stop executing the loop
and
.I continue
to prematurely terminate one iteration
and begin the next.
After the
.I foreach
loop the iteration variable
(\fIi\fR in this case)
has the value at the last iteration.
.PP
We set the variable
.I noglob
here to prevent filename expansion of the members of
.I argv.
This is a good idea, in general, if the arguments to a shell script
are filenames which have already been expanded or if the arguments
may contain filename expansion metacharacters.
It is also possible to quote each use of a `$' variable expansion,
but this is harder and less reliable.
.PP
The other control construct used here is a statement of the form
.DS
\fBif\fR ( expression ) \fBthen\fR
command
...
\fBendif\fR
.DE
The placement of the keywords here is
.B not
flexible due to the current implementation of the shell.\(dg
.FS
\(dgThe following two formats are not currently acceptable to the shell:
.sp
.in +5
.nf
\fBif\fR ( expression ) # \fBWon't work!\fR
\fBthen\fR
command
...
\fBendif\fR
.fi
.in -5
.sp
and
.sp
.in +5
.nf
\fBif\fR ( expression ) \fBthen\fR command \fBendif\fR # \fBWon't work\fR
.in -5
.fi
.FE
.PP
The shell does have another form of the if statement of the form
.DS
\fBif\fR ( expression ) \fBcommand\fR
.DE
which can be written
.DS
\fBif\fR ( expression ) \e
command
.DE
Here we have escaped the newline for the sake of appearance.
The command must not involve `\||\|', `&' or `;'
and must not be another control command.
The second form requires the final `\e' to
.B immediately
precede the end-of-line.
.PP
The more general
.I if
statements above also admit a sequence of
.I else\-if
pairs followed by a single
.I else
and an
.I endif,
e.g.:
.DS
\fBif\fR ( expression ) \fBthen\fR
commands
\fBelse\fR \fBif\fR (expression ) \fBthen\fR
commands
\&...
\fBelse\fR
commands
\fBendif\fR
.DE
.PP
Another important mechanism used in shell scripts is the `:' modifier.
We can use the modifier `:r' here to extract a root of a filename or
`:e' to extract the
.I extension.
Thus if the variable
.I i
has the value
`/mnt/foo.bar'
then
.sp
.in +5
.nf
% echo $i $i:r $i:e
/mnt/foo.bar /mnt/foo bar
%
.sp
.in -5
.fi
shows how the `:r' modifier strips off the trailing `.bar' and the
the `:e' modifier leaves only the `bar'.
Other modifiers will take off the last component of a pathname leaving
the head `:h' or all but the last component of a pathname leaving the
tail `:t'.
These modifiers are fully described in the
.I csh
manual pages in the User's Reference Manual.
It is also possible to use the
.I "command substitution"
mechanism described in the next major section to perform modifications
on strings to then reenter the shell's environment.
Since each usage of this mechanism involves the creation of a new process,
it is much more expensive to use than the `:' modification mechanism.\(dd
.FS
\(dd It is also important to note that
the current implementation of the shell limits the number of `:' modifiers
on a `$' substitution to 1.
Thus
.sp
.nf
.in +5
% echo $i $i:h:t
/a/b/c /a/b:t
%
.in -5
.fi
.sp
does not do what one would expect.
.FE
Finally, we note that the character `#' lexically introduces a shell
comment in shell scripts (but not from the terminal).
All subsequent characters on the input line after a `#' are discarded
by the shell.
This character can be quoted using `\'' or `\e' to place it in
an argument word.
.NH 2
Other control structures
.PP
The shell also has control structures
.I while
and
.I switch
similar to those of C.
These take the forms
.DS
\fBwhile\fR ( expression )
commands
\fBend\fR
.DE
and
.DS
\fBswitch\fR ( word )
\fBcase\fR str1:
commands
\fBbreaksw\fR
\& ...
\fBcase\fR strn:
commands
\fBbreaksw\fR
\fBdefault:\fR
commands
\fBbreaksw\fR
\fBendsw\fR
.DE
For details see the manual section for
.I csh.
C programmers should note that we use
.I breaksw
to exit from a
.I switch
while
.I break
exits a
.I while
or
.I foreach
loop.
A common mistake to make in
.I csh
scripts is to use
.I break
rather than
.I breaksw
in switches.
.PP
Finally,
.I csh
allows a
.I goto
statement, with labels looking like they do in C, i.e.:
.DS
loop:
commands
\fBgoto\fR loop
.DE
.NH 2
Supplying input to commands
.PP
Commands run from shell scripts receive by default the standard
input of the shell which is running the script.
This is different from previous shells running
under \s-2UNIX\s0. It allows shell scripts to fully participate
in pipelines, but mandates extra notation for commands which are to take
inline data.
.PP
Thus we need a metanotation for supplying inline data to commands in
shell scripts.
As an example, consider this script which runs the editor to
delete leading blanks from the lines in each argument file:
.DS
% cat deblank
# deblank \-\- remove leading blanks
foreach i ($argv)
ed \- $i << \'EOF\'
1,$s/^[ ]*//
w
q
\&\'EOF\'
end
%
.DE
The notation `<< \'EOF\''
means that the standard input for the
.I ed
command is to come from the text in the shell script file
up to the next line consisting of exactly `\'EOF\''.
The fact that the `EOF' is enclosed in `\'' characters, i.e. quoted,
causes the shell to not perform variable substitution on the
intervening lines.
In general, if any part of the word following the `<<' which the
shell uses to terminate the text to be given to the command is quoted
then these substitutions will not be performed.
In this case since we used the form `1,$' in our editor script
we needed to insure that this `$' was not variable substituted.
We could also have insured this by preceding the `$' here with a `\e',
i.e.:
.DS
1,\e$s/^[ ]*//
.DE
but quoting the `EOF' terminator is a more reliable way of achieving the
same thing.
.NH 2
Catching interrupts
.PP
If our shell script creates temporary files, we may wish to catch
interruptions of the shell script so that we can clean up
these files.
We can then do
.DS
onintr label
.DE
where
.I label
is a label in our program.
If an interrupt is received the shell will do a
`goto label'
and we can remove the temporary files and then do an
.I exit
command (which is built in to the shell)
to exit from the shell script.
If we wish to exit with a non-zero status we can do
.DS
exit(1)
.DE
e.g. to exit with status `1'.
.NH 2
What else?
.PP
There are other features of the shell useful to writers of shell
procedures.
The
.I verbose
and
.I echo
options and the related
.I \-v
and
.I \-x
command line options can be used to help trace the actions of the shell.
The
.I \-n
option causes the shell only to read commands and not to execute
them and may sometimes be of use.
.PP
One other thing to note is that
.I csh
will not execute shell scripts which do not begin with the
character `#', that is shell scripts that do not begin with a comment.
Similarly, the `/bin/sh' on your system may well defer to `csh'
to interpret shell scripts which begin with `#'.
This allows shell scripts for both shells to live in harmony.
.PP
There is also another quotation mechanism using `"' which allows
only some of the expansion mechanisms we have so far discussed to occur
on the quoted string and serves to make this string into a single word
as `\'' does.
+177
View File
@@ -0,0 +1,177 @@
.\" Copyright (c) 1980, 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.
.\"
.\" @(#)csh.4 8.2 (Berkeley) 5/16/94
.\"
.nr H1 3
.NH
Other, less commonly used, shell features
.NH 2
Loops at the terminal; variables as vectors
.PP
It is occasionally useful to use the
.I foreach
control structure at the terminal to aid in performing a number
of similar commands.
For instance, there were at one point three shells in use on the Cory \s-2UNIX\s0
system at Cory Hall,
`/bin/sh',
`/bin/nsh',
and
`/bin/csh'.
To count the number of persons using each shell one could have issued
the commands
.DS
% grep \-c csh$ /etc/passwd
27
% grep \-c nsh$ /etc/passwd
128
% grep \-c \-v sh$ /etc/passwd
430
%
.DE
Since these commands are very similar we can use
.I foreach
to do this more easily.
.DS
% foreach i (\'sh$\' \'csh$\' \'\-v sh$\')
? grep \-c $i /etc/passwd
? end
27
128
430
%
.DE
Note here that the shell prompts for
input with `? ' when reading the body of the loop.
.PP
Very useful with loops are variables which contain lists of filenames
or other words.
You can, for example, do
.DS
% set a=(\`ls\`)
% echo $a
csh.n csh.rm
% ls
csh.n
csh.rm
% echo $#a
2
%
.DE
The
.I set
command here gave the variable
.I a
a list of all the filenames in the current directory as value.
We can then iterate over these names to perform any chosen function.
.PP
The output of a command within `\`' characters is converted by
the shell to a list of words.
You can also place the `\`' quoted string within `"' characters
to take each (non-empty) line as a component of the variable;
preventing the lines from being split into words at blanks and tabs.
A modifier `:x' exists which can be used later to expand each component
of the variable into another variable splitting it into separate words
at embedded blanks and tabs.
.NH 2
Braces { ... } in argument expansion
.PP
Another form of filename expansion, alluded
to before involves the characters `{' and `}'.
These characters specify that the contained strings, separated by `,'
are to be consecutively substituted into the containing characters
and the results expanded left to right.
Thus
.DS
A{str1,str2,...strn}B
.DE
expands to
.DS
Astr1B Astr2B ... AstrnB
.DE
This expansion occurs before the other filename expansions, and may
be applied recursively (i.e. nested).
The results of each expanded string are sorted separately, left
to right order being preserved.
The resulting filenames are not required to exist if no other expansion
mechanisms are used.
This means that this mechanism can be used to generate arguments which are
not filenames, but which have common parts.
.PP
A typical use of this would be
.DS
mkdir ~/{hdrs,retrofit,csh}
.DE
to make subdirectories `hdrs', `retrofit' and `csh'
in your home directory.
This mechanism is most useful when the common prefix is longer
than in this example, i.e.
.DS
chown root /usr/{ucb/{ex,edit},lib/{ex?.?*,how_ex}}
.DE
.NH 2
Command substitution
.PP
A command enclosed in `\`' characters is replaced, just before
filenames are expanded, by the output from that command.
Thus it is possible to do
.DS
set pwd=\`pwd\`
.DE
to save the current directory in the variable
.I pwd
or to do
.DS
ex \`grep \-l TRACE *.c\`
.DE
to run the editor
.I ex
supplying as arguments those files whose names end in `.c'
which have the string `TRACE' in them.*
.FS
*Command expansion also occurs in input redirected with `<<'
and within `"' quotations.
Refer to the shell manual section for full details.
.FE
.NH 2
Other details not covered here
.PP
In particular circumstances it may be necessary to know the exact
nature and order of different substitutions performed by the shell.
The exact meaning of certain combinations of quotations is also
occasionally important.
These are detailed fully in its manual section.
.PP
The shell has a number of command line option flags mostly of use
in writing \s-2UNIX\s0 programs,
and debugging shell scripts.
See the csh(1) manual section for a list of these options.
+2185
View File
File diff suppressed because it is too large Load Diff
+1368
View File
File diff suppressed because it is too large Load Diff
+552
View File
@@ -0,0 +1,552 @@
/*-
* Copyright (c) 1980, 1991, 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.
*
* @(#)csh.h 8.2 (Berkeley) 4/29/95
*/
/*
* Fundamental definitions which may vary from system to system.
*
* BUFSIZ The i/o buffering size; also limits word size
* MAILINTVL How often to mailcheck; more often is more expensive
*/
#ifndef BUFSIZ
#define BUFSIZ 1024 /* default buffer size */
#endif /* BUFSIZ */
#define FORKSLEEP 10 /* delay loop on non-interactive fork failure */
#define MAILINTVL 600 /* 10 minutes */
/*
* The shell moves std in/out/diag and the old std input away from units
* 0, 1, and 2 so that it is easy to set up these standards for invoked
* commands.
*/
#define FSHTTY 15 /* /dev/tty when manip pgrps */
#define FSHIN 16 /* Preferred desc for shell input */
#define FSHOUT 17 /* ... shell output */
#define FSHERR 18 /* ... shell diagnostics */
#define FOLDSTD 19 /* ... old std input */
#ifdef PROF
#define xexit(n) done(n)
#endif
#ifdef SHORT_STRINGS
typedef short Char;
#define SAVE(a) (Strsave(str2short(a)))
#else
typedef char Char;
#define SAVE(a) (strsave(a))
#endif
/*
* Make sure a variable is not stored in a register by taking its address
* This is used where variables might be clobbered by longjmp.
*/
#define UNREGISTER(a) (void) &a
typedef void *ioctl_t; /* Third arg of ioctl */
typedef void *ptr_t;
#include "const.h"
#include "char.h"
#include "err.h"
#define xmalloc(i) Malloc(i)
#define xrealloc(p, i) Realloc(p, i)
#define xcalloc(n, s) Calloc(n, s)
#define xfree(p) Free(p)
#include <stdio.h>
FILE *cshin, *cshout, *csherr;
#define isdir(d) ((d.st_mode & S_IFMT) == S_IFDIR)
typedef int bool;
#define eq(a, b) (Strcmp(a, b) == 0)
/* globone() flags */
#define G_ERROR 0 /* default action: error if multiple words */
#define G_IGNORE 1 /* ignore the rest of the words */
#define G_APPEND 2 /* make a sentence by cat'ing the words */
/*
* Global flags
*/
bool chkstop; /* Warned of stopped jobs... allow exit */
bool didfds; /* Have setup i/o fd's for child */
bool doneinp; /* EOF indicator after reset from readc */
bool exiterr; /* Exit if error or non-zero exit status */
bool child; /* Child shell ... errors cause exit */
bool haderr; /* Reset was because of an error */
bool intty; /* Input is a tty */
bool intact; /* We are interactive... therefore prompt */
bool justpr; /* Just print because of :p hist mod */
bool loginsh; /* We are a loginsh -> .login/.logout */
bool neednote; /* Need to pnotify() */
bool noexec; /* Don't execute, just syntax check */
bool pjobs; /* want to print jobs if interrupted */
bool setintr; /* Set interrupts on/off -> Wait intr... */
bool timflg; /* Time the next waited for command */
bool havhash; /* path hashing is available */
#ifdef FILEC
bool filec; /* doing filename expansion */
#endif
/*
* Global i/o info
*/
Char *arginp; /* Argument input for sh -c and internal `xx` */
int onelflg; /* 2 -> need line for -t, 1 -> exit on read */
Char *ffile; /* Name of shell file for $0 */
char *seterr; /* Error message from scanner/parser */
Char *shtemp; /* Temp name for << shell files in /tmp */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
struct timeval time0; /* Time at which the shell started */
struct rusage ru0;
/*
* Miscellany
*/
Char *doldol; /* Character pid for $$ */
int backpid; /* Pid of the last background process */
int uid, euid; /* Invokers uid */
int gid, egid; /* Invokers gid */
time_t chktim; /* Time mail last checked */
int shpgrp; /* Pgrp of shell */
int tpgrp; /* Terminal process group */
/* If tpgrp is -1, leave tty alone! */
int opgrp; /* Initial pgrp and tty pgrp */
/*
* To be able to redirect i/o for builtins easily, the shell moves the i/o
* descriptors it uses away from 0,1,2.
* Ideally these should be in units which are closed across exec's
* (this saves work) but for version 6, this is not usually possible.
* The desired initial values for these descriptors are F{SHIN,...}.
*/
int SHIN; /* Current shell input (script) */
int SHOUT; /* Shell output */
int SHERR; /* Diagnostic output... shell errs go here */
int OLDSTD; /* Old standard input (def for cmds) */
/*
* Error control
*
* Errors in scanning and parsing set up an error message to be printed
* at the end and complete. Other errors always cause a reset.
* Because of source commands and .cshrc we need nested error catches.
*/
#include <setjmp.h>
jmp_buf reslab;
#define setexit() (setjmp(reslab))
#define reset() longjmp(reslab, 1)
/* Should use structure assignment here */
#define getexit(a) memmove((a), reslab, sizeof reslab)
#define resexit(a) memmove(reslab, (a), sizeof reslab)
Char *gointr; /* Label for an onintr transfer */
#include <signal.h>
sig_t parintr; /* Parents interrupt catch */
sig_t parterm; /* Parents terminate catch */
/*
* Lexical definitions.
*
* All lexical space is allocated dynamically.
* The eighth/sixteenth bit of characters is used to prevent recognition,
* and eventually stripped.
*/
#define META 0200
#define ASCII 0177
#ifdef SHORT_STRINGS
#define CHAR 0377
#define QUOTE 0100000 /* 16nth char bit used for 'ing */
#define TRIM 0077777 /* Mask to strip quote bit */
#else
#define CHAR 0177
#define QUOTE 0200 /* Eighth char bit used for 'ing */
#define TRIM 0177 /* Mask to strip quote bit */
#endif
int AsciiOnly; /* If set only 7 bits is expected in characters */
/*
* Each level of input has a buffered input structure.
* There are one or more blocks of buffered input for each level,
* exactly one if the input is seekable and tell is available.
* In other cases, the shell buffers enough blocks to keep all loops
* in the buffer.
*/
struct Bin {
off_t Bfseekp; /* Seek pointer */
off_t Bfbobp; /* Seekp of beginning of buffers */
off_t Bfeobp; /* Seekp of end of buffers */
int Bfblocks; /* Number of buffer blocks */
Char **Bfbuf; /* The array of buffer blocks */
} B;
/*
* This structure allows us to seek inside aliases
*/
struct Ain {
int type;
#define I_SEEK -1 /* Invalid seek */
#define A_SEEK 0 /* Alias seek */
#define F_SEEK 1 /* File seek */
#define E_SEEK 2 /* Eval seek */
union {
off_t _f_seek;
Char* _c_seek;
} fc;
#define f_seek fc._f_seek
#define c_seek fc._c_seek
Char **a_seek;
} ;
extern int aret; /* What was the last character returned */
#define SEEKEQ(a, b) ((a)->type == (b)->type && \
(a)->f_seek == (b)->f_seek && \
(a)->a_seek == (b)->a_seek)
#define fseekp B.Bfseekp
#define fbobp B.Bfbobp
#define feobp B.Bfeobp
#define fblocks B.Bfblocks
#define fbuf B.Bfbuf
/*
* The shell finds commands in loops by reseeking the input
* For whiles, in particular, it reseeks to the beginning of the
* line the while was on; hence the while placement restrictions.
*/
struct Ain lineloc;
bool cantell; /* Is current source tellable ? */
/*
* Input lines are parsed into doubly linked circular
* lists of words of the following form.
*/
struct wordent {
Char *word;
struct wordent *prev;
struct wordent *next;
};
/*
* During word building, both in the initial lexical phase and
* when expanding $ variable substitutions, expansion by `!' and `$'
* must be inhibited when reading ahead in routines which are themselves
* processing `!' and `$' expansion or after characters such as `\' or in
* quotations. The following flags are passed to the getC routines
* telling them which of these substitutions are appropriate for the
* next character to be returned.
*/
#define DODOL 1
#define DOEXCL 2
#define DOALL DODOL|DOEXCL
/*
* Labuf implements a general buffer for lookahead during lexical operations.
* Text which is to be placed in the input stream can be stuck here.
* We stick parsed ahead $ constructs during initial input,
* process id's from `$$', and modified variable values (from qualifiers
* during expansion in sh.dol.c) here.
*/
Char *lap;
/*
* Parser structure
*
* Each command is parsed to a tree of command structures and
* flags are set bottom up during this process, to be propagated down
* as needed during the semantics/exeuction pass (sh.sem.c).
*/
struct command {
short t_dtyp; /* Type of node */
#define NODE_COMMAND 1 /* t_dcom <t_dlef >t_drit */
#define NODE_PAREN 2 /* ( t_dspr ) <t_dlef >t_drit */
#define NODE_PIPE 3 /* t_dlef | t_drit */
#define NODE_LIST 4 /* t_dlef ; t_drit */
#define NODE_OR 5 /* t_dlef || t_drit */
#define NODE_AND 6 /* t_dlef && t_drit */
short t_dflg; /* Flags, e.g. F_AMPERSAND|... */
#define F_SAVE (F_NICE|F_TIME|F_NOHUP) /* save these when re-doing */
#define F_AMPERSAND (1<<0) /* executes in background */
#define F_APPEND (1<<1) /* output is redirected >> */
#define F_PIPEIN (1<<2) /* input is a pipe */
#define F_PIPEOUT (1<<3) /* output is a pipe */
#define F_NOFORK (1<<4) /* don't fork, last ()ized cmd */
#define F_NOINTERRUPT (1<<5) /* should be immune from intr's */
/* spare */
#define F_STDERR (1<<7) /* redirect unit 2 with unit 1 */
#define F_OVERWRITE (1<<8) /* output was ! */
#define F_READ (1<<9) /* input redirection is << */
#define F_REPEAT (1<<10) /* reexec aft if, repeat,... */
#define F_NICE (1<<11) /* t_nice is meaningful */
#define F_NOHUP (1<<12) /* nohup this command */
#define F_TIME (1<<13) /* time this command */
union {
Char *T_dlef; /* Input redirect word */
struct command *T_dcar; /* Left part of list/pipe */
} L;
union {
Char *T_drit; /* Output redirect word */
struct command *T_dcdr; /* Right part of list/pipe */
} R;
#define t_dlef L.T_dlef
#define t_dcar L.T_dcar
#define t_drit R.T_drit
#define t_dcdr R.T_dcdr
Char **t_dcom; /* Command/argument vector */
struct command *t_dspr; /* Pointer to ()'d subtree */
int t_nice;
};
/*
* These are declared here because they want to be
* initialized in sh.init.c (to allow them to be made readonly)
*/
extern struct biltins {
char *bname;
void (*bfunct) __P((Char **, struct command *));
short minargs, maxargs;
} bfunc[];
extern int nbfunc;
extern struct srch {
char *s_name;
short s_value;
} srchn[];
extern int nsrchn;
/*
* The keywords for the parser
*/
#define T_BREAK 0
#define T_BRKSW 1
#define T_CASE 2
#define T_DEFAULT 3
#define T_ELSE 4
#define T_END 5
#define T_ENDIF 6
#define T_ENDSW 7
#define T_EXIT 8
#define T_FOREACH 9
#define T_GOTO 10
#define T_IF 11
#define T_LABEL 12
#define T_LET 13
#define T_SET 14
#define T_SWITCH 15
#define T_TEST 16
#define T_THEN 17
#define T_WHILE 18
/*
* Structure defining the existing while/foreach loops at this
* source level. Loops are implemented by seeking back in the
* input. For foreach (fe), the word list is attached here.
*/
struct whyle {
struct Ain w_start; /* Point to restart loop */
struct Ain w_end; /* End of loop (0 if unknown) */
Char **w_fe, **w_fe0; /* Current/initial wordlist for fe */
Char *w_fename; /* Name for fe */
struct whyle *w_next; /* Next (more outer) loop */
} *whyles;
/*
* Variable structure
*
* Aliases and variables are stored in AVL balanced binary trees.
*/
struct varent {
Char **vec; /* Array of words which is the value */
Char *v_name; /* Name of variable/alias */
struct varent *v_link[3]; /* The links, see below */
int v_bal; /* Balance factor */
} shvhed, aliases;
#define v_left v_link[0]
#define v_right v_link[1]
#define v_parent v_link[2]
struct varent *adrof1();
#define adrof(v) adrof1(v, &shvhed)
#define value(v) value1(v, &shvhed)
/*
* The following are for interfacing redo substitution in
* aliases to the lexical routines.
*/
struct wordent *alhistp; /* Argument list (first) */
struct wordent *alhistt; /* Node after last in arg list */
Char **alvec, *alvecp; /* The (remnants of) alias vector */
/*
* Filename/command name expansion variables
*/
int gflag; /* After tglob -> is globbing needed? */
#define MAXVARLEN 30 /* Maximum number of char in a variable name */
/*
* Variables for filename expansion
*/
extern Char **gargv; /* Pointer to the (stack) arglist */
extern long gargc; /* Number args in gargv */
/*
* Variables for command expansion.
*/
extern Char **pargv; /* Pointer to the argv list space */
extern long pargc; /* Count of arguments in pargv */
Char *pargs; /* Pointer to start current word */
long pnleft; /* Number of chars left in pargs */
Char *pargcp; /* Current index into pargs */
/*
* History list
*
* Each history list entry contains an embedded wordlist
* from the scanner, a number for the event, and a reference count
* to aid in discarding old entries.
*
* Essentially "invisible" entries are put on the history list
* when history substitution includes modifiers, and thrown away
* at the next discarding since their event numbers are very negative.
*/
struct Hist {
struct wordent Hlex;
int Hnum;
int Href;
struct Hist *Hnext;
} Histlist;
struct wordent paraml; /* Current lexical word list */
int eventno; /* Next events number */
int lastev; /* Last event reference (default) */
Char HIST; /* history invocation character */
Char HISTSUB; /* auto-substitute character */
/*
* strings.h:
*/
#ifndef SHORT_STRINGS
#define Strchr(a, b) strchr(a, b)
#define Strrchr(a, b) strrchr(a, b)
#define Strcat(a, b) strcat(a, b)
#define Strncat(a, b, c) strncat(a, b, c)
#define Strcpy(a, b) strcpy(a, b)
#define Strncpy(a, b, c) strncpy(a, b, c)
#define Strlen(a) strlen(a)
#define Strcmp(a, b) strcmp(a, b)
#define Strncmp(a, b, c) strncmp(a, b, c)
#define Strspl(a, b) strspl(a, b)
#define Strsave(a) strsave(a)
#define Strend(a) strend(a)
#define Strstr(a, b) strstr(a, b)
#define str2short(a) (a)
#define blk2short(a) saveblk(a)
#define short2blk(a) saveblk(a)
#define short2str(a) strip(a)
#else
#define Strchr(a, b) s_strchr(a, b)
#define Strrchr(a, b) s_strrchr(a, b)
#define Strcat(a, b) s_strcat(a, b)
#define Strncat(a, b, c) s_strncat(a, b, c)
#define Strcpy(a, b) s_strcpy(a, b)
#define Strncpy(a, b, c) s_strncpy(a, b, c)
#define Strlen(a) s_strlen(a)
#define Strcmp(a, b) s_strcmp(a, b)
#define Strncmp(a, b, c) s_strncmp(a, b, c)
#define Strspl(a, b) s_strspl(a, b)
#define Strsave(a) s_strsave(a)
#define Strend(a) s_strend(a)
#define Strstr(a, b) s_strstr(a, b)
#endif
/*
* setname is a macro to save space (see sh.err.c)
*/
char *bname;
#define setname(a) (bname = (a))
Char *Vsav;
Char *Vdp;
Char *Vexpath;
char **Vt;
Char **evalvec;
Char *evalp;
/* word_chars is set by default to WORD_CHARS but can be overridden by
the worchars variable--if unset, reverts to WORD_CHARS */
Char *word_chars;
#define WORD_CHARS "*?_-.[]~=" /* default chars besides alnums in words */
Char *STR_SHELLPATH;
#include <paths.h>
#ifdef _PATH_BSHELL
Char *STR_BSHELL;
#endif
Char *STR_WORD_CHARS;
Char **STR_environ;
+930
View File
@@ -0,0 +1,930 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 4/29/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "dir.h"
#include "extern.h"
/* Directory management. */
static struct directory
*dfind __P((Char *));
static Char *dfollow __P((Char *));
static void printdirs __P((void));
static Char *dgoto __P((Char *));
static void dnewcwd __P((struct directory *));
static void dset __P((Char *));
struct directory dhead; /* "head" of loop */
int printd; /* force name to be printed */
static int dirflag = 0;
/*
* dinit - initialize current working directory
*/
void
dinit(hp)
Char *hp;
{
register char *tcp;
register Char *cp;
register struct directory *dp;
char path[MAXPATHLEN];
static char *emsg = "csh: Trying to start from \"%s\"\n";
/* Don't believe the login shell home, because it may be a symlink */
tcp = getcwd(path, MAXPATHLEN);
if (tcp == NULL || *tcp == '\0') {
(void) fprintf(csherr, "csh: %s\n", strerror(errno));
if (hp && *hp) {
tcp = short2str(hp);
if (chdir(tcp) == -1)
cp = NULL;
else
cp = hp;
(void) fprintf(csherr, emsg, vis_str(hp));
}
else
cp = NULL;
if (cp == NULL) {
(void) fprintf(csherr, emsg, "/");
if (chdir("/") == -1)
/* I am not even try to print an error message! */
xexit(1);
cp = SAVE("/");
}
}
else {
struct stat swd, shp;
/*
* See if $HOME is the working directory we got and use that
*/
if (hp && *hp &&
stat(tcp, &swd) != -1 && stat(short2str(hp), &shp) != -1 &&
swd.st_dev == shp.st_dev && swd.st_ino == shp.st_ino)
cp = hp;
else {
char *cwd;
/*
* use PWD if we have it (for subshells)
*/
if ((cwd = getenv("PWD")) != NULL) {
if (stat(cwd, &shp) != -1 && swd.st_dev == shp.st_dev &&
swd.st_ino == shp.st_ino)
tcp = cwd;
}
cp = dcanon(SAVE(tcp), STRNULL);
}
}
dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
dp->di_name = Strsave(cp);
dp->di_count = 0;
dhead.di_next = dhead.di_prev = dp;
dp->di_next = dp->di_prev = &dhead;
printd = 0;
dnewcwd(dp);
}
static void
dset(dp)
Char *dp;
{
/*
* Don't call set() directly cause if the directory contains ` or
* other junk characters glob will fail.
*/
register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
vec[0] = Strsave(dp);
vec[1] = 0;
setq(STRcwd, vec, &shvhed);
Setenv(STRPWD, dp);
}
#define DIR_LONG 1
#define DIR_VERT 2
#define DIR_LINE 4
static void
skipargs(v, str)
Char ***v;
char *str;
{
Char **n = *v, *s;
dirflag = 0;
for (n++; *n != NULL && (*n)[0] == '-'; n++)
for (s = &((*n)[1]); *s; s++)
switch (*s) {
case 'l':
dirflag |= DIR_LONG;
break;
case 'v':
dirflag |= DIR_VERT;
break;
case 'n':
dirflag |= DIR_LINE;
break;
default:
stderror(ERR_DIRUS, vis_str(**v), str);
break;
}
*v = n;
}
/*
* dodirs - list all directories in directory loop
*/
void
/*ARGSUSED*/
dodirs(v, t)
Char **v;
struct command *t;
{
skipargs(&v, "");
if (*v != NULL)
stderror(ERR_DIRUS, "dirs", "");
printdirs();
}
static void
printdirs()
{
register struct directory *dp;
Char *s, *hp = value(STRhome);
int idx, len, cur;
if (*hp == '\0')
hp = NULL;
dp = dcwd;
idx = 0;
cur = 0;
do {
if (dp == &dhead)
continue;
if (dirflag & DIR_VERT) {
(void) fprintf(cshout, "%d\t", idx++);
cur = 0;
}
if (!(dirflag & DIR_LONG) && hp != NULL && !eq(hp, STRslash) &&
(len = Strlen(hp), Strncmp(hp, dp->di_name, len) == 0) &&
(dp->di_name[len] == '\0' || dp->di_name[len] == '/'))
len = Strlen(s = (dp->di_name + len)) + 2;
else
len = Strlen(s = dp->di_name) + 1;
cur += len;
if ((dirflag & DIR_LINE) && cur >= 80 - 1 && len < 80) {
(void) fprintf(cshout, "\n");
cur = len;
}
(void) fprintf(cshout, s != dp->di_name ? "~%s%c" : "%s%c",
vis_str(s), (dirflag & DIR_VERT) ? '\n' : ' ');
} while ((dp = dp->di_prev) != dcwd);
if (!(dirflag & DIR_VERT))
(void) fprintf(cshout, "\n");
}
void
dtildepr(home, dir)
register Char *home, *dir;
{
if (!eq(home, STRslash) && prefix(home, dir))
(void) fprintf(cshout, "~%s", vis_str(dir + Strlen(home)));
else
(void) fprintf(cshout, "%s", vis_str(dir));
}
void
dtilde()
{
struct directory *d = dcwd;
do {
if (d == &dhead)
continue;
d->di_name = dcanon(d->di_name, STRNULL);
} while ((d = d->di_prev) != dcwd);
dset(dcwd->di_name);
}
/* dnormalize():
* If the name starts with . or .. then we might need to normalize
* it depending on the symbolic link flags
*/
Char *
dnormalize(cp)
Char *cp;
{
#define UC (unsigned char)
#define ISDOT(c) (UC(c)[0] == '.' && ((UC(c)[1] == '\0') || (UC(c)[1] == '/')))
#define ISDOTDOT(c) (UC(c)[0] == '.' && ISDOT(&((c)[1])))
if ((unsigned char) cp[0] == '/')
return (Strsave(cp));
if (adrof(STRignore_symlinks)) {
int dotdot = 0;
Char *dp, *cwd;
cwd = (Char *) xmalloc((size_t) ((Strlen(dcwd->di_name) + 3) *
sizeof(Char)));
(void) Strcpy(cwd, dcwd->di_name);
/*
* Ignore . and count ..'s
*/
while (*cp) {
if (ISDOT(cp)) {
if (*++cp)
cp++;
}
else if (ISDOTDOT(cp)) {
dotdot++;
cp += 2;
if (*cp)
cp++;
}
else
break;
}
while (dotdot > 0)
if ((dp = Strrchr(cwd, '/'))) {
*dp = '\0';
dotdot--;
}
else
break;
if (*cp) {
cwd[dotdot = Strlen(cwd)] = '/';
cwd[dotdot + 1] = '\0';
dp = Strspl(cwd, cp);
xfree((ptr_t) cwd);
return dp;
}
else {
if (!*cwd) {
cwd[0] = '/';
cwd[1] = '\0';
}
return cwd;
}
}
return Strsave(cp);
}
/*
* dochngd - implement chdir command.
*/
void
/*ARGSUSED*/
dochngd(v, t)
Char **v;
struct command *t;
{
register Char *cp;
register struct directory *dp;
skipargs(&v, " [<dir>]");
printd = 0;
if (*v == NULL) {
if ((cp = value(STRhome)) == NULL || *cp == 0)
stderror(ERR_NAME | ERR_NOHOMEDIR);
if (chdir(short2str(cp)) < 0)
stderror(ERR_NAME | ERR_CANTCHANGE);
cp = Strsave(cp);
}
else if (v[1] != NULL) {
stderror(ERR_NAME | ERR_TOOMANY);
/* NOTREACHED */
return;
}
else if ((dp = dfind(*v)) != 0) {
char *tmp;
printd = 1;
if (chdir(tmp = short2str(dp->di_name)) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
dcwd->di_prev->di_next = dcwd->di_next;
dcwd->di_next->di_prev = dcwd->di_prev;
dfree(dcwd);
dnewcwd(dp);
return;
}
else
cp = dfollow(*v);
dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
dp->di_name = cp;
dp->di_count = 0;
dp->di_next = dcwd->di_next;
dp->di_prev = dcwd->di_prev;
dp->di_prev->di_next = dp;
dp->di_next->di_prev = dp;
dfree(dcwd);
dnewcwd(dp);
}
static Char *
dgoto(cp)
Char *cp;
{
Char *dp;
if (*cp != '/') {
register Char *p, *q;
int cwdlen;
for (p = dcwd->di_name; *p++;)
continue;
if ((cwdlen = p - dcwd->di_name - 1) == 1) /* root */
cwdlen = 0;
for (p = cp; *p++;)
continue;
dp = (Char *) xmalloc((size_t)((cwdlen + (p - cp) + 1) * sizeof(Char)));
for (p = dp, q = dcwd->di_name; (*p++ = *q++) != '\0';)
continue;
if (cwdlen)
p[-1] = '/';
else
p--; /* don't add a / after root */
for (q = cp; (*p++ = *q++) != '\0';)
continue;
xfree((ptr_t) cp);
cp = dp;
dp += cwdlen;
}
else
dp = cp;
cp = dcanon(cp, dp);
return cp;
}
/*
* dfollow - change to arg directory; fall back on cdpath if not valid
*/
static Char *
dfollow(cp)
register Char *cp;
{
register Char *dp;
struct varent *c;
char ebuf[MAXPATHLEN];
int serrno;
cp = globone(cp, G_ERROR);
/*
* if we are ignoring symlinks, try to fix relatives now.
*/
dp = dnormalize(cp);
if (chdir(short2str(dp)) >= 0) {
xfree((ptr_t) cp);
return dgoto(dp);
}
else {
xfree((ptr_t) dp);
if (chdir(short2str(cp)) >= 0)
return dgoto(cp);
serrno = errno;
}
if (cp[0] != '/' && !prefix(STRdotsl, cp) && !prefix(STRdotdotsl, cp)
&& (c = adrof(STRcdpath))) {
Char **cdp;
register Char *p;
Char buf[MAXPATHLEN];
for (cdp = c->vec; *cdp; cdp++) {
for (dp = buf, p = *cdp; (*dp++ = *p++) != '\0';)
continue;
dp[-1] = '/';
for (p = cp; (*dp++ = *p++) != '\0';)
continue;
if (chdir(short2str(buf)) >= 0) {
printd = 1;
xfree((ptr_t) cp);
cp = Strsave(buf);
return dgoto(cp);
}
}
}
dp = value(cp);
if ((dp[0] == '/' || dp[0] == '.') && chdir(short2str(dp)) >= 0) {
xfree((ptr_t) cp);
cp = Strsave(dp);
printd = 1;
return dgoto(cp);
}
(void) strcpy(ebuf, short2str(cp));
xfree((ptr_t) cp);
stderror(ERR_SYSTEM, ebuf, strerror(serrno));
return (NULL);
}
/*
* dopushd - push new directory onto directory stack.
* with no arguments exchange top and second.
* with numeric argument (+n) bring it to top.
*/
void
/*ARGSUSED*/
dopushd(v, t)
Char **v;
struct command *t;
{
register struct directory *dp;
skipargs(&v, " [<dir>|+<n>]");
printd = 1;
if (*v == NULL) {
char *tmp;
if ((dp = dcwd->di_prev) == &dhead)
dp = dhead.di_prev;
if (dp == dcwd)
stderror(ERR_NAME | ERR_NODIR);
if (chdir(tmp = short2str(dp->di_name)) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
dp->di_prev->di_next = dp->di_next;
dp->di_next->di_prev = dp->di_prev;
dp->di_next = dcwd->di_next;
dp->di_prev = dcwd;
dcwd->di_next->di_prev = dp;
dcwd->di_next = dp;
}
else if (v[1] != NULL) {
stderror(ERR_NAME | ERR_TOOMANY);
/* NOTREACHED */
return;
}
else if ((dp = dfind(*v)) != NULL) {
char *tmp;
if (chdir(tmp = short2str(dp->di_name)) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
}
else {
register Char *ccp;
ccp = dfollow(*v);
dp = (struct directory *) xcalloc(sizeof(struct directory), 1);
dp->di_name = ccp;
dp->di_count = 0;
dp->di_prev = dcwd;
dp->di_next = dcwd->di_next;
dcwd->di_next = dp;
dp->di_next->di_prev = dp;
}
dnewcwd(dp);
}
/*
* dfind - find a directory if specified by numeric (+n) argument
*/
static struct directory *
dfind(cp)
register Char *cp;
{
register struct directory *dp;
register int i;
register Char *ep;
if (*cp++ != '+')
return (0);
for (ep = cp; Isdigit(*ep); ep++)
continue;
if (*ep)
return (0);
i = getn(cp);
if (i <= 0)
return (0);
for (dp = dcwd; i != 0; i--) {
if ((dp = dp->di_prev) == &dhead)
dp = dp->di_prev;
if (dp == dcwd)
stderror(ERR_NAME | ERR_DEEP);
}
return (dp);
}
/*
* dopopd - pop a directory out of the directory stack
* with a numeric argument just discard it.
*/
void
/*ARGSUSED*/
dopopd(v, t)
Char **v;
struct command *t;
{
register struct directory *dp, *p = NULL;
skipargs(&v, " [+<n>]");
printd = 1;
if (*v == NULL)
dp = dcwd;
else if (v[1] != NULL) {
stderror(ERR_NAME | ERR_TOOMANY);
/* NOTREACHED */
return;
}
else if ((dp = dfind(*v)) == 0)
stderror(ERR_NAME | ERR_BADDIR);
if (dp->di_prev == &dhead && dp->di_next == &dhead)
stderror(ERR_NAME | ERR_EMPTY);
if (dp == dcwd) {
char *tmp;
if ((p = dp->di_prev) == &dhead)
p = dhead.di_prev;
if (chdir(tmp = short2str(p->di_name)) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
}
dp->di_prev->di_next = dp->di_next;
dp->di_next->di_prev = dp->di_prev;
if (dp == dcwd)
dnewcwd(p);
else {
printdirs();
}
dfree(dp);
}
/*
* dfree - free the directory (or keep it if it still has ref count)
*/
void
dfree(dp)
register struct directory *dp;
{
if (dp->di_count != 0) {
dp->di_next = dp->di_prev = 0;
}
else {
xfree((char *) dp->di_name);
xfree((ptr_t) dp);
}
}
/*
* dcanon - canonicalize the pathname, removing excess ./ and ../ etc.
* we are of course assuming that the file system is standardly
* constructed (always have ..'s, directories have links)
*/
Char *
dcanon(cp, p)
register Char *cp, *p;
{
register Char *sp;
register Char *p1, *p2; /* general purpose */
bool slash;
Char link[MAXPATHLEN];
char tlink[MAXPATHLEN];
int cc;
Char *newcp;
/*
* christos: if the path given does not start with a slash prepend cwd. If
* cwd does not start with a path or the result would be too long abort().
*/
if (*cp != '/') {
Char tmpdir[MAXPATHLEN];
p1 = value(STRcwd);
if (p1 == NULL || *p1 != '/')
abort();
if (Strlen(p1) + Strlen(cp) + 1 >= MAXPATHLEN)
abort();
(void) Strcpy(tmpdir, p1);
(void) Strcat(tmpdir, STRslash);
(void) Strcat(tmpdir, cp);
xfree((ptr_t) cp);
cp = p = Strsave(tmpdir);
}
while (*p) { /* for each component */
sp = p; /* save slash address */
while (*++p == '/') /* flush extra slashes */
continue;
if (p != ++sp)
for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';)
continue;
p = sp; /* save start of component */
slash = 0;
while (*++p) /* find next slash or end of path */
if (*p == '/') {
slash = 1;
*p = 0;
break;
}
if (*sp == '\0') /* if component is null */
if (--sp == cp) /* if path is one char (i.e. /) */
break;
else
*sp = '\0';
else if (sp[0] == '.' && sp[1] == 0) {
if (slash) {
for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';)
continue;
p = --sp;
}
else if (--sp != cp)
*sp = '\0';
}
else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) {
/*
* We have something like "yyy/xxx/..", where "yyy" can be null or
* a path starting at /, and "xxx" is a single component. Before
* compressing "xxx/..", we want to expand "yyy/xxx", if it is a
* symbolic link.
*/
*--sp = 0; /* form the pathname for readlink */
if (sp != cp && !adrof(STRignore_symlinks) &&
(cc = readlink(short2str(cp), tlink,
sizeof tlink)) >= 0) {
(void) Strcpy(link, str2short(tlink));
link[cc] = '\0';
if (slash)
*p = '/';
/*
* Point p to the '/' in "/..", and restore the '/'.
*/
*(p = sp) = '/';
/*
* find length of p
*/
for (p1 = p; *p1++;)
continue;
if (*link != '/') {
/*
* Relative path, expand it between the "yyy/" and the
* "/..". First, back sp up to the character past "yyy/".
*/
while (*--sp != '/')
continue;
sp++;
*sp = 0;
/*
* New length is "yyy/" + link + "/.." and rest
*/
p1 = newcp = (Char *) xmalloc((size_t)
(((sp - cp) + cc + (p1 - p)) *
sizeof(Char)));
/*
* Copy new path into newcp
*/
for (p2 = cp; (*p1++ = *p2++) != '\0';)
continue;
for (p1--, p2 = link; (*p1++ = *p2++) != '\0';)
continue;
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
continue;
/*
* Restart canonicalization at expanded "/xxx".
*/
p = sp - cp - 1 + newcp;
}
else {
/*
* New length is link + "/.." and rest
*/
p1 = newcp = (Char *) xmalloc((size_t)
((cc + (p1 - p)) * sizeof(Char)));
/*
* Copy new path into newcp
*/
for (p2 = link; (*p1++ = *p2++) != '\0';)
continue;
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
continue;
/*
* Restart canonicalization at beginning
*/
p = newcp;
}
xfree((ptr_t) cp);
cp = newcp;
continue; /* canonicalize the link */
}
*sp = '/';
if (sp != cp)
while (*--sp != '/')
continue;
if (slash) {
for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';)
continue;
p = sp;
}
else if (cp == sp)
*++sp = '\0';
else
*sp = '\0';
}
else { /* normal dir name (not . or .. or nothing) */
if (sp != cp && adrof(STRchase_symlinks) &&
!adrof(STRignore_symlinks) &&
(cc = readlink(short2str(cp), tlink,
sizeof tlink)) >= 0) {
(void) Strcpy(link, str2short(tlink));
link[cc] = '\0';
/*
* restore the '/'.
*/
if (slash)
*p = '/';
/*
* point sp to p (rather than backing up).
*/
sp = p;
/*
* find length of p
*/
for (p1 = p; *p1++;)
continue;
if (*link != '/') {
/*
* Relative path, expand it between the "yyy/" and the
* remainder. First, back sp up to the character past
* "yyy/".
*/
while (*--sp != '/')
continue;
sp++;
*sp = 0;
/*
* New length is "yyy/" + link + "/.." and rest
*/
p1 = newcp = (Char *) xmalloc((size_t)
(((sp - cp) + cc + (p1 - p))
* sizeof(Char)));
/*
* Copy new path into newcp
*/
for (p2 = cp; (*p1++ = *p2++) != '\0';)
continue;
for (p1--, p2 = link; (*p1++ = *p2++) != '\0';)
continue;
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
continue;
/*
* Restart canonicalization at expanded "/xxx".
*/
p = sp - cp - 1 + newcp;
}
else {
/*
* New length is link + the rest
*/
p1 = newcp = (Char *) xmalloc((size_t)
((cc + (p1 - p)) * sizeof(Char)));
/*
* Copy new path into newcp
*/
for (p2 = link; (*p1++ = *p2++) != '\0';)
continue;
for (p1--, p2 = p; (*p1++ = *p2++) != '\0';)
continue;
/*
* Restart canonicalization at beginning
*/
p = newcp;
}
xfree((ptr_t) cp);
cp = newcp;
continue; /* canonicalize the link */
}
if (slash)
*p = '/';
}
}
/*
* fix home...
*/
p1 = value(STRhome);
cc = Strlen(p1);
/*
* See if we're not in a subdir of STRhome
*/
if (p1 && *p1 == '/' &&
(Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) {
static ino_t home_ino = -1;
static dev_t home_dev = -1;
static Char *home_ptr = NULL;
struct stat statbuf;
/*
* Get dev and ino of STRhome
*/
if (home_ptr != p1 &&
stat(short2str(p1), &statbuf) != -1) {
home_dev = statbuf.st_dev;
home_ino = statbuf.st_ino;
home_ptr = p1;
}
/*
* Start comparing dev & ino backwards
*/
p2 = Strcpy(link, cp);
for (sp = NULL; *p2 && stat(short2str(p2), &statbuf) != -1;) {
if (statbuf.st_dev == home_dev &&
statbuf.st_ino == home_ino) {
sp = (Char *) - 1;
break;
}
if ((sp = Strrchr(p2, '/')) != NULL)
*sp = '\0';
}
/*
* See if we found it
*/
if (*p2 && sp == (Char *) -1) {
/*
* Use STRhome to make '~' work
*/
newcp = Strspl(p1, cp + Strlen(p2));
xfree((ptr_t) cp);
cp = newcp;
}
}
return cp;
}
/*
* dnewcwd - make a new directory in the loop the current one
*/
static void
dnewcwd(dp)
register struct directory *dp;
{
dcwd = dp;
dset(dcwd->di_name);
if (printd && !(adrof(STRpushdsilent)))
printdirs();
}
+978
View File
@@ -0,0 +1,978 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)dol.c 8.2 (Berkeley) 4/29/95";
#endif /* not lint */
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "extern.h"
/*
* These routines perform variable substitution and quoting via ' and ".
* To this point these constructs have been preserved in the divided
* input words. Here we expand variables and turn quoting via ' and " into
* QUOTE bits on characters (which prevent further interpretation).
* If the `:q' modifier was applied during history expansion, then
* some QUOTEing may have occurred already, so we dont "trim()" here.
*/
static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
static Char *Dcp, **Dvp; /* Input vector for Dreadc */
#define DEOF -1
#define unDgetC(c) Dpeekc = c
#define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */
/*
* The following variables give the information about the current
* $ expansion, recording the current word position, the remaining
* words within this expansion, the count of remaining words, and the
* information about any : modifier which is being applied.
*/
#define MAXWLEN (BUFSIZ - 4)
#define MAXMOD MAXWLEN /* This cannot overflow */
static Char *dolp; /* Remaining chars from this word */
static Char **dolnxt; /* Further words */
static int dolcnt; /* Count of further words */
static Char dolmod[MAXMOD]; /* : modifier character */
static int dolnmod; /* Number of modifiers */
static int dolmcnt; /* :gx -> 10000, else 1 */
static int dolwcnt; /* :wx -> 10000, else 1 */
static void Dfix2 __P((Char **));
static Char *Dpack __P((Char *, Char *));
static int Dword __P((void));
static void dolerror __P((Char *));
static int DgetC __P((int));
static void Dgetdol __P((void));
static void fixDolMod __P((void));
static void setDolp __P((Char *));
static void unDredc __P((int));
static int Dredc __P((void));
static void Dtestq __P((int));
/*
* Fix up the $ expansions and quotations in the
* argument list to command t.
*/
void
Dfix(t)
register struct command *t;
{
register Char **pp;
register Char *p;
if (noexec)
return;
/* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
for (pp = t->t_dcom; (p = *pp++) != NULL;)
for (; *p; p++) {
if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */
Dfix2(t->t_dcom); /* found one */
blkfree(t->t_dcom);
t->t_dcom = gargv;
gargv = 0;
return;
}
}
}
/*
* $ substitute one word, for i/o redirection
*/
Char *
Dfix1(cp)
register Char *cp;
{
Char *Dv[2];
if (noexec)
return (0);
Dv[0] = cp;
Dv[1] = NULL;
Dfix2(Dv);
if (gargc != 1) {
setname(vis_str(cp));
stderror(ERR_NAME | ERR_AMBIG);
}
cp = Strsave(gargv[0]);
blkfree(gargv), gargv = 0;
return (cp);
}
/*
* Subroutine to do actual fixing after state initialization.
*/
static void
Dfix2(v)
Char **v;
{
ginit(); /* Initialize glob's area pointers */
Dvp = v;
Dcp = STRNULL; /* Setup input vector for Dreadc */
unDgetC(0);
unDredc(0); /* Clear out any old peeks (at error) */
dolp = 0;
dolcnt = 0; /* Clear out residual $ expands (...) */
while (Dword())
continue;
}
/*
* Pack up more characters in this word
*/
static Char *
Dpack(wbuf, wp)
Char *wbuf, *wp;
{
register int c;
register int i = MAXWLEN - (wp - wbuf);
for (;;) {
c = DgetC(DODOL);
if (c == '\\') {
c = DgetC(0);
if (c == DEOF) {
unDredc(c);
*wp = 0;
Gcat(STRNULL, wbuf);
return (NULL);
}
if (c == '\n')
c = ' ';
else
c |= QUOTE;
}
if (c == DEOF) {
unDredc(c);
*wp = 0;
Gcat(STRNULL, wbuf);
return (NULL);
}
if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */
unDgetC(c);
if (cmap(c, QUOTES))
return (wp);
*wp++ = 0;
Gcat(STRNULL, wbuf);
return (NULL);
}
if (--i <= 0)
stderror(ERR_WTOOLONG);
*wp++ = c;
}
}
/*
* Get a word. This routine is analogous to the routine
* word() in sh.lex.c for the main lexical input. One difference
* here is that we don't get a newline to terminate our expansion.
* Rather, DgetC will return a DEOF when we hit the end-of-input.
*/
static int
Dword()
{
register int c, c1;
Char wbuf[BUFSIZ];
register Char *wp = wbuf;
register int i = MAXWLEN;
register bool dolflg;
bool sofar = 0, done = 0;
while (!done) {
done = 1;
c = DgetC(DODOL);
switch (c) {
case DEOF:
if (sofar == 0)
return (0);
/* finish this word and catch the code above the next time */
unDredc(c);
/* fall into ... */
case '\n':
*wp = 0;
Gcat(STRNULL, wbuf);
return (1);
case ' ':
case '\t':
done = 0;
break;
case '`':
/* We preserve ` quotations which are done yet later */
*wp++ = c, --i;
case '\'':
case '"':
/*
* Note that DgetC never returns a QUOTES character from an
* expansion, so only true input quotes will get us here or out.
*/
c1 = c;
dolflg = c1 == '"' ? DODOL : 0;
for (;;) {
c = DgetC(dolflg);
if (c == c1)
break;
if (c == '\n' || c == DEOF)
stderror(ERR_UNMATCHED, c1);
if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
--wp, ++i;
if (--i <= 0)
stderror(ERR_WTOOLONG);
switch (c1) {
case '"':
/*
* Leave any `s alone for later. Other chars are all
* quoted, thus `...` can tell it was within "...".
*/
*wp++ = c == '`' ? '`' : c | QUOTE;
break;
case '\'':
/* Prevent all further interpretation */
*wp++ = c | QUOTE;
break;
case '`':
/* Leave all text alone for later */
*wp++ = c;
break;
default:
break;
}
}
if (c1 == '`')
*wp++ = '`' /* i--; eliminated */;
sofar = 1;
if ((wp = Dpack(wbuf, wp)) == NULL)
return (1);
else {
i = MAXWLEN - (wp - wbuf);
done = 0;
}
break;
case '\\':
c = DgetC(0); /* No $ subst! */
if (c == '\n' || c == DEOF) {
done = 0;
break;
}
c |= QUOTE;
break;
default:
break;
}
if (done) {
unDgetC(c);
sofar = 1;
if ((wp = Dpack(wbuf, wp)) == NULL)
return (1);
else {
i = MAXWLEN - (wp - wbuf);
done = 0;
}
}
}
/* Really NOTREACHED */
return (0);
}
/*
* Get a character, performing $ substitution unless flag is 0.
* Any QUOTES character which is returned from a $ expansion is
* QUOTEd so that it will not be recognized above.
*/
static int
DgetC(flag)
register int flag;
{
register int c;
top:
if ((c = Dpeekc) != '\0') {
Dpeekc = 0;
return (c);
}
if (lap) {
c = *lap++ & (QUOTE | TRIM);
if (c == 0) {
lap = 0;
goto top;
}
quotspec:
if (cmap(c, QUOTES))
return (c | QUOTE);
return (c);
}
if (dolp) {
if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
goto quotspec;
if (dolcnt > 0) {
setDolp(*dolnxt++);
--dolcnt;
return (' ');
}
dolp = 0;
}
if (dolcnt > 0) {
setDolp(*dolnxt++);
--dolcnt;
goto top;
}
c = Dredc();
if (c == '$' && flag) {
Dgetdol();
goto top;
}
return (c);
}
static Char *nulvec[] = {0};
static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
static void
dolerror(s)
Char *s;
{
setname(vis_str(s));
stderror(ERR_NAME | ERR_RANGE);
}
/*
* Handle the multitudinous $ expansion forms.
* Ugh.
*/
static void
Dgetdol()
{
register Char *np;
register struct varent *vp = NULL;
Char name[4 * MAXVARLEN + 1];
int c, sc;
int subscr = 0, lwb = 1, upb = 0;
bool dimen = 0, bitset = 0;
char tnp;
Char wbuf[BUFSIZ];
static Char *dolbang = NULL;
dolnmod = dolmcnt = dolwcnt = 0;
c = sc = DgetC(0);
if (c == '{')
c = DgetC(0); /* sc is { to take } later */
if ((c & TRIM) == '#')
dimen++, c = DgetC(0); /* $# takes dimension */
else if (c == '?')
bitset++, c = DgetC(0); /* $? tests existence */
switch (c) {
case '!':
if (dimen || bitset)
stderror(ERR_SYNTAX);
if (backpid != 0) {
if (dolbang)
xfree((ptr_t) dolbang);
setDolp(dolbang = putn(backpid));
}
goto eatbrac;
case '$':
if (dimen || bitset)
stderror(ERR_SYNTAX);
setDolp(doldol);
goto eatbrac;
case '<' | QUOTE:
if (bitset)
stderror(ERR_NOTALLOWED, "$?<");
if (dimen)
stderror(ERR_NOTALLOWED, "$?#");
for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
*np = (unsigned char) tnp;
if (np >= &wbuf[BUFSIZ - 1])
stderror(ERR_LTOOLONG);
if (tnp == '\n')
break;
}
*np = 0;
/*
* KLUDGE: dolmod is set here because it will cause setDolp to call
* domod and thus to copy wbuf. Otherwise setDolp would use it
* directly. If we saved it ourselves, no one would know when to free
* it. The actual function of the 'q' causes filename expansion not to
* be done on the interpolated value.
*/
dolmod[dolnmod++] = 'q';
dolmcnt = 10000;
setDolp(wbuf);
goto eatbrac;
case DEOF:
case '\n':
stderror(ERR_SYNTAX);
/* NOTREACHED */
break;
case '*':
(void) Strcpy(name, STRargv);
vp = adrof(STRargv);
subscr = -1; /* Prevent eating [...] */
break;
default:
np = name;
if (Isdigit(c)) {
if (dimen)
stderror(ERR_NOTALLOWED, "$#<num>");
subscr = 0;
do {
subscr = subscr * 10 + c - '0';
c = DgetC(0);
} while (Isdigit(c));
unDredc(c);
if (subscr < 0) {
dolerror(vp->v_name);
return;
}
if (subscr == 0) {
if (bitset) {
dolp = ffile ? STR1 : STR0;
goto eatbrac;
}
if (ffile == 0)
stderror(ERR_DOLZERO);
fixDolMod();
setDolp(ffile);
goto eatbrac;
}
if (bitset)
stderror(ERR_DOLQUEST);
vp = adrof(STRargv);
if (vp == 0) {
vp = &nulargv;
goto eatmod;
}
break;
}
if (!alnum(c))
stderror(ERR_VARALNUM);
for (;;) {
*np++ = c;
c = DgetC(0);
if (!alnum(c))
break;
if (np >= &name[MAXVARLEN])
stderror(ERR_VARTOOLONG);
}
*np++ = 0;
unDredc(c);
vp = adrof(name);
}
if (bitset) {
dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
goto eatbrac;
}
if (vp == 0) {
np = str2short(getenv(short2str(name)));
if (np) {
fixDolMod();
setDolp(np);
goto eatbrac;
}
udvar(name);
/* NOTREACHED */
}
c = DgetC(0);
upb = blklen(vp->vec);
if (dimen == 0 && subscr == 0 && c == '[') {
np = name;
for (;;) {
c = DgetC(DODOL); /* Allow $ expand within [ ] */
if (c == ']')
break;
if (c == '\n' || c == DEOF)
stderror(ERR_INCBR);
if (np >= &name[sizeof(name) / sizeof(Char) - 2])
stderror(ERR_VARTOOLONG);
*np++ = c;
}
*np = 0, np = name;
if (dolp || dolcnt) /* $ exp must end before ] */
stderror(ERR_EXPORD);
if (!*np)
stderror(ERR_SYNTAX);
if (Isdigit(*np)) {
int i;
for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
continue;
if ((i < 0 || i > upb) && !any("-*", *np)) {
dolerror(vp->v_name);
return;
}
lwb = i;
if (!*np)
upb = lwb, np = STRstar;
}
if (*np == '*')
np++;
else if (*np != '-')
stderror(ERR_MISSING, '-');
else {
register int i = upb;
np++;
if (Isdigit(*np)) {
i = 0;
while (Isdigit(*np))
i = i * 10 + *np++ - '0';
if (i < 0 || i > upb) {
dolerror(vp->v_name);
return;
}
}
if (i < lwb)
upb = lwb - 1;
else
upb = i;
}
if (lwb == 0) {
if (upb != 0) {
dolerror(vp->v_name);
return;
}
upb = -1;
}
if (*np)
stderror(ERR_SYNTAX);
}
else {
if (subscr > 0)
if (subscr > upb)
lwb = 1, upb = 0;
else
lwb = upb = subscr;
unDredc(c);
}
if (dimen) {
Char *cp = putn(upb - lwb + 1);
addla(cp);
xfree((ptr_t) cp);
}
else {
eatmod:
fixDolMod();
dolnxt = &vp->vec[lwb - 1];
dolcnt = upb - lwb + 1;
}
eatbrac:
if (sc == '{') {
c = Dredc();
if (c != '}')
stderror(ERR_MISSING, '}');
}
}
static void
fixDolMod()
{
register int c;
c = DgetC(0);
if (c == ':') {
do {
c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
if (c == 'g' || c == 'a') {
if (c == 'g')
dolmcnt = 10000;
else
dolwcnt = 10000;
c = DgetC(0);
}
if ((c == 'g' && dolmcnt != 10000) ||
(c == 'a' && dolwcnt != 10000)) {
if (c == 'g')
dolmcnt = 10000;
else
dolwcnt = 10000;
c = DgetC(0);
}
if (c == 's') { /* [eichin:19910926.0755EST] */
int delimcnt = 2;
int delim = DgetC(0);
dolmod[dolnmod++] = c;
dolmod[dolnmod++] = delim;
if (!delim || letter(delim)
|| Isdigit(delim) || any(" \t\n", delim)) {
seterror(ERR_BADSUBST);
break;
}
while ((c = DgetC(0)) != (-1)) {
dolmod[dolnmod++] = c;
if(c == delim) delimcnt--;
if(!delimcnt) break;
}
if(delimcnt) {
seterror(ERR_BADSUBST);
break;
}
continue;
}
if (!any("htrqxes", c))
stderror(ERR_BADMOD, c);
dolmod[dolnmod++] = c;
if (c == 'q')
dolmcnt = 10000;
}
while ((c = DgetC(0)) == ':');
unDredc(c);
}
else
unDredc(c);
}
static void
setDolp(cp)
register Char *cp;
{
register Char *dp;
int i;
if (dolnmod == 0 || dolmcnt == 0) {
dolp = cp;
return;
}
dp = cp = Strsave(cp);
for (i = 0; i < dolnmod; i++) {
/* handle s// [eichin:19910926.0510EST] */
if(dolmod[i] == 's') {
int delim;
Char *lhsub, *rhsub, *np;
size_t lhlen = 0, rhlen = 0;
int didmod = 0;
delim = dolmod[++i];
if (!delim || letter(delim)
|| Isdigit(delim) || any(" \t\n", delim)) {
seterror(ERR_BADSUBST);
break;
}
lhsub = &dolmod[++i];
while(dolmod[i] != delim && dolmod[++i]) {
lhlen++;
}
dolmod[i] = 0;
rhsub = &dolmod[++i];
while(dolmod[i] != delim && dolmod[++i]) {
rhlen++;
}
dolmod[i] = 0;
do {
dp = Strstr(cp, lhsub);
if (dp) {
np = (Char *) xmalloc((size_t)
((Strlen(cp) + 1 - lhlen + rhlen) *
sizeof(Char)));
(void) Strncpy(np, cp, dp - cp);
(void) Strcpy(np + (dp - cp), rhsub);
(void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
xfree((ptr_t) cp);
dp = cp = np;
didmod = 1;
} else {
/* should this do a seterror? */
break;
}
}
while (dolwcnt == 10000);
/*
* restore dolmod for additional words
*/
dolmod[i] = rhsub[-1] = delim;
if (didmod)
dolmcnt--;
else
break;
} else {
int didmod = 0;
do {
if ((dp = domod(cp, dolmod[i]))) {
didmod = 1;
if (Strcmp(cp, dp) == 0) {
xfree((ptr_t) cp);
cp = dp;
break;
}
else {
xfree((ptr_t) cp);
cp = dp;
}
}
else
break;
}
while (dolwcnt == 10000);
dp = cp;
if (didmod)
dolmcnt--;
else
break;
}
}
if (dp) {
addla(dp);
xfree((ptr_t) dp);
}
else
addla(cp);
dolp = STRNULL;
if (seterr)
stderror(ERR_OLD);
}
static void
unDredc(c)
int c;
{
Dpeekrd = c;
}
static int
Dredc()
{
register int c;
if ((c = Dpeekrd) != '\0') {
Dpeekrd = 0;
return (c);
}
if (Dcp && (c = *Dcp++))
return (c & (QUOTE | TRIM));
if (*Dvp == 0) {
Dcp = 0;
return (DEOF);
}
Dcp = *Dvp++;
return (' ');
}
static void
Dtestq(c)
register int c;
{
if (cmap(c, QUOTES))
gflag = 1;
}
/*
* Form a shell temporary file (in unit 0) from the words
* of the shell input up to EOF or a line the same as "term".
* Unit 0 should have been closed before this call.
*/
void
/*ARGSUSED*/
heredoc(term)
Char *term;
{
register int c;
Char *Dv[2];
Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
int ocnt, lcnt, mcnt;
register Char *lbp, *obp, *mbp;
Char **vp;
bool quoted;
char *tmp;
tmp = short2str(shtemp);
if (open(tmp, O_RDWR | O_CREAT | O_TRUNC, 0600) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
(void) unlink(tmp); /* 0 0 inode! */
Dv[0] = term;
Dv[1] = NULL;
gflag = 0;
trim(Dv);
rscan(Dv, Dtestq);
quoted = gflag;
ocnt = BUFSIZ;
obp = obuf;
for (;;) {
/*
* Read up a line
*/
lbp = lbuf;
lcnt = BUFSIZ - 4;
for (;;) {
c = readc(1); /* 1 -> Want EOF returns */
if (c < 0 || c == '\n')
break;
if ((c &= TRIM) != '\0') {
*lbp++ = c;
if (--lcnt < 0) {
setname("<<");
stderror(ERR_NAME | ERR_OVERFLOW);
}
}
}
*lbp = 0;
/*
* Check for EOF or compare to terminator -- before expansion
*/
if (c < 0 || eq(lbuf, term)) {
(void) write(0, short2str(obuf), (size_t) (BUFSIZ - ocnt));
(void) lseek(0, 0l, L_SET);
return;
}
/*
* If term was quoted or -n just pass it on
*/
if (quoted || noexec) {
*lbp++ = '\n';
*lbp = 0;
for (lbp = lbuf; (c = *lbp++) != '\0';) {
*obp++ = c;
if (--ocnt == 0) {
(void) write(0, short2str(obuf), BUFSIZ);
obp = obuf;
ocnt = BUFSIZ;
}
}
continue;
}
/*
* Term wasn't quoted so variable and then command expand the input
* line
*/
Dcp = lbuf;
Dvp = Dv + 1;
mbp = mbuf;
mcnt = BUFSIZ - 4;
for (;;) {
c = DgetC(DODOL);
if (c == DEOF)
break;
if ((c &= TRIM) == 0)
continue;
/* \ quotes \ $ ` here */
if (c == '\\') {
c = DgetC(0);
if (!any("$\\`", c))
unDgetC(c | QUOTE), c = '\\';
else
c |= QUOTE;
}
*mbp++ = c;
if (--mcnt == 0) {
setname("<<");
stderror(ERR_NAME | ERR_OVERFLOW);
}
}
*mbp++ = 0;
/*
* If any ` in line do command substitution
*/
mbp = mbuf;
if (any(short2str(mbp), '`')) {
/*
* 1 arg to dobackp causes substitution to be literal. Words are
* broken only at newlines so that all blanks and tabs are
* preserved. Blank lines (null words) are not discarded.
*/
vp = dobackp(mbuf, 1);
}
else
/* Setup trivial vector similar to return of dobackp */
Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
/*
* Resurrect the words from the command substitution each separated by
* a newline. Note that the last newline of a command substitution
* will have been discarded, but we put a newline after the last word
* because this represents the newline after the last input line!
*/
for (; *vp; vp++) {
for (mbp = *vp; *mbp; mbp++) {
*obp++ = *mbp & TRIM;
if (--ocnt == 0) {
(void) write(0, short2str(obuf), BUFSIZ);
obp = obuf;
ocnt = BUFSIZ;
}
}
*obp++ = '\n';
if (--ocnt == 0) {
(void) write(0, short2str(obuf), BUFSIZ);
obp = obuf;
ocnt = BUFSIZ;
}
}
if (pargv)
blkfree(pargv), pargv = 0;
}
}
+746
View File
@@ -0,0 +1,746 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)exec.c 8.3 (Berkeley) 5/23/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "extern.h"
/*
* System level search and execute of a command. We look in each directory
* for the specified command name. If the name contains a '/' then we
* execute only the full path name. If there is no search path then we
* execute only full path names.
*/
extern char **environ;
/*
* As we search for the command we note the first non-trivial error
* message for presentation to the user. This allows us often
* to show that a file has the wrong mode/no access when the file
* is not in the last component of the search path, so we must
* go on after first detecting the error.
*/
static char *exerr; /* Execution error message */
static Char *expath; /* Path for exerr */
/*
* Xhash is an array of HSHSIZ bits (HSHSIZ / 8 chars), which are used
* to hash execs. If it is allocated (havhash true), then to tell
* whether ``name'' is (possibly) present in the i'th component
* of the variable path, you look at the bit in xhash indexed by
* hash(hashname("name"), i). This is setup automatically
* after .login is executed, and recomputed whenever ``path'' is
* changed.
* The two part hash function is designed to let texec() call the
* more expensive hashname() only once and the simple hash() several
* times (once for each path component checked).
* Byte size is assumed to be 8.
*/
#define HSHSIZ 8192 /* 1k bytes */
#define HSHMASK (HSHSIZ - 1)
#define HSHMUL 243
static char xhash[HSHSIZ / 8];
#define hash(a, b) (((a) * HSHMUL + (b)) & HSHMASK)
#define bit(h, b) ((h)[(b) >> 3] & 1 << ((b) & 7)) /* bit test */
#define bis(h, b) ((h)[(b) >> 3] |= 1 << ((b) & 7)) /* bit set */
static int hits, misses;
/* Dummy search path for just absolute search when no path */
static Char *justabs[] = {STRNULL, 0};
static void pexerr __P((void));
static void texec __P((Char *, Char **));
static int hashname __P((Char *));
static void tellmewhat __P((struct wordent *));
static int executable __P((Char *, Char *, bool));
static int iscommand __P((Char *));
void
/*ARGSUSED*/
doexec(v, t)
Char **v;
struct command *t;
{
register Char *dp, **pv, **av, *sav;
register struct varent *pathv;
register bool slash;
register int hashval = 0, hashval1, i;
Char *blk[2];
sigset_t sigset;
/*
* Glob the command name. We will search $path even if this does something,
* as in sh but not in csh. One special case: if there is no PATH, then we
* execute only commands which start with '/'.
*/
blk[0] = t->t_dcom[0];
blk[1] = 0;
gflag = 0, tglob(blk);
if (gflag) {
pv = globall(blk);
if (pv == 0) {
setname(vis_str(blk[0]));
stderror(ERR_NAME | ERR_NOMATCH);
}
gargv = 0;
}
else
pv = saveblk(blk);
trim(pv);
exerr = 0;
expath = Strsave(pv[0]);
Vexpath = expath;
pathv = adrof(STRpath);
if (pathv == 0 && expath[0] != '/') {
blkfree(pv);
pexerr();
}
slash = any(short2str(expath), '/');
/*
* Glob the argument list, if necessary. Otherwise trim off the quote bits.
*/
gflag = 0;
av = &t->t_dcom[1];
tglob(av);
if (gflag) {
av = globall(av);
if (av == 0) {
blkfree(pv);
setname(vis_str(expath));
stderror(ERR_NAME | ERR_NOMATCH);
}
gargv = 0;
}
else
av = saveblk(av);
blkfree(t->t_dcom);
t->t_dcom = blkspl(pv, av);
xfree((ptr_t) pv);
xfree((ptr_t) av);
av = t->t_dcom;
trim(av);
if (*av == NULL || **av == '\0')
pexerr();
xechoit(av); /* Echo command if -x */
/*
* Since all internal file descriptors are set to close on exec, we don't
* need to close them explicitly here. Just reorient ourselves for error
* messages.
*/
SHIN = 0;
SHOUT = 1;
SHERR = 2;
OLDSTD = 0;
/*
* We must do this AFTER any possible forking (like `foo` in glob) so that
* this shell can still do subprocesses.
*/
sigemptyset(&sigset);
sigprocmask(SIG_SETMASK, &sigset, NULL);
/*
* If no path, no words in path, or a / in the filename then restrict the
* command search.
*/
if (pathv == 0 || pathv->vec[0] == 0 || slash)
pv = justabs;
else
pv = pathv->vec;
sav = Strspl(STRslash, *av);/* / command name for postpending */
Vsav = sav;
if (havhash)
hashval = hashname(*av);
i = 0;
hits++;
do {
/*
* Try to save time by looking at the hash table for where this command
* could be. If we are doing delayed hashing, then we put the names in
* one at a time, as the user enters them. This is kinda like Korn
* Shell's "tracked aliases".
*/
if (!slash && pv[0][0] == '/' && havhash) {
hashval1 = hash(hashval, i);
if (!bit(xhash, hashval1))
goto cont;
}
if (pv[0][0] == 0 || eq(pv[0], STRdot)) /* don't make ./xxx */
texec(*av, av);
else {
dp = Strspl(*pv, sav);
Vdp = dp;
texec(dp, av);
Vdp = 0;
xfree((ptr_t) dp);
}
misses++;
cont:
pv++;
i++;
} while (*pv);
hits--;
Vsav = 0;
xfree((ptr_t) sav);
pexerr();
}
static void
pexerr()
{
/* Couldn't find the damn thing */
if (expath) {
setname(vis_str(expath));
Vexpath = 0;
xfree((ptr_t) expath);
expath = 0;
}
else
setname("");
if (exerr)
stderror(ERR_NAME | ERR_STRING, exerr);
stderror(ERR_NAME | ERR_COMMAND);
}
/*
* Execute command f, arg list t.
* Record error message if not found.
* Also do shell scripts here.
*/
static void
texec(sf, st)
Char *sf;
register Char **st;
{
register char **t;
register char *f;
register struct varent *v;
register Char **vp;
Char *lastsh[2];
int fd;
unsigned char c;
Char *st0, **ost;
/* The order for the conversions is significant */
t = short2blk(st);
f = short2str(sf);
Vt = t;
errno = 0; /* don't use a previous error */
(void) execve(f, t, environ);
Vt = 0;
blkfree((Char **) t);
switch (errno) {
case ENOEXEC:
/*
* From: casper@fwi.uva.nl (Casper H.S. Dik) If we could not execute
* it, don't feed it to the shell if it looks like a binary!
*/
if ((fd = open(f, O_RDONLY)) != -1) {
if (read(fd, (char *) &c, 1) == 1) {
if (!Isprint(c) && (c != '\n' && c != '\t')) {
(void) close(fd);
/*
* We *know* what ENOEXEC means.
*/
stderror(ERR_ARCH, f, strerror(errno));
}
}
#ifdef _PATH_BSHELL
else
c = '#';
#endif
(void) close(fd);
}
/*
* If there is an alias for shell, then put the words of the alias in
* front of the argument list replacing the command name. Note no
* interpretation of the words at this point.
*/
v = adrof1(STRshell, &aliases);
if (v == 0) {
vp = lastsh;
vp[0] = adrof(STRshell) ? value(STRshell) : STR_SHELLPATH;
vp[1] = NULL;
#ifdef _PATH_BSHELL
if (fd != -1 && c != '#')
vp[0] = STR_BSHELL;
#endif
}
else
vp = v->vec;
st0 = st[0];
st[0] = sf;
ost = st;
st = blkspl(vp, st); /* Splice up the new arglst */
ost[0] = st0;
sf = *st;
/* The order for the conversions is significant */
t = short2blk(st);
f = short2str(sf);
xfree((ptr_t) st);
Vt = t;
(void) execve(f, t, environ);
Vt = 0;
blkfree((Char **) t);
/* The sky is falling, the sky is falling! */
case ENOMEM:
stderror(ERR_SYSTEM, f, strerror(errno));
case ENOENT:
break;
default:
if (exerr == 0) {
exerr = strerror(errno);
if (expath)
xfree((ptr_t) expath);
expath = Strsave(sf);
Vexpath = expath;
}
}
}
/*ARGSUSED*/
void
execash(t, kp)
Char **t;
register struct command *kp;
{
int saveIN, saveOUT, saveDIAG, saveSTD;
int oSHIN;
int oSHOUT;
int oSHERR;
int oOLDSTD;
jmp_buf osetexit;
int my_reenter;
int odidfds;
sig_t osigint, osigquit, osigterm;
if (chkstop == 0 && setintr)
panystop(0);
/*
* Hmm, we don't really want to do that now because we might
* fail, but what is the choice
*/
rechist();
osigint = signal(SIGINT, parintr);
osigquit = signal(SIGQUIT, parintr);
osigterm = signal(SIGTERM, parterm);
odidfds = didfds;
oSHIN = SHIN;
oSHOUT = SHOUT;
oSHERR = SHERR;
oOLDSTD = OLDSTD;
saveIN = dcopy(SHIN, -1);
saveOUT = dcopy(SHOUT, -1);
saveDIAG = dcopy(SHERR, -1);
saveSTD = dcopy(OLDSTD, -1);
lshift(kp->t_dcom, 1);
getexit(osetexit);
if ((my_reenter = setexit()) == 0) {
SHIN = dcopy(0, -1);
SHOUT = dcopy(1, -1);
SHERR = dcopy(2, -1);
didfds = 0;
doexec(t, kp);
}
(void) signal(SIGINT, osigint);
(void) signal(SIGQUIT, osigquit);
(void) signal(SIGTERM, osigterm);
doneinp = 0;
didfds = odidfds;
(void) close(SHIN);
(void) close(SHOUT);
(void) close(SHERR);
(void) close(OLDSTD);
SHIN = dmove(saveIN, oSHIN);
SHOUT = dmove(saveOUT, oSHOUT);
SHERR = dmove(saveDIAG, oSHERR);
OLDSTD = dmove(saveSTD, oOLDSTD);
resexit(osetexit);
if (my_reenter)
stderror(ERR_SILENT);
}
void
xechoit(t)
Char **t;
{
if (adrof(STRecho)) {
(void) fflush(csherr);
blkpr(csherr, t);
(void) fputc('\n', csherr);
}
}
void
/*ARGSUSED*/
dohash(v, t)
Char **v;
struct command *t;
{
DIR *dirp;
register struct dirent *dp;
register int cnt;
int i = 0;
struct varent *pathv = adrof(STRpath);
Char **pv;
int hashval;
havhash = 1;
for (cnt = 0; cnt < sizeof xhash; cnt++)
xhash[cnt] = 0;
if (pathv == 0)
return;
for (pv = pathv->vec; *pv; pv++, i++) {
if (pv[0][0] != '/')
continue;
dirp = opendir(short2str(*pv));
if (dirp == NULL)
continue;
while ((dp = readdir(dirp)) != NULL) {
if (dp->d_ino == 0)
continue;
if (dp->d_name[0] == '.' &&
(dp->d_name[1] == '\0' ||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
continue;
hashval = hash(hashname(str2short(dp->d_name)), i);
bis(xhash, hashval);
/* tw_add_comm_name (dp->d_name); */
}
(void) closedir(dirp);
}
}
void
/*ARGSUSED*/
dounhash(v, t)
Char **v;
struct command *t;
{
havhash = 0;
}
void
/*ARGSUSED*/
hashstat(v, t)
Char **v;
struct command *t;
{
if (hits + misses)
(void) fprintf(cshout, "%d hits, %d misses, %d%%\n",
hits, misses, 100 * hits / (hits + misses));
}
/*
* Hash a command name.
*/
static int
hashname(cp)
register Char *cp;
{
register long h = 0;
while (*cp)
h = hash(h, *cp++);
return ((int) h);
}
static int
iscommand(name)
Char *name;
{
register Char **pv;
register Char *sav;
register struct varent *v;
register bool slash = any(short2str(name), '/');
register int hashval = 0, hashval1, i;
v = adrof(STRpath);
if (v == 0 || v->vec[0] == 0 || slash)
pv = justabs;
else
pv = v->vec;
sav = Strspl(STRslash, name); /* / command name for postpending */
if (havhash)
hashval = hashname(name);
i = 0;
do {
if (!slash && pv[0][0] == '/' && havhash) {
hashval1 = hash(hashval, i);
if (!bit(xhash, hashval1))
goto cont;
}
if (pv[0][0] == 0 || eq(pv[0], STRdot)) { /* don't make ./xxx */
if (executable(NULL, name, 0)) {
xfree((ptr_t) sav);
return i + 1;
}
}
else {
if (executable(*pv, sav, 0)) {
xfree((ptr_t) sav);
return i + 1;
}
}
cont:
pv++;
i++;
} while (*pv);
xfree((ptr_t) sav);
return 0;
}
/* Also by:
* Andreas Luik <luik@isaak.isa.de>
* I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
* Azenberstr. 35
* D-7000 Stuttgart 1
* West-Germany
* is the executable() routine below and changes to iscommand().
* Thanks again!!
*/
/*
* executable() examines the pathname obtained by concatenating dir and name
* (dir may be NULL), and returns 1 either if it is executable by us, or
* if dir_ok is set and the pathname refers to a directory.
* This is a bit kludgy, but in the name of optimization...
*/
static int
executable(dir, name, dir_ok)
Char *dir, *name;
bool dir_ok;
{
struct stat stbuf;
Char path[MAXPATHLEN + 1], *dp, *sp;
char *strname;
if (dir && *dir) {
for (dp = path, sp = dir; *sp; *dp++ = *sp++)
if (dp == &path[MAXPATHLEN + 1]) {
*--dp = '\0';
break;
}
for (sp = name; *sp; *dp++ = *sp++)
if (dp == &path[MAXPATHLEN + 1]) {
*--dp = '\0';
break;
}
*dp = '\0';
strname = short2str(path);
}
else
strname = short2str(name);
return (stat(strname, &stbuf) != -1 &&
((S_ISREG(stbuf.st_mode) &&
/* save time by not calling access() in the hopeless case */
(stbuf.st_mode & (S_IXOTH | S_IXGRP | S_IXUSR)) &&
access(strname, X_OK) == 0) ||
(dir_ok && S_ISDIR(stbuf.st_mode))));
}
/* The dowhich() is by:
* Andreas Luik <luik@isaak.isa.de>
* I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung
* Azenberstr. 35
* D-7000 Stuttgart 1
* West-Germany
* Thanks!!
*/
/*ARGSUSED*/
void
dowhich(v, c)
register Char **v;
struct command *c;
{
struct wordent lex[3];
struct varent *vp;
lex[0].next = &lex[1];
lex[1].next = &lex[2];
lex[2].next = &lex[0];
lex[0].prev = &lex[2];
lex[1].prev = &lex[0];
lex[2].prev = &lex[1];
lex[0].word = STRNULL;
lex[2].word = STRret;
while (*++v) {
if ((vp = adrof1(*v, &aliases)) != NULL) {
(void) fprintf(cshout, "%s: \t aliased to ", vis_str(*v));
blkpr(cshout, vp->vec);
(void) fputc('\n', cshout);
}
else {
lex[1].word = *v;
tellmewhat(lex);
}
}
}
static void
tellmewhat(lex)
struct wordent *lex;
{
register int i;
register struct biltins *bptr;
register struct wordent *sp = lex->next;
bool aliased = 0;
Char *s0, *s1, *s2, *cmd;
Char qc;
if (adrof1(sp->word, &aliases)) {
alias(lex);
sp = lex->next;
aliased = 1;
}
s0 = sp->word; /* to get the memory freeing right... */
/* handle quoted alias hack */
if ((*(sp->word) & (QUOTE | TRIM)) == QUOTE)
(sp->word)++;
/* do quoting, if it hasn't been done */
s1 = s2 = sp->word;
while (*s2)
switch (*s2) {
case '\'':
case '"':
qc = *s2++;
while (*s2 && *s2 != qc)
*s1++ = *s2++ | QUOTE;
if (*s2)
s2++;
break;
case '\\':
if (*++s2)
*s1++ = *s2++ | QUOTE;
break;
default:
*s1++ = *s2++;
}
*s1 = '\0';
for (bptr = bfunc; bptr < &bfunc[nbfunc]; bptr++) {
if (eq(sp->word, str2short(bptr->bname))) {
if (aliased)
prlex(cshout, lex);
(void) fprintf(cshout, "%s: shell built-in command.\n",
vis_str(sp->word));
sp->word = s0; /* we save and then restore this */
return;
}
}
sp->word = cmd = globone(sp->word, G_IGNORE);
if ((i = iscommand(strip(sp->word))) != 0) {
register Char **pv;
register struct varent *v;
bool slash = any(short2str(sp->word), '/');
v = adrof(STRpath);
if (v == 0 || v->vec[0] == 0 || slash)
pv = justabs;
else
pv = v->vec;
while (--i)
pv++;
if (pv[0][0] == 0 || eq(pv[0], STRdot)) {
if (!slash) {
sp->word = Strspl(STRdotsl, sp->word);
prlex(cshout, lex);
xfree((ptr_t) sp->word);
}
else
prlex(cshout, lex);
sp->word = s0; /* we save and then restore this */
xfree((ptr_t) cmd);
return;
}
s1 = Strspl(*pv, STRslash);
sp->word = Strspl(s1, sp->word);
xfree((ptr_t) s1);
prlex(cshout, lex);
xfree((ptr_t) sp->word);
}
else {
if (aliased)
prlex(cshout, lex);
(void) fprintf(csherr, "%s: Command not found.\n", vis_str(sp->word));
}
sp->word = s0; /* we save and then restore this */
xfree((ptr_t) cmd);
}
+690
View File
@@ -0,0 +1,690 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)file.c 8.4 (Berkeley) 5/6/95";
#endif /* not lint */
#ifdef FILEC
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <termios.h>
#include <dirent.h>
#include <pwd.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef SHORT_STRINGS
#include <string.h>
#endif /* SHORT_STRINGS */
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "extern.h"
/*
* Tenex style file name recognition, .. and more.
* History:
* Author: Ken Greer, Sept. 1975, CMU.
* Finally got around to adding to the Cshell., Ken Greer, Dec. 1981.
*/
#define ON 1
#define OFF 0
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define ESC '\033'
typedef enum {
LIST, RECOGNIZE
} COMMAND;
static void setup_tty __P((int));
static void back_to_col_1 __P((void));
static void pushback __P((Char *));
static void catn __P((Char *, Char *, int));
static void copyn __P((Char *, Char *, int));
static Char filetype __P((Char *, Char *));
static void print_by_column __P((Char *, Char *[], int));
static Char *tilde __P((Char *, Char *));
static void retype __P((void));
static void beep __P((void));
static void print_recognized_stuff __P((Char *));
static void extract_dir_and_name __P((Char *, Char *, Char *));
static Char *getentry __P((DIR *, int));
static void free_items __P((Char **));
static int tsearch __P((Char *, COMMAND, int));
static int recognize __P((Char *, Char *, int, int));
static int is_prefix __P((Char *, Char *));
static int is_suffix __P((Char *, Char *));
static int ignored __P((Char *));
/*
* Put this here so the binary can be patched with adb to enable file
* completion by default. Filec controls completion, nobeep controls
* ringing the terminal bell on incomplete expansions.
*/
bool filec = 0;
static void
setup_tty(on)
int on;
{
static struct termios tchars;
(void) tcgetattr(SHIN, &tchars);
if (on) {
tchars.c_cc[VEOL] = ESC;
if (tchars.c_lflag & ICANON)
on = TCSANOW;
else {
on = TCSAFLUSH;
tchars.c_lflag |= ICANON;
}
}
else {
tchars.c_cc[VEOL] = _POSIX_VDISABLE;
on = TCSANOW;
}
(void) tcsetattr(SHIN, TCSANOW, &tchars);
}
/*
* Move back to beginning of current line
*/
static void
back_to_col_1()
{
struct termios tty, tty_normal;
sigset_t sigset, osigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_BLOCK, &sigset, &osigset);
(void) tcgetattr(SHOUT, &tty);
tty_normal = tty;
tty.c_iflag &= ~INLCR;
tty.c_oflag &= ~ONLCR;
(void) tcsetattr(SHOUT, TCSANOW, &tty);
(void) write(SHOUT, "\r", 1);
(void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
sigprocmask(SIG_SETMASK, &osigset, NULL);
}
/*
* Push string contents back into tty queue
*/
static void
pushback(string)
Char *string;
{
register Char *p;
struct termios tty, tty_normal;
sigset_t sigset, osigset;
char c;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_BLOCK, &sigset, &osigset);
(void) tcgetattr(SHOUT, &tty);
tty_normal = tty;
tty.c_lflag &= ~(ECHOKE | ECHO | ECHOE | ECHOK | ECHONL | ECHOPRT | ECHOCTL);
(void) tcsetattr(SHOUT, TCSANOW, &tty);
for (p = string; (c = *p) != '\0'; p++)
(void) ioctl(SHOUT, TIOCSTI, (ioctl_t) & c);
(void) tcsetattr(SHOUT, TCSANOW, &tty_normal);
sigprocmask(SIG_SETMASK, &osigset, NULL);
}
/*
* Concatenate src onto tail of des.
* Des is a string whose maximum length is count.
* Always null terminate.
*/
static void
catn(des, src, count)
register Char *des, *src;
register int count;
{
while (--count >= 0 && *des)
des++;
while (--count >= 0)
if ((*des++ = *src++) == 0)
return;
*des = '\0';
}
/*
* Like strncpy but always leave room for trailing \0
* and always null terminate.
*/
static void
copyn(des, src, count)
register Char *des, *src;
register int count;
{
while (--count >= 0)
if ((*des++ = *src++) == 0)
return;
*des = '\0';
}
static Char
filetype(dir, file)
Char *dir, *file;
{
Char path[MAXPATHLEN];
struct stat statb;
catn(Strcpy(path, dir), file, sizeof(path) / sizeof(Char));
if (lstat(short2str(path), &statb) == 0) {
switch (statb.st_mode & S_IFMT) {
case S_IFDIR:
return ('/');
case S_IFLNK:
if (stat(short2str(path), &statb) == 0 && /* follow it out */
S_ISDIR(statb.st_mode))
return ('>');
else
return ('@');
case S_IFSOCK:
return ('=');
default:
if (statb.st_mode & 0111)
return ('*');
}
}
return (' ');
}
static struct winsize win;
/*
* Print sorted down columns
*/
static void
print_by_column(dir, items, count)
Char *dir, *items[];
int count;
{
register int i, rows, r, c, maxwidth = 0, columns;
if (ioctl(SHOUT, TIOCGWINSZ, (ioctl_t) & win) < 0 || win.ws_col == 0)
win.ws_col = 80;
for (i = 0; i < count; i++)
maxwidth = maxwidth > (r = Strlen(items[i])) ? maxwidth : r;
maxwidth += 2; /* for the file tag and space */
columns = win.ws_col / maxwidth;
if (columns == 0)
columns = 1;
rows = (count + (columns - 1)) / columns;
for (r = 0; r < rows; r++) {
for (c = 0; c < columns; c++) {
i = c * rows + r;
if (i < count) {
register int w;
(void) fprintf(cshout, "%s", vis_str(items[i]));
(void) fputc(dir ? filetype(dir, items[i]) : ' ', cshout);
if (c < columns - 1) { /* last column? */
w = Strlen(items[i]) + 1;
for (; w < maxwidth; w++)
(void) fputc(' ', cshout);
}
}
}
(void) fputc('\r', cshout);
(void) fputc('\n', cshout);
}
}
/*
* Expand file name with possible tilde usage
* ~person/mumble
* expands to
* home_directory_of_person/mumble
*/
static Char *
tilde(new, old)
Char *new, *old;
{
register Char *o, *p;
register struct passwd *pw;
static Char person[40];
if (old[0] != '~')
return (Strcpy(new, old));
for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++)
continue;
*p = '\0';
if (person[0] == '\0')
(void) Strcpy(new, value(STRhome));
else {
pw = getpwnam(short2str(person));
if (pw == NULL)
return (NULL);
(void) Strcpy(new, str2short(pw->pw_dir));
}
(void) Strcat(new, o);
return (new);
}
/*
* Cause pending line to be printed
*/
static void
retype()
{
struct termios tty;
(void) tcgetattr(SHOUT, &tty);
tty.c_lflag |= PENDIN;
(void) tcsetattr(SHOUT, TCSANOW, &tty);
}
static void
beep()
{
if (adrof(STRnobeep) == 0)
(void) write(SHOUT, "\007", 1);
}
/*
* Erase that silly ^[ and
* print the recognized part of the string
*/
static void
print_recognized_stuff(recognized_part)
Char *recognized_part;
{
/* An optimized erasing of that silly ^[ */
(void) fputc('\b', cshout);
(void) fputc('\b', cshout);
switch (Strlen(recognized_part)) {
case 0: /* erase two Characters: ^[ */
(void) fputc(' ', cshout);
(void) fputc(' ', cshout);
(void) fputc('\b', cshout);
(void) fputc('\b', cshout);
break;
case 1: /* overstrike the ^, erase the [ */
(void) fprintf(cshout, "%s", vis_str(recognized_part));
(void) fputc(' ', cshout);
(void) fputc('\b', cshout);
break;
default: /* overstrike both Characters ^[ */
(void) fprintf(cshout, "%s", vis_str(recognized_part));
break;
}
(void) fflush(cshout);
}
/*
* Parse full path in file into 2 parts: directory and file names
* Should leave final slash (/) at end of dir.
*/
static void
extract_dir_and_name(path, dir, name)
Char *path, *dir, *name;
{
register Char *p;
p = Strrchr(path, '/');
if (p == NULL) {
copyn(name, path, MAXNAMLEN);
dir[0] = '\0';
}
else {
copyn(name, ++p, MAXNAMLEN);
copyn(dir, path, p - path);
}
}
static Char *
getentry(dir_fd, looking_for_lognames)
DIR *dir_fd;
int looking_for_lognames;
{
register struct passwd *pw;
register struct dirent *dirp;
if (looking_for_lognames) {
if ((pw = getpwent()) == NULL)
return (NULL);
return (str2short(pw->pw_name));
}
if ((dirp = readdir(dir_fd)) != NULL)
return (str2short(dirp->d_name));
return (NULL);
}
static void
free_items(items)
register Char **items;
{
register int i;
for (i = 0; items[i]; i++)
xfree((ptr_t) items[i]);
xfree((ptr_t) items);
}
#define FREE_ITEMS(items) { \
sigset_t sigset, osigset;\
\
sigemptyset(&sigset);\
sigaddset(&sigset, SIGINT);\
sigprocmask(SIG_BLOCK, &sigset, &osigset);\
free_items(items);\
items = NULL;\
sigprocmask(SIG_SETMASK, &osigset, NULL);\
}
/*
* Perform a RECOGNIZE or LIST command on string "word".
*/
static int
tsearch(word, command, max_word_length)
Char *word;
COMMAND command;
int max_word_length;
{
static Char **items = NULL;
register DIR *dir_fd;
register numitems = 0, ignoring = TRUE, nignored = 0;
register name_length, looking_for_lognames;
Char tilded_dir[MAXPATHLEN + 1], dir[MAXPATHLEN + 1];
Char name[MAXNAMLEN + 1], extended_name[MAXNAMLEN + 1];
Char *entry;
#define MAXITEMS 1024
if (items != NULL)
FREE_ITEMS(items);
looking_for_lognames = (*word == '~') && (Strchr(word, '/') == NULL);
if (looking_for_lognames) {
(void) setpwent();
copyn(name, &word[1], MAXNAMLEN); /* name sans ~ */
dir_fd = NULL;
}
else {
extract_dir_and_name(word, dir, name);
if (tilde(tilded_dir, dir) == 0)
return (0);
dir_fd = opendir(*tilded_dir ? short2str(tilded_dir) : ".");
if (dir_fd == NULL)
return (0);
}
again: /* search for matches */
name_length = Strlen(name);
for (numitems = 0; (entry = getentry(dir_fd, looking_for_lognames)) != NULL;) {
if (!is_prefix(name, entry))
continue;
/* Don't match . files on null prefix match */
if (name_length == 0 && entry[0] == '.' &&
!looking_for_lognames)
continue;
if (command == LIST) {
if (numitems >= MAXITEMS) {
(void) fprintf(csherr, "\nYikes!! Too many %s!!\n",
looking_for_lognames ?
"names in password file" : "files");
break;
}
if (items == NULL)
items = (Char **) xcalloc(sizeof(items[0]), MAXITEMS);
items[numitems] = (Char *) xmalloc((size_t) (Strlen(entry) + 1) *
sizeof(Char));
copyn(items[numitems], entry, MAXNAMLEN);
numitems++;
}
else { /* RECOGNIZE command */
if (ignoring && ignored(entry))
nignored++;
else if (recognize(extended_name,
entry, name_length, ++numitems))
break;
}
}
if (ignoring && numitems == 0 && nignored > 0) {
ignoring = FALSE;
nignored = 0;
if (looking_for_lognames)
(void) setpwent();
else
rewinddir(dir_fd);
goto again;
}
if (looking_for_lognames)
(void) endpwent();
else
(void) closedir(dir_fd);
if (numitems == 0)
return (0);
if (command == RECOGNIZE) {
if (looking_for_lognames)
copyn(word, STRtilde, 1);
else
/* put back dir part */
copyn(word, dir, max_word_length);
/* add extended name */
catn(word, extended_name, max_word_length);
return (numitems);
}
else { /* LIST */
qsort((ptr_t) items, numitems, sizeof(items[0]),
(int (*) __P((const void *, const void *))) sortscmp);
print_by_column(looking_for_lognames ? NULL : tilded_dir,
items, numitems);
if (items != NULL)
FREE_ITEMS(items);
}
return (0);
}
/*
* Object: extend what user typed up to an ambiguity.
* Algorithm:
* On first match, copy full entry (assume it'll be the only match)
* On subsequent matches, shorten extended_name to the first
* Character mismatch between extended_name and entry.
* If we shorten it back to the prefix length, stop searching.
*/
static int
recognize(extended_name, entry, name_length, numitems)
Char *extended_name, *entry;
int name_length, numitems;
{
if (numitems == 1) /* 1st match */
copyn(extended_name, entry, MAXNAMLEN);
else { /* 2nd & subsequent matches */
register Char *x, *ent;
register int len = 0;
x = extended_name;
for (ent = entry; *x && *x == *ent++; x++, len++)
continue;
*x = '\0'; /* Shorten at 1st Char diff */
if (len == name_length) /* Ambiguous to prefix? */
return (-1); /* So stop now and save time */
}
return (0);
}
/*
* Return true if check matches initial Chars in template.
* This differs from PWB imatch in that if check is null
* it matches anything.
*/
static int
is_prefix(check, template)
register Char *check, *template;
{
do
if (*check == 0)
return (TRUE);
while (*check++ == *template++);
return (FALSE);
}
/*
* Return true if the Chars in template appear at the
* end of check, I.e., are it's suffix.
*/
static int
is_suffix(check, template)
Char *check, *template;
{
register Char *c, *t;
for (c = check; *c++;)
continue;
for (t = template; *t++;)
continue;
for (;;) {
if (t == template)
return 1;
if (c == check || *--t != *--c)
return 0;
}
}
int
tenex(inputline, inputline_size)
Char *inputline;
int inputline_size;
{
register int numitems, num_read;
char tinputline[BUFSIZ];
setup_tty(ON);
while ((num_read = read(SHIN, tinputline, BUFSIZ)) > 0) {
int i;
static Char delims[] = {' ', '\'', '"', '\t', ';', '&', '<',
'>', '(', ')', '|', '^', '%', '\0'};
register Char *str_end, *word_start, last_Char, should_retype;
register int space_left;
COMMAND command;
for (i = 0; i < num_read; i++)
inputline[i] = (unsigned char) tinputline[i];
last_Char = inputline[num_read - 1] & ASCII;
if (last_Char == '\n' || num_read == inputline_size)
break;
command = (last_Char == ESC) ? RECOGNIZE : LIST;
if (command == LIST)
(void) fputc('\n', cshout);
str_end = &inputline[num_read];
if (last_Char == ESC)
--str_end; /* wipeout trailing cmd Char */
*str_end = '\0';
/*
* Find LAST occurence of a delimiter in the inputline. The word start
* is one Character past it.
*/
for (word_start = str_end; word_start > inputline; --word_start)
if (Strchr(delims, word_start[-1]))
break;
space_left = inputline_size - (word_start - inputline) - 1;
numitems = tsearch(word_start, command, space_left);
if (command == RECOGNIZE) {
/* print from str_end on */
print_recognized_stuff(str_end);
if (numitems != 1) /* Beep = No match/ambiguous */
beep();
}
/*
* Tabs in the input line cause trouble after a pushback. tty driver
* won't backspace over them because column positions are now
* incorrect. This is solved by retyping over current line.
*/
should_retype = FALSE;
if (Strchr(inputline, '\t')) { /* tab Char in input line? */
back_to_col_1();
should_retype = TRUE;
}
if (command == LIST) /* Always retype after a LIST */
should_retype = TRUE;
if (should_retype)
printprompt();
pushback(inputline);
if (should_retype)
retype();
}
setup_tty(OFF);
return (num_read);
}
static int
ignored(entry)
register Char *entry;
{
struct varent *vp;
register Char **cp;
if ((vp = adrof(STRfignore)) == NULL || (cp = vp->vec) == NULL)
return (FALSE);
for (; *cp != NULL; cp++)
if (is_suffix(entry, *cp))
return (TRUE);
return (FALSE);
}
#endif /* FILEC */
+1517
View File
File diff suppressed because it is too large Load Diff
+188
View File
@@ -0,0 +1,188 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)hist.c 8.2 (Berkeley) 3/22/95";
#endif /* not lint */
#include <sys/types.h>
#include <stdlib.h>
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "extern.h"
static void hfree __P((struct Hist *));
static void dohist1 __P((struct Hist *, int *, int, int));
static void phist __P((struct Hist *, int));
void
savehist(sp)
struct wordent *sp;
{
register struct Hist *hp, *np;
register int histlen = 0;
Char *cp;
/* throw away null lines */
if (sp->next->word[0] == '\n')
return;
cp = value(STRhistory);
if (*cp) {
register Char *p = cp;
while (*p) {
if (!Isdigit(*p)) {
histlen = 0;
break;
}
histlen = histlen * 10 + *p++ - '0';
}
}
for (hp = &Histlist; (np = hp->Hnext) != NULL;)
if (eventno - np->Href >= histlen || histlen == 0)
hp->Hnext = np->Hnext, hfree(np);
else
hp = np;
(void) enthist(++eventno, sp, 1);
}
struct Hist *
enthist(event, lp, docopy)
int event;
register struct wordent *lp;
bool docopy;
{
register struct Hist *np;
np = (struct Hist *) xmalloc((size_t) sizeof(*np));
np->Hnum = np->Href = event;
if (docopy) {
copylex(&np->Hlex, lp);
}
else {
np->Hlex.next = lp->next;
lp->next->prev = &np->Hlex;
np->Hlex.prev = lp->prev;
lp->prev->next = &np->Hlex;
}
np->Hnext = Histlist.Hnext;
Histlist.Hnext = np;
return (np);
}
static void
hfree(hp)
register struct Hist *hp;
{
freelex(&hp->Hlex);
xfree((ptr_t) hp);
}
void
/*ARGSUSED*/
dohist(v, t)
Char **v;
struct command *t;
{
int n, rflg = 0, hflg = 0;
sigset_t sigset;
if (getn(value(STRhistory)) == 0)
return;
if (setintr) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
while (*++v && **v == '-') {
Char *vp = *v;
while (*++vp)
switch (*vp) {
case 'h':
hflg++;
break;
case 'r':
rflg++;
break;
case '-': /* ignore multiple '-'s */
break;
default:
stderror(ERR_HISTUS);
break;
}
}
if (*v)
n = getn(*v);
else {
n = getn(value(STRhistory));
}
dohist1(Histlist.Hnext, &n, rflg, hflg);
}
static void
dohist1(hp, np, rflg, hflg)
struct Hist *hp;
int *np, rflg, hflg;
{
bool print = (*np) > 0;
for (; hp != 0; hp = hp->Hnext) {
(*np)--;
hp->Href++;
if (rflg == 0) {
dohist1(hp->Hnext, np, rflg, hflg);
if (print)
phist(hp, hflg);
return;
}
if (*np >= 0)
phist(hp, hflg);
}
}
static void
phist(hp, hflg)
register struct Hist *hp;
int hflg;
{
if (hflg == 0)
(void) fprintf(cshout, "%6d\t", hp->Hnum);
prlex(cshout, &hp->Hlex);
}
+1639
View File
File diff suppressed because it is too large Load Diff
+1379
View File
File diff suppressed because it is too large Load Diff
+653
View File
@@ -0,0 +1,653 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)sem.c 8.3 (Berkeley) 4/29/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "proc.h"
#include "extern.h"
static void vffree __P((int));
static Char *splicepipe __P((struct command *t, Char *));
static void doio __P((struct command *t, int *, int *));
static void chkclob __P((char *));
void
execute(t, wanttty, pipein, pipeout)
register struct command *t;
int wanttty, *pipein, *pipeout;
{
bool forked = 0;
struct biltins *bifunc;
int pid = 0;
int pv[2];
sigset_t sigset;
static sigset_t csigset;
static sigset_t ocsigset;
static int onosigchld = 0;
static int nosigchld = 0;
UNREGISTER(forked);
UNREGISTER(bifunc);
UNREGISTER(wanttty);
if (t == 0)
return;
if (t->t_dflg & F_AMPERSAND)
wanttty = 0;
switch (t->t_dtyp) {
case NODE_COMMAND:
if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE)
(void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1);
if ((t->t_dflg & F_REPEAT) == 0)
Dfix(t); /* $ " ' \ */
if (t->t_dcom[0] == 0)
return;
/* fall into... */
case NODE_PAREN:
if (t->t_dflg & F_PIPEOUT)
mypipe(pipeout);
/*
* Must do << early so parent will know where input pointer should be.
* If noexec then this is all we do.
*/
if (t->t_dflg & F_READ) {
(void) close(0);
heredoc(t->t_dlef);
if (noexec)
(void) close(0);
}
set(STRstatus, Strsave(STR0));
/*
* This mess is the necessary kludge to handle the prefix builtins:
* nice, nohup, time. These commands can also be used by themselves,
* and this is not handled here. This will also work when loops are
* parsed.
*/
while (t->t_dtyp == NODE_COMMAND)
if (eq(t->t_dcom[0], STRnice))
if (t->t_dcom[1])
if (strchr("+-", t->t_dcom[1][0]))
if (t->t_dcom[2]) {
setname("nice");
t->t_nice =
getn(t->t_dcom[1]);
lshift(t->t_dcom, 2);
t->t_dflg |= F_NICE;
}
else
break;
else {
t->t_nice = 4;
lshift(t->t_dcom, 1);
t->t_dflg |= F_NICE;
}
else
break;
else if (eq(t->t_dcom[0], STRnohup))
if (t->t_dcom[1]) {
t->t_dflg |= F_NOHUP;
lshift(t->t_dcom, 1);
}
else
break;
else if (eq(t->t_dcom[0], STRtime))
if (t->t_dcom[1]) {
t->t_dflg |= F_TIME;
lshift(t->t_dcom, 1);
}
else
break;
else
break;
/* is it a command */
if (t->t_dtyp == NODE_COMMAND) {
/*
* Check if we have a builtin function and remember which one.
*/
bifunc = isbfunc(t);
if (noexec) {
/*
* Continue for builtins that are part of the scripting language
*/
if (bifunc->bfunct != dobreak && bifunc->bfunct != docontin &&
bifunc->bfunct != doelse && bifunc->bfunct != doend &&
bifunc->bfunct != doforeach && bifunc->bfunct != dogoto &&
bifunc->bfunct != doif && bifunc->bfunct != dorepeat &&
bifunc->bfunct != doswbrk && bifunc->bfunct != doswitch &&
bifunc->bfunct != dowhile && bifunc->bfunct != dozip)
break;
}
}
else { /* not a command */
bifunc = NULL;
if (noexec)
break;
}
/*
* We fork only if we are timed, or are not the end of a parenthesized
* list and not a simple builtin function. Simple meaning one that is
* not pipedout, niced, nohupped, or &'d. It would be nice(?) to not
* fork in some of these cases.
*/
/*
* Prevent forking cd, pushd, popd, chdir cause this will cause the
* shell not to change dir!
*/
if (bifunc && (bifunc->bfunct == dochngd ||
bifunc->bfunct == dopushd ||
bifunc->bfunct == dopopd))
t->t_dflg &= ~(F_NICE);
if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 &&
(!bifunc || t->t_dflg &
(F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP)))) ||
/*
* We have to fork for eval too.
*/
(bifunc && (t->t_dflg & (F_PIPEIN | F_PIPEOUT)) != 0 &&
bifunc->bfunct == doeval))
if (t->t_dtyp == NODE_PAREN ||
t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) {
forked++;
/*
* We need to block SIGCHLD here, so that if the process does
* not die before we can set the process group
*/
if (wanttty >= 0 && !nosigchld) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigset, &csigset);
nosigchld = 1;
}
pid = pfork(t, wanttty);
if (pid == 0 && nosigchld) {
sigprocmask(SIG_SETMASK, &csigset, NULL);
nosigchld = 0;
}
else if (pid != 0 && (t->t_dflg & F_AMPERSAND))
backpid = pid;
}
else {
int ochild, osetintr, ohaderr, odidfds;
int oSHIN, oSHOUT, oSHERR, oOLDSTD, otpgrp;
sigset_t osigset;
/*
* Prepare for the vfork by saving everything that the child
* corrupts before it exec's. Note that in some signal
* implementations which keep the signal info in user space
* (e.g. Sun's) it will also be necessary to save and restore
* the current sigaction's for the signals the child touches
* before it exec's.
*/
if (wanttty >= 0 && !nosigchld && !noexec) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigset, &csigset);
nosigchld = 1;
}
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_BLOCK, &sigset, &osigset);
ochild = child;
osetintr = setintr;
ohaderr = haderr;
odidfds = didfds;
oSHIN = SHIN;
oSHOUT = SHOUT;
oSHERR = SHERR;
oOLDSTD = OLDSTD;
otpgrp = tpgrp;
ocsigset = csigset;
onosigchld = nosigchld;
Vsav = Vdp = 0;
Vexpath = 0;
Vt = 0;
pid = vfork();
if (pid < 0) {
sigprocmask(SIG_SETMASK, &osigset, NULL);
stderror(ERR_NOPROC);
}
forked++;
if (pid) { /* parent */
child = ochild;
setintr = osetintr;
haderr = ohaderr;
didfds = odidfds;
SHIN = oSHIN;
SHOUT = oSHOUT;
SHERR = oSHERR;
OLDSTD = oOLDSTD;
tpgrp = otpgrp;
csigset = ocsigset;
nosigchld = onosigchld;
xfree((ptr_t) Vsav);
Vsav = 0;
xfree((ptr_t) Vdp);
Vdp = 0;
xfree((ptr_t) Vexpath);
Vexpath = 0;
blkfree((Char **) Vt);
Vt = 0;
/* this is from pfork() */
palloc(pid, t);
sigprocmask(SIG_SETMASK, &osigset, NULL);
}
else { /* child */
/* this is from pfork() */
int pgrp;
bool ignint = 0;
if (nosigchld) {
sigprocmask(SIG_SETMASK, &csigset, NULL);
nosigchld = 0;
}
if (setintr)
ignint =
(tpgrp == -1 &&
(t->t_dflg & F_NOINTERRUPT))
|| (gointr && eq(gointr, STRminus));
pgrp = pcurrjob ? pcurrjob->p_jobid : getpid();
child++;
if (setintr) {
setintr = 0;
if (ignint) {
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGQUIT, SIG_IGN);
}
else {
(void) signal(SIGINT, vffree);
(void) signal(SIGQUIT, SIG_DFL);
}
if (wanttty >= 0) {
(void) signal(SIGTSTP, SIG_DFL);
(void) signal(SIGTTIN, SIG_DFL);
(void) signal(SIGTTOU, SIG_DFL);
}
(void) signal(SIGTERM, parterm);
}
else if (tpgrp == -1 &&
(t->t_dflg & F_NOINTERRUPT)) {
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGQUIT, SIG_IGN);
}
pgetty(wanttty, pgrp);
if (t->t_dflg & F_NOHUP)
(void) signal(SIGHUP, SIG_IGN);
if (t->t_dflg & F_NICE)
(void) setpriority(PRIO_PROCESS, 0, t->t_nice);
}
}
if (pid != 0) {
/*
* It would be better if we could wait for the whole job when we
* knew the last process had been started. Pwait, in fact, does
* wait for the whole job anyway, but this test doesn't really
* express our intentions.
*/
if (didfds == 0 && t->t_dflg & F_PIPEIN) {
(void) close(pipein[0]);
(void) close(pipein[1]);
}
if ((t->t_dflg & F_PIPEOUT) == 0) {
if (nosigchld) {
sigprocmask(SIG_SETMASK, &csigset, NULL);
nosigchld = 0;
}
if ((t->t_dflg & F_AMPERSAND) == 0)
pwait();
}
break;
}
doio(t, pipein, pipeout);
if (t->t_dflg & F_PIPEOUT) {
(void) close(pipeout[0]);
(void) close(pipeout[1]);
}
/*
* Perform a builtin function. If we are not forked, arrange for
* possible stopping
*/
if (bifunc) {
func(t, bifunc);
if (forked)
exitstat();
break;
}
if (t->t_dtyp != NODE_PAREN) {
doexec(NULL, t);
/* NOTREACHED */
}
/*
* For () commands must put new 0,1,2 in FSH* and recurse
*/
OLDSTD = dcopy(0, FOLDSTD);
SHOUT = dcopy(1, FSHOUT);
SHERR = dcopy(2, FSHERR);
(void) close(SHIN);
SHIN = -1;
didfds = 0;
wanttty = -1;
t->t_dspr->t_dflg |= t->t_dflg & F_NOINTERRUPT;
execute(t->t_dspr, wanttty, NULL, NULL);
exitstat();
case NODE_PIPE:
t->t_dcar->t_dflg |= F_PIPEOUT |
(t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT));
execute(t->t_dcar, wanttty, pipein, pv);
t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg &
(F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT));
if (wanttty > 0)
wanttty = 0; /* got tty already */
execute(t->t_dcdr, wanttty, pv, pipeout);
break;
case NODE_LIST:
if (t->t_dcar) {
t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
execute(t->t_dcar, wanttty, NULL, NULL);
/*
* In strange case of A&B make a new job after A
*/
if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr &&
(t->t_dcdr->t_dflg & F_AMPERSAND) == 0)
pendjob();
}
if (t->t_dcdr) {
t->t_dcdr->t_dflg |= t->t_dflg &
(F_NOFORK | F_NOINTERRUPT);
execute(t->t_dcdr, wanttty, NULL, NULL);
}
break;
case NODE_OR:
case NODE_AND:
if (t->t_dcar) {
t->t_dcar->t_dflg |= t->t_dflg & F_NOINTERRUPT;
execute(t->t_dcar, wanttty, NULL, NULL);
if ((getn(value(STRstatus)) == 0) !=
(t->t_dtyp == NODE_AND))
return;
}
if (t->t_dcdr) {
t->t_dcdr->t_dflg |= t->t_dflg &
(F_NOFORK | F_NOINTERRUPT);
execute(t->t_dcdr, wanttty, NULL, NULL);
}
break;
}
/*
* Fall through for all breaks from switch
*
* If there will be no more executions of this command, flush all file
* descriptors. Places that turn on the F_REPEAT bit are responsible for
* doing donefds after the last re-execution
*/
if (didfds && !(t->t_dflg & F_REPEAT))
donefds();
}
static void
vffree(i)
int i;
{
register Char **v;
if ((v = gargv) != NULL) {
gargv = 0;
xfree((ptr_t) v);
}
if ((v = pargv) != NULL) {
pargv = 0;
xfree((ptr_t) v);
}
_exit(i);
}
/*
* Expand and glob the words after an i/o redirection.
* If more than one word is generated, then update the command vector.
*
* This is done differently in all the shells:
* 1. in the bourne shell and ksh globbing is not performed
* 2. Bash/csh say ambiguous
* 3. zsh does i/o to/from all the files
* 4. itcsh concatenates the words.
*
* I don't know what is best to do. I think that Ambiguous is better
* than restructuring the command vector, because the user can get
* unexpected results. In any case, the command vector restructuring
* code is present and the user can choose it by setting noambiguous
*/
static Char *
splicepipe(t, cp)
register struct command *t;
Char *cp; /* word after < or > */
{
Char *blk[2];
if (adrof(STRnoambiguous)) {
Char **pv;
blk[0] = Dfix1(cp); /* expand $ */
blk[1] = NULL;
gflag = 0, tglob(blk);
if (gflag) {
pv = globall(blk);
if (pv == NULL) {
setname(vis_str(blk[0]));
xfree((ptr_t) blk[0]);
stderror(ERR_NAME | ERR_NOMATCH);
}
gargv = NULL;
if (pv[1] != NULL) { /* we need to fix the command vector */
Char **av = blkspl(t->t_dcom, &pv[1]);
xfree((ptr_t) t->t_dcom);
t->t_dcom = av;
}
xfree((ptr_t) blk[0]);
blk[0] = pv[0];
xfree((ptr_t) pv);
}
}
else {
blk[0] = globone(blk[1] = Dfix1(cp), G_ERROR);
xfree((ptr_t) blk[1]);
}
return(blk[0]);
}
/*
* Perform io redirection.
* We may or maynot be forked here.
*/
static void
doio(t, pipein, pipeout)
register struct command *t;
int *pipein, *pipeout;
{
register int fd;
register Char *cp;
register int flags = t->t_dflg;
if (didfds || (flags & F_REPEAT))
return;
if ((flags & F_READ) == 0) {/* F_READ already done */
if (t->t_dlef) {
char tmp[MAXPATHLEN+1];
/*
* so < /dev/std{in,out,err} work
*/
(void) dcopy(SHIN, 0);
(void) dcopy(SHOUT, 1);
(void) dcopy(SHERR, 2);
cp = splicepipe(t, t->t_dlef);
(void) strncpy(tmp, short2str(cp), MAXPATHLEN);
tmp[MAXPATHLEN] = '\0';
xfree((ptr_t) cp);
if ((fd = open(tmp, O_RDONLY)) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
(void) dmove(fd, 0);
}
else if (flags & F_PIPEIN) {
(void) close(0);
(void) dup(pipein[0]);
(void) close(pipein[0]);
(void) close(pipein[1]);
}
else if ((flags & F_NOINTERRUPT) && tpgrp == -1) {
(void) close(0);
(void) open(_PATH_DEVNULL, O_RDONLY);
}
else {
(void) close(0);
(void) dup(OLDSTD);
(void) ioctl(0, FIONCLEX, NULL);
}
}
if (t->t_drit) {
char tmp[MAXPATHLEN+1];
cp = splicepipe(t, t->t_drit);
(void) strncpy(tmp, short2str(cp), MAXPATHLEN);
tmp[MAXPATHLEN] = '\0';
xfree((ptr_t) cp);
/*
* so > /dev/std{out,err} work
*/
(void) dcopy(SHOUT, 1);
(void) dcopy(SHERR, 2);
if ((flags & F_APPEND) &&
#ifdef O_APPEND
(fd = open(tmp, O_WRONLY | O_APPEND)) >= 0);
#else
(fd = open(tmp, O_WRONLY)) >= 0)
(void) lseek(1, (off_t) 0, L_XTND);
#endif
else {
if (!(flags & F_OVERWRITE) && adrof(STRnoclobber)) {
if (flags & F_APPEND)
stderror(ERR_SYSTEM, tmp, strerror(errno));
chkclob(tmp);
}
if ((fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
}
(void) dmove(fd, 1);
}
else if (flags & F_PIPEOUT) {
(void) close(1);
(void) dup(pipeout[1]);
}
else {
(void) close(1);
(void) dup(SHOUT);
(void) ioctl(1, FIONCLEX, NULL);
}
(void) close(2);
if (flags & F_STDERR) {
(void) dup(1);
}
else {
(void) dup(SHERR);
(void) ioctl(2, FIONCLEX, NULL);
}
didfds = 1;
}
void
mypipe(pv)
register int *pv;
{
if (pipe(pv) < 0)
goto oops;
pv[0] = dmove(pv[0], -1);
pv[1] = dmove(pv[1], -1);
if (pv[0] >= 0 && pv[1] >= 0)
return;
oops:
stderror(ERR_PIPE);
}
static void
chkclob(cp)
register char *cp;
{
struct stat stb;
if (stat(cp, &stb) < 0)
return;
if (S_ISCHR(stb.st_mode))
return;
stderror(ERR_EXISTS, cp);
}
+848
View File
@@ -0,0 +1,848 @@
/*-
* Copyright (c) 1980, 1991, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)set.c 8.2 (Berkeley) 3/22/95";
#endif /* not lint */
#include <sys/types.h>
#include <stdlib.h>
#ifndef SHORT_STRINGS
#include <string.h>
#endif /* SHORT_STRINGS */
#if __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#include "csh.h"
#include "extern.h"
static Char *getinx __P((Char *, int *));
static void asx __P((Char *, int, Char *));
static struct varent
*getvx __P((Char *, int));
static Char *xset __P((Char *, Char ***));
static Char *operate __P((int, Char *, Char *));
static void putn1 __P((int));
static struct varent
*madrof __P((Char *, struct varent *));
static void unsetv1 __P((struct varent *));
static void exportpath __P((Char **));
static void balance __P((struct varent *, int, int));
/*
* C Shell
*/
void
/*ARGSUSED*/
doset(v, t)
Char **v;
struct command *t;
{
register Char *p;
Char *vp, op;
Char **vecp;
bool hadsub;
int subscr;
v++;
p = *v++;
if (p == 0) {
prvars();
return;
}
do {
hadsub = 0;
vp = p;
if (letter(*p))
for (; alnum(*p); p++)
continue;
if (vp == p || !letter(*vp))
stderror(ERR_NAME | ERR_VARBEGIN);
if ((p - vp) > MAXVARLEN) {
stderror(ERR_NAME | ERR_VARTOOLONG);
return;
}
if (*p == '[') {
hadsub++;
p = getinx(p, &subscr);
}
if ((op = *p) != '\0') {
*p++ = 0;
if (*p == 0 && *v && **v == '(')
p = *v++;
}
else if (*v && eq(*v, STRequal)) {
op = '=', v++;
if (*v)
p = *v++;
}
if (op && op != '=')
stderror(ERR_NAME | ERR_SYNTAX);
if (eq(p, STRLparen)) {
register Char **e = v;
if (hadsub)
stderror(ERR_NAME | ERR_SYNTAX);
for (;;) {
if (!*e)
stderror(ERR_NAME | ERR_MISSING, ')');
if (**e == ')')
break;
e++;
}
p = *e;
*e = 0;
vecp = saveblk(v);
set1(vp, vecp, &shvhed);
*e = p;
v = e + 1;
}
else if (hadsub)
asx(vp, subscr, Strsave(p));
else
set(vp, Strsave(p));
if (eq(vp, STRpath)) {
exportpath(adrof(STRpath)->vec);
dohash(NULL, NULL);
}
else if (eq(vp, STRhistchars)) {
register Char *pn = value(STRhistchars);
HIST = *pn++;
HISTSUB = *pn;
}
else if (eq(vp, STRuser)) {
Setenv(STRUSER, value(vp));
Setenv(STRLOGNAME, value(vp));
}
else if (eq(vp, STRwordchars)) {
word_chars = value(vp);
}
else if (eq(vp, STRterm))
Setenv(STRTERM, value(vp));
else if (eq(vp, STRhome)) {
register Char *cp;
cp = Strsave(value(vp)); /* get the old value back */
/*
* convert to cononical pathname (possibly resolving symlinks)
*/
cp = dcanon(cp, cp);
set(vp, Strsave(cp)); /* have to save the new val */
/* and now mirror home with HOME */
Setenv(STRHOME, cp);
/* fix directory stack for new tilde home */
dtilde();
xfree((ptr_t) cp);
}
#ifdef FILEC
else if (eq(vp, STRfilec))
filec = 1;
#endif
} while ((p = *v++) != NULL);
}
static Char *
getinx(cp, ip)
register Char *cp;
register int *ip;
{
*ip = 0;
*cp++ = 0;
while (*cp && Isdigit(*cp))
*ip = *ip * 10 + *cp++ - '0';
if (*cp++ != ']')
stderror(ERR_NAME | ERR_SUBSCRIPT);
return (cp);
}
static void
asx(vp, subscr, p)
Char *vp;
int subscr;
Char *p;
{
register struct varent *v = getvx(vp, subscr);
xfree((ptr_t) v->vec[subscr - 1]);
v->vec[subscr - 1] = globone(p, G_APPEND);
}
static struct varent *
getvx(vp, subscr)
Char *vp;
int subscr;
{
register struct varent *v = adrof(vp);
if (v == 0)
udvar(vp);
if (subscr < 1 || subscr > blklen(v->vec))
stderror(ERR_NAME | ERR_RANGE);
return (v);
}
void
/*ARGSUSED*/
dolet(v, t)
Char **v;
struct command *t;
{
register Char *p;
Char *vp, c, op;
bool hadsub;
int subscr;
v++;
p = *v++;
if (p == 0) {
prvars();
return;
}
do {
hadsub = 0;
vp = p;
if (letter(*p))
for (; alnum(*p); p++)
continue;
if (vp == p || !letter(*vp))
stderror(ERR_NAME | ERR_VARBEGIN);
if ((p - vp) > MAXVARLEN)
stderror(ERR_NAME | ERR_VARTOOLONG);
if (*p == '[') {
hadsub++;
p = getinx(p, &subscr);
}
if (*p == 0 && *v)
p = *v++;
if ((op = *p) != '\0')
*p++ = 0;
else
stderror(ERR_NAME | ERR_ASSIGN);
if (*p == '\0' && *v == NULL)
stderror(ERR_NAME | ERR_ASSIGN);
vp = Strsave(vp);
if (op == '=') {
c = '=';
p = xset(p, &v);
}
else {
c = *p++;
if (any("+-", c)) {
if (c != op || *p)
stderror(ERR_NAME | ERR_UNKNOWNOP);
p = Strsave(STR1);
}
else {
if (any("<>", op)) {
if (c != op)
stderror(ERR_NAME | ERR_UNKNOWNOP);
c = *p++;
stderror(ERR_NAME | ERR_SYNTAX);
}
if (c != '=')
stderror(ERR_NAME | ERR_UNKNOWNOP);
p = xset(p, &v);
}
}
if (op == '=')
if (hadsub)
asx(vp, subscr, p);
else
set(vp, p);
else if (hadsub) {
struct varent *gv = getvx(vp, subscr);
asx(vp, subscr, operate(op, gv->vec[subscr - 1], p));
}
else
set(vp, operate(op, value(vp), p));
if (eq(vp, STRpath)) {
exportpath(adrof(STRpath)->vec);
dohash(NULL, NULL);
}
xfree((ptr_t) vp);
if (c != '=')
xfree((ptr_t) p);
} while ((p = *v++) != NULL);
}
static Char *
xset(cp, vp)
Char *cp, ***vp;
{
register Char *dp;
if (*cp) {
dp = Strsave(cp);
--(*vp);
xfree((ptr_t) ** vp);
**vp = dp;
}
return (putn(expr(vp)));
}
static Char *
operate(op, vp, p)
int op;
Char *vp, *p;
{
Char opr[2];
Char *vec[5];
register Char **v = vec;
Char **vecp = v;
register int i;
if (op != '=') {
if (*vp)
*v++ = vp;
opr[0] = op;
opr[1] = 0;
*v++ = opr;
if (op == '<' || op == '>')
*v++ = opr;
}
*v++ = p;
*v++ = 0;
i = expr(&vecp);
if (*vecp)
stderror(ERR_NAME | ERR_EXPRESSION);
return (putn(i));
}
static Char *putp;
Char *
putn(n)
register int n;
{
int num;
static Char number[15];
putp = number;
if (n < 0) {
n = -n;
*putp++ = '-';
}
num = 2; /* confuse lint */
if (sizeof(int) == num && ((unsigned int) n) == 0x8000) {
*putp++ = '3';
n = 2768;
#ifdef pdp11
}
#else
}
else {
num = 4; /* confuse lint */
if (sizeof(int) == num && ((unsigned int) n) == 0x80000000) {
*putp++ = '2';
n = 147483648;
}
}
#endif
putn1(n);
*putp = 0;
return (Strsave(number));
}
static void
putn1(n)
register int n;
{
if (n > 9)
putn1(n / 10);
*putp++ = n % 10 + '0';
}
int
getn(cp)
register Char *cp;
{
register int n;
int sign;
sign = 0;
if (cp[0] == '+' && cp[1])
cp++;
if (*cp == '-') {
sign++;
cp++;
if (!Isdigit(*cp))
stderror(ERR_NAME | ERR_BADNUM);
}
n = 0;
while (Isdigit(*cp))
n = n * 10 + *cp++ - '0';
if (*cp)
stderror(ERR_NAME | ERR_BADNUM);
return (sign ? -n : n);
}
Char *
value1(var, head)
Char *var;
struct varent *head;
{
register struct varent *vp;
vp = adrof1(var, head);
return (vp == 0 || vp->vec[0] == 0 ? STRNULL : vp->vec[0]);
}
static struct varent *
madrof(pat, vp)
Char *pat;
register struct varent *vp;
{
register struct varent *vp1;
for (; vp; vp = vp->v_right) {
if (vp->v_left && (vp1 = madrof(pat, vp->v_left)))
return vp1;
if (Gmatch(vp->v_name, pat))
return vp;
}
return vp;
}
struct varent *
adrof1(name, v)
register Char *name;
register struct varent *v;
{
register cmp;
v = v->v_left;
while (v && ((cmp = *name - *v->v_name) ||
(cmp = Strcmp(name, v->v_name))))
if (cmp < 0)
v = v->v_left;
else
v = v->v_right;
return v;
}
/*
* The caller is responsible for putting value in a safe place
*/
void
set(var, val)
Char *var, *val;
{
register Char **vec = (Char **) xmalloc((size_t) (2 * sizeof(Char **)));
vec[0] = val;
vec[1] = 0;
set1(var, vec, &shvhed);
}
void
set1(var, vec, head)
Char *var, **vec;
struct varent *head;
{
register Char **oldv = vec;
gflag = 0;
tglob(oldv);
if (gflag) {
vec = globall(oldv);
if (vec == 0) {
blkfree(oldv);
stderror(ERR_NAME | ERR_NOMATCH);
return;
}
blkfree(oldv);
gargv = 0;
}
setq(var, vec, head);
}
void
setq(name, vec, p)
Char *name, **vec;
register struct varent *p;
{
register struct varent *c;
register f;
f = 0; /* tree hangs off the header's left link */
while ((c = p->v_link[f]) != NULL) {
if ((f = *name - *c->v_name) == 0 &&
(f = Strcmp(name, c->v_name)) == 0) {
blkfree(c->vec);
goto found;
}
p = c;
f = f > 0;
}
p->v_link[f] = c = (struct varent *) xmalloc((size_t) sizeof(struct varent));
c->v_name = Strsave(name);
c->v_bal = 0;
c->v_left = c->v_right = 0;
c->v_parent = p;
balance(p, f, 0);
found:
trim(c->vec = vec);
}
void
/*ARGSUSED*/
unset(v, t)
Char **v;
struct command *t;
{
unset1(v, &shvhed);
#ifdef FILEC
if (adrof(STRfilec) == 0)
filec = 0;
#endif
if (adrof(STRhistchars) == 0) {
HIST = '!';
HISTSUB = '^';
}
if (adrof(STRwordchars) == 0)
word_chars = STR_WORD_CHARS;
}
void
unset1(v, head)
register Char *v[];
struct varent *head;
{
register struct varent *vp;
register int cnt;
while (*++v) {
cnt = 0;
while ((vp = madrof(*v, head->v_left)) != NULL)
unsetv1(vp), cnt++;
if (cnt == 0)
setname(vis_str(*v));
}
}
void
unsetv(var)
Char *var;
{
register struct varent *vp;
if ((vp = adrof1(var, &shvhed)) == 0)
udvar(var);
unsetv1(vp);
}
static void
unsetv1(p)
register struct varent *p;
{
register struct varent *c, *pp;
register f;
/*
* Free associated memory first to avoid complications.
*/
blkfree(p->vec);
xfree((ptr_t) p->v_name);
/*
* If p is missing one child, then we can move the other into where p is.
* Otherwise, we find the predecessor of p, which is guaranteed to have no
* right child, copy it into p, and move it's left child into it.
*/
if (p->v_right == 0)
c = p->v_left;
else if (p->v_left == 0)
c = p->v_right;
else {
for (c = p->v_left; c->v_right; c = c->v_right)
continue;
p->v_name = c->v_name;
p->vec = c->vec;
p = c;
c = p->v_left;
}
/*
* Move c into where p is.
*/
pp = p->v_parent;
f = pp->v_right == p;
if ((pp->v_link[f] = c) != NULL)
c->v_parent = pp;
/*
* Free the deleted node, and rebalance.
*/
xfree((ptr_t) p);
balance(pp, f, 1);
}
void
setNS(cp)
Char *cp;
{
set(cp, Strsave(STRNULL));
}
void
/*ARGSUSED*/
shift(v, t)
Char **v;
struct command *t;
{
register struct varent *argv;
register Char *name;
v++;
name = *v;
if (name == 0)
name = STRargv;
else
(void) strip(name);
argv = adrof(name);
if (argv == 0)
udvar(name);
if (argv->vec[0] == 0)
stderror(ERR_NAME | ERR_NOMORE);
lshift(argv->vec, 1);
}
static void
exportpath(val)
Char **val;
{
Char exppath[BUFSIZ];
exppath[0] = 0;
if (val)
while (*val) {
if (Strlen(*val) + Strlen(exppath) + 2 > BUFSIZ) {
(void) fprintf(csherr,
"Warning: ridiculously long PATH truncated\n");
break;
}
if ((**val != '/' || **val == '\0') && (euid == 0 || uid == 0))
(void) fprintf(csherr,
"Warning: exported path contains relative components.\n");
(void) Strcat(exppath, *val++);
if (*val == 0 || eq(*val, STRRparen))
break;
(void) Strcat(exppath, STRcolon);
}
Setenv(STRPATH, exppath);
}
#ifndef lint
/*
* Lint thinks these have null effect
*/
/* macros to do single rotations on node p */
#define rright(p) (\
t = (p)->v_left,\
(t)->v_parent = (p)->v_parent,\
((p)->v_left = t->v_right) ? (t->v_right->v_parent = (p)) : 0,\
(t->v_right = (p))->v_parent = t,\
(p) = t)
#define rleft(p) (\
t = (p)->v_right,\
(t)->v_parent = (p)->v_parent,\
((p)->v_right = t->v_left) ? (t->v_left->v_parent = (p)) : 0,\
(t->v_left = (p))->v_parent = t,\
(p) = t)
#else
struct varent *
rleft(p)
struct varent *p;
{
return (p);
}
struct varent *
rright(p)
struct varent *p;
{
return (p);
}
#endif /* ! lint */
/*
* Rebalance a tree, starting at p and up.
* F == 0 means we've come from p's left child.
* D == 1 means we've just done a delete, otherwise an insert.
*/
static void
balance(p, f, d)
register struct varent *p;
register int f, d;
{
register struct varent *pp;
#ifndef lint
register struct varent *t; /* used by the rotate macros */
#endif
register ff;
/*
* Ok, from here on, p is the node we're operating on; pp is it's parent; f
* is the branch of p from which we have come; ff is the branch of pp which
* is p.
*/
for (; (pp = p->v_parent) != NULL; p = pp, f = ff) {
ff = pp->v_right == p;
if (f ^ d) { /* right heavy */
switch (p->v_bal) {
case -1: /* was left heavy */
p->v_bal = 0;
break;
case 0: /* was balanced */
p->v_bal = 1;
break;
case 1: /* was already right heavy */
switch (p->v_right->v_bal) {
case 1: /* sigle rotate */
pp->v_link[ff] = rleft(p);
p->v_left->v_bal = 0;
p->v_bal = 0;
break;
case 0: /* single rotate */
pp->v_link[ff] = rleft(p);
p->v_left->v_bal = 1;
p->v_bal = -1;
break;
case -1: /* double rotate */
(void) rright(p->v_right);
pp->v_link[ff] = rleft(p);
p->v_left->v_bal =
p->v_bal < 1 ? 0 : -1;
p->v_right->v_bal =
p->v_bal > -1 ? 0 : 1;
p->v_bal = 0;
break;
}
break;
}
}
else { /* left heavy */
switch (p->v_bal) {
case 1: /* was right heavy */
p->v_bal = 0;
break;
case 0: /* was balanced */
p->v_bal = -1;
break;
case -1: /* was already left heavy */
switch (p->v_left->v_bal) {
case -1: /* single rotate */
pp->v_link[ff] = rright(p);
p->v_right->v_bal = 0;
p->v_bal = 0;
break;
case 0: /* signle rotate */
pp->v_link[ff] = rright(p);
p->v_right->v_bal = -1;
p->v_bal = 1;
break;
case 1: /* double rotate */
(void) rleft(p->v_left);
pp->v_link[ff] = rright(p);
p->v_left->v_bal =
p->v_bal < 1 ? 0 : -1;
p->v_right->v_bal =
p->v_bal > -1 ? 0 : 1;
p->v_bal = 0;
break;
}
break;
}
}
/*
* If from insert, then we terminate when p is balanced. If from
* delete, then we terminate when p is unbalanced.
*/
if ((p->v_bal == 0) ^ d)
break;
}
}
void
plist(p)
register struct varent *p;
{
register struct varent *c;
register len;
sigset_t sigset;
if (setintr) {
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
for (;;) {
while (p->v_left)
p = p->v_left;
x:
if (p->v_parent == 0) /* is it the header? */
return;
len = blklen(p->vec);
(void) fprintf(cshout, "%s\t", short2str(p->v_name));
if (len != 1)
(void) fputc('(', cshout);
blkpr(cshout, p->vec);
if (len != 1)
(void) fputc(')', cshout);
(void) fputc('\n', cshout);
if (p->v_right) {
p = p->v_right;
continue;
}
do {
c = p;
p = p->v_parent;
} while (p->v_right == c);
goto x;
}
}
+232
View File
@@ -0,0 +1,232 @@
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt DATE 1
.Os
.Sh NAME
.Nm date
.Nd display or set date and time
.Sh SYNOPSIS
.Nm date
.Op Fl d Ar dst
.Op Fl r Ar seconds
.Op Fl t Ar minutes_west
.Op Fl nu
.Op Cm + Ns Ar format
.Op [yy[mm[dd[hh]]]]mm[\&.ss]
.Sh DESCRIPTION
.Nm Date
displays the current date and time when invoked without arguments.
Providing arguments will format the date and time in a user-defined
way or set the date.
Only the superuser may set the date.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl d
Set the kernel's value for daylight savings time.
If
.Ar dst
is non-zero, future calls
to
.Xr gettimeofday 2
will return a non-zero
.Ql tz_dsttime .
.It Fl n
The utility
.Xr timed 8
is used to synchronize the clocks on groups of machines.
By default, if
.Xr timed
is running,
.Nm date
will set the time on all of the machines in the local group.
The
.Fl n
option stops
.Nm date
from setting the time for other than the current machine.
.It Fl r
Print out the date and time in
.Ar seconds
from the Epoch.
.It Fl t
Set the kernel's value for minutes west of
.Tn GMT .
.Ar Minutes_west
specifies the number of minutes returned in
.Ql tz_minuteswest
by future calls to
.Xr gettimeofday 2 .
.It Fl u
Display or set the date in
.Tn UCT
(universal) time.
.El
.Pp
An operand with a leading plus (``+'') sign signals a user-defined format
string which specifies the format in which to display the date and time.
The format string may contain any of the conversion specifications described
in the
.Xr strftime 3
manual page, as well as any arbitrary text.
A <newline> character is always output after the characters specified by
the format string.
The format string for the default display is:
.Bd -literal -offset indent
``%a %b %e %H:%M:%S %Z %Y''.
.Ed
.Pp
If an operand does not have a leading plus sign, it is interpreted as
a value for setting the system's notion of the current date and time.
The canonical representation for setting the date and time is:
.Pp
.Bl -tag -width Ds -compact -offset indent
.It Ar yy
Year in abbreviated form (.e.g 89 for 1989).
.It Ar mm
Numeric month.
A number from 1 to 12.
.It Ar dd
Day, a number from 1 to 31.
.It Ar hh
Hour, a number from 0 to 23.
.It Ar mm
Minutes, a number from 0 to 59.
.It Ar .ss
Seconds, a number from 0 to 61 (59 plus a a maximum of two leap seconds).
.El
.Pp
Everything but the minutes is optional.
.Pp
Time changes for Daylight Saving and Standard time and leap seconds
and years are handled automatically.
.Sh EXAMPLES
The command:
.Bd -literal -offset indent
date ``+DATE: %m/%d/%y%nTIME: %H:%M:%S''
.Ed
.Pp
will display:
.Bd -literal -offset indent
DATE: 11/21/87
TIME: 13:36:16
.Ed
.Pp
The command:
.Bd -literal -offset indent
date 8506131627
.Ed
.Pp
sets the date to
.Dq Li "June 13, 1985, 4:27 PM" .
.Pp
The command:
.Bd -literal -offset indent
date 1432
.Ed
.Pp
sets the time to
.Li "2:32 PM" ,
without modifying the date.
.Sh ENVIRONMENTAL VARIABLES
The following environment variables affect the execution of
.Nm date :
.Bl -tag -width TZ
.It Ev TZ
The timezone to use when displaying dates.
See
.Xr environ 7
for more information.
.El
.Sh FILES
.Bl -tag -width /var/log/messages -compact
.It Pa /var/log/wtmp
A record of date resets and time changes.
.It Pa /var/log/messages
A record of the user setting the time.
.El
.Sh SEE ALSO
.Xr gettimeofday 2 ,
.Xr strftime 3 ,
.Xr utmp 5 ,
.Xr timed 8
.Rs
.%T "TSP: The Time Synchronization Protocol for UNIX 4.3BSD"
.%A R. Gusella
.%A S. Zatti
.Re
.Sh DIAGNOSTICS
Exit status is 0 on success, 1 if unable to set the date, and 2
if able to set the local date, but unable to set it globally.
.Pp
Occasionally, when
.Xr timed
synchronizes the time on many hosts, the setting of a new time value may
require more than a few seconds.
On these occasions,
.Nm date
prints:
.Ql Network time being set .
The message
.Ql Communication error with timed
occurs when the communication
between
.Nm date
and
.Xr timed
fails.
.Sh BUGS
The system attempts to keep the date in a format closely compatible
with
.Tn VMS .
.Tn VMS ,
however, uses local time (rather than
.Tn GMT )
and does not understand daylight-savings time.
Thus, if you use both
.Tn UNIX
and
.Tn VMS ,
.Tn VMS
will be running on
.Tn GMT .
.Sh STANDARDS
The
.Nm date
command is expected to be compatible with
.St -p1003.2 .
+237
View File
@@ -0,0 +1,237 @@
/*
* Copyright (c) 1985, 1987, 1988, 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1985, 1987, 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)date.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "extern.h"
time_t tval;
int retval, nflag;
static void setthetime __P((char *));
static void badformat __P((void));
static void usage __P((void));
int logwtmp __P((char *, char *, char *));
int
main(argc, argv)
int argc;
char **argv;
{
extern int optind;
extern char *optarg;
struct timezone tz;
int ch, rflag;
char *format, buf[1024];
tz.tz_dsttime = tz.tz_minuteswest = 0;
rflag = 0;
while ((ch = getopt(argc, argv, "d:nr:ut:")) != -1)
switch((char)ch) {
case 'd': /* daylight savings time */
tz.tz_dsttime = atoi(optarg) ? 1 : 0;
break;
case 'n': /* don't set network */
nflag = 1;
break;
case 'r': /* user specified seconds */
rflag = 1;
tval = atol(optarg);
break;
case 'u': /* do everything in GMT */
(void)setenv("TZ", "GMT0", 1);
break;
case 't': /* minutes west of GMT */
/* error check; don't allow "PST" */
if (isdigit(*optarg)) {
tz.tz_minuteswest = atoi(optarg);
break;
}
/* FALLTHROUGH */
default:
usage();
}
argc -= optind;
argv += optind;
/*
* If -d or -t, set the timezone or daylight savings time; this
* doesn't belong here, there kernel should not know about either.
*/
if ((tz.tz_minuteswest || tz.tz_dsttime) &&
settimeofday(NULL, &tz))
err(1, "settimeofday");
if (!rflag && time(&tval) == -1)
err(1, "time");
format = "%a %b %e %H:%M:%S %Z %Y";
/* allow the operands in any order */
if (*argv && **argv == '+') {
format = *argv + 1;
++argv;
}
if (*argv) {
setthetime(*argv);
++argv;
}
if (*argv && **argv == '+')
format = *argv + 1;
(void)strftime(buf, sizeof(buf), format, localtime(&tval));
(void)printf("%s\n", buf);
exit(retval);
}
#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
void
setthetime(p)
register char *p;
{
register struct tm *lt;
struct timeval tv;
char *dot, *t;
for (t = p, dot = NULL; *t; ++t) {
if (isdigit(*t))
continue;
if (*t == '.' && dot == NULL) {
dot = t;
continue;
}
badformat();
}
lt = localtime(&tval);
if (dot != NULL) { /* .ss */
*dot++ = '\0';
if (strlen(dot) != 2)
badformat();
lt->tm_sec = ATOI2(dot);
if (lt->tm_sec > 61)
badformat();
} else
lt->tm_sec = 0;
switch (strlen(p)) {
case 10: /* yy */
lt->tm_year = ATOI2(p);
if (lt->tm_year < 69) /* hack for 2000 ;-} */
lt->tm_year += 100;
/* FALLTHROUGH */
case 8: /* mm */
lt->tm_mon = ATOI2(p);
if (lt->tm_mon > 12)
badformat();
--lt->tm_mon; /* time struct is 0 - 11 */
/* FALLTHROUGH */
case 6: /* dd */
lt->tm_mday = ATOI2(p);
if (lt->tm_mday > 31)
badformat();
/* FALLTHROUGH */
case 4: /* hh */
lt->tm_hour = ATOI2(p);
if (lt->tm_hour > 23)
badformat();
/* FALLTHROUGH */
case 2: /* mm */
lt->tm_min = ATOI2(p);
if (lt->tm_min > 59)
badformat();
break;
default:
badformat();
}
/* convert broken-down time to GMT clock time */
if ((tval = mktime(lt)) == -1)
badformat();
/* set the time */
if (nflag || netsettime(tval)) {
logwtmp("|", "date", "");
tv.tv_sec = tval;
tv.tv_usec = 0;
if (settimeofday(&tv, NULL)) {
perror("date: settimeofday");
exit(1);
}
logwtmp("{", "date", "");
}
if ((p = getlogin()) == NULL)
p = "???";
syslog(LOG_AUTH | LOG_NOTICE, "date set by %s", p);
}
static void
badformat()
{
warnx("illegal time format");
usage();
}
static void
usage()
{
(void)fprintf(stderr,
"usage: date [-nu] [-d dst] [-r seconds] [-t west] [+format]\n");
(void)fprintf(stderr, " [yy[mm[dd[hh]]]]mm[.ss]]\n");
exit(1);
}
+183
View File
@@ -0,0 +1,183 @@
/*-
* Copyright (c) 1990, 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.
*/
#ifndef lint
static char sccsid[] = "@(#)netdate.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define TSPTYPES
#include <protocols/timed.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
#define WAITACK 2 /* seconds */
#define WAITDATEACK 5 /* seconds */
extern int retval;
/*
* Set the date in the machines controlled by timedaemons by communicating the
* new date to the local timedaemon. If the timedaemon is in the master state,
* it performs the correction on all slaves. If it is in the slave state, it
* notifies the master that a correction is needed.
* Returns 0 on success. Returns > 0 on failure, setting retval to 2;
*/
int
netsettime(tval)
time_t tval;
{
struct timeval tout;
struct servent *sp;
struct tsp msg;
struct sockaddr_in sin, dest, from;
fd_set ready;
long waittime;
int s, length, port, timed_ack, found, err;
char hostname[MAXHOSTNAMELEN];
if ((sp = getservbyname("timed", "udp")) == NULL) {
warnx("udp/timed: unknown service");
return (retval = 2);
}
memset(&dest, 0, sizeof(dest));
dest.sin_port = sp->s_port;
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = htonl((u_long)INADDR_ANY);
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s < 0) {
if (errno != EPROTONOSUPPORT)
warn("timed");
return (retval = 2);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) {
sin.sin_port = htons((u_short)port);
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
break;
if (errno == EADDRINUSE)
continue;
if (errno != EADDRNOTAVAIL)
warn("bind");
goto bad;
}
if (port == IPPORT_RESERVED / 2) {
warnx("all ports in use");
goto bad;
}
msg.tsp_type = TSP_SETDATE;
msg.tsp_vers = TSPVERSION;
if (gethostname(hostname, sizeof(hostname))) {
warn("gethostname");
goto bad;
}
(void)strncpy(msg.tsp_name, hostname, sizeof(hostname));
msg.tsp_seq = htons((u_short)0);
msg.tsp_time.tv_sec = htonl((u_long)tval);
msg.tsp_time.tv_usec = htonl((u_long)0);
length = sizeof(struct sockaddr_in);
if (connect(s, (struct sockaddr *)&dest, length) < 0) {
warn("connect");
goto bad;
}
if (send(s, (char *)&msg, sizeof(struct tsp), 0) < 0) {
if (errno != ECONNREFUSED)
warn("send");
goto bad;
}
timed_ack = -1;
waittime = WAITACK;
loop:
tout.tv_sec = waittime;
tout.tv_usec = 0;
FD_ZERO(&ready);
FD_SET(s, &ready);
found = select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout);
length = sizeof(err);
if (!getsockopt(s,
SOL_SOCKET, SO_ERROR, (char *)&err, &length) && err) {
if (err != ECONNREFUSED)
warn("send (delayed error)");
goto bad;
}
if (found > 0 && FD_ISSET(s, &ready)) {
length = sizeof(struct sockaddr_in);
if (recvfrom(s, &msg, sizeof(struct tsp), 0,
(struct sockaddr *)&from, &length) < 0) {
if (errno != ECONNREFUSED)
warn("recvfrom");
goto bad;
}
msg.tsp_seq = ntohs(msg.tsp_seq);
msg.tsp_time.tv_sec = ntohl(msg.tsp_time.tv_sec);
msg.tsp_time.tv_usec = ntohl(msg.tsp_time.tv_usec);
switch (msg.tsp_type) {
case TSP_ACK:
timed_ack = TSP_ACK;
waittime = WAITDATEACK;
goto loop;
case TSP_DATEACK:
(void)close(s);
return (0);
default:
warnx("wrong ack received from timed: %s",
tsptype[msg.tsp_type]);
timed_ack = -1;
break;
}
}
if (timed_ack == -1)
warnx("can't reach time daemon, time set locally");
bad:
(void)close(s);
return (retval = 2);
}
+66
View File
@@ -0,0 +1,66 @@
.\" Copyright (c) 1983, 1988, 1990, 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.
.\"
.\" @(#)hostname.1 8.2 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt HOSTNAME 1
.Os BSD 4.2
.Sh NAME
.Nm hostname
.Nd set or print name of current host system
.Sh SYNOPSIS
.Nm hostname
.Op Fl s
.Op Ar name-of-host
.Sh DESCRIPTION
.Nm Hostname
prints the name of the current host. The super-user can
set the hostname by supplying an argument; this is usually done in the
network initialization script
.Pa /etc/netstart ,
normally run at boot
time.
.Pp
Options:
.Bl -tag -width flag
.It Fl s
Trims off any domain information from the printed
name.
.El
.Sh SEE ALSO
.Xr gethostname 2 ,
.Xr sethostname 2
.Sh HISTORY
The
.Nm hostname
command appeared in
.Bx 4.2 .
+94
View File
@@ -0,0 +1,94 @@
/*
* Copyright (c) 1988, 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)hostname.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void usage __P((void));
int
main(argc,argv)
int argc;
char *argv[];
{
int ch, sflag;
char *p, hostname[MAXHOSTNAMELEN];
sflag = 0;
while ((ch = getopt(argc, argv, "s")) != -1)
switch (ch) {
case 's':
sflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (*argv) {
if (sethostname(*argv, strlen(*argv)))
err(1, "sethostname");
} else {
if (gethostname(hostname, sizeof(hostname)))
err(1, "gethostname");
if (sflag && (p = strchr(hostname, '.')))
*p = '\0';
(void)printf("%s\n", hostname);
}
exit(0);
}
void
usage()
{
(void)fprintf(stderr, "usage: hostname [-s] [hostname]\n");
exit(1);
}
+142
View File
@@ -0,0 +1,142 @@
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)kill.1 8.2 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt KILL 1
.Os
.Sh NAME
.Nm kill
.Nd terminate or signal a process
.Sh SYNOPSIS
.Nm kill
.Op Fl s Ar signal_name
.Ar pid
\&...
.Nm kill
.Fl l
.Op Ar exit_status
.Nm kill
.Fl signal_name
.Ar pid
\&...
.Nm kill
.Fl signal_number
.Ar pid
\&...
.Sh DESCRIPTION
The kill utility sends a signal to the processes specified
by the pid operand(s).
.Pp
Only the super-user may send signals to other users' processes.
.Pp
The options are as follows:
.Pp
.Bl -tag -width Ds
.It Fl s Ar signal_name
A symbolic signal name specifying the signal to be sent instead of the
default
.Dv TERM .
.It Fl l Op Ar exit_status
If no operand is given, list the signal names; otherwise, write
the signal name corresponding to
.Ar exit_status .
.It Fl signal_name
A symbolic signal name specifying the signal to be sent instead of the
default
.Dv TERM .
.It Fl signal_number
A non-negative decimal integer, specifying the signal to be sent instead
of the default
.Dv TERM .
.El
.Pp
The following pids have special meanings:
.Bl -tag -width Ds -compact
.It -1
If superuser, broadcast the signal to all processes; otherwise broadcast
to all processes belonging to the user.
.El
.Pp
Some of the more commonly used signals:
.Bl -tag -width Ds -compact
.It 1
HUP (hang up)
.It 2
INT (interrupt)
.It 3
QUIT (quit)
.It 6
ABRT (abort)
.It 9
KILL (non-catchable, non-ignorable kill)
.It 14
ALRM (alarm clock)
.It 15
TERM (software termination signal)
.El
.Pp
.Nm Kill
is a built-in to
.Xr csh 1 ;
it allows job specifiers of the form ``%...'' as arguments
so process id's are not as often used as
.Nm kill
arguments.
See
.Xr csh 1
for details.
.Sh SEE ALSO
.Xr csh 1 ,
.Xr ps 1 ,
.Xr kill 2 ,
.Xr sigvec 2
.Sh STANDARDS
The
.Nm kill
function is expected to be
.St -p1003.2
compatible.
.Sh HISTORY
A
.Nm kill
command appeared in
.At v6 .
.Sh BUGS
A replacement for the command
.Dq Li kill 0
for
.Xr csh 1
users should be provided.
+187
View File
@@ -0,0 +1,187 @@
/*
* Copyright (c) 1988, 1993, 1994
* 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)kill.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void nosig __P((char *));
void printsignals __P((FILE *));
int signame_to_signum __P((char *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
const char *const *p;
int errors, numsig, pid;
char *ep;
if (argc < 2)
usage();
numsig = SIGTERM;
argc--, argv++;
if (!strcmp(*argv, "-l")) {
argc--, argv++;
if (argc > 1)
usage();
if (argc == 1) {
if (!isdigit(**argv))
usage();
numsig = strtol(*argv, &ep, 10);
if (!*argv || *ep)
errx(1, "illegal signal number: %s", *argv);
if (numsig >= 128)
numsig -= 128;
if (numsig <= 0 || numsig >= NSIG)
nosig(*argv);
printf("%s\n", sys_signame[numsig]);
exit(0);
}
printsignals(stdout);
exit(0);
}
if (!strcmp(*argv, "-s")) {
argc--, argv++;
if (argc < 1) {
warnx("option requires an argument -- s");
usage();
}
if (strcmp(*argv, "0")) {
if ((numsig = signame_to_signum(*argv)) < 0)
nosig(*argv);
} else
numsig = 0;
argc--, argv++;
} else if (**argv == '-') {
++*argv;
if (isalpha(**argv)) {
if ((numsig = signame_to_signum(*argv)) < 0)
nosig(*argv);
} else if (isdigit(**argv)) {
numsig = strtol(*argv, &ep, 10);
if (!*argv || *ep)
errx(1, "illegal signal number: %s", *argv);
if (numsig <= 0 || numsig >= NSIG)
nosig(*argv);
} else
nosig(*argv);
argc--, argv++;
}
if (argc == 0)
usage();
for (errors = 0; argc; argc--, argv++) {
pid = strtol(*argv, &ep, 10);
if (!*argv || *ep) {
warnx("illegal process id: %s", *argv);
errors = 1;
} else if (kill(pid, numsig) == -1) {
warn("%s", *argv);
errors = 1;
}
}
exit(errors);
}
int
signame_to_signum(sig)
char *sig;
{
int n;
if (!strncasecmp(sig, "sig", 3))
sig += 3;
for (n = 1; n < NSIG; n++) {
if (!strcasecmp(sys_signame[n], sig))
return (n);
}
return (-1);
}
void
nosig(name)
char *name;
{
warnx("unknown signal %s; valid signals:", name);
printsignals(stderr);
exit(1);
}
void
printsignals(fp)
FILE *fp;
{
int n;
for (n = 1; n < NSIG; n++) {
(void)fprintf(fp, "%s", sys_signame[n]);
if (n == (NSIG / 2) || n == (NSIG - 1))
(void)fprintf(fp, "\n");
else
(void)fprintf(fp, " ");
}
}
void
usage()
{
(void)fprintf(stderr, "usage: kill [-s signal_name] pid ...\n");
(void)fprintf(stderr, " kill -l [exit_status]\n");
(void)fprintf(stderr, " kill -signal_name pid ...\n");
(void)fprintf(stderr, " kill -signal_number pid ...\n");
exit(1);
}
+338
View File
@@ -0,0 +1,338 @@
.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)ls.1 8.7 (Berkeley) 7/29/94
.\"
.Dd July 29, 1994
.Dt LS 1
.Os
.Sh NAME
.Nm ls
.Nd list directory contents
.Sh SYNOPSIS
.Nm ls
.Op Fl ACFLRTWacdfiloqrstu1
.Op Ar file ...
.Sh DESCRIPTION
For each operand that names a
.Ar file
of a type other than
directory,
.Nm ls
displays its name as well as any requested,
associated information.
For each operand that names a
.Ar file
of type directory,
.Nm ls
displays the names of files contained
within that directory, as well as any requested, associated
information.
.Pp
If no operands are given, the contents of the current
directory are displayed.
If more than one operand is given,
non-directory operands are displayed first; directory
and non-directory operands are sorted separately and in
lexicographical order.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl A
List all entries except for
.Ql \&.
and
.Ql \&.. .
Always set for the super-user.
.It Fl C
Force multi-column output; this is the default when output is to a terminal.
.It Fl F
Display a slash (/) immediately after each pathname
that is a directory, an asterisk (*) after each that is
executable,
an at sign (@) after each symbolic link,
and a percent sign (%) after each whiteout.
.\" and a vertical bar (|) after each that is a
.\" .Tn FIFO .
.It Fl L
If argument is a symbolic link, list the file or directory the link references
rather than the link itself.
.It Fl R
Recursively list subdirectories encountered.
.It Fl T
Display complete time information for the file, including
month, day, hour, minute, second, and year.
.It Fl W
Display whiteouts when scanning directories.
.It Fl a
Include directory entries whose names begin with a
dot (.).
.It Fl c
Use time when file status was last changed for sorting or printing.
.It Fl d
Directories are listed as plain files (not searched recursively) and
symbolic links in the argument list are not indirected through.
.It Fl f
Output is not sorted.
.It Fl i
For each file, print the file's file serial number (inode number).
.It Fl l
(The lowercase letter ``ell.'') List in long format. (See below.)
If the output is to a terminal, a total sum for all the file
sizes is output on a line before the long listing.
.It Fl o
Include the file flags in a long
.Pq Fl l
output
.It Fl q
Force printing of non-graphic characters in file names as
the character `?'; this is the default when output is to a terminal.
.It Fl r
Reverse the order of the sort to get reverse
lexicographical order or the oldest entries first.
.It Fl s
Display the number of file system blocks actually used by each file, in units
of 512 bytes, where partial units are rounded up to the next integer value.
If the output is to a terminal, a total sum for all the file
sizes is output on a line before the listing.
.It Fl t
Sort by time modified (most recently modified
first) before sorting the operands by lexicographical
order.
.It Fl u
Use time of last access,
instead of last modification
of the file for sorting
.Pq Fl t
or printing
.Pq Fl l .
.It Fl \&1
(The numeric digit ``one.'') Force output to be
one entry per line.
This is the default when
output is not to a terminal.
.El
.Pp
The
.Fl 1 ,
.Fl C ,
and
.Fl l
options all override each other; the last one specified determines
the format used.
.Pp
The
.Fl c ,
and
.Fl u
options override each other; the last one specified determines
the file time used.
.Pp
By default,
.Nm ls
lists one entry per line to standard
output; the exceptions are to terminals or when the
.Fl C
option is specified.
.Pp
File information is displayed with one or more
<blank>s separating the information associated with the
.Fl i ,
.Fl s ,
and
.Fl l
options.
.Ss The Long Format
If the
.Fl l
option is given, the following information
is displayed for each file:
file mode,
number of links, owner name, group name,
number of bytes in the file, abbreviated
month, day-of-month file was last modified,
hour file last modified, minute file last
modified, and the pathname.
In addition, for each directory whose contents are displayed, the total
number of 512-byte blocks used by the files in the directory is displayed
on a line by itself immediately before the information for the files in the
directory.
.Pp
If the owner or group names are not a known user or group name
the numeric ID's are displayed.
.Pp
If the file is a character special or block special file,
the major and minor device numbers for the file are displayed
in the size field. If the file is a symbolic link the pathname of the
linked-to file is preceded by
.Dq \-> .
.Pp
The file mode printed under the -l option consists of the
entry type, owner permissions, and group permissions.
The entry type character describes the type of file, as
follows:
.Pp
.Bl -tag -width 4n -offset indent -compact
.It Sy b
Block special file.
.It Sy c
Character special file.
.It Sy d
Directory.
.It Sy l
Symbolic link.
.It Sy s
Socket link.
.\" .It Sy p
.\" .Tn FIFO .
.It Sy w
Whiteout.
.It Sy \-
Regular file.
.El
.Pp
The next three fields
are three characters each:
owner permissions,
group permissions, and
other permissions.
Each field has three character positions:
.Bl -enum -offset indent
.It
If
.Sy r ,
the file is readable; if
.Sy \- ,
it is not readable.
.It
If
.Sy w ,
the file is writable; if
.Sy \- ,
it is not writable.
.It
The first of the following that applies:
.Bl -tag -width 4n -offset indent
.It Sy S
If in the owner permissions, the file is not executable and
set-user-ID mode is set.
If in the group permissions, the file is not executable
and set-group-ID mode is set.
.It Sy s
If in the owner permissions, the file is executable
and set-user-ID mode is set.
If in the group permissions, the file is executable
and setgroup-ID mode is set.
.It Sy x
The file is executable or the directory is
searchable.
.It Sy \-
The file is neither readable, writeable, executable,
nor set-user-ID nor set-group-ID mode, nor sticky. (See below.)
.El
.Pp
These next two apply only to the third character in the last group
(other permissions).
.Bl -tag -width 4n -offset indent
.It Sy T
The sticky bit is set
(mode
.Li 1000 ) ,
but not execute or search permission. (See
.Xr chmod 1
or
.Xr sticky 8 . )
.It Sy t
The sticky bit is set (mode
.Li 1000 ) ,
and is searchable or executable.
(See
.Xr chmod 1
or
.Xr sticky 8 . )
.El
.El
.Pp
The
.Nm ls
utility exits 0 on success, and >0 if an error occurs.
.Sh ENVIRONMENTAL VARIABLES
The following environment variables affect the execution of
.Nm ls :
.Bl -tag -width BLOCKSIZE
.It Ev BLOCKSIZE
If the environmental variable
.Ev BLOCKSIZE
is set, the block counts
(see
.Fl s )
will be displayed in units of that size block.
.It COLUMNS
If this variable contains a string representing a
decimal integer, it is used as the
column position width for displaying
multiple-text-column output.
The
.Nm ls
utility calculates how
many pathname text columns to display
based on the width provided.
(See
.Fl C . )
.It Ev TZ
The timezone to use when displaying dates.
See
.Xr environ 7
for more information.
.El
.Sh COMPATIBILITY
The group field is now automatically included in the long listing for
files in order to be compatible with the
.St -p1003.2
specification.
.Sh SEE ALSO
.Xr chmod 1 ,
.Xr symlink 7 ,
.Xr sticky 8
.Sh HISTORY
An
.Nm ls
command appeared in
.At v6 .
.Sh STANDARDS
The
.Nm ls
function is expected to be a superset of the
.St -p1003.2
specification.
+518
View File
@@ -0,0 +1,518 @@
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Michael Fischbein.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1989, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)ls.c 8.7 (Berkeley) 8/5/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ls.h"
#include "extern.h"
static void display __P((FTSENT *, FTSENT *));
static int mastercmp __P((const FTSENT **, const FTSENT **));
static void traverse __P((int, char **, int));
static void (*printfcn) __P((DISPLAY *));
static int (*sortfcn) __P((const FTSENT *, const FTSENT *));
long blocksize; /* block size units */
int termwidth = 80; /* default terminal width */
/* flags */
int f_accesstime; /* use time of last access */
int f_column; /* columnated format */
int f_flags; /* show flags associated with a file */
int f_inode; /* print inode */
int f_listdir; /* list actual directory, not contents */
int f_listdot; /* list files beginning with . */
int f_longform; /* long listing format */
int f_newline; /* if precede with newline */
int f_nonprint; /* show unprintables as ? */
int f_nosort; /* don't sort output */
int f_recursive; /* ls subdirectories also */
int f_reversesort; /* reverse whatever sort is used */
int f_sectime; /* print the real time for all files */
int f_singlecol; /* use single column output */
int f_size; /* list size in short listing */
int f_statustime; /* use time of last mode change */
int f_dirname; /* if precede with directory name */
int f_timesort; /* sort by time vice name */
int f_type; /* add type character for non-regular files */
int f_whiteout; /* show whiteout entries */
int
main(argc, argv)
int argc;
char *argv[];
{
static char dot[] = ".", *dotav[] = { dot, NULL };
struct winsize win;
int ch, fts_options, notused;
char *p;
/* Terminal defaults to -Cq, non-terminal defaults to -1. */
if (isatty(STDOUT_FILENO)) {
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 ||
!win.ws_col) {
if ((p = getenv("COLUMNS")) != NULL)
termwidth = atoi(p);
}
else
termwidth = win.ws_col;
f_column = f_nonprint = 1;
} else
f_singlecol = 1;
/* Root is -A automatically. */
if (!getuid())
f_listdot = 1;
fts_options = FTS_PHYSICAL;
while ((ch = getopt(argc, argv, "1ACFLRTWacdfgiloqrstu")) != EOF) {
switch (ch) {
/*
* The -1, -C and -l options all override each other so shell
* aliasing works right.
*/
case '1':
f_singlecol = 1;
f_column = f_longform = 0;
break;
case 'C':
f_column = 1;
f_longform = f_singlecol = 0;
break;
case 'l':
f_longform = 1;
f_column = f_singlecol = 0;
break;
/* The -c and -u options override each other. */
case 'c':
f_statustime = 1;
f_accesstime = 0;
break;
case 'u':
f_accesstime = 1;
f_statustime = 0;
break;
case 'F':
f_type = 1;
break;
case 'L':
fts_options &= ~FTS_PHYSICAL;
fts_options |= FTS_LOGICAL;
break;
case 'R':
f_recursive = 1;
break;
case 'a':
fts_options |= FTS_SEEDOT;
/* FALLTHROUGH */
case 'A':
f_listdot = 1;
break;
/* The -d option turns off the -R option. */
case 'd':
f_listdir = 1;
f_recursive = 0;
break;
case 'f':
f_nosort = 1;
break;
case 'g': /* Compatibility with 4.3BSD. */
break;
case 'i':
f_inode = 1;
break;
case 'o':
f_flags = 1;
break;
case 'q':
f_nonprint = 1;
break;
case 'r':
f_reversesort = 1;
break;
case 's':
f_size = 1;
break;
case 'T':
f_sectime = 1;
break;
case 't':
f_timesort = 1;
break;
case 'W':
f_whiteout = 1;
break;
default:
case '?':
usage();
}
}
argc -= optind;
argv += optind;
/*
* If not -F, -i, -l, -s or -t options, don't require stat
* information.
*/
if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type)
fts_options |= FTS_NOSTAT;
/*
* If not -F, -d or -l options, follow any symbolic links listed on
* the command line.
*/
if (!f_longform && !f_listdir && !f_type)
fts_options |= FTS_COMFOLLOW;
/*
* If -W, show whiteout entries
*/
#ifdef FTS_WHITEOUT
if (f_whiteout)
fts_options |= FTS_WHITEOUT;
#endif
/* If -l or -s, figure out block size. */
if (f_longform || f_size) {
(void)getbsize(&notused, &blocksize);
blocksize /= 512;
}
/* Select a sort function. */
if (f_reversesort) {
if (!f_timesort)
sortfcn = revnamecmp;
else if (f_accesstime)
sortfcn = revacccmp;
else if (f_statustime)
sortfcn = revstatcmp;
else /* Use modification time. */
sortfcn = revmodcmp;
} else {
if (!f_timesort)
sortfcn = namecmp;
else if (f_accesstime)
sortfcn = acccmp;
else if (f_statustime)
sortfcn = statcmp;
else /* Use modification time. */
sortfcn = modcmp;
}
/* Select a print function. */
if (f_singlecol)
printfcn = printscol;
else if (f_longform)
printfcn = printlong;
else
printfcn = printcol;
if (argc)
traverse(argc, argv, fts_options);
else
traverse(1, dotav, fts_options);
exit(0);
}
static int output; /* If anything output. */
/*
* Traverse() walks the logical directory structure specified by the argv list
* in the order specified by the mastercmp() comparison function. During the
* traversal it passes linked lists of structures to display() which represent
* a superset (may be exact set) of the files to be displayed.
*/
static void
traverse(argc, argv, options)
int argc, options;
char *argv[];
{
FTS *ftsp;
FTSENT *p, *chp;
int ch_options;
if ((ftsp =
fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
err(1, NULL);
display(NULL, fts_children(ftsp, 0));
if (f_listdir)
return;
/*
* If not recursing down this tree and don't need stat info, just get
* the names.
*/
ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0;
while ((p = fts_read(ftsp)) != NULL)
switch (p->fts_info) {
case FTS_DC:
warnx("%s: directory causes a cycle", p->fts_name);
break;
case FTS_DNR:
case FTS_ERR:
warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
break;
case FTS_D:
if (p->fts_level != FTS_ROOTLEVEL &&
p->fts_name[0] == '.' && !f_listdot)
break;
/*
* If already output something, put out a newline as
* a separator. If multiple arguments, precede each
* directory with its name.
*/
if (output)
(void)printf("\n%s:\n", p->fts_path);
else if (argc > 1) {
(void)printf("%s:\n", p->fts_path);
output = 1;
}
chp = fts_children(ftsp, ch_options);
display(p, chp);
if (!f_recursive && chp != NULL)
(void)fts_set(ftsp, p, FTS_SKIP);
break;
}
if (errno)
err(1, "fts_read");
}
/*
* Display() takes a linked list of FTSENT structures and passes the list
* along with any other necessary information to the print function. P
* points to the parent directory of the display list.
*/
static void
display(p, list)
FTSENT *p, *list;
{
struct stat *sp;
DISPLAY d;
FTSENT *cur;
NAMES *np;
u_quad_t maxsize;
u_long btotal, maxblock, maxinode, maxlen, maxnlink;
int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser;
int entries, needstats;
char *user, *group, *flags, buf[20]; /* 32 bits == 10 digits */
/*
* If list is NULL there are two possibilities: that the parent
* directory p has no children, or that fts_children() returned an
* error. We ignore the error case since it will be replicated
* on the next call to fts_read() on the post-order visit to the
* directory p, and will be signalled in traverse().
*/
if (list == NULL)
return;
needstats = f_inode || f_longform || f_size;
flen = 0;
btotal = maxblock = maxinode = maxlen = maxnlink = 0;
bcfile = 0;
maxuser = maxgroup = maxflags = 0;
maxsize = 0;
for (cur = list, entries = 0; cur; cur = cur->fts_link) {
if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
warnx("%s: %s",
cur->fts_name, strerror(cur->fts_errno));
cur->fts_number = NO_PRINT;
continue;
}
/*
* P is NULL if list is the argv list, to which different rules
* apply.
*/
if (p == NULL) {
/* Directories will be displayed later. */
if (cur->fts_info == FTS_D && !f_listdir) {
cur->fts_number = NO_PRINT;
continue;
}
} else {
/* Only display dot file if -a/-A set. */
if (cur->fts_name[0] == '.' && !f_listdot) {
cur->fts_number = NO_PRINT;
continue;
}
}
if (f_nonprint)
prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen);
if (cur->fts_namelen > maxlen)
maxlen = cur->fts_namelen;
if (needstats) {
sp = cur->fts_statp;
if (sp->st_blocks > maxblock)
maxblock = sp->st_blocks;
if (sp->st_ino > maxinode)
maxinode = sp->st_ino;
if (sp->st_nlink > maxnlink)
maxnlink = sp->st_nlink;
if (sp->st_size > maxsize)
maxsize = sp->st_size;
btotal += sp->st_blocks;
if (f_longform) {
user = user_from_uid(sp->st_uid, 0);
if ((ulen = strlen(user)) > maxuser)
maxuser = ulen;
group = group_from_gid(sp->st_gid, 0);
if ((glen = strlen(group)) > maxgroup)
maxgroup = glen;
if (f_flags) {
flags =
flags_to_string(sp->st_flags, "-");
if ((flen = strlen(flags)) > maxflags)
maxflags = flen;
} else
flen = 0;
if ((np = malloc(sizeof(NAMES) +
ulen + glen + flen + 3)) == NULL)
err(1, NULL);
np->user = &np->data[0];
(void)strcpy(np->user, user);
np->group = &np->data[ulen + 1];
(void)strcpy(np->group, group);
if (S_ISCHR(sp->st_mode) ||
S_ISBLK(sp->st_mode))
bcfile = 1;
if (f_flags) {
np->flags = &np->data[ulen + glen + 2];
(void)strcpy(np->flags, flags);
}
cur->fts_pointer = np;
}
}
++entries;
}
if (!entries)
return;
d.list = list;
d.entries = entries;
d.maxlen = maxlen;
if (needstats) {
d.bcfile = bcfile;
d.btotal = btotal;
(void)snprintf(buf, sizeof(buf), "%lu", maxblock);
d.s_block = strlen(buf);
d.s_flags = maxflags;
d.s_group = maxgroup;
(void)snprintf(buf, sizeof(buf), "%lu", maxinode);
d.s_inode = strlen(buf);
(void)snprintf(buf, sizeof(buf), "%lu", maxnlink);
d.s_nlink = strlen(buf);
(void)snprintf(buf, sizeof(buf), "%qu", maxsize);
d.s_size = strlen(buf);
d.s_user = maxuser;
}
printfcn(&d);
output = 1;
if (f_longform)
for (cur = list; cur; cur = cur->fts_link)
free(cur->fts_pointer);
}
/*
* Ordering for mastercmp:
* If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories
* as larger than directories. Within either group, use the sort function.
* All other levels use the sort function. Error entries remain unsorted.
*/
static int
mastercmp(a, b)
const FTSENT **a, **b;
{
int a_info, b_info;
a_info = (*a)->fts_info;
if (a_info == FTS_ERR)
return (0);
b_info = (*b)->fts_info;
if (b_info == FTS_ERR)
return (0);
if (a_info == FTS_NS || b_info == FTS_NS)
return (namecmp(*a, *b));
if (a_info == b_info)
return (sortfcn(*a, *b));
if ((*a)->fts_level == FTS_ROOTLEVEL)
if (a_info == FTS_D)
return (1);
else if (b_info == FTS_D)
return (-1);
else
return (sortfcn(*a, *b));
else
return (sortfcn(*a, *b));
}
+296
View File
@@ -0,0 +1,296 @@
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Michael Fischbein.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)print.c 8.5 (Berkeley) 7/28/94";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
#include <utmp.h>
#include "ls.h"
#include "extern.h"
static int printaname __P((FTSENT *, u_long, u_long));
static void printlink __P((FTSENT *));
static void printtime __P((time_t));
static int printtype __P((u_int));
#define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT)
void
printscol(dp)
DISPLAY *dp;
{
FTSENT *p;
for (p = dp->list; p; p = p->fts_link) {
if (IS_NOPRINT(p))
continue;
(void)printaname(p, dp->s_inode, dp->s_block);
(void)putchar('\n');
}
}
void
printlong(dp)
DISPLAY *dp;
{
struct stat *sp;
FTSENT *p;
NAMES *np;
char buf[20];
if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
for (p = dp->list; p; p = p->fts_link) {
if (IS_NOPRINT(p))
continue;
sp = p->fts_statp;
if (f_inode)
(void)printf("%*lu ", dp->s_inode, sp->st_ino);
if (f_size)
(void)printf("%*qd ",
dp->s_block, howmany(sp->st_blocks, blocksize));
(void)strmode(sp->st_mode, buf);
np = p->fts_pointer;
(void)printf("%s %*u %-*s %-*s ", buf, dp->s_nlink,
sp->st_nlink, dp->s_user, np->user, dp->s_group,
np->group);
if (f_flags)
(void)printf("%-*s ", dp->s_flags, np->flags);
if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
(void)printf("%3d, %3d ",
major(sp->st_rdev), minor(sp->st_rdev));
else if (dp->bcfile)
(void)printf("%*s%*qd ",
8 - dp->s_size, "", dp->s_size, sp->st_size);
else
(void)printf("%*qd ", dp->s_size, sp->st_size);
if (f_accesstime)
printtime(sp->st_atime);
else if (f_statustime)
printtime(sp->st_ctime);
else
printtime(sp->st_mtime);
(void)printf("%s", p->fts_name);
if (f_type)
(void)printtype(sp->st_mode);
if (S_ISLNK(sp->st_mode))
printlink(p);
(void)putchar('\n');
}
}
#define TAB 8
void
printcol(dp)
DISPLAY *dp;
{
extern int termwidth;
static FTSENT **array;
static int lastentries = -1;
FTSENT *p;
int base, chcnt, cnt, col, colwidth, num;
int endcol, numcols, numrows, row;
/*
* Have to do random access in the linked list -- build a table
* of pointers.
*/
if (dp->entries > lastentries) {
lastentries = dp->entries;
if ((array =
realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
warn(NULL);
printscol(dp);
}
}
for (p = dp->list, num = 0; p; p = p->fts_link)
if (p->fts_number != NO_PRINT)
array[num++] = p;
colwidth = dp->maxlen;
if (f_inode)
colwidth += dp->s_inode + 1;
if (f_size)
colwidth += dp->s_block + 1;
if (f_type)
colwidth += 1;
colwidth = (colwidth + TAB) & ~(TAB - 1);
if (termwidth < 2 * colwidth) {
printscol(dp);
return;
}
numcols = termwidth / colwidth;
numrows = num / numcols;
if (num % numcols)
++numrows;
if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
for (row = 0; row < numrows; ++row) {
endcol = colwidth;
for (base = row, chcnt = col = 0; col < numcols; ++col) {
chcnt += printaname(array[base], dp->s_inode,
dp->s_block);
if ((base += numrows) >= num)
break;
while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
(void)putchar('\t');
chcnt = cnt;
}
endcol += colwidth;
}
(void)putchar('\n');
}
}
/*
* print [inode] [size] name
* return # of characters printed, no trailing characters.
*/
static int
printaname(p, inodefield, sizefield)
FTSENT *p;
u_long sizefield, inodefield;
{
struct stat *sp;
int chcnt;
sp = p->fts_statp;
chcnt = 0;
if (f_inode)
chcnt += printf("%*lu ", (int)inodefield, sp->st_ino);
if (f_size)
chcnt += printf("%*qd ",
(int)sizefield, howmany(sp->st_blocks, blocksize));
chcnt += printf("%s", p->fts_name);
if (f_type)
chcnt += printtype(sp->st_mode);
return (chcnt);
}
static void
printtime(ftime)
time_t ftime;
{
int i;
char *longstring;
longstring = ctime(&ftime);
for (i = 4; i < 11; ++i)
(void)putchar(longstring[i]);
#define SIXMONTHS ((DAYSPERNYEAR / 2) * SECSPERDAY)
if (f_sectime)
for (i = 11; i < 24; i++)
(void)putchar(longstring[i]);
else if (ftime + SIXMONTHS > time(NULL))
for (i = 11; i < 16; ++i)
(void)putchar(longstring[i]);
else {
(void)putchar(' ');
for (i = 20; i < 24; ++i)
(void)putchar(longstring[i]);
}
(void)putchar(' ');
}
static int
printtype(mode)
u_int mode;
{
switch (mode & S_IFMT) {
case S_IFDIR:
(void)putchar('/');
return (1);
case S_IFIFO:
(void)putchar('|');
return (1);
case S_IFLNK:
(void)putchar('@');
return (1);
case S_IFSOCK:
(void)putchar('=');
return (1);
case S_IFWHT:
(void)putchar('%');
return (1);
}
if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
(void)putchar('*');
return (1);
}
return (0);
}
static void
printlink(p)
FTSENT *p;
{
int lnklen;
char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
if (p->fts_level == FTS_ROOTLEVEL)
(void)snprintf(name, sizeof(name), "%s", p->fts_name);
else
(void)snprintf(name, sizeof(name),
"%s/%s", p->fts_parent->fts_accpath, p->fts_name);
if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
(void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
return;
}
path[lnklen] = '\0';
(void)printf(" -> %s", path);
}
+153
View File
@@ -0,0 +1,153 @@
/*-
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)stat_flags.c 8.2 (Berkeley) 7/28/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <stddef.h>
#include <string.h>
#define SAPPEND(s) { \
if (prefix != NULL) \
(void)strcat(string, prefix); \
(void)strcat(string, s); \
prefix = ","; \
}
/*
* flags_to_string --
* Convert stat flags to a comma-separated string. If no flags
* are set, return the default string.
*/
char *
flags_to_string(flags, def)
u_long flags;
char *def;
{
static char string[128];
char *prefix;
string[0] = '\0';
prefix = NULL;
if (flags & UF_APPEND)
SAPPEND("uappnd");
if (flags & UF_IMMUTABLE)
SAPPEND("uchg");
if (flags & UF_NODUMP)
SAPPEND("nodump");
if (flags & UF_OPAQUE)
SAPPEND("opaque");
if (flags & SF_APPEND)
SAPPEND("sappnd");
if (flags & SF_ARCHIVED)
SAPPEND("arch");
if (flags & SF_IMMUTABLE)
SAPPEND("schg");
return (prefix == NULL && def != NULL ? def : string);
}
#define TEST(a, b, f) { \
if (!memcmp(a, b, sizeof(b))) { \
if (clear) { \
if (clrp) \
*clrp |= (f); \
} else if (setp) \
*setp |= (f); \
break; \
} \
}
/*
* string_to_flags --
* Take string of arguments and return stat flags. Return 0 on
* success, 1 on failure. On failure, stringp is set to point
* to the offending token.
*/
int
string_to_flags(stringp, setp, clrp)
char **stringp;
u_long *setp, *clrp;
{
int clear;
char *string, *p;
clear = 0;
if (setp)
*setp = 0;
if (clrp)
*clrp = 0;
string = *stringp;
while ((p = strsep(&string, "\t ,")) != NULL) {
*stringp = p;
if (*p == '\0')
continue;
if (p[0] == 'n' && p[1] == 'o') {
clear = 1;
p += 2;
}
switch (p[0]) {
case 'a':
TEST(p, "arch", SF_ARCHIVED);
TEST(p, "archived", SF_ARCHIVED);
return (1);
case 'd':
clear = !clear;
TEST(p, "dump", UF_NODUMP);
return (1);
case 'o':
TEST(p, "opaque", UF_OPAQUE);
return (1);
case 's':
TEST(p, "sappnd", SF_APPEND);
TEST(p, "sappend", SF_APPEND);
TEST(p, "schg", SF_IMMUTABLE);
TEST(p, "schange", SF_IMMUTABLE);
TEST(p, "simmutable", SF_IMMUTABLE);
return (1);
case 'u':
TEST(p, "uappnd", UF_APPEND);
TEST(p, "uappend", UF_APPEND);
TEST(p, "uchg", UF_IMMUTABLE);
TEST(p, "uchange", UF_IMMUTABLE);
TEST(p, "uimmutable", UF_IMMUTABLE);
/* FALLTHROUGH */
default:
return (1);
}
}
return (0);
}
+72
View File
@@ -0,0 +1,72 @@
/*
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Michael Fischbein.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)util.c 8.5 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ls.h"
#include "extern.h"
void
prcopy(src, dest, len)
char *src, *dest;
int len;
{
int ch;
while (len--) {
ch = *src++;
*dest++ = isprint(ch) ? ch : '?';
}
}
void
usage()
{
(void)fprintf(stderr,
"usage: ls [-1ACFLRTWacdfikloqrstu] [file ...]\n");
exit(1);
}
+119
View File
@@ -0,0 +1,119 @@
/*-
* Copyright (c) 1992, 1993, 1994
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)fmt.c 8.5 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vis.h>
#include "ps.h"
static char *cmdpart __P((char *));
static char *shquote __P((char **));
/*
* XXX
* This is a stub until marc does the real one.
*/
static char *
shquote(argv)
char **argv;
{
char **p, *dst, *src;
static char buf[4096]; /* XXX */
if (*argv == 0) {
buf[0] = 0;
return (buf);
}
dst = buf;
for (p = argv; (src = *p++) != 0; ) {
if (*src == 0)
continue;
strvis(dst, src, VIS_NL | VIS_CSTYLE);
while (*dst)
dst++;
*dst++ = ' ';
}
if (dst != buf)
--dst;
*dst = '\0';
return (buf);
}
static char *
cmdpart(arg0)
char *arg0;
{
char *cp;
return ((cp = strrchr(arg0, '/')) != NULL ? cp + 1 : arg0);
}
char *
fmt_argv(argv, cmd, maxlen)
char **argv;
char *cmd;
int maxlen;
{
int len;
char *ap, *cp;
if (argv == 0 || argv[0] == 0) {
if (cmd == NULL)
return ("");
ap = NULL;
len = maxlen + 3;
} else {
ap = shquote(argv);
len = strlen(ap) + maxlen + 4;
}
if ((cp = malloc(len)) == NULL)
return (NULL);
if (ap == NULL)
sprintf(cp, "(%.*s)", maxlen, cmd);
else if (strncmp(cmdpart(argv[0]), cmd, maxlen) != 0)
sprintf(cp, "%s (%.*s)", ap, maxlen, cmd);
else
(void) strcpy(cp, ap);
return (cp);
}
+68
View File
@@ -0,0 +1,68 @@
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt PWD 1
.Os BSD 4
.Sh NAME
.Nm pwd
.Nd return working directory name
.Sh SYNOPSIS
.Nm pwd
.Sh DESCRIPTION
.Nm Pwd
writes the absolute pathname of the current working directory to
the standard output.
.Pp
The pwd utility exits 0 on success, and >0 if an error occurs.
.Sh STANDARDS
The
.Nm pwd
command is expected to be
.St -p1003.2
compatible .
.Sh SEE ALSO
.Xr cd 1 ,
.Xr csh 1 ,
.Xr getcwd 3
.Sh BUGS
In
.Xr csh 1
the command
.Ic dirs
is always faster (although it can give a different answer in the rare case
that the current directory or a containing directory was moved after
the shell descended into it).
+155
View File
@@ -0,0 +1,155 @@
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
.\"
.Dd December 5, 1994
.Dt RM 1
.Os
.Sh NAME
.Nm rm
.Nd remove directory entries
.Sh SYNOPSIS
.Nm rm
.Op Fl f | Fl i
.Op Fl dPRrW
.Ar file ...
.Sh DESCRIPTION
The
.Nm rm
utility attempts to remove the non-directory type files specified on the
command line.
If the permissions of the file do not permit writing, and the standard
input device is a terminal, the user is prompted (on the standard error
output) for confirmation.
.Pp
The options are as follows:
.Bl -tag -width flag
.It Fl d
Attempt to remove directories as well as other types of files.
.It Fl f
Attempt to remove the files without prompting for confirmation,
regardless of the file's permissions.
If the file does not exist, do not display a diagnostic message or modify
the exit status to reflect an error.
The
.Fl f
option overrides any previous
.Fl i
options.
.It Fl i
Request confirmation before attempting to remove each file, regardless of
the file's permissions, or whether or not the standard input device is a
terminal.
The
.Fl i
option overrides any previous
.Fl f
options.
.It Fl P
Overwrite regular files before deleting them.
Files are overwritten three times, first with the byte pattern 0xff,
then 0x00, and then 0xff again, before they are deleted.
.It Fl R
Attempt to remove the file hierarchy rooted in each file argument.
The
.Fl R
option implies the
.Fl d
option.
If the
.Fl i
option is specified, the user is prompted for confirmation before
each directory's contents are processed (as well as before the attempt
is made to remove the directory).
If the user does not respond affirmatively, the file hierarchy rooted in
that directory is skipped.
.Pp
.It Fl r
Equivalent to
.Fl R .
.It Fl W
Attempts to undelete the named files.
Currently, this option can only be used to recover
files covered by whiteouts.
.El
.Pp
The
.Nm rm
utility removes symbolic links, not the files referenced by the links.
.Pp
It is an error to attempt to remove the files ``.'' and ``..''.
.Pp
The
.Nm rm
utility exits 0 if all of the named files or file hierarchies were removed,
or if the
.Fl f
option was specified and all of the existing files or file hierarchies were
removed.
If an error occurs,
.Nm rm
exits with a value >0.
.Sh SEE ALSO
.Xr rmdir 1 ,
.Xr undelete 2 ,
.Xr unlink 2 ,
.Xr fts 3 ,
.Xr symlink 7
.Sh BUGS
The
.Fl P
option assumes that the underlying file system is a fixed-block file
system.
UFS is a fixed-block file system, LFS is not.
In addition, only regular files are overwritten, other types of files
are not.
.Sh COMPATIBILITY
The
.Nm rm
utility differs from historical implementations in that the
.Fl f
option only masks attempts to remove non-existent files instead of
masking a large variety of errors.
.Pp
Also, historical
.Bx
implementations prompted on the standard output,
not the standard error output.
.Sh STANDARDS
The
.Nm rm
command is expected to be
.St -p1003.2
compatible.
+403
View File
@@ -0,0 +1,403 @@
/*-
* Copyright (c) 1990, 1993, 1994
* 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1990, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rm.c 8.8 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int dflag, eval, fflag, iflag, Pflag, Wflag, stdin_ok;
int check __P((char *, char *, struct stat *));
void checkdot __P((char **));
void rm_file __P((char **));
void rm_overwrite __P((char *, struct stat *));
void rm_tree __P((char **));
void usage __P((void));
/*
* rm --
* This rm is different from historic rm's, but is expected to match
* POSIX 1003.2 behavior. The most visible difference is that -f
* has two specific effects now, ignore non-existent files and force
* file removal.
*/
int
main(argc, argv)
int argc;
char *argv[];
{
int ch, rflag;
Pflag = rflag = 0;
while ((ch = getopt(argc, argv, "dfiPRrW")) != -1)
switch(ch) {
case 'd':
dflag = 1;
break;
case 'f':
fflag = 1;
iflag = 0;
break;
case 'i':
fflag = 0;
iflag = 1;
break;
case 'P':
Pflag = 1;
break;
case 'R':
case 'r': /* Compatibility. */
rflag = 1;
break;
case 'W':
Wflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
checkdot(argv);
if (*argv) {
stdin_ok = isatty(STDIN_FILENO);
if (rflag)
rm_tree(argv);
else
rm_file(argv);
}
exit (eval);
}
void
rm_tree(argv)
char **argv;
{
FTS *fts;
FTSENT *p;
int needstat;
int flags;
/*
* Remove a file hierarchy. If forcing removal (-f), or interactive
* (-i) or can't ask anyway (stdin_ok), don't stat the file.
*/
needstat = !fflag && !iflag && stdin_ok;
/*
* If the -i option is specified, the user can skip on the pre-order
* visit. The fts_number field flags skipped directories.
*/
#define SKIPPED 1
flags = FTS_PHYSICAL;
if (!needstat)
flags |= FTS_NOSTAT;
if (Wflag)
flags |= FTS_WHITEOUT;
if (!(fts = fts_open(argv, flags, (int (*)())NULL)))
err(1, NULL);
while ((p = fts_read(fts)) != NULL) {
switch (p->fts_info) {
case FTS_DNR:
if (!fflag || p->fts_errno != ENOENT) {
warnx("%s: %s",
p->fts_path, strerror(p->fts_errno));
eval = 1;
}
continue;
case FTS_ERR:
errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
case FTS_NS:
/*
* FTS_NS: assume that if can't stat the file, it
* can't be unlinked.
*/
if (!needstat)
break;
if (!fflag || p->fts_errno != ENOENT) {
warnx("%s: %s",
p->fts_path, strerror(p->fts_errno));
eval = 1;
}
continue;
case FTS_D:
/* Pre-order: give user chance to skip. */
if (!fflag && !check(p->fts_path, p->fts_accpath,
p->fts_statp)) {
(void)fts_set(fts, p, FTS_SKIP);
p->fts_number = SKIPPED;
}
continue;
case FTS_DP:
/* Post-order: see if user skipped. */
if (p->fts_number == SKIPPED)
continue;
break;
default:
if (!fflag &&
!check(p->fts_path, p->fts_accpath, p->fts_statp))
continue;
}
/*
* If we can't read or search the directory, may still be
* able to remove it. Don't print out the un{read,search}able
* message unless the remove fails.
*/
switch (p->fts_info) {
case FTS_DP:
case FTS_DNR:
if (!rmdir(p->fts_accpath) || fflag && errno == ENOENT)
continue;
break;
case FTS_W:
if (!undelete(p->fts_accpath) ||
fflag && errno == ENOENT)
continue;
break;
default:
if (Pflag)
rm_overwrite(p->fts_accpath, NULL);
if (!unlink(p->fts_accpath) || fflag && errno == ENOENT)
continue;
}
warn("%s", p->fts_path);
eval = 1;
}
if (errno)
err(1, "fts_read");
}
void
rm_file(argv)
char **argv;
{
struct stat sb;
int rval;
char *f;
/*
* Remove a file. POSIX 1003.2 states that, by default, attempting
* to remove a directory is an error, so must always stat the file.
*/
while ((f = *argv++) != NULL) {
/* Assume if can't stat the file, can't unlink it. */
if (lstat(f, &sb)) {
if (Wflag) {
sb.st_mode = S_IFWHT|S_IWUSR|S_IRUSR;
} else {
if (!fflag || errno != ENOENT) {
warn("%s", f);
eval = 1;
}
continue;
}
} else if (Wflag) {
warnx("%s: %s", f, strerror(EEXIST));
eval = 1;
continue;
}
if (S_ISDIR(sb.st_mode) && !dflag) {
warnx("%s: is a directory", f);
eval = 1;
continue;
}
if (!fflag && !S_ISWHT(sb.st_mode) && !check(f, f, &sb))
continue;
if (S_ISWHT(sb.st_mode))
rval = undelete(f);
else if (S_ISDIR(sb.st_mode))
rval = rmdir(f);
else {
if (Pflag)
rm_overwrite(f, &sb);
rval = unlink(f);
}
if (rval && (!fflag || errno != ENOENT)) {
warn("%s", f);
eval = 1;
}
}
}
/*
* rm_overwrite --
* Overwrite the file 3 times with varying bit patterns.
*
* XXX
* This is a cheap way to *really* delete files. Note that only regular
* files are deleted, directories (and therefore names) will remain.
* Also, this assumes a fixed-block file system (like FFS, or a V7 or a
* System V file system). In a logging file system, you'll have to have
* kernel support.
*/
void
rm_overwrite(file, sbp)
char *file;
struct stat *sbp;
{
struct stat sb;
off_t len;
int fd, wlen;
char buf[8 * 1024];
fd = -1;
if (sbp == NULL) {
if (lstat(file, &sb))
goto err;
sbp = &sb;
}
if (!S_ISREG(sbp->st_mode))
return;
if ((fd = open(file, O_WRONLY, 0)) == -1)
goto err;
#define PASS(byte) { \
memset(buf, byte, sizeof(buf)); \
for (len = sbp->st_size; len > 0; len -= wlen) { \
wlen = len < sizeof(buf) ? len : sizeof(buf); \
if (write(fd, buf, wlen) != wlen) \
goto err; \
} \
}
PASS(0xff);
if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
goto err;
PASS(0x00);
if (fsync(fd) || lseek(fd, (off_t)0, SEEK_SET))
goto err;
PASS(0xff);
if (!fsync(fd) && !close(fd))
return;
err: eval = 1;
warn("%s", file);
}
int
check(path, name, sp)
char *path, *name;
struct stat *sp;
{
int ch, first;
char modep[15];
/* Check -i first. */
if (iflag)
(void)fprintf(stderr, "remove %s? ", path);
else {
/*
* If it's not a symbolic link and it's unwritable and we're
* talking to a terminal, ask. Symbolic links are excluded
* because their permissions are meaningless. Check stdin_ok
* first because we may not have stat'ed the file.
*/
if (!stdin_ok || S_ISLNK(sp->st_mode) || !access(name, W_OK))
return (1);
strmode(sp->st_mode, modep);
(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
modep + 1, modep[9] == ' ' ? "" : " ",
user_from_uid(sp->st_uid, 0),
group_from_gid(sp->st_gid, 0), path);
}
(void)fflush(stderr);
first = ch = getchar();
while (ch != '\n' && ch != EOF)
ch = getchar();
return (first == 'y');
}
#define ISDOT(a) ((a)[0] == '.' && (!(a)[1] || (a)[1] == '.' && !(a)[2]))
void
checkdot(argv)
char **argv;
{
char *p, **save, **t;
int complained;
complained = 0;
for (t = argv; *t;) {
if ((p = strrchr(*t, '/')) != NULL)
++p;
else
p = *t;
if (ISDOT(p)) {
if (!complained++)
warnx("\".\" and \"..\" may not be removed");
eval = 1;
for (save = t; (t[0] = t[1]) != NULL; ++t)
continue;
t = save;
} else
++t;
}
}
void
usage()
{
(void)fprintf(stderr, "usage: rm [-dfiPRrW] file ...\n");
exit(1);
}
+373
View File
@@ -0,0 +1,373 @@
/*
* Copyright (c) 1988, 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rmail.c 8.3 (Berkeley) 5/15/95";
#endif /* not lint */
/*
* RMAIL -- UUCP mail server.
*
* This program reads the >From ... remote from ... lines that UUCP is so
* fond of and turns them into something reasonable. It then execs sendmail
* with various options built from these lines.
*
* The expected syntax is:
*
* <user> := [-a-z0-9]+
* <date> := ctime format
* <site> := [-a-z0-9!]+
* <blank line> := "^\n$"
* <from> := "From" <space> <user> <space> <date>
* [<space> "remote from" <space> <site>]
* <forward> := ">" <from>
* msg := <from> <forward>* <blank-line> <body>
*
* The output of rmail(8) compresses the <forward> lines into a single
* from path.
*
* The err(3) routine is included here deliberately to make this code
* a bit more portable.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <ctype.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#ifndef MAX
# define MAX(a, b) ((a) < (b) ? (b) : (a))
#endif
void err __P((int, const char *, ...));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int errno, optind;
FILE *fp;
struct stat sb;
size_t fplen, fptlen, len;
off_t offset;
int ch, debug, i, pdes[2], pid, status;
char *addrp, *domain, *p, *t;
char *from_path, *from_sys, *from_user;
char *args[100], buf[2048], lbuf[2048];
debug = 0;
domain = "UUCP"; /* Default "domain". */
while ((ch = getopt(argc, argv, "D:T")) != EOF)
switch (ch) {
case 'T':
debug = 1;
break;
case 'D':
domain = optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
from_path = from_sys = from_user = NULL;
for (offset = 0;;) {
/* Get and nul-terminate the line. */
if (fgets(lbuf, sizeof(lbuf), stdin) == NULL)
exit (EX_DATAERR);
if ((p = strchr(lbuf, '\n')) == NULL)
err(EX_DATAERR, "line too long");
*p = '\0';
/* Parse lines until reach a non-"From" line. */
if (!strncmp(lbuf, "From ", 5))
addrp = lbuf + 5;
else if (!strncmp(lbuf, ">From ", 6))
addrp = lbuf + 6;
else if (offset == 0)
err(EX_DATAERR,
"missing or empty From line: %s", lbuf);
else {
*p = '\n';
break;
}
if (*addrp == '\0')
err(EX_DATAERR, "corrupted From line: %s", lbuf);
/* Use the "remote from" if it exists. */
for (p = addrp; (p = strchr(p + 1, 'r')) != NULL;)
if (!strncmp(p, "remote from ", 12)) {
for (t = p += 12; *t && !isspace(*t); ++t);
*t = '\0';
if (debug)
(void)fprintf(stderr,
"remote from: %s\n", p);
break;
}
/* Else use the string up to the last bang. */
if (p == NULL)
if (*addrp == '!')
err(EX_DATAERR,
"bang starts address: %s", addrp);
else if ((t = strrchr(addrp, '!')) != NULL) {
*t = '\0';
p = addrp;
addrp = t + 1;
if (*addrp == '\0')
err(EX_DATAERR,
"corrupted From line: %s", lbuf);
if (debug)
(void)fprintf(stderr, "bang: %s\n", p);
}
/* 'p' now points to any system string from this line. */
if (p != NULL) {
/* Nul terminate it as necessary. */
for (t = p; *t && !isspace(*t); ++t);
*t = '\0';
/* If the first system, copy to the from_sys string. */
if (from_sys == NULL) {
if ((from_sys = strdup(p)) == NULL)
err(EX_TEMPFAIL, NULL);
if (debug)
(void)fprintf(stderr,
"from_sys: %s\n", from_sys);
}
/* Concatenate to the path string. */
len = t - p;
if (from_path == NULL) {
fplen = 0;
if ((from_path = malloc(fptlen = 256)) == NULL)
err(EX_TEMPFAIL, NULL);
}
if (fplen + len + 2 > fptlen) {
fptlen += MAX(fplen + len + 2, 256);
if ((from_path =
realloc(from_path, fptlen)) == NULL)
err(EX_TEMPFAIL, NULL);
}
memmove(from_path + fplen, p, len);
fplen += len;
from_path[fplen++] = '!';
from_path[fplen] = '\0';
}
/* Save off from user's address; the last one wins. */
for (p = addrp; *p && !isspace(*p); ++p);
*p = '\0';
if (*addrp == '\0')
addrp = "<>";
if (from_user != NULL)
free(from_user);
if ((from_user = strdup(addrp)) == NULL)
err(EX_TEMPFAIL, NULL);
if (debug) {
if (from_path != NULL)
(void)fprintf(stderr,
"from_path: %s\n", from_path);
(void)fprintf(stderr, "from_user: %s\n", from_user);
}
if (offset != -1)
offset = (off_t)ftell(stdin);
}
i = 0;
args[i++] = _PATH_SENDMAIL; /* Build sendmail's argument list. */
args[i++] = "-oee"; /* No errors, just status. */
args[i++] = "-odq"; /* Queue it, don't try to deliver. */
args[i++] = "-oi"; /* Ignore '.' on a line by itself. */
/* set from system and protocol used */
if (from_sys == NULL)
(void)snprintf(buf, sizeof(buf), "-p%s", domain);
else if (strchr(from_sys, '.') == NULL)
(void)snprintf(buf, sizeof(buf), "-p%s:%s.%s",
domain, from_sys, domain);
else
(void)snprintf(buf, sizeof(buf), "-p%s:%s", domain, from_sys);
if ((args[i++] = strdup(buf)) == NULL)
err(EX_TEMPFAIL, NULL);
/* Set name of ``from'' person. */
(void)snprintf(buf, sizeof(buf), "-f%s%s",
from_path ? from_path : "", from_user);
if ((args[i++] = strdup(buf)) == NULL)
err(EX_TEMPFAIL, NULL);
/*
* Don't copy arguments beginning with - as they will be
* passed to sendmail and could be interpreted as flags.
* To prevent confusion of sendmail wrap < and > around
* the address (helps to pass addrs like @gw1,@gw2:aa@bb)
*/
while (*argv) {
if (**argv == '-')
err(EX_USAGE, "dash precedes argument: %s", *argv);
if (strchr(*argv, ',') == NULL || strchr(*argv, '<') != NULL)
args[i++] = *argv;
else {
if ((args[i] = malloc(strlen(*argv) + 3)) == NULL)
err(EX_TEMPFAIL, "Cannot malloc");
sprintf (args [i++], "<%s>", *argv);
}
argv++;
}
args[i] = 0;
if (debug) {
(void)fprintf(stderr, "Sendmail arguments:\n");
for (i = 0; args[i]; i++)
(void)fprintf(stderr, "\t%s\n", args[i]);
}
/*
* If called with a regular file as standard input, seek to the right
* position in the file and just exec sendmail. Could probably skip
* skip the stat, but it's not unreasonable to believe that a failed
* seek will cause future reads to fail.
*/
if (!fstat(STDIN_FILENO, &sb) && S_ISREG(sb.st_mode)) {
if (lseek(STDIN_FILENO, offset, SEEK_SET) != offset)
err(EX_TEMPFAIL, "stdin seek");
execv(_PATH_SENDMAIL, args);
err(EX_OSERR, "%s", _PATH_SENDMAIL);
}
if (pipe(pdes) < 0)
err(EX_OSERR, NULL);
switch (pid = vfork()) {
case -1: /* Err. */
err(EX_OSERR, NULL);
case 0: /* Child. */
if (pdes[0] != STDIN_FILENO) {
(void)dup2(pdes[0], STDIN_FILENO);
(void)close(pdes[0]);
}
(void)close(pdes[1]);
execv(_PATH_SENDMAIL, args);
_exit(127);
/* NOTREACHED */
}
if ((fp = fdopen(pdes[1], "w")) == NULL)
err(EX_OSERR, NULL);
(void)close(pdes[0]);
/* Copy the file down the pipe. */
do {
(void)fprintf(fp, "%s", lbuf);
} while (fgets(lbuf, sizeof(lbuf), stdin) != NULL);
if (ferror(stdin))
err(EX_TEMPFAIL, "stdin: %s", strerror(errno));
if (fclose(fp))
err(EX_OSERR, NULL);
if ((waitpid(pid, &status, 0)) == -1)
err(EX_OSERR, "%s", _PATH_SENDMAIL);
if (!WIFEXITED(status))
err(EX_OSERR,
"%s: did not terminate normally", _PATH_SENDMAIL);
if (WEXITSTATUS(status))
err(status, "%s: terminated with %d (non-zero) status",
_PATH_SENDMAIL, WEXITSTATUS(status));
exit(EX_OK);
}
void
usage()
{
(void)fprintf(stderr, "usage: rmail [-T] [-D domain] user ...\n");
exit(EX_USAGE);
}
#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#ifdef __STDC__
err(int eval, const char *fmt, ...)
#else
err(eval, fmt, va_alist)
int eval;
const char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "rmail: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(eval);
}
+300
View File
@@ -0,0 +1,300 @@
/*-
* Copyright (c) 1991, 1993, 1994
* 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.
*/
#ifndef lint
static char sccsid[] = "@(#)key.c 8.4 (Berkeley) 2/20/95";
#endif /* not lint */
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "stty.h"
#include "extern.h"
__BEGIN_DECLS
void f_all __P((struct info *));
void f_cbreak __P((struct info *));
void f_columns __P((struct info *));
void f_dec __P((struct info *));
void f_everything __P((struct info *));
void f_extproc __P((struct info *));
void f_ispeed __P((struct info *));
void f_nl __P((struct info *));
void f_ospeed __P((struct info *));
void f_raw __P((struct info *));
void f_rows __P((struct info *));
void f_sane __P((struct info *));
void f_size __P((struct info *));
void f_speed __P((struct info *));
void f_tty __P((struct info *));
__END_DECLS
static struct key {
char *name; /* name */
void (*f) __P((struct info *)); /* function */
#define F_NEEDARG 0x01 /* needs an argument */
#define F_OFFOK 0x02 /* can turn off */
int flags;
} keys[] = {
{ "all", f_all, 0 },
{ "cbreak", f_cbreak, F_OFFOK },
{ "cols", f_columns, F_NEEDARG },
{ "columns", f_columns, F_NEEDARG },
{ "cooked", f_sane, 0 },
{ "dec", f_dec, 0 },
{ "everything", f_everything, 0 },
{ "extproc", f_extproc, F_OFFOK },
{ "ispeed", f_ispeed, F_NEEDARG },
{ "new", f_tty, 0 },
{ "nl", f_nl, F_OFFOK },
{ "old", f_tty, 0 },
{ "ospeed", f_ospeed, F_NEEDARG },
{ "raw", f_raw, F_OFFOK },
{ "rows", f_rows, F_NEEDARG },
{ "sane", f_sane, 0 },
{ "size", f_size, 0 },
{ "speed", f_speed, 0 },
{ "tty", f_tty, 0 },
};
static int
c_key(a, b)
const void *a, *b;
{
return (strcmp(((struct key *)a)->name, ((struct key *)b)->name));
}
int
ksearch(argvp, ip)
char ***argvp;
struct info *ip;
{
char *name;
struct key *kp, tmp;
name = **argvp;
if (*name == '-') {
ip->off = 1;
++name;
} else
ip->off = 0;
tmp.name = name;
if (!(kp = (struct key *)bsearch(&tmp, keys,
sizeof(keys)/sizeof(struct key), sizeof(struct key), c_key)))
return (0);
if (!(kp->flags & F_OFFOK) && ip->off) {
errx(1, "illegal option -- %s", name);
usage();
}
if (kp->flags & F_NEEDARG && !(ip->arg = *++*argvp)) {
errx(1, "option requires an argument -- %s", name);
usage();
}
kp->f(ip);
return (1);
}
void
f_all(ip)
struct info *ip;
{
print(&ip->t, &ip->win, ip->ldisc, BSD);
}
void
f_cbreak(ip)
struct info *ip;
{
if (ip->off)
f_sane(ip);
else {
ip->t.c_iflag |= BRKINT|IXON|IMAXBEL;
ip->t.c_oflag |= OPOST;
ip->t.c_lflag |= ISIG|IEXTEN;
ip->t.c_lflag &= ~ICANON;
ip->set = 1;
}
}
void
f_columns(ip)
struct info *ip;
{
ip->win.ws_col = atoi(ip->arg);
ip->wset = 1;
}
void
f_dec(ip)
struct info *ip;
{
ip->t.c_cc[VERASE] = (u_char)0177;
ip->t.c_cc[VKILL] = CTRL('u');
ip->t.c_cc[VINTR] = CTRL('c');
ip->t.c_lflag &= ~ECHOPRT;
ip->t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
ip->t.c_iflag &= ~IXANY;
ip->set = 1;
}
void
f_everything(ip)
struct info *ip;
{
print(&ip->t, &ip->win, ip->ldisc, BSD);
}
void
f_extproc(ip)
struct info *ip;
{
if (ip->off) {
int tmp = 0;
(void)ioctl(ip->fd, TIOCEXT, &tmp);
} else {
int tmp = 1;
(void)ioctl(ip->fd, TIOCEXT, &tmp);
}
ip->set = 1;
}
void
f_ispeed(ip)
struct info *ip;
{
cfsetispeed(&ip->t, atoi(ip->arg));
ip->set = 1;
}
void
f_nl(ip)
struct info *ip;
{
if (ip->off) {
ip->t.c_iflag |= ICRNL;
ip->t.c_oflag |= ONLCR;
} else {
ip->t.c_iflag &= ~ICRNL;
ip->t.c_oflag &= ~ONLCR;
}
ip->set = 1;
}
void
f_ospeed(ip)
struct info *ip;
{
cfsetospeed(&ip->t, atoi(ip->arg));
ip->set = 1;
}
void
f_raw(ip)
struct info *ip;
{
if (ip->off)
f_sane(ip);
else {
cfmakeraw(&ip->t);
ip->t.c_cflag &= ~(CSIZE|PARENB);
ip->t.c_cflag |= CS8;
ip->set = 1;
}
}
void
f_rows(ip)
struct info *ip;
{
ip->win.ws_row = atoi(ip->arg);
ip->wset = 1;
}
void
f_sane(ip)
struct info *ip;
{
ip->t.c_cflag = TTYDEF_CFLAG | (ip->t.c_cflag & CLOCAL);
ip->t.c_iflag = TTYDEF_IFLAG;
ip->t.c_iflag |= ICRNL;
/* preserve user-preference flags in lflag */
#define LKEEP (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
ip->t.c_lflag = TTYDEF_LFLAG | (ip->t.c_lflag & LKEEP);
ip->t.c_oflag = TTYDEF_OFLAG;
ip->set = 1;
}
void
f_size(ip)
struct info *ip;
{
(void)printf("%d %d\n", ip->win.ws_row, ip->win.ws_col);
}
void
f_speed(ip)
struct info *ip;
{
(void)printf("%d\n", cfgetospeed(&ip->t));
}
void
f_tty(ip)
struct info *ip;
{
int tmp;
tmp = TTYDISC;
if (ioctl(0, TIOCSETD, &tmp) < 0)
err(1, "TIOCSETD");
}
+585
View File
@@ -0,0 +1,585 @@
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" the Institute of Electrical and Electronics Engineers, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)stty.1 8.5 (Berkeley) 6/1/94
.\"
.Dd June 1, 1994
.Dt STTY 1
.Os
.Sh NAME
.Nm stty
.Nd set the options for a terminal device interface
.Sh SYNOPSIS
.Nm stty
.Op Fl a | Fl e | Fl g
.Op Fl f Ar file
.Op operands
.Sh DESCRIPTION
The
.Nm stty
utility sets or reports on terminal
characteristics for the device that is its standard input.
If no options or operands are specified, it reports the settings of a subset
of characteristics as well as additional ones if they differ from their
default values.
Otherwise it modifies
the terminal state according to the specified arguments.
Some combinations of arguments are mutually
exclusive on some terminal types.
.Pp
The following options are available:
.Bl -tag -width Ds
.It Fl a
Display all the current settings for the terminal to standard output
as per
.St -p1003.2 .
.It Fl e
Display all the current settings for the terminal to standard output
in the traditional
.Tn BSD
``all'' and ``everything'' formats.
.It Fl f
Open and use the terminal named by
.Ar file
rather than using standard input. The file is opened
using the
.Dv O_NONBLOCK
flag of
.Fn open ,
making it possible to
set or display settings on a terminal that might otherwise
block on the open.
.It Fl g
Display all the current settings for the terminal to standard output
in a form that may be used as an argument to a subsequent invocation of
.Nm stty
to restore the current terminal state as per
.St -p1003.2 .
.El
.Pp
The following arguments are available to set the terminal
characteristics:
.Ss Control Modes:
.Pp
Control mode flags affect hardware characteristics associated with the
terminal. This corresponds to the c_cflag in the termios structure.
.Bl -tag -width Fl
.It Cm parenb Pq Fl parenb
Enable (disable) parity generation
and detection.
.It Cm parodd Pq Fl parodd
Select odd (even) parity.
.It Cm cs5 cs6 cs7 cs8
Select character size, if possible.
.It Ar number
Set terminal baud rate to the
number given, if possible.
If the
baud rate is set to zero, modem
control is no longer
asserted.
.It Cm ispeed Ar number
Set terminal input baud rate to the
number given, if possible.
If the
input baud rate is set to zero, the
input baud rate is set to the
value of the output baud
rate.
.It Cm ospeed Ar number
Set terminal output baud rate to
the number given, if possible.
If
the output baud rate is set to
zero, modem control is
no longer asserted.
.ne 1i
.It Cm speed Ar number
This sets both
.Cm ispeed
and
.Cm ospeed
to
.Ar number .
.It Cm hupcl Pq Fl hupcl
Stop asserting modem control
(do not stop asserting modem control) on last close.
.It Cm hup Pq Fl hup
Same as hupcl
.Pq Fl hupcl .
.It Cm cstopb Pq Fl cstopb
Use two (one) stop bits per character.
.It Cm cread Pq Fl cread
Enable (disable) the receiver.
.It Cm clocal Pq Fl clocal
Assume a line without (with) modem
control.
.It Cm crtscts Pq Fl crtscts
Enable RTS/CTS flow control.
.El
.Ss Input Modes:
This corresponds to the c_iflag in the termios structure.
.Bl -tag -width Fl
.It Cm ignbrk Pq Fl ignbrk
Ignore (do not ignore) break on
input.
.It Cm brkint Pq Fl brkint
Signal (do not signal)
.Dv INTR
on
break.
.It Cm ignpar Pq Fl ignpar
Ignore (do not ignore) parity
errors.
.It Cm parmrk Pq Fl parmrk
Mark (do not mark) parity errors.
.It Cm inpck Pq Fl inpck
Enable (disable) input parity
checking.
.It Cm istrip Pq Fl istrip
Strip (do not strip) input characters
to seven bits.
.It Cm inlcr Pq Fl inlcr
Map (do not map)
.Dv NL
to
.Dv CR
on input.
.It Cm igncr Pq Fl igncr
Ignore (do not ignore)
.Dv CR
on input.
.It Cm icrnl Pq Fl icrnl
Map (do not map)
.Dv CR
to
.Dv NL
on input.
.It Cm ixon Pq Fl ixon
Enable (disable)
.Dv START/STOP
output
control.
Output from the system is
stopped when the system receives
.Dv STOP
and started when the system
receives
.Dv START ,
or if
.Cm ixany
is set, any character restarts output.
.ne 1i
.It Cm ixoff Pq Fl ixoff
Request that the system send (not
send)
.Dv START/STOP
characters when
the input queue is nearly
empty/full.
.It Cm ixany Pq Fl ixany
Allow any character (allow only
.Dv START )
to restart output.
.It Cm imaxbel Pq Fl imaxbel
The system imposes a limit of
.Dv MAX_INPUT
(currently 255) characters in the input queue. If
.Cm imaxbel
is set and the input queue limit has been reached,
subsequent input causes the system to send an ASCII BEL
character to the output queue (the terminal beeps at you). Otherwise,
if
.Cm imaxbel
is unset and the input queue is full, the next input character causes
the entire input and output queues to be discarded.
.El
.Ss Output Modes:
This corresponds to the c_oflag of the termios structure.
.Bl -tag -width Fl
.It Cm opost Pq Fl opost
Post-process output (do not
post-process output; ignore all other
output modes).
.It Cm onlcr Pq Fl onlcr
Map (do not map)
.Dv NL
to
.DV CR-NL
on output.
.It Cm oxtabs Pq Fl oxtabs
Expand (do not expand) tabs to spaces on output.
.El
.Ss Local Modes:
.Pp
Local mode flags (lflags) affect various and sundry characteristics of terminal
processing.
Historically the term "local" pertained to new job control features
implemented by Jim Kulp on a
.Tn Pdp 11/70
at
.Tn IIASA .
Later the driver ran on the first
.Tn VAX
at Evans Hall, UC Berkeley, where the job control details
were greatly modified but the structure definitions and names
remained essentially unchanged.
The second interpretation of the 'l' in lflag
is ``line discipline flag'' which corresponds to the
.Ar c_lflag
of the
.Ar termios
structure.
.Bl -tag -width Fl
.It Cm isig Pq Fl isig
Enable (disable) the checking of
characters against the special control
characters
.Dv INTR , QUIT ,
and
.Dv SUSP .
.It Cm icanon Pq Fl icanon
Enable (disable) canonical input
.Pf ( Dv ERASE
and
.Dv KILL
processing).
.It Cm iexten Pq Fl iexten
Enable (disable) any implementation
defined special control characters
not currently controlled by icanon,
isig, or ixon.
.It Cm echo Pq Fl echo
Echo back (do not echo back) every
character typed.
.It Cm echoe Pq Fl echoe
The
.Dv ERASE
character shall (shall
not) visually erase the last character
in the current line from the
display, if possible.
.It Cm echok Pq Fl echok
Echo (do not echo)
.Dv NL
after
.Dv KILL
character.
.ne 1i
.It Cm echoke Pq Fl echoke
The
.Dv KILL
character shall (shall
not) visually erase the
the current line from the
display, if possible.
.It Cm echonl Pq Fl echonl
Echo (do not echo)
.Dv NL ,
even if echo
is disabled.
.It Cm echoctl Pq Fl echoctl
If
.Cm echoctl
is set, echo control characters as ^X. Otherwise control characters
echo as themselves.
.It Cm echoprt Pq Fl echoprt
For printing terminals. If set, echo erased characters backwards within ``\\''
and ``/''. Otherwise, disable this feature.
.It Cm noflsh Pq Fl noflsh
Disable (enable) flush after
.Dv INTR , QUIT , SUSP .
.It Cm tostop Pq Fl tostop
Send (do not send)
.Dv SIGTTOU
for background output. This causes background jobs to stop if they attempt
terminal output.
.It Cm altwerase Pq Fl altwerase
Use (do not use) an alternate word erase algorithm when processing
.Dv WERASE
characters.
This alternate algorithm considers sequences of
alphanumeric/underscores as words.
It also skips the first preceding character in its classification
(as a convenience since the one preceding character could have been
erased with simply an
.Dv ERASE
character.)
.It Cm mdmbuf Pq Fl mdmbuf
If set, flow control output based on condition of Carrier Detect. Otherwise
writes return an error if Carrier Detect is low (and Carrier is not being
ignored with the
.Dv CLOCAL
flag.)
.It Cm flusho Pq Fl flusho
Indicates output is (is not) being discarded.
.It Cm pendin Pq Fl pendin
Indicates input is (is not) pending after a switch from non-canonical
to canonical mode and will be re-input when a read becomes pending
or more input arrives.
.El
.Ss Control Characters:
.Bl -tag -width Fl
.It Ar control-character Ar string
Set
.Ar control-character
to
.Ar string .
If string is a single character,
the control character is set to
that character.
If string is the
two character sequence "^-" or the
string "undef" the control character
is disabled (i.e. set to
.Pf { Dv _POSIX_VDISABLE Ns } . )
.Pp
Recognized control-characters:
.Bd -ragged -offset indent
.Bl -column character Subscript
.It control-
.It character Subscript Description
.It _________ _________ _______________
.It eof Ta Tn VEOF EOF No character
.It eol Ta Tn VEOL EOL No character
.It eol2 Ta Tn VEOL2 EOL2 No character
.It erase Ta Tn VERASE ERASE No character
.It werase Ta Tn VWERASE WERASE No character
.It intr Ta Tn VINTR INTR No character
.It kill Ta Tn VKILL KILL No character
.It quit Ta Tn VQUIT QUIT No character
.It susp Ta Tn VSUSP SUSP No character
.It start Ta Tn VSTART START No character
.It stop Ta Tn VSTOP STOP No character
.It dsusp Ta Tn VDSUSP DSUSP No character
.It lnext Ta Tn VLNEXT LNEXT No character
.It reprint Ta Tn VREPRINT REPRINT No character
.It status Ta Tn VSTATUS STATUS No character
.El
.Ed
.It Cm min Ar number
.It Cm time Ar number
Set the value of min or time to
number.
.Dv MIN
and
.Dv TIME
are used in
Non-Canonical mode input processing
(-icanon).
.El
.Ss Combination Modes:
.Pp
.Bl -tag -width Fl
.It Ar saved settings
Set the current terminal
characteristics to the saved settings
produced by the
.Fl g
option.
.It Cm evenp No or Cm parity
Enable parenb and cs7; disable
parodd.
.It Cm oddp
Enable parenb, cs7, and parodd.
.It Fl parity , evenp , oddp
Disable parenb, and set cs8.
.It Cm \&nl Pq Fl \&nl
Enable (disable) icrnl.
In addition
-nl unsets inlcr and igncr.
.It Cm ek
Reset
.Dv ERASE
and
.Dv KILL
characters
back to system defaults.
.It Cm sane
Resets all modes to reasonable values for interactive terminal use.
.It Cm tty
Set the line discipline to the standard terminal line discipline
.Dv TTYDISC .
.It Cm crt Pq Fl crt
Set (disable) all modes suitable for a CRT display device.
.It Cm kerninfo Pq Fl kerninfo
Enable (disable) the system generated status line associated with
processing a
.Dv STATUS
character (usually set to ^T). The status line consists of the
system load average, the current command name, its process ID, the
event the process is waiting on (or the status of the process), the user
and system times, percent cpu, and current memory usage.
.It Cm columns Ar number
The terminal size is recorded as having
.Ar number
columns.
.It Cm cols Ar number
is an alias for
.Cm columns.
.ne 1i
.It Cm rows Ar number
The terminal size is recorded as having
.Ar number
rows.
.It Cm dec
Set modes suitable for users of Digital Equipment Corporation systems (
.Dv ERASE ,
.Dv KILL ,
and
.Dv INTR
characters are set to ^?, ^U, and ^C;
.Dv ixany
is disabled, and
.Dv crt
is enabled.)
.It Cm extproc Pq Fl extproc
If set, this flag indicates that some amount of terminal processing is being
performed by either the terminal hardware or by the remote side connected
to a pty.
.It Cm raw Pq Fl raw
If set, change the modes of the terminal so that no input or output processing
is performed. If unset, change the modes of the terminal to some reasonable
state that performs input and output processing. Note that since the
terminal driver no longer has a single
.Dv RAW
bit, it is not possible to intuit what flags were set prior to setting
.Cm raw .
This means that unsetting
.Cm raw
may not put back all the setting that were previously in effect.
To set the terminal into a raw state and then accurately restore it, the following
shell code is recommended:
.nf
save_state=$(stty -g)
stty raw
\&...
stty "$save_state"
.fi
.It Cm size
The size of the terminal is printed as two numbers on a single line,
first rows, then columns.
.El
.Ss Compatibility Modes:
.Pp
These modes remain for compatibility with the previous version of
the stty command.
.Bl -tag -width Fl
.It Cm all
Reports all the terminal modes as with
.Cm stty Fl a
except that the control characters are printed in a columnar format.
.It Cm everything
Same as
.Cm all .
.It Cm cooked
Same as
.Cm sane .
.It Cm cbreak
If set, enables
.Cm brkint , ixon , imaxbel , opost ,
.Cm isig , iexten ,
and
.Cm Fl icanon .
If unset, same as
.Cm sane .
.It Cm new
Same as
.Cm tty .
.It Cm old
Same as
.Cm tty .
.It Cm newcrt Pq Fl newcrt
Same as
.Cm crt .
.It Cm pass8
The converse of
.Cm parity .
.It Cm tandem Pq Fl tandem
Same as
.Cm ixoff .
.It Cm decctlq Pq Fl decctlq
The converse of
.Cm ixany .
.ne 1i
.It Cm crterase Pq Fl crterase
Same as
.Cm echoe .
.It Cm crtbs Pq Fl crtbs
Same as
.Cm echoe .
.It Cm crtkill Pq Fl crtkill
Same as
.Cm echoke .
.It Cm ctlecho Pq Fl ctlecho
Same as
.Cm echoctl .
.It Cm prterase Pq Fl prterase
Same as
.Cm echoprt .
.It Cm litout Pq Fl litout
The converse of
.Cm opost .
.It Cm tabs Pq Fl tabs
The converse of
.Cm tabs .
.It Cm brk Ar value
Same as the control character
.Cm eol .
.It Cm flush Ar value
Same as the control character
.Cm discard .
.It Cm rprnt Ar value
Same as the control character
.Cm reprint .
.El
.Pp
The
.Nm stty
utility exits with a value of 0 if successful, and >0 if an error occurs.
.Sh SEE ALSO
.Xr termios 4
.Sh STANDARDS
The
.Nm stty
function is expected to be
.St -p1003.2
compatible. The flags
.Fl e
and
.Fl f
are
extensions to the standard.