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:
+120
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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.
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
+1368
File diff suppressed because it is too large
Load Diff
+552
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+188
@@ -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
File diff suppressed because it is too large
Load Diff
+1379
File diff suppressed because it is too large
Load Diff
+653
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 .
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(¬used, &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
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
Reference in New Issue
Block a user