Import some parts of CSRG 4.4BSD-Lite2 usr.bin sources to fix tree build.

This commit is contained in:
Peter Wemm 1997-03-11 13:08:12 +00:00
parent ed00518230
commit 0da30e9aa7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=23690
33 changed files with 9400 additions and 0 deletions

139
usr.bin/basename/basename.c Normal file
View File

@ -0,0 +1,139 @@
/*-
* 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 copyright[] =
"@(#) Copyright (c) 1991, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)basename.c 8.4 (Berkeley) 5/4/95";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void usage __P((void));
int
main(argc, argv)
int argc;
char **argv;
{
char *p;
int ch;
while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc != 1 && argc != 2)
usage();
/*
* (1) If string is // it is implementation defined whether steps (2)
* through (5) are skipped or processed.
*
* (2) If string consists entirely of slash characters, string shall
* be set to a single slash character. In this case, skip steps
* (3) through (5).
*/
for (p = *argv;; ++p) {
if (!*p) {
if (p > *argv)
(void)printf("/\n");
else
(void)printf("\n");
exit(0);
}
if (*p != '/')
break;
}
/*
* (3) If there are any trailing slash characters in string, they
* shall be removed.
*/
for (; *p; ++p)
continue;
while (*--p == '/')
continue;
*++p = '\0';
/*
* (4) If there are any slash characters remaining in string, the
* prefix of string up to an including the last slash character
* in string shall be removed.
*/
while (--p >= *argv)
if (*p == '/')
break;
++p;
/*
* (5) If the suffix operand is present, is not identical to the
* characters remaining in string, and is identical to a suffix
* of the characters remaining in string, the suffix suffix
* shall be removed from string.
*/
if (*++argv) {
int suffixlen, stringlen, off;
suffixlen = strlen(*argv);
stringlen = strlen(p);
if (suffixlen < stringlen) {
off = stringlen - suffixlen;
if (!strcmp(p + off, *argv))
p[off] = '\0';
}
}
(void)printf("%s\n", p);
exit(0);
}
void
usage()
{
(void)fprintf(stderr, "usage: basename string [suffix]\n");
exit(1);
}

538
usr.bin/col/col.c Normal file
View File

@ -0,0 +1,538 @@
/*-
* 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
* Michael Rendell of the Memorial University of Newfoundland.
*
* 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[] = "@(#)col.c 8.5 (Berkeley) 5/4/95";
#endif /* not lint */
#include <ctype.h>
#include <err.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define BS '\b' /* backspace */
#define TAB '\t' /* tab */
#define SPACE ' ' /* space */
#define NL '\n' /* newline */
#define CR '\r' /* carriage return */
#define ESC '\033' /* escape */
#define SI '\017' /* shift in to normal character set */
#define SO '\016' /* shift out to alternate character set */
#define VT '\013' /* vertical tab (aka reverse line feed) */
#define RLF '\007' /* ESC-07 reverse line feed */
#define RHLF '\010' /* ESC-010 reverse half-line feed */
#define FHLF '\011' /* ESC-011 forward half-line feed */
/* build up at least this many lines before flushing them out */
#define BUFFER_MARGIN 32
typedef char CSET;
typedef struct char_str {
#define CS_NORMAL 1
#define CS_ALTERNATE 2
short c_column; /* column character is in */
CSET c_set; /* character set (currently only 2) */
char c_char; /* character in question */
} CHAR;
typedef struct line_str LINE;
struct line_str {
CHAR *l_line; /* characters on the line */
LINE *l_prev; /* previous line */
LINE *l_next; /* next line */
int l_lsize; /* allocated sizeof l_line */
int l_line_len; /* strlen(l_line) */
int l_needs_sort; /* set if chars went in out of order */
int l_max_col; /* max column in the line */
};
LINE *alloc_line __P((void));
void dowarn __P((int));
void flush_line __P((LINE *));
void flush_lines __P((int));
void flush_blanks __P((void));
void free_line __P((LINE *));
void usage __P((void));
void wrerr __P((void));
void *xmalloc __P((void *, size_t));
CSET last_set; /* char_set of last char printed */
LINE *lines;
int compress_spaces; /* if doing space -> tab conversion */
int fine; /* if `fine' resolution (half lines) */
int max_bufd_lines; /* max # lines to keep in memory */
int nblank_lines; /* # blanks after last flushed line */
int no_backspaces; /* if not to output any backspaces */
#define PUTC(ch) \
if (putchar(ch) == EOF) \
wrerr();
int
main(argc, argv)
int argc;
char **argv;
{
int ch;
CHAR *c;
CSET cur_set; /* current character set */
LINE *l; /* current line */
int extra_lines; /* # of lines above first line */
int cur_col; /* current column */
int cur_line; /* line number of current position */
int max_line; /* max value of cur_line */
int this_line; /* line l points to */
int nflushd_lines; /* number of lines that were flushed */
int adjust, opt, warned;
max_bufd_lines = 128;
compress_spaces = 1; /* compress spaces into tabs */
while ((opt = getopt(argc, argv, "bfhl:x")) != EOF)
switch (opt) {
case 'b': /* do not output backspaces */
no_backspaces = 1;
break;
case 'f': /* allow half forward line feeds */
fine = 1;
break;
case 'h': /* compress spaces into tabs */
compress_spaces = 1;
break;
case 'l': /* buffered line count */
if ((max_bufd_lines = atoi(optarg)) <= 0) {
(void)fprintf(stderr,
"col: bad -l argument %s.\n", optarg);
exit(1);
}
break;
case 'x': /* do not compress spaces into tabs */
compress_spaces = 0;
break;
case '?':
default:
usage();
}
if (optind != argc)
usage();
/* this value is in half lines */
max_bufd_lines *= 2;
adjust = cur_col = extra_lines = warned = 0;
cur_line = max_line = nflushd_lines = this_line = 0;
cur_set = last_set = CS_NORMAL;
lines = l = alloc_line();
while ((ch = getchar()) != EOF) {
if (!isgraph(ch)) {
switch (ch) {
case BS: /* can't go back further */
if (cur_col == 0)
continue;
--cur_col;
continue;
case CR:
cur_col = 0;
continue;
case ESC: /* just ignore EOF */
switch(getchar()) {
case RLF:
cur_line -= 2;
break;
case RHLF:
cur_line--;
break;
case FHLF:
cur_line++;
if (cur_line > max_line)
max_line = cur_line;
}
continue;
case NL:
cur_line += 2;
if (cur_line > max_line)
max_line = cur_line;
cur_col = 0;
continue;
case SPACE:
++cur_col;
continue;
case SI:
cur_set = CS_NORMAL;
continue;
case SO:
cur_set = CS_ALTERNATE;
continue;
case TAB: /* adjust column */
cur_col |= 7;
++cur_col;
continue;
case VT:
cur_line -= 2;
continue;
}
continue;
}
/* Must stuff ch in a line - are we at the right one? */
if (cur_line != this_line - adjust) {
LINE *lnew;
int nmove;
adjust = 0;
nmove = cur_line - this_line;
if (!fine) {
/* round up to next line */
if (cur_line & 1) {
adjust = 1;
nmove++;
}
}
if (nmove < 0) {
for (; nmove < 0 && l->l_prev; nmove++)
l = l->l_prev;
if (nmove) {
if (nflushd_lines == 0) {
/*
* Allow backup past first
* line if nothing has been
* flushed yet.
*/
for (; nmove < 0; nmove++) {
lnew = alloc_line();
l->l_prev = lnew;
lnew->l_next = l;
l = lines = lnew;
extra_lines++;
}
} else {
if (!warned++)
dowarn(cur_line);
cur_line -= nmove;
}
}
} else {
/* may need to allocate here */
for (; nmove > 0 && l->l_next; nmove--)
l = l->l_next;
for (; nmove > 0; nmove--) {
lnew = alloc_line();
lnew->l_prev = l;
l->l_next = lnew;
l = lnew;
}
}
this_line = cur_line + adjust;
nmove = this_line - nflushd_lines;
if (nmove >= max_bufd_lines + BUFFER_MARGIN) {
nflushd_lines += nmove - max_bufd_lines;
flush_lines(nmove - max_bufd_lines);
}
}
/* grow line's buffer? */
if (l->l_line_len + 1 >= l->l_lsize) {
int need;
need = l->l_lsize ? l->l_lsize * 2 : 90;
l->l_line = (CHAR *)xmalloc((void *) l->l_line,
(unsigned) need * sizeof(CHAR));
l->l_lsize = need;
}
c = &l->l_line[l->l_line_len++];
c->c_char = ch;
c->c_set = cur_set;
c->c_column = cur_col;
/*
* If things are put in out of order, they will need sorting
* when it is flushed.
*/
if (cur_col < l->l_max_col)
l->l_needs_sort = 1;
else
l->l_max_col = cur_col;
cur_col++;
}
if (max_line == 0)
exit(0); /* no lines, so just exit */
/* goto the last line that had a character on it */
for (; l->l_next; l = l->l_next)
this_line++;
flush_lines(this_line - nflushd_lines + extra_lines + 1);
/* make sure we leave things in a sane state */
if (last_set != CS_NORMAL)
PUTC('\017');
/* flush out the last few blank lines */
nblank_lines = max_line - this_line;
if (max_line & 1)
nblank_lines++;
else if (!nblank_lines)
/* missing a \n on the last line? */
nblank_lines = 2;
flush_blanks();
exit(0);
}
void
flush_lines(nflush)
int nflush;
{
LINE *l;
while (--nflush >= 0) {
l = lines;
lines = l->l_next;
if (l->l_line) {
flush_blanks();
flush_line(l);
}
nblank_lines++;
if (l->l_line)
(void)free((void *)l->l_line);
free_line(l);
}
if (lines)
lines->l_prev = NULL;
}
/*
* Print a number of newline/half newlines. If fine flag is set, nblank_lines
* is the number of half line feeds, otherwise it is the number of whole line
* feeds.
*/
void
flush_blanks()
{
int half, i, nb;
half = 0;
nb = nblank_lines;
if (nb & 1) {
if (fine)
half = 1;
else
nb++;
}
nb /= 2;
for (i = nb; --i >= 0;)
PUTC('\n');
if (half) {
PUTC('\033');
PUTC('9');
if (!nb)
PUTC('\r');
}
nblank_lines = 0;
}
/*
* Write a line to stdout taking care of space to tab conversion (-h flag)
* and character set shifts.
*/
void
flush_line(l)
LINE *l;
{
CHAR *c, *endc;
int nchars, last_col, this_col;
last_col = 0;
nchars = l->l_line_len;
if (l->l_needs_sort) {
static CHAR *sorted;
static int count_size, *count, i, save, sorted_size, tot;
/*
* Do an O(n) sort on l->l_line by column being careful to
* preserve the order of characters in the same column.
*/
if (l->l_lsize > sorted_size) {
sorted_size = l->l_lsize;
sorted = (CHAR *)xmalloc((void *)sorted,
(unsigned)sizeof(CHAR) * sorted_size);
}
if (l->l_max_col >= count_size) {
count_size = l->l_max_col + 1;
count = (int *)xmalloc((void *)count,
(unsigned)sizeof(int) * count_size);
}
memset((char *)count, 0, sizeof(int) * l->l_max_col + 1);
for (i = nchars, c = l->l_line; --i >= 0; c++)
count[c->c_column]++;
/*
* calculate running total (shifted down by 1) to use as
* indices into new line.
*/
for (tot = 0, i = 0; i <= l->l_max_col; i++) {
save = count[i];
count[i] = tot;
tot += save;
}
for (i = nchars, c = l->l_line; --i >= 0; c++)
sorted[count[c->c_column]++] = *c;
c = sorted;
} else
c = l->l_line;
while (nchars > 0) {
this_col = c->c_column;
endc = c;
do {
++endc;
} while (--nchars > 0 && this_col == endc->c_column);
/* if -b only print last character */
if (no_backspaces)
c = endc - 1;
if (this_col > last_col) {
int nspace = this_col - last_col;
if (compress_spaces && nspace > 1) {
int ntabs;
ntabs = this_col / 8 - last_col / 8;
nspace -= ntabs * 8;
while (--ntabs >= 0)
PUTC('\t');
}
while (--nspace >= 0)
PUTC(' ');
last_col = this_col;
}
last_col++;
for (;;) {
if (c->c_set != last_set) {
switch (c->c_set) {
case CS_NORMAL:
PUTC('\017');
break;
case CS_ALTERNATE:
PUTC('\016');
}
last_set = c->c_set;
}
PUTC(c->c_char);
if (++c >= endc)
break;
PUTC('\b');
}
}
}
#define NALLOC 64
static LINE *line_freelist;
LINE *
alloc_line()
{
LINE *l;
int i;
if (!line_freelist) {
l = (LINE *)xmalloc((void *)NULL, sizeof(LINE) * NALLOC);
line_freelist = l;
for (i = 1; i < NALLOC; i++, l++)
l->l_next = l + 1;
l->l_next = NULL;
}
l = line_freelist;
line_freelist = l->l_next;
memset(l, 0, sizeof(LINE));
return (l);
}
void
free_line(l)
LINE *l;
{
l->l_next = line_freelist;
line_freelist = l;
}
void *
xmalloc(p, size)
void *p;
size_t size;
{
if (!(p = (void *)realloc(p, size)))
err(1, NULL);
return (p);
}
void
usage()
{
(void)fprintf(stderr, "usage: col [-bfx] [-l nline]\n");
exit(1);
}
void
wrerr()
{
(void)fprintf(stderr, "col: write error.\n");
exit(1);
}
void
dowarn(line)
int line;
{
warnx("warning: can't back up %s",
line < 0 ? "past first line" : "-- line already flushed");
}

168
usr.bin/colrm/colrm.c Normal file
View File

@ -0,0 +1,168 @@
/*-
* Copyright (c) 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 copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)colrm.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define TAB 8
void err __P((const char *, ...));
void check __P((FILE *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
register u_long column, start, stop;
register int ch;
char *p;
while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
start = stop = 0;
switch(argc) {
case 2:
stop = strtol(argv[1], &p, 10);
if (stop <= 0 || *p)
err("illegal column -- %s", argv[1]);
/* FALLTHROUGH */
case 1:
start = strtol(argv[0], &p, 10);
if (start <= 0 || *p)
err("illegal column -- %s", argv[0]);
break;
case 0:
break;
default:
usage();
}
if (stop && start > stop)
err("illegal start and stop columns");
for (column = 0;;) {
switch (ch = getchar()) {
case EOF:
check(stdin);
break;
case '\b':
if (column)
--column;
break;
case '\n':
column = 0;
break;
case '\t':
column = (column + TAB) & ~(TAB - 1);
break;
default:
++column;
break;
}
if ((!start || column < start || stop && column > stop) &&
putchar(ch) == EOF)
check(stdout);
}
}
void
check(stream)
FILE *stream;
{
if (feof(stream))
exit(0);
if (ferror(stream))
err("%s: %s",
stream == stdin ? "stdin" : "stdout", strerror(errno));
}
void
usage()
{
(void)fprintf(stderr, "usage: colrm [start [stop]]\n");
exit(1);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "colrm: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(1);
/* NOTREACHED */
}

305
usr.bin/column/column.c Normal file
View File

@ -0,0 +1,305 @@
/*
* Copyright (c) 1989, 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) 1989, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)column.c 8.4 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void c_columnate __P((void));
void *emalloc __P((int));
void input __P((FILE *));
void maketbl __P((void));
void print __P((void));
void r_columnate __P((void));
void usage __P((void));
int termwidth = 80; /* default terminal width */
int entries; /* number of records */
int eval; /* exit value */
int maxlength; /* longest record */
char **list; /* array of pointers to records */
char *separator = "\t "; /* field separator for table option */
int
main(argc, argv)
int argc;
char **argv;
{
struct winsize win;
FILE *fp;
int ch, tflag, xflag;
char *p;
if (ioctl(1, TIOCGWINSZ, &win) == -1 || !win.ws_col) {
if (p = getenv("COLUMNS"))
termwidth = atoi(p);
} else
termwidth = win.ws_col;
tflag = xflag = 0;
while ((ch = getopt(argc, argv, "c:s:tx")) != EOF)
switch(ch) {
case 'c':
termwidth = atoi(optarg);
break;
case 's':
separator = optarg;
break;
case 't':
tflag = 1;
break;
case 'x':
xflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (!*argv)
input(stdin);
else for (; *argv; ++argv)
if (fp = fopen(*argv, "r")) {
input(fp);
(void)fclose(fp);
} else {
warn("%s", *argv);
eval = 1;
}
if (!entries)
exit(eval);
if (tflag)
maketbl();
else if (maxlength >= termwidth)
print();
else if (xflag)
c_columnate();
else
r_columnate();
exit(eval);
}
#define TAB 8
void
c_columnate()
{
int chcnt, col, cnt, endcol, numcols;
char **lp;
maxlength = (maxlength + TAB) & ~(TAB - 1);
numcols = termwidth / maxlength;
endcol = maxlength;
for (chcnt = col = 0, lp = list;; ++lp) {
chcnt += printf("%s", *lp);
if (!--entries)
break;
if (++col == numcols) {
chcnt = col = 0;
endcol = maxlength;
putchar('\n');
} else {
while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
(void)putchar('\t');
chcnt = cnt;
}
endcol += maxlength;
}
}
if (chcnt)
putchar('\n');
}
void
r_columnate()
{
int base, chcnt, cnt, col, endcol, numcols, numrows, row;
maxlength = (maxlength + TAB) & ~(TAB - 1);
numcols = termwidth / maxlength;
numrows = entries / numcols;
if (entries % numcols)
++numrows;
for (row = 0; row < numrows; ++row) {
endcol = maxlength;
for (base = row, chcnt = col = 0; col < numcols; ++col) {
chcnt += printf("%s", list[base]);
if ((base += numrows) >= entries)
break;
while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
(void)putchar('\t');
chcnt = cnt;
}
endcol += maxlength;
}
putchar('\n');
}
}
void
print()
{
int cnt;
char **lp;
for (cnt = entries, lp = list; cnt--; ++lp)
(void)printf("%s\n", *lp);
}
typedef struct _tbl {
char **list;
int cols, *len;
} TBL;
#define DEFCOLS 25
void
maketbl()
{
TBL *t;
int coloff, cnt;
char *p, **lp;
int *lens, maxcols;
TBL *tbl;
char **cols;
t = tbl = emalloc(entries * sizeof(TBL));
cols = emalloc((maxcols = DEFCOLS) * sizeof(char *));
lens = emalloc(maxcols * sizeof(int));
for (cnt = 0, lp = list; cnt < entries; ++cnt, ++lp, ++t) {
for (coloff = 0, p = *lp; cols[coloff] = strtok(p, separator);
p = NULL)
if (++coloff == maxcols) {
if (!(cols = realloc(cols, (u_int)maxcols +
DEFCOLS * sizeof(char *))) ||
!(lens = realloc(lens,
(u_int)maxcols + DEFCOLS * sizeof(int))))
err(1, NULL);
memset((char *)lens + maxcols * sizeof(int),
0, DEFCOLS * sizeof(int));
maxcols += DEFCOLS;
}
t->list = emalloc(coloff * sizeof(char *));
t->len = emalloc(coloff * sizeof(int));
for (t->cols = coloff; --coloff >= 0;) {
t->list[coloff] = cols[coloff];
t->len[coloff] = strlen(cols[coloff]);
if (t->len[coloff] > lens[coloff])
lens[coloff] = t->len[coloff];
}
}
for (cnt = 0, t = tbl; cnt < entries; ++cnt, ++t) {
for (coloff = 0; coloff < t->cols - 1; ++coloff)
(void)printf("%s%*s", t->list[coloff],
lens[coloff] - t->len[coloff] + 2, " ");
(void)printf("%s\n", t->list[coloff]);
}
}
#define DEFNUM 1000
#define MAXLINELEN (LINE_MAX + 1)
void
input(fp)
FILE *fp;
{
static int maxentry;
int len;
char *p, buf[MAXLINELEN];
if (!list)
list = emalloc((maxentry = DEFNUM) * sizeof(char *));
while (fgets(buf, MAXLINELEN, fp)) {
for (p = buf; *p && isspace(*p); ++p);
if (!*p)
continue;
if (!(p = strchr(p, '\n'))) {
warnx("line too long");
eval = 1;
continue;
}
*p = '\0';
len = p - buf;
if (maxlength < len)
maxlength = len;
if (entries == maxentry) {
maxentry += DEFNUM;
if (!(list = realloc(list,
(u_int)maxentry * sizeof(char *))))
err(1, NULL);
}
list[entries++] = strdup(buf);
}
}
void *
emalloc(size)
int size;
{
char *p;
if (!(p = malloc(size)))
err(1, NULL);
memset(p, 0, size);
return (p);
}
void
usage()
{
(void)fprintf(stderr,
"usage: column [-tx] [-c columns] [file ...]\n");
exit(1);
}

187
usr.bin/comm/comm.c Normal file
View File

@ -0,0 +1,187 @@
/*
* 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
* Case Larsen.
*
* 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[] = "@(#)comm.c 8.4 (Berkeley) 5/4/95";
#endif /* not lint */
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXLINELEN (LINE_MAX + 1)
char *tabs[] = { "", "\t", "\t\t" };
FILE *file __P((char *));
void show __P((FILE *, char *, char *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
int comp, file1done, file2done, read1, read2;
int ch, flag1, flag2, flag3;
FILE *fp1, *fp2;
char *col1, *col2, *col3;
char **p, line1[MAXLINELEN], line2[MAXLINELEN];
flag1 = flag2 = flag3 = 1;
while ((ch = getopt(argc, argv, "-123")) != EOF)
switch(ch) {
case '-':
--optind;
goto done;
case '1':
flag1 = 0;
break;
case '2':
flag2 = 0;
break;
case '3':
flag3 = 0;
break;
case '?':
default:
usage();
}
done: argc -= optind;
argv += optind;
if (argc != 2)
usage();
fp1 = file(argv[0]);
fp2 = file(argv[1]);
/* for each column printed, add another tab offset */
p = tabs;
col1 = col2 = col3 = NULL;
if (flag1)
col1 = *p++;
if (flag2)
col2 = *p++;
if (flag3)
col3 = *p;
for (read1 = read2 = 1;;) {
/* read next line, check for EOF */
if (read1)
file1done = !fgets(line1, MAXLINELEN, fp1);
if (read2)
file2done = !fgets(line2, MAXLINELEN, fp2);
/* if one file done, display the rest of the other file */
if (file1done) {
if (!file2done && col2)
show(fp2, col2, line2);
break;
}
if (file2done) {
if (!file1done && col1)
show(fp1, col1, line1);
break;
}
/* lines are the same */
if (!(comp = strcmp(line1, line2))) {
read1 = read2 = 1;
if (col3)
(void)printf("%s%s", col3, line1);
continue;
}
/* lines are different */
if (comp < 0) {
read1 = 1;
read2 = 0;
if (col1)
(void)printf("%s%s", col1, line1);
} else {
read1 = 0;
read2 = 1;
if (col2)
(void)printf("%s%s", col2, line2);
}
}
exit(0);
}
void
show(fp, offset, buf)
FILE *fp;
char *offset, *buf;
{
do {
(void)printf("%s%s", offset, buf);
} while (fgets(buf, MAXLINELEN, fp));
}
FILE *
file(name)
char *name;
{
FILE *fp;
if (!strcmp(name, "-"))
return (stdin);
if ((fp = fopen(name, "r")) == NULL) {
(void)fprintf(stderr, "comm: %s: %s\n", name, strerror(errno));
exit(1);
}
return (fp);
}
void
usage()
{
(void)fprintf(stderr, "usage: comm [-123] file1 file2\n");
exit(1);
}

298
usr.bin/cut/cut.c Normal file
View File

@ -0,0 +1,298 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Adam S. Moskowitz of Menlo Consulting and Marciano Pitargue.
*
* 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[] = "@(#)cut.c 8.3 (Berkeley) 5/4/95";
#endif /* not lint */
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int cflag;
char dchar;
int dflag;
int fflag;
int sflag;
void c_cut __P((FILE *, char *));
void err __P((const char *, ...));
void f_cut __P((FILE *, char *));
void get_list __P((char *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
FILE *fp;
void (*fcn) __P((FILE *, char *));
int ch;
dchar = '\t'; /* default delimiter is \t */
while ((ch = getopt(argc, argv, "c:d:f:s")) != EOF)
switch(ch) {
case 'c':
fcn = c_cut;
get_list(optarg);
cflag = 1;
break;
case 'd':
dchar = *optarg;
dflag = 1;
break;
case 'f':
get_list(optarg);
fcn = f_cut;
fflag = 1;
break;
case 's':
sflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (fflag) {
if (cflag)
usage();
} else if (!cflag || dflag || sflag)
usage();
if (*argv)
for (; *argv; ++argv) {
if (!(fp = fopen(*argv, "r")))
err("%s: %s\n", *argv, strerror(errno));
fcn(fp, *argv);
(void)fclose(fp);
}
else
fcn(stdin, "stdin");
exit(0);
}
int autostart, autostop, maxval;
char positions[_POSIX2_LINE_MAX + 1];
void
get_list(list)
char *list;
{
register int setautostart, start, stop;
register char *pos;
char *p;
/*
* set a byte in the positions array to indicate if a field or
* column is to be selected; use +1, it's 1-based, not 0-based.
* This parser is less restrictive than the Draft 9 POSIX spec.
* POSIX doesn't allow lists that aren't in increasing order or
* overlapping lists. We also handle "-3-5" although there's no
* real reason too.
*/
for (; p = strtok(list, ", \t"); list = NULL) {
setautostart = start = stop = 0;
if (*p == '-') {
++p;
setautostart = 1;
}
if (isdigit(*p)) {
start = stop = strtol(p, &p, 10);
if (setautostart && start > autostart)
autostart = start;
}
if (*p == '-') {
if (isdigit(p[1]))
stop = strtol(p + 1, &p, 10);
if (*p == '-') {
++p;
if (!autostop || autostop > stop)
autostop = stop;
}
}
if (*p)
err("[-cf] list: illegal list value\n");
if (!stop || !start)
err("[-cf] list: values may not include zero\n");
if (stop > _POSIX2_LINE_MAX)
err("[-cf] list: %d too large (max %d)\n",
stop, _POSIX2_LINE_MAX);
if (maxval < stop)
maxval = stop;
for (pos = positions + start; start++ <= stop; *pos++ = 1);
}
/* overlapping ranges */
if (autostop && maxval > autostop)
maxval = autostop;
/* set autostart */
if (autostart)
memset(positions + 1, '1', autostart);
}
/* ARGSUSED */
void
c_cut(fp, fname)
FILE *fp;
char *fname;
{
register int ch, col;
register char *pos;
for (;;) {
pos = positions + 1;
for (col = maxval; col; --col) {
if ((ch = getc(fp)) == EOF)
return;
if (ch == '\n')
break;
if (*pos++)
(void)putchar(ch);
}
if (ch != '\n')
if (autostop)
while ((ch = getc(fp)) != EOF && ch != '\n')
(void)putchar(ch);
else
while ((ch = getc(fp)) != EOF && ch != '\n');
(void)putchar('\n');
}
}
void
f_cut(fp, fname)
FILE *fp;
char *fname;
{
register int ch, field, isdelim;
register char *pos, *p, sep;
int output;
char lbuf[_POSIX2_LINE_MAX + 1];
for (sep = dchar; fgets(lbuf, sizeof(lbuf), fp);) {
output = 0;
for (isdelim = 0, p = lbuf;; ++p) {
if (!(ch = *p))
err("%s: line too long.\n", fname);
/* this should work if newline is delimiter */
if (ch == sep)
isdelim = 1;
if (ch == '\n') {
if (!isdelim && !sflag)
(void)printf("%s", lbuf);
break;
}
}
if (!isdelim)
continue;
pos = positions + 1;
for (field = maxval, p = lbuf; field; --field, ++pos) {
if (*pos) {
if (output++)
(void)putchar(sep);
while ((ch = *p++) != '\n' && ch != sep)
(void)putchar(ch);
} else
while ((ch = *p++) != '\n' && ch != sep);
if (ch == '\n')
break;
}
if (ch != '\n')
if (autostop) {
if (output)
(void)putchar(sep);
for (; (ch = *p) != '\n'; ++p)
(void)putchar(ch);
} else
for (; (ch = *p) != '\n'; ++p);
(void)putchar('\n');
}
}
void
usage()
{
(void)fprintf(stderr,
"usage:\tcut -c list [file1 ...]\n\tcut -f list [-s] [-d delim] [file ...]\n");
exit(1);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "cut: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(1);
/* NOTREACHED */
}

145
usr.bin/dirname/dirname.c Normal file
View File

@ -0,0 +1,145 @@
/*-
* 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 copyright[] =
"@(#) Copyright (c) 1991, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)dirname.c 8.4 (Berkeley) 5/4/95";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void usage __P((void));
int
main(argc, argv)
int argc;
char **argv;
{
char *p;
int ch;
while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
/*
* (1) If string is //, skip steps (2) through (5).
* (2) If string consists entirely of slash characters, string
* shall be set to a single slash character. In this case,
* skip steps (3) through (8).
*/
for (p = *argv;; ++p) {
if (!*p) {
if (p > *argv)
(void)printf("/\n");
else
(void)printf(".\n");
exit(0);
}
if (*p != '/')
break;
}
/*
* (3) If there are any trailing slash characters in string, they
* shall be removed.
*/
for (; *p; ++p);
while (*--p == '/')
continue;
*++p = '\0';
/*
* (4) If there are no slash characters remaining in string,
* string shall be set to a single period character. In this
* case skip steps (5) through (8).
*
* (5) If there are any trailing nonslash characters in string,
* they shall be removed.
*/
while (--p >= *argv)
if (*p == '/')
break;
++p;
if (p == *argv) {
(void)printf(".\n");
exit(0);
}
/*
* (6) If the remaining string is //, it is implementation defined
* whether steps (7) and (8) are skipped or processed.
*
* This case has already been handled, as part of steps (1) and (2).
*/
/*
* (7) If there are any trailing slash characters in string, they
* shall be removed.
*/
while (--p >= *argv)
if (*p != '/')
break;
++p;
/*
* (8) If the remaining string is empty, string shall be set to
* a single slash character.
*/
*p = '\0';
(void)printf("%s\n", p == *argv ? "/" : *argv);
exit(0);
}
void
usage()
{
(void)fprintf(stderr, "usage: dirname path\n");
exit(1);
}

230
usr.bin/du/du.c Normal file
View File

@ -0,0 +1,230 @@
/*
* 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
* Chris Newcomb.
*
* 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[] = "@(#)du.c 8.5 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.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>
int linkchk __P((FTSENT *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
FTS *fts;
FTSENT *p;
long blocksize;
int ftsoptions, listdirs, listfiles;
int Hflag, Lflag, Pflag, aflag, ch, notused, rval, sflag;
char **save;
save = argv;
Hflag = Lflag = Pflag = aflag = sflag = 0;
ftsoptions = FTS_PHYSICAL;
while ((ch = getopt(argc, argv, "HLPasx")) != 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 'a':
aflag = 1;
break;
case 's':
sflag = 1;
break;
case 'x':
ftsoptions |= FTS_XDEV;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
/*
* XXX
* Because of the way that fts(3) works, logical walks will not count
* the blocks actually used by symbolic links. We rationalize this by
* noting that users computing logical sizes are likely to do logical
* copies, so not counting the links is correct. The real reason is
* that we'd have to re-implement the kernel's symbolic link traversing
* algorithm to get this right. If, for example, you have relative
* symbolic links referencing other relative symbolic links, it gets
* very nasty, very fast. The bottom line is that it's documented in
* the man page, so it's a feature.
*/
if (Hflag)
ftsoptions |= FTS_COMFOLLOW;
if (Lflag) {
ftsoptions &= ~FTS_PHYSICAL;
ftsoptions |= FTS_LOGICAL;
}
if (aflag) {
if (sflag)
usage();
listdirs = listfiles = 1;
} else if (sflag)
listdirs = listfiles = 0;
else {
listfiles = 0;
listdirs = 1;
}
if (!*argv) {
argv = save;
argv[0] = ".";
argv[1] = NULL;
}
(void)getbsize(&notused, &blocksize);
blocksize /= 512;
if ((fts = fts_open(argv, ftsoptions, NULL)) == NULL)
err(1, NULL);
for (rval = 0; (p = fts_read(fts)) != NULL;)
switch (p->fts_info) {
case FTS_D: /* Ignore. */
break;
case FTS_DP:
p->fts_parent->fts_number +=
p->fts_number += p->fts_statp->st_blocks;
/*
* If listing each directory, or not listing files
* or directories and this is post-order of the
* root of a traversal, display the total.
*/
if (listdirs || !listfiles && !p->fts_level)
(void)printf("%ld\t%s\n",
howmany(p->fts_number, blocksize),
p->fts_path);
break;
case FTS_DC: /* Ignore. */
break;
case FTS_DNR: /* Warn, continue. */
case FTS_ERR:
case FTS_NS:
warnx("%s: %s", p->fts_path, strerror(p->fts_errno));
rval = 1;
break;
default:
if (p->fts_statp->st_nlink > 1 && linkchk(p))
break;
/*
* If listing each file, or a non-directory file was
* the root of a traversal, display the total.
*/
if (listfiles || !p->fts_level)
(void)printf("%qd\t%s\n",
howmany(p->fts_statp->st_blocks, blocksize),
p->fts_path);
p->fts_parent->fts_number += p->fts_statp->st_blocks;
}
if (errno)
err(1, "fts_read");
exit(0);
}
typedef struct _ID {
dev_t dev;
ino_t inode;
} ID;
int
linkchk(p)
FTSENT *p;
{
static ID *files;
static int maxfiles, nfiles;
ID *fp, *start;
ino_t ino;
dev_t dev;
ino = p->fts_statp->st_ino;
dev = p->fts_statp->st_dev;
if ((start = files) != NULL)
for (fp = start + nfiles - 1; fp >= start; --fp)
if (ino == fp->inode && dev == fp->dev)
return (1);
if (nfiles == maxfiles && (files = realloc((char *)files,
(u_int)(sizeof(ID) * (maxfiles += 128)))) == NULL)
err(1, "");
files[nfiles].inode = ino;
files[nfiles].dev = dev;
++nfiles;
return (0);
}
void
usage()
{
(void)fprintf(stderr,
"usage: du [-H | -L | -P] [-a | -s] [-x] [file ...]\n");
exit(1);
}

461
usr.bin/find/find.1 Normal file
View File

@ -0,0 +1,461 @@
.\" 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.
.\"
.\" @(#)find.1 8.7 (Berkeley) 5/9/95
.\"
.Dd May 9, 1995
.Dt FIND 1
.Os
.Sh NAME
.Nm find
.Nd walk a file hierarchy
.Sh SYNOPSIS
.Nm find
.Op Fl H | Fl L | Fl P
.Op Fl Xdx
.Op Fl f Ar file
.Op Ar file ...
.Ar expression
.Sh DESCRIPTION
.Nm Find
recursively descends the directory tree for each
.Ar file
listed, evaluating an
.Ar expression
(composed of the ``primaries'' and ``operands'' listed below) in terms
of each file in the tree.
.Pp
The options are as follows:
.Pp
.Bl -tag -width Ds
.It Fl H
The
.Fl H
option causes the file information and file type (see
.Xr stat 2)
returned for each symbolic link specified on the command line to be
those of the file referenced by the link, not the link itself.
If the referenced file does not exist, the file information and type will
be for the link itself. File information of all symbolic links not on
the command line is that of the link itself.
.It Fl L
The
.Fl L
option causes the file information and file type (see
.Xr stat 2)
returned for each symbolic link to be those of the file referenced by the
link, not the link itself.
If the referenced file does not exist, the file information and type will
be for the link itself.
.It Fl P
The
.Fl P
option causes the file information and file type (see
.Xr stat 2)
returned for each symbolic link to be those of the link itself.
.It Fl X
The
.Fl X
option is a modification to permit
.Nm
to be safely used in conjunction with
.Xr xargs 1 .
If a file name contains any of the delimiting characters used by
.Xr xargs ,
a diagnostic message is displayed on standard error, and the file
is skipped.
The delimiting characters include single (`` ' '') and double (`` " '')
quotes, backslash (``\e''), space, tab and newline characters.
.It Fl d
The
.Fl d
option causes
.Nm find
to perform a depth\-first traversal, i.e. directories
are visited in post\-order and all entries in a directory will be acted
on before the directory itself.
By default,
.Nm find
visits directories in pre\-order, i.e. before their contents.
Note, the default is
.Ar not
a breadth\-first traversal.
.It Fl f
The
.Fl f
option specifies a file hierarchy for
.Nm find
to traverse.
File hierarchies may also be specified as the operands immediately
following the options.
.It Fl x
The
.Fl x
option prevents
.Nm find
from descending into directories that have a device number different
than that of the file from which the descent began.
.El
.Sh PRIMARIES
.Bl -tag -width Ds
.It Ic -atime Ar n
True if the difference between the file last access time and the time
.Nm find
was started, rounded up to the next full 24\-hour period, is
.Ar n
24\-hour periods.
.It Ic -ctime Ar n
True if the difference between the time of last change of file status
information and the time
.Nm find
was started, rounded up to the next full 24\-hour period, is
.Ar n
24\-hour periods.
.It Ic -exec Ar utility Op argument ... ;
True if the program named
.Ar utility
returns a zero value as its exit status.
Optional arguments may be passed to the utility.
The expression must be terminated by a semicolon (``;'').
If the string ``{}'' appears anywhere in the utility name or the
arguments it is replaced by the pathname of the current file.
.Ar Utility
will be executed from the directory from which
.Nm find
was executed.
.It Ic -fstype Ar type
True if the file is contained in a file system of type
.Ar type .
The
.Xr sysctl 8
command can be used to find out the types of filesystems
that are available on the system:
.Bd -literal -offset indent
sysctl vfs
.Ed
In addition, there are two pseudo-types, ``local'' and ``rdonly''.
The former matches any file system physically mounted on the system where
the
.Nm find
is being executed and the latter matches any file system which is
mounted read-only.
.It Ic -group Ar gname
True if the file belongs to the group
.Ar gname .
If
.Ar gname
is numeric and there is no such group name, then
.Ar gname
is treated as a group id.
.It Ic -inum Ar n
True if the file has inode number
.Ar n .
.It Ic -links Ar n
True if the file has
.Ar n
links.
.It Ic -ls
This primary always evaluates to true.
The following information for the current file is written to standard output:
its inode number, size in 512\-byte blocks, file permissions, number of hard
links, owner, group, size in bytes, last modification time, and pathname.
If the file is a block or character special file, the major and minor numbers
will be displayed instead of the size in bytes.
If the file is a symbolic link, the pathname of the linked\-to file will be
displayed preceded by ``\->''.
The format is identical to that produced by ``ls \-dgils''.
.It Ic -mtime Ar n
True if the difference between the file last modification time and the time
.Nm find
was started, rounded up to the next full 24\-hour period, is
.Ar n
24\-hour periods.
.It Ic \&-ok Ar utility Op argument ... ;
The
.Ic \&-ok
primary is identical to the
.Ic -exec
primary with the exception that
.Nm find
requests user affirmation for the execution of the utility by printing
a message to the terminal and reading a response.
If the response is other than ``y'' the command is not executed and the
value of the
.Ar \&ok
expression is false.
.It Ic -name Ar pattern
True if the last component of the pathname being examined matches
.Ar pattern .
Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'')
may be used as part of
.Ar pattern .
These characters may be matched explicitly by escaping them with a
backslash (``\e'').
.It Ic -newer Ar file
True if the current file has a more recent last modification time than
.Ar file .
.It Ic -nouser
True if the file belongs to an unknown user.
.It Ic -nogroup
True if the file belongs to an unknown group.
.It Ic -path Ar pattern
True if the pathname being examined matches
.Ar pattern .
Special shell pattern matching characters (``['', ``]'', ``*'', and ``?'')
may be used as part of
.Ar pattern .
These characters may be matched explicitly by escaping them with a
backslash (``\e'').
Slashes (``/'') are treated as normal characters and do not have to be
matched explicitly.
.It Ic -perm Op Fl Ns Ar mode
The
.Ar mode
may be either symbolic (see
.Xr chmod 1 )
or an octal number.
If the mode is symbolic, a starting value of zero is assumed and the
mode sets or clears permissions without regard to the process' file mode
creation mask.
If the mode is octal, only bits 07777
.Pf ( Dv S_ISUID
|
.Dv S_ISGID
|
.Dv S_ISTXT
|
.Dv S_IRWXU
|
.Dv S_IRWXG
|
.Dv S_IRWXO )
of the file's mode bits participate
in the comparison.
If the mode is preceded by a dash (``\-''), this primary evaluates to true
if at least all of the bits in the mode are set in the file's mode bits.
If the mode is not preceded by a dash, this primary evaluates to true if
the bits in the mode exactly match the file's mode bits.
Note, the first character of a symbolic mode may not be a dash (``\-'').
.It Ic -print
This primary always evaluates to true.
It prints the pathname of the current file to standard output.
If none of
.Ic -exec ,
.Ic -ls ,
or
.Ic \&-ok
is specified, the given expression shall be effectively replaced by
.Cm \&( Ns Ar given\& expression Ns Cm \&)
.Ic -print .
.It Ic -prune
This primary always evaluates to true.
It causes
.Nm find
to not descend into the current file.
Note, the
.Ic -prune
primary has no effect if the
.Fl d
option was specified.
.It Ic -size Ar n Ns Op Cm c
True if the file's size, rounded up, in 512\-byte blocks is
.Ar n .
If
.Ar n
is followed by a ``c'', then the primary is true if the
file's size is
.Ar n
bytes.
.It Ic -type Ar t
True if the file is of the specified type.
Possible file types are as follows:
.Pp
.Bl -tag -width flag -offset indent -compact
.It Cm b
block special
.It Cm c
character special
.It Cm d
directory
.It Cm f
regular file
.It Cm l
symbolic link
.It Cm p
FIFO
.It Cm s
socket
.El
.Pp
.It Ic -user Ar uname
True if the file belongs to the user
.Ar uname .
If
.Ar uname
is numeric and there is no such user name, then
.Ar uname
is treated as a user id.
.El
.Pp
All primaries which take a numeric argument allow the number to be
preceded by a plus sign (``+'') or a minus sign (``\-'').
A preceding plus sign means ``more than n'', a preceding minus sign means
``less than n'' and neither means ``exactly n'' .
.Sh OPERATORS
The primaries may be combined using the following operators.
The operators are listed in order of decreasing precedence.
.Bl -tag -width (expression)
.It Cm \&( Ns Ar expression Ns Cm \&)
This evaluates to true if the parenthesized expression evaluates to
true.
.Pp
.It Cm \&! Ns Ar expression
This is the unary
.Tn NOT
operator.
It evaluates to true if the expression is false.
.Pp
.It Ar expression Cm -and Ar expression
.It Ar expression expression
The
.Cm -and
operator is the logical
.Tn AND
operator.
As it is implied by the juxtaposition of two expressions it does not
have to be specified.
The expression evaluates to true if both expressions are true.
The second expression is not evaluated if the first expression is false.
.Pp
.It Ar expression Cm -or Ar expression
The
.Cm -or
operator is the logical
.Tn OR
operator.
The expression evaluates to true if either the first or the second expression
is true.
The second expression is not evaluated if the first expression is true.
.El
.Pp
All operands and primaries must be separate arguments to
.Nm find .
Primaries which themselves take arguments expect each argument
to be a separate argument to
.Nm find .
.Sh EXAMPLES
.Pp
The following examples are shown as given to the shell:
.Bl -tag -width findx
.It Li "find / \e! -name \*q*.c\*q -print"
Print out a list of all the files whose names do not end in ``.c''.
.It Li "find / -newer ttt -user wnj -print"
Print out a list of all the files owned by user ``wnj'' that are newer
than the file ``ttt''.
.It Li "find / \e! \e( -newer ttt -user wnj \e) -print"
Print out a list of all the files which are not both newer than ``ttt''
and owned by ``wnj''.
.It Li "find / \e( -newer ttt -or -user wnj \e) -print"
Print out a list of all the files that are either owned by ``wnj'' or
that are newer than ``ttt''.
.El
.Sh SEE ALSO
.Xr chmod 1 ,
.Xr locate 1 ,
.Xr stat 2 ,
.Xr fts 3 ,
.Xr getgrent 3 ,
.Xr getpwent 3 ,
.Xr strmode 3 ,
.Xr symlink 7
.Sh STANDARDS
The
.Nm find
utility syntax is a superset of the syntax specified by the
.St -p1003.2
standard.
.Pp
The
.Fl s
and
.Fl X
options and the
.Ic -inum
and
.Ic -ls
primaries are extensions to
.St -p1003.2 .
.Pp
Historically, the
.Fl d ,
.Fl h
and
.Fl x
options were implemented using the primaries ``\-depth'', ``\-follow'',
and ``\-xdev''.
These primaries always evaluated to true.
As they were really global variables that took effect before the traversal
began, some legal expressions could have unexpected results.
An example is the expression ``\-print \-o \-depth''.
As \-print always evaluates to true, the standard order of evaluation
implies that \-depth would never be evaluated.
This is not the case.
.Pp
The operator ``-or'' was implemented as ``\-o'', and the operator ``-and''
was implemented as ``\-a''.
.Pp
Historic implementations of the
.Ic exec
and
.Ic ok
primaries did not replace the string ``{}'' in the utility name or the
utility arguments if it had preceding or following non-whitespace characters.
This version replaces it no matter where in the utility name or arguments
it appears.
.Sh BUGS
The special characters used by
.Nm find
are also special characters to many shell programs.
In particular, the characters ``*'', ``['', ``]'', ``?'', ``('', ``)'',
``!'', ``\e'' and ``;'' may have to be escaped from the shell.
.Pp
As there is no delimiter separating options and file names or file
names and the
.Ar expression ,
it is difficult to specify files named ``-xdev'' or ``!''.
These problems are handled by the
.Fl f
option and the
.Xr getopt 3
``--'' construct.

202
usr.bin/find/find.c Normal file
View File

@ -0,0 +1,202 @@
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Cimarron D. Taylor of the University of California, Berkeley.
*
* 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[] = "@(#)find.c 8.5 (Berkeley) 8/5/94";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fts.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "find.h"
/*
* find_formplan --
* process the command line and create a "plan" corresponding to the
* command arguments.
*/
PLAN *
find_formplan(argv)
char **argv;
{
PLAN *plan, *tail, *new;
/*
* for each argument in the command line, determine what kind of node
* it is, create the appropriate node type and add the new plan node
* to the end of the existing plan. The resulting plan is a linked
* list of plan nodes. For example, the string:
*
* % find . -name foo -newer bar -print
*
* results in the plan:
*
* [-name foo]--> [-newer bar]--> [-print]
*
* in this diagram, `[-name foo]' represents the plan node generated
* by c_name() with an argument of foo and `-->' represents the
* plan->next pointer.
*/
for (plan = tail = NULL; *argv;) {
if (!(new = find_create(&argv)))
continue;
if (plan == NULL)
tail = plan = new;
else {
tail->next = new;
tail = new;
}
}
/*
* if the user didn't specify one of -print, -ok or -exec, then -print
* is assumed so we bracket the current expression with parens, if
* necessary, and add a -print node on the end.
*/
if (!isoutput) {
if (plan == NULL) {
new = c_print();
tail = plan = new;
} else {
new = c_openparen();
new->next = plan;
plan = new;
new = c_closeparen();
tail->next = new;
tail = new;
new = c_print();
tail->next = new;
tail = new;
}
}
/*
* the command line has been completely processed into a search plan
* except for the (, ), !, and -o operators. Rearrange the plan so
* that the portions of the plan which are affected by the operators
* are moved into operator nodes themselves. For example:
*
* [!]--> [-name foo]--> [-print]
*
* becomes
*
* [! [-name foo] ]--> [-print]
*
* and
*
* [(]--> [-depth]--> [-name foo]--> [)]--> [-print]
*
* becomes
*
* [expr [-depth]-->[-name foo] ]--> [-print]
*
* operators are handled in order of precedence.
*/
plan = paren_squish(plan); /* ()'s */
plan = not_squish(plan); /* !'s */
plan = or_squish(plan); /* -o's */
return (plan);
}
FTS *tree; /* pointer to top of FTS hierarchy */
/*
* find_execute --
* take a search plan and an array of search paths and executes the plan
* over all FTSENT's returned for the given search paths.
*/
int
find_execute(plan, paths)
PLAN *plan; /* search plan */
char **paths; /* array of pathnames to traverse */
{
register FTSENT *entry;
PLAN *p;
int rval;
if ((tree = fts_open(paths, ftsoptions, (int (*)())NULL)) == NULL)
err(1, "ftsopen");
for (rval = 0; (entry = fts_read(tree)) != NULL;) {
switch (entry->fts_info) {
case FTS_D:
if (isdepth)
continue;
break;
case FTS_DP:
if (!isdepth)
continue;
break;
case FTS_DNR:
case FTS_ERR:
case FTS_NS:
(void)fflush(stdout);
warnx("%s: %s",
entry->fts_path, strerror(entry->fts_errno));
rval = 1;
continue;
#ifdef FTS_W
case FTS_W:
continue;
#endif /* FTS_W */
}
#define BADCH " \t\n\\'\""
if (isxargs && strpbrk(entry->fts_path, BADCH)) {
(void)fflush(stdout);
warnx("%s: illegal path", entry->fts_path);
rval = 1;
continue;
}
/*
* Call all the functions in the execution plan until one is
* false or all have been executed. This is where we do all
* the work specified by the user on the command line.
*/
for (p = plan; p && (p->eval)(p, entry); p = p->next);
}
if (errno)
err(1, "fts_read");
return (rval);
}

1055
usr.bin/find/function.c Normal file

File diff suppressed because it is too large Load Diff

154
usr.bin/find/main.c Normal file
View File

@ -0,0 +1,154 @@
/*-
* 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
* Cimarron D. Taylor of the University of California, Berkeley.
*
* 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
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[] = "@(#)main.c 8.4 (Berkeley) 5/4/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 <time.h>
#include <unistd.h>
#include "find.h"
time_t now; /* time find was run */
int dotfd; /* starting directory */
int ftsoptions; /* options for the ftsopen(3) call */
int isdeprecated; /* using deprecated syntax */
int isdepth; /* do directories on post-order visit */
int isoutput; /* user specified output operator */
int isxargs; /* don't permit xargs delimiting chars */
static void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
register char **p, **start;
int Hflag, Lflag, Pflag, ch;
(void)time(&now); /* initialize the time-of-day */
p = start = argv;
Hflag = Lflag = Pflag = 0;
ftsoptions = FTS_NOSTAT | FTS_PHYSICAL;
while ((ch = getopt(argc, argv, "HLPXdf:x")) != 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 'X':
isxargs = 1;
break;
case 'd':
isdepth = 1;
break;
case 'f':
*p++ = optarg;
break;
case 'x':
ftsoptions |= FTS_XDEV;
break;
case '?':
default:
break;
}
argc -= optind;
argv += optind;
if (Hflag)
ftsoptions |= FTS_COMFOLLOW;
if (Lflag) {
ftsoptions &= ~FTS_PHYSICAL;
ftsoptions |= FTS_LOGICAL;
}
/*
* Find first option to delimit the file list. The first argument
* that starts with a -, or is a ! or a ( must be interpreted as a
* part of the find expression, according to POSIX .2.
*/
for (; *argv != NULL; *p++ = *argv++) {
if (argv[0][0] == '-')
break;
if ((argv[0][0] == '!' || argv[0][0] == '(') &&
argv[0][1] == '\0')
break;
}
if (p == start)
usage();
*p = NULL;
if ((dotfd = open(".", O_RDONLY, 0)) < 0)
err(1, ".");
exit(find_execute(find_formplan(argv), start));
}
static void
usage()
{
(void)fprintf(stderr,
"usage: find [-H | -L | -P] [-Xdx] [-f file] [file ...] [expression]\n");
exit(1);
}

49
usr.bin/finger/extern.h Normal file
View File

@ -0,0 +1,49 @@
/*-
* Copyright (c) 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.
*
* @(#)extern.h 8.2 (Berkeley) 4/28/95
*/
extern char tbuf[1024]; /* Temp buffer for anybody. */
extern int entries; /* Number of people. */
extern DB *db; /* Database. */
void enter_lastlog __P((PERSON *));
PERSON *enter_person __P((struct passwd *));
void enter_where __P((struct utmp *, PERSON *));
PERSON *find_person __P((char *));
void lflag_print __P((void));
int match __P((struct passwd *, char *));
void netfinger __P((char *));
PERSON *palloc __P((void));
char *prphone __P((char *));
void sflag_print __P((void));

166
usr.bin/finger/finger.1 Normal file
View File

@ -0,0 +1,166 @@
.\" Copyright (c) 1989, 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.
.\"
.\" @(#)finger.1 8.3 (Berkeley) 5/5/94
.\"
.Dd May 5, 1994
.Dt FINGER 1
.Os BSD 4
.Sh NAME
.Nm finger
.Nd user information lookup program
.Sh SYNOPSIS
.Nm finger
.Op Fl lmsp
.Op Ar user ...
.Op Ar user@host ...
.Sh DESCRIPTION
The
.Nm finger
displays information about the system users.
.Pp
Options are:
.Bl -tag -width flag
.It Fl s
.Nm Finger
displays the user's login name, real name, terminal name and write
status (as a ``*'' before the terminal name if write permission is
denied), idle time, login time, office location and office phone
number.
.Pp
Idle time is in minutes if it is a single integer, hours and minutes
if a ``:'' is present, or days if a ``d'' is present.
Login time is displayed as month, day, hours and minutes, unless
more than six months ago, in which case the year is displayed rather
than the hours and minutes.
.Pp
Unknown devices as well as nonexistent idle and login times are
displayed as single asterisks.
.Pp
.It Fl l
Produces a multi-line format displaying all of the information
described for the
.Fl s
option as well as the user's home directory, home phone number, login
shell, and the contents of the files
.Dq Pa .forward ,
.Dq Pa .plan
and
.Dq Pa .project
from the user's home directory.
.Pp
If idle time is at least a minute and less than a day, it is
presented in the form ``hh:mm''.
Idle times greater than a day are presented as ``d day[s]hh:mm''.
.Pp
Phone numbers specified as eleven digits are printed as ``+N-NNN-NNN-NNNN''.
Numbers specified as ten or seven digits are printed as the appropriate
subset of that string.
Numbers specified as five digits are printed as ``xN-NNNN''.
.Pp
If write permission is denied to the device, the phrase ``(messages off)''
is appended to the line containing the device name.
One entry per user is displayed with the
.Fl l
option; if a user is logged on multiple times, terminal information
is repeated once per login.
.Pp
.It Fl p
Prevents
the
.Fl l
option of
.Nm finger
from displaying the contents of the
.Dq Pa .forward ,
.Dq Pa .plan
and
.Dq Pa .project
files.
.It Fl m
Prevent matching of
.Ar user
names.
.Ar User
is usually a login name; however, matching will also be done on the
users' real names, unless the
.Fl m
option is supplied.
All name matching performed by
.Nm finger
is case insensitive.
.El
.Pp
If no options are specified,
.Nm finger
defaults to the
.Fl l
style output if operands are provided, otherwise to the
.Fl s
style.
Note that some fields may be missing, in either format, if information
is not available for them.
.Pp
If no arguments are specified,
.Nm finger
will print an entry for each user currently logged into the system.
.Pp
.Nm Finger
may be used to look up users on a remote machine.
The format is to specify a
.Ar user
as
.Dq Li user@host ,
or
.Dq Li @host ,
where the default output
format for the former is the
.Fl l
style, and the default output format for the latter is the
.Fl s
style.
The
.Fl l
option is the only option that may be passed to a remote machine.
.Sh FILES
.Bl -tag -width /var/log/lastlog -compact
.It Pa /var/log/lastlog
last login data base
.El
.Sh SEE ALSO
.Xr chpass 1 ,
.Xr w 1 ,
.Xr who 1 ,
.Sh HISTORY
The
.Nm finger
command appeared in
.Bx 3.0 .

268
usr.bin/finger/finger.c Normal file
View File

@ -0,0 +1,268 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
*
* 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[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95";
#endif /* not lint */
/*
* Finger prints out information about users. It is not portable since
* certain fields (e.g. the full user name, office, and phone numbers) are
* extracted from the gecos field of the passwd file which other UNIXes
* may not have or may use for other things.
*
* There are currently two output formats; the short format is one line
* per user and displays login name, tty, login time, real name, idle time,
* and office location/phone number. The long format gives the same
* information (in a more legible format) as well as home directory, shell,
* mail info, and .plan/.project files.
*/
#include <sys/param.h>
#include <db.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utmp.h>
#include "finger.h"
DB *db;
time_t now;
int entries, lflag, mflag, pplan, sflag;
char tbuf[1024];
static void loginlist __P((void));
static void userlist __P((int, char **));
int
main(argc, argv)
int argc;
char **argv;
{
int ch;
while ((ch = getopt(argc, argv, "lmps")) != EOF)
switch(ch) {
case 'l':
lflag = 1; /* long format */
break;
case 'm':
mflag = 1; /* force exact match of names */
break;
case 'p':
pplan = 1; /* don't show .plan/.project */
break;
case 's':
sflag = 1; /* short format */
break;
case '?':
default:
(void)fprintf(stderr,
"usage: finger [-lmps] [login ...]\n");
exit(1);
}
argc -= optind;
argv += optind;
(void)time(&now);
setpassent(1);
if (!*argv) {
/*
* Assign explicit "small" format if no names given and -l
* not selected. Force the -s BEFORE we get names so proper
* screening will be done.
*/
if (!lflag)
sflag = 1; /* if -l not explicit, force -s */
loginlist();
if (entries == 0)
(void)printf("No one logged on.\n");
} else {
userlist(argc, argv);
/*
* Assign explicit "large" format if names given and -s not
* explicitly stated. Force the -l AFTER we get names so any
* remote finger attempts specified won't be mishandled.
*/
if (!sflag)
lflag = 1; /* if -s not explicit, force -l */
}
if (entries)
if (lflag)
lflag_print();
else
sflag_print();
return (0);
}
static void
loginlist()
{
register PERSON *pn;
DBT data, key;
struct passwd *pw;
struct utmp user;
int r, sflag;
char name[UT_NAMESIZE + 1];
if (!freopen(_PATH_UTMP, "r", stdin))
err(1, "%s", _PATH_UTMP);
name[UT_NAMESIZE] = NULL;
while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
if (!user.ut_name[0])
continue;
if ((pn = find_person(user.ut_name)) == NULL) {
bcopy(user.ut_name, name, UT_NAMESIZE);
if ((pw = getpwnam(name)) == NULL)
continue;
pn = enter_person(pw);
}
enter_where(&user, pn);
}
if (db && lflag)
for (sflag = R_FIRST;; sflag = R_NEXT) {
PERSON *tmp;
r = (*db->seq)(db, &key, &data, sflag);
if (r == -1)
err(1, "db seq");
if (r == 1)
break;
memmove(&tmp, data.data, sizeof tmp);
enter_lastlog(tmp);
}
}
static void
userlist(argc, argv)
register int argc;
register char **argv;
{
register PERSON *pn;
DBT data, key;
struct utmp user;
struct passwd *pw;
int r, sflag, *used, *ip;
char **ap, **nargv, **np, **p;
if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL ||
(used = calloc(argc, sizeof(int))) == NULL)
err(1, NULL);
/* Pull out all network requests. */
for (ap = p = argv, np = nargv; *p; ++p)
if (index(*p, '@'))
*np++ = *p;
else
*ap++ = *p;
*np++ = NULL;
*ap++ = NULL;
if (!*argv)
goto net;
/*
* Traverse the list of possible login names and check the login name
* and real name against the name specified by the user.
*/
if (mflag)
for (p = argv; *p; ++p)
if ((pw = getpwnam(*p)) != NULL)
enter_person(pw);
else
(void)fprintf(stderr,
"finger: %s: no such user\n", *p);
else {
while ((pw = getpwent()) != NULL)
for (p = argv, ip = used; *p; ++p, ++ip)
if (match(pw, *p)) {
enter_person(pw);
*ip = 1;
}
for (p = argv, ip = used; *p; ++p, ++ip)
if (!*ip)
(void)fprintf(stderr,
"finger: %s: no such user\n", *p);
}
/* Handle network requests. */
net: for (p = nargv; *p;)
netfinger(*p++);
if (entries == 0)
return;
/*
* Scan thru the list of users currently logged in, saving
* appropriate data whenever a match occurs.
*/
if (!freopen(_PATH_UTMP, "r", stdin))
err(1, "%s", _PATH_UTMP);
while (fread((char *)&user, sizeof(user), 1, stdin) == 1) {
if (!user.ut_name[0])
continue;
if ((pn = find_person(user.ut_name)) == NULL)
continue;
enter_where(&user, pn);
}
if (db)
for (sflag = R_FIRST;; sflag = R_NEXT) {
PERSON *tmp;
r = (*db->seq)(db, &key, &data, sflag);
if (r == -1)
err(1, "db seq");
if (r == 1)
break;
memmove(&tmp, data.data, sizeof tmp);
enter_lastlog(tmp);
}
}

336
usr.bin/finger/lprint.c Normal file
View File

@ -0,0 +1,336 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
*
* 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[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <time.h>
#include <tzfile.h>
#include <db.h>
#include <err.h>
#include <pwd.h>
#include <utmp.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <paths.h>
#include "finger.h"
#define LINE_LEN 80
#define TAB_LEN 8 /* 8 spaces between tabs */
#define _PATH_FORWARD ".forward"
#define _PATH_PLAN ".plan"
#define _PATH_PROJECT ".project"
static int demi_print __P((char *, int));
static void lprint __P((PERSON *));
static int show_text __P((char *, char *, char *));
static void vputc __P((int));
void
lflag_print()
{
extern int pplan;
register PERSON *pn;
register int sflag, r;
PERSON *tmp;
DBT data, key;
for (sflag = R_FIRST;; sflag = R_NEXT) {
r = (*db->seq)(db, &key, &data, sflag);
if (r == -1)
err(1, "db seq");
if (r == 1)
break;
memmove(&tmp, data.data, sizeof tmp);
pn = tmp;
if (sflag != R_FIRST)
putchar('\n');
lprint(pn);
if (!pplan) {
(void)show_text(pn->dir,
_PATH_FORWARD, "Mail forwarded to");
(void)show_text(pn->dir, _PATH_PROJECT, "Project");
if (!show_text(pn->dir, _PATH_PLAN, "Plan"))
(void)printf("No Plan.\n");
}
}
}
static void
lprint(pn)
register PERSON *pn;
{
extern time_t now;
register struct tm *delta;
register WHERE *w;
register int cpr, len, maxlen;
struct tm *tp;
int oddfield;
char *t, *tzn;
/*
* long format --
* login name
* real name
* home directory
* shell
* office, office phone, home phone if available
*/
(void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s",
pn->name, pn->realname, pn->dir);
(void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL);
/*
* try and print office, office phone, and home phone on one line;
* if that fails, do line filling so it looks nice.
*/
#define OFFICE_TAG "Office"
#define OFFICE_PHONE_TAG "Office Phone"
oddfield = 0;
if (pn->office && pn->officephone &&
strlen(pn->office) + strlen(pn->officephone) +
sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) {
(void)snprintf(tbuf, sizeof(tbuf), "%s: %s, %s",
OFFICE_TAG, pn->office, prphone(pn->officephone));
oddfield = demi_print(tbuf, oddfield);
} else {
if (pn->office) {
(void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
OFFICE_TAG, pn->office);
oddfield = demi_print(tbuf, oddfield);
}
if (pn->officephone) {
(void)snprintf(tbuf, sizeof(tbuf), "%s: %s",
OFFICE_PHONE_TAG, prphone(pn->officephone));
oddfield = demi_print(tbuf, oddfield);
}
}
if (pn->homephone) {
(void)snprintf(tbuf, sizeof(tbuf), "%s: %s", "Home Phone",
prphone(pn->homephone));
oddfield = demi_print(tbuf, oddfield);
}
if (oddfield)
putchar('\n');
/*
* long format con't: * if logged in
* terminal
* idle time
* if messages allowed
* where logged in from
* if not logged in
* when last logged in
*/
/* find out longest device name for this user for formatting */
for (w = pn->whead, maxlen = -1; w != NULL; w = w->next)
if ((len = strlen(w->tty)) > maxlen)
maxlen = len;
/* find rest of entries for user */
for (w = pn->whead; w != NULL; w = w->next) {
switch (w->info) {
case LOGGEDIN:
tp = localtime(&w->loginat);
t = asctime(tp);
tzn = tp->tm_zone;
cpr = printf("On since %.16s (%s) on %s",
t, tzn, w->tty);
/*
* idle time is tough; if have one, print a comma,
* then spaces to pad out the device name, then the
* idle time. Follow with a comma if a remote login.
*/
delta = gmtime(&w->idletime);
if (delta->tm_yday || delta->tm_hour || delta->tm_min) {
cpr += printf("%-*s idle ",
maxlen - strlen(w->tty) + 1, ",");
if (delta->tm_yday > 0) {
cpr += printf("%d day%s ",
delta->tm_yday,
delta->tm_yday == 1 ? "" : "s");
}
cpr += printf("%d:%02d",
delta->tm_hour, delta->tm_min);
if (*w->host) {
putchar(',');
++cpr;
}
}
if (!w->writable)
cpr += printf(" (messages off)");
break;
case LASTLOG:
if (w->loginat == 0) {
(void)printf("Never logged in.");
break;
}
tp = localtime(&w->loginat);
t = asctime(tp);
tzn = tp->tm_zone;
if (now - w->loginat > SECSPERDAY * DAYSPERNYEAR / 2)
cpr =
printf("Last login %.16s %.4s (%s) on %s",
t, t + 20, tzn, w->tty);
else
cpr = printf("Last login %.16s (%s) on %s",
t, tzn, w->tty);
break;
}
if (*w->host) {
if (LINE_LEN < (cpr + 6 + strlen(w->host)))
(void)printf("\n ");
(void)printf(" from %s", w->host);
}
putchar('\n');
}
}
static int
demi_print(str, oddfield)
char *str;
int oddfield;
{
static int lenlast;
int lenthis, maxlen;
lenthis = strlen(str);
if (oddfield) {
/*
* We left off on an odd number of fields. If we haven't
* crossed the midpoint of the screen, and we have room for
* the next field, print it on the same line; otherwise,
* print it on a new line.
*
* Note: we insist on having the right hand fields start
* no less than 5 tabs out.
*/
maxlen = 5 * TAB_LEN;
if (maxlen < lenlast)
maxlen = lenlast;
if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) +
lenthis) <= LINE_LEN) {
while(lenlast < (4 * TAB_LEN)) {
putchar('\t');
lenlast += TAB_LEN;
}
(void)printf("\t%s\n", str); /* force one tab */
} else {
(void)printf("\n%s", str); /* go to next line */
oddfield = !oddfield; /* this'll be undone below */
}
} else
(void)printf("%s", str);
oddfield = !oddfield; /* toggle odd/even marker */
lenlast = lenthis;
return(oddfield);
}
static int
show_text(directory, file_name, header)
char *directory, *file_name, *header;
{
struct stat sb;
register FILE *fp;
register int ch, cnt, lastc;
register char *p;
int fd, nr;
(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name);
if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) ||
sb.st_size == 0)
return(0);
/* If short enough, and no newlines, show it on a single line.*/
if (sb.st_size <= LINE_LEN - strlen(header) - 5) {
nr = read(fd, tbuf, sizeof(tbuf));
if (nr <= 0) {
(void)close(fd);
return(0);
}
for (p = tbuf, cnt = nr; cnt--; ++p)
if (*p == '\n')
break;
if (cnt <= 1) {
(void)printf("%s: ", header);
for (p = tbuf, cnt = nr; cnt--; ++p)
vputc(lastc = *p);
if (lastc != '\n')
(void)putchar('\n');
(void)close(fd);
return(1);
}
else
(void)lseek(fd, 0L, SEEK_SET);
}
if ((fp = fdopen(fd, "r")) == NULL)
return(0);
(void)printf("%s:\n", header);
while ((ch = getc(fp)) != EOF)
vputc(lastc = ch);
if (lastc != '\n')
(void)putchar('\n');
(void)fclose(fp);
return(1);
}
static void
vputc(ch)
register int ch;
{
int meta;
if (!isascii(ch)) {
(void)putchar('M');
(void)putchar('-');
ch = toascii(ch);
meta = 1;
} else
meta = 0;
if (isprint(ch) || !meta && (ch == ' ' || ch == '\t' || ch == '\n'))
(void)putchar(ch);
else {
(void)putchar('^');
(void)putchar(ch == '\177' ? '?' : ch | 0100);
}
}

149
usr.bin/finger/net.c Normal file
View File

@ -0,0 +1,149 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
*
* 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[] = "@(#)net.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <db.h>
#include <unistd.h>
#include <pwd.h>
#include <utmp.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "finger.h"
void
netfinger(name)
char *name;
{
extern int lflag;
register FILE *fp;
register int c, lastc;
struct in_addr defaddr;
struct hostent *hp, def;
struct servent *sp;
struct sockaddr_in sin;
int s;
char *alist[1], *host;
if (!(host = rindex(name, '@')))
return;
*host++ = NULL;
if (isdigit(*host) && (defaddr.s_addr = inet_addr(host)) != -1) {
def.h_name = host;
def.h_addr_list = alist;
def.h_addr = (char *)&defaddr;
def.h_length = sizeof(struct in_addr);
def.h_addrtype = AF_INET;
def.h_aliases = 0;
hp = &def;
} else if (!(hp = gethostbyname(host))) {
(void)fprintf(stderr,
"finger: unknown host: %s\n", host);
return;
}
if (!(sp = getservbyname("finger", "tcp"))) {
(void)fprintf(stderr, "finger: tcp/finger: unknown service\n");
return;
}
sin.sin_family = hp->h_addrtype;
bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
sin.sin_port = sp->s_port;
if ((s = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
perror("finger: socket");
return;
}
/* have network connection; identify the host connected with */
(void)printf("[%s]\n", hp->h_name);
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("finger: connect");
(void)close(s);
return;
}
/* -l flag for remote fingerd */
if (lflag)
write(s, "/W ", 3);
/* send the name followed by <CR><LF> */
(void)write(s, name, strlen(name));
(void)write(s, "\r\n", 2);
/*
* Read from the remote system; once we're connected, we assume some
* data. If none arrives, we hang until the user interrupts.
*
* If we see a <CR> or a <CR> with the high bit set, treat it as
* a newline; if followed by a newline character, only output one
* newline.
*
* Otherwise, all high bits are stripped; if it isn't printable and
* it isn't a space, we can simply set the 7th bit. Every ASCII
* character with bit 7 set is printable.
*/
lastc = 0;
if ((fp = fdopen(s, "r")) != NULL)
while ((c = getc(fp)) != EOF) {
c &= 0x7f;
if (c == 0x0d) {
if (lastc == '\r') /* ^M^M - skip dupes */
continue;
c = '\n';
lastc = '\r';
} else {
if (!isprint(c) && !isspace(c))
c |= 0x40;
if (lastc != '\r' || c != '\n')
lastc = c;
else {
lastc = '\n';
continue;
}
}
putchar(c);
}
if (lastc != '\n')
putchar('\n');
putchar('\n');
(void)fclose(fp);
}

151
usr.bin/finger/sprint.c Normal file
View File

@ -0,0 +1,151 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
*
* 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[] = "@(#)sprint.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <tzfile.h>
#include <db.h>
#include <err.h>
#include <pwd.h>
#include <errno.h>
#include <utmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "finger.h"
static void stimeprint __P((WHERE *));
void
sflag_print()
{
extern time_t now;
register PERSON *pn;
register WHERE *w;
register int sflag, r;
register char *p;
PERSON *tmp;
DBT data, key;
/*
* short format --
* login name
* real name
* terminal name (the XX of ttyXX)
* if terminal writeable (add an '*' to the terminal name
* if not)
* if logged in show idle time and day logged in, else
* show last login date and time. If > 6 moths,
* show year instead of time.
* office location
* office phone
*/
#define MAXREALNAME 20
(void)printf("%-*s %-*s %s\n", UT_NAMESIZE, "Login", MAXREALNAME,
"Name", "Tty Idle Login Time Office Office Phone");
for (sflag = R_FIRST;; sflag = R_NEXT) {
r = (*db->seq)(db, &key, &data, sflag);
if (r == -1)
err(1, "db seq");
if (r == 1)
break;
memmove(&tmp, data.data, sizeof tmp);
pn = tmp;
for (w = pn->whead; w != NULL; w = w->next) {
(void)printf("%-*.*s %-*.*s ", UT_NAMESIZE, UT_NAMESIZE,
pn->name, MAXREALNAME, MAXREALNAME,
pn->realname ? pn->realname : "");
if (!w->loginat) {
(void)printf(" * * No logins ");
goto office;
}
(void)putchar(w->info == LOGGEDIN && !w->writable ?
'*' : ' ');
if (*w->tty)
(void)printf("%-2.2s ",
w->tty[0] != 't' || w->tty[1] != 't' ||
w->tty[2] != 'y' ? w->tty : w->tty + 3);
else
(void)printf(" ");
if (w->info == LOGGEDIN) {
stimeprint(w);
(void)printf(" ");
} else
(void)printf(" * ");
p = ctime(&w->loginat);
(void)printf("%.6s", p + 4);
if (now - w->loginat >= SECSPERDAY * DAYSPERNYEAR / 2)
(void)printf(" %.4s", p + 20);
else
(void)printf(" %.5s", p + 11);
office: if (pn->office)
(void)printf(" %-10.10s", pn->office);
else if (pn->officephone)
(void)printf(" %-10.10s", " ");
if (pn->officephone)
(void)printf(" %-.15s",
prphone(pn->officephone));
putchar('\n');
}
}
}
static void
stimeprint(w)
WHERE *w;
{
register struct tm *delta;
delta = gmtime(&w->idletime);
if (!delta->tm_yday)
if (!delta->tm_hour)
if (!delta->tm_min)
(void)printf(" ");
else
(void)printf("%5d", delta->tm_min);
else
(void)printf("%2d:%02d",
delta->tm_hour, delta->tm_min);
else
(void)printf("%4dd", delta->tm_yday);
}

357
usr.bin/finger/util.c Normal file
View File

@ -0,0 +1,357 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Tony Nardo of the Johns Hopkins University/Applied Physics Lab.
*
* 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.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <db.h>
#include <err.h>
#include <pwd.h>
#include <utmp.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <paths.h>
#include "finger.h"
static void find_idle_and_ttywrite __P((WHERE *));
static void userinfo __P((PERSON *, struct passwd *));
static WHERE *walloc __P((PERSON *));
int
match(pw, user)
struct passwd *pw;
char *user;
{
register char *p, *t;
char name[1024];
if (!strcasecmp(pw->pw_name, user))
return(1);
/*
* XXX
* Why do we skip asterisks!?!?
*/
(void)strcpy(p = tbuf, pw->pw_gecos);
if (*p == '*')
++p;
/* Ampersands get replaced by the login name. */
if ((p = strtok(p, ",")) == NULL)
return(0);
for (t = name; (*t = *p) != '\0'; ++p)
if (*t == '&') {
(void)strcpy(t, pw->pw_name);
while (*++t);
}
else
++t;
for (t = name; (p = strtok(t, "\t ")) != NULL; t = NULL)
if (!strcasecmp(p, user))
return(1);
return(0);
}
void
enter_lastlog(pn)
register PERSON *pn;
{
register WHERE *w;
static int opened, fd;
struct lastlog ll;
char doit = 0;
/* some systems may not maintain lastlog, don't report errors. */
if (!opened) {
fd = open(_PATH_LASTLOG, O_RDONLY, 0);
opened = 1;
}
if (fd == -1 ||
lseek(fd, (long)pn->uid * sizeof(ll), SEEK_SET) !=
(long)pn->uid * sizeof(ll) ||
read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) {
/* as if never logged in */
ll.ll_line[0] = ll.ll_host[0] = NULL;
ll.ll_time = 0;
}
if ((w = pn->whead) == NULL)
doit = 1;
else if (ll.ll_time != 0) {
/* if last login is earlier than some current login */
for (; !doit && w != NULL; w = w->next)
if (w->info == LOGGEDIN && w->loginat < ll.ll_time)
doit = 1;
/*
* and if it's not any of the current logins
* can't use time comparison because there may be a small
* discrepency since login calls time() twice
*/
for (w = pn->whead; doit && w != NULL; w = w->next)
if (w->info == LOGGEDIN &&
strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0)
doit = 0;
}
if (doit) {
w = walloc(pn);
w->info = LASTLOG;
bcopy(ll.ll_line, w->tty, UT_LINESIZE);
w->tty[UT_LINESIZE] = 0;
bcopy(ll.ll_host, w->host, UT_HOSTSIZE);
w->host[UT_HOSTSIZE] = 0;
w->loginat = ll.ll_time;
}
}
void
enter_where(ut, pn)
struct utmp *ut;
PERSON *pn;
{
register WHERE *w;
w = walloc(pn);
w->info = LOGGEDIN;
bcopy(ut->ut_line, w->tty, UT_LINESIZE);
w->tty[UT_LINESIZE] = 0;
bcopy(ut->ut_host, w->host, UT_HOSTSIZE);
w->host[UT_HOSTSIZE] = 0;
w->loginat = (time_t)ut->ut_time;
find_idle_and_ttywrite(w);
}
PERSON *
enter_person(pw)
register struct passwd *pw;
{
DBT data, key;
PERSON *pn;
if (db == NULL &&
(db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL)
err(1, NULL);
key.data = pw->pw_name;
key.size = strlen(pw->pw_name);
switch ((*db->get)(db, &key, &data, 0)) {
case 0:
memmove(&pn, data.data, sizeof pn);
return (pn);
default:
case -1:
err(1, "db get");
/* NOTREACHED */
case 1:
++entries;
pn = palloc();
userinfo(pn, pw);
pn->whead = NULL;
data.size = sizeof(PERSON *);
data.data = &pn;
if ((*db->put)(db, &key, &data, 0))
err(1, "db put");
return (pn);
}
}
PERSON *
find_person(name)
char *name;
{
register int cnt;
DBT data, key;
PERSON *p;
char buf[UT_NAMESIZE + 1];
if (!db)
return(NULL);
/* Name may be only UT_NAMESIZE long and not NUL terminated. */
for (cnt = 0; cnt < UT_NAMESIZE && *name; ++name, ++cnt)
buf[cnt] = *name;
buf[cnt] = '\0';
key.data = buf;
key.size = cnt;
if ((*db->get)(db, &key, &data, 0))
return (NULL);
memmove(&p, data.data, sizeof p);
return (p);
}
PERSON *
palloc()
{
PERSON *p;
if ((p = malloc((u_int) sizeof(PERSON))) == NULL)
err(1, NULL);
return(p);
}
static WHERE *
walloc(pn)
register PERSON *pn;
{
register WHERE *w;
if ((w = malloc((u_int) sizeof(WHERE))) == NULL)
err(1, NULL);
if (pn->whead == NULL)
pn->whead = pn->wtail = w;
else {
pn->wtail->next = w;
pn->wtail = w;
}
w->next = NULL;
return(w);
}
char *
prphone(num)
char *num;
{
register char *p;
int len;
static char pbuf[15];
/* don't touch anything if the user has their own formatting */
for (p = num; *p; ++p)
if (!isdigit(*p))
return(num);
len = p - num;
p = pbuf;
switch(len) {
case 11: /* +0-123-456-7890 */
*p++ = '+';
*p++ = *num++;
*p++ = '-';
/* FALLTHROUGH */
case 10: /* 012-345-6789 */
*p++ = *num++;
*p++ = *num++;
*p++ = *num++;
*p++ = '-';
/* FALLTHROUGH */
case 7: /* 012-3456 */
*p++ = *num++;
*p++ = *num++;
*p++ = *num++;
break;
case 5: /* x0-1234 */
*p++ = 'x';
*p++ = *num++;
break;
default:
return(num);
}
*p++ = '-';
*p++ = *num++;
*p++ = *num++;
*p++ = *num++;
*p++ = *num++;
*p = '\0';
return(pbuf);
}
static void
find_idle_and_ttywrite(w)
register WHERE *w;
{
extern time_t now;
struct stat sb;
(void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty);
if (stat(tbuf, &sb) < 0) {
warn(tbuf);
return;
}
w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime;
#define TALKABLE 0220 /* tty is writable if 220 mode */
w->writable = ((sb.st_mode & TALKABLE) == TALKABLE);
}
static void
userinfo(pn, pw)
register PERSON *pn;
register struct passwd *pw;
{
register char *p, *t;
char *bp, name[1024];
pn->realname = pn->office = pn->officephone = pn->homephone = NULL;
pn->uid = pw->pw_uid;
pn->name = strdup(pw->pw_name);
pn->dir = strdup(pw->pw_dir);
pn->shell = strdup(pw->pw_shell);
/* why do we skip asterisks!?!? */
(void)strcpy(bp = tbuf, pw->pw_gecos);
if (*bp == '*')
++bp;
/* ampersands get replaced by the login name */
if (!(p = strsep(&bp, ",")))
return;
for (t = name; (*t = *p) != '\0'; ++p)
if (*t == '&') {
(void)strcpy(t, pw->pw_name);
if (islower(*t))
*t = toupper(*t);
while (*++t);
}
else
++t;
pn->realname = strdup(name);
pn->office = ((p = strsep(&bp, ",")) && *p) ?
strdup(p) : NULL;
pn->officephone = ((p = strsep(&bp, ",")) && *p) ?
strdup(p) : NULL;
pn->homephone = ((p = strsep(&bp, ",")) && *p) ?
strdup(p) : NULL;
}

748
usr.bin/fstat/fstat.c Normal file
View File

@ -0,0 +1,748 @@
/*-
* 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[] = "@(#)fstat.c 8.3 (Berkeley) 5/2/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/proc.h>
#include <sys/user.h>
#include <sys/stat.h>
#include <sys/vnode.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/unpcb.h>
#include <sys/sysctl.h>
#include <sys/filedesc.h>
#define KERNEL
#include <sys/file.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
#undef KERNEL
#define NFS
#include <sys/mount.h>
#include <nfs/nfsproto.h>
#include <nfs/rpcv2.h>
#include <nfs/nfs.h>
#include <nfs/nfsnode.h>
#undef NFS
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/in_pcb.h>
#include <ctype.h>
#include <errno.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEXT -1
#define CDIR -2
#define RDIR -3
#define TRACE -4
typedef struct devs {
struct devs *next;
long fsid;
ino_t ino;
char *name;
} DEVS;
DEVS *devs;
struct filestat {
long fsid;
long fileid;
mode_t mode;
u_long size;
dev_t rdev;
};
#ifdef notdef
struct nlist nl[] = {
{ "" },
};
#endif
int fsflg, /* show files on same filesystem as file(s) argument */
pflg, /* show files open by a particular pid */
uflg; /* show files open by a particular (effective) user */
int checkfile; /* true if restricting to particular files or filesystems */
int nflg; /* (numerical) display f.s. and rdev as dev_t */
int vflg; /* display errors in locating kernel data objects etc... */
#define dprintf if (vflg) fprintf
struct file **ofiles; /* buffer of pointers to file structures */
int maxfiles;
#define ALLOC_OFILES(d) \
if ((d) > maxfiles) { \
free(ofiles); \
ofiles = malloc((d) * sizeof(struct file *)); \
if (ofiles == NULL) { \
fprintf(stderr, "fstat: %s\n", strerror(errno)); \
exit(1); \
} \
maxfiles = (d); \
}
/*
* a kvm_read that returns true if everything is read
*/
#define KVM_READ(kaddr, paddr, len) \
(kvm_read(kd, (u_long)(kaddr), (char *)(paddr), (len)) == (len))
kvm_t *kd;
int ufs_filestat(), nfs_filestat();
void dofiles(), getinetproto(), socktrans();
void usage(), vtrans();
main(argc, argv)
int argc;
char **argv;
{
extern char *optarg;
extern int optind;
register struct passwd *passwd;
struct kinfo_proc *p, *plast;
int arg, ch, what;
char *memf, *nlistf;
char buf[_POSIX2_LINE_MAX];
int cnt;
arg = 0;
what = KERN_PROC_ALL;
nlistf = memf = NULL;
while ((ch = getopt(argc, argv, "fnp:u:vNM")) != EOF)
switch((char)ch) {
case 'f':
fsflg = 1;
break;
case 'M':
memf = optarg;
break;
case 'N':
nlistf = optarg;
break;
case 'n':
nflg = 1;
break;
case 'p':
if (pflg++)
usage();
if (!isdigit(*optarg)) {
fprintf(stderr,
"fstat: -p requires a process id\n");
usage();
}
what = KERN_PROC_PID;
arg = atoi(optarg);
break;
case 'u':
if (uflg++)
usage();
if (!(passwd = getpwnam(optarg))) {
fprintf(stderr, "%s: unknown uid\n",
optarg);
exit(1);
}
what = KERN_PROC_UID;
arg = passwd->pw_uid;
break;
case 'v':
vflg = 1;
break;
case '?':
default:
usage();
}
if (*(argv += optind)) {
for (; *argv; ++argv) {
if (getfname(*argv))
checkfile = 1;
}
if (!checkfile) /* file(s) specified, but none accessable */
exit(1);
}
ALLOC_OFILES(256); /* reserve space for file pointers */
if (fsflg && !checkfile) {
/* -f with no files means use wd */
if (getfname(".") == 0)
exit(1);
checkfile = 1;
}
/*
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
*/
if (nlistf != NULL || memf != NULL)
setgid(getgid());
if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf)) == NULL) {
fprintf(stderr, "fstat: %s\n", buf);
exit(1);
}
#ifdef notdef
if (kvm_nlist(kd, nl) != 0) {
fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr(kd));
exit(1);
}
#endif
if ((p = kvm_getprocs(kd, what, arg, &cnt)) == NULL) {
fprintf(stderr, "fstat: %s\n", kvm_geterr(kd));
exit(1);
}
if (nflg)
printf("%s",
"USER CMD PID FD DEV INUM MODE SZ|DV R/W");
else
printf("%s",
"USER CMD PID FD MOUNT INUM MODE SZ|DV R/W");
if (checkfile && fsflg == 0)
printf(" NAME\n");
else
putchar('\n');
for (plast = &p[cnt]; p < plast; ++p) {
if (p->kp_proc.p_stat == SZOMB)
continue;
dofiles(p);
}
exit(0);
}
char *Uname, *Comm;
int Pid;
#define PREFIX(i) printf("%-8.8s %-10s %5d", Uname, Comm, Pid); \
switch(i) { \
case TEXT: \
printf(" text"); \
break; \
case CDIR: \
printf(" wd"); \
break; \
case RDIR: \
printf(" root"); \
break; \
case TRACE: \
printf(" tr"); \
break; \
default: \
printf(" %4d", i); \
break; \
}
/*
* print open files attributed to this process
*/
void
dofiles(kp)
struct kinfo_proc *kp;
{
int i, last;
struct file file;
struct filedesc0 filed0;
#define filed filed0.fd_fd
struct proc *p = &kp->kp_proc;
struct eproc *ep = &kp->kp_eproc;
extern char *user_from_uid();
Uname = user_from_uid(ep->e_ucred.cr_uid, 0);
Pid = p->p_pid;
Comm = p->p_comm;
if (p->p_fd == NULL)
return;
if (!KVM_READ(p->p_fd, &filed0, sizeof (filed0))) {
dprintf(stderr, "can't read filedesc at %x for pid %d\n",
p->p_fd, Pid);
return;
}
/*
* root directory vnode, if one
*/
if (filed.fd_rdir)
vtrans(filed.fd_rdir, RDIR, FREAD);
/*
* current working directory vnode
*/
vtrans(filed.fd_cdir, CDIR, FREAD);
/*
* ktrace vnode, if one
*/
if (p->p_tracep)
vtrans(p->p_tracep, TRACE, FREAD|FWRITE);
/*
* open files
*/
#define FPSIZE (sizeof (struct file *))
ALLOC_OFILES(filed.fd_lastfile+1);
if (filed.fd_nfiles > NDFILE) {
if (!KVM_READ(filed.fd_ofiles, ofiles,
(filed.fd_lastfile+1) * FPSIZE)) {
dprintf(stderr,
"can't read file structures at %x for pid %d\n",
filed.fd_ofiles, Pid);
return;
}
} else
bcopy(filed0.fd_dfiles, ofiles, (filed.fd_lastfile+1) * FPSIZE);
for (i = 0; i <= filed.fd_lastfile; i++) {
if (ofiles[i] == NULL)
continue;
if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
dprintf(stderr, "can't read file %d at %x for pid %d\n",
i, ofiles[i], Pid);
continue;
}
if (file.f_type == DTYPE_VNODE)
vtrans((struct vnode *)file.f_data, i, file.f_flag);
else if (file.f_type == DTYPE_SOCKET) {
if (checkfile == 0)
socktrans((struct socket *)file.f_data, i);
}
else {
dprintf(stderr,
"unknown file type %d for file %d of pid %d\n",
file.f_type, i, Pid);
}
}
}
void
vtrans(vp, i, flag)
struct vnode *vp;
int i;
int flag;
{
struct vnode vn;
struct filestat fst;
char rw[3], mode[15];
char *badtype = NULL, *filename, *getmnton();
filename = badtype = NULL;
if (!KVM_READ(vp, &vn, sizeof (struct vnode))) {
dprintf(stderr, "can't read vnode at %x for pid %d\n",
vp, Pid);
return;
}
if (vn.v_type == VNON || vn.v_tag == VT_NON)
badtype = "none";
else if (vn.v_type == VBAD)
badtype = "bad";
else
switch (vn.v_tag) {
case VT_UFS:
if (!ufs_filestat(&vn, &fst))
badtype = "error";
break;
case VT_MFS:
if (!ufs_filestat(&vn, &fst))
badtype = "error";
break;
case VT_NFS:
if (!nfs_filestat(&vn, &fst))
badtype = "error";
break;
default: {
static char unknown[10];
sprintf(badtype = unknown, "?(%x)", vn.v_tag);
break;;
}
}
if (checkfile) {
int fsmatch = 0;
register DEVS *d;
if (badtype)
return;
for (d = devs; d != NULL; d = d->next)
if (d->fsid == fst.fsid) {
fsmatch = 1;
if (d->ino == fst.fileid) {
filename = d->name;
break;
}
}
if (fsmatch == 0 || (filename == NULL && fsflg == 0))
return;
}
PREFIX(i);
if (badtype) {
(void)printf(" - - %10s -\n", badtype);
return;
}
if (nflg)
(void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
else
(void)printf(" %-8s", getmnton(vn.v_mount));
if (nflg)
(void)sprintf(mode, "%o", fst.mode);
else
strmode(fst.mode, mode);
(void)printf(" %6d %10s", fst.fileid, mode);
switch (vn.v_type) {
case VBLK:
case VCHR: {
char *name;
if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
S_IFCHR : S_IFBLK)) == NULL))
printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
else
printf(" %6s", name);
break;
}
default:
printf(" %6d", fst.size);
}
rw[0] = '\0';
if (flag & FREAD)
strcat(rw, "r");
if (flag & FWRITE)
strcat(rw, "w");
printf(" %2s", rw);
if (filename && !fsflg)
printf(" %s", filename);
putchar('\n');
}
int
ufs_filestat(vp, fsp)
struct vnode *vp;
struct filestat *fsp;
{
struct inode inode;
if (!KVM_READ(VTOI(vp), &inode, sizeof (inode))) {
dprintf(stderr, "can't read inode at %x for pid %d\n",
VTOI(vp), Pid);
return 0;
}
fsp->fsid = inode.i_dev & 0xffff;
fsp->fileid = (long)inode.i_number;
fsp->mode = (mode_t)inode.i_mode;
fsp->size = (u_long)inode.i_size;
fsp->rdev = inode.i_rdev;
return 1;
}
int
nfs_filestat(vp, fsp)
struct vnode *vp;
struct filestat *fsp;
{
struct nfsnode nfsnode;
register mode_t mode;
if (!KVM_READ(VTONFS(vp), &nfsnode, sizeof (nfsnode))) {
dprintf(stderr, "can't read nfsnode at %x for pid %d\n",
VTONFS(vp), Pid);
return 0;
}
fsp->fsid = nfsnode.n_vattr.va_fsid;
fsp->fileid = nfsnode.n_vattr.va_fileid;
fsp->size = nfsnode.n_size;
fsp->rdev = nfsnode.n_vattr.va_rdev;
mode = (mode_t)nfsnode.n_vattr.va_mode;
switch (vp->v_type) {
case VREG:
mode |= S_IFREG;
break;
case VDIR:
mode |= S_IFDIR;
break;
case VBLK:
mode |= S_IFBLK;
break;
case VCHR:
mode |= S_IFCHR;
break;
case VLNK:
mode |= S_IFLNK;
break;
case VSOCK:
mode |= S_IFSOCK;
break;
case VFIFO:
mode |= S_IFIFO;
break;
};
fsp->mode = mode;
return 1;
}
char *
getmnton(m)
struct mount *m;
{
static struct mount mount;
static struct mtab {
struct mtab *next;
struct mount *m;
char mntonname[MNAMELEN];
} *mhead = NULL;
register struct mtab *mt;
for (mt = mhead; mt != NULL; mt = mt->next)
if (m == mt->m)
return (mt->mntonname);
if (!KVM_READ(m, &mount, sizeof(struct mount))) {
fprintf(stderr, "can't read mount table at %x\n", m);
return (NULL);
}
if ((mt = malloc(sizeof (struct mtab))) == NULL) {
fprintf(stderr, "fstat: %s\n", strerror(errno));
exit(1);
}
mt->m = m;
bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
mt->next = mhead;
mhead = mt;
return (mt->mntonname);
}
void
socktrans(sock, i)
struct socket *sock;
int i;
{
static char *stypename[] = {
"unused", /* 0 */
"stream", /* 1 */
"dgram", /* 2 */
"raw", /* 3 */
"rdm", /* 4 */
"seqpak" /* 5 */
};
#define STYPEMAX 5
struct socket so;
struct protosw proto;
struct domain dom;
struct inpcb inpcb;
struct unpcb unpcb;
int len;
char dname[32], *strcpy();
PREFIX(i);
/* fill in socket */
if (!KVM_READ(sock, &so, sizeof(struct socket))) {
dprintf(stderr, "can't read sock at %x\n", sock);
goto bad;
}
/* fill in protosw entry */
if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
dprintf(stderr, "can't read protosw at %x", so.so_proto);
goto bad;
}
/* fill in domain */
if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
dprintf(stderr, "can't read domain at %x\n", proto.pr_domain);
goto bad;
}
if ((len = kvm_read(kd, (u_long)dom.dom_name, dname,
sizeof(dname) - 1)) < 0) {
dprintf(stderr, "can't read domain name at %x\n",
dom.dom_name);
dname[0] = '\0';
}
else
dname[len] = '\0';
if ((u_short)so.so_type > STYPEMAX)
printf("* %s ?%d", dname, so.so_type);
else
printf("* %s %s", dname, stypename[so.so_type]);
/*
* protocol specific formatting
*
* Try to find interesting things to print. For tcp, the interesting
* thing is the address of the tcpcb, for udp and others, just the
* inpcb (socket pcb). For unix domain, its the address of the socket
* pcb and the address of the connected pcb (if connected). Otherwise
* just print the protocol number and address of the socket itself.
* The idea is not to duplicate netstat, but to make available enough
* information for further analysis.
*/
switch(dom.dom_family) {
case AF_INET:
getinetproto(proto.pr_protocol);
if (proto.pr_protocol == IPPROTO_TCP ) {
if (so.so_pcb) {
if (kvm_read(kd, (u_long)so.so_pcb,
(char *)&inpcb, sizeof(struct inpcb))
!= sizeof(struct inpcb)) {
dprintf(stderr,
"can't read inpcb at %x\n",
so.so_pcb);
goto bad;
}
printf(" %x", (int)inpcb.inp_ppcb);
}
}
else if (so.so_pcb)
printf(" %x", (int)so.so_pcb);
break;
case AF_UNIX:
/* print address of pcb and connected pcb */
if (so.so_pcb) {
printf(" %x", (int)so.so_pcb);
if (kvm_read(kd, (u_long)so.so_pcb, (char *)&unpcb,
sizeof(struct unpcb)) != sizeof(struct unpcb)){
dprintf(stderr, "can't read unpcb at %x\n",
so.so_pcb);
goto bad;
}
if (unpcb.unp_conn) {
char shoconn[4], *cp;
cp = shoconn;
if (!(so.so_state & SS_CANTRCVMORE))
*cp++ = '<';
*cp++ = '-';
if (!(so.so_state & SS_CANTSENDMORE))
*cp++ = '>';
*cp = '\0';
printf(" %s %x", shoconn,
(int)unpcb.unp_conn);
}
}
break;
default:
/* print protocol number and socket address */
printf(" %d %x", proto.pr_protocol, (int)sock);
}
printf("\n");
return;
bad:
printf("* error\n");
}
/*
* getinetproto --
* print name of protocol number
*/
void
getinetproto(number)
int number;
{
char *cp;
switch(number) {
case IPPROTO_IP:
cp = "ip"; break;
case IPPROTO_ICMP:
cp ="icmp"; break;
case IPPROTO_GGP:
cp ="ggp"; break;
case IPPROTO_TCP:
cp ="tcp"; break;
case IPPROTO_EGP:
cp ="egp"; break;
case IPPROTO_PUP:
cp ="pup"; break;
case IPPROTO_UDP:
cp ="udp"; break;
case IPPROTO_IDP:
cp ="idp"; break;
case IPPROTO_RAW:
cp ="raw"; break;
default:
printf(" %d", number);
return;
}
printf(" %s", cp);
}
getfname(filename)
char *filename;
{
struct stat statbuf;
DEVS *cur;
if (stat(filename, &statbuf)) {
fprintf(stderr, "fstat: %s: %s\n", filename, strerror(errno));
return(0);
}
if ((cur = malloc(sizeof(DEVS))) == NULL) {
fprintf(stderr, "fstat: %s\n", strerror(errno));
exit(1);
}
cur->next = devs;
devs = cur;
cur->ino = statbuf.st_ino;
cur->fsid = statbuf.st_dev & 0xffff;
cur->name = filename;
return(1);
}
void
usage()
{
(void)fprintf(stderr,
"usage: fstat [-fnv] [-p pid] [-u user] [-N system] [-M core] [file ...]\n");
exit(1);
}

182
usr.bin/head/head.c Normal file
View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 1980, 1987, 1992, 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) 1980, 1987, 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
* head - give the first few lines of a stream or of each of a set of files
*
* Bill Joy UCB August 24, 1977
*/
void err __P((int, const char *, ...));
void head __P((FILE *, int));
void obsolete __P((char *[]));
void usage __P((void));
int eval;
int
main(argc, argv)
int argc;
char *argv[];
{
register int ch;
FILE *fp;
int first, linecnt;
char *ep;
obsolete(argv);
linecnt = 10;
while ((ch = getopt(argc, argv, "n:")) != EOF)
switch(ch) {
case 'n':
linecnt = strtol(optarg, &ep, 10);
if (*ep || linecnt <= 0)
err(1, "illegal line count -- %s", optarg);
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (*argv)
for (first = 1; *argv; ++argv) {
if ((fp = fopen(*argv, "r")) == NULL) {
err(0, "%s: %s", *argv, strerror(errno));
continue;
}
if (argc > 1) {
(void)printf("%s==> %s <==\n",
first ? "" : "\n", *argv);
first = 0;
}
head(fp, linecnt);
(void)fclose(fp);
}
else
head(stdin, linecnt);
exit(eval);
}
void
head(fp, cnt)
FILE *fp;
register int cnt;
{
register int ch;
while (cnt--)
while ((ch = getc(fp)) != EOF) {
if (putchar(ch) == EOF)
err(1, "stdout: %s", strerror(errno));
if (ch == '\n')
break;
}
}
void
obsolete(argv)
char *argv[];
{
char *ap;
while (ap = *++argv) {
/* Return if "--" or not "-[0-9]*". */
if (ap[0] != '-' || ap[1] == '-' || !isdigit(ap[1]))
return;
if ((ap = malloc(strlen(*argv) + 2)) == NULL)
err(1, "%s", strerror(errno));
ap[0] = '-';
ap[1] = 'n';
(void)strcpy(ap + 2, *argv + 1);
*argv = ap;
}
}
void
usage()
{
(void)fprintf(stderr, "usage: head [-n lines] [file ...]\n");
exit(1);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(int fatal, const char *fmt, ...)
#else
err(fatal, fmt, va_alist)
int fatal;
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "head: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
if (fatal)
exit(1);
eval = 1;
}

129
usr.bin/hexdump/hexsyntax.c Normal file
View File

@ -0,0 +1,129 @@
/*-
* 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[] = "@(#)hexsyntax.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "hexdump.h"
off_t skip; /* bytes to skip */
void
newsyntax(argc, argvp)
int argc;
char ***argvp;
{
extern enum _vflag vflag;
extern FS *fshead;
extern int length;
int ch;
char *p, **argv;
argv = *argvp;
while ((ch = getopt(argc, argv, "bcde:f:n:os:vx")) != EOF)
switch (ch) {
case 'b':
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"");
break;
case 'c':
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"");
break;
case 'd':
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"");
break;
case 'e':
add(optarg);
break;
case 'f':
addfile(optarg);
break;
case 'n':
if ((length = atoi(optarg)) < 0)
err("%s: bad length value", optarg);
break;
case 'o':
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"");
break;
case 's':
if ((skip = strtol(optarg, &p, 0)) < 0)
err("%s: bad skip value", optarg);
switch(*p) {
case 'b':
skip *= 512;
break;
case 'k':
skip *= 1024;
break;
case 'm':
skip *= 1048576;
break;
}
break;
case 'v':
vflag = ALL;
break;
case 'x':
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"");
break;
case '?':
usage();
}
if (!fshead) {
add("\"%07.7_Ax\n\"");
add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
}
*argvp += optind;
}
void
usage()
{
(void)fprintf(stderr,
"hexdump: [-bcdovx] [-e fmt] [-f fmt_file] [-n length] [-s skip] [file ...]\n");
exit(1);
}

265
usr.bin/hexdump/odsyntax.c Normal file
View File

@ -0,0 +1,265 @@
/*-
* 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[] = "@(#)odsyntax.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "hexdump.h"
int deprecated;
static void odoffset __P((int, char ***));
static void odprecede __P((void));
void
oldsyntax(argc, argvp)
int argc;
char ***argvp;
{
extern enum _vflag vflag;
extern FS *fshead;
int ch;
char **argv;
deprecated = 1;
argv = *argvp;
while ((ch = getopt(argc, argv, "aBbcDdeFfHhIiLlOoPpswvXx")) != EOF)
switch (ch) {
case 'a':
odprecede();
add("16/1 \"%3_u \" \"\\n\"");
break;
case 'B':
case 'o':
odprecede();
add("8/2 \" %06o \" \"\\n\"");
break;
case 'b':
odprecede();
add("16/1 \"%03o \" \"\\n\"");
break;
case 'c':
odprecede();
add("16/1 \"%3_c \" \"\\n\"");
break;
case 'd':
odprecede();
add("8/2 \" %05u \" \"\\n\"");
break;
case 'D':
odprecede();
add("4/4 \" %010u \" \"\\n\"");
break;
case 'e': /* undocumented in od */
case 'F':
odprecede();
add("2/8 \" %21.14e \" \"\\n\"");
break;
case 'f':
odprecede();
add("4/4 \" %14.7e \" \"\\n\"");
break;
case 'H':
case 'X':
odprecede();
add("4/4 \" %08x \" \"\\n\"");
break;
case 'h':
case 'x':
odprecede();
add("8/2 \" %04x \" \"\\n\"");
break;
case 'I':
case 'L':
case 'l':
odprecede();
add("4/4 \" %11d \" \"\\n\"");
break;
case 'i':
odprecede();
add("8/2 \" %6d \" \"\\n\"");
break;
case 'O':
odprecede();
add("4/4 \" %011o \" \"\\n\"");
break;
case 'v':
vflag = ALL;
break;
case 'P':
case 'p':
case 's':
case 'w':
case '?':
default:
(void)fprintf(stderr,
"od: od(1) has been deprecated for hexdump(1).\n");
if (ch != '?')
(void)fprintf(stderr,
"od: hexdump(1) compatibility doesn't support the -%c option%s\n",
ch, ch == 's' ? "; see strings(1)." : ".");
usage();
}
if (!fshead) {
add("\"%07.7_Ao\n\"");
add("\"%07.7_ao \" 8/2 \"%06o \" \"\\n\"");
}
argc -= optind;
*argvp += optind;
if (argc)
odoffset(argc, argvp);
}
static void
odoffset(argc, argvp)
int argc;
char ***argvp;
{
extern off_t skip;
register char *num, *p;
int base;
char *end;
/*
* The offset syntax of od(1) was genuinely bizarre. First, if
* it started with a plus it had to be an offset. Otherwise, if
* there were at least two arguments, a number or lower-case 'x'
* followed by a number makes it an offset. By default it was
* octal; if it started with 'x' or '0x' it was hex. If it ended
* in a '.', it was decimal. If a 'b' or 'B' was appended, it
* multiplied the number by 512 or 1024 byte units. There was
* no way to assign a block count to a hex offset.
*
* We assume it's a file if the offset is bad.
*/
p = argc == 1 ? (*argvp)[0] : (*argvp)[1];
if (*p != '+' && (argc < 2 ||
(!isdigit(p[0]) && (p[0] != 'x' || !isxdigit(p[1])))))
return;
base = 0;
/*
* skip over leading '+', 'x[0-9a-fA-f]' or '0x', and
* set base.
*/
if (p[0] == '+')
++p;
if (p[0] == 'x' && isxdigit(p[1])) {
++p;
base = 16;
} else if (p[0] == '0' && p[1] == 'x') {
p += 2;
base = 16;
}
/* skip over the number */
if (base == 16)
for (num = p; isxdigit(*p); ++p);
else
for (num = p; isdigit(*p); ++p);
/* check for no number */
if (num == p)
return;
/* if terminates with a '.', base is decimal */
if (*p == '.') {
if (base)
return;
base = 10;
}
skip = strtol(num, &end, base ? base : 8);
/* if end isn't the same as p, we got a non-octal digit */
if (end != p) {
skip = 0;
return;
}
if (*p)
if (*p == 'B') {
skip *= 1024;
++p;
} else if (*p == 'b') {
skip *= 512;
++p;
}
if (*p) {
skip = 0;
return;
}
/*
* If the offset uses a non-octal base, the base of the offset
* is changed as well. This isn't pretty, but it's easy.
*/
#define TYPE_OFFSET 7
if (base == 16) {
fshead->nextfu->fmt[TYPE_OFFSET] = 'x';
fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'x';
} else if (base == 10) {
fshead->nextfu->fmt[TYPE_OFFSET] = 'd';
fshead->nextfs->nextfu->fmt[TYPE_OFFSET] = 'd';
}
/* Terminate file list. */
(*argvp)[1] = NULL;
}
static void
odprecede()
{
static int first = 1;
if (first) {
first = 0;
add("\"%07.7_Ao\n\"");
add("\"%07.7_ao \"");
} else
add("\" \"");
}

215
usr.bin/join/join.1 Normal file
View File

@ -0,0 +1,215 @@
.\" 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.
.\"
.\" @(#)join.1 8.3 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt JOIN 1
.Os
.Sh NAME
.Nm join
.Nd relational database operator
.Sh SYNOPSIS
.Nm join
.Oo
.Fl a Ar file_number | Fl v Ar file_number
.Oc
.Op Fl e Ar string
.Op Fl j Ar file_number field
.Op Fl o Ar list
.Bk -words
.Ek
.Op Fl t Ar char
.Op Fl \&1 Ar field
.Op Fl \&2 Ar field
.Ar file1
.Ar file2
.Sh DESCRIPTION
The join utility performs an ``equality join'' on the specified files
and writes the result to the standard output.
The ``join field'' is the field in each file by which the files are compared.
The first field in each line is used by default.
There is one line in the output for each pair of lines in
.Ar file1
and
.Ar file2
which have identical join fields.
Each output line consists of the join field, the remaining fields from
.Ar file1
and then the remaining fields from
.Ar file2 .
.Pp
The default field separators are tab and space characters.
In this case, multiple tabs and spaces count as a single field separator,
and leading tabs and spaces are ignored.
The default output field separator is a single space character.
.Pp
Many of the options use file and field numbers.
Both file numbers and field numbers are 1 based, i.e. the first file on
the command line is file number 1 and the first field is field number 1.
The following options are available:
.Bl -tag -width Fl
.It Fl a Ar file_number
In addition to the default output, produce a line for each unpairable
line in file
.Ar file_number .
(The argument to
.Fl a
must not be preceded by a space; see the
.Sx COMPATIBILITY
section.)
.It Fl e Ar string
Replace empty output fields with
.Ar string .
.It Fl o Ar list
The
.Fl o
option specifies the fields that will be output from each file for
each line with matching join fields.
Each element of
.Ar list
has the form
.Ql file_number.field ,
where
.Ar file_number
is a file number and
.Ar field
is a field number.
The elements of list must be either comma (``,'') or whitespace separated.
(The latter requires quoting to protect it from the shell, or, a simpler
approach is to use multiple
.Fl o
options.)
.It Fl t Ar char
Use character
.Ar char
as a field delimiter for both input and output.
Every occurrence of
.Ar char
in a line is significant.
.It Fl v Ar file_number
Do not display the default output, but display a line for each unpairable
line in file
.Ar file_number .
The options
.Fl v Ar 1
and
.Fl v Ar 2
may be specified at the same time.
.It Fl 1 Ar field
Join on the
.Ar field Ns 'th
field of file 1.
.It Fl 2 Ar field
Join on the
.Ar field Ns 'th
field of file 2.
.El
.Pp
When the default field delimiter characters are used, the files to be joined
should be ordered in the collating sequence of
.Xr sort 1 ,
using the
.Fl b
option, on the fields on which they are to be joined, otherwise
.Nm join
may not report all field matches.
When the field delimiter characters are specified by the
.Fl t
option, the collating sequence should be the same as
.Xr sort
without the
.Fl b
option.
.Pp
If one of the arguments
.Ar file1
or
.Ar file2
is ``-'', the standard input is used.
.Pp
The
.Nm join
utility exits 0 on success, and >0 if an error occurs.
.Sh COMPATIBILITY
For compatibility with historic versions of
.Nm join ,
the following options are available:
.Bl -tag -width Fl
.It Fl a
In addition to the default output, produce a line for each unpairable line
in both file 1 and file 2.
(To distinguish between this and
.Fl a Ar file_number ,
.Nm join
currently requires that the latter not include any white space.)
.It Fl j1 Ar field
Join on the
.Ar field Ns 'th
field of file 1.
.It Fl j2 Ar field
Join on the
.Ar field Ns 'th
field of file 2.
.It Fl j Ar field
Join on the
.Ar field Ns 'th
field of both file 1 and file 2.
.It Fl o Ar list ...
Historical implementations of
.Nm join
permitted multiple arguments to the
.Fl o
option.
These arguments were of the form ``file_number.field_number'' as described
for the current
.Fl o
option.
This has obvious difficulties in the presence of files named ``1.2''.
.El
.Pp
These options are available only so historic shellscripts don't require
modification and should not be used.
.Sh STANDARDS
The
.Nm join
command is expected to be
.St -p1003.2
compatible.
.Sh SEE ALSO
.Xr awk 1 ,
.Xr comm 1 ,
.Xr paste 1 ,
.Xr sort 1 ,
.Xr uniq 1

587
usr.bin/join/join.c Normal file
View File

@ -0,0 +1,587 @@
/*-
* Copyright (c) 1991, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Steve Hayman of the Computer Science Department, Indiana University,
* Michiro Hikida and David Goodenough.
*
* 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) 1991, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)join.c 8.6 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/param.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/*
* There's a structure per input file which encapsulates the state of the
* file. We repeatedly read lines from each file until we've read in all
* the consecutive lines from the file with a common join field. Then we
* compare the set of lines with an equivalent set from the other file.
*/
typedef struct {
char *line; /* line */
u_long linealloc; /* line allocated count */
char **fields; /* line field(s) */
u_long fieldcnt; /* line field(s) count */
u_long fieldalloc; /* line field(s) allocated count */
} LINE;
typedef struct {
FILE *fp; /* file descriptor */
u_long joinf; /* join field (-1, -2, -j) */
int unpair; /* output unpairable lines (-a) */
int number; /* 1 for file 1, 2 for file 2 */
LINE *set; /* set of lines with same field */
int pushbool; /* if pushback is set */
u_long pushback; /* line on the stack */
u_long setcnt; /* set count */
u_long setalloc; /* set allocated count */
} INPUT;
INPUT input1 = { NULL, 0, 0, 1, NULL, 0, 0, 0, },
input2 = { NULL, 0, 0, 2, NULL, 0, 0, 0, };
typedef struct {
u_long filenum; /* file number */
u_long fieldno; /* field number */
} OLIST;
OLIST *olist; /* output field list */
u_long olistcnt; /* output field list count */
u_long olistalloc; /* output field allocated count */
int joinout = 1; /* show lines with matched join fields (-v) */
int needsep; /* need separator character */
int spans = 1; /* span multiple delimiters (-t) */
char *empty; /* empty field replacement string (-e) */
char *tabchar = " \t"; /* delimiter characters (-t) */
int cmp __P((LINE *, u_long, LINE *, u_long));
void fieldarg __P((char *));
void joinlines __P((INPUT *, INPUT *));
void obsolete __P((char **));
void outfield __P((LINE *, u_long, int));
void outoneline __P((INPUT *, LINE *));
void outtwoline __P((INPUT *, LINE *, INPUT *, LINE *));
void slurp __P((INPUT *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
INPUT *F1, *F2;
int aflag, ch, cval, vflag;
char *end;
F1 = &input1;
F2 = &input2;
aflag = vflag = 0;
obsolete(argv);
while ((ch = getopt(argc, argv, "\01a:e:j:1:2:o:t:v:")) != EOF) {
switch (ch) {
case '\01': /* See comment in obsolete(). */
aflag = 1;
F1->unpair = F2->unpair = 1;
break;
case '1':
if ((F1->joinf = strtol(optarg, &end, 10)) < 1)
errx(1, "-1 option field number less than 1");
if (*end)
errx(1, "illegal field number -- %s", optarg);
--F1->joinf;
break;
case '2':
if ((F2->joinf = strtol(optarg, &end, 10)) < 1)
errx(1, "-2 option field number less than 1");
if (*end)
errx(1, "illegal field number -- %s", optarg);
--F2->joinf;
break;
case 'a':
aflag = 1;
switch(strtol(optarg, &end, 10)) {
case 1:
F1->unpair = 1;
break;
case 2:
F2->unpair = 1;
break;
default:
errx(1, "-a option file number not 1 or 2");
break;
}
if (*end)
errx(1, "illegal file number -- %s", optarg);
break;
case 'e':
empty = optarg;
break;
case 'j':
if ((F1->joinf = F2->joinf =
strtol(optarg, &end, 10)) < 1)
errx(1, "-j option field number less than 1");
if (*end)
errx(1, "illegal field number -- %s", optarg);
--F1->joinf;
--F2->joinf;
break;
case 'o':
fieldarg(optarg);
break;
case 't':
spans = 0;
if (strlen(tabchar = optarg) != 1)
errx(1, "illegal tab character specification");
break;
case 'v':
vflag = 1;
joinout = 0;
switch (strtol(optarg, &end, 10)) {
case 1:
F1->unpair = 1;
break;
case 2:
F2->unpair = 1;
break;
default:
errx(1, "-v option file number not 1 or 2");
break;
}
if (*end)
errx(1, "illegal file number -- %s", optarg);
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (aflag && vflag)
errx(1, "the -a and -v options are mutually exclusive");
if (argc != 2)
usage();
/* Open the files; "-" means stdin. */
if (!strcmp(*argv, "-"))
F1->fp = stdin;
else if ((F1->fp = fopen(*argv, "r")) == NULL)
err(1, "%s", *argv);
++argv;
if (!strcmp(*argv, "-"))
F2->fp = stdin;
else if ((F2->fp = fopen(*argv, "r")) == NULL)
err(1, "%s", *argv);
if (F1->fp == stdin && F2->fp == stdin)
errx(1, "only one input file may be stdin");
slurp(F1);
slurp(F2);
while (F1->setcnt && F2->setcnt) {
cval = cmp(F1->set, F1->joinf, F2->set, F2->joinf);
if (cval == 0) {
/* Oh joy, oh rapture, oh beauty divine! */
if (joinout)
joinlines(F1, F2);
slurp(F1);
slurp(F2);
} else if (cval < 0) {
/* File 1 takes the lead... */
if (F1->unpair)
joinlines(F1, NULL);
slurp(F1);
} else {
/* File 2 takes the lead... */
if (F2->unpair)
joinlines(F2, NULL);
slurp(F2);
}
}
/*
* Now that one of the files is used up, optionally output any
* remaining lines from the other file.
*/
if (F1->unpair)
while (F1->setcnt) {
joinlines(F1, NULL);
slurp(F1);
}
if (F2->unpair)
while (F2->setcnt) {
joinlines(F2, NULL);
slurp(F2);
}
exit(0);
}
void
slurp(F)
INPUT *F;
{
LINE *lp, *lastlp, tmp;
size_t len;
int cnt;
char *bp, *fieldp;
/*
* Read all of the lines from an input file that have the same
* join field.
*/
F->setcnt = 0;
for (lastlp = NULL;; ++F->setcnt, lastlp = lp) {
/*
* If we're out of space to hold line structures, allocate
* more. Initialize the structure so that we know that this
* is new space.
*/
if (F->setcnt == F->setalloc) {
cnt = F->setalloc;
F->setalloc += 50;
if ((F->set = realloc(F->set,
F->setalloc * sizeof(LINE))) == NULL)
err(1, NULL);
memset(F->set + cnt, 0, 50 * sizeof(LINE));
/* re-set lastlp in case it moved */
if (lastlp != NULL)
lastlp = &F->set[F->setcnt - 1];
}
/*
* Get any pushed back line, else get the next line. Allocate
* space as necessary. If taking the line from the stack swap
* the two structures so that we don't lose space allocated to
* either structure. This could be avoided by doing another
* level of indirection, but it's probably okay as is.
* but it's probably okay as is.
*/
lp = &F->set[F->setcnt];
if (F->pushbool) {
tmp = F->set[F->setcnt];
F->set[F->setcnt] = F->set[F->pushback];
F->set[F->pushback] = tmp;
F->pushbool = 0;
continue;
}
if ((bp = fgetln(F->fp, &len)) == NULL)
return;
if (lp->linealloc <= len + 1) {
lp->linealloc += MAX(100, len + 1 - lp->linealloc);
if ((lp->line =
realloc(lp->line, lp->linealloc)) == NULL)
err(1, NULL);
}
memmove(lp->line, bp, len);
/* Replace trailing newline, if it exists. */
if (bp[len - 1] == '\n')
lp->line[len - 1] = '\0';
else
lp->line[len] = '\0';
bp = lp->line;
/* Split the line into fields, allocate space as necessary. */
lp->fieldcnt = 0;
while ((fieldp = strsep(&bp, tabchar)) != NULL) {
if (spans && *fieldp == '\0')
continue;
if (lp->fieldcnt == lp->fieldalloc) {
lp->fieldalloc += 50;
if ((lp->fields = realloc(lp->fields,
lp->fieldalloc * sizeof(char *))) == NULL)
err(1, NULL);
}
lp->fields[lp->fieldcnt++] = fieldp;
}
/* See if the join field value has changed. */
if (lastlp != NULL && cmp(lp, F->joinf, lastlp, F->joinf)) {
F->pushbool = 1;
F->pushback = F->setcnt;
break;
}
}
}
int
cmp(lp1, fieldno1, lp2, fieldno2)
LINE *lp1, *lp2;
u_long fieldno1, fieldno2;
{
if (lp1->fieldcnt <= fieldno1)
return (lp2->fieldcnt <= fieldno2 ? 0 : 1);
if (lp2->fieldcnt <= fieldno2)
return (-1);
return (strcmp(lp1->fields[fieldno1], lp2->fields[fieldno2]));
}
void
joinlines(F1, F2)
INPUT *F1, *F2;
{
int cnt1, cnt2;
/*
* Output the results of a join comparison. The output may be from
* either file 1 or file 2 (in which case the first argument is the
* file from which to output) or from both.
*/
if (F2 == NULL) {
for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1)
outoneline(F1, &F1->set[cnt1]);
return;
}
for (cnt1 = 0; cnt1 < F1->setcnt; ++cnt1)
for (cnt2 = 0; cnt2 < F2->setcnt; ++cnt2)
outtwoline(F1, &F1->set[cnt1], F2, &F2->set[cnt2]);
}
void
outoneline(F, lp)
INPUT *F;
LINE *lp;
{
int cnt;
/*
* Output a single line from one of the files, according to the
* join rules. This happens when we are writing unmatched single
* lines. Output empty fields in the right places.
*/
if (olist)
for (cnt = 0; cnt < olistcnt; ++cnt) {
if (olist[cnt].filenum == F->number)
outfield(lp, olist[cnt].fieldno, 0);
else
outfield(lp, 0, 1);
}
else
for (cnt = 0; cnt < lp->fieldcnt; ++cnt)
outfield(lp, cnt, 0);
(void)printf("\n");
if (ferror(stdout))
err(1, "stdout");
needsep = 0;
}
void
outtwoline(F1, lp1, F2, lp2)
INPUT *F1, *F2;
LINE *lp1, *lp2;
{
int cnt;
/* Output a pair of lines according to the join list (if any). */
if (olist)
for (cnt = 0; cnt < olistcnt; ++cnt)
if (olist[cnt].filenum == 1)
outfield(lp1, olist[cnt].fieldno, 0);
else /* if (olist[cnt].filenum == 2) */
outfield(lp2, olist[cnt].fieldno, 0);
else {
/*
* Output the join field, then the remaining fields from F1
* and F2.
*/
outfield(lp1, F1->joinf, 0);
for (cnt = 0; cnt < lp1->fieldcnt; ++cnt)
if (F1->joinf != cnt)
outfield(lp1, cnt, 0);
for (cnt = 0; cnt < lp2->fieldcnt; ++cnt)
if (F2->joinf != cnt)
outfield(lp2, cnt, 0);
}
(void)printf("\n");
if (ferror(stdout))
err(1, "stdout");
needsep = 0;
}
void
outfield(lp, fieldno, out_empty)
LINE *lp;
u_long fieldno;
int out_empty;
{
if (needsep++)
(void)printf("%c", *tabchar);
if (!ferror(stdout))
if (lp->fieldcnt < fieldno || out_empty) {
if (empty != NULL)
(void)printf("%s", empty);
} else {
if (*lp->fields[fieldno] == '\0')
return;
(void)printf("%s", lp->fields[fieldno]);
}
if (ferror(stdout))
err(1, "stdout");
}
/*
* Convert an output list argument "2.1, 1.3, 2.4" into an array of output
* fields.
*/
void
fieldarg(option)
char *option;
{
u_long fieldno;
char *end, *token;
while ((token = strsep(&option, ", \t")) != NULL) {
if (*token == '\0')
continue;
if (token[0] != '1' && token[0] != '2' || token[1] != '.')
errx(1, "malformed -o option field");
fieldno = strtol(token + 2, &end, 10);
if (*end)
errx(1, "malformed -o option field");
if (fieldno == 0)
errx(1, "field numbers are 1 based");
if (olistcnt == olistalloc) {
olistalloc += 50;
if ((olist = realloc(olist,
olistalloc * sizeof(OLIST))) == NULL)
err(1, NULL);
}
olist[olistcnt].filenum = token[0] - '0';
olist[olistcnt].fieldno = fieldno - 1;
++olistcnt;
}
}
void
obsolete(argv)
char **argv;
{
int len;
char **p, *ap, *t;
while ((ap = *++argv) != NULL) {
/* Return if "--". */
if (ap[0] == '-' && ap[1] == '-')
return;
switch (ap[1]) {
case 'a':
/*
* The original join allowed "-a", which meant the
* same as -a1 plus -a2. POSIX 1003.2, Draft 11.2
* only specifies this as "-a 1" and "a -2", so we
* have to use another option flag, one that is
* unlikely to ever be used or accidentally entered
* on the command line. (Well, we could reallocate
* the argv array, but that hardly seems worthwhile.)
*/
if (ap[2] == '\0')
ap[1] = '\01';
break;
case 'j':
/*
* The original join allowed "-j[12] arg" and "-j arg".
* Convert the former to "-[12] arg". Don't convert
* the latter since getopt(3) can handle it.
*/
switch(ap[2]) {
case '1':
if (ap[3] != '\0')
goto jbad;
ap[1] = '1';
ap[2] = '\0';
break;
case '2':
if (ap[3] != '\0')
goto jbad;
ap[1] = '2';
ap[2] = '\0';
break;
case '\0':
break;
default:
jbad: errx(1, "illegal option -- %s", ap);
usage();
}
break;
case 'o':
/*
* The original join allowed "-o arg arg".
* Convert to "-o arg -o arg".
*/
if (ap[2] != '\0')
break;
for (p = argv + 2; *p; ++p) {
if (p[0][0] != '1' &&
p[0][0] != '2' || p[0][1] != '.')
break;
len = strlen(*p);
if (len - 2 != strspn(*p + 2, "0123456789"))
break;
if ((t = malloc(len + 3)) == NULL)
err(1, NULL);
t[0] = '-';
t[1] = 'o';
memmove(t + 2, *p, len + 1);
*p = t;
}
argv = p - 1;
break;
}
}
}
void
usage()
{
(void)fprintf(stderr, "%s%s\n",
"usage: join [-a fileno | -v fileno ] [-e string] [-1 field] ",
"[-2 field]\n [-o list] [-t char] file1 file2");
exit(1);
}

359
usr.bin/look/look.c Normal file
View File

@ -0,0 +1,359 @@
/*-
* Copyright (c) 1991, 1993
* 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) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)look.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
/*
* look -- find lines in a sorted list.
*
* The man page said that TABs and SPACEs participate in -d comparisons.
* In fact, they were ignored. This implements historic practice, not
* the manual page.
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "pathnames.h"
/*
* FOLD and DICT convert characters to a normal form for comparison,
* according to the user specified flags.
*
* DICT expects integers because it uses a non-character value to
* indicate a character which should not participate in comparisons.
*/
#define EQUAL 0
#define GREATER 1
#define LESS (-1)
#define NO_COMPARE (-2)
#define FOLD(c) (isascii(c) && isupper(c) ? tolower(c) : (c))
#define DICT(c) (isascii(c) && isalnum(c) ? (c) : NO_COMPARE)
int dflag, fflag;
char *binary_search __P((char *, char *, char *));
int compare __P((char *, char *, char *));
void err __P((const char *fmt, ...));
char *linear_search __P((char *, char *, char *));
int look __P((char *, char *, char *));
void print_from __P((char *, char *, char *));
static void usage __P((void));
main(argc, argv)
int argc;
char *argv[];
{
struct stat sb;
int ch, fd, termchar;
char *back, *file, *front, *string, *p;
file = _PATH_WORDS;
termchar = '\0';
while ((ch = getopt(argc, argv, "dft:")) != EOF)
switch(ch) {
case 'd':
dflag = 1;
break;
case 'f':
fflag = 1;
break;
case 't':
termchar = *optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
switch (argc) {
case 2: /* Don't set -df for user. */
string = *argv++;
file = *argv;
break;
case 1: /* But set -df by default. */
dflag = fflag = 1;
string = *argv;
break;
default:
usage();
}
if (termchar != '\0' && (p = strchr(string, termchar)) != NULL)
*++p = '\0';
if ((fd = open(file, O_RDONLY, 0)) < 0 || fstat(fd, &sb))
err("%s: %s", file, strerror(errno));
if (sb.st_size > SIZE_T_MAX)
err("%s: %s", file, strerror(EFBIG));
if ((front = mmap(NULL,
(size_t)sb.st_size, PROT_READ, 0, fd, (off_t)0)) == NULL)
err("%s: %s", file, strerror(errno));
back = front + sb.st_size;
exit(look(string, front, back));
}
look(string, front, back)
char *string, *front, *back;
{
register int ch;
register char *readp, *writep;
/* Reformat string string to avoid doing it multiple times later. */
for (readp = writep = string; ch = *readp++;) {
if (fflag)
ch = FOLD(ch);
if (dflag)
ch = DICT(ch);
if (ch != NO_COMPARE)
*(writep++) = ch;
}
*writep = '\0';
front = binary_search(string, front, back);
front = linear_search(string, front, back);
if (front)
print_from(string, front, back);
return (front ? 0 : 1);
}
/*
* Binary search for "string" in memory between "front" and "back".
*
* This routine is expected to return a pointer to the start of a line at
* *or before* the first word matching "string". Relaxing the constraint
* this way simplifies the algorithm.
*
* Invariants:
* front points to the beginning of a line at or before the first
* matching string.
*
* back points to the beginning of a line at or after the first
* matching line.
*
* Base of the Invariants.
* front = NULL;
* back = EOF;
*
* Advancing the Invariants:
*
* p = first newline after halfway point from front to back.
*
* If the string at "p" is not greater than the string to match,
* p is the new front. Otherwise it is the new back.
*
* Termination:
*
* The definition of the routine allows it return at any point,
* since front is always at or before the line to print.
*
* In fact, it returns when the chosen "p" equals "back". This
* implies that there exists a string is least half as long as
* (back - front), which in turn implies that a linear search will
* be no more expensive than the cost of simply printing a string or two.
*
* Trying to continue with binary search at this point would be
* more trouble than it's worth.
*/
#define SKIP_PAST_NEWLINE(p, back) \
while (p < back && *p++ != '\n');
char *
binary_search(string, front, back)
register char *string, *front, *back;
{
register char *p;
p = front + (back - front) / 2;
SKIP_PAST_NEWLINE(p, back);
/*
* If the file changes underneath us, make sure we don't
* infinitely loop.
*/
while (p < back && back > front) {
if (compare(string, p, back) == GREATER)
front = p;
else
back = p;
p = front + (back - front) / 2;
SKIP_PAST_NEWLINE(p, back);
}
return (front);
}
/*
* Find the first line that starts with string, linearly searching from front
* to back.
*
* Return NULL for no such line.
*
* This routine assumes:
*
* o front points at the first character in a line.
* o front is before or at the first line to be printed.
*/
char *
linear_search(string, front, back)
char *string, *front, *back;
{
while (front < back) {
switch (compare(string, front, back)) {
case EQUAL: /* Found it. */
return (front);
break;
case LESS: /* No such string. */
return (NULL);
break;
case GREATER: /* Keep going. */
break;
}
SKIP_PAST_NEWLINE(front, back);
}
return (NULL);
}
/*
* Print as many lines as match string, starting at front.
*/
void
print_from(string, front, back)
register char *string, *front, *back;
{
for (; front < back && compare(string, front, back) == EQUAL; ++front) {
for (; front < back && *front != '\n'; ++front)
if (putchar(*front) == EOF)
err("stdout: %s", strerror(errno));
if (putchar('\n') == EOF)
err("stdout: %s", strerror(errno));
}
}
/*
* Return LESS, GREATER, or EQUAL depending on how the string1 compares with
* string2 (s1 ??? s2).
*
* o Matches up to len(s1) are EQUAL.
* o Matches up to len(s2) are GREATER.
*
* Compare understands about the -f and -d flags, and treats comparisons
* appropriately.
*
* The string "s1" is null terminated. The string s2 is '\n' terminated (or
* "back" terminated).
*/
int
compare(s1, s2, back)
register char *s1, *s2, *back;
{
register int ch;
for (; *s1 && s2 < back && *s2 != '\n'; ++s1, ++s2) {
ch = *s2;
if (fflag)
ch = FOLD(ch);
if (dflag)
ch = DICT(ch);
if (ch == NO_COMPARE) {
++s2; /* Ignore character in comparison. */
continue;
}
if (*s1 != ch)
return (*s1 < ch ? LESS : GREATER);
}
return (*s1 ? GREATER : EQUAL);
}
static void
usage()
{
(void)fprintf(stderr, "usage: look [-df] [-t char] string [file]\n");
exit(2);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "look: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(2);
/* NOTREACHED */
}

276
usr.bin/mt/mt.c Normal file
View File

@ -0,0 +1,276 @@
/*
* 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.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1980, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)mt.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
/*
* mt --
* magnetic tape manipulation program
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct commands {
char *c_name;
int c_code;
int c_ronly;
} com[] = {
{ "bsf", MTBSF, 1 },
{ "bsr", MTBSR, 1 },
{ "eof", MTWEOF, 0 },
{ "fsf", MTFSF, 1 },
{ "fsr", MTFSR, 1 },
{ "offline", MTOFFL, 1 },
{ "rewind", MTREW, 1 },
{ "rewoffl", MTOFFL, 1 },
{ "status", MTNOP, 1 },
{ "weof", MTWEOF, 0 },
{ NULL }
};
void err __P((const char *, ...));
void printreg __P((char *, u_int, char *));
void status __P((struct mtget *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
register struct commands *comp;
struct mtget mt_status;
struct mtop mt_com;
int ch, len, mtfd;
char *p, *tape;
if ((tape = getenv("TAPE")) == NULL)
tape = DEFTAPE;
while ((ch = getopt(argc, argv, "f:t:")) != EOF)
switch(ch) {
case 'f':
case 't':
tape = optarg;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1 || argc > 2)
usage();
len = strlen(p = *argv++);
for (comp = com;; comp++) {
if (comp->c_name == NULL)
err("%s: unknown command", p);
if (strncmp(p, comp->c_name, len) == 0)
break;
}
if ((mtfd = open(tape, comp->c_ronly ? O_RDONLY : O_RDWR)) < 0)
err("%s: %s", tape, strerror(errno));
if (comp->c_code != MTNOP) {
mt_com.mt_op = comp->c_code;
if (*argv) {
mt_com.mt_count = strtol(*argv, &p, 10);
if (mt_com.mt_count <= 0 || *p)
err("%s: illegal count", *argv);
}
else
mt_com.mt_count = 1;
if (ioctl(mtfd, MTIOCTOP, &mt_com) < 0)
err("%s: %s: %s", tape, comp->c_name, strerror(errno));
} else {
if (ioctl(mtfd, MTIOCGET, &mt_status) < 0)
err("%s", strerror(errno));
status(&mt_status);
}
exit (0);
/* NOTREACHED */
}
#ifdef vax
#include <vax/mba/mtreg.h>
#include <vax/mba/htreg.h>
#include <vax/uba/utreg.h>
#include <vax/uba/tmreg.h>
#undef b_repcnt /* argh */
#include <vax/uba/tsreg.h>
#endif
#ifdef sun
#include <sundev/tmreg.h>
#include <sundev/arreg.h>
#endif
#ifdef tahoe
#include <tahoe/vba/cyreg.h>
#endif
struct tape_desc {
short t_type; /* type of magtape device */
char *t_name; /* printing name */
char *t_dsbits; /* "drive status" register */
char *t_erbits; /* "error" register */
} tapes[] = {
#ifdef vax
{ MT_ISTS, "ts11", 0, TSXS0_BITS },
{ MT_ISHT, "tm03", HTDS_BITS, HTER_BITS },
{ MT_ISTM, "tm11", 0, TMER_BITS },
{ MT_ISMT, "tu78", MTDS_BITS, 0 },
{ MT_ISUT, "tu45", UTDS_BITS, UTER_BITS },
#endif
#ifdef sun
{ MT_ISCPC, "TapeMaster", TMS_BITS, 0 },
{ MT_ISAR, "Archive", ARCH_CTRL_BITS, ARCH_BITS },
#endif
#ifdef tahoe
{ MT_ISCY, "cipher", CYS_BITS, CYCW_BITS },
#endif
{ 0 }
};
/*
* Interpret the status buffer returned
*/
void
status(bp)
register struct mtget *bp;
{
register struct tape_desc *mt;
for (mt = tapes;; mt++) {
if (mt->t_type == 0) {
(void)printf("%d: unknown tape drive type\n",
bp->mt_type);
return;
}
if (mt->t_type == bp->mt_type)
break;
}
(void)printf("%s tape drive, residual=%d\n", mt->t_name, bp->mt_resid);
printreg("ds", bp->mt_dsreg, mt->t_dsbits);
printreg("\ner", bp->mt_erreg, mt->t_erbits);
(void)putchar('\n');
}
/*
* Print a register a la the %b format of the kernel's printf.
*/
void
printreg(s, v, bits)
char *s;
register u_int v;
register char *bits;
{
register int i, any = 0;
register char c;
if (bits && *bits == 8)
printf("%s=%o", s, v);
else
printf("%s=%x", s, v);
bits++;
if (v && bits) {
putchar('<');
while (i = *bits++) {
if (v & (1 << (i-1))) {
if (any)
putchar(',');
any = 1;
for (; (c = *bits) > 32; bits++)
putchar(c);
} else
for (; *bits > 32; bits++)
;
}
putchar('>');
}
}
void
usage()
{
(void)fprintf(stderr, "usage: mt [-f device] command [ count ]\n");
exit(1);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "mt: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(1);
/* NOTREACHED */
}

100
usr.bin/printenv/printenv.c Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright (c) 1987, 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) 1987, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)printenv.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void usage __P((void));
/*
* printenv
*
* Bill Joy, UCB
* February, 1979
*/
int
main(argc, argv)
int argc;
char *argv[];
{
extern char **environ;
register char *cp, **ep;
register size_t len;
int ch;
while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc == 0) {
for (ep = environ; *ep; ep++)
(void)printf("%s\n", *ep);
exit(0);
}
len = strlen(*argv);
for (ep = environ; *ep; ep++)
if (!memcmp(*ep, *argv, len)) {
cp = *ep + len;
if (!*cp || *cp == '=') {
(void)printf("%s\n", *cp ? cp + 1 : cp);
exit(0);
}
}
exit(1);
}
void
usage()
{
(void)fprintf(stderr, "usage: printenv [name]\n");
exit(1);
}

110
usr.bin/rev/rev.c Normal file
View File

@ -0,0 +1,110 @@
/*-
* Copyright (c) 1987, 1992, 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) 1987, 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)rev.c 8.3 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <err.h>
#include <errno.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[];
{
register char *filename, *p, *t;
FILE *fp;
size_t len;
int ch, rval;
while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
fp = stdin;
filename = "stdin";
rval = 0;
do {
if (*argv) {
if ((fp = fopen(*argv, "r")) == NULL) {
warn("%s", *argv);
rval = 1;
++argv;
continue;
}
filename = *argv++;
}
while ((p = fgetln(fp, &len)) != NULL) {
if (p[len - 1] == '\n')
--len;
t = p + len - 1;
for (t = p + len - 1; t >= p; --t)
putchar(*t);
putchar('\n');
}
if (ferror(fp)) {
warn("%s", filename);
rval = 1;
}
(void)fclose(fp);
} while(*argv);
exit(rval);
}
void
usage()
{
(void)fprintf(stderr, "usage: rev [file ...]\n");
exit(1);
}

342
usr.bin/tr/str.c Normal file
View File

@ -0,0 +1,342 @@
/*-
* Copyright (c) 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[] = "@(#)str.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "extern.h"
static int backslash __P((STR *));
static int bracket __P((STR *));
static int c_class __P((const void *, const void *));
static void genclass __P((STR *));
static void genequiv __P((STR *));
static int genrange __P((STR *));
static void genseq __P((STR *));
int
next(s)
register STR *s;
{
register int ch;
switch (s->state) {
case EOS:
return (0);
case INFINITE:
return (1);
case NORMAL:
switch (ch = *s->str) {
case '\0':
s->state = EOS;
return (0);
case '\\':
s->lastch = backslash(s);
break;
case '[':
if (bracket(s))
return (next(s));
/* FALLTHROUGH */
default:
++s->str;
s->lastch = ch;
break;
}
/* We can start a range at any time. */
if (s->str[0] == '-' && genrange(s))
return (next(s));
return (1);
case RANGE:
if (s->cnt-- == 0) {
s->state = NORMAL;
return (next(s));
}
++s->lastch;
return (1);
case SEQUENCE:
if (s->cnt-- == 0) {
s->state = NORMAL;
return (next(s));
}
return (1);
case SET:
if ((s->lastch = s->set[s->cnt++]) == OOBCH) {
s->state = NORMAL;
return (next(s));
}
return (1);
}
/* NOTREACHED */
}
static int
bracket(s)
register STR *s;
{
register char *p;
switch (s->str[1]) {
case ':': /* "[:class:]" */
if ((p = strstr(s->str + 2, ":]")) == NULL)
return (0);
*p = '\0';
s->str += 2;
genclass(s);
s->str = p + 2;
return (1);
case '=': /* "[=equiv=]" */
if ((p = strstr(s->str + 2, "=]")) == NULL)
return (0);
s->str += 2;
genequiv(s);
return (1);
default: /* "[\###*n]" or "[#*n]" */
if ((p = strpbrk(s->str + 2, "*]")) == NULL)
return (0);
if (p[0] != '*' || index(p, ']') == NULL)
return (0);
s->str += 1;
genseq(s);
return (1);
}
/* NOTREACHED */
}
int isalnum __P((int)),
isalpha __P((int)),
isblank __P((int)),
isspace __P((int)),
iscntrl __P((int)),
isdigit __P((int)),
isgraph __P((int)),
islower __P((int)),
isprint __P((int)),
ispunct __P((int)),
isupper __P((int)),
isxdigit __P((int));
typedef struct {
char *name;
int (*func) __P((int));
int *set;
} CLASS;
static CLASS classes[] = {
{ "alnum", isalnum, },
{ "alpha", isalpha, },
{ "blank", isblank, },
{ "cntrl", iscntrl, },
{ "digit", isdigit, },
{ "graph", isgraph, },
{ "lower", islower, },
{ "print", isupper, },
{ "punct", ispunct, },
{ "space", isspace, },
{ "upper", isupper, },
{ "xdigit", isxdigit, },
};
static void
genclass(s)
STR *s;
{
register int cnt, (*func) __P((int));
CLASS *cp, tmp;
int *p;
tmp.name = s->str;
if ((cp = (CLASS *)bsearch(&tmp, classes, sizeof(classes) /
sizeof(CLASS), sizeof(CLASS), c_class)) == NULL)
err("unknown class %s", s->str);
if ((cp->set = p = malloc((NCHARS + 1) * sizeof(int))) == NULL)
err("%s", strerror(errno));
bzero(p, (NCHARS + 1) * sizeof(int));
for (cnt = 0, func = cp->func; cnt < NCHARS; ++cnt)
if ((func)(cnt))
*p++ = cnt;
*p = OOBCH;
s->cnt = 0;
s->state = SET;
s->set = cp->set;
}
static int
c_class(a, b)
const void *a, *b;
{
return (strcmp(((CLASS *)a)->name, ((CLASS *)b)->name));
}
/*
* English doesn't have any equivalence classes, so for now
* we just syntax check and grab the character.
*/
static void
genequiv(s)
STR *s;
{
if (*s->str == '\\') {
s->equiv[0] = backslash(s);
if (*s->str != '=')
err("misplaced equivalence equals sign");
} else {
s->equiv[0] = s->str[0];
if (s->str[1] != '=')
err("misplaced equivalence equals sign");
}
s->str += 2;
s->cnt = 0;
s->state = SET;
s->set = s->equiv;
}
static int
genrange(s)
STR *s;
{
int stopval;
char *savestart;
savestart = s->str;
stopval = *++s->str == '\\' ? backslash(s) : *s->str++;
if (stopval < (u_char)s->lastch) {
s->str = savestart;
return (0);
}
s->cnt = stopval - s->lastch + 1;
s->state = RANGE;
--s->lastch;
return (1);
}
static void
genseq(s)
STR *s;
{
char *ep;
if (s->which == STRING1)
err("sequences only valid in string2");
if (*s->str == '\\')
s->lastch = backslash(s);
else
s->lastch = *s->str++;
if (*s->str != '*')
err("misplaced sequence asterisk");
switch (*++s->str) {
case '\\':
s->cnt = backslash(s);
break;
case ']':
s->cnt = 0;
++s->str;
break;
default:
if (isdigit(*s->str)) {
s->cnt = strtol(s->str, &ep, 0);
if (*ep == ']') {
s->str = ep + 1;
break;
}
}
err("illegal sequence count");
/* NOTREACHED */
}
s->state = s->cnt ? SEQUENCE : INFINITE;
}
/* Use the #defines isXXX() here, DON'T use them above. */
#include <ctype.h>
/*
* Translate \??? into a character. Up to 3 octal digits, if no digits either
* an escape code or a literal character.
*/
static int
backslash(s)
register STR *s;
{
register int ch, cnt, val;
for (cnt = val = 0;;) {
ch = *++s->str;
if (!isascii(ch) || !isdigit(ch))
break;
val = val * 8 + ch - '0';
if (++cnt == 3) {
++s->str;
break;
}
}
if (cnt)
return (val);
if (ch != '\0')
++s->str;
switch (ch) {
case 'a': /* escape characters */
return ('\7');
case 'b':
return ('\b');
case 'f':
return ('\f');
case 'n':
return ('\n');
case 'r':
return ('\r');
case 't':
return ('\t');
case 'v':
return ('\13');
case '\0': /* \" -> \ */
s->state = EOS;
return ('\\');
default: /* \x" -> x */
return (ch);
}
}

290
usr.bin/tr/tr.c Normal file
View File

@ -0,0 +1,290 @@
/*
* 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[] = "@(#)tr.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "extern.h"
static int string1[NCHARS] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* ASCII */
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
}, string2[NCHARS];
STR s1 = { STRING1, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
STR s2 = { STRING2, NORMAL, 0, OOBCH, { 0, OOBCH }, NULL, NULL };
static void setup __P((int *, char *, STR *, int));
static void usage __P((void));
int
main(argc, argv)
int argc;
char **argv;
{
register int ch, cnt, lastch, *p;
int cflag, dflag, sflag, isstring2;
cflag = dflag = sflag = 0;
while ((ch = getopt(argc, argv, "cds")) != EOF)
switch((char)ch) {
case 'c':
cflag = 1;
break;
case 'd':
dflag = 1;
break;
case 's':
sflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
switch(argc) {
case 0:
default:
usage();
/* NOTREACHED */
case 1:
isstring2 = 0;
break;
case 2:
isstring2 = 1;
break;
}
/*
* tr -ds [-c] string1 string2
* Delete all characters (or complemented characters) in string1.
* Squeeze all characters in string2.
*/
if (dflag && sflag) {
if (!isstring2)
usage();
setup(string1, argv[0], &s1, cflag);
setup(string2, argv[1], &s2, 0);
for (lastch = OOBCH; (ch = getchar()) != EOF;)
if (!string1[ch] && (!string2[ch] || lastch != ch)) {
lastch = ch;
(void)putchar(ch);
}
exit(0);
}
/*
* tr -d [-c] string1
* Delete all characters (or complemented characters) in string1.
*/
if (dflag) {
if (isstring2)
usage();
setup(string1, argv[0], &s1, cflag);
while ((ch = getchar()) != EOF)
if (!string1[ch])
(void)putchar(ch);
exit(0);
}
/*
* tr -s [-c] string1
* Squeeze all characters (or complemented characters) in string1.
*/
if (sflag && !isstring2) {
setup(string1, argv[0], &s1, cflag);
for (lastch = OOBCH; (ch = getchar()) != EOF;)
if (!string1[ch] || lastch != ch) {
lastch = ch;
(void)putchar(ch);
}
exit(0);
}
/*
* tr [-cs] string1 string2
* Replace all characters (or complemented characters) in string1 with
* the character in the same position in string2. If the -s option is
* specified, squeeze all the characters in string2.
*/
if (!isstring2)
usage();
s1.str = argv[0];
s2.str = argv[1];
if (cflag)
for (cnt = NCHARS, p = string1; cnt--;)
*p++ = OOBCH;
if (!next(&s2))
err("empty string2");
/* If string2 runs out of characters, use the last one specified. */
if (sflag)
while (next(&s1)) {
string1[s1.lastch] = ch = s2.lastch;
string2[ch] = 1;
(void)next(&s2);
}
else
while (next(&s1)) {
string1[s1.lastch] = ch = s2.lastch;
(void)next(&s2);
}
if (cflag)
for (cnt = 0, p = string1; cnt < NCHARS; ++p, ++cnt)
*p = *p == OOBCH ? ch : cnt;
if (sflag)
for (lastch = OOBCH; (ch = getchar()) != EOF;) {
ch = string1[ch];
if (!string2[ch] || lastch != ch) {
lastch = ch;
(void)putchar(ch);
}
}
else
while ((ch = getchar()) != EOF)
(void)putchar(string1[ch]);
exit (0);
}
static void
setup(string, arg, str, cflag)
int *string;
char *arg;
STR *str;
int cflag;
{
register int cnt, *p;
str->str = arg;
bzero(string, NCHARS * sizeof(int));
while (next(str))
string[str->lastch] = 1;
if (cflag)
for (p = string, cnt = NCHARS; cnt--; ++p)
*p = !*p;
}
static void
usage()
{
(void)fprintf(stderr, "usage: tr [-cs] string1 string2\n");
(void)fprintf(stderr, " tr [-c] -d string1\n");
(void)fprintf(stderr, " tr [-c] -s string1\n");
(void)fprintf(stderr, " tr [-c] -ds string1 string2\n");
exit(1);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "tr: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(1);
/* NOTREACHED */
}

163
usr.bin/uname/uname.c Normal file
View File

@ -0,0 +1,163 @@
/*-
* 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 copyright[] =
"@(#) Copyright (c) 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)uname.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/sysctl.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
#define MFLAG 0x01
#define NFLAG 0x02
#define RFLAG 0x04
#define SFLAG 0x08
#define VFLAG 0x10
u_int flags;
int ch, mib[2];
size_t len, tlen;
char *p, *prefix, buf[1024];
flags = 0;
while ((ch = getopt(argc, argv, "amnrsv")) != EOF)
switch(ch) {
case 'a':
flags |= (MFLAG | NFLAG | RFLAG | SFLAG | VFLAG);
break;
case 'm':
flags |= MFLAG;
break;
case 'n':
flags |= NFLAG;
break;
case 'r':
flags |= RFLAG;
break;
case 's':
flags |= SFLAG;
break;
case 'v':
flags |= VFLAG;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc)
usage();
if (!flags)
flags |= SFLAG;
prefix = "";
if (flags & SFLAG) {
mib[0] = CTL_KERN;
mib[1] = KERN_OSTYPE;
len = sizeof(buf);
if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1)
err(1, "sysctl");
(void)printf("%s%.*s", prefix, len, buf);
prefix = " ";
}
if (flags & NFLAG) {
mib[0] = CTL_KERN;
mib[1] = KERN_HOSTNAME;
len = sizeof(buf);
if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1)
err(1, "sysctl");
(void)printf("%s%.*s", prefix, len, buf);
prefix = " ";
}
if (flags & RFLAG) {
mib[0] = CTL_KERN;
mib[1] = KERN_OSRELEASE;
len = sizeof(buf);
if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1)
err(1, "sysctl");
(void)printf("%s%.*s", prefix, len, buf);
prefix = " ";
}
if (flags & VFLAG) {
mib[0] = CTL_KERN;
mib[1] = KERN_VERSION;
len = sizeof(buf);
if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1)
err(1, "sysctl");
for (p = buf, tlen = len; tlen--; ++p)
if (*p == '\n' || *p == '\t')
*p = ' ';
(void)printf("%s%.*s", prefix, len, buf);
prefix = " ";
}
if (flags & MFLAG) {
mib[0] = CTL_HW;
mib[1] = HW_MACHINE;
len = sizeof(buf);
if (sysctl(mib, 2, &buf, &len, NULL, 0) == -1)
err(1, "sysctl");
(void)printf("%s%.*s", prefix, len, buf);
prefix = " ";
}
(void)printf("\n");
exit (0);
}
void
usage()
{
(void)fprintf(stderr, "usage: uname [-amnrsv]\n");
exit(1);
}

276
usr.bin/uniq/uniq.c Normal file
View File

@ -0,0 +1,276 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Case Larsen.
*
* 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[] = "@(#)uniq.c 8.3 (Berkeley) 5/4/95";
#endif /* not lint */
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAXLINELEN (8 * 1024)
int cflag, dflag, uflag;
int numchars, numfields, repeats;
void err __P((const char *, ...));
FILE *file __P((char *, char *));
void show __P((FILE *, char *));
char *skip __P((char *));
void obsolete __P((char *[]));
void usage __P((void));
int
main (argc, argv)
int argc;
char *argv[];
{
register char *t1, *t2;
FILE *ifp, *ofp;
int ch;
char *prevline, *thisline, *p;
obsolete(argv);
while ((ch = getopt(argc, argv, "-cdf:s:u")) != EOF)
switch (ch) {
case '-':
--optind;
goto done;
case 'c':
cflag = 1;
break;
case 'd':
dflag = 1;
break;
case 'f':
numfields = strtol(optarg, &p, 10);
if (numfields < 0 || *p)
err("illegal field skip value: %s", optarg);
break;
case 's':
numchars = strtol(optarg, &p, 10);
if (numchars < 0 || *p)
err("illegal character skip value: %s", optarg);
break;
case 'u':
uflag = 1;
break;
case '?':
default:
usage();
}
done: argc -= optind;
argv +=optind;
/* If no flags are set, default is -d -u. */
if (cflag) {
if (dflag || uflag)
usage();
} else if (!dflag && !uflag)
dflag = uflag = 1;
switch(argc) {
case 0:
ifp = stdin;
ofp = stdout;
break;
case 1:
ifp = file(argv[0], "r");
ofp = stdout;
break;
case 2:
ifp = file(argv[0], "r");
ofp = file(argv[1], "w");
break;
default:
usage();
}
prevline = malloc(MAXLINELEN);
thisline = malloc(MAXLINELEN);
if (prevline == NULL || thisline == NULL)
err("%s", strerror(errno));
if (fgets(prevline, MAXLINELEN, ifp) == NULL)
exit(0);
while (fgets(thisline, MAXLINELEN, ifp)) {
/* If requested get the chosen fields + character offsets. */
if (numfields || numchars) {
t1 = skip(thisline);
t2 = skip(prevline);
} else {
t1 = thisline;
t2 = prevline;
}
/* If different, print; set previous to new value. */
if (strcmp(t1, t2)) {
show(ofp, prevline);
t1 = prevline;
prevline = thisline;
thisline = t1;
repeats = 0;
} else
++repeats;
}
show(ofp, prevline);
exit(0);
}
/*
* show --
* Output a line depending on the flags and number of repetitions
* of the line.
*/
void
show(ofp, str)
FILE *ofp;
char *str;
{
if (cflag && *str)
(void)fprintf(ofp, "%4d %s", repeats + 1, str);
if (dflag && repeats || uflag && !repeats)
(void)fprintf(ofp, "%s", str);
}
char *
skip(str)
register char *str;
{
register int infield, nchars, nfields;
for (nfields = numfields, infield = 0; nfields && *str; ++str)
if (isspace(*str)) {
if (infield) {
infield = 0;
--nfields;
}
} else if (!infield)
infield = 1;
for (nchars = numchars; nchars-- && *str; ++str);
return(str);
}
FILE *
file(name, mode)
char *name, *mode;
{
FILE *fp;
if ((fp = fopen(name, mode)) == NULL)
err("%s: %s", name, strerror(errno));
return(fp);
}
void
obsolete(argv)
char *argv[];
{
int len;
char *ap, *p, *start;
while (ap = *++argv) {
/* Return if "--" or not an option of any form. */
if (ap[0] != '-') {
if (ap[0] != '+')
return;
} else if (ap[1] == '-')
return;
if (!isdigit(ap[1]))
continue;
/*
* Digit signifies an old-style option. Malloc space for dash,
* new option and argument.
*/
len = strlen(ap);
if ((start = p = malloc(len + 3)) == NULL)
err("%s", strerror(errno));
*p++ = '-';
*p++ = ap[0] == '+' ? 's' : 'f';
(void)strcpy(p, ap + 1);
*argv = start;
}
}
void
usage()
{
(void)fprintf(stderr,
"usage: uniq [-c | -du] [-f fields] [-s chars] [input [output]]\n");
exit(1);
}
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
void
#if __STDC__
err(const char *fmt, ...)
#else
err(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
(void)fprintf(stderr, "uniq: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(1);
/* NOTREACHED */
}