This commit was generated by cvs2svn to compensate for changes in r27241,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
Bruce Evans 1997-07-06 06:54:14 +00:00
commit aac7bd5670
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=27242
84 changed files with 25364 additions and 0 deletions

7
usr.bin/apropos/Makefile Normal file
View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= apropos
SRCS= apropos.c config.c
.PATH: ${.CURDIR}/../man
.include <bsd.prog.mk>

120
usr.bin/apropos/apropos.1 Normal file
View File

@ -0,0 +1,120 @@
.\" Copyright (c) 1989, 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.
.\"
.\" @(#)apropos.1 8.1 (Berkeley) 6/29/93
.\"
.Dd June 29, 1993
.Dt APROPOS 1
.Os
.Sh NAME
.Nm apropos
.Nd locate commands by keyword lookup
.Sh SYNOPSIS
.Nm apropos
.Op Fl M Ar path
.Op Fl m Ar path
.Ar keyword ...
.Sh DESCRIPTION
.Nm Apropos
shows which manual pages contain instances of any of the given
.Ar keyword(s)
in their title line.
Each word is considered separately and case of letters is ignored.
Words which are part of other words are considered; when looking for
.Dq compile ,
.Nm apropos
will also list all instances of
.Dq compiler .
.Pp
If the line output by
.Nm apropos
starts
.Dq Li name(section) ...
you can enter
.Dq Li man section name
to get
its documentation.
.Pp
The options are as follows:
.Bl -tag -width flag
.It Fl M
Override the list of standard directories
.Nm apropos
searches for a database named
.Pa whatis.db .
The supplied
.Ar path
must be a colon
.Dq \&:
separated list of directories.
This search path may also be set using the environment variable
.Ev MANPATH .
.It Fl m
Augment the list of standard directories
.Nm apropos
searches for its database.
The supplied
.Ar path
must be a colon
.Dq \&:
separated list of directories.
These directories will be searched before the standard directories,
or the directories supplied with the
.Fl M
option or the
.Ev MANPATH
environment variable.
.Sh ENVIRONMENT
.Bl -tag -width MANPATH
.It Ev MANPATH
The standard search path used by
.Xr man 1
may be overridden by specifying a path in the
.Ev MANPATH
environment variable.
The format of the path is a colon
.Dq \&:
separated list of directories.
.El
.Sh FILES
.Bl -tag -width whatis.db -compact
.It Pa whatis.db
name of the apropos database
.El
.Sh SEE ALSO
.Xr man 1 ,
.Xr whatis 1 ,
.Xr whereis 1
.Sh HISTORY
The
.Nm apropos
command appeared in
.Bx 3.0 .

224
usr.bin/apropos/apropos.c Normal file
View File

@ -0,0 +1,224 @@
/*
* Copyright (c) 1987, 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) 1987, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)apropos.c 8.8 (Berkeley) 5/4/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "../man/config.h"
#include "../man/pathnames.h"
static int *found, foundman;
void apropos __P((char **, char *, int));
void lowstr __P((char *, char *));
int match __P((char *, char *));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
ENTRY *ep;
TAG *tp;
int ch, rv;
char *conffile, **p, *p_augment, *p_path;
conffile = NULL;
p_augment = p_path = NULL;
while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF)
switch (ch) {
case 'C':
conffile = optarg;
break;
case 'M':
case 'P': /* backward compatible */
p_path = optarg;
break;
case 'm':
p_augment = optarg;
break;
case '?':
default:
usage();
}
argv += optind;
argc -= optind;
if (argc < 1)
usage();
if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
err(1, NULL);
memset(found, 0, argc * sizeof(int));
for (p = argv; *p; ++p) /* convert to lower-case */
lowstr(*p, *p);
if (p_augment)
apropos(argv, p_augment, 1);
if (p_path || (p_path = getenv("MANPATH")))
apropos(argv, p_path, 1);
else {
config(conffile);
ep = (tp = getlist("_whatdb")) == NULL ?
NULL : tp->list.tqh_first;
for (; ep != NULL; ep = ep->q.tqe_next)
apropos(argv, ep->s, 0);
}
if (!foundman)
errx(1, "no %s file found", _PATH_WHATIS);
rv = 1;
for (p = argv; *p; ++p)
if (found[p - argv])
rv = 0;
else
(void)printf("%s: nothing appropriate\n", *p);
exit(rv);
}
void
apropos(argv, path, buildpath)
char **argv, *path;
int buildpath;
{
char *end, *name, **p;
char buf[LINE_MAX + 1], wbuf[LINE_MAX + 1];
for (name = path; name; name = end) { /* through name list */
if (end = strchr(name, ':'))
*end++ = '\0';
if (buildpath) {
char hold[MAXPATHLEN + 1];
(void)sprintf(hold, "%s/%s", name, _PATH_WHATIS);
name = hold;
}
if (!freopen(name, "r", stdin))
continue;
foundman = 1;
/* for each file found */
while (fgets(buf, sizeof(buf), stdin)) {
if (!strchr(buf, '\n')) {
warnx("%s: line too long", name);
continue;
}
lowstr(buf, wbuf);
for (p = argv; *p; ++p)
if (match(wbuf, *p)) {
(void)printf("%s", buf);
found[p - argv] = 1;
/* only print line once */
while (*++p)
if (match(wbuf, *p))
found[p - argv] = 1;
break;
}
}
}
}
/*
* match --
* match anywhere the string appears
*/
int
match(bp, str)
char *bp, *str;
{
int len;
char test;
if (!*bp)
return (0);
/* backward compatible: everything matches empty string */
if (!*str)
return (1);
for (test = *str++, len = strlen(str); *bp;)
if (test == *bp++ && !strncmp(bp, str, len))
return (1);
return (0);
}
/*
* lowstr --
* convert a string to lower case
*/
void
lowstr(from, to)
char *from, *to;
{
char ch;
while ((ch = *from++) && ch != '\n')
*to++ = isupper(ch) ? tolower(ch) : ch;
*to = '\0';
}
/*
* usage --
* print usage message and die
*/
void
usage()
{
(void)fprintf(stderr,
"usage: apropos [-C file] [-M path] [-m path] keyword ...\n");
exit(1);
}

146
usr.bin/ar/ar.5.5 Normal file
View File

@ -0,0 +1,146 @@
.\" Copyright (c) 1990, 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.
.\"
.\" @(#)ar.5.5 8.2 (Berkeley) 6/1/94
.\"
.Dd June 1, 1994
.Dt AR 5
.Os
.Sh NAME
.Nm ar
.Nd archive (library) file format
.Sh SYNOPSIS
.Fd #include <ar.h>
.Sh DESCRIPTION
The archive command
.Nm ar
combines several files into one.
Archives are mainly used as libraries of object files intended to be
loaded using the link-editor
.Xr ld 1 .
.Pp
A file created with
.Nm ar
begins with the ``magic'' string "!<arch>\en".
The rest of the archive is made up of objects, each of which is composed
of a header for a file, a possible file name, and the file contents.
The header is portable between machine architectures, and, if the file
contents are printable, the archive is itself printable.
.Pp
The header is made up of six variable length
.Tn ASCII
fields, followed by a
two character trailer.
The fields are the object name (16 characters), the file last modification
time (12 characters), the user and group id's (each 6 characters), the file
mode (8 characters) and the file size (10 characters).
All numeric fields are in decimal, except for the file mode which is in
octal.
.Pp
The modification time is the file
.Fa st_mtime
field, i.e.,
.Dv CUT
seconds since
the epoch.
The user and group id's are the file
.Fa st_uid
and
.Fa st_gid
fields.
The file mode is the file
.Fa st_mode
field.
The file size is the file
.Fa st_size
field.
The two-byte trailer is the string "\`\en".
.Pp
Only the name field has any provision for overflow.
If any file name is more than 16 characters in length or contains an
embedded space, the string "#1/" followed by the
.Tn ASCII
length of the
name is written in the name field.
The file size (stored in the archive header) is incremented by the length
of the name.
The name is then written immediately following the archive header.
.Pp
Any unused characters in any of these fields are written as space
characters.
If any fields are their particular maximum number of characters in
length, there will be no separation between the fields.
.Pp
Objects in the archive are always an even number of bytes long; files
which are an odd number of bytes long are padded with a newline (``\en'')
character, although the size in the header does not reflect this.
.Sh SEE ALSO
.Xr ar 1 ,
.Xr stat 2
.Sh HISTORY
There have been at least four
.Nm ar
formats.
The first was denoted by the leading ``magic'' number 0177555 (stored as
type int).
These archives were almost certainly created on a 16-bit machine, and
contain headers made up of five fields.
The fields are the object name (8 characters), the file last modification
time (type long), the user id (type char), the file mode (type char) and
the file size (type unsigned int).
Files were padded to an even number of bytes.
.Pp
The second was denoted by the leading ``magic'' number 0177545 (stored as
type int).
These archives may have been created on either 16 or 32-bit machines, and
contain headers made up of six fields.
The fields are the object name (14 characters), the file last modification
time (type long), the user and group id's (each type char), the file mode
(type int) and the file size (type long).
Files were padded to an even number of bytes.
For more information on converting from this format see
.Xr arcv 8 .
.ne 1i
.Pp
The current archive format (without support for long character names and
names with embedded spaces) was introduced in
.Bx 4.0 .
The headers were the same as the current format, with the exception that
names longer than 16 characters were truncated, and names with embedded
spaces (and often trailing spaces) were not supported.
It has been extended for these reasons,
as described above.
This format first appeared in 4.4BSD.
.Sh COMPATIBILITY
No archive format is currently specified by any standard.
.At V
has historically distributed archives in a different format from
all of the above.

7
usr.bin/ld/Makefile Normal file
View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= ld
SRCS= ld.c cplus-dem.c
NOMAN= noman
.include <bsd.prog.mk>

970
usr.bin/ld/cplus-dem.c Normal file
View File

@ -0,0 +1,970 @@
/*-
* This code is derived from software copyrighted by the Free Software
* Foundation.
*/
#ifndef lint
static char sccsid[] = "@(#)cplus-dem.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/* Demangler for GNU C++
Copyright (C) 1989 Free Software Foundation, Inc.
written by James Clark (jjc@jclark.uucp)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* This is for g++ 1.36.1 (November 6 version). It will probably
require changes for any other version.
Modified for g++ 1.36.2 (November 18 version). */
/* This file exports one function
char *cplus_demangle (const char *name)
If `name' is a mangled function name produced by g++, then
a pointer to a malloced string giving a C++ representation
of the name will be returned; otherwise NULL will be returned.
It is the caller's responsibility to free the string which
is returned.
For example,
cplus_demangle ("_foo__1Ai")
returns
"A::foo(int)"
This file imports xmalloc and xrealloc, which are like malloc and
realloc except that they generate a fatal error if there is no
available memory. */
/* #define nounderscore 1 /* define this is names don't start with _ */
#include <stdio.h>
#include <ctype.h>
#ifdef USG
#include <memory.h>
#include <string.h>
#else
#include <strings.h>
#define memcpy(s1, s2, n) bcopy ((s2), (s1), (n))
#define memcmp(s1, s2, n) bcmp ((s2), (s1), (n))
#define strchr index
#define strrchr rindex
#endif
#ifdef __STDC__
extern char *cplus_demangle (const char *type);
#else
extern char *cplus_demangle ();
#endif
#ifdef __STDC__
extern char *xmalloc (int);
extern char *xrealloc (char *, int);
#else
extern char *xmalloc ();
extern char *xrealloc ();
#endif
static char **typevec = 0;
static int ntypes = 0;
static int typevec_size = 0;
static struct {
const char *in;
const char *out;
} optable[] = {
"new", " new",
"delete", " delete",
"ne", "!=",
"eq", "==",
"ge", ">=",
"gt", ">",
"le", "<=",
"lt", "<",
"plus", "+",
"minus", "-",
"mult", "*",
"convert", "+", /* unary + */
"negate", "-", /* unary - */
"trunc_mod", "%",
"trunc_div", "/",
"truth_andif", "&&",
"truth_orif", "||",
"truth_not", "!",
"postincrement", "++",
"postdecrement", "--",
"bit_ior", "|",
"bit_xor", "^",
"bit_and", "&",
"bit_not", "~",
"call", "()",
"cond", "?:",
"alshift", "<<",
"arshift", ">>",
"component", "->",
"indirect", "*",
"method_call", "->()",
"addr", "&", /* unary & */
"array", "[]",
"nop", "", /* for operator= */
};
/* Beware: these aren't '\0' terminated. */
typedef struct {
char *b; /* pointer to start of string */
char *p; /* pointer after last character */
char *e; /* pointer after end of allocated space */
} string;
#ifdef __STDC__
static void string_need (string *s, int n);
static void string_delete (string *s);
static void string_init (string *s);
static void string_clear (string *s);
static int string_empty (string *s);
static void string_append (string *p, const char *s);
static void string_appends (string *p, string *s);
static void string_appendn (string *p, const char *s, int n);
static void string_prepend (string *p, const char *s);
#if 0
static void string_prepends (string *p, string *s);
#endif
static void string_prependn (string *p, const char *s, int n);
static int get_count (const char **type, int *count);
static int do_args (const char **type, string *decl);
static int do_type (const char **type, string *result);
static int do_arg (const char **type, string *result);
static int do_args (const char **type, string *decl);
static void munge_function_name (string *name);
static void remember_type (const char *type, int len);
#else
static void string_need ();
static void string_delete ();
static void string_init ();
static void string_clear ();
static int string_empty ();
static void string_append ();
static void string_appends ();
static void string_appendn ();
static void string_prepend ();
static void string_prepends ();
static void string_prependn ();
static int get_count ();
static int do_args ();
static int do_type ();
static int do_arg ();
static int do_args ();
static void munge_function_name ();
static void remember_type ();
#endif
char *
cplus_demangle (type)
const char *type;
{
string decl;
int n;
int success = 0;
int constructor = 0;
int const_flag = 0;
int i;
const char *p;
#ifndef LONGERNAMES
const char *premangle;
#endif
if (type == NULL || *type == '\0')
return NULL;
#ifndef nounderscore
if (*type++ != '_')
return NULL;
#endif
p = type;
while (*p != '\0' && !(*p == '_' && p[1] == '_'))
p++;
if (*p == '\0')
{
/* destructor */
if (type[0] == '_' && type[1] == '$' && type[2] == '_')
{
int n = (strlen (type) - 3)*2 + 3 + 2 + 1;
char *tem = (char *) xmalloc (n);
strcpy (tem, type + 3);
strcat (tem, "::~");
strcat (tem, type + 3);
strcat (tem, "()");
return tem;
}
/* static data member */
if (*type != '_' && (p = strchr (type, '$')) != NULL)
{
int n = strlen (type) + 2;
char *tem = (char *) xmalloc (n);
memcpy (tem, type, p - type);
strcpy (tem + (p - type), "::");
strcpy (tem + (p - type) + 2, p + 1);
return tem;
}
/* virtual table */
if (type[0] == '_' && type[1] == 'v' && type[2] == 't' && type[3] == '$')
{
int n = strlen (type + 4) + 14 + 1;
char *tem = (char *) xmalloc (n);
strcpy (tem, type + 4);
strcat (tem, " virtual table");
return tem;
}
return NULL;
}
string_init (&decl);
if (p == type)
{
if (!isdigit (p[2]))
{
string_delete (&decl);
return NULL;
}
constructor = 1;
}
else
{
string_appendn (&decl, type, p - type);
munge_function_name (&decl);
}
p += 2;
#ifndef LONGERNAMES
premangle = p;
#endif
switch (*p)
{
case 'C':
/* a const member function */
if (!isdigit (p[1]))
{
string_delete (&decl);
return NULL;
}
p += 1;
const_flag = 1;
/* fall through */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
n = 0;
do
{
n *= 10;
n += *p - '0';
p += 1;
}
while (isdigit (*p));
if (strlen (p) < n)
{
string_delete (&decl);
return NULL;
}
if (constructor)
{
string_appendn (&decl, p, n);
string_append (&decl, "::");
string_appendn (&decl, p, n);
}
else
{
string_prepend (&decl, "::");
string_prependn (&decl, p, n);
}
p += n;
#ifndef LONGERNAMES
remember_type (premangle, p - premangle);
#endif
success = do_args (&p, &decl);
if (const_flag)
string_append (&decl, " const");
break;
case 'F':
p += 1;
success = do_args (&p, &decl);
break;
}
for (i = 0; i < ntypes; i++)
if (typevec[i] != NULL)
free (typevec[i]);
ntypes = 0;
if (typevec != NULL)
{
free ((char *)typevec);
typevec = NULL;
typevec_size = 0;
}
if (success)
{
string_appendn (&decl, "", 1);
return decl.b;
}
else
{
string_delete (&decl);
return NULL;
}
}
static int
get_count (type, count)
const char **type;
int *count;
{
if (!isdigit (**type))
return 0;
*count = **type - '0';
*type += 1;
/* see flush_repeats in cplus-method.c */
if (isdigit (**type))
{
const char *p = *type;
int n = *count;
do
{
n *= 10;
n += *p - '0';
p += 1;
}
while (isdigit (*p));
if (*p == '_')
{
*type = p + 1;
*count = n;
}
}
return 1;
}
/* result will be initialised here; it will be freed on failure */
static int
do_type (type, result)
const char **type;
string *result;
{
int n;
int done;
int non_empty = 0;
int success;
string decl;
const char *remembered_type;
string_init (&decl);
string_init (result);
done = 0;
success = 1;
while (success && !done)
{
int member;
switch (**type)
{
case 'P':
*type += 1;
string_prepend (&decl, "*");
break;
case 'R':
*type += 1;
string_prepend (&decl, "&");
break;
case 'T':
*type += 1;
if (!get_count (type, &n) || n >= ntypes)
success = 0;
else
{
remembered_type = typevec[n];
type = &remembered_type;
}
break;
case 'F':
*type += 1;
if (!string_empty (&decl) && decl.b[0] == '*')
{
string_prepend (&decl, "(");
string_append (&decl, ")");
}
if (!do_args (type, &decl) || **type != '_')
success = 0;
else
*type += 1;
break;
case 'M':
case 'O':
{
int constp = 0;
int volatilep = 0;
member = **type == 'M';
*type += 1;
if (!isdigit (**type))
{
success = 0;
break;
}
n = 0;
do
{
n *= 10;
n += **type - '0';
*type += 1;
}
while (isdigit (**type));
if (strlen (*type) < n)
{
success = 0;
break;
}
string_append (&decl, ")");
string_prepend (&decl, "::");
string_prependn (&decl, *type, n);
string_prepend (&decl, "(");
*type += n;
if (member)
{
if (**type == 'C')
{
*type += 1;
constp = 1;
}
if (**type == 'V')
{
*type += 1;
volatilep = 1;
}
if (*(*type)++ != 'F')
{
success = 0;
break;
}
}
if ((member && !do_args (type, &decl)) || **type != '_')
{
success = 0;
break;
}
*type += 1;
if (constp)
{
if (non_empty)
string_append (&decl, " ");
else
non_empty = 1;
string_append (&decl, "const");
}
if (volatilep)
{
if (non_empty)
string_append (&decl, " ");
else
non_empty = 1;
string_append (&decl, "volatilep");
}
break;
}
case 'C':
if ((*type)[1] == 'P')
{
*type += 1;
if (!string_empty (&decl))
string_prepend (&decl, " ");
string_prepend (&decl, "const");
break;
}
/* fall through */
default:
done = 1;
break;
}
}
done = 0;
non_empty = 0;
while (success && !done)
{
switch (**type)
{
case 'C':
*type += 1;
if (non_empty)
string_append (result, " ");
else
non_empty = 1;
string_append (result, "const");
break;
case 'U':
*type += 1;
if (non_empty)
string_append (result, " ");
else
non_empty = 1;
string_append (result, "unsigned");
break;
case 'V':
*type += 1;
if (non_empty)
string_append (result, " ");
else
non_empty = 1;
string_append (result, "volatile");
break;
default:
done = 1;
break;
}
}
if (success)
switch (**type)
{
case '\0':
case '_':
break;
case 'v':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "void");
break;
case 'x':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "long long");
break;
case 'l':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "long");
break;
case 'i':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "int");
break;
case 's':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "short");
break;
case 'c':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "char");
break;
case 'r':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "long double");
break;
case 'd':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "double");
break;
case 'f':
*type += 1;
if (non_empty)
string_append (result, " ");
string_append (result, "float");
break;
case 'G':
*type += 1;
if (!isdigit (**type))
{
success = 0;
break;
}
/* fall through */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
n = 0;
do
{
n *= 10;
n += **type - '0';
*type += 1;
}
while (isdigit (**type));
if (strlen (*type) < n)
{
success = 0;
break;
}
if (non_empty)
string_append (result, " ");
string_appendn (result, *type, n);
*type += n;
break;
default:
success = 0;
break;
}
if (success)
{
if (!string_empty (&decl))
{
string_append (result, " ");
string_appends (result, &decl);
}
string_delete (&decl);
return 1;
}
else
{
string_delete (&decl);
string_delete (result);
return 0;
}
}
/* `result' will be initialised in do_type; it will be freed on failure */
static int
do_arg (type, result)
const char **type;
string *result;
{
const char *start = *type;
if (!do_type (type, result))
return 0;
remember_type (start, *type - start);
return 1;
}
static void
remember_type (start, len)
const char *start;
int len;
{
char *tem;
if (ntypes >= typevec_size)
{
if (typevec_size == 0)
{
typevec_size = 3;
typevec = (char **) xmalloc (sizeof (char*)*typevec_size);
}
else
{
typevec_size *= 2;
typevec = (char **) xrealloc ((char *)typevec, sizeof (char*)*typevec_size);
}
}
tem = (char *) xmalloc (len + 1);
memcpy (tem, start, len);
tem[len] = '\0';
typevec[ntypes++] = tem;
}
/* `decl' must be already initialised, usually non-empty;
it won't be freed on failure */
static int
do_args (type, decl)
const char **type;
string *decl;
{
string arg;
int need_comma = 0;
string_append (decl, "(");
while (**type != '_' && **type != '\0' && **type != 'e' && **type != 'v')
{
if (**type == 'N')
{
int r;
int t;
*type += 1;
if (!get_count (type, &r) || !get_count (type, &t) || t >= ntypes)
return 0;
while (--r >= 0)
{
const char *tem = typevec[t];
if (need_comma)
string_append (decl, ", ");
if (!do_arg (&tem, &arg))
return 0;
string_appends (decl, &arg);
string_delete (&arg);
need_comma = 1;
}
}
else
{
if (need_comma)
string_append (decl, ", ");
if (!do_arg (type, &arg))
return 0;
string_appends (decl, &arg);
string_delete (&arg);
need_comma = 1;
}
}
if (**type == 'v')
*type += 1;
else if (**type == 'e')
{
*type += 1;
if (need_comma)
string_append (decl, ",");
string_append (decl, "...");
}
string_append (decl, ")");
return 1;
}
static void
munge_function_name (name)
string *name;
{
if (!string_empty (name) && name->p - name->b >= 3
&& name->b[0] == 'o' && name->b[1] == 'p' && name->b[2] == '$')
{
int i;
/* see if it's an assignment expression */
if (name->p - name->b >= 10 /* op$assign_ */
&& memcmp (name->b + 3, "assign_", 7) == 0)
{
for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
{
int len = name->p - name->b - 10;
if (strlen (optable[i].in) == len
&& memcmp (optable[i].in, name->b + 10, len) == 0)
{
string_clear (name);
string_append (name, "operator");
string_append (name, optable[i].out);
string_append (name, "=");
return;
}
}
}
else
{
for (i = 0; i < sizeof (optable)/sizeof (optable[0]); i++)
{
int len = name->p - name->b - 3;
if (strlen (optable[i].in) == len
&& memcmp (optable[i].in, name->b + 3, len) == 0)
{
string_clear (name);
string_append (name, "operator");
string_append (name, optable[i].out);
return;
}
}
}
return;
}
else if (!string_empty (name) && name->p - name->b >= 5
&& memcmp (name->b, "type$", 5) == 0)
{
/* type conversion operator */
string type;
const char *tem = name->b + 5;
if (do_type (&tem, &type))
{
string_clear (name);
string_append (name, "operator ");
string_appends (name, &type);
string_delete (&type);
return;
}
}
}
/* a mini string-handling package */
static void
string_need (s, n)
string *s;
int n;
{
if (s->b == NULL)
{
if (n < 32)
n = 32;
s->p = s->b = (char *) xmalloc (n);
s->e = s->b + n;
}
else if (s->e - s->p < n)
{
int tem = s->p - s->b;
n += tem;
n *= 2;
s->b = (char *) xrealloc (s->b, n);
s->p = s->b + tem;
s->e = s->b + n;
}
}
static void
string_delete (s)
string *s;
{
if (s->b != NULL)
{
free (s->b);
s->b = s->e = s->p = NULL;
}
}
static void
string_init (s)
string *s;
{
s->b = s->p = s->e = NULL;
}
static void
string_clear (s)
string *s;
{
s->p = s->b;
}
static int
string_empty (s)
string *s;
{
return s->b == s->p;
}
static void
string_append (p, s)
string *p;
const char *s;
{
int n;
if (s == NULL || *s == '\0')
return;
n = strlen (s);
string_need (p, n);
memcpy (p->p, s, n);
p->p += n;
}
static void
string_appends (p, s)
string *p, *s;
{
int n;
if (s->b == s->p)
return;
n = s->p - s->b;
string_need (p, n);
memcpy (p->p, s->b, n);
p->p += n;
}
static void
string_appendn (p, s, n)
string *p;
const char *s;
int n;
{
if (n == 0)
return;
string_need (p, n);
memcpy (p->p, s, n);
p->p += n;
}
static void
string_prepend (p, s)
string *p;
const char *s;
{
if (s == NULL || *s == '\0')
return;
string_prependn (p, s, strlen (s));
}
#if 0
static void
string_prepends (p, s)
string *p, *s;
{
if (s->b == s->p)
return;
string_prependn (p, s->b, s->p - s->b);
}
#endif
static void
string_prependn (p, s, n)
string *p;
const char *s;
int n;
{
char *q;
if (n == 0)
return;
string_need (p, n);
for (q = p->p - 1; q >= p->b; q--)
q[n] = q[0];
memcpy (p->b, s, n);
p->p += n;
}

4718
usr.bin/ld/ld.c Normal file

File diff suppressed because it is too large Load Diff

358
usr.bin/ld/symseg.h Normal file
View File

@ -0,0 +1,358 @@
/*-
*
* This code is derived from software copyrighted by the Free Software
* Foundation.
*
* @(#)symseg.h 8.1 (Berkeley) 6/6/93
*/
/* GDB symbol table format definitions.
Copyright (C) 1987, 1988 Free Software Foundation, Inc.
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU CC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Format of GDB symbol table data.
There is one symbol segment for each source file or
independant compilation. These segments are simply concatenated
to form the GDB symbol table. A zero word where the beginning
of a segment is expected indicates there are no more segments.
Format of a symbol segment:
The symbol segment begins with a word containing 1
if it is in the format described here. Other formats may
be designed, with other code numbers.
The segment contains many objects which point at each other.
The pointers are offsets in bytes from the beginning of the segment.
Thus, each segment can be loaded into core and its pointers relocated
to make valid in-core pointers.
All the data objects in the segment can be found indirectly from
one of them, the root object, of type `struct symbol_root'.
It appears at the beginning of the segment.
The total size of the segment, in bytes, appears as the `length'
field of this object. This size includes the size of the
root object.
All the object data types are defined here to contain pointer types
appropriate for in-core use on a relocated symbol segment.
Casts to and from type int are required for working with
unrelocated symbol segments such as are found in the file.
The ldsymaddr word is filled in by the loader to contain
the offset (in bytes) within the ld symbol table
of the first nonglobal symbol from this compilation.
This makes it possible to match those symbols
(which contain line number information) reliably with
the segment they go with.
Core addresses within the program that appear in the symbol segment
are not relocated by the loader. They are inserted by the assembler
and apply to addresses as output by the assembler, so GDB must
relocate them when it loads the symbol segment. It gets the information
on how to relocate from the textrel, datarel, bssrel, databeg and bssbeg
words of the root object.
The words textrel, datarel and bssrel
are filled in by ld with the amounts to relocate within-the-file
text, data and bss addresses by; databeg and bssbeg can be
used to tell which kind of relocation an address needs. */
enum language {language_c};
struct symbol_root
{
int format; /* Data format version */
int length; /* # bytes in this symbol segment */
int ldsymoff; /* Offset in ld symtab of this file's syms */
int textrel; /* Relocation for text addresses */
int datarel; /* Relocation for data addresses */
int bssrel; /* Relocation for bss addresses */
char *filename; /* Name of main source file compiled */
char *filedir; /* Name of directory it was reached from */
struct blockvector *blockvector; /* Vector of all symbol-naming blocks */
struct typevector *typevector; /* Vector of all data types */
enum language language; /* Code identifying the language used */
char *version; /* Version info. Not fully specified */
char *compilation; /* Compilation info. Not fully specified */
int databeg; /* Address within the file of data start */
int bssbeg; /* Address within the file of bss start */
struct sourcevector *sourcevector; /* Vector of line-number info */
};
/* All data types of symbols in the compiled program
are represented by `struct type' objects.
All of these objects are pointed to by the typevector.
The type vector may have empty slots that contain zero. */
struct typevector
{
int length; /* Number of types described */
struct type *type[1];
};
/* Different kinds of data types are distinguished by the `code' field. */
enum type_code
{
TYPE_CODE_UNDEF, /* Not used; catches errors */
TYPE_CODE_PTR, /* Pointer type */
TYPE_CODE_ARRAY, /* Array type, lower bound zero */
TYPE_CODE_STRUCT, /* C struct or Pascal record */
TYPE_CODE_UNION, /* C union or Pascal variant part */
TYPE_CODE_ENUM, /* Enumeration type */
TYPE_CODE_FUNC, /* Function type */
TYPE_CODE_INT, /* Integer type */
TYPE_CODE_FLT, /* Floating type */
TYPE_CODE_VOID, /* Void type (values zero length) */
TYPE_CODE_SET, /* Pascal sets */
TYPE_CODE_RANGE, /* Range (integers within spec'd bounds) */
TYPE_CODE_PASCAL_ARRAY, /* Array with explicit type of index */
};
/* This appears in a type's flags word for an unsigned integer type. */
#define TYPE_FLAG_UNSIGNED 1
/* Other flag bits are used with GDB. */
struct type
{
/* Code for kind of type */
enum type_code code;
/* Name of this type, or zero if none.
This is used for printing only.
Type names specified as input are defined by symbols. */
char *name;
/* Length in bytes of storage for a value of this type */
int length;
/* For a pointer type, describes the type of object pointed to.
For an array type, describes the type of the elements.
For a function type, describes the type of the value.
Unused otherwise. */
struct type *target_type;
/* Type that is a pointer to this type.
Zero if no such pointer-to type is known yet.
The debugger may add the address of such a type
if it has to construct one later. */
struct type *pointer_type;
/* Type that is a function returning this type.
Zero if no such function type is known here.
The debugger may add the address of such a type
if it has to construct one later. */
struct type *function_type;
/* Flags about this type. */
short flags;
/* Number of fields described for this type */
short nfields;
/* For structure and union types, a description of each field.
For set and pascal array types, there is one "field",
whose type is the domain type of the set or array.
For range types, there are two "fields",
the minimum and maximum values (both inclusive).
For enum types, each possible value is described by one "field".
For range types, there are two "fields", that record constant values
(inclusive) for the minimum and maximum.
Using a pointer to a separate array of fields
allows all types to have the same size, which is useful
because we can allocate the space for a type before
we know what to put in it. */
struct field
{
/* Position of this field, counting in bits from start of
containing structure. For a function type, this is the
position in the argument list of this argument.
For a range bound or enum value, this is the value itself. */
int bitpos;
/* Size of this field, in bits, or zero if not packed.
For an unpacked field, the field's type's length
says how many bytes the field occupies. */
int bitsize;
/* In a struct or enum type, type of this field.
In a function type, type of this argument.
In an array type, the domain-type of the array. */
struct type *type;
/* Name of field, value or argument.
Zero for range bounds and array domains. */
char *name;
} *fields;
};
/* All of the name-scope contours of the program
are represented by `struct block' objects.
All of these objects are pointed to by the blockvector.
Each block represents one name scope.
Each lexical context has its own block.
The first two blocks in the blockvector are special.
The first one contains all the symbols defined in this compilation
whose scope is the entire program linked together.
The second one contains all the symbols whose scope is the
entire compilation excluding other separate compilations.
In C, these correspond to global symbols and static symbols.
Each block records a range of core addresses for the code that
is in the scope of the block. The first two special blocks
give, for the range of code, the entire range of code produced
by the compilation that the symbol segment belongs to.
The blocks appear in the blockvector
in order of increasing starting-address,
and, within that, in order of decreasing ending-address.
This implies that within the body of one function
the blocks appear in the order of a depth-first tree walk. */
struct blockvector
{
/* Number of blocks in the list. */
int nblocks;
/* The blocks themselves. */
struct block *block[1];
};
struct block
{
/* Addresses in the executable code that are in this block.
Note: in an unrelocated symbol segment in a file,
these are always zero. They can be filled in from the
N_LBRAC and N_RBRAC symbols in the loader symbol table. */
int startaddr, endaddr;
/* The symbol that names this block,
if the block is the body of a function;
otherwise, zero.
Note: In an unrelocated symbol segment in an object file,
this field may be zero even when the block has a name.
That is because the block is output before the name
(since the name resides in a higher block).
Since the symbol does point to the block (as its value),
it is possible to find the block and set its name properly. */
struct symbol *function;
/* The `struct block' for the containing block, or 0 if none. */
/* Note that in an unrelocated symbol segment in an object file
this pointer may be zero when the correct value should be
the second special block (for symbols whose scope is one compilation).
This is because the compiler ouptuts the special blocks at the
very end, after the other blocks. */
struct block *superblock;
/* Number of local symbols. */
int nsyms;
/* The symbols. */
struct symbol *sym[1];
};
/* Represent one symbol name; a variable, constant, function or typedef. */
/* Different name spaces for symbols. Looking up a symbol specifies
a namespace and ignores symbol definitions in other name spaces.
VAR_NAMESPACE is the usual namespace.
In C, this contains variables, function names, typedef names
and enum type values.
STRUCT_NAMESPACE is used in C to hold struct, union and enum type names.
Thus, if `struct foo' is used in a C program,
it produces a symbol named `foo' in the STRUCT_NAMESPACE.
LABEL_NAMESPACE may be used for names of labels (for gotos);
currently it is not used and labels are not recorded at all. */
/* For a non-global symbol allocated statically,
the correct core address cannot be determined by the compiler.
The compiler puts an index number into the symbol's value field.
This index number can be matched with the "desc" field of
an entry in the loader symbol table. */
enum namespace
{
UNDEF_NAMESPACE, VAR_NAMESPACE, STRUCT_NAMESPACE, LABEL_NAMESPACE,
};
/* An address-class says where to find the value of the symbol in core. */
enum address_class
{
LOC_UNDEF, /* Not used; catches errors */
LOC_CONST, /* Value is constant int */
LOC_STATIC, /* Value is at fixed address */
LOC_REGISTER, /* Value is in register */
LOC_ARG, /* Value is at spec'd position in arglist */
LOC_LOCAL, /* Value is at spec'd pos in stack frame */
LOC_TYPEDEF, /* Value not used; definition in SYMBOL_TYPE
Symbols in the namespace STRUCT_NAMESPACE
all have this class. */
LOC_LABEL, /* Value is address in the code */
LOC_BLOCK, /* Value is address of a `struct block'.
Function names have this class. */
LOC_EXTERNAL, /* Value is at address not in this compilation.
This is used for .comm symbols
and for extern symbols within functions.
Inside GDB, this is changed to LOC_STATIC once the
real address is obtained from a loader symbol. */
LOC_CONST_BYTES /* Value is a constant byte-sequence. */
};
struct symbol
{
/* Symbol name */
char *name;
/* Name space code. */
enum namespace namespace;
/* Address class */
enum address_class class;
/* Data type of value */
struct type *type;
/* constant value, or address if static, or register number,
or offset in arguments, or offset in stack frame. */
union
{
long value;
struct block *block; /* for LOC_BLOCK */
char *bytes; /* for LOC_CONST_BYTES */
}
value;
};
/* Source-file information.
This describes the relation between source files and line numbers
and addresses in the program text. */
struct sourcevector
{
int length; /* Number of source files described */
struct source *source[1]; /* Descriptions of the files */
};
/* Line number and address of one line. */
struct line
{
int linenum;
int address;
};
/* All the information on one source file. */
struct source
{
char *name; /* Name of file */
int nlines; /* Number of lines that follow */
struct line lines[1]; /* Information on each line */
};

475
usr.bin/m4/serv.c Normal file
View File

@ -0,0 +1,475 @@
/*
* Copyright (c) 1989
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* This code is derived from software contributed to Berkeley by
* Ozan Yigit.
*
* 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[] = "@(#)serv.c 5.4 (Berkeley) 1/21/94";
#endif /* not lint */
/*
* serv.c
* Facility: m4 macro processor
* by: oz
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mdef.h"
#include "extr.h"
#include "pathnames.h"
extern ndptr lookup();
extern ndptr addent();
char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef */
/*
* expand - user-defined macro expansion
*
*/
expand(argv, argc)
register char *argv[];
register int argc;
{
register char *t;
register char *p;
register int n;
register int argno;
t = argv[0]; /* defn string as a whole */
p = t;
while (*p)
p++;
p--; /* last character of defn */
while (p > t) {
if (*(p-1) != ARGFLAG)
putback(*p);
else {
switch (*p) {
case '#':
pbnum(argc-2);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if ((argno = *p - '0') < argc-1)
pbstr(argv[argno+1]);
break;
case '*':
for (n = argc - 1; n > 2; n--) {
pbstr(argv[n]);
putback(',');
}
pbstr(argv[2]);
break;
default :
putback(*p);
break;
}
p--;
}
p--;
}
if (p == t) /* do last character */
putback(*p);
}
/*
* dodefine - install definition in the table
*
*/
dodefine(name, defn)
register char *name;
register char *defn;
{
register ndptr p;
if (!*name)
error("m4: null definition.");
if (strcmp(name, defn) == 0)
error("m4: recursive definition.");
if ((p = lookup(name)) == nil)
p = addent(name);
else if (p->defn != null)
free(p->defn);
if (!*defn)
p->defn = null;
else
p->defn = strdup(defn);
p->type = MACRTYPE;
}
/*
* dodefn - push back a quoted definition of
* the given name.
*/
dodefn(name)
char *name;
{
register ndptr p;
if ((p = lookup(name)) != nil && p->defn != null) {
putback(rquote);
pbstr(p->defn);
putback(lquote);
}
}
/*
* dopushdef - install a definition in the hash table
* without removing a previous definition. Since
* each new entry is entered in *front* of the
* hash bucket, it hides a previous definition from
* lookup.
*/
dopushdef(name, defn)
register char *name;
register char *defn;
{
register ndptr p;
if (!*name)
error("m4: null definition");
if (strcmp(name, defn) == 0)
error("m4: recursive definition.");
p = addent(name);
if (!*defn)
p->defn = null;
else
p->defn = strdup(defn);
p->type = MACRTYPE;
}
/*
* dodumpdef - dump the specified definitions in the hash
* table to stderr. If nothing is specified, the entire
* hash table is dumped.
*
*/
dodump(argv, argc)
register char *argv[];
register int argc;
{
register int n;
ndptr p;
if (argc > 2) {
for (n = 2; n < argc; n++)
if ((p = lookup(argv[n])) != nil)
fprintf(stderr, dumpfmt, p->name,
p->defn);
}
else {
for (n = 0; n < HASHSIZE; n++)
for (p = hashtab[n]; p != nil; p = p->nxtptr)
fprintf(stderr, dumpfmt, p->name,
p->defn);
}
}
/*
* doifelse - select one of two alternatives - loop.
*
*/
doifelse(argv,argc)
register char *argv[];
register int argc;
{
cycle {
if (strcmp(argv[2], argv[3]) == 0)
pbstr(argv[4]);
else if (argc == 6)
pbstr(argv[5]);
else if (argc > 6) {
argv += 3;
argc -= 3;
continue;
}
break;
}
}
/*
* doinclude - include a given file.
*
*/
doincl(ifile)
char *ifile;
{
if (ilevel+1 == MAXINP)
error("m4: too many include files.");
if ((infile[ilevel+1] = fopen(ifile, "r")) != NULL) {
ilevel++;
return (1);
}
else
return (0);
}
#ifdef EXTENDED
/*
* dopaste - include a given file without any
* macro processing.
*/
dopaste(pfile)
char *pfile;
{
FILE *pf;
register int c;
if ((pf = fopen(pfile, "r")) != NULL) {
while((c = getc(pf)) != EOF)
putc(c, active);
(void) fclose(pf);
return(1);
}
else
return(0);
}
#endif
/*
* dochq - change quote characters
*
*/
dochq(argv, argc)
register char *argv[];
register int argc;
{
if (argc > 2) {
if (*argv[2])
lquote = *argv[2];
if (argc > 3) {
if (*argv[3])
rquote = *argv[3];
}
else
rquote = lquote;
}
else {
lquote = LQUOTE;
rquote = RQUOTE;
}
}
/*
* dochc - change comment characters
*
*/
dochc(argv, argc)
register char *argv[];
register int argc;
{
if (argc > 2) {
if (*argv[2])
scommt = *argv[2];
if (argc > 3) {
if (*argv[3])
ecommt = *argv[3];
}
else
ecommt = ECOMMT;
}
else {
scommt = SCOMMT;
ecommt = ECOMMT;
}
}
/*
* dodivert - divert the output to a temporary file
*
*/
dodiv(n)
register int n;
{
if (n < 0 || n >= MAXOUT)
n = 0; /* bitbucket */
if (outfile[n] == NULL) {
m4temp[UNIQUE] = n + '0';
if ((outfile[n] = fopen(m4temp, "w")) == NULL)
error("m4: cannot divert.");
}
oindex = n;
active = outfile[n];
}
/*
* doundivert - undivert a specified output, or all
* other outputs, in numerical order.
*/
doundiv(argv, argc)
register char *argv[];
register int argc;
{
register int ind;
register int n;
if (argc > 2) {
for (ind = 2; ind < argc; ind++) {
n = atoi(argv[ind]);
if (n > 0 && n < MAXOUT && outfile[n] != NULL)
getdiv(n);
}
}
else
for (n = 1; n < MAXOUT; n++)
if (outfile[n] != NULL)
getdiv(n);
}
/*
* dosub - select substring
*
*/
dosub (argv, argc)
register char *argv[];
register int argc;
{
register char *ap, *fc, *k;
register int nc;
if (argc < 5)
nc = MAXTOK;
else
#ifdef EXPR
nc = expr(argv[4]);
#else
nc = atoi(argv[4]);
#endif
ap = argv[2]; /* target string */
#ifdef EXPR
fc = ap + expr(argv[3]); /* first char */
#else
fc = ap + atoi(argv[3]); /* first char */
#endif
if (fc >= ap && fc < ap+strlen(ap))
for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
putback(*k);
}
/*
* map:
* map every character of s1 that is specified in from
* into s3 and replace in s. (source s1 remains untouched)
*
* This is a standard implementation of map(s,from,to) function of ICON
* language. Within mapvec, we replace every character of "from" with
* the corresponding character in "to". If "to" is shorter than "from",
* than the corresponding entries are null, which means that those
* characters dissapear altogether. Furthermore, imagine
* map(dest, "sourcestring", "srtin", "rn..*") type call. In this case,
* `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s'
* ultimately maps to `*'. In order to achieve this effect in an efficient
* manner (i.e. without multiple passes over the destination string), we
* loop over mapvec, starting with the initial source character. if the
* character value (dch) in this location is different than the source
* character (sch), sch becomes dch, once again to index into mapvec, until
* the character value stabilizes (i.e. sch = dch, in other words
* mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary
* character, it will stabilize, since mapvec[0] == 0 at all times. At the
* end, we restore mapvec* back to normal where mapvec[n] == n for
* 0 <= n <= 127. This strategy, along with the restoration of mapvec, is
* about 5 times faster than any algorithm that makes multiple passes over
* destination string.
*
*/
map(dest,src,from,to)
register char *dest;
register char *src;
register char *from;
register char *to;
{
register char *tmp;
register char sch, dch;
static char mapvec[128] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107,
108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127
};
if (*src) {
tmp = from;
/*
* create a mapping between "from" and "to"
*/
while (*from)
mapvec[*from++] = (*to) ? *to++ : (char) 0;
while (*src) {
sch = *src++;
dch = mapvec[sch];
while (dch != sch) {
sch = dch;
dch = mapvec[sch];
}
if (*dest = dch)
dest++;
}
/*
* restore all the changed characters
*/
while (*tmp) {
mapvec[*tmp] = *tmp;
tmp++;
}
}
*dest = (char) 0;
}

8
usr.bin/man/Makefile Normal file
View File

@ -0,0 +1,8 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= man
SRCS= config.c man.c
MAN1= man.0
MAN5= man.conf.0
.include <bsd.prog.mk>

176
usr.bin/man/config.c Normal file
View File

@ -0,0 +1,176 @@
/*
* Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)config.c 8.8 (Berkeley) 1/31/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "pathnames.h"
struct _head head;
/*
* config --
*
* Read the configuration file and build a doubly linked
* list that looks like:
*
* tag1 <-> record <-> record <-> record
* |
* tag2 <-> record <-> record <-> record
*/
void
config(fname)
char *fname;
{
TAG *tp;
ENTRY *ep;
FILE *cfp;
size_t len;
int lcnt;
char *p, *t;
if (fname == NULL)
fname = _PATH_MANCONF;
if ((cfp = fopen(fname, "r")) == NULL)
err(1, "%s", fname);
TAILQ_INIT(&head);
for (lcnt = 1; (p = fgetln(cfp, &len)) != NULL; ++lcnt) {
if (len == 1) /* Skip empty lines. */
continue;
if (p[len - 1] != '\n') { /* Skip corrupted lines. */
warnx("%s: line %d corrupted", fname, lcnt);
continue;
}
p[len - 1] = '\0'; /* Terminate the line. */
/* Skip leading space. */
for (; *p != '\0' && isspace(*p); ++p);
/* Skip empty/comment lines. */
if (*p == '\0' || *p == '#')
continue;
/* Find first token. */
for (t = p; *t && !isspace(*t); ++t);
if (*t == '\0') /* Need more than one token.*/
continue;
*t = '\0';
for (tp = head.tqh_first; /* Find any matching tag. */
tp != NULL && strcmp(p, tp->s); tp = tp->q.tqe_next);
if (tp == NULL) /* Create a new tag. */
tp = addlist(p);
/*
* Attach new records. The keyword _build takes the rest of
* the line as a single entity, everything else is white
* space separated. The reason we're not just using strtok(3)
* for all of the parsing is so we don't get caught if a line
* has only a single token on it.
*/
if (!strcmp(p, "_build")) {
while (*++t && isspace(*t));
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(t)) == NULL)
err(1, NULL);
TAILQ_INSERT_TAIL(&tp->list, ep, q);
} else for (++t; (p = strtok(t, " \t\n")) != NULL; t = NULL) {
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(p)) == NULL)
err(1, NULL);
TAILQ_INSERT_TAIL(&tp->list, ep, q);
}
}
fclose(cfp);
}
/*
* addlist --
* Add a tag to the list.
*/
TAG *
addlist(name)
char *name;
{
TAG *tp;
if ((tp = calloc(1, sizeof(TAG))) == NULL ||
(tp->s = strdup(name)) == NULL)
err(1, NULL);
TAILQ_INIT(&tp->list);
TAILQ_INSERT_TAIL(&head, tp, q);
return (tp);
}
/*
* getlist --
* Return the linked list of entries for a tag if it exists.
*/
TAG *
getlist(name)
char *name;
{
TAG *tp;
for (tp = head.tqh_first; tp != NULL; tp = tp->q.tqe_next)
if (!strcmp(name, tp->s))
return (tp);
return (NULL);
}
void
debug(l)
char *l;
{
TAG *tp;
ENTRY *ep;
(void)printf("%s ===============\n", l);
for (tp = head.tqh_first; tp != NULL; tp = tp->q.tqe_next) {
printf("%s\n", tp->s);
for (ep = tp->list.tqh_first; ep != NULL; ep = ep->q.tqe_next)
printf("\t%s\n", ep->s);
}
}

57
usr.bin/man/config.h Normal file
View File

@ -0,0 +1,57 @@
/*-
* 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.
*
* @(#)config.h 8.4 (Berkeley) 12/18/93
*/
typedef struct _tag {
TAILQ_ENTRY(_tag) q; /* Queue of tags. */
TAILQ_HEAD(tqh, _entry) list; /* Queue of entries. */
char *s; /* Associated string. */
size_t len; /* Length of 's'. */
} TAG;
typedef struct _entry {
TAILQ_ENTRY(_entry) q; /* Queue of entries. */
char *s; /* Associated string. */
size_t len; /* Length of 's'. */
} ENTRY;
TAILQ_HEAD(_head, _tag);
extern struct _head head;
TAG *addlist __P((char *));
void config __P((char *));
void debug __P((char *));
TAG *getlist __P((char *));

188
usr.bin/man/man.1 Normal file
View File

@ -0,0 +1,188 @@
.\" Copyright (c) 1989, 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.
.\"
.\" @(#)man.1 8.2 (Berkeley) 1/2/94
.\"
.Dd January 2, 1994
.Dt MAN 1
.Os BSD 4
.Sh NAME
.Nm man
.Nd display the on-line manual pages
.Sh SYNOPSIS
.Nm man
.Op Fl achw
.Op Fl C Ar file
.Op Fl M Ar path
.Op Fl m Ar path
.Op Ar section
.Ar name Ar ...
.Sh DESCRIPTION
The
.Nm man
utility
displays the
.Bx
manual pages entitled
.Ar name .
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl a
Display all of the manual pages for a specified
.Ar section
and
.Ar name
combination.
(Normally, only the first manual page found is displayed.)
.It Fl C
Use the specified
.Ar file
instead of the default configuration file.
This permits users to configure their own manual environment.
See
.Xr man.conf 5
for a description of the contents of this file.
.It Fl c
Copy the manual page to the standard output instead of using
.Xr more 1
to paginate it.
This is done by default if the standard output is not a terminal device.
.It Fl h
Display only the
.Dq Tn SYNOPSIS
lines of the requested manual pages.
.It Fl M
Override the list of standard directories which
.Nm man
searches for manual pages.
The supplied
.Ar path
must be a colon (``:'') separated list of directories.
This search path may also be set using the environment variable
.Ev MANPATH .
The subdirectories to be searched, and their search order,
is specified by the ``_subdir'' line in the
.Nm man
configuration file.
.It Fl m
Augment the list of standard directories which
.Nm man
searches for manual pages.
The supplied
.Ar path
must be a colon (``:'') separated list of directories.
These directories will be searched before the standard directories or
the directories specified using the
.Fl M
option or the
.Ev MANPATH
environment variable.
The subdirectories to be searched, and their search order,
is specified by the ``_subdir'' line in the
.Nm man
configuration file.
.It Fl w
List the pathnames of the manual pages which
.Nm man
would display for the specified
.Ar section
and
.Ar name
combination.
.El
.Pp
The optional
.Ar section
argument restricts the directories that
.Nm man
will search.
The
.Nm man
configuration file (see
.Xr man.conf 5 )
specifies the possible
.Ar section
values that are currently available.
If only a single argument is specified or if the first argument is
not a valid section,
.Nm man
assumes that the argument is the name of a manual page to be displayed.
.Sh ENVIRONMENT
.Bl -tag -width MANPATHX
.It Ev MACHINE
As some manual pages are intended only for specific architectures,
.Nm man
searches any subdirectories,
with the same name as the current architecture,
in every directory which it searches.
Machine specific areas are checked before general areas.
The current machine type may be overridden by setting the environment
variable
.Ev MACHINE
to the name of a specific architecture.
.It Ev MANPATH
The standard search path used by
.Nm man
may be overridden by specifying a path in the
.Ev MANPATH
environment
variable.
The format of the path is a colon (``:'') separated list of directories.
The subdirectories to be searched as well as their search order
is specified by the ``_subdir'' line in the
.Nm man
configuration file.
.It Ev PAGER
Any value of the environment variable
.Ev PAGER
will be used instead of the standard pagination program,
.Xr more 1 .
.El
.Sh FILES
.Bl -tag -width /etc/man.conf -compact
.It Pa /etc/man.conf
default man configuration file.
.El
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr whatis 1 ,
.Xr whereis 1 ,
.Xr man.conf 5
.Sh BUGS
The on-line manual pages are, by necessity, forgiving toward stupid
display devices, causing a few manual pages to not as nicely formatted
as their typeset counterparts.
.Sh HISTORY
A
.Nm
command appeared in
.At v6 .

712
usr.bin/man/man.c Normal file
View File

@ -0,0 +1,712 @@
/*
* Copyright (c) 1987, 1993, 1994, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1987, 1993, 1994, 1995\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)man.c 8.17 (Berkeley) 1/31/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <glob.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "config.h"
#include "pathnames.h"
int f_all, f_where;
static void build_page __P((char *, char **));
static void cat __P((char *));
static char *check_pager __P((char *));
static int cleanup __P((void));
static void how __P((char *));
static void jump __P((char **, char *, char *));
static int manual __P((char *, TAG *, glob_t *));
static void onsig __P((int));
static void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
TAG *defp, *defnewp, *section, *sectnewp, *subp;
ENTRY *e_defp, *e_sectp, *e_subp, *ep;
glob_t pg;
size_t len;
int ch, f_cat, f_how, found;
char **ap, *cmd, *machine, *p, *p_add, *p_path, *pager, *slashp;
char *conffile, buf[MAXPATHLEN * 2];
f_cat = f_how = 0;
conffile = p_add = p_path = NULL;
while ((ch = getopt(argc, argv, "-aC:cfhkM:m:P:w")) != EOF)
switch (ch) {
case 'a':
f_all = 1;
break;
case 'C':
conffile = optarg;
break;
case 'c':
case '-': /* Deprecated. */
f_cat = 1;
break;
case 'h':
f_how = 1;
break;
case 'm':
p_add = optarg;
break;
case 'M':
case 'P': /* Backward compatibility. */
p_path = optarg;
break;
/*
* The -f and -k options are backward compatible,
* undocumented ways of calling whatis(1) and apropos(1).
*/
case 'f':
jump(argv, "-f", "whatis");
/* NOTREACHED */
case 'k':
jump(argv, "-k", "apropos");
/* NOTREACHED */
case 'w':
f_all = f_where = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (!*argv)
usage();
if (!f_cat && !f_how && !f_where)
if (!isatty(1))
f_cat = 1;
else if ((pager = getenv("PAGER")) != NULL)
pager = check_pager(pager);
else
pager = _PATH_PAGER;
/* Read the configuration file. */
config(conffile);
/* Get the machine type. */
if ((machine = getenv("MACHINE")) == NULL)
machine = MACHINE;
/* If there's no _default list, create an empty one. */
if ((defp = getlist("_default")) == NULL)
defp = addlist("_default");
/*
* 1: If the user specified a MANPATH variable, or set the -M
* option, we replace the _default list with the user's list,
* appending the entries in the _subdir list and the machine.
*/
if (p_path == NULL)
p_path = getenv("MANPATH");
if (p_path != NULL) {
while ((e_defp = defp->list.tqh_first) != NULL) {
free(e_defp->s);
TAILQ_REMOVE(&defp->list, e_defp, q);
}
for (p = strtok(p_path, ":");
p != NULL; p = strtok(NULL, ":")) {
slashp = p[strlen(p) - 1] == '/' ? "" : "/";
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
p, slashp, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, NULL);
TAILQ_INSERT_TAIL(&defp->list, ep, q);
}
}
}
/*
* 2: If the user did not specify MANPATH, -M or a section, rewrite
* the _default list to include the _subdir list and the machine.
*/
if (argv[1] == NULL)
section = NULL;
else if ((section = getlist(*argv)) != NULL)
++argv;
if (p_path == NULL && section == NULL) {
defnewp = addlist("_default_new");
e_defp =
defp->list.tqh_first == NULL ? NULL : defp->list.tqh_first;
for (; e_defp != NULL; e_defp = e_defp->q.tqe_next) {
slashp =
e_defp->s[strlen(e_defp->s) - 1] == '/' ? "" : "/";
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
e_defp->s, slashp, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, NULL);
TAILQ_INSERT_TAIL(&defnewp->list, ep, q);
}
}
defp = getlist("_default");
while ((e_defp = defp->list.tqh_first) != NULL) {
free(e_defp->s);
TAILQ_REMOVE(&defp->list, e_defp, q);
}
free(defp->s);
TAILQ_REMOVE(&head, defp, q);
defnewp = getlist("_default_new");
free(defnewp->s);
defnewp->s = "_default";
defp = defnewp;
}
/*
* 3: If the user set the -m option, insert the user's list before
* whatever list we have, again appending the _subdir list and
* the machine.
*/
if (p_add != NULL)
for (p = strtok(p_add, ":"); p != NULL; p = strtok(NULL, ":")) {
slashp = p[strlen(p) - 1] == '/' ? "" : "/";
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s%s{/%s,}",
p, slashp, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, NULL);
TAILQ_INSERT_HEAD(&defp->list, ep, q);
}
}
/*
* 4: If none of MANPATH, -M, or -m were specified, and a section was,
* rewrite the section's paths (if they have a trailing slash) to
* append the _subdir list and the machine. This then becomes the
* _default list.
*/
if (p_path == NULL && p_add == NULL && section != NULL) {
sectnewp = addlist("_section_new");
for (e_sectp = section->list.tqh_first;
e_sectp != NULL; e_sectp = e_sectp->q.tqe_next) {
if (e_sectp->s[strlen(e_sectp->s) - 1] != '/') {
(void)snprintf(buf, sizeof(buf),
"%s{/%s,}", e_sectp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, NULL);
TAILQ_INSERT_TAIL(&sectnewp->list, ep, q);
continue;
}
e_subp = (subp = getlist("_subdir")) == NULL ?
NULL : subp->list.tqh_first;
for (; e_subp != NULL; e_subp = e_subp->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s%s{/%s,}",
e_sectp->s, e_subp->s, machine);
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(buf)) == NULL)
err(1, NULL);
TAILQ_INSERT_TAIL(&sectnewp->list, ep, q);
}
}
sectnewp->s = section->s;
defp = sectnewp;
TAILQ_REMOVE(&head, section, q);
}
/*
* 5: Search for the files. Set up an interrupt handler, so the
* temporary files go away.
*/
(void)signal(SIGINT, onsig);
(void)signal(SIGHUP, onsig);
memset(&pg, 0, sizeof(pg));
for (found = 0; *argv; ++argv)
if (manual(*argv, defp, &pg))
found = 1;
/* 6: If nothing found, we're done. */
if (!found) {
(void)cleanup();
exit (1);
}
/* 7: If it's simple, display it fast. */
if (f_cat) {
for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0')
continue;
cat(*ap);
}
exit (cleanup());
}
if (f_how) {
for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0')
continue;
how(*ap);
}
exit(cleanup());
}
if (f_where) {
for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0')
continue;
(void)printf("%s\n", *ap);
}
exit(cleanup());
}
/*
* 8: We display things in a single command; build a list of things
* to display.
*/
for (ap = pg.gl_pathv, len = strlen(pager) + 1; *ap != NULL; ++ap) {
if (**ap == '\0')
continue;
len += strlen(*ap) + 1;
}
if ((cmd = malloc(len)) == NULL) {
warn(NULL);
(void)cleanup();
exit(1);
}
p = cmd;
len = strlen(pager);
memmove(p, pager, len);
p += len;
*p++ = ' ';
for (ap = pg.gl_pathv; *ap != NULL; ++ap) {
if (**ap == '\0')
continue;
len = strlen(*ap);
memmove(p, *ap, len);
p += len;
*p++ = ' ';
}
*p = '\0';
/* Use system(3) in case someone's pager is "pager arg1 arg2". */
(void)system(cmd);
exit(cleanup());
}
/*
* manual --
* Search the manuals for the pages.
*/
static int
manual(page, tag, pg)
char *page;
TAG *tag;
glob_t *pg;
{
ENTRY *ep, *e_sufp, *e_tag;
TAG *missp, *sufp;
int anyfound, cnt, found;
char *p, buf[128];
anyfound = 0;
buf[0] = '*';
/* For each element in the list... */
e_tag = tag == NULL ? NULL : tag->list.tqh_first;
for (; e_tag != NULL; e_tag = e_tag->q.tqe_next) {
(void)snprintf(buf, sizeof(buf), "%s/%s.*", e_tag->s, page);
if (glob(buf,
GLOB_APPEND | GLOB_BRACE | GLOB_NOSORT | GLOB_QUOTE,
NULL, pg)) {
warn("globbing");
(void)cleanup();
exit(1);
}
if (pg->gl_matchc == 0)
continue;
/* Find out if it's really a man page. */
for (cnt = pg->gl_pathc - pg->gl_matchc;
cnt < pg->gl_pathc; ++cnt) {
/*
* Try the _suffix key words first.
*
* XXX
* Older versions of man.conf didn't have the suffix
* key words, it was assumed that everything was a .0.
* We just test for .0 first, it's fast and probably
* going to hit.
*/
(void)snprintf(buf, sizeof(buf), "*/%s.0", page);
if (!fnmatch(buf, pg->gl_pathv[cnt], 0))
goto next;
e_sufp = (sufp = getlist("_suffix")) == NULL ?
NULL : sufp->list.tqh_first;
for (found = 0;
e_sufp != NULL; e_sufp = e_sufp->q.tqe_next) {
(void)snprintf(buf,
sizeof(buf), "*/%s%s", page, e_sufp->s);
if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
found = 1;
break;
}
}
if (found)
goto next;
/* Try the _build key words next. */
e_sufp = (sufp = getlist("_build")) == NULL ?
NULL : sufp->list.tqh_first;
for (found = 0;
e_sufp != NULL; e_sufp = e_sufp->q.tqe_next) {
for (p = e_sufp->s;
*p != '\0' && !isspace(*p); ++p);
if (*p == '\0')
continue;
*p = '\0';
(void)snprintf(buf,
sizeof(buf), "*/%s%s", page, e_sufp->s);
if (!fnmatch(buf, pg->gl_pathv[cnt], 0)) {
if (!f_where)
build_page(p + 1,
&pg->gl_pathv[cnt]);
*p = ' ';
found = 1;
break;
}
*p = ' ';
}
if (found) {
next: anyfound = 1;
if (!f_all) {
/* Delete any other matches. */
while (++cnt< pg->gl_pathc)
pg->gl_pathv[cnt] = "";
break;
}
continue;
}
/* It's not a man page, forget about it. */
pg->gl_pathv[cnt] = "";
}
if (anyfound && !f_all)
break;
}
/* If not found, enter onto the missing list. */
if (!anyfound) {
if ((missp = getlist("_missing")) == NULL)
missp = addlist("_missing");
if ((ep = malloc(sizeof(ENTRY))) == NULL ||
(ep->s = strdup(page)) == NULL) {
warn(NULL);
(void)cleanup();
exit(1);
}
TAILQ_INSERT_TAIL(&missp->list, ep, q);
}
return (anyfound);
}
/*
* build_page --
* Build a man page for display.
*/
static void
build_page(fmt, pathp)
char *fmt, **pathp;
{
static int warned;
ENTRY *ep;
TAG *intmpp;
int fd;
char buf[MAXPATHLEN], cmd[MAXPATHLEN], tpath[sizeof(_PATH_TMP)];
/* Let the user know this may take awhile. */
if (!warned) {
warned = 1;
warnx("Formatting manual page...");
}
/* Add a remove-when-done list. */
if ((intmpp = getlist("_intmp")) == NULL)
intmpp = addlist("_intmp");
/* Move to the printf(3) format string. */
for (; *fmt && isspace(*fmt); ++fmt);
/*
* Get a temporary file and build a version of the file
* to display. Replace the old file name with the new one.
*/
(void)strcpy(tpath, _PATH_TMP);
if ((fd = mkstemp(tpath)) == -1) {
warn("%s", tpath);
(void)cleanup();
exit(1);
}
(void)snprintf(buf, sizeof(buf), "%s > %s", fmt, tpath);
(void)snprintf(cmd, sizeof(cmd), buf, *pathp);
(void)system(cmd);
(void)close(fd);
if ((*pathp = strdup(tpath)) == NULL) {
warn(NULL);
(void)cleanup();
exit(1);
}
/* Link the built file into the remove-when-done list. */
if ((ep = malloc(sizeof(ENTRY))) == NULL) {
warn(NULL);
(void)cleanup();
exit(1);
}
ep->s = *pathp;
TAILQ_INSERT_TAIL(&intmpp->list, ep, q);
}
/*
* how --
* display how information
*/
static void
how(fname)
char *fname;
{
FILE *fp;
int lcnt, print;
char *p, buf[256];
if (!(fp = fopen(fname, "r"))) {
warn("%s", fname);
(void)cleanup();
exit (1);
}
#define S1 "SYNOPSIS"
#define S2 "S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS"
#define D1 "DESCRIPTION"
#define D2 "D\bDE\bES\bSC\bCR\bRI\bIP\bPT\bTI\bIO\bON\bN"
for (lcnt = print = 0; fgets(buf, sizeof(buf), fp);) {
if (!strncmp(buf, S1, sizeof(S1) - 1) ||
!strncmp(buf, S2, sizeof(S2) - 1)) {
print = 1;
continue;
} else if (!strncmp(buf, D1, sizeof(D1) - 1) ||
!strncmp(buf, D2, sizeof(D2) - 1))
return;
if (!print)
continue;
if (*buf == '\n')
++lcnt;
else {
for(; lcnt; --lcnt)
(void)putchar('\n');
for (p = buf; isspace(*p); ++p);
(void)fputs(p, stdout);
}
}
(void)fclose(fp);
}
/*
* cat --
* cat out the file
*/
static void
cat(fname)
char *fname;
{
int fd, n;
char buf[2048];
if ((fd = open(fname, O_RDONLY, 0)) < 0) {
warn("%s", fname);
(void)cleanup();
exit(1);
}
while ((n = read(fd, buf, sizeof(buf))) > 0)
if (write(STDOUT_FILENO, buf, n) != n) {
warn("write");
(void)cleanup();
exit (1);
}
if (n == -1) {
warn("read");
(void)cleanup();
exit(1);
}
(void)close(fd);
}
/*
* check_pager --
* check the user supplied page information
*/
static char *
check_pager(name)
char *name;
{
char *p, *save;
/*
* if the user uses "more", we make it "more -s"; watch out for
* PAGER = "mypager /usr/ucb/more"
*/
for (p = name; *p && !isspace(*p); ++p);
for (; p > name && *p != '/'; --p);
if (p != name)
++p;
/* make sure it's "more", not "morex" */
if (!strncmp(p, "more", 4) && (!p[4] || isspace(p[4]))){
save = name;
/* allocate space to add the "-s" */
if (!(name =
malloc((u_int)(strlen(save) + sizeof("-s") + 1))))
err(1, NULL);
(void)sprintf(name, "%s %s", save, "-s");
}
return(name);
}
/*
* jump --
* strip out flag argument and jump
*/
static void
jump(argv, flag, name)
char **argv, *flag, *name;
{
char **arg;
argv[0] = name;
for (arg = argv + 1; *arg; ++arg)
if (!strcmp(*arg, flag))
break;
for (; *arg; ++arg)
arg[0] = arg[1];
execvp(name, argv);
(void)fprintf(stderr, "%s: Command not found.\n", name);
exit(1);
}
/*
* onsig --
* If signaled, delete the temporary files.
*/
static void
onsig(signo)
int signo;
{
(void)cleanup();
(void)signal(signo, SIG_DFL);
(void)kill(getpid(), signo);
/* NOTREACHED */
exit (1);
}
/*
* cleanup --
* Clean up temporary files, show any error messages.
*/
static int
cleanup()
{
TAG *intmpp, *missp;
ENTRY *ep;
int rval;
rval = 0;
ep = (missp = getlist("_missing")) == NULL ?
NULL : missp->list.tqh_first;
if (ep != NULL)
for (; ep != NULL; ep = ep->q.tqe_next) {
warnx("no entry for %s in the manual.", ep->s);
rval = 1;
}
ep = (intmpp = getlist("_intmp")) == NULL ?
NULL : intmpp->list.tqh_first;
for (; ep != NULL; ep = ep->q.tqe_next)
(void)unlink(ep->s);
return (rval);
}
/*
* usage --
* print usage message and die
*/
static void
usage()
{
(void)fprintf(stderr,
"usage: man [-achw] [-C file] [-M path] [-m path] [section] title ...\n");
exit(1);
}

46
usr.bin/man/man.conf Normal file
View File

@ -0,0 +1,46 @@
# Sheer, raging paranoia...
_version BSD.2
# The whatis/apropos database.
_whatdb /usr/share/man/whatis.db
# Subdirectories for paths ending in '/', IN SEARCH ORDER.
_subdir cat{1,8,6,2,3,4,5,7,3f}
# Files typed by suffix and their commands.
# Note the order, .Z must come after .[1-9].Z, or it will match first.
_suffix .0
_build .[1-9] /usr/bin/nroff -man %s
_build .[1-9].Z /usr/bin/zcat %s | /usr/bin/nroff -man
_build .Z /usr/bin/zcat %s
_build .0.Z /usr/bin/zcat %s
_build .gz /usr/contrib/bin/gunzip %s
_build .z /usr/contrib/bin/gunzip %s
_build .nr /usr/bin/nroff -man %s
# Sections and their directories.
# All paths ending in '/' are the equivalent of entries specifying that
# directory with all of the subdirectories listed for the keyword _subdir.
# default
_default /usr/{share,X11,contrib,local}/{man,man/old}/
# Other sections that represent complete man subdirectories.
X11 /usr/X11R4/man/
X11R4 /usr/X11R4/man/
contrib /usr/contrib/man/
local /usr/local/man/
new /usr/contrib/man/
old /usr/share/man/old/
# Specific section/directory combinations.
1 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat1
2 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat2
3 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat3
3F /usr/share/man/cat3f
3f /usr/share/man/cat3f
4 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat4
5 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat5
6 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat6
7 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat7
8 /usr/{share,X11R4,contrib,local}/{man/,man/old/}cat8

195
usr.bin/man/man.conf.5 Normal file
View File

@ -0,0 +1,195 @@
.\" Copyright (c) 1989, 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.
.\"
.\" @(#)man.conf.5 8.5 (Berkeley) 1/2/94
.\"
.Dd January 2, 1994
.Dt MAN.CONF 5
.Os
.Sh NAME
.Nm man.conf
.Nd configuration file for
.Xr man 1
.Sh DESCRIPTION
The
.Xr man 1 ,
.Xr apropos 1 ,
and
.Xr whatis 1
commands
search for manual pages or their database files as specified by the
.Nm man.conf
file.
Manual pages are normally expected to be preformatted (see
.Xr nroff 1 )
and named with a trailing ``.0''.
.Pp
The
.Nm man.conf
file contains two types of lines.
.Pp
The first type of line is a ``section'' line, which contains a
section name followed by one or more directory paths.
The directory paths may contain the normal shell globbing characters,
including curly braces (``{}''); to escape a shell globbing character,
precede it with a backslash (``\e'').
Lines in this format specify that manual pages for the section
may be found in the following directories.
.Pp
Directories named with a trailing slash character (``/'') are expected
to contain subdirectories of manual pages, (see the keyword ``_subdir''
below) instead of manual pages.
These subdirectories are searched instead of the directory.
.Pp
Before searching any directory for a manual page, the
.Xr man 1
command always searches the subdirectory with the same name
as the current machine type, if it exists.
No specification of these subdirectories is necessary in the
.Nm man.conf
file.
.Pp
Section names are unrestricted except for the reserved words specified
below; in general, you should avoid anything with a leading underscore
(``_'') to avoid future incompatibilities.
.Pp
The section named ``_default'' is the list of directories that will
be searched if no section is specified by the user.
.Pp
The second type of line is preceded with a ``keyword''.
The possible keywords and their meanings are as follows:
.Pp
.Bl -tag -width "_version"
.It _build
Man file names, regardless of their format, are expected to end in
a ``.*'' pattern, i.e. a ``.'' followed by some suffix.
The first field of a _build line lists a suffix which indicates
files which need to be reformated or manipulated in some way before
being displayed to the user.
The suffix may contain the normal shell globbing characters (NOT
including curly braces (``{}'')).
The rest of the line must be a shell command line, the standard
output of which is the manual page in a format which may be directly
displayed to the user.
Any occurrences of the string ``%s'' in the shell command line will
be replaced by the name of the file which is being reformatted.
.It _subdir
The list (in search order) of subdirectories which will be searched in
any directory named with a trailing slash (``/'') character.
This list is also used when a path is specified to the
.Xr man 1
utility by the user, using the
.Ev MANPATH
environment variable or the
.Fl M
and
.Fl m
options.
.It _suffix
Man file names, regardless of their format are expected to end in
a ``.*'' pattern, i.e. a ``.'' followed by some suffix.
Each field of a _suffix line is a suffix which indicates
files which do not need to be reformatted or manipulated
in any way, but which may be directly displayed to the user.
Each suffix may contain the normal shell globbing characters (NOT
including curly braces (``{}'')).
.It _version
The version of the configuration file.
.It _whatdb
The full pathname (not just a directory path) for a database to be used
by the
.Xr apropos 1
and
.Xr whatis 1
commands.
.El
.Pp
Multiple specifications for all types of lines are cumulative and the
entries are used in the order listed in the file; multiple entries may
be listed per line, as well.
.Pp
Empty lines or lines whose first non-whitespace character is a hash
mark (``#'') are ignored.
.Sh EXAMPLES
Given the following
.Nm man.conf
file:
.Bd -literal -offset indent
_version BSD.2
_subdir cat[123]
_suffix .0
_build .[1-9] nroff -man %s
_build .tbl tbl %s | nroff -man
_default /usr/share/man/
sect3 /usr/share/man/{old/,}cat3
.Ed
.Pp
By default, the command
.Dq Li man mktemp
will search for
``mktemp.<any_digit>'' and ``mktemp.tbl''
in the directories
.Dq Pa /usr/share/man/cat1 ,
.Dq Pa /usr/share/man/cat2 ,
and
.Dq Pa /usr/share/man/cat3 .
If on a machine of type ``vax'', the subdirectory ``vax'' in each
directory would be searched as well, before the directory was
searched.
.Pp
If ``mktemp.tbl'' was found first, the command
.Dq Li tbl <manual page> | nroff -man
would be run to build a man page for display to the user.
.Pp
The command
.Dq Li man sect3 mktemp
would search the directories
.Dq Pa /usr/share/man/old/cat3
and
.Dq Pa /usr/share/man/cat3 ,
in that order, for
the mktemp manual page.
If a subdirectory with the same name as the current machine type
existed in any of them, it would be searched as well, before each
of them were searched.
.Sh FILES
.Bl -tag -width /etc/man.conf -compact
.It Pa /etc/man.conf
Standard manual directory search path.
.El
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr machine 1 ,
.Xr man 1 ,
.Xr whatis 1 ,
.Xr whereis 1 ,
.Xr fnmatch 3 ,
.Xr glob 3

39
usr.bin/man/pathnames.h Normal file
View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 1989, 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.
*
* @(#)pathnames.h 8.3 (Berkeley) 1/2/94
*/
#define _PATH_MANCONF "/etc/man.conf"
#define _PATH_PAGER "/usr/bin/more -s"
#define _PATH_TMP "/tmp/man.XXXXXX"
#define _PATH_WHATIS "whatis.db"

158
usr.bin/mklocale/Japanese Normal file
View File

@ -0,0 +1,158 @@
# @(#)Japanese 8.1 (Berkeley) 6/6/93
/*
* Japanese LOCALE_CTYPE definitions using EUC of JIS character sets
*/
ENCODING "EUC"
/* JIS JIS JIS */
/* X201 X208 X201 */
/* 00-7f 84-fe */
VARIABLE 1 0x0000 2 0x8080 2 0x0080 3 0x8000 0x8080
/*
* Code Set 1
*/
ALPHA 'A' - 'Z' 'a' - 'z'
CONTROL 0x00 - 0x1f 0x7f
DIGIT '0' - '9'
GRAPH 0x21 - 0x7e
LOWER 'a' - 'z'
PUNCT 0x21 - 0x2f 0x3a - 0x40 0x5b - 0x60 0x7b - 0x7e
SPACE 0x09 - 0x0d 0x20
UPPER 'A' - 'Z'
XDIGIT 'a' - 'f' 'A' - 'F'
BLANK ' ' '\t'
PRINT 0x20 - 0x7e
MAPLOWER < 'A' - 'Z' : 'a' >
MAPLOWER < 'a' - 'z' : 'a' >
MAPUPPER < 'A' - 'Z' : 'A' >
MAPUPPER < 'a' - 'z' : 'A' >
TODIGIT < '0' - '9' : 0 >
TODIGIT < 'A' - 'F' : 10 >
TODIGIT < 'a' - 'f' : 10 >
/*
* Code Set 2
*/
SPACE 0xa1a1
PHONOGRAM 0xa1bc
SPECIAL 0xa1a2 - 0xa1fe
PUNCT 0xa1a2 - 0xa1f8 /* A few too many in here... */
SPECIAL 0xa2a1 - 0xa2ae 0xa2ba - 0xa2c1 0xa2ca - 0xa2d0 0xa2dc - 0xa2ea
SPECIAL 0xa2f2 - 0xa2f9 0xa2fe
DIGIT 0xa3b0 - 0xa3b9
UPPER 0xa3c1 - 0xa3da /* Romaji */
LOWER 0xa3e1 - 0xa3fa /* Romaji */
MAPLOWER < 0xa3c1 - 0xa3da : 0xa3e1 > /* English */
MAPLOWER < 0xa3e1 - 0xa3fa : 0xa3e1 > /* English */
MAPUPPER < 0xa3c1 - 0xa3da : 0xa3c1 >
MAPUPPER < 0xa3e1 - 0xa3fa : 0xa3c1 >
XDIGIT 0xa3c1 - 0xa3c6 0xa3e1 - 0xa3e6
TODIGIT < 0xa3b0 - 0xa3b9 : 0 >
TODIGIT < 0xa3c1 - 0xa3c6 : 10 >
TODIGIT < 0xa3e1 - 0xa3e6 : 10 >
PHONOGRAM 0xa4a1 - 0xa4f3
PHONOGRAM 0xa5a1 - 0xa5f6
UPPER 0xa6a1 - 0xa6b8 /* Greek */
LOWER 0xa6c1 - 0xa6d8 /* Greek */
MAPLOWER < 0xa6a1 - 0xa6b8 : 0xa6c1 >
MAPLOWER < 0xa6c1 - 0xa6d8 : 0xa6c1 >
MAPUPPER < 0xa6a1 - 0xa6b8 : 0xa6a1 >
MAPUPPER < 0xa6c1 - 0xa6d8 : 0xa6a1 >
UPPER 0xa7a1 - 0xa7c1 /* Cyrillic */
LOWER 0xa7d1 - 0xa7f1 /* Cyrillic */
MAPLOWER < 0xa7a1 - 0xa7c1 : 0xa7d1 >
MAPLOWER < 0xa7d1 - 0xa7f1 : 0xa7d1 >
MAPUPPER < 0xa7a1 - 0xa7c1 : 0xa7a1 >
MAPUPPER < 0xa7d1 - 0xa7f1 : 0xa7a1 >
SPECIAL 0xa8a1 - 0xa8c0
IDEOGRAM 0xb0a1 - 0xb0fe
IDEOGRAM 0xb1a1 - 0xb1fe
IDEOGRAM 0xb2a1 - 0xb2fe
IDEOGRAM 0xb3a1 - 0xb3fe
IDEOGRAM 0xb4a1 - 0xb4fe
IDEOGRAM 0xb5a1 - 0xb5fe
IDEOGRAM 0xb6a1 - 0xb6fe
IDEOGRAM 0xb7a1 - 0xb7fe
IDEOGRAM 0xb8a1 - 0xb8fe
IDEOGRAM 0xb9a1 - 0xb9fe
IDEOGRAM 0xbaa1 - 0xbafe
IDEOGRAM 0xbba1 - 0xbbfe
IDEOGRAM 0xbca1 - 0xbcfe
IDEOGRAM 0xbda1 - 0xbdfe
IDEOGRAM 0xbea1 - 0xbefe
IDEOGRAM 0xbfa1 - 0xbffe
IDEOGRAM 0xc0a1 - 0xc0fe
IDEOGRAM 0xc1a1 - 0xc1fe
IDEOGRAM 0xc2a1 - 0xc2fe
IDEOGRAM 0xc3a1 - 0xc3fe
IDEOGRAM 0xc4a1 - 0xc4fe
IDEOGRAM 0xc5a1 - 0xc5fe
IDEOGRAM 0xc6a1 - 0xc6fe
IDEOGRAM 0xc7a1 - 0xc7fe
IDEOGRAM 0xc8a1 - 0xc8fe
IDEOGRAM 0xc9a1 - 0xc9fe
IDEOGRAM 0xcaa1 - 0xcafe
IDEOGRAM 0xcba1 - 0xcbfe
IDEOGRAM 0xcca1 - 0xccfe
IDEOGRAM 0xcda1 - 0xcdfe
IDEOGRAM 0xcea1 - 0xcefe
IDEOGRAM 0xcfa1 - 0xcfd3
IDEOGRAM 0xd0a1 - 0xd0fe
IDEOGRAM 0xd1a1 - 0xd1fe
IDEOGRAM 0xd2a1 - 0xd2fe
IDEOGRAM 0xd3a1 - 0xd3fe
IDEOGRAM 0xd4a1 - 0xd4fe
IDEOGRAM 0xd5a1 - 0xd5fe
IDEOGRAM 0xd6a1 - 0xd6fe
IDEOGRAM 0xd7a1 - 0xd7fe
IDEOGRAM 0xd8a1 - 0xd8fe
IDEOGRAM 0xd9a1 - 0xd9fe
IDEOGRAM 0xdaa1 - 0xdafe
IDEOGRAM 0xdba1 - 0xdbfe
IDEOGRAM 0xdca1 - 0xdcfe
IDEOGRAM 0xdda1 - 0xddfe
IDEOGRAM 0xdea1 - 0xdefe
IDEOGRAM 0xdfa1 - 0xdffe
IDEOGRAM 0xe0a1 - 0xe0fe
IDEOGRAM 0xe1a1 - 0xe1fe
IDEOGRAM 0xe2a1 - 0xe2fe
IDEOGRAM 0xe3a1 - 0xe3fe
IDEOGRAM 0xe4a1 - 0xe4fe
IDEOGRAM 0xe5a1 - 0xe5fe
IDEOGRAM 0xe6a1 - 0xe6fe
IDEOGRAM 0xe7a1 - 0xe7fe
IDEOGRAM 0xe8a1 - 0xe8fe
IDEOGRAM 0xe9a1 - 0xe9fe
IDEOGRAM 0xeaa1 - 0xeafe
IDEOGRAM 0xeba1 - 0xebfe
IDEOGRAM 0xeca1 - 0xecfe
IDEOGRAM 0xeda1 - 0xedfe
IDEOGRAM 0xeea1 - 0xeefe
IDEOGRAM 0xefa1 - 0xeffe
IDEOGRAM 0xf0a1 - 0xf0fe
IDEOGRAM 0xf1a1 - 0xf1fe
IDEOGRAM 0xf2a1 - 0xf2fe
IDEOGRAM 0xf3a1 - 0xf3fe
IDEOGRAM 0xf4a1 - 0xf4a4
/*
* This is for Code Set 3, half-width kana
*/
SPECIAL 0xa1 - 0xdf
PHONOGRAM 0xa1 - 0xdf
CONTROL 0x84 - 0x97 0x9b - 0x9f 0xe0 - 0xfe

View File

@ -0,0 +1,54 @@
/*-
* Copyright (c) 1989, 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.
*
* @(#)kpasswd_proto.h 8.1 (Berkeley) 6/6/93
*/
/*
* kpasswd_proto
*
* definitions for the kpasswd "protocol"
* (We hope this to be temporary until a real admin protocol is worked out.)
*/
struct kpasswd_data {
des_cblock random_key;
char secure_msg[_PASSWORD_LEN];
};
struct update_data {
char pw[_PASSWORD_LEN];
char secure_msg[_PASSWORD_LEN];
};
#define SERVICE "kpasswd"
#define SECURE_STRING \
"Kerberos password update program -- 12/9/88 UC Berkeley"

319
usr.bin/passwd/krb_passwd.c Normal file
View File

@ -0,0 +1,319 @@
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char sccsid[] = "@(#)krb_passwd.c 8.3 (Berkeley) 4/2/94";
#endif /* not lint */
#ifdef KERBEROS
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "kpasswd_proto.h"
#include "extern.h"
#define PROTO "tcp"
static void send_update __P((int, char *, char *));
static void recv_ack __P((int));
static void cleanup __P((void));
static void finish __P((void));
static struct timeval timeout = { CLIENT_KRB_TIMEOUT, 0 };
static struct kpasswd_data proto_data;
static des_cblock okey;
static Key_schedule osched;
static KTEXT_ST ticket;
static Key_schedule random_schedule;
static long authopts;
static char realm[REALM_SZ], krbhst[MAX_HSTNM];
static int sock;
int
krb_passwd()
{
struct servent *se;
struct hostent *host;
struct sockaddr_in sin;
CREDENTIALS cred;
fd_set readfds;
int rval;
char pass[_PASSWORD_LEN], password[_PASSWORD_LEN];
static void finish();
static struct rlimit rl = { 0, 0 };
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGTSTP, SIG_IGN);
if (setrlimit(RLIMIT_CORE, &rl) < 0) {
warn("setrlimit");
return (1);
}
if ((se = getservbyname(SERVICE, PROTO)) == NULL) {
warnx("couldn't find entry for service %s/%s",
SERVICE, PROTO);
return (1);
}
if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) {
warnx("couldn't get local Kerberos realm: %s",
krb_err_txt[rval]);
return (1);
}
if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) {
warnx("couldn't get Kerberos host: %s",
krb_err_txt[rval]);
return (1);
}
if ((host = gethostbyname(krbhst)) == NULL) {
warnx("couldn't get host entry for krb host %s",
krbhst);
return (1);
}
sin.sin_family = host->h_addrtype;
memmove((char *) &sin.sin_addr, host->h_addr, host->h_length);
sin.sin_port = se->s_port;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
warn("socket");
return (1);
}
if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
warn("connect");
(void)close(sock);
return (1);
}
rval = krb_sendauth(
authopts, /* NOT mutual */
sock,
&ticket, /* (filled in) */
SERVICE,
krbhst, /* instance (krbhst) */
realm, /* dest realm */
(u_long) getpid(), /* checksum */
NULL, /* msg data */
NULL, /* credentials */
NULL, /* schedule */
NULL, /* local addr */
NULL, /* foreign addr */
"KPWDV0.1"
);
if (rval != KSUCCESS) {
warnx("Kerberos sendauth error: %s", krb_err_txt[rval]);
return (1);
}
krb_get_cred("krbtgt", realm, realm, &cred);
(void)printf("Changing Kerberos password for %s.%s@%s.\n",
cred.pname, cred.pinst, realm);
if (des_read_pw_string(pass,
sizeof(pass)-1, "Old Kerberos password:", 0)) {
warnx("error reading old Kerberos password");
return (1);
}
(void)des_string_to_key(pass, okey);
(void)des_key_sched(okey, osched);
(void)des_set_key(okey, osched);
/* wait on the verification string */
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
rval =
select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
if(rval == 0) {
warnx("timed out (aborted)");
cleanup();
return (1);
}
warnx("select failed (aborted)");
cleanup();
return (1);
}
/* read verification string */
if (des_read(sock, &proto_data, sizeof(proto_data)) !=
sizeof(proto_data)) {
warnx("couldn't read verification string (aborted)");
cleanup();
return (1);
}
(void)signal(SIGHUP, finish);
(void)signal(SIGINT, finish);
if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) {
cleanup();
/* don't complain loud if user just hit return */
if (pass == NULL || (!*pass))
return (0);
(void)fprintf(stderr, "Sorry\n");
return (1);
}
(void)des_key_sched(proto_data.random_key, random_schedule);
(void)des_set_key(proto_data.random_key, random_schedule);
(void)memset(pass, 0, sizeof(pass));
if (des_read_pw_string(pass,
sizeof(pass)-1, "New Kerberos password:", 0)) {
warnx("error reading new Kerberos password (aborted)");
cleanup();
return (1);
}
if (des_read_pw_string(password,
sizeof(password)-1, "Retype new Kerberos password:", 0)) {
warnx("error reading new Kerberos password (aborted)");
cleanup();
return (1);
}
if (strcmp(password, pass) != 0) {
warnx("password mismatch (aborted)");
cleanup();
return (1);
}
if (strlen(pass) == 0)
(void)printf("using NULL password\n");
send_update(sock, password, SECURE_STRING);
/* wait for ACK */
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
rval =
select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
if(rval == 0) {
warnx("timed out reading ACK (aborted)");
cleanup();
exit(1);
}
warnx("select failed (aborted)");
cleanup();
exit(1);
}
recv_ack(sock);
cleanup();
return (0);
}
static void
send_update(dest, pwd, str)
int dest;
char *pwd, *str;
{
static struct update_data ud;
(void)strncpy(ud.secure_msg, str, _PASSWORD_LEN);
(void)strncpy(ud.pw, pwd, sizeof(ud.pw));
if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) {
warnx("couldn't write pw update (abort)");
memset((char *)&ud, 0, sizeof(ud));
cleanup();
exit(1);
}
}
static void
recv_ack(remote)
int remote;
{
int cc;
char buf[BUFSIZ];
cc = des_read(remote, buf, sizeof(buf));
if (cc <= 0) {
warnx("error reading acknowledgement (aborted)");
cleanup();
exit(1);
}
(void)printf("%s", buf);
}
static void
cleanup()
{
(void)memset((char *)&proto_data, 0, sizeof(proto_data));
(void)memset((char *)okey, 0, sizeof(okey));
(void)memset((char *)osched, 0, sizeof(osched));
(void)memset((char *)random_schedule, 0, sizeof(random_schedule));
}
static void
finish()
{
(void)close(sock);
exit(1);
}
#endif /* KERBEROS */

15
usr.bin/patch/EXTERN.h Normal file
View File

@ -0,0 +1,15 @@
/* $Header: EXTERN.h,v 2.0 86/09/17 15:35:37 lwall Exp $
*
* $Log: EXTERN.h,v $
* Revision 2.0 86/09/17 15:35:37 lwall
* Baseline for netwide release.
*
*/
#undef EXT
#define EXT extern
#undef INIT
#define INIT(x)
#undef DOINIT

15
usr.bin/patch/INTERN.h Normal file
View File

@ -0,0 +1,15 @@
/* $Header: INTERN.h,v 2.0 86/09/17 15:35:58 lwall Exp $
*
* $Log: INTERN.h,v $
* Revision 2.0 86/09/17 15:35:58 lwall
* Baseline for netwide release.
*
*/
#undef EXT
#define EXT
#undef INIT
#define INIT(x) = x
#define DOINIT

6
usr.bin/patch/Makefile Normal file
View File

@ -0,0 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= patch
SRCS= patch.c pch.c inp.c version.c util.c
.include <bsd.prog.mk>

79
usr.bin/patch/README Normal file
View File

@ -0,0 +1,79 @@
The Makefile and config.h files in this directory work with the current
BSD release. Don't run the Configure script, you'll get wrong results.
Keith Bostic 1/10/88
-----------------------------------------------------------------------------
Patch Kit, Version 2.0
Copyright (c) 1986, Larry Wall
You may copy the patch kit in whole or in part as long as you don't try to
make money off it, or pretend that you wrote it.
--------------------------------------------------------------------------
Please read all the directions below before you proceed any further, and
then follow them carefully. Failure to do so may void your warranty. :-)
After you have unpacked your kit, you should have all the files listed
in MANIFEST.
Installation
1) Run Configure. This will figure out various things about your system.
Some things Configure will figure out for itself, other things it will
ask you about. It will then proceed to make config.h, config.sh, and
Makefile.
You might possibly have to trim # comments from the front of Configure
if your sh doesn't handle them, but all other # comments will be taken
care of.
If you don't have sh, you'll have to rip the prototype of config.h out
of Configure and generate the defines by hand.
2) Glance through config.h to make sure system dependencies are correct.
Most of them should have been taken care of by running the Configure script.
If you have any additional changes to make to the C definitions, they
can be done in the Makefile, or in config.h. Bear in mind that they may
get undone next time you run Configure.
3) make
This will attempt to make patch in the current directory.
4) make install
This will put patch into a public directory (normally /usr/local/bin).
It will also try to put the man pages in a reasonable place. It will not
nroff the man page, however.
5) Read the manual entry before running patch.
6) IMPORTANT! Help save the world! Communicate any problems and
suggested patches to me, lwall@sdcrdcf.UUCP (Larry Wall), so we can
keep the world in sync. If you have a problem, there's someone else
out there who either has had or will have the same problem.
If possible, send in patches such that the patch program will apply them.
Context diffs are the best, then normal diffs. Don't send ed scripts--
I've probably changed my copy since the version you have.
Watch for patch patches in net.sources.bugs. Patches will generally be
in a form usable by the patch program. If you are just now bringing up
patch and aren't sure how many patches there are, write to me and I'll
send any you don't have. Your current patch level is shown in patchlevel.h.
NEW FEATURES IN THIS RELEASE
(Correct) support for 4.3bsd-style context diffs.
Files can be created from scratch.
You can specify a fuzz-factor for context matching.
You can force patch to ask no questions.
You can specify how much of the leading pathname to strip off filenames.
Uses a Configure script for greater portability.
You are now asked if you want to apply a reversed patch.
No limit (apart from memory) on the size of hunks.

138
usr.bin/patch/common.h Normal file
View File

@ -0,0 +1,138 @@
/* $Header: common.h,v 2.0 86/09/17 15:36:39 lwall Exp $
*
* $Log: common.h,v $
* Revision 2.0 86/09/17 15:36:39 lwall
* Baseline for netwide release.
*
*/
#define DEBUGGING
#include "config.h"
/* shut lint up about the following when return value ignored */
#define Signal (void)signal
#define Unlink (void)unlink
#define Lseek (void)lseek
#define Fseek (void)fseek
#define Fstat (void)fstat
#define Pclose (void)pclose
#define Close (void)close
#define Fclose (void)fclose
#define Fflush (void)fflush
#define Sprintf (void)sprintf
#define Mktemp (void)mktemp
#define Strcpy (void)strcpy
#define Strcat (void)strcat
#include <stdio.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <signal.h>
/* constants */
#define TRUE (1)
#define FALSE (0)
#define MAXHUNKSIZE 100000 /* is this enough lines? */
#define INITHUNKMAX 125 /* initial dynamic allocation size */
#define MAXLINELEN 1024
#define BUFFERSIZE 1024
#define ORIGEXT ".orig"
#define SCCSPREFIX "s."
#define GET "get -e %s"
#define RCSSUFFIX ",v"
#define CHECKOUT "co -l %s"
/* handy definitions */
#define Null(t) ((t)0)
#define Nullch Null(char *)
#define Nullfp Null(FILE *)
#define Nulline Null(LINENUM)
#define Ctl(ch) ((ch) & 037)
#define strNE(s1,s2) (strcmp(s1, s2))
#define strEQ(s1,s2) (!strcmp(s1, s2))
#define strnNE(s1,s2,l) (strncmp(s1, s2, l))
#define strnEQ(s1,s2,l) (!strncmp(s1, s2, l))
/* typedefs */
typedef char bool;
typedef long LINENUM; /* must be signed */
typedef unsigned MEM; /* what to feed malloc */
/* globals */
EXT int Argc; /* guess */
EXT char **Argv;
EXT int Argc_last; /* for restarting plan_b */
EXT char **Argv_last;
EXT struct stat filestat; /* file statistics area */
EXT int filemode INIT(0644);
EXT char buf[MAXLINELEN]; /* general purpose buffer */
EXT FILE *ofp INIT(Nullfp); /* output file pointer */
EXT FILE *rejfp INIT(Nullfp); /* reject file pointer */
EXT bool using_plan_a INIT(TRUE); /* try to keep everything in memory */
EXT bool out_of_mem INIT(FALSE); /* ran out of memory in plan a */
#define MAXFILEC 2
EXT int filec INIT(0); /* how many file arguments? */
EXT char *filearg[MAXFILEC];
EXT bool ok_to_create_file INIT(FALSE);
EXT char *bestguess INIT(Nullch); /* guess at correct filename */
EXT char *outname INIT(Nullch);
EXT char rejname[128];
EXT char *origext INIT(Nullch);
EXT char TMPOUTNAME[] INIT("/tmp/patchoXXXXXX");
EXT char TMPINNAME[] INIT("/tmp/patchiXXXXXX"); /* might want /usr/tmp here */
EXT char TMPREJNAME[] INIT("/tmp/patchrXXXXXX");
EXT char TMPPATNAME[] INIT("/tmp/patchpXXXXXX");
EXT bool toutkeep INIT(FALSE);
EXT bool trejkeep INIT(FALSE);
EXT LINENUM last_offset INIT(0);
#ifdef DEBUGGING
EXT int debug INIT(0);
#endif
EXT LINENUM maxfuzz INIT(2);
EXT bool force INIT(FALSE);
EXT bool verbose INIT(TRUE);
EXT bool reverse INIT(FALSE);
EXT bool noreverse INIT(FALSE);
EXT bool skip_rest_of_patch INIT(FALSE);
EXT int strippath INIT(957);
EXT bool canonicalize INIT(FALSE);
#define CONTEXT_DIFF 1
#define NORMAL_DIFF 2
#define ED_DIFF 3
#define NEW_CONTEXT_DIFF 4
EXT int diff_type INIT(0);
EXT bool do_defines INIT(FALSE); /* patch using ifdef, ifndef, etc. */
EXT char if_defined[128]; /* #ifdef xyzzy */
EXT char not_defined[128]; /* #ifndef xyzzy */
EXT char else_defined[] INIT("#else\n");/* #else */
EXT char end_defined[128]; /* #endif xyzzy */
EXT char *revision INIT(Nullch); /* prerequisite revision, if any */
char *malloc();
char *realloc();
char *strcpy();
char *strcat();
long atol();
char *mktemp();

16
usr.bin/patch/config.h Normal file
View File

@ -0,0 +1,16 @@
#define Reg1 register /**/
#define Reg2 register /**/
#define Reg3 register /**/
#define Reg4 register /**/
#define Reg5 register /**/
#define Reg6 register /**/
#define Reg7 register /**/
#define Reg8 register /**/
#define Reg9 register /**/
#define Reg10 register /**/
#define Reg11 /**/
#define Reg12 /**/
#define Reg13 /**/
#define Reg14 /**/
#define Reg15 /**/
#define Reg16 /**/

313
usr.bin/patch/inp.c Normal file
View File

@ -0,0 +1,313 @@
/* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $
*
* $Log: inp.c,v $
* Revision 2.0 86/09/17 15:37:02 lwall
* Baseline for netwide release.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "pch.h"
#include "INTERN.h"
#include "inp.h"
/* Input-file-with-indexable-lines abstract type */
static long i_size; /* size of the input file */
static char *i_womp; /* plan a buffer for entire file */
static char **i_ptr; /* pointers to lines in i_womp */
static int tifd = -1; /* plan b virtual string array */
static char *tibuf[2]; /* plan b buffers */
static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
static LINENUM lines_per_buf; /* how many lines per buffer */
static int tireclen; /* length of records in tmp file */
/* New patch--prepare to edit another file. */
void
re_input()
{
if (using_plan_a) {
i_size = 0;
#ifndef lint
if (i_ptr != Null(char**))
free((char *)i_ptr);
#endif
if (i_womp != Nullch)
free(i_womp);
i_womp = Nullch;
i_ptr = Null(char **);
}
else {
using_plan_a = TRUE; /* maybe the next one is smaller */
Close(tifd);
tifd = -1;
free(tibuf[0]);
free(tibuf[1]);
tibuf[0] = tibuf[1] = Nullch;
tiline[0] = tiline[1] = -1;
tireclen = 0;
}
}
/* Constuct the line index, somehow or other. */
void
scan_input(filename)
char *filename;
{
if (!plan_a(filename))
plan_b(filename);
if (verbose) {
say3("Patching file %s using Plan %s...\n", filename,
(using_plan_a ? "A" : "B") );
}
}
/* Try keeping everything in memory. */
bool
plan_a(filename)
char *filename;
{
int ifd;
Reg1 char *s;
Reg2 LINENUM iline;
if (ok_to_create_file && stat(filename, &filestat) < 0) {
if (verbose)
say2("(Creating file %s...)\n",filename);
makedirs(filename, TRUE);
close(creat(filename, 0666));
}
if (stat(filename, &filestat) < 0) {
Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
Sprintf(buf, CHECKOUT, filename);
if (verbose)
say2("Can't find %s--attempting to check it out from RCS.\n",
filename);
if (system(buf) || stat(filename, &filestat))
fatal2("Can't check out %s.\n", filename);
}
else {
Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
if (stat(buf, &filestat) >= 0 || stat(buf+5, &filestat) >= 0) {
Sprintf(buf, GET, filename);
if (verbose)
say2("Can't find %s--attempting to get it from SCCS.\n",
filename);
if (system(buf) || stat(filename, &filestat))
fatal2("Can't get %s.\n", filename);
}
else
fatal2("Can't find %s.\n", filename);
}
}
filemode = filestat.st_mode;
if ((filemode & S_IFMT) & ~S_IFREG)
fatal2("%s is not a normal file--can't patch.\n", filename);
i_size = filestat.st_size;
if (out_of_mem) {
set_hunkmax(); /* make sure dynamic arrays are allocated */
out_of_mem = FALSE;
return FALSE; /* force plan b because plan a bombed */
}
#ifdef lint
i_womp = Nullch;
#else
i_womp = malloc((MEM)(i_size+2)); /* lint says this may alloc less than */
/* i_size, but that's okay, I think. */
#endif
if (i_womp == Nullch)
return FALSE;
if ((ifd = open(filename, 0)) < 0)
fatal2("Can't open file %s\n", filename);
#ifndef lint
if (read(ifd, i_womp, (int)i_size) != i_size) {
Close(ifd); /* probably means i_size > 15 or 16 bits worth */
free(i_womp); /* at this point it doesn't matter if i_womp was */
return FALSE; /* undersized. */
}
#endif
Close(ifd);
if (i_size && i_womp[i_size-1] != '\n')
i_womp[i_size++] = '\n';
i_womp[i_size] = '\0';
/* count the lines in the buffer so we know how many pointers we need */
iline = 0;
for (s=i_womp; *s; s++) {
if (*s == '\n')
iline++;
}
#ifdef lint
i_ptr = Null(char**);
#else
i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
#endif
if (i_ptr == Null(char **)) { /* shucks, it was a near thing */
free((char *)i_womp);
return FALSE;
}
/* now scan the buffer and build pointer array */
iline = 1;
i_ptr[iline] = i_womp;
for (s=i_womp; *s; s++) {
if (*s == '\n')
i_ptr[++iline] = s+1; /* these are NOT null terminated */
}
input_lines = iline - 1;
/* now check for revision, if any */
if (revision != Nullch) {
if (!rev_in_string(i_womp)) {
if (force) {
if (verbose)
say2("\
Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else {
ask2("\
This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal1("Aborted.\n");
}
}
else if (verbose)
say2("Good. This file appears to be the %s version.\n",
revision);
}
return TRUE; /* plan a will work */
}
/* Keep (virtually) nothing in memory. */
void
plan_b(filename)
char *filename;
{
Reg3 FILE *ifp;
Reg1 int i = 0;
Reg2 int maxlen = 1;
Reg4 bool found_revision = (revision == Nullch);
using_plan_a = FALSE;
if ((ifp = fopen(filename, "r")) == Nullfp)
fatal2("Can't open file %s\n", filename);
if ((tifd = creat(TMPINNAME, 0666)) < 0)
fatal2("Can't open file %s\n", TMPINNAME);
while (fgets(buf, sizeof buf, ifp) != Nullch) {
if (revision != Nullch && !found_revision && rev_in_string(buf))
found_revision = TRUE;
if ((i = strlen(buf)) > maxlen)
maxlen = i; /* find longest line */
}
if (revision != Nullch) {
if (!found_revision) {
if (force) {
if (verbose)
say2("\
Warning: this file doesn't appear to be the %s version--patching anyway.\n",
revision);
}
else {
ask2("\
This file doesn't appear to be the %s version--patch anyway? [n] ",
revision);
if (*buf != 'y')
fatal1("Aborted.\n");
}
}
else if (verbose)
say2("Good. This file appears to be the %s version.\n",
revision);
}
Fseek(ifp, 0L, 0); /* rewind file */
lines_per_buf = BUFFERSIZE / maxlen;
tireclen = maxlen;
tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
if (tibuf[1] == Nullch)
fatal1("Can't seem to get enough memory.\n");
for (i=1; ; i++) {
if (! (i % lines_per_buf)) /* new block */
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
fatal1("patch: can't write temp file.\n");
if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
== Nullch) {
input_lines = i - 1;
if (i % lines_per_buf)
if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
fatal1("patch: can't write temp file.\n");
break;
}
}
Fclose(ifp);
Close(tifd);
if ((tifd = open(TMPINNAME, 0)) < 0) {
fatal2("Can't reopen file %s\n", TMPINNAME);
}
}
/* Fetch a line from the input file, \n terminated, not necessarily \0. */
char *
ifetch(line,whichbuf)
Reg1 LINENUM line;
int whichbuf; /* ignored when file in memory */
{
if (line < 1 || line > input_lines)
return "";
if (using_plan_a)
return i_ptr[line];
else {
LINENUM offline = line % lines_per_buf;
LINENUM baseline = line - offline;
if (tiline[0] == baseline)
whichbuf = 0;
else if (tiline[1] == baseline)
whichbuf = 1;
else {
tiline[whichbuf] = baseline;
#ifndef lint /* complains of long accuracy */
Lseek(tifd, (off_t)baseline / lines_per_buf * BUFFERSIZE, 0);
#endif
if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
fatal2("Error reading tmp file %s.\n", TMPINNAME);
}
return tibuf[whichbuf] + (tireclen*offline);
}
}
/* True if the string argument contains the revision number we want. */
bool
rev_in_string(string)
char *string;
{
Reg1 char *s;
Reg2 int patlen;
if (revision == Nullch)
return TRUE;
patlen = strlen(revision);
for (s = string; *s; s++) {
if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
isspace(s[patlen+1] )) {
return TRUE;
}
}
return FALSE;
}

18
usr.bin/patch/inp.h Normal file
View File

@ -0,0 +1,18 @@
/* $Header: inp.h,v 2.0 86/09/17 15:37:25 lwall Exp $
*
* $Log: inp.h,v $
* Revision 2.0 86/09/17 15:37:25 lwall
* Baseline for netwide release.
*
*/
EXT LINENUM input_lines INIT(0); /* how long is input file in lines */
EXT LINENUM last_frozen_line INIT(0); /* how many input lines have been */
/* irretractibly output */
bool rev_in_string();
void scan_input();
bool plan_a(); /* returns false if insufficient memory */
void plan_b();
char *ifetch();

446
usr.bin/patch/patch.1 Normal file
View File

@ -0,0 +1,446 @@
''' $Header: patch.man,v 2.0 86/09/17 15:39:09 lwall Exp $
'''
''' $Log: patch.man,v $
''' Revision 2.0 86/09/17 15:39:09 lwall
''' Baseline for netwide release.
'''
''' Revision 1.4 86/08/01 19:23:22 lwall
''' Documented -v, -p, -F.
''' Added notes to patch senders.
'''
''' Revision 1.3 85/03/26 15:11:06 lwall
''' Frozen.
'''
''' Revision 1.2.1.4 85/03/12 16:14:27 lwall
''' Documented -p.
'''
''' Revision 1.2.1.3 85/03/12 16:09:41 lwall
''' Documented -D.
'''
''' Revision 1.2.1.2 84/12/05 11:06:55 lwall
''' Added -l switch, and noted bistability bug.
'''
''' Revision 1.2.1.1 84/12/04 17:23:39 lwall
''' Branch for sdcrdcf changes.
'''
''' Revision 1.2 84/12/04 17:22:02 lwall
''' Baseline version.
'''
.de Sh
.br
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp
.if t .sp .5v
.if n .sp
..
'''
''' Set up \*(-- to give an unbreakable dash;
''' string Tr holds user defined translation string.
''' Bell System Logo is used as a dummy character.
'''
.ie n \{\
.tr \(bs-\*(Tr
.ds -- \(bs-
.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
.ds L" ""
.ds R" ""
.ds L' '
.ds R' '
'br\}
.el\{\
.ds -- \(em\|
.tr \*(Tr
.ds L" ``
.ds R" ''
.ds L' `
.ds R' '
'br\}
.TH PATCH 1 "June 30, 1993"
.SH NAME
patch \- a program for applying a diff file to an original
.SH SYNOPSIS
.B patch
[options] orig patchfile [+ [options] orig]
.sp
but usually just
.sp
.B patch
<patchfile
.SH DESCRIPTION
.I Patch
will take a patch file containing any of the three forms of difference
listing produced by the
.I diff
program and apply those differences to an original file, producing a patched
version.
By default, the patched version is put in place of the original, with
the original file backed up to the same name with the
extension \*(L".orig\*(R", or as specified by the
.B -b
switch.
You may also specify where you want the output to go with a
.B -o
switch.
If
.I patchfile
is omitted, or is a hyphen, the patch will be read from standard input.
.PP
Upon startup, patch will attempt to determine the type of the diff listing,
unless over-ruled by a
.BR -c ,
.BR -e ,
or
.B -n
switch.
Context diffs and normal diffs are applied by the
.I patch
program itself, while ed diffs are simply fed to the
.I ed
editor via a pipe.
.PP
.I Patch
will try to skip any leading garbage, apply the diff,
and then skip any trailing garbage.
Thus you could feed an article or message containing a
diff listing to
.IR patch ,
and it should work.
If the entire diff is indented by a consistent amount,
this will be taken into account.
.PP
With context diffs, and to a lesser extent with normal diffs,
.I patch
can detect when the line numbers mentioned in the patch are incorrect,
and will attempt to find the correct place to apply each hunk of the patch.
As a first guess, it takes the line number mentioned for the hunk, plus or
minus any offset used in applying the previous hunk.
If that is not the correct place,
.I patch
will scan both forwards and backwards for a set of lines matching the context
given in the hunk.
First
.I patch
looks for a place where all lines of the context match.
If no such place is found, and it's a context diff, and the maximum fuzz factor
is set to 1 or more, then another scan takes place ignoring the first and last
line of context.
If that fails, and the maximum fuzz factor is set to 2 or more,
the first two and last two lines of context are ignored,
and another scan is made.
(The default maximum fuzz factor is 2.)
If
.I patch
cannot find a place to install that hunk of the patch, it will put the
hunk out to a reject file, which normally is the name of the output file
plus \*(L".rej\*(R".
(Note that the rejected hunk will come out in context diff form whether the
input patch was a context diff or a normal diff.
If the input was a normal diff, many of the contexts will simply be null.)
The line numbers on the hunks in the reject file may be different than
in the patch file: they reflect the approximate location patch thinks the
failed hunks belong in the new file rather than the old one.
.PP
As each hunk is completed, you will be told whether the hunk succeeded or
failed, and which line (in the new file)
.I patch
thought the hunk should go on.
If this is different from the line number specified in the diff you will
be told the offset.
A single large offset MAY be an indication that a hunk was installed in the
wrong place.
You will also be told if a fuzz factor was used to make the match, in which
case you should also be slightly suspicious.
.PP
If no original file is specified on the command line,
.I patch
will try to figure out from the leading garbage what the name of the file
to edit is.
In the header of a context diff, the filename is found from lines beginning
with \*(L"***\*(R" or \*(L"---\*(R", with the shortest name of an existing
file winning.
Only context diffs have lines like that, but if there is an \*(L"Index:\*(R"
line in the leading garbage,
.I patch
will try to use the filename from that line.
The context diff header takes precedence over an Index line.
If no filename can be intuited from the leading garbage, you will be asked
for the name of the file to patch.
.PP
(If the original file cannot be found, but a suitable SCCS or RCS file is
handy,
.I patch
will attempt to get or check out the file.)
.PP
Additionally, if the leading garbage contains a \*(L"Prereq: \*(R" line,
.I patch
will take the first word from the prerequisites line (normally a version
number) and check the input file to see if that word can be found.
If not,
.I patch
will ask for confirmation before proceeding.
.PP
The upshot of all this is that you should be able to say, while in a news
interface, the following:
.Sp
| patch -d /usr/src/local/blurfl
.Sp
and patch a file in the blurfl directory directly from the article containing
the patch.
.PP
If the patch file contains more than one patch,
.I patch
will try to apply each of them as if they came from separate patch files.
This means, among other things, that it is assumed that the name of the file
to patch must be determined for each diff listing,
and that the garbage before each diff listing will
be examined for interesting things such as filenames and revision level, as
mentioned previously.
You can give switches (and another original file name) for the second and
subsequent patches by separating the corresponding argument lists
by a \*(L'+\*(R'.
(The argument list for a second or subsequent patch may not specify a new
patch file, however.)
.PP
.I Patch
recognizes the following switches:
.TP 5
.B \-b
causes the next argument to be interpreted as the backup extension, to be
used in place of \*(L".orig\*(R".
.TP 5
.B \-c
forces
.I patch
to interpret the patch file as a context diff.
.TP 5
.B \-d
causes
.I patch
to interpret the next argument as a directory, and cd to it before doing
anything else.
.TP 5
.B \-D
causes
.I patch
to use the "#ifdef...#endif" construct to mark changes.
The argument following will be used as the differentiating symbol.
Note that, unlike the C compiler, there must be a space between the
.B \-D
and the argument.
.TP 5
.B \-e
forces
.I patch
to interpret the patch file as an ed script.
.TP 5
.B \-f
forces
.I patch
to assume that the user knows exactly what he or she is doing, and to not
ask any questions.
It does not suppress commentary, however.
Use
.B \-s
for that.
.TP 5
.B \-F<number>
sets the maximum fuzz factor.
This switch only applied to context diffs, and causes
.I patch
to ignore up to that many lines in looking for places to install a hunk.
Note that a larger fuzz factor increases the odds of a faulty patch.
The default fuzz factor is 2, and it may not be set to more than
the number of lines of context in the context diff, ordinarily 3.
.TP 5
.B \-l
causes the pattern matching to be done loosely, in case the tabs and
spaces have been munged in your input file.
Any sequence of whitespace in the pattern line will match any sequence
in the input file.
Normal characters must still match exactly.
Each line of the context must still match a line in the input file.
.TP 5
.B \-n
forces
.I patch
to interpret the patch file as a normal diff.
.TP 5
.B \-N
causes
.I patch
to ignore patches that it thinks are reversed or already applied.
See also
.B \-R .
.TP 5
.B \-o
causes the next argument to be interpreted as the output file name.
.TP 5
.B \-p<number>
sets the pathname strip count,
which controls how pathnames found in the patch file are treated, in case
the you keep your files in a different directory than the person who sent
out the patch.
The strip count specifies how many backslashes are to be stripped from
the front of the pathname.
(Any intervening directory names also go away.)
For example, supposing the filename in the patch file was
.sp
/u/howard/src/blurfl/blurfl.c
.sp
setting
.B \-p
or
.B \-p0
gives the entire pathname unmodified,
.B \-p1
gives
.sp
u/howard/src/blurfl/blurfl.c
.sp
without the leading slash,
.B \-p4
gives
.sp
blurfl/blurfl.c
.sp
and not specifying
.B \-p
at all just gives you "blurfl.c".
Whatever you end up with is looked for either in the current directory,
or the directory specified by the
.B \-d
switch.
.TP 5
.B \-r
causes the next argument to be interpreted as the reject file name.
.TP 5
.B \-R
tells
.I patch
that this patch was created with the old and new files swapped.
(Yes, I'm afraid that does happen occasionally, human nature being what it
is.)
.I Patch
will attempt to swap each hunk around before applying it.
Rejects will come out in the swapped format.
The
.B \-R
switch will not work with ed diff scripts because there is too little
information to reconstruct the reverse operation.
.Sp
If the first hunk of a patch fails,
.I patch
will reverse the hunk to see if it can be applied that way.
If it can, you will be asked if you want to have the
.B \-R
switch set.
If it can't, the patch will continue to be applied normally.
(Note: this method cannot detect a reversed patch if it is a normal diff
and if the first command is an append (i.e. it should have been a delete)
since appends always succeed, due to the fact that a null context will match
anywhere.
Luckily, most patches add or change lines rather than delete them, so most
reversed normal diffs will begin with a delete, which will fail, triggering
the heuristic.)
.TP 5
.B \-s
makes
.I patch
do its work silently, unless an error occurs.
.TP 5
.B \-S
causes
.I patch
to ignore this patch from the patch file, but continue on looking
for the next patch in the file.
Thus
.sp
patch -S + -S + <patchfile
.sp
will ignore the first and second of three patches.
.TP 5
.B \-v
causes
.I patch
to print out it's revision header and patch level.
.TP 5
.B \-x<number>
sets internal debugging flags, and is of interest only to
.I patch
patchers.
.SH ENVIRONMENT
No environment variables are used by
.IR patch .
.SH FILES
/tmp/patch*
.SH SEE ALSO
diff(1)
.SH NOTES FOR PATCH SENDERS
There are several things you should bear in mind if you are going to
be sending out patches.
First, you can save people a lot of grief by keeping a patchlevel.h file
which is patched to increment the patch level as the first diff in the
patch file you send out.
If you put a Prereq: line in with the patch, it won't let them apply
patches out of order without some warning.
Second, make sure you've specified the filenames right, either in a
context diff header, or with an Index: line.
If you are patching something in a subdirectory, be sure to tell the patch
user to specify a
.B \-p
switch as needed.
Third, you can create a file by sending out a diff that compares a
null file to the file you want to create.
This will only work if the file you want to create doesn't exist already in
the target directory.
Fourth, take care not to send out reversed patches, since it makes people wonder
whether they already applied the patch.
Fifth, while you may be able to get away with putting 582 diff listings into
one file, it is probably wiser to group related patches into separate files in
case something goes haywire.
.SH DIAGNOSTICS
Too many to list here, but generally indicative that
.I patch
couldn't parse your patch file.
.PP
The message \*(L"Hmm...\*(R" indicates that there is unprocessed text in
the patch file and that
.I patch
is attempting to intuit whether there is a patch in that text and, if so,
what kind of patch it is.
.SH CAVEATS
.I Patch
cannot tell if the line numbers are off in an ed script, and can only detect
bad line numbers in a normal diff when it finds a \*(L"change\*(R" or
a \*(L"delete\*(R" command.
A context diff using fuzz factor 3 may have the same problem.
Until a suitable interactive interface is added, you should probably do
a context diff in these cases to see if the changes made sense.
Of course, compiling without errors is a pretty good indication that the patch
worked, but not always.
.PP
.I Patch
usually produces the correct results, even when it has to do a lot of
guessing.
However, the results are guaranteed to be correct only when the patch is
applied to exactly the same version of the file that the patch was
generated from.
.SH BUGS
Could be smarter about partial matches, excessively \&deviant offsets and
swapped code, but that would take an extra pass.
.PP
If code has been duplicated (for instance with #ifdef OLDCODE ... #else ...
#endif),
.I patch
is incapable of patching both versions, and, if it works at all, will likely
patch the wrong one, and tell you that it succeeded to boot.
.PP
If you apply a patch you've already applied,
.I patch
will think it is a reversed patch, and offer to un-apply the patch.
This could be construed as a feature.

800
usr.bin/patch/patch.c Normal file
View File

@ -0,0 +1,800 @@
#ifndef lint
static char sccsid[] = "@(#)patch.c 8.1 (Berkeley) 6/6/93";
#endif not lint
char rcsid[] =
"$Header: patch.c,v 2.0.1.4 87/02/16 14:00:04 lwall Exp $";
/* patch - a program to apply diffs to original files
*
* Copyright 1986, Larry Wall
*
* This program may be copied as long as you don't try to make any
* money off of it, or pretend that you wrote it.
*
* $Log: patch.c,v $
* Revision 2.0.1.4 87/02/16 14:00:04 lwall
* Short replacement caused spurious "Out of sync" message.
*
* Revision 2.0.1.3 87/01/30 22:45:50 lwall
* Improved diagnostic on sync error.
* Moved do_ed_script() to pch.c.
*
* Revision 2.0.1.2 86/11/21 09:39:15 lwall
* Fuzz factor caused offset of installed lines.
*
* Revision 2.0.1.1 86/10/29 13:10:22 lwall
* Backwards search could terminate prematurely.
*
* Revision 2.0 86/09/17 15:37:32 lwall
* Baseline for netwide release.
*
* Revision 1.5 86/08/01 20:53:24 lwall
* Changed some %d's to %ld's.
* Linted.
*
* Revision 1.4 86/08/01 19:17:29 lwall
* Fixes for machines that can't vararg.
* Added fuzz factor.
* Generalized -p.
* General cleanup.
*
* 85/08/15 van%ucbmonet@berkeley
* Changes for 4.3bsd diff -c.
*
* Revision 1.3 85/03/26 15:07:43 lwall
* Frozen.
*
* Revision 1.2.1.9 85/03/12 17:03:35 lwall
* Changed pfp->_file to fileno(pfp).
*
* Revision 1.2.1.8 85/03/12 16:30:43 lwall
* Check i_ptr and i_womp to make sure they aren't null before freeing.
* Also allow ed output to be suppressed.
*
* Revision 1.2.1.7 85/03/12 15:56:13 lwall
* Added -p option from jromine@uci-750a.
*
* Revision 1.2.1.6 85/03/12 12:12:51 lwall
* Now checks for normalness of file to patch.
*
* Revision 1.2.1.5 85/03/12 11:52:12 lwall
* Added -D (#ifdef) option from joe@fluke.
*
* Revision 1.2.1.4 84/12/06 11:14:15 lwall
* Made smarter about SCCS subdirectories.
*
* Revision 1.2.1.3 84/12/05 11:18:43 lwall
* Added -l switch to do loose string comparison.
*
* Revision 1.2.1.2 84/12/04 09:47:13 lwall
* Failed hunk count not reset on multiple patch file.
*
* Revision 1.2.1.1 84/12/04 09:42:37 lwall
* Branch for sdcrdcf changes.
*
* Revision 1.2 84/11/29 13:29:51 lwall
* Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed
* multiple calls to mktemp(). Will now work on machines that can only
* read 32767 chars. Added -R option for diffs with new and old swapped.
* Various cosmetic changes.
*
* Revision 1.1 84/11/09 17:03:58 lwall
* Initial revision
*
*/
#include "INTERN.h"
#include "common.h"
#include "EXTERN.h"
#include "version.h"
#include "util.h"
#include "pch.h"
#include "inp.h"
/* procedures */
void reinitialize_almost_everything();
void get_some_switches();
LINENUM locate_hunk();
void abort_hunk();
void apply_hunk();
void init_output();
void init_reject();
void copy_till();
void spew_output();
void dump_line();
bool patch_match();
bool similar();
void re_input();
void my_exit();
/* Apply a set of diffs as appropriate. */
main(argc,argv)
int argc;
char **argv;
{
LINENUM where;
LINENUM newwhere;
LINENUM fuzz;
LINENUM mymaxfuzz;
int hunk = 0;
int failed = 0;
int i;
setbuf(stderr, serrbuf);
for (i = 0; i<MAXFILEC; i++)
filearg[i] = Nullch;
Mktemp(TMPOUTNAME);
Mktemp(TMPINNAME);
Mktemp(TMPREJNAME);
Mktemp(TMPPATNAME);
/* parse switches */
Argc = argc;
Argv = argv;
get_some_switches();
/* make sure we clean up /tmp in case of disaster */
set_signals();
for (
open_patch_file(filearg[1]);
there_is_another_patch();
reinitialize_almost_everything()
) { /* for each patch in patch file */
if (outname == Nullch)
outname = savestr(filearg[0]);
/* initialize the patched file */
if (!skip_rest_of_patch)
init_output(TMPOUTNAME);
/* for ed script just up and do it and exit */
if (diff_type == ED_DIFF) {
do_ed_script();
continue;
}
/* initialize reject file */
init_reject(TMPREJNAME);
/* find out where all the lines are */
if (!skip_rest_of_patch)
scan_input(filearg[0]);
/* from here on, open no standard i/o files, because malloc */
/* might misfire and we can't catch it easily */
/* apply each hunk of patch */
hunk = 0;
failed = 0;
out_of_mem = FALSE;
while (another_hunk()) {
hunk++;
fuzz = Nulline;
mymaxfuzz = pch_context();
if (maxfuzz < mymaxfuzz)
mymaxfuzz = maxfuzz;
if (!skip_rest_of_patch) {
do {
where = locate_hunk(fuzz);
if (hunk == 1 && where == Nulline && !force) {
/* dwim for reversed patch? */
if (!pch_swap()) {
if (fuzz == Nulline)
say1("\
Not enough memory to try swapped hunk! Assuming unswapped.\n");
continue;
}
reverse = !reverse;
where = locate_hunk(fuzz); /* try again */
if (where == Nulline) { /* didn't find it swapped */
if (!pch_swap()) /* put it back to normal */
fatal1("Lost hunk on alloc error!\n");
reverse = !reverse;
}
else if (noreverse) {
if (!pch_swap()) /* put it back to normal */
fatal1("Lost hunk on alloc error!\n");
reverse = !reverse;
say1("\
Ignoring previously applied (or reversed) patch.\n");
skip_rest_of_patch = TRUE;
}
else {
ask3("\
%seversed (or previously applied) patch detected! %s -R? [y] ",
reverse ? "R" : "Unr",
reverse ? "Assume" : "Ignore");
if (*buf == 'n') {
ask1("Apply anyway? [n] ");
if (*buf != 'y')
skip_rest_of_patch = TRUE;
where = Nulline;
reverse = !reverse;
if (!pch_swap()) /* put it back to normal */
fatal1("Lost hunk on alloc error!\n");
}
}
}
} while (!skip_rest_of_patch && where == Nulline &&
++fuzz <= mymaxfuzz);
if (skip_rest_of_patch) { /* just got decided */
Fclose(ofp);
ofp = Nullfp;
}
}
newwhere = pch_newfirst() + last_offset;
if (skip_rest_of_patch) {
abort_hunk();
failed++;
if (verbose)
say3("Hunk #%d ignored at %ld.\n", hunk, newwhere);
}
else if (where == Nulline) {
abort_hunk();
failed++;
if (verbose)
say3("Hunk #%d failed at %ld.\n", hunk, newwhere);
}
else {
apply_hunk(where);
if (verbose) {
say3("Hunk #%d succeeded at %ld", hunk, newwhere);
if (fuzz)
say2(" with fuzz %ld", fuzz);
if (last_offset)
say3(" (offset %ld line%s)",
last_offset, last_offset==1L?"":"s");
say1(".\n");
}
}
}
if (out_of_mem && using_plan_a) {
Argc = Argc_last;
Argv = Argv_last;
say1("\n\nRan out of memory using Plan A--trying again...\n\n");
continue;
}
assert(hunk);
/* finish spewing out the new file */
if (!skip_rest_of_patch)
spew_output();
/* and put the output where desired */
ignore_signals();
if (!skip_rest_of_patch) {
if (move_file(TMPOUTNAME, outname) < 0) {
toutkeep = TRUE;
chmod(TMPOUTNAME, filemode);
}
else
chmod(outname, filemode);
}
Fclose(rejfp);
rejfp = Nullfp;
if (failed) {
if (!*rejname) {
Strcpy(rejname, outname);
Strcat(rejname, ".rej");
}
if (skip_rest_of_patch) {
say4("%d out of %d hunks ignored--saving rejects to %s\n",
failed, hunk, rejname);
}
else {
say4("%d out of %d hunks failed--saving rejects to %s\n",
failed, hunk, rejname);
}
if (move_file(TMPREJNAME, rejname) < 0)
trejkeep = TRUE;
}
set_signals();
}
my_exit(0);
}
/* Prepare to find the next patch to do in the patch file. */
void
reinitialize_almost_everything()
{
re_patch();
re_input();
input_lines = 0;
last_frozen_line = 0;
filec = 0;
if (filearg[0] != Nullch && !out_of_mem) {
free(filearg[0]);
filearg[0] = Nullch;
}
if (outname != Nullch) {
free(outname);
outname = Nullch;
}
last_offset = 0;
diff_type = 0;
if (revision != Nullch) {
free(revision);
revision = Nullch;
}
reverse = FALSE;
skip_rest_of_patch = FALSE;
get_some_switches();
if (filec >= 2)
fatal1("You may not change to a different patch file.\n");
}
/* Process switches and filenames up to next '+' or end of list. */
void
get_some_switches()
{
Reg1 char *s;
rejname[0] = '\0';
Argc_last = Argc;
Argv_last = Argv;
if (!Argc)
return;
for (Argc--,Argv++; Argc; Argc--,Argv++) {
s = Argv[0];
if (strEQ(s, "+")) {
return; /* + will be skipped by for loop */
}
if (*s != '-' || !s[1]) {
if (filec == MAXFILEC)
fatal1("Too many file arguments.\n");
filearg[filec++] = savestr(s);
}
else {
switch (*++s) {
case 'b':
origext = savestr(Argv[1]);
Argc--,Argv++;
break;
case 'c':
diff_type = CONTEXT_DIFF;
break;
case 'd':
if (!*++s) {
Argc--,Argv++;
s = Argv[0];
}
if (chdir(s) < 0)
fatal2("Can't cd to %s.\n", s);
break;
case 'D':
do_defines = TRUE;
if (!*++s) {
Argc--,Argv++;
s = Argv[0];
}
Sprintf(if_defined, "#ifdef %s\n", s);
Sprintf(not_defined, "#ifndef %s\n", s);
Sprintf(end_defined, "#endif /* %s */\n", s);
break;
case 'e':
diff_type = ED_DIFF;
break;
case 'f':
force = TRUE;
break;
case 'F':
if (*++s == '=')
s++;
maxfuzz = atoi(s);
break;
case 'l':
canonicalize = TRUE;
break;
case 'n':
diff_type = NORMAL_DIFF;
break;
case 'N':
noreverse = TRUE;
break;
case 'o':
outname = savestr(Argv[1]);
Argc--,Argv++;
break;
case 'p':
if (*++s == '=')
s++;
strippath = atoi(s);
break;
case 'r':
Strcpy(rejname, Argv[1]);
Argc--,Argv++;
break;
case 'R':
reverse = TRUE;
break;
case 's':
verbose = FALSE;
break;
case 'S':
skip_rest_of_patch = TRUE;
break;
case 'v':
version();
break;
#ifdef DEBUGGING
case 'x':
debug = atoi(s+1);
break;
#endif
default:
fatal2("Unrecognized switch: %s\n", Argv[0]);
}
}
}
}
/* Attempt to find the right place to apply this hunk of patch. */
LINENUM
locate_hunk(fuzz)
LINENUM fuzz;
{
Reg1 LINENUM first_guess = pch_first() + last_offset;
Reg2 LINENUM offset;
LINENUM pat_lines = pch_ptrn_lines();
Reg3 LINENUM max_pos_offset = input_lines - first_guess
- pat_lines + 1;
Reg4 LINENUM max_neg_offset = first_guess - last_frozen_line - 1
+ pch_context();
if (!pat_lines) /* null range matches always */
return first_guess;
if (max_neg_offset >= first_guess) /* do not try lines < 0 */
max_neg_offset = first_guess - 1;
if (first_guess <= input_lines && patch_match(first_guess, Nulline, fuzz))
return first_guess;
for (offset = 1; ; offset++) {
Reg5 bool check_after = (offset <= max_pos_offset);
Reg6 bool check_before = (offset <= max_neg_offset);
if (check_after && patch_match(first_guess, offset, fuzz)) {
#ifdef DEBUGGING
if (debug & 1)
say3("Offset changing from %ld to %ld\n", last_offset, offset);
#endif
last_offset = offset;
return first_guess+offset;
}
else if (check_before && patch_match(first_guess, -offset, fuzz)) {
#ifdef DEBUGGING
if (debug & 1)
say3("Offset changing from %ld to %ld\n", last_offset, -offset);
#endif
last_offset = -offset;
return first_guess-offset;
}
else if (!check_before && !check_after)
return Nulline;
}
}
/* We did not find the pattern, dump out the hunk so they can handle it. */
void
abort_hunk()
{
Reg1 LINENUM i;
Reg2 LINENUM pat_end = pch_end();
/* add in last_offset to guess the same as the previous successful hunk */
LINENUM oldfirst = pch_first() + last_offset;
LINENUM newfirst = pch_newfirst() + last_offset;
LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1;
LINENUM newlast = newfirst + pch_repl_lines() - 1;
char *stars = (diff_type == NEW_CONTEXT_DIFF ? " ****" : "");
char *minuses = (diff_type == NEW_CONTEXT_DIFF ? " ----" : " -----");
fprintf(rejfp, "***************\n");
for (i=0; i<=pat_end; i++) {
switch (pch_char(i)) {
case '*':
if (oldlast < oldfirst)
fprintf(rejfp, "*** 0%s\n", stars);
else if (oldlast == oldfirst)
fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
else
fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, oldlast, stars);
break;
case '=':
if (newlast < newfirst)
fprintf(rejfp, "--- 0%s\n", minuses);
else if (newlast == newfirst)
fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
else
fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, newlast, minuses);
break;
case '\n':
fprintf(rejfp, "%s", pfetch(i));
break;
case ' ': case '-': case '+': case '!':
fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
break;
default:
say1("Fatal internal error in abort_hunk().\n");
abort();
}
}
}
/* We found where to apply it (we hope), so do it. */
void
apply_hunk(where)
LINENUM where;
{
Reg1 LINENUM old = 1;
Reg2 LINENUM lastline = pch_ptrn_lines();
Reg3 LINENUM new = lastline+1;
#define OUTSIDE 0
#define IN_IFNDEF 1
#define IN_IFDEF 2
#define IN_ELSE 3
Reg4 int def_state = OUTSIDE;
Reg5 bool R_do_defines = do_defines;
Reg6 LINENUM pat_end = pch_end();
where--;
while (pch_char(new) == '=' || pch_char(new) == '\n')
new++;
while (old <= lastline) {
if (pch_char(old) == '-') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == OUTSIDE) {
fputs(not_defined, ofp);
def_state = IN_IFNDEF;
}
else if (def_state == IN_IFDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
fputs(pfetch(old), ofp);
}
last_frozen_line++;
old++;
}
else if (new > pat_end)
break;
else if (pch_char(new) == '+') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == IN_IFNDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
else if (def_state == OUTSIDE) {
fputs(if_defined, ofp);
def_state = IN_IFDEF;
}
}
fputs(pfetch(new), ofp);
new++;
}
else {
if (pch_char(new) != pch_char(old)) {
say3("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
pch_hunk_beg() + old,
pch_hunk_beg() + new);
#ifdef DEBUGGING
say3("oldchar = '%c', newchar = '%c'\n",
pch_char(old), pch_char(new));
#endif
my_exit(1);
}
if (pch_char(new) == '!') {
copy_till(where + old - 1);
if (R_do_defines) {
fputs(not_defined, ofp);
def_state = IN_IFNDEF;
}
while (pch_char(old) == '!') {
if (R_do_defines) {
fputs(pfetch(old), ofp);
}
last_frozen_line++;
old++;
}
if (R_do_defines) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
while (pch_char(new) == '!') {
fputs(pfetch(new), ofp);
new++;
}
if (R_do_defines) {
fputs(end_defined, ofp);
def_state = OUTSIDE;
}
}
else {
assert(pch_char(new) == ' ');
old++;
new++;
}
}
}
if (new <= pat_end && pch_char(new) == '+') {
copy_till(where + old - 1);
if (R_do_defines) {
if (def_state == OUTSIDE) {
fputs(if_defined, ofp);
def_state = IN_IFDEF;
}
else if (def_state == IN_IFNDEF) {
fputs(else_defined, ofp);
def_state = IN_ELSE;
}
}
while (new <= pat_end && pch_char(new) == '+') {
fputs(pfetch(new), ofp);
new++;
}
}
if (R_do_defines && def_state != OUTSIDE) {
fputs(end_defined, ofp);
}
}
/* Open the new file. */
void
init_output(name)
char *name;
{
ofp = fopen(name, "w");
if (ofp == Nullfp)
fatal2("patch: can't create %s.\n", name);
}
/* Open a file to put hunks we can't locate. */
void
init_reject(name)
char *name;
{
rejfp = fopen(name, "w");
if (rejfp == Nullfp)
fatal2("patch: can't create %s.\n", name);
}
/* Copy input file to output, up to wherever hunk is to be applied. */
void
copy_till(lastline)
Reg1 LINENUM lastline;
{
Reg2 LINENUM R_last_frozen_line = last_frozen_line;
if (R_last_frozen_line > lastline)
say1("patch: misordered hunks! output will be garbled.\n");
while (R_last_frozen_line < lastline) {
dump_line(++R_last_frozen_line);
}
last_frozen_line = R_last_frozen_line;
}
/* Finish copying the input file to the output file. */
void
spew_output()
{
#ifdef DEBUGGING
if (debug & 256)
say3("il=%ld lfl=%ld\n",input_lines,last_frozen_line);
#endif
if (input_lines)
copy_till(input_lines); /* dump remainder of file */
Fclose(ofp);
ofp = Nullfp;
}
/* Copy one line from input to output. */
void
dump_line(line)
LINENUM line;
{
Reg1 char *s;
Reg2 char R_newline = '\n';
/* Note: string is not null terminated. */
for (s=ifetch(line, 0); putc(*s, ofp) != R_newline; s++) ;
}
/* Does the patch pattern match at line base+offset? */
bool
patch_match(base, offset, fuzz)
LINENUM base;
LINENUM offset;
LINENUM fuzz;
{
Reg1 LINENUM pline = 1 + fuzz;
Reg2 LINENUM iline;
Reg3 LINENUM pat_lines = pch_ptrn_lines() - fuzz;
for (iline=base+offset+fuzz; pline <= pat_lines; pline++,iline++) {
if (canonicalize) {
if (!similar(ifetch(iline, (offset >= 0)),
pfetch(pline),
pch_line_len(pline) ))
return FALSE;
}
else if (strnNE(ifetch(iline, (offset >= 0)),
pfetch(pline),
pch_line_len(pline) ))
return FALSE;
}
return TRUE;
}
/* Do two lines match with canonicalized white space? */
bool
similar(a,b,len)
Reg1 char *a;
Reg2 char *b;
Reg3 int len;
{
while (len) {
if (isspace(*b)) { /* whitespace (or \n) to match? */
if (!isspace(*a)) /* no corresponding whitespace? */
return FALSE;
while (len && isspace(*b) && *b != '\n')
b++,len--; /* skip pattern whitespace */
while (isspace(*a) && *a != '\n')
a++; /* skip target whitespace */
if (*a == '\n' || *b == '\n')
return (*a == *b); /* should end in sync */
}
else if (*a++ != *b++) /* match non-whitespace chars */
return FALSE;
else
len--; /* probably not necessary */
}
return TRUE; /* actually, this is not reached */
/* since there is always a \n */
}
/* Exit with cleanup. */
void
my_exit(status)
int status;
{
Unlink(TMPINNAME);
if (!toutkeep) {
Unlink(TMPOUTNAME);
}
if (!trejkeep) {
Unlink(TMPREJNAME);
}
Unlink(TMPPATNAME);
exit(status);
}

View File

@ -0,0 +1 @@
#define PATCHLEVEL 9

1108
usr.bin/patch/pch.c Normal file

File diff suppressed because it is too large Load Diff

36
usr.bin/patch/pch.h Normal file
View File

@ -0,0 +1,36 @@
/* $Header: pch.h,v 2.0.1.1 87/01/30 22:47:16 lwall Exp $
*
* $Log: pch.h,v $
* Revision 2.0.1.1 87/01/30 22:47:16 lwall
* Added do_ed_script().
*
* Revision 2.0 86/09/17 15:39:57 lwall
* Baseline for netwide release.
*
*/
EXT FILE *pfp INIT(Nullfp); /* patch file pointer */
void re_patch();
void open_patch_file();
void set_hunkmax();
void grow_hunkmax();
bool there_is_another_patch();
int intuit_diff_type();
void next_intuit_at();
void skip_to();
bool another_hunk();
bool pch_swap();
char *pfetch();
short pch_line_len();
LINENUM pch_first();
LINENUM pch_ptrn_lines();
LINENUM pch_newfirst();
LINENUM pch_repl_lines();
LINENUM pch_end();
LINENUM pch_context();
LINENUM pch_hunk_beg();
char pch_char();
char *pfetch();
char *pgets();
void do_ed_script();

339
usr.bin/patch/util.c Normal file
View File

@ -0,0 +1,339 @@
#include "EXTERN.h"
#include "common.h"
#include "INTERN.h"
#include "util.h"
/* Rename a file, copying it if necessary. */
int
move_file(from,to)
char *from, *to;
{
char bakname[512];
Reg1 char *s;
Reg2 int i;
Reg3 int fromfd;
/* to stdout? */
if (strEQ(to, "-")) {
#ifdef DEBUGGING
if (debug & 4)
say2("Moving %s to stdout.\n", from);
#endif
fromfd = open(from, 0);
if (fromfd < 0)
fatal2("patch: internal error, can't reopen %s\n", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(1, buf, i) != 1)
fatal1("patch: write failed\n");
Close(fromfd);
return 0;
}
Strcpy(bakname, to);
Strcat(bakname, origext?origext:ORIGEXT);
if (stat(to, &filestat) >= 0) { /* output file exists */
dev_t to_device = filestat.st_dev;
ino_t to_inode = filestat.st_ino;
char *simplename = bakname;
for (s=bakname; *s; s++) {
if (*s == '/')
simplename = s+1;
}
/* find a backup name that is not the same file */
while (stat(bakname, &filestat) >= 0 &&
to_device == filestat.st_dev && to_inode == filestat.st_ino) {
for (s=simplename; *s && !islower(*s); s++) ;
if (*s)
*s = toupper(*s);
else
Strcpy(simplename, simplename+1);
}
while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
#ifdef DEBUGGING
if (debug & 4)
say3("Moving %s to %s.\n", to, bakname);
#endif
if (link(to, bakname) < 0) {
say3("patch: can't backup %s, output is in %s\n",
to, from);
return -1;
}
while (unlink(to) >= 0) ;
}
#ifdef DEBUGGING
if (debug & 4)
say3("Moving %s to %s.\n", from, to);
#endif
if (link(from, to) < 0) { /* different file system? */
Reg4 int tofd;
tofd = creat(to, 0666);
if (tofd < 0) {
say3("patch: can't create %s, output is in %s.\n",
to, from);
return -1;
}
fromfd = open(from, 0);
if (fromfd < 0)
fatal2("patch: internal error, can't reopen %s\n", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
fatal1("patch: write failed\n");
Close(fromfd);
Close(tofd);
}
Unlink(from);
return 0;
}
/* Copy a file. */
void
copy_file(from,to)
char *from, *to;
{
Reg3 int tofd;
Reg2 int fromfd;
Reg1 int i;
tofd = creat(to, 0666);
if (tofd < 0)
fatal2("patch: can't create %s.\n", to);
fromfd = open(from, 0);
if (fromfd < 0)
fatal2("patch: internal error, can't reopen %s\n", from);
while ((i=read(fromfd, buf, sizeof buf)) > 0)
if (write(tofd, buf, i) != i)
fatal2("patch: write (%s) failed\n", to);
Close(fromfd);
Close(tofd);
}
/* Allocate a unique area for a string. */
char *
savestr(s)
Reg1 char *s;
{
Reg3 char *rv;
Reg2 char *t;
if (!s)
s = "Oops";
t = s;
while (*t++);
rv = malloc((MEM) (t - s));
if (rv == Nullch) {
if (using_plan_a)
out_of_mem = TRUE;
else
fatal1("patch: out of memory (savestr)\n");
}
else {
t = rv;
while (*t++ = *s++);
}
return rv;
}
#if defined(lint) && defined(CANVARARG)
/*VARARGS ARGSUSED*/
say(pat) char *pat; { ; }
/*VARARGS ARGSUSED*/
fatal(pat) char *pat; { ; }
/*VARARGS ARGSUSED*/
ask(pat) char *pat; { ; }
#else
/* Vanilla terminal output (buffered). */
void
say(pat,arg1,arg2,arg3)
char *pat;
int arg1,arg2,arg3;
{
fprintf(stderr, pat, arg1, arg2, arg3);
Fflush(stderr);
}
/* Terminal output, pun intended. */
void /* very void */
fatal(pat,arg1,arg2,arg3)
char *pat;
int arg1,arg2,arg3;
{
void my_exit();
say(pat, arg1, arg2, arg3);
my_exit(1);
}
/* Get a response from the user, somehow or other. */
void
ask(pat,arg1,arg2,arg3)
char *pat;
int arg1,arg2,arg3;
{
int ttyfd;
int r;
bool tty2 = isatty(2);
Sprintf(buf, pat, arg1, arg2, arg3);
Fflush(stderr);
write(2, buf, strlen(buf));
if (tty2) { /* might be redirected to a file */
r = read(2, buf, sizeof buf);
}
else if (isatty(1)) { /* this may be new file output */
Fflush(stdout);
write(1, buf, strlen(buf));
r = read(1, buf, sizeof buf);
}
else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) {
/* might be deleted or unwriteable */
write(ttyfd, buf, strlen(buf));
r = read(ttyfd, buf, sizeof buf);
Close(ttyfd);
}
else if (isatty(0)) { /* this is probably patch input */
Fflush(stdin);
write(0, buf, strlen(buf));
r = read(0, buf, sizeof buf);
}
else { /* no terminal at all--default it */
buf[0] = '\n';
r = 1;
}
if (r <= 0)
buf[0] = 0;
else
buf[r] = '\0';
if (!tty2)
say1(buf);
}
#endif lint
/* How to handle certain events when not in a critical region. */
void
set_signals()
{
void my_exit();
#ifndef lint
if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
Signal(SIGHUP, my_exit);
if (signal(SIGINT, SIG_IGN) != SIG_IGN)
Signal(SIGINT, my_exit);
#endif
}
/* How to handle certain events when in a critical region. */
void
ignore_signals()
{
#ifndef lint
Signal(SIGHUP, SIG_IGN);
Signal(SIGINT, SIG_IGN);
#endif
}
/* Make sure we'll have the directories to create a file. */
void
makedirs(filename,striplast)
Reg1 char *filename;
bool striplast;
{
char tmpbuf[256];
Reg2 char *s = tmpbuf;
char *dirv[20];
Reg3 int i;
Reg4 int dirvp = 0;
while (*filename) {
if (*filename == '/') {
filename++;
dirv[dirvp++] = s;
*s++ = '\0';
}
else {
*s++ = *filename++;
}
}
*s = '\0';
dirv[dirvp] = s;
if (striplast)
dirvp--;
if (dirvp < 0)
return;
strcpy(buf, "mkdir");
s = buf;
for (i=0; i<=dirvp; i++) {
while (*s) s++;
*s++ = ' ';
strcpy(s, tmpbuf);
*dirv[i] = '/';
}
system(buf);
}
/* Make filenames more reasonable. */
char *
fetchname(at,strip_leading,assume_exists)
char *at;
int strip_leading;
int assume_exists;
{
char *s;
char *name;
Reg1 char *t;
char tmpbuf[200];
if (!at)
return Nullch;
s = savestr(at);
for (t=s; isspace(*t); t++) ;
name = t;
#ifdef DEBUGGING
if (debug & 128)
say4("fetchname %s %d %d\n",name,strip_leading,assume_exists);
#endif
if (strnEQ(name, "/dev/null", 9)) /* so files can be created by diffing */
return Nullch; /* against /dev/null. */
for (; *t && !isspace(*t); t++)
if (*t == '/')
if (--strip_leading >= 0)
name = t+1;
*t = '\0';
if (name != s && *s != '/') {
name[-1] = '\0';
if (stat(s, &filestat) && filestat.st_mode & S_IFDIR) {
name[-1] = '/';
name=s;
}
}
name = savestr(name);
Sprintf(tmpbuf, "RCS/%s", name);
free(s);
if (stat(name, &filestat) < 0 && !assume_exists) {
Strcat(tmpbuf, RCSSUFFIX);
if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+4, &filestat) < 0) {
Sprintf(tmpbuf, "SCCS/%s%s", SCCSPREFIX, name);
if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+5, &filestat) < 0) {
free(name);
name = Nullch;
}
}
}
return name;
}

74
usr.bin/patch/util.h Normal file
View File

@ -0,0 +1,74 @@
/* $Header: util.h,v 2.0 86/09/17 15:40:06 lwall Exp $
*
* $Log: util.h,v $
* Revision 2.0 86/09/17 15:40:06 lwall
* Baseline for netwide release.
*
*/
/* and for those machine that can't handle a variable argument list */
#ifdef CANVARARG
#define say1 say
#define say2 say
#define say3 say
#define say4 say
#define ask1 ask
#define ask2 ask
#define ask3 ask
#define ask4 ask
#define fatal1 fatal
#define fatal2 fatal
#define fatal3 fatal
#define fatal4 fatal
#else /* hope they allow multi-line macro actual arguments */
#ifdef lint
#define say1(a) say(a, 0, 0, 0)
#define say2(a,b) say(a, (b)==(b), 0, 0)
#define say3(a,b,c) say(a, (b)==(b), (c)==(c), 0)
#define say4(a,b,c,d) say(a, (b)==(b), (c)==(c), (d)==(d))
#define ask1(a) ask(a, 0, 0, 0)
#define ask2(a,b) ask(a, (b)==(b), 0, 0)
#define ask3(a,b,c) ask(a, (b)==(b), (c)==(c), 0)
#define ask4(a,b,c,d) ask(a, (b)==(b), (c)==(c), (d)==(d))
#define fatal1(a) fatal(a, 0, 0, 0)
#define fatal2(a,b) fatal(a, (b)==(b), 0, 0)
#define fatal3(a,b,c) fatal(a, (b)==(b), (c)==(c), 0)
#define fatal4(a,b,c,d) fatal(a, (b)==(b), (c)==(c), (d)==(d))
#else /* lint */
/* if this doesn't work, try defining CANVARARG above */
#define say1(a) say(a, Nullch, Nullch, Nullch)
#define say2(a,b) say(a, b, Nullch, Nullch)
#define say3(a,b,c) say(a, b, c, Nullch)
#define say4 say
#define ask1(a) ask(a, Nullch, Nullch, Nullch)
#define ask2(a,b) ask(a, b, Nullch, Nullch)
#define ask3(a,b,c) ask(a, b, c, Nullch)
#define ask4 ask
#define fatal1(a) fatal(a, Nullch, Nullch, Nullch)
#define fatal2(a,b) fatal(a, b, Nullch, Nullch)
#define fatal3(a,b,c) fatal(a, b, c, Nullch)
#define fatal4 fatal
#endif /* lint */
/* if neither of the above work, join all multi-line macro calls. */
#endif
EXT char serrbuf[BUFSIZ]; /* buffer for stderr */
char *fetchname();
int move_file();
void copy_file();
void say();
void fatal();
void ask();
char *savestr();
void set_signals();
void ignore_signals();
void makedirs();

28
usr.bin/patch/version.c Normal file
View File

@ -0,0 +1,28 @@
/* $Header: version.c,v 2.0 86/09/17 15:40:11 lwall Exp $
*
* $Log: version.c,v $
* Revision 2.0 86/09/17 15:40:11 lwall
* Baseline for netwide release.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "INTERN.h"
#include "patchlevel.h"
#include "version.h"
/* Print out the version number and die. */
void
version()
{
extern char rcsid[];
#ifdef lint
rcsid[0] = rcsid[0];
#else
fatal3("%s\nPatch level: %d\n", rcsid, PATCHLEVEL);
#endif
}

9
usr.bin/patch/version.h Normal file
View File

@ -0,0 +1,9 @@
/* $Header: version.h,v 2.0 86/09/17 15:40:14 lwall Exp $
*
* $Log: version.h,v $
* Revision 2.0 86/09/17 15:40:14 lwall
* Baseline for netwide release.
*
*/
void version();

70
usr.bin/ranlib/ranlib.5.5 Normal file
View File

@ -0,0 +1,70 @@
.\" Copyright (c) 1990, 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.
.\"
.\" @(#)ranlib.5.5 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dt RANLIB 5
.Os
.Sh NAME
.Nm ranlib
.Nd archive (library) table-of-contents format
.Sh SYNOPSIS
.Fd #include <ranlib.h>
.Sh DESCRIPTION
The archive table-of-contents command
.Nm ranlib
creates a table of contents for archives, containing object files, to
be used by the link-editor
.Xr ld 1 .
It operates on archives created with the utility
.Xr ar 1 .
.Pp
The
.Nm Ranlib
function
prepends a new file to the archive which has three separate parts.
The first part is a standard archive header, which has a special name
field, "__.SYMDEF".
.Pp
The second part is a ``long'' followed by a list of ranlib structures.
The long is the size, in bytes, of the list of ranlib structures.
Each of the ranlib structures consists of a zero based offset into the
next section (a string table of symbols) and an offset from the beginning
of the archive to the start of the archive file which defines the symbol.
The actual number of ranlib structures is this number divided by the size
of an individual ranlib structure.
.Pp
The third part is a ``long'' followed by a string table.
The long is the size, in bytes of the string table.
.Sh SEE ALSO
.Xr ar 1 ,
.Xr ranlib 1

203
usr.bin/rlogin/des_rw.c Normal file
View File

@ -0,0 +1,203 @@
/*-
* Copyright (c) 1989, 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[] = "@(#)des_rw.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#ifdef CRYPT
#ifdef KERBEROS
#include <sys/param.h>
#include <kerberosIV/des.h>
#include <kerberosIV/krb.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static unsigned char des_inbuf[10240], storage[10240], *store_ptr;
static bit_64 *key;
static u_char *key_schedule;
/* XXX these should be in a kerberos include file */
int krb_net_read __P((int, char *, int));
#ifdef notdef
/* XXX too hard to make this work */
int des_pcbc_encrypt __P((des_cblock *, des_cblock *, long,
des_key_schedule, des_cblock *, int));
#endif
/*
* NB: These routines will not function properly if NBIO
* is set
*/
/*
* des_set_key
*
* Set des encryption/decryption key for use by the des_read and
* des_write routines
*
* The inkey parameter is actually the DES initial vector,
* and the insched is the DES Key unwrapped for faster decryption
*/
void
des_set_key(inkey, insched)
bit_64 *inkey;
u_char *insched;
{
key = inkey;
key_schedule = insched;
}
void
des_clear_key()
{
bzero((char *) key, sizeof(C_Block));
bzero((char *) key_schedule, sizeof(Key_schedule));
}
int
des_read(fd, buf, len)
int fd;
register char *buf;
int len;
{
int nreturned = 0;
long net_len, rd_len;
int nstored = 0;
if (nstored >= len) {
(void) bcopy(store_ptr, buf, len);
store_ptr += len;
nstored -= len;
return(len);
} else if (nstored) {
(void) bcopy(store_ptr, buf, nstored);
nreturned += nstored;
buf += nstored;
len -= nstored;
nstored = 0;
}
if (krb_net_read(fd, (char *)&net_len, sizeof(net_len)) !=
sizeof(net_len)) {
/* XXX can't read enough, pipe
must have closed */
return(0);
}
net_len = ntohl(net_len);
if (net_len <= 0 || net_len > sizeof(des_inbuf)) {
/* preposterous length; assume out-of-sync; only
recourse is to close connection, so return 0 */
return(0);
}
/* the writer tells us how much real data we are getting, but
we need to read the pad bytes (8-byte boundary) */
rd_len = roundup(net_len, 8);
if (krb_net_read(fd, (char *)des_inbuf, rd_len) != rd_len) {
/* pipe must have closed, return 0 */
return(0);
}
(void) des_pcbc_encrypt(des_inbuf, /* inbuf */
storage, /* outbuf */
net_len, /* length */
key_schedule, /* DES key */
key, /* IV */
DECRYPT); /* direction */
if(net_len < 8)
store_ptr = storage + 8 - net_len;
else
store_ptr = storage;
nstored = net_len;
if (nstored > len) {
(void) bcopy(store_ptr, buf, len);
nreturned += len;
store_ptr += len;
nstored -= len;
} else {
(void) bcopy(store_ptr, buf, nstored);
nreturned += nstored;
nstored = 0;
}
return(nreturned);
}
static unsigned char des_outbuf[10240]; /* > longest write */
int
des_write(fd, buf, len)
int fd;
char *buf;
int len;
{
static int seeded = 0;
static char garbage_buf[8];
long net_len, garbage;
if(len < 8) {
if(!seeded) {
seeded = 1;
srandom((int) time((long *)0));
}
garbage = random();
/* insert random garbage */
(void) bcopy(&garbage, garbage_buf, MIN(sizeof(long),8));
/* this "right-justifies" the data in the buffer */
(void) bcopy(buf, garbage_buf + 8 - len, len);
}
/* pcbc_encrypt outputs in 8-byte (64 bit) increments */
(void) des_pcbc_encrypt((len < 8) ? garbage_buf : buf,
des_outbuf,
(len < 8) ? 8 : len,
key_schedule, /* DES key */
key, /* IV */
ENCRYPT);
/* tell the other end the real amount, but send an 8-byte padded
packet */
net_len = htonl(len);
(void) write(fd, &net_len, sizeof(net_len));
(void) write(fd, des_outbuf, roundup(len,8));
return(len);
}
#endif /* KERBEROS */
#endif /* CRYPT */

5
usr.bin/sccs/Makefile Normal file
View File

@ -0,0 +1,5 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= sccs
.include <bsd.prog.mk>

View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.2 (Berkeley) 5/23/94
DIR= psd/14.sccs
SRCS= sccs.me
MACROS= -me
.include <bsd.doc.mk>

1609
usr.bin/sccs/PSD.doc/sccs.me Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,77 @@
AccessSid
Admin
Allman
Berkeley.Edu
Delget
Ingres
LDFLAGS
LIB
LIBS
OBJS
OpsysSid
PS1:14
PWB
REL
SCCS
SID
SRCS
Sccs
SccsId
System''PS1:14
TARG
a.c
a.o
a.out
access.h
admin
b.c
b.o
backslash
bi
c.c
c.o
c.y
ch
cm7
cmd
cs
d.o
d.s
deledit
delget
eric
example.c
example.o
fb
fd1
foreach
g.c
info
inline
john
lib
lib.a
makefile
makefiles
mod
mothballed
newxyz
ok
opsys.h
prog
prog.c
prog.h
prog.o
prt
rvu
sccs
sccsdiff
src
syssccs
t.c
ujohn
who.c
x.h
xyz
y.h
z.h

51
usr.bin/sccs/pathnames.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 1989, 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.
*
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
*/
#include <paths.h>
#define _PATH_SCCSADMIN "/usr/local/bin/admin"
#define _PATH_SCCSBDIFF "/usr/local/bin/bdiff"
#define _PATH_SCCSCOMB "/usr/local/bin/comb"
#define _PATH_SCCSDELTA "/usr/local/bin/delta"
#define _PATH_SCCSDIFF "/usr/local/bin/sccsdiff"
#define _PATH_SCCSGET "/usr/local/bin/get"
#define _PATH_SCCSHELP "/usr/local/bin/help"
#define _PATH_SCCSPRS "/usr/local/bin/prs"
#define _PATH_SCCSPRT "/usr/local/bin/prt"
#define _PATH_SCCSRMDEL "/usr/local/bin/rmdel"
#define _PATH_SCCSVAL "/usr/local/bin/val"
#define _PATH_SCCSWHAT "/usr/local/bin/what"
#undef _PATH_TMP
#define _PATH_TMP "/tmp/sccsXXXXX"

398
usr.bin/sccs/sccs.1 Normal file
View File

@ -0,0 +1,398 @@
.\" Copyright (c) 1983, 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.
.\"
.\" @(#)sccs.1 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dt SCCS 1
.Os BSD 4.2
.Sh NAME
.Nm sccs
.Nd front end for the
.Li SCCS
subsystem
.Sh SYNOPSIS
.Nm sccs
.Op Fl r
.Op Fl d Ar path
.Op Fl p Ar path
.Ar command
.Op flags
.Op Ar
.Sh DESCRIPTION
.Nm Sccs
is a front end to the
.Li SCCS
programs
that
helps them mesh more cleanly
with
the rest of UNIX.
It
also includes the capability to run
.Dq set user id
to another user
to
provide additional protection.
.Pp
Basically,
.Nm sccs
runs the command with the specified
.Ar flags
and
.Ar args .
Each argument is normally modified to be prepended with
.Dq Li SCCS/s. .
.Pp
Flags to be interpreted by the
.Nm sccs
program must be before the
.Ar command
argument.
Flags to be passed to the actual
.Li SCCS
program must come after the
.Ar command
argument.
These flags are specific to the command and
are discussed in the documentation for that command.
.Pp
Besides the usual
.Li SCCS
commands,
several
.Dq pseudo-commands
can be issued.
These are:
.Bl -tag -width deledit
.It Cm edit
Equivalent
to
.Dq Li get \-e .
.It Cm delget
Perform a delta on the named files and
then get new versions.
The new versions will have id keywords expanded, and
will not be editable.
The
.Fl m ,
.Fl p ,
.Fl r ,
.Fl s ,
and
.Fl y
flags will be passed to
.Nm delta ,
and the
.Fl b,
.Fl c ,
.Fl e ,
.Fl i ,
.Fl k ,
.Fl l ,
.Fl s ,
.\" anybody who has a bad xterm which is almost anyone
and
.Fl x
flags will be passed to get.
.It Cm deledit
Equivalent
to
.Nm delget
except that the
.Nm get
phase includes the
.Fl e
flag.
This
option is useful for making a
.Em checkpoint
of your current editing phase. The same flags will be passed to delta
as described above, and
all the flags listed for
.om get
above except
.Fl e
and
.Fl k
are
passed to
.Nm edit .
.It Cm create
Creates
an
.Li SCCS
file ,
taking
the initial contents from the file of the same name.
Any
flags to
.Nm admin
are accepted. If the creation is successful,
the files are renamed with a comma on the front.
These should be removed when you are convinced that the
.Li SCCS
files
have been created successfully.
.It Cm fix
Must
be followed by a
.Fl r
flag.
This command essentially removes the named delta, but
leaves you with a copy of the delta
with the changes that were in it. It
is useful for fixing small compiler bugs, etc.
Since it doesn't leave audit trails, it should be used carefully.
.It Cm clean
This routine removes everything from the current directory
that can be recreated from SCCS files.
It will not remove any files being edited.
If the
.Fl b
flag is given, branches are ignored in the determination of
whether they are being edited; this
is dangerous if you are keeping the branches in the
same directory.
.It Cm unedit
This
is the opposite of an
.Nm edit
or
a
.Dq Li get \-e .
It should be used with extreme caution, since
any changes you made since the get will be irretrievably lost.
.It Cm info
Gives a listing of all files being edited.
If the
.Fl b
flag
is given, branches (i.e.,
.Li SID Ns \&\'s
with two or fewer components)
are ignored. If the
.Fl u
flag is given (with an optional argument) then
only files being edited by you (or the named user) are listed.
.It Cm check
Like
.Nm info
except that nothing is printed if nothing is being edited, and
a non-zero exit status is returned if anything is being edited.
The intent is to have this included in an
.Em install
entry in a makefile to insure that everything is included into the
.Li SCCS
file before a version is installed.
.It Cm tell
Gives a newline-separated list of the files being edited
on the standard output. Takes the
.Fl b
and
.Fl u
flags like
.Nm info
and
.Nm check .
.It Cm diffs
Gives a
.Nm diff
listing between the current version of the
program(s) you have out for editing and the versions in
.Li SCCS
format.
The
.Fl r ,
.Fl c ,
.Fl i ,
.Fl x ,
and
.Fl t
flags are passed to
.if n \{\
. br
.\}
.Nm get ;
the
.Fl l ,
.Fl s ,
.Fl e ,
.Fl f ,
.Fl h ,
and
.Fl b
options are passed to
.if n \{\
. br
.\}
.Nm diff .
The
.Fl C
flag is passed to
.Nm diff
as
.Fl c .
.It Cm print
This command prints out verbose information
about the named files.
.Pp
.It Fl r
Runs
.Nm sccs
as the real user rather than as whatever effective user
.Nm sccs
is
.Dq Li set user id
to.
.It Fl d
Specifies a root directory for the
.Li SCCS
files.
The default is the current directory.
If environment variable
.Ev PROJECT
is set,
it will be used to determine the
.Fl d
flag.
.It Fl p
Defines the pathname of the directory in which the
.Li SCCS
files will be found;
.Dq Li SCCS
is the default.
The
.Fl p
flag
differs from the
.Fl d
flag
in that the
.Fl d
argument is prepended to the entire pathname and the
.Fl p
argument is inserted before the final component of the pathname.
For example,
.Dq Li sccs \-d/x \-py get a/b
will convert to
.Dq Li get /x/a/y/s.b .
The intent here is to create aliases such as
.Dq Li alias syssccs sccs -d/usr/src
which
will be used as
.Dq Li syssccs get cmd/who.c .
.Pp
Certain
commands (such as
.Nm admin )
cannot be run
.Dq Li set user id
by all users, since this would allow anyone to change the authorizations.
These commands are always run as the real user.
.Sh EXAMPLES
To get a file for editing,
edit it,
and produce a new delta:
.Pp
.Dl sccs get \-e file.c
.Dl ex file.c
.Dl sccs delta file.c
.Pp
To get a file from another directory:
.Pp
.Dl sccs \-p/usr/src/sccs/s. get cc.c
.Pp
or
.Pp
.Dl sccs get /usr/src/sccs/s.cc.c
.Pp
To make a delta of a large number of files
in the current directory:
.Pp
.Dl sccs delta *.c
.Pp
To get a list of files being edited that are not on branches:
.Pp
.Dl sccs info \-b
.Pp
To delta everything being edited by you:
.Pp
.Dl sccs delta \`sccs tell \-u\`
.Pp
In a makefile, to get source files
from an
.Li SCCS
file if it does not already exist:
.Pp
.Dl SRCS = <list of source files>
.Dl $(SRCS):
.Dl \&\tsccs get $(REL) $@
.Sh ENVIRONMENT
.Bl -tag -width Ar
.It Ev PROJECT
The PROJECT environment variable is checked by the
.Fl d
flag. If
it begins with a slash, it is taken directly; otherwise,
the home directory of a user of that name is
examined for a subdirectory
.Dq Li src
or
.Dq Li source .
If such a directory is found, it is used.
.El
.Sh SEE ALSO
.Xr what 1
.Xr admin SCCS ,
.Xr chghist SCCS ,
.Xr comb SCCS ,
.Xr delta SCCS ,
.Xr get SCCS ,
.Xr help SCCS ,
.Xr prt SCCS ,
.Xr rmdel SCCS ,
.Xr sccsdiff SCCS ,
.Rs
.%A Eric Allman
.%T "An Introduction to the Source Code Control System"
.Re
.Sh HISTORY
The
.Nm sccs
command
appeared in
.Bx 4.3 .
.Sh BUGS
It should be able to take directory arguments on pseudo-commands
like the
.Li SCCS
commands do.

1621
usr.bin/sccs/sccs.c Normal file

File diff suppressed because it is too large Load Diff

310
usr.bin/sort/sort.1 Normal file
View File

@ -0,0 +1,310 @@
.\" Copyright (c) 1991, 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.
.\"
.\" @(#)sort.1 8.2 (Berkeley) 5/4/95
.\"
.Dd May 4, 1995
.Dt SORT 1
.Os
.Sh NAME
.Nm sort
.Nd sort or merge text files
.Sh SYNOPSIS
.Nm sort
.Op Fl mubdfinrtx
.Oo
.Cm \(pl Ns Ar pos1
.Op Fl Ns Ar pos2
.Oc
.Ar ...
.Op Fl o Ar output
.Op Fl T Ar directory
.Op Ar file
.Ar ...
.Sh DESCRIPTION
The
.Nm sort
utility
sorts text files by lines.
Comparisons are based on one or more sort keys (or fields) extracted
from each line of input, and are performed
lexicographically. By default, if keys are not given,
.Nm sort
regards each input line as a single field.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl c
Check that the single input file is sorted lexicographically.
If the file is not sorted,
.Nm sort
sorts it and writes the sorted output to the standard output or the
filename specified by the
.Fl o
option.
.It Fl m
Merge only; the input files are assumed to be pre-sorted.
.It Fl o Ar output
The argument given is the name of an
.Ar output
file to
be used instead of the standard output.
This file
can be the same as one of the input files.
.It Fl T Ar directory
The argument
.Ar directory
is used for creating temporary files.
.It Fl u
Unique: suppress all but one in each set of lines
having equal keys.
If used with the
.Fl c
option,
check that there are no lines with duplicate keys.
.El
.Pp
The following options override the default ordering rules.
When ordering options appear independent of key field
specifications, the requested field ordering rules are
applied globally to all sort keys.
.\" When attached to a
.\" specific key
.\" (see
.\" .Fl k ) ,
.\" the specified ordering options override
.\" all global ordering options for that key.
.Bl -tag -width indent
.It Fl d
Only blank space and alphanumeric characters
.\" according
.\" to the current setting of LC_CTYPE
are used
in making comparisons.
.It Fl f
Considers all lowercase characters that have uppercase
equivalents to be the same for purposes of
comparison.
.It Fl i
Ignore all non-printable characters.
.It Fl n
An initial numeric string, consisting of optional
blank space, optional minus sign, and zero or more
digits (including decimal point)
.\" with
.\" optional radix character and thousands
.\" separator
.\" (as defined in the current locale),
is sorted by arithmetic value.
The
.Fl n
option implies
the
.Fl b
option. (See below.)
Note that the
.Fl b
option
is only effective when key fields have been specified
and that
.Fl \&0
is considered equal to zero.
.It Fl r
Reverse the sense of comparisons.
.El
.Pp
The treatment of field separators can be altered using the
options:
.Bl -tag -width indent
.It Fl b
Leading blank spaces are ignored when determining the starting
ending positions of a restricted sort key.
If the
.Fl b
option is specified before the first
.Cm \(pl Ns Ar pos1
argument, it shall be applied to all
.Cm \(pl Ns Ar pos1
arguments.
Otherwise, the
.Fl b
option can be
attached independently to each
.Cm \(pl Ns Ar pos1
or
.Fl Ar pos2
argument (see below).
.It Fl t Ar char
.Ar Char
is used as the field separator character;
.Ar char
is not considered to be part of a field (although it
can be included in a sort key).
Each occurrence of
.Ar char
is significant (for example,
.Dq Ar charchar
delimits an empty field).
If
.Fl t
is not specified,
blank space characters are used as default field
separators.
.It Cm \(pl Ns Ar pos1
Designates the start position of a key field.
.It Fl Ns Ar pos1
Designates the end position of a key field.
.El
.Pp
The following operands are available:
.Bl -tag -width indent
.Ar file
The pathname of a file to be sorted, merged, or checked.
If no file
operands are specified, or if
a file operand is
.Fl ,
the standard input is used.
.Pp
A field is
defined as a minimal sequence of characters followed by a
field separator or a newline character.
By default, the first
blank space of a sequence of blank spaces acts as the field separator.
All blank spaces in a sequence of blank spaces are considered
to be part of the next field; for example, all blank spaces at
the beginning of a line are considered to be part of the
first field.
.Pp
Fields are specified
by the
.Cm \(pl Ns Ar pos1
and
.Fl Ar pos2
arguments. A missing
.Cm \(pl Ns Ar pos1
argument defaults to the beginning of a line.
A missing
.Fl Ar pos2
argument defaults to the end of a line.
.Pp
The arguments
.Cm \(pl Ns Ar pos1
and
.Fl Ar pos2
have the form
.Em m.n
followed by one or more of the options
.Fl b , d , f , i ,
.Fl n , r .
A
.Cm \(pl Ns Ar pos1
position specified by
.Em m.n
is interpreted to
mean the
.Em n Ns th
character in the
.Em m Ns \(pl1th
field.
A missing
.Em \&.n
means
.Ql \&.0 ,
indicating the first character of the
.Em m Ns \(pl1th
field.
If the
.Fl b
option is in effect,
.Em n
is counted from the first
non-blank character in the
.Em m Ns \(pl1th
field;
.Em m Ns \&.0b
refers to the first
non-blank character in the
.Em m Ns \(pl1th
field.
.Pp
A
.Fl Ar pos2
position specified by
.Em m.n
is interpreted to mean
the
.Em n Ns th
character (including separators) after the last
character of the
.Em m Ns th
field.
A missing
.Em \&.n
means
.Ql \&.0 ,
indicating
the last character of the
.Em m Ns th
field.
If the
.Fl b
option
is in effect,
.Em n
is counted from the last leading blank character in
the
.Em m Ns \(pl1th
field;
.Em m Ns \&.1b
refers to the first non-blank character in the
.Em m Ns \(pl1th
field.
.Sh FILES
.Bl -tag -width Pa -compact
.It Pa /var/tmp/stm*, /tmp/*
Default temporary directories (in order of search).
.El
.Sh SEE ALSO
.Xr comm 1 ,
.Xr uniq 1 ,
.Xr join 1
.Sh DIAGNOSTICS
.Sh BUGS
Lines which are longer than 4096 are discarded and processing continues.
.Sh HISTORY
A
.Nm
command appeared in
.At v6 .

196
usr.bin/tip/acu.c Normal file
View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 1983, 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[] = "@(#)acu.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
static acu_t *acu = NOACU;
static int conflag;
static void acuabort();
static acu_t *acutype();
static jmp_buf jmpbuf;
/*
* Establish connection for tip
*
* If DU is true, we should dial an ACU whose type is AT.
* The phone numbers are in PN, and the call unit is in CU.
*
* If the PN is an '@', then we consult the PHONES file for
* the phone numbers. This file is /etc/phones, unless overriden
* by an exported shell variable.
*
* The data base files must be in the format:
* host-name[ \t]*phone-number
* with the possibility of multiple phone numbers
* for a single host acting as a rotary (in the order
* found in the file).
*/
char *
connect()
{
register char *cp = PN;
char *phnum, string[256];
FILE *fd;
int tried = 0;
if (!DU) { /* regular connect message */
if (CM != NOSTR)
pwrite(FD, CM, size(CM));
logent(value(HOST), "", DV, "call completed");
return (NOSTR);
}
/*
* @ =>'s use data base in PHONES environment variable
* otherwise, use /etc/phones
*/
signal(SIGINT, acuabort);
signal(SIGQUIT, acuabort);
if (setjmp(jmpbuf)) {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
printf("\ncall aborted\n");
logent(value(HOST), "", "", "call aborted");
if (acu != NOACU) {
boolean(value(VERBOSE)) = FALSE;
if (conflag)
disconnect(NOSTR);
else
(*acu->acu_abort)();
}
return ("interrupt");
}
if ((acu = acutype(AT)) == NOACU)
return ("unknown ACU type");
if (*cp != '@') {
while (*cp) {
for (phnum = cp; *cp && *cp != ','; cp++)
;
if (*cp)
*cp++ = '\0';
if (conflag = (*acu->acu_dialer)(phnum, CU)) {
if (CM != NOSTR)
pwrite(FD, CM, size(CM));
logent(value(HOST), phnum, acu->acu_name,
"call completed");
return (NOSTR);
} else
logent(value(HOST), phnum, acu->acu_name,
"call failed");
tried++;
}
} else {
if ((fd = fopen(PH, "r")) == NOFILE) {
printf("%s: ", PH);
return ("can't open phone number file");
}
while (fgets(string, sizeof(string), fd) != NOSTR) {
for (cp = string; !any(*cp, " \t\n"); cp++)
;
if (*cp == '\n') {
fclose(fd);
return ("unrecognizable host name");
}
*cp++ = '\0';
if (strcmp(string, value(HOST)))
continue;
while (any(*cp, " \t"))
cp++;
if (*cp == '\n') {
fclose(fd);
return ("missing phone number");
}
for (phnum = cp; *cp && *cp != ',' && *cp != '\n'; cp++)
;
if (*cp)
*cp++ = '\0';
if (conflag = (*acu->acu_dialer)(phnum, CU)) {
fclose(fd);
if (CM != NOSTR)
pwrite(FD, CM, size(CM));
logent(value(HOST), phnum, acu->acu_name,
"call completed");
return (NOSTR);
} else
logent(value(HOST), phnum, acu->acu_name,
"call failed");
tried++;
}
fclose(fd);
}
if (!tried)
logent(value(HOST), "", acu->acu_name, "missing phone number");
else
(*acu->acu_abort)();
return (tried ? "call failed" : "missing phone number");
}
disconnect(reason)
char *reason;
{
if (!conflag) {
logent(value(HOST), "", DV, "call terminated");
return;
}
if (reason == NOSTR) {
logent(value(HOST), "", acu->acu_name, "call terminated");
if (boolean(value(VERBOSE)))
printf("\r\ndisconnecting...");
} else
logent(value(HOST), "", acu->acu_name, reason);
(*acu->acu_disconnect)();
}
static void
acuabort(s)
{
signal(s, SIG_IGN);
longjmp(jmpbuf, 1);
}
static acu_t *
acutype(s)
register char *s;
{
register acu_t *p;
extern acu_t acutable[];
for (p = acutable; p->acu_name != '\0'; p++)
if (!strcmp(s, p->acu_name))
return (p);
return (NOACU);
}

187
usr.bin/tip/aculib/biz22.c Normal file
View File

@ -0,0 +1,187 @@
/*
* Copyright (c) 1983, 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[] = "@(#)biz22.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
#define DISCONNECT_CMD "\20\04" /* disconnection string */
static void sigALRM();
static int timeout = 0;
static jmp_buf timeoutbuf;
/*
* Dial up on a BIZCOMP Model 1022 with either
* tone dialing (mod = "V")
* pulse dialing (mod = "W")
*/
static int
biz_dialer(num, mod)
char *num, *mod;
{
register int connected = 0;
char cbuf[40];
static int cmd(), detect();
if (boolean(value(VERBOSE)))
printf("\nstarting call...");
/*
* Disable auto-answer and configure for tone/pulse
* dialing
*/
if (cmd("\02K\r")) {
printf("can't initialize bizcomp...");
return (0);
}
strcpy(cbuf, "\02.\r");
cbuf[1] = *mod;
if (cmd(cbuf)) {
printf("can't set dialing mode...");
return (0);
}
strcpy(cbuf, "\02D");
strcat(cbuf, num);
strcat(cbuf, "\r");
write(FD, cbuf, strlen(cbuf));
if (!detect("7\r")) {
printf("can't get dial tone...");
return (0);
}
if (boolean(value(VERBOSE)))
printf("ringing...");
/*
* The reply from the BIZCOMP should be:
* 2 \r or 7 \r failure
* 1 \r success
*/
connected = detect("1\r");
#ifdef ACULOG
if (timeout) {
char line[80];
sprintf(line, "%d second dial timeout",
number(value(DIALTIMEOUT)));
logent(value(HOST), num, "biz1022", line);
}
#endif
if (timeout)
biz22_disconnect(); /* insurance */
return (connected);
}
biz22w_dialer(num, acu)
char *num, *acu;
{
return (biz_dialer(num, "W"));
}
biz22f_dialer(num, acu)
char *num, *acu;
{
return (biz_dialer(num, "V"));
}
biz22_disconnect()
{
int rw = 2;
write(FD, DISCONNECT_CMD, 4);
sleep(2);
ioctl(FD, TIOCFLUSH, &rw);
}
biz22_abort()
{
write(FD, "\02", 1);
}
static void
sigALRM()
{
timeout = 1;
longjmp(timeoutbuf, 1);
}
static int
cmd(s)
register char *s;
{
sig_t f;
char c;
write(FD, s, strlen(s));
f = signal(SIGALRM, sigALRM);
if (setjmp(timeoutbuf)) {
biz22_abort();
signal(SIGALRM, f);
return (1);
}
alarm(number(value(DIALTIMEOUT)));
read(FD, &c, 1);
alarm(0);
signal(SIGALRM, f);
c &= 0177;
return (c != '\r');
}
static int
detect(s)
register char *s;
{
sig_t f;
char c;
f = signal(SIGALRM, sigALRM);
timeout = 0;
while (*s) {
if (setjmp(timeoutbuf)) {
biz22_abort();
break;
}
alarm(number(value(DIALTIMEOUT)));
read(FD, &c, 1);
alarm(0);
c &= 0177;
if (c != *s++)
return (0);
}
signal(SIGALRM, f);
return (timeout == 0);
}

248
usr.bin/tip/aculib/biz31.c Normal file
View File

@ -0,0 +1,248 @@
/*
* Copyright (c) 1983, 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[] = "@(#)biz31.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
#define MAXRETRY 3 /* sync up retry count */
#define DISCONNECT_CMD "\21\25\11\24" /* disconnection string */
static void sigALRM();
static int timeout = 0;
static jmp_buf timeoutbuf;
/*
* Dial up on a BIZCOMP Model 1031 with either
* tone dialing (mod = "f")
* pulse dialing (mod = "w")
*/
static int
biz_dialer(num, mod)
char *num, *mod;
{
register int connected = 0;
if (!bizsync(FD)) {
logent(value(HOST), "", "biz", "out of sync");
printf("bizcomp out of sync\n");
delock(uucplock);
exit(0);
}
if (boolean(value(VERBOSE)))
printf("\nstarting call...");
echo("#\rk$\r$\n"); /* disable auto-answer */
echo("$>$.$ #\r"); /* tone/pulse dialing */
echo(mod);
echo("$\r$\n");
echo("$>$.$ #\re$ "); /* disconnection sequence */
echo(DISCONNECT_CMD);
echo("\r$\n$\r$\n");
echo("$>$.$ #\rr$ "); /* repeat dial */
echo(num);
echo("\r$\n");
if (boolean(value(VERBOSE)))
printf("ringing...");
/*
* The reply from the BIZCOMP should be:
* `^G NO CONNECTION\r\n^G\r\n' failure
* ` CONNECTION\r\n^G' success
*/
connected = detect(" ");
#ifdef ACULOG
if (timeout) {
char line[80];
sprintf(line, "%d second dial timeout",
number(value(DIALTIMEOUT)));
logent(value(HOST), num, "biz", line);
}
#endif
if (!connected)
flush(" NO CONNECTION\r\n\07\r\n");
else
flush("CONNECTION\r\n\07");
if (timeout)
biz31_disconnect(); /* insurance */
return (connected);
}
biz31w_dialer(num, acu)
char *num, *acu;
{
return (biz_dialer(num, "w"));
}
biz31f_dialer(num, acu)
char *num, *acu;
{
return (biz_dialer(num, "f"));
}
biz31_disconnect()
{
write(FD, DISCONNECT_CMD, 4);
sleep(2);
ioctl(FD, TIOCFLUSH);
}
biz31_abort()
{
write(FD, "\33", 1);
}
static int
echo(s)
register char *s;
{
char c;
while (c = *s++) switch (c) {
case '$':
read(FD, &c, 1);
s++;
break;
case '#':
c = *s++;
write(FD, &c, 1);
break;
default:
write(FD, &c, 1);
read(FD, &c, 1);
}
}
static void
sigALRM()
{
timeout = 1;
longjmp(timeoutbuf, 1);
}
static int
detect(s)
register char *s;
{
sig_t f;
char c;
f = signal(SIGALRM, sigALRM);
timeout = 0;
while (*s) {
if (setjmp(timeoutbuf)) {
printf("\07timeout waiting for reply\n");
biz31_abort();
break;
}
alarm(number(value(DIALTIMEOUT)));
read(FD, &c, 1);
alarm(0);
if (c != *s++)
break;
}
signal(SIGALRM, f);
return (timeout == 0);
}
static int
flush(s)
register char *s;
{
sig_t f;
char c;
f = signal(SIGALRM, sigALRM);
while (*s++) {
if (setjmp(timeoutbuf))
break;
alarm(10);
read(FD, &c, 1);
alarm(0);
}
signal(SIGALRM, f);
timeout = 0; /* guard against disconnection */
}
/*
* This convoluted piece of code attempts to get
* the bizcomp in sync. If you don't have the capacity or nread
* call there are gory ways to simulate this.
*/
static int
bizsync(fd)
{
#ifdef FIOCAPACITY
struct capacity b;
# define chars(b) ((b).cp_nbytes)
# define IOCTL FIOCAPACITY
#endif
#ifdef FIONREAD
long b;
# define chars(b) (b)
# define IOCTL FIONREAD
#endif
register int already = 0;
char buf[10];
retry:
if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0 && chars(b) > 0)
ioctl(fd, TIOCFLUSH);
write(fd, "\rp>\r", 4);
sleep(1);
if (ioctl(fd, IOCTL, (caddr_t)&b) >= 0) {
if (chars(b) != 10) {
nono:
if (already > MAXRETRY)
return (0);
write(fd, DISCONNECT_CMD, 4);
sleep(2);
already++;
goto retry;
} else {
read(fd, buf, 10);
if (strncmp(buf, "p >\r\n\r\n>", 8))
goto nono;
}
}
return (1);
}

View File

@ -0,0 +1,380 @@
/*
* Copyright (c) 1986, 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[] = "@(#)courier.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for calling up on a Courier modem.
* Derived from Hayes driver.
*/
#include "tip.h"
#include <stdio.h>
#define MAXRETRY 5
static void sigALRM();
static int timeout = 0;
static int connected = 0;
static jmp_buf timeoutbuf, intbuf;
static int coursync();
cour_dialer(num, acu)
register char *num;
char *acu;
{
register char *cp;
#ifdef ACULOG
char line[80];
#endif
static int cour_connect(), cour_swallow();
if (boolean(value(VERBOSE)))
printf("Using \"%s\"\n", acu);
ioctl(FD, TIOCHPCL, 0);
/*
* Get in synch.
*/
if (!coursync()) {
badsynch:
printf("can't synchronize with courier\n");
#ifdef ACULOG
logent(value(HOST), num, "courier", "can't synch up");
#endif
return (0);
}
cour_write(FD, "AT E0\r", 6); /* turn off echoing */
sleep(1);
#ifdef DEBUG
if (boolean(value(VERBOSE)))
cour_verbose_read();
#endif
ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
cour_write(FD, "AT C1 E0 H0 Q0 X6 V1\r", 21);
if (!cour_swallow("\r\nOK\r\n"))
goto badsynch;
fflush(stdout);
cour_write(FD, "AT D", 4);
for (cp = num; *cp; cp++)
if (*cp == '=')
*cp = ',';
cour_write(FD, num, strlen(num));
cour_write(FD, "\r", 1);
connected = cour_connect();
#ifdef ACULOG
if (timeout) {
sprintf(line, "%d second dial timeout",
number(value(DIALTIMEOUT)));
logent(value(HOST), num, "cour", line);
}
#endif
if (timeout)
cour_disconnect();
return (connected);
}
cour_disconnect()
{
/* first hang up the modem*/
ioctl(FD, TIOCCDTR, 0);
sleep(1);
ioctl(FD, TIOCSDTR, 0);
coursync(); /* reset */
close(FD);
}
cour_abort()
{
cour_write(FD, "\r", 1); /* send anything to abort the call */
cour_disconnect();
}
static void
sigALRM()
{
printf("\07timeout waiting for reply\n");
timeout = 1;
longjmp(timeoutbuf, 1);
}
static int
cour_swallow(match)
register char *match;
{
sig_t f;
char c;
f = signal(SIGALRM, sigALRM);
timeout = 0;
do {
if (*match =='\0') {
signal(SIGALRM, f);
return (1);
}
if (setjmp(timeoutbuf)) {
signal(SIGALRM, f);
return (0);
}
alarm(number(value(DIALTIMEOUT)));
read(FD, &c, 1);
alarm(0);
c &= 0177;
#ifdef DEBUG
if (boolean(value(VERBOSE)))
putchar(c);
#endif
} while (c == *match++);
#ifdef DEBUG
if (boolean(value(VERBOSE)))
fflush(stdout);
#endif
signal(SIGALRM, SIG_DFL);
return (0);
}
struct baud_msg {
char *msg;
int baud;
} baud_msg[] = {
"", B300,
" 1200", B1200,
" 2400", B2400,
" 9600", B9600,
" 9600/ARQ", B9600,
0, 0,
};
static int
cour_connect()
{
char c;
int nc, nl, n;
struct sgttyb sb;
char dialer_buf[64];
struct baud_msg *bm;
sig_t f;
if (cour_swallow("\r\n") == 0)
return (0);
f = signal(SIGALRM, sigALRM);
again:
nc = 0; nl = sizeof(dialer_buf)-1;
bzero(dialer_buf, sizeof(dialer_buf));
timeout = 0;
for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
if (setjmp(timeoutbuf))
break;
alarm(number(value(DIALTIMEOUT)));
n = read(FD, &c, 1);
alarm(0);
if (n <= 0)
break;
c &= 0x7f;
if (c == '\r') {
if (cour_swallow("\n") == 0)
break;
if (!dialer_buf[0])
goto again;
if (strcmp(dialer_buf, "RINGING") == 0 &&
boolean(value(VERBOSE))) {
#ifdef DEBUG
printf("%s\r\n", dialer_buf);
#endif
goto again;
}
if (strncmp(dialer_buf, "CONNECT",
sizeof("CONNECT")-1) != 0)
break;
for (bm = baud_msg ; bm->msg ; bm++)
if (strcmp(bm->msg,
dialer_buf+sizeof("CONNECT")-1) == 0) {
if (ioctl(FD, TIOCGETP, &sb) < 0) {
perror("TIOCGETP");
goto error;
}
sb.sg_ispeed = sb.sg_ospeed = bm->baud;
if (ioctl(FD, TIOCSETP, &sb) < 0) {
perror("TIOCSETP");
goto error;
}
signal(SIGALRM, f);
#ifdef DEBUG
if (boolean(value(VERBOSE)))
printf("%s\r\n", dialer_buf);
#endif
return (1);
}
break;
}
dialer_buf[nc] = c;
#ifdef notdef
if (boolean(value(VERBOSE)))
putchar(c);
#endif
}
error1:
printf("%s\r\n", dialer_buf);
error:
signal(SIGALRM, f);
return (0);
}
/*
* This convoluted piece of code attempts to get
* the courier in sync.
*/
static int
coursync()
{
int already = 0;
int len;
char buf[40];
while (already++ < MAXRETRY) {
ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
cour_write(FD, "\rAT Z\r", 6); /* reset modem */
bzero(buf, sizeof(buf));
sleep(1);
ioctl(FD, FIONREAD, &len);
if (len) {
len = read(FD, buf, sizeof(buf));
#ifdef DEBUG
buf[len] = '\0';
printf("coursync: (\"%s\")\n\r", buf);
#endif
if (index(buf, '0') ||
(index(buf, 'O') && index(buf, 'K')))
return(1);
}
/*
* If not strapped for DTR control,
* try to get command mode.
*/
sleep(1);
cour_write(FD, "+++", 3);
sleep(1);
/*
* Toggle DTR to force anyone off that might have left
* the modem connected.
*/
ioctl(FD, TIOCCDTR, 0);
sleep(1);
ioctl(FD, TIOCSDTR, 0);
}
cour_write(FD, "\rAT Z\r", 6);
return (0);
}
cour_write(fd, cp, n)
int fd;
char *cp;
int n;
{
struct sgttyb sb;
#ifdef notdef
if (boolean(value(VERBOSE)))
write(1, cp, n);
#endif
ioctl(fd, TIOCGETP, &sb);
ioctl(fd, TIOCSETP, &sb);
cour_nap();
for ( ; n-- ; cp++) {
write(fd, cp, 1);
ioctl(fd, TIOCGETP, &sb);
ioctl(fd, TIOCSETP, &sb);
cour_nap();
}
}
#ifdef DEBUG
cour_verbose_read()
{
int n = 0;
char buf[BUFSIZ];
if (ioctl(FD, FIONREAD, &n) < 0)
return;
if (n <= 0)
return;
if (read(FD, buf, n) != n)
return;
write(1, buf, n);
}
#endif
/*
* Code stolen from /usr/src/lib/libc/gen/sleep.c
*/
#define mask(s) (1<<((s)-1))
#define setvec(vec, a) \
vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
static napms = 50; /* Give the courier 50 milliseconds between characters */
static int ringring;
cour_nap()
{
static void cour_napx();
int omask;
struct itimerval itv, oitv;
register struct itimerval *itp = &itv;
struct sigvec vec, ovec;
timerclear(&itp->it_interval);
timerclear(&itp->it_value);
if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
return;
setvec(ovec, SIG_DFL);
omask = sigblock(mask(SIGALRM));
itp->it_value.tv_sec = napms/1000;
itp->it_value.tv_usec = ((napms%1000)*1000);
setvec(vec, cour_napx);
ringring = 0;
(void) sigvec(SIGALRM, &vec, &ovec);
(void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
while (!ringring)
sigpause(omask &~ mask(SIGALRM));
(void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
(void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
(void) sigsetmask(omask);
}
static void
cour_napx()
{
ringring = 1;
}

132
usr.bin/tip/aculib/df.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 1983, 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[] = "@(#)df.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Dial the DF02-AC or DF03-AC
*/
#include "tip.h"
static jmp_buf Sjbuf;
static void timeout();
df02_dialer(num, acu)
char *num, *acu;
{
return (df_dialer(num, acu, 0));
}
df03_dialer(num, acu)
char *num, *acu;
{
return (df_dialer(num, acu, 1));
}
df_dialer(num, acu, df03)
char *num, *acu;
int df03;
{
register int f = FD;
struct sgttyb buf;
int speed = 0, rw = 2;
char c = '\0';
ioctl(f, TIOCHPCL, 0); /* make sure it hangs up when done */
if (setjmp(Sjbuf)) {
printf("connection timed out\r\n");
df_disconnect();
return (0);
}
if (boolean(value(VERBOSE)))
printf("\ndialing...");
fflush(stdout);
#ifdef TIOCMSET
if (df03) {
int st = TIOCM_ST; /* secondary Transmit flag */
ioctl(f, TIOCGETP, &buf);
if (buf.sg_ospeed != B1200) { /* must dial at 1200 baud */
speed = buf.sg_ospeed;
buf.sg_ospeed = buf.sg_ispeed = B1200;
ioctl(f, TIOCSETP, &buf);
ioctl(f, TIOCMBIC, &st); /* clear ST for 300 baud */
} else
ioctl(f, TIOCMBIS, &st); /* set ST for 1200 baud */
}
#endif
signal(SIGALRM, timeout);
alarm(5 * strlen(num) + 10);
ioctl(f, TIOCFLUSH, &rw);
write(f, "\001", 1);
sleep(1);
write(f, "\002", 1);
write(f, num, strlen(num));
read(f, &c, 1);
#ifdef TIOCMSET
if (df03 && speed) {
buf.sg_ispeed = buf.sg_ospeed = speed;
ioctl(f, TIOCSETP, &buf);
}
#endif
return (c == 'A');
}
df_disconnect()
{
int rw = 2;
write(FD, "\001", 1);
sleep(1);
ioctl(FD, TIOCFLUSH, &rw);
}
df_abort()
{
df_disconnect();
}
static void
timeout()
{
longjmp(Sjbuf, 1);
}

142
usr.bin/tip/aculib/dn11.c Normal file
View File

@ -0,0 +1,142 @@
/*
* Copyright (c) 1983, 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[] = "@(#)dn11.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for dialing up on DN-11
*/
#include "tip.h"
int dn_abort();
void alarmtr();
static jmp_buf jmpbuf;
static int child = -1, dn;
dn_dialer(num, acu)
char *num, *acu;
{
extern errno;
char *p, *q, phone[40];
int lt, nw, connected = 1;
register int timelim;
if (boolean(value(VERBOSE)))
printf("\nstarting call...");
if ((dn = open(acu, 1)) < 0) {
if (errno == EBUSY)
printf("line busy...");
else
printf("acu open error...");
return (0);
}
if (setjmp(jmpbuf)) {
kill(child, SIGKILL);
close(dn);
return (0);
}
signal(SIGALRM, alarmtr);
timelim = 5 * strlen(num);
alarm(timelim < 30 ? 30 : timelim);
if ((child = fork()) == 0) {
/*
* ignore this stuff for aborts
*/
signal(SIGALRM, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
sleep(2);
nw = write(dn, num, lt = strlen(num));
exit(nw != lt);
}
/*
* open line - will return on carrier
*/
if ((FD = open(DV, 2)) < 0) {
if (errno == EIO)
printf("lost carrier...");
else
printf("dialup line open failed...");
alarm(0);
kill(child, SIGKILL);
close(dn);
return (0);
}
alarm(0);
ioctl(dn, TIOCHPCL, 0);
signal(SIGALRM, SIG_DFL);
while ((nw = wait(&lt)) != child && nw != -1)
;
fflush(stdout);
close(dn);
if (lt != 0) {
close(FD);
return (0);
}
return (1);
}
void
alarmtr()
{
alarm(0);
longjmp(jmpbuf, 1);
}
/*
* Insurance, for some reason we don't seem to be
* hanging up...
*/
dn_disconnect()
{
sleep(2);
if (FD > 0)
ioctl(FD, TIOCCDTR, 0);
close(FD);
}
dn_abort()
{
sleep(2);
if (child > 0)
kill(child, SIGKILL);
if (dn > 0)
close(dn);
if (FD > 0)
ioctl(FD, TIOCCDTR, 0);
close(FD);
}

305
usr.bin/tip/aculib/hayes.c Normal file
View File

@ -0,0 +1,305 @@
/*
* Copyright (c) 1983, 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[] = "@(#)hayes.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for calling up on a Hayes Modem
* (based on the old VenTel driver).
* The modem is expected to be strapped for "echo".
* Also, the switches enabling the DTR and CD lines
* must be set correctly.
* NOTICE:
* The easy way to hang up a modem is always simply to
* clear the DTR signal. However, if the +++ sequence
* (which switches the modem back to local mode) is sent
* before modem is hung up, removal of the DTR signal
* has no effect (except that it prevents the modem from
* recognizing commands).
* (by Helge Skrivervik, Calma Company, Sunnyvale, CA. 1984)
*/
/*
* TODO:
* It is probably not a good idea to switch the modem
* state between 'verbose' and terse (status messages).
* This should be kicked out and we should use verbose
* mode only. This would make it consistent with normal
* interactive use thru the command 'tip dialer'.
*/
#include "tip.h"
#define min(a,b) ((a < b) ? a : b)
static void sigALRM();
static int timeout = 0;
static jmp_buf timeoutbuf;
static char gobble();
#define DUMBUFLEN 40
static char dumbuf[DUMBUFLEN];
#define DIALING 1
#define IDLE 2
#define CONNECTED 3
#define FAILED 4
static int state = IDLE;
hay_dialer(num, acu)
register char *num;
char *acu;
{
register char *cp;
register int connected = 0;
char dummy;
#ifdef ACULOG
char line[80];
#endif
if (hay_sync() == 0) /* make sure we can talk to the modem */
return(0);
if (boolean(value(VERBOSE)))
printf("\ndialing...");
fflush(stdout);
ioctl(FD, TIOCHPCL, 0);
ioctl(FD, TIOCFLUSH, 0); /* get rid of garbage */
write(FD, "ATv0\r", 5); /* tell modem to use short status codes */
gobble("\r");
gobble("\r");
write(FD, "ATTD", 4); /* send dial command */
write(FD, num, strlen(num));
state = DIALING;
write(FD, "\r", 1);
connected = 0;
if (gobble("\r")) {
if ((dummy = gobble("01234")) != '1')
error_rep(dummy);
else
connected = 1;
}
if (connected)
state = CONNECTED;
else {
state = FAILED;
return (connected); /* lets get out of here.. */
}
ioctl(FD, TIOCFLUSH, 0);
#ifdef ACULOG
if (timeout) {
sprintf(line, "%d second dial timeout",
number(value(DIALTIMEOUT)));
logent(value(HOST), num, "hayes", line);
}
#endif
if (timeout)
hay_disconnect(); /* insurance */
return (connected);
}
hay_disconnect()
{
char c;
int len, rlen;
/* first hang up the modem*/
#ifdef DEBUG
printf("\rdisconnecting modem....\n\r");
#endif
ioctl(FD, TIOCCDTR, 0);
sleep(1);
ioctl(FD, TIOCSDTR, 0);
goodbye();
}
hay_abort()
{
char c;
write(FD, "\r", 1); /* send anything to abort the call */
hay_disconnect();
}
static void
sigALRM()
{
printf("\07timeout waiting for reply\n\r");
timeout = 1;
longjmp(timeoutbuf, 1);
}
static char
gobble(match)
register char *match;
{
char c;
sig_t f;
int i, status = 0;
f = signal(SIGALRM, sigALRM);
timeout = 0;
#ifdef DEBUG
printf("\ngobble: waiting for %s\n", match);
#endif
do {
if (setjmp(timeoutbuf)) {
signal(SIGALRM, f);
return (0);
}
alarm(number(value(DIALTIMEOUT)));
read(FD, &c, 1);
alarm(0);
c &= 0177;
#ifdef DEBUG
printf("%c 0x%x ", c, c);
#endif
for (i = 0; i < strlen(match); i++)
if (c == match[i])
status = c;
} while (status == 0);
signal(SIGALRM, SIG_DFL);
#ifdef DEBUG
printf("\n");
#endif
return (status);
}
error_rep(c)
register char c;
{
printf("\n\r");
switch (c) {
case '0':
printf("OK");
break;
case '1':
printf("CONNECT");
break;
case '2':
printf("RING");
break;
case '3':
printf("NO CARRIER");
break;
case '4':
printf("ERROR in input");
break;
case '5':
printf("CONNECT 1200");
break;
default:
printf("Unknown Modem error: %c (0x%x)", c, c);
}
printf("\n\r");
return;
}
/*
* set modem back to normal verbose status codes.
*/
goodbye()
{
int len, rlen;
char c;
ioctl(FD, TIOCFLUSH, &len); /* get rid of trash */
if (hay_sync()) {
sleep(1);
#ifndef DEBUG
ioctl(FD, TIOCFLUSH, 0);
#endif
write(FD, "ATH0\r", 5); /* insurance */
#ifndef DEBUG
c = gobble("03");
if (c != '0' && c != '3') {
printf("cannot hang up modem\n\r");
printf("please use 'tip dialer' to make sure the line is hung up\n\r");
}
#endif
sleep(1);
ioctl(FD, FIONREAD, &len);
#ifdef DEBUG
printf("goodbye1: len=%d -- ", len);
rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
dumbuf[rlen] = '\0';
printf("read (%d): %s\r\n", rlen, dumbuf);
#endif
write(FD, "ATv1\r", 5);
sleep(1);
#ifdef DEBUG
ioctl(FD, FIONREAD, &len);
printf("goodbye2: len=%d -- ", len);
rlen = read(FD, dumbuf, min(len, DUMBUFLEN));
dumbuf[rlen] = '\0';
printf("read (%d): %s\r\n", rlen, dumbuf);
#endif
}
ioctl(FD, TIOCFLUSH, 0); /* clear the input buffer */
ioctl(FD, TIOCCDTR, 0); /* clear DTR (insurance) */
close(FD);
}
#define MAXRETRY 5
hay_sync()
{
int len, retry = 0;
while (retry++ <= MAXRETRY) {
write(FD, "AT\r", 3);
sleep(1);
ioctl(FD, FIONREAD, &len);
if (len) {
len = read(FD, dumbuf, min(len, DUMBUFLEN));
if (index(dumbuf, '0') ||
(index(dumbuf, 'O') && index(dumbuf, 'K')))
return(1);
#ifdef DEBUG
dumbuf[len] = '\0';
printf("hay_sync: (\"%s\") %d\n\r", dumbuf, retry);
#endif
}
ioctl(FD, TIOCCDTR, 0);
ioctl(FD, TIOCSDTR, 0);
}
printf("Cannot synchronize with hayes...\n\r");
return(0);
}

408
usr.bin/tip/aculib/t3000.c Normal file
View File

@ -0,0 +1,408 @@
/*
* Copyright (c) 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 sccsid[] = "@(#)t3000.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for calling up on a Telebit T3000 modem.
* Derived from Courier driver.
*/
#include "tip.h"
#include <stdio.h>
#define MAXRETRY 5
static void sigALRM();
static int timeout = 0;
static int connected = 0;
static jmp_buf timeoutbuf, intbuf;
static int t3000_sync();
t3000_dialer(num, acu)
register char *num;
char *acu;
{
register char *cp;
#ifdef ACULOG
char line[80];
#endif
static int t3000_connect(), t3000_swallow();
if (boolean(value(VERBOSE)))
printf("Using \"%s\"\n", acu);
ioctl(FD, TIOCHPCL, 0);
/*
* Get in synch.
*/
if (!t3000_sync()) {
badsynch:
printf("can't synchronize with t3000\n");
#ifdef ACULOG
logent(value(HOST), num, "t3000", "can't synch up");
#endif
return (0);
}
t3000_write(FD, "AT E0\r", 6); /* turn off echoing */
sleep(1);
#ifdef DEBUG
if (boolean(value(VERBOSE)))
t3000_verbose_read();
#endif
ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
t3000_write(FD, "AT E0 H0 Q0 X4 V1\r", 18);
if (!t3000_swallow("\r\nOK\r\n"))
goto badsynch;
fflush(stdout);
t3000_write(FD, "AT D", 4);
for (cp = num; *cp; cp++)
if (*cp == '=')
*cp = ',';
t3000_write(FD, num, strlen(num));
t3000_write(FD, "\r", 1);
connected = t3000_connect();
#ifdef ACULOG
if (timeout) {
sprintf(line, "%d second dial timeout",
number(value(DIALTIMEOUT)));
logent(value(HOST), num, "t3000", line);
}
#endif
if (timeout)
t3000_disconnect();
return (connected);
}
t3000_disconnect()
{
/* first hang up the modem*/
ioctl(FD, TIOCCDTR, 0);
sleep(1);
ioctl(FD, TIOCSDTR, 0);
t3000_sync(); /* reset */
close(FD);
}
t3000_abort()
{
t3000_write(FD, "\r", 1); /* send anything to abort the call */
t3000_disconnect();
}
static void
sigALRM()
{
printf("\07timeout waiting for reply\n");
timeout = 1;
longjmp(timeoutbuf, 1);
}
static int
t3000_swallow(match)
register char *match;
{
sig_t f;
char c;
f = signal(SIGALRM, sigALRM);
timeout = 0;
do {
if (*match =='\0') {
signal(SIGALRM, f);
return (1);
}
if (setjmp(timeoutbuf)) {
signal(SIGALRM, f);
return (0);
}
alarm(number(value(DIALTIMEOUT)));
read(FD, &c, 1);
alarm(0);
c &= 0177;
#ifdef DEBUG
if (boolean(value(VERBOSE)))
putchar(c);
#endif
} while (c == *match++);
#ifdef DEBUG
if (boolean(value(VERBOSE)))
fflush(stdout);
#endif
signal(SIGALRM, SIG_DFL);
return (0);
}
#ifndef B19200 /* XXX */
#define B19200 EXTA
#define B38400 EXTB
#endif
struct tbaud_msg {
char *msg;
int baud;
int baud2;
} tbaud_msg[] = {
"", B300, 0,
" 1200", B1200, 0,
" 2400", B2400, 0,
" 4800", B4800, 0,
" 9600", B9600, 0,
" 14400", B19200, B9600,
" 19200", B19200, B9600,
" 38400", B38400, B9600,
" 57600", B38400, B9600,
" 7512", B9600, 0,
" 1275", B2400, 0,
" 7200", B9600, 0,
" 12000", B19200, B9600,
0, 0, 0,
};
static int
t3000_connect()
{
char c;
int nc, nl, n;
struct sgttyb sb;
char dialer_buf[64];
struct tbaud_msg *bm;
sig_t f;
if (t3000_swallow("\r\n") == 0)
return (0);
f = signal(SIGALRM, sigALRM);
again:
nc = 0; nl = sizeof(dialer_buf)-1;
bzero(dialer_buf, sizeof(dialer_buf));
timeout = 0;
for (nc = 0, nl = sizeof(dialer_buf)-1 ; nl > 0 ; nc++, nl--) {
if (setjmp(timeoutbuf))
break;
alarm(number(value(DIALTIMEOUT)));
n = read(FD, &c, 1);
alarm(0);
if (n <= 0)
break;
c &= 0x7f;
if (c == '\r') {
if (t3000_swallow("\n") == 0)
break;
if (!dialer_buf[0])
goto again;
if (strcmp(dialer_buf, "RINGING") == 0 &&
boolean(value(VERBOSE))) {
#ifdef DEBUG
printf("%s\r\n", dialer_buf);
#endif
goto again;
}
if (strncmp(dialer_buf, "CONNECT",
sizeof("CONNECT")-1) != 0)
break;
for (bm = tbaud_msg ; bm->msg ; bm++)
if (strcmp(bm->msg,
dialer_buf+sizeof("CONNECT")-1) == 0) {
if (ioctl(FD, TIOCGETP, &sb) < 0) {
perror("TIOCGETP");
goto error;
}
sb.sg_ispeed = sb.sg_ospeed = bm->baud;
if (ioctl(FD, TIOCSETP, &sb) < 0) {
if (bm->baud2) {
sb.sg_ispeed =
sb.sg_ospeed =
bm->baud2;
if (ioctl(FD,
TIOCSETP,
&sb) >= 0)
goto isok;
}
perror("TIOCSETP");
goto error;
}
isok:
signal(SIGALRM, f);
#ifdef DEBUG
if (boolean(value(VERBOSE)))
printf("%s\r\n", dialer_buf);
#endif
return (1);
}
break;
}
dialer_buf[nc] = c;
#ifdef notdef
if (boolean(value(VERBOSE)))
putchar(c);
#endif
}
error1:
printf("%s\r\n", dialer_buf);
error:
signal(SIGALRM, f);
return (0);
}
/*
* This convoluted piece of code attempts to get
* the t3000 in sync.
*/
static int
t3000_sync()
{
int already = 0;
int len;
char buf[40];
while (already++ < MAXRETRY) {
ioctl(FD, TIOCFLUSH, 0); /* flush any clutter */
t3000_write(FD, "\rAT Z\r", 6); /* reset modem */
bzero(buf, sizeof(buf));
sleep(2);
ioctl(FD, FIONREAD, &len);
#if 1
if (len == 0) len = 1;
#endif
if (len) {
len = read(FD, buf, sizeof(buf));
#ifdef DEBUG
buf[len] = '\0';
printf("t3000_sync: (\"%s\")\n\r", buf);
#endif
if (index(buf, '0') ||
(index(buf, 'O') && index(buf, 'K')))
return(1);
}
/*
* If not strapped for DTR control,
* try to get command mode.
*/
sleep(1);
t3000_write(FD, "+++", 3);
sleep(1);
/*
* Toggle DTR to force anyone off that might have left
* the modem connected.
*/
ioctl(FD, TIOCCDTR, 0);
sleep(1);
ioctl(FD, TIOCSDTR, 0);
}
t3000_write(FD, "\rAT Z\r", 6);
return (0);
}
t3000_write(fd, cp, n)
int fd;
char *cp;
int n;
{
struct sgttyb sb;
#ifdef notdef
if (boolean(value(VERBOSE)))
write(1, cp, n);
#endif
ioctl(fd, TIOCGETP, &sb);
ioctl(fd, TIOCSETP, &sb);
t3000_nap();
for ( ; n-- ; cp++) {
write(fd, cp, 1);
ioctl(fd, TIOCGETP, &sb);
ioctl(fd, TIOCSETP, &sb);
t3000_nap();
}
}
#ifdef DEBUG
t3000_verbose_read()
{
int n = 0;
char buf[BUFSIZ];
if (ioctl(FD, FIONREAD, &n) < 0)
return;
if (n <= 0)
return;
if (read(FD, buf, n) != n)
return;
write(1, buf, n);
}
#endif
/*
* Code stolen from /usr/src/lib/libc/gen/sleep.c
*/
#define mask(s) (1<<((s)-1))
#define setvec(vec, a) \
vec.sv_handler = a; vec.sv_mask = vec.sv_onstack = 0
static napms = 50; /* Give the t3000 50 milliseconds between characters */
static int ringring;
t3000_nap()
{
static void t3000_napx();
int omask;
struct itimerval itv, oitv;
register struct itimerval *itp = &itv;
struct sigvec vec, ovec;
timerclear(&itp->it_interval);
timerclear(&itp->it_value);
if (setitimer(ITIMER_REAL, itp, &oitv) < 0)
return;
setvec(ovec, SIG_DFL);
omask = sigblock(mask(SIGALRM));
itp->it_value.tv_sec = napms/1000;
itp->it_value.tv_usec = ((napms%1000)*1000);
setvec(vec, t3000_napx);
ringring = 0;
(void) sigvec(SIGALRM, &vec, &ovec);
(void) setitimer(ITIMER_REAL, itp, (struct itimerval *)0);
while (!ringring)
sigpause(omask &~ mask(SIGALRM));
(void) sigvec(SIGALRM, &ovec, (struct sigvec *)0);
(void) setitimer(ITIMER_REAL, &oitv, (struct itimerval *)0);
(void) sigsetmask(omask);
}
static void
t3000_napx()
{
ringring = 1;
}

214
usr.bin/tip/aculib/v3451.c Normal file
View File

@ -0,0 +1,214 @@
/*
* Copyright (c) 1983, 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[] = "@(#)v3451.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for calling up on a Vadic 3451 Modem
*/
#include "tip.h"
static jmp_buf Sjbuf;
v3451_dialer(num, acu)
register char *num;
char *acu;
{
sig_t func;
int ok;
int slow = number(value(BAUDRATE)) < 1200, rw = 2;
char phone[50];
#ifdef ACULOG
char line[80];
#endif
static int expect();
static void vawrite();
/*
* Get in synch
*/
vawrite("I\r", 1 + slow);
vawrite("I\r", 1 + slow);
vawrite("I\r", 1 + slow);
vawrite("\005\r", 2 + slow);
if (!expect("READY")) {
printf("can't synchronize with vadic 3451\n");
#ifdef ACULOG
logent(value(HOST), num, "vadic", "can't synch up");
#endif
return (0);
}
ioctl(FD, TIOCHPCL, 0);
sleep(1);
vawrite("D\r", 2 + slow);
if (!expect("NUMBER?")) {
printf("Vadic will not accept dial command\n");
#ifdef ACULOG
logent(value(HOST), num, "vadic", "will not accept dial");
#endif
return (0);
}
strcpy(phone, num);
strcat(phone, "\r");
vawrite(phone, 1 + slow);
if (!expect(phone)) {
printf("Vadic will not accept phone number\n");
#ifdef ACULOG
logent(value(HOST), num, "vadic", "will not accept number");
#endif
return (0);
}
func = signal(SIGINT,SIG_IGN);
/*
* You cannot interrupt the Vadic when its dialing;
* even dropping DTR does not work (definitely a
* brain damaged design).
*/
vawrite("\r", 1 + slow);
vawrite("\r", 1 + slow);
if (!expect("DIALING:")) {
printf("Vadic failed to dial\n");
#ifdef ACULOG
logent(value(HOST), num, "vadic", "failed to dial");
#endif
return (0);
}
if (boolean(value(VERBOSE)))
printf("\ndialing...");
ok = expect("ON LINE");
signal(SIGINT, func);
if (!ok) {
printf("call failed\n");
#ifdef ACULOG
logent(value(HOST), num, "vadic", "call failed");
#endif
return (0);
}
ioctl(FD, TIOCFLUSH, &rw);
return (1);
}
v3451_disconnect()
{
close(FD);
}
v3451_abort()
{
close(FD);
}
static void
vawrite(cp, delay)
register char *cp;
int delay;
{
for (; *cp; sleep(delay), cp++)
write(FD, cp, 1);
}
static
expect(cp)
register char *cp;
{
char buf[300];
register char *rp = buf;
int timeout = 30, online = 0;
static int notin();
static void alarmtr();
if (strcmp(cp, "\"\"") == 0)
return (1);
*rp = 0;
/*
* If we are waiting for the Vadic to complete
* dialing and get a connection, allow more time
* Unfortunately, the Vadic times out 24 seconds after
* the last digit is dialed
*/
online = strcmp(cp, "ON LINE") == 0;
if (online)
timeout = number(value(DIALTIMEOUT));
signal(SIGALRM, alarmtr);
if (setjmp(Sjbuf))
return (0);
alarm(timeout);
while (notin(cp, buf) && rp < buf + sizeof (buf) - 1) {
if (online && notin("FAILED CALL", buf) == 0)
return (0);
if (read(FD, rp, 1) < 0) {
alarm(0);
return (0);
}
if (*rp &= 0177)
rp++;
*rp = '\0';
}
alarm(0);
return (1);
}
static void
alarmtr()
{
longjmp(Sjbuf, 1);
}
static int
notin(sh, lg)
char *sh, *lg;
{
static int prefix();
for (; *lg; lg++)
if (prefix(sh, lg))
return (0);
return (1);
}
static
prefix(s1, s2)
register char *s1, *s2;
{
register char c;
while ((c = *s1++) == *s2++)
if (c == '\0')
return (1);
return (c == '\0');
}

259
usr.bin/tip/aculib/v831.c Normal file
View File

@ -0,0 +1,259 @@
/*
* Copyright (c) 1983, 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[] = "@(#)v831.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for dialing up on Vadic 831
*/
#include "tip.h"
int v831_abort();
static void alarmtr();
extern int errno;
static jmp_buf jmpbuf;
static int child = -1;
v831_dialer(num, acu)
char *num, *acu;
{
int status, pid, connected = 1;
register int timelim;
static int dialit();
if (boolean(value(VERBOSE)))
printf("\nstarting call...");
#ifdef DEBUG
printf ("(acu=%s)\n", acu);
#endif
if ((AC = open(acu, O_RDWR)) < 0) {
if (errno == EBUSY)
printf("line busy...");
else
printf("acu open error...");
return (0);
}
if (setjmp(jmpbuf)) {
kill(child, SIGKILL);
close(AC);
return (0);
}
signal(SIGALRM, alarmtr);
timelim = 5 * strlen(num);
alarm(timelim < 30 ? 30 : timelim);
if ((child = fork()) == 0) {
/*
* ignore this stuff for aborts
*/
signal(SIGALRM, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
sleep(2);
exit(dialit(num, acu) != 'A');
}
/*
* open line - will return on carrier
*/
if ((FD = open(DV, O_RDWR)) < 0) {
#ifdef DEBUG
printf("(after open, errno=%d)\n", errno);
#endif
if (errno == EIO)
printf("lost carrier...");
else
printf("dialup line open failed...");
alarm(0);
kill(child, SIGKILL);
close(AC);
return (0);
}
alarm(0);
#ifdef notdef
ioctl(AC, TIOCHPCL, 0);
#endif
signal(SIGALRM, SIG_DFL);
while ((pid = wait(&status)) != child && pid != -1)
;
if (status) {
close(AC);
return (0);
}
return (1);
}
static void
alarmtr()
{
alarm(0);
longjmp(jmpbuf, 1);
}
/*
* Insurance, for some reason we don't seem to be
* hanging up...
*/
v831_disconnect()
{
struct sgttyb cntrl;
sleep(2);
#ifdef DEBUG
printf("[disconnect: FD=%d]\n", FD);
#endif
if (FD > 0) {
ioctl(FD, TIOCCDTR, 0);
ioctl(FD, TIOCGETP, &cntrl);
cntrl.sg_ispeed = cntrl.sg_ospeed = 0;
ioctl(FD, TIOCSETP, &cntrl);
ioctl(FD, TIOCNXCL, (struct sgttyb *)NULL);
}
close(FD);
}
v831_abort()
{
#ifdef DEBUG
printf("[abort: AC=%d]\n", AC);
#endif
sleep(2);
if (child > 0)
kill(child, SIGKILL);
if (AC > 0)
ioctl(FD, TIOCNXCL, (struct sgttyb *)NULL);
close(AC);
if (FD > 0)
ioctl(FD, TIOCCDTR, 0);
close(FD);
}
/*
* Sigh, this probably must be changed at each site.
*/
struct vaconfig {
char *vc_name;
char vc_rack;
char vc_modem;
} vaconfig[] = {
{ "/dev/cua0",'4','0' },
{ "/dev/cua1",'4','1' },
{ 0 }
};
#define pc(x) (c = x, write(AC,&c,1))
#define ABORT 01
#define SI 017
#define STX 02
#define ETX 03
static int
dialit(phonenum, acu)
register char *phonenum;
char *acu;
{
register struct vaconfig *vp;
struct sgttyb cntrl;
char c;
int i, two = 2;
static char *sanitize();
phonenum = sanitize(phonenum);
#ifdef DEBUG
printf ("(dial phonenum=%s)\n", phonenum);
#endif
if (*phonenum == '<' && phonenum[1] == 0)
return ('Z');
for (vp = vaconfig; vp->vc_name; vp++)
if (strcmp(vp->vc_name, acu) == 0)
break;
if (vp->vc_name == 0) {
printf("Unable to locate dialer (%s)\n", acu);
return ('K');
}
ioctl(AC, TIOCGETP, &cntrl);
cntrl.sg_ispeed = cntrl.sg_ospeed = B2400;
cntrl.sg_flags = RAW | EVENP | ODDP;
ioctl(AC, TIOCSETP, &cntrl);
ioctl(AC, TIOCFLUSH, &two);
pc(STX);
pc(vp->vc_rack);
pc(vp->vc_modem);
while (*phonenum && *phonenum != '<')
pc(*phonenum++);
pc(SI);
pc(ETX);
sleep(1);
i = read(AC, &c, 1);
#ifdef DEBUG
printf("read %d chars, char=%c, errno %d\n", i, c, errno);
#endif
if (i != 1)
c = 'M';
if (c == 'B' || c == 'G') {
char cc, oc = c;
pc(ABORT);
read(AC, &cc, 1);
#ifdef DEBUG
printf("abort response=%c\n", cc);
#endif
c = oc;
v831_disconnect();
}
close(AC);
#ifdef DEBUG
printf("dialit: returns %c\n", c);
#endif
return (c);
}
static char *
sanitize(s)
register char *s;
{
static char buf[128];
register char *cp;
for (cp = buf; *s; s++) {
if (!isdigit(*s) && *s == '<' && *s != '_')
continue;
if (*s == '_')
*s = '=';
*cp++ = *s;
}
*cp++ = 0;
return (buf);
}

251
usr.bin/tip/aculib/ventel.c Normal file
View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 1983, 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[] = "@(#)ventel.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Routines for calling up on a Ventel Modem
* The Ventel is expected to be strapped for local echo (just like uucp)
*/
#include "tip.h"
#define MAXRETRY 5
static void sigALRM();
static int timeout = 0;
static jmp_buf timeoutbuf;
/*
* some sleep calls have been replaced by this macro
* because some ventel modems require two <cr>s in less than
* a second in order to 'wake up'... yes, it is dirty...
*/
#define delay(num,denom) busyloop(CPUSPEED*num/denom)
#define CPUSPEED 1000000 /* VAX 780 is 1MIPS */
#define DELAY(n) { register long N = (n); while (--N > 0); }
busyloop(n) { DELAY(n); }
ven_dialer(num, acu)
register char *num;
char *acu;
{
register char *cp;
register int connected = 0;
char *msg, *index(), line[80];
static int gobble(), vensync();
static void echo();
/*
* Get in synch with a couple of carriage returns
*/
if (!vensync(FD)) {
printf("can't synchronize with ventel\n");
#ifdef ACULOG
logent(value(HOST), num, "ventel", "can't synch up");
#endif
return (0);
}
if (boolean(value(VERBOSE)))
printf("\ndialing...");
fflush(stdout);
ioctl(FD, TIOCHPCL, 0);
echo("#k$\r$\n$D$I$A$L$:$ ");
for (cp = num; *cp; cp++) {
delay(1, 10);
write(FD, cp, 1);
}
delay(1, 10);
write(FD, "\r", 1);
gobble('\n', line);
if (gobble('\n', line))
connected = gobble('!', line);
ioctl(FD, TIOCFLUSH);
#ifdef ACULOG
if (timeout) {
sprintf(line, "%d second dial timeout",
number(value(DIALTIMEOUT)));
logent(value(HOST), num, "ventel", line);
}
#endif
if (timeout)
ven_disconnect(); /* insurance */
if (connected || timeout || !boolean(value(VERBOSE)))
return (connected);
/* call failed, parse response for user */
cp = index(line, '\r');
if (cp)
*cp = '\0';
for (cp = line; cp = index(cp, ' '); cp++)
if (cp[1] == ' ')
break;
if (cp) {
while (*cp == ' ')
cp++;
msg = cp;
while (*cp) {
if (isupper(*cp))
*cp = tolower(*cp);
cp++;
}
printf("%s...", msg);
}
return (connected);
}
ven_disconnect()
{
close(FD);
}
ven_abort()
{
write(FD, "\03", 1);
close(FD);
}
static void
echo(s)
register char *s;
{
char c;
while (c = *s++) switch (c) {
case '$':
read(FD, &c, 1);
s++;
break;
case '#':
c = *s++;
write(FD, &c, 1);
break;
default:
write(FD, &c, 1);
read(FD, &c, 1);
}
}
static void
sigALRM()
{
printf("\07timeout waiting for reply\n");
timeout = 1;
longjmp(timeoutbuf, 1);
}
static int
gobble(match, response)
register char match;
char response[];
{
register char *cp = response;
sig_t f;
char c;
f = signal(SIGALRM, sigALRM);
timeout = 0;
do {
if (setjmp(timeoutbuf)) {
signal(SIGALRM, f);
*cp = '\0';
return (0);
}
alarm(number(value(DIALTIMEOUT)));
read(FD, cp, 1);
alarm(0);
c = (*cp++ &= 0177);
#ifdef notdef
if (boolean(value(VERBOSE)))
putchar(c);
#endif
} while (c != '\n' && c != match);
signal(SIGALRM, SIG_DFL);
*cp = '\0';
return (c == match);
}
#define min(a,b) ((a)>(b)?(b):(a))
/*
* This convoluted piece of code attempts to get
* the ventel in sync. If you don't have FIONREAD
* there are gory ways to simulate this.
*/
static int
vensync(fd)
{
int already = 0, nread;
char buf[60];
/*
* Toggle DTR to force anyone off that might have left
* the modem connected, and insure a consistent state
* to start from.
*
* If you don't have the ioctl calls to diddle directly
* with DTR, you can always try setting the baud rate to 0.
*/
ioctl(FD, TIOCCDTR, 0);
sleep(1);
ioctl(FD, TIOCSDTR, 0);
while (already < MAXRETRY) {
/*
* After reseting the modem, send it two \r's to
* autobaud on. Make sure to delay between them
* so the modem can frame the incoming characters.
*/
write(fd, "\r", 1);
delay(1,10);
write(fd, "\r", 1);
sleep(2);
if (ioctl(fd, FIONREAD, (caddr_t)&nread) < 0) {
perror("tip: ioctl");
continue;
}
while (nread > 0) {
read(fd, buf, min(nread, 60));
if ((buf[nread - 1] & 0177) == '$')
return (1);
nread -= min(nread, 60);
}
sleep(1);
already++;
}
return (0);
}

97
usr.bin/tip/acutab.c Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 1983, 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[] = "@(#)acutab.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
extern int df02_dialer(), df03_dialer(), df_disconnect(), df_abort(),
biz31f_dialer(), biz31_disconnect(), biz31_abort(),
biz31w_dialer(),
biz22f_dialer(), biz22_disconnect(), biz22_abort(),
biz22w_dialer(),
ven_dialer(), ven_disconnect(), ven_abort(),
hay_dialer(), hay_disconnect(), hay_abort(),
cour_dialer(), cour_disconnect(), cour_abort(),
t3000_dialer(), t3000_disconnect(), t3000_abort(),
v3451_dialer(), v3451_disconnect(), v3451_abort(),
v831_dialer(), v831_disconnect(), v831_abort(),
dn_dialer(), dn_disconnect(), dn_abort();
acu_t acutable[] = {
#if BIZ1031
"biz31f", biz31f_dialer, biz31_disconnect, biz31_abort,
"biz31w", biz31w_dialer, biz31_disconnect, biz31_abort,
#endif
#if BIZ1022
"biz22f", biz22f_dialer, biz22_disconnect, biz22_abort,
"biz22w", biz22w_dialer, biz22_disconnect, biz22_abort,
#endif
#if DF02
"df02", df02_dialer, df_disconnect, df_abort,
#endif
#if DF03
"df03", df03_dialer, df_disconnect, df_abort,
#endif
#if DN11
"dn11", dn_dialer, dn_disconnect, dn_abort,
#endif
#ifdef VENTEL
"ventel",ven_dialer, ven_disconnect, ven_abort,
#endif
#ifdef HAYES
"hayes",hay_dialer, hay_disconnect, hay_abort,
#endif
#ifdef COURIER
"courier",cour_dialer, cour_disconnect, cour_abort,
#endif
#ifdef T3000
"t3000",t3000_dialer, t3000_disconnect, t3000_abort,
#endif
#ifdef V3451
#ifndef V831
"vadic",v3451_dialer, v3451_disconnect, v3451_abort,
#endif
"v3451",v3451_dialer, v3451_disconnect, v3451_abort,
#endif
#ifdef V831
#ifndef V3451
"vadic",v831_dialer, v831_disconnect, v831_abort,
#endif
"v831",v831_dialer, v831_disconnect, v831_abort,
#endif
0, 0, 0, 0
};

888
usr.bin/tip/cmds.c Normal file
View File

@ -0,0 +1,888 @@
/*
* Copyright (c) 1983, 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[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
#include "pathnames.h"
/*
* tip
*
* miscellaneous commands
*/
int quant[] = { 60, 60, 24 };
char null = '\0';
char *sep[] = { "second", "minute", "hour" };
static char *argv[10]; /* argument vector for take and put */
void timeout(); /* timeout function called on alarm */
void stopsnd(); /* SIGINT handler during file transfers */
void intcopy(); /* interrupt routine for file transfers */
/*
* FTP - remote ==> local
* get a file from the remote host
*/
getfl(c)
char c;
{
char buf[256], *cp, *expand();
putchar(c);
/*
* get the UNIX receiving file's name
*/
if (prompt("Local file name? ", copyname))
return;
cp = expand(copyname);
if ((sfd = creat(cp, 0666)) < 0) {
printf("\r\n%s: cannot creat\r\n", copyname);
return;
}
/*
* collect parameters
*/
if (prompt("List command for remote system? ", buf)) {
unlink(copyname);
return;
}
transfer(buf, sfd, value(EOFREAD));
}
/*
* Cu-like take command
*/
cu_take(cc)
char cc;
{
int fd, argc;
char line[BUFSIZ], *expand(), *cp;
if (prompt("[take] ", copyname))
return;
if ((argc = args(copyname, argv)) < 1 || argc > 2) {
printf("usage: <take> from [to]\r\n");
return;
}
if (argc == 1)
argv[1] = argv[0];
cp = expand(argv[1]);
if ((fd = creat(cp, 0666)) < 0) {
printf("\r\n%s: cannot create\r\n", argv[1]);
return;
}
sprintf(line, "cat %s;echo \01", argv[0]);
transfer(line, fd, "\01");
}
static jmp_buf intbuf;
/*
* Bulk transfer routine --
* used by getfl(), cu_take(), and pipefile()
*/
transfer(buf, fd, eofchars)
char *buf, *eofchars;
{
register int ct;
char c, buffer[BUFSIZ];
register char *p = buffer;
register int cnt, eof;
time_t start;
sig_t f;
char r;
pwrite(FD, buf, size(buf));
quit = 0;
kill(pid, SIGIOT);
read(repdes[0], (char *)&ccc, 1); /* Wait until read process stops */
/*
* finish command
*/
r = '\r';
pwrite(FD, &r, 1);
do
read(FD, &c, 1);
while ((c&0177) != '\n');
ioctl(0, TIOCSETC, &defchars);
(void) setjmp(intbuf);
f = signal(SIGINT, intcopy);
start = time(0);
for (ct = 0; !quit;) {
eof = read(FD, &c, 1) <= 0;
c &= 0177;
if (quit)
continue;
if (eof || any(c, eofchars))
break;
if (c == 0)
continue; /* ignore nulls */
if (c == '\r')
continue;
*p++ = c;
if (c == '\n' && boolean(value(VERBOSE)))
printf("\r%d", ++ct);
if ((cnt = (p-buffer)) == number(value(FRAMESIZE))) {
if (write(fd, buffer, cnt) != cnt) {
printf("\r\nwrite error\r\n");
quit = 1;
}
p = buffer;
}
}
if (cnt = (p-buffer))
if (write(fd, buffer, cnt) != cnt)
printf("\r\nwrite error\r\n");
if (boolean(value(VERBOSE)))
prtime(" lines transferred in ", time(0)-start);
ioctl(0, TIOCSETC, &tchars);
write(fildes[1], (char *)&ccc, 1);
signal(SIGINT, f);
close(fd);
}
/*
* FTP - remote ==> local process
* send remote input to local process via pipe
*/
pipefile()
{
int cpid, pdes[2];
char buf[256];
int status, p;
extern int errno;
if (prompt("Local command? ", buf))
return;
if (pipe(pdes)) {
printf("can't establish pipe\r\n");
return;
}
if ((cpid = fork()) < 0) {
printf("can't fork!\r\n");
return;
} else if (cpid) {
if (prompt("List command for remote system? ", buf)) {
close(pdes[0]), close(pdes[1]);
kill (cpid, SIGKILL);
} else {
close(pdes[0]);
signal(SIGPIPE, intcopy);
transfer(buf, pdes[1], value(EOFREAD));
signal(SIGPIPE, SIG_DFL);
while ((p = wait(&status)) > 0 && p != cpid)
;
}
} else {
register int f;
dup2(pdes[0], 0);
close(pdes[0]);
for (f = 3; f < 20; f++)
close(f);
execute(buf);
printf("can't execl!\r\n");
exit(0);
}
}
/*
* Interrupt service routine for FTP
*/
void
stopsnd()
{
stop = 1;
signal(SIGINT, SIG_IGN);
}
/*
* FTP - local ==> remote
* send local file to remote host
* terminate transmission with pseudo EOF sequence
*/
sendfile(cc)
char cc;
{
FILE *fd;
char *fnamex;
char *expand();
putchar(cc);
/*
* get file name
*/
if (prompt("Local file name? ", fname))
return;
/*
* look up file
*/
fnamex = expand(fname);
if ((fd = fopen(fnamex, "r")) == NULL) {
printf("%s: cannot open\r\n", fname);
return;
}
transmit(fd, value(EOFWRITE), NULL);
if (!boolean(value(ECHOCHECK))) {
struct sgttyb buf;
ioctl(FD, TIOCGETP, &buf); /* this does a */
ioctl(FD, TIOCSETP, &buf); /* wflushtty */
}
}
/*
* Bulk transfer routine to remote host --
* used by sendfile() and cu_put()
*/
transmit(fd, eofchars, command)
FILE *fd;
char *eofchars, *command;
{
char *pc, lastc;
int c, ccount, lcount;
time_t start_t, stop_t;
sig_t f;
kill(pid, SIGIOT); /* put TIPOUT into a wait state */
stop = 0;
f = signal(SIGINT, stopsnd);
ioctl(0, TIOCSETC, &defchars);
read(repdes[0], (char *)&ccc, 1);
if (command != NULL) {
for (pc = command; *pc; pc++)
send(*pc);
if (boolean(value(ECHOCHECK)))
read(FD, (char *)&c, 1); /* trailing \n */
else {
struct sgttyb buf;
ioctl(FD, TIOCGETP, &buf); /* this does a */
ioctl(FD, TIOCSETP, &buf); /* wflushtty */
sleep(5); /* wait for remote stty to take effect */
}
}
lcount = 0;
lastc = '\0';
start_t = time(0);
while (1) {
ccount = 0;
do {
c = getc(fd);
if (stop)
goto out;
if (c == EOF)
goto out;
if (c == 0177 && !boolean(value(RAWFTP)))
continue;
lastc = c;
if (c < 040) {
if (c == '\n') {
if (!boolean(value(RAWFTP)))
c = '\r';
}
else if (c == '\t') {
if (!boolean(value(RAWFTP))) {
if (boolean(value(TABEXPAND))) {
send(' ');
while ((++ccount % 8) != 0)
send(' ');
continue;
}
}
} else
if (!boolean(value(RAWFTP)))
continue;
}
send(c);
} while (c != '\r' && !boolean(value(RAWFTP)));
if (boolean(value(VERBOSE)))
printf("\r%d", ++lcount);
if (boolean(value(ECHOCHECK))) {
timedout = 0;
alarm((int)value(ETIMEOUT));
do { /* wait for prompt */
read(FD, (char *)&c, 1);
if (timedout || stop) {
if (timedout)
printf("\r\ntimed out at eol\r\n");
alarm(0);
goto out;
}
} while ((c&0177) != character(value(PROMPT)));
alarm(0);
}
}
out:
if (lastc != '\n' && !boolean(value(RAWFTP)))
send('\r');
for (pc = eofchars; *pc; pc++)
send(*pc);
stop_t = time(0);
fclose(fd);
signal(SIGINT, f);
if (boolean(value(VERBOSE)))
if (boolean(value(RAWFTP)))
prtime(" chars transferred in ", stop_t-start_t);
else
prtime(" lines transferred in ", stop_t-start_t);
write(fildes[1], (char *)&ccc, 1);
ioctl(0, TIOCSETC, &tchars);
}
/*
* Cu-like put command
*/
cu_put(cc)
char cc;
{
FILE *fd;
char line[BUFSIZ];
int argc;
char *expand();
char *copynamex;
if (prompt("[put] ", copyname))
return;
if ((argc = args(copyname, argv)) < 1 || argc > 2) {
printf("usage: <put> from [to]\r\n");
return;
}
if (argc == 1)
argv[1] = argv[0];
copynamex = expand(argv[0]);
if ((fd = fopen(copynamex, "r")) == NULL) {
printf("%s: cannot open\r\n", copynamex);
return;
}
if (boolean(value(ECHOCHECK)))
sprintf(line, "cat>%s\r", argv[1]);
else
sprintf(line, "stty -echo;cat>%s;stty echo\r", argv[1]);
transmit(fd, "\04", line);
}
/*
* FTP - send single character
* wait for echo & handle timeout
*/
send(c)
char c;
{
char cc;
int retry = 0;
cc = c;
pwrite(FD, &cc, 1);
#ifdef notdef
if (number(value(CDELAY)) > 0 && c != '\r')
nap(number(value(CDELAY)));
#endif
if (!boolean(value(ECHOCHECK))) {
#ifdef notdef
if (number(value(LDELAY)) > 0 && c == '\r')
nap(number(value(LDELAY)));
#endif
return;
}
tryagain:
timedout = 0;
alarm((int)value(ETIMEOUT));
read(FD, &cc, 1);
alarm(0);
if (timedout) {
printf("\r\ntimeout error (%s)\r\n", ctrl(c));
if (retry++ > 3)
return;
pwrite(FD, &null, 1); /* poke it */
goto tryagain;
}
}
void
timeout()
{
signal(SIGALRM, timeout);
timedout = 1;
}
/*
* Stolen from consh() -- puts a remote file on the output of a local command.
* Identical to consh() except for where stdout goes.
*/
pipeout(c)
{
char buf[256];
int cpid, status, p;
time_t start;
putchar(c);
if (prompt("Local command? ", buf))
return;
kill(pid, SIGIOT); /* put TIPOUT into a wait state */
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
ioctl(0, TIOCSETC, &defchars);
read(repdes[0], (char *)&ccc, 1);
/*
* Set up file descriptors in the child and
* let it go...
*/
if ((cpid = fork()) < 0)
printf("can't fork!\r\n");
else if (cpid) {
start = time(0);
while ((p = wait(&status)) > 0 && p != cpid)
;
} else {
register int i;
dup2(FD, 1);
for (i = 3; i < 20; i++)
close(i);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
execute(buf);
printf("can't find `%s'\r\n", buf);
exit(0);
}
if (boolean(value(VERBOSE)))
prtime("away for ", time(0)-start);
write(fildes[1], (char *)&ccc, 1);
ioctl(0, TIOCSETC, &tchars);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
}
#ifdef CONNECT
/*
* Fork a program with:
* 0 <-> remote tty in
* 1 <-> remote tty out
* 2 <-> local tty out
*/
consh(c)
{
char buf[256];
int cpid, status, p;
time_t start;
putchar(c);
if (prompt("Local command? ", buf))
return;
kill(pid, SIGIOT); /* put TIPOUT into a wait state */
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
ioctl(0, TIOCSETC, &defchars);
read(repdes[0], (char *)&ccc, 1);
/*
* Set up file descriptors in the child and
* let it go...
*/
if ((cpid = fork()) < 0)
printf("can't fork!\r\n");
else if (cpid) {
start = time(0);
while ((p = wait(&status)) > 0 && p != cpid)
;
} else {
register int i;
dup2(FD, 0);
dup2(3, 1);
for (i = 3; i < 20; i++)
close(i);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
execute(buf);
printf("can't find `%s'\r\n", buf);
exit(0);
}
if (boolean(value(VERBOSE)))
prtime("away for ", time(0)-start);
write(fildes[1], (char *)&ccc, 1);
ioctl(0, TIOCSETC, &tchars);
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
}
#endif
/*
* Escape to local shell
*/
shell()
{
int shpid, status;
extern char **environ;
char *cp;
printf("[sh]\r\n");
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
unraw();
if (shpid = fork()) {
while (shpid != wait(&status));
raw();
printf("\r\n!\r\n");
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
return;
} else {
signal(SIGQUIT, SIG_DFL);
signal(SIGINT, SIG_DFL);
if ((cp = rindex(value(SHELL), '/')) == NULL)
cp = value(SHELL);
else
cp++;
shell_uid();
execl(value(SHELL), cp, 0);
printf("\r\ncan't execl!\r\n");
exit(1);
}
}
/*
* TIPIN portion of scripting
* initiate the conversation with TIPOUT
*/
setscript()
{
char c;
/*
* enable TIPOUT side for dialogue
*/
kill(pid, SIGEMT);
if (boolean(value(SCRIPT)))
write(fildes[1], value(RECORD), size(value(RECORD)));
write(fildes[1], "\n", 1);
/*
* wait for TIPOUT to finish
*/
read(repdes[0], &c, 1);
if (c == 'n')
printf("can't create %s\r\n", value(RECORD));
}
/*
* Change current working directory of
* local portion of tip
*/
chdirectory()
{
char dirname[80];
register char *cp = dirname;
if (prompt("[cd] ", dirname)) {
if (stoprompt)
return;
cp = value(HOME);
}
if (chdir(cp) < 0)
printf("%s: bad directory\r\n", cp);
printf("!\r\n");
}
tipabort(msg)
char *msg;
{
kill(pid, SIGTERM);
disconnect(msg);
if (msg != NOSTR)
printf("\r\n%s", msg);
printf("\r\n[EOT]\r\n");
daemon_uid();
(void)uu_unlock(uucplock);
unraw();
exit(0);
}
finish()
{
char *dismsg;
if ((dismsg = value(DISCONNECT)) != NOSTR) {
write(FD, dismsg, strlen(dismsg));
sleep(5);
}
tipabort(NOSTR);
}
void
intcopy()
{
raw();
quit = 1;
longjmp(intbuf, 1);
}
execute(s)
char *s;
{
register char *cp;
if ((cp = rindex(value(SHELL), '/')) == NULL)
cp = value(SHELL);
else
cp++;
shell_uid();
execl(value(SHELL), cp, "-c", s, 0);
}
args(buf, a)
char *buf, *a[];
{
register char *p = buf, *start;
register char **parg = a;
register int n = 0;
do {
while (*p && (*p == ' ' || *p == '\t'))
p++;
start = p;
if (*p)
*parg = p;
while (*p && (*p != ' ' && *p != '\t'))
p++;
if (p != start)
parg++, n++;
if (*p)
*p++ = '\0';
} while (*p);
return(n);
}
prtime(s, a)
char *s;
time_t a;
{
register i;
int nums[3];
for (i = 0; i < 3; i++) {
nums[i] = (int)(a % quant[i]);
a /= quant[i];
}
printf("%s", s);
while (--i >= 0)
if (nums[i] || i == 0 && nums[1] == 0 && nums[2] == 0)
printf("%d %s%c ", nums[i], sep[i],
nums[i] == 1 ? '\0' : 's');
printf("\r\n!\r\n");
}
variable()
{
char buf[256];
if (prompt("[set] ", buf))
return;
vlex(buf);
if (vtable[BEAUTIFY].v_access&CHANGED) {
vtable[BEAUTIFY].v_access &= ~CHANGED;
kill(pid, SIGSYS);
}
if (vtable[SCRIPT].v_access&CHANGED) {
vtable[SCRIPT].v_access &= ~CHANGED;
setscript();
/*
* So that "set record=blah script" doesn't
* cause two transactions to occur.
*/
if (vtable[RECORD].v_access&CHANGED)
vtable[RECORD].v_access &= ~CHANGED;
}
if (vtable[RECORD].v_access&CHANGED) {
vtable[RECORD].v_access &= ~CHANGED;
if (boolean(value(SCRIPT)))
setscript();
}
if (vtable[TAND].v_access&CHANGED) {
vtable[TAND].v_access &= ~CHANGED;
if (boolean(value(TAND)))
tandem("on");
else
tandem("off");
}
if (vtable[LECHO].v_access&CHANGED) {
vtable[LECHO].v_access &= ~CHANGED;
HD = boolean(value(LECHO));
}
if (vtable[PARITY].v_access&CHANGED) {
vtable[PARITY].v_access &= ~CHANGED;
setparity();
}
}
/*
* Turn tandem mode on or off for remote tty.
*/
tandem(option)
char *option;
{
struct sgttyb rmtty;
ioctl(FD, TIOCGETP, &rmtty);
if (strcmp(option,"on") == 0) {
rmtty.sg_flags |= TANDEM;
arg.sg_flags |= TANDEM;
} else {
rmtty.sg_flags &= ~TANDEM;
arg.sg_flags &= ~TANDEM;
}
ioctl(FD, TIOCSETP, &rmtty);
ioctl(0, TIOCSETP, &arg);
}
/*
* Send a break.
*/
genbrk()
{
ioctl(FD, TIOCSBRK, NULL);
sleep(1);
ioctl(FD, TIOCCBRK, NULL);
}
/*
* Suspend tip
*/
suspend(c)
char c;
{
unraw();
kill(c == CTRL('y') ? getpid() : 0, SIGTSTP);
raw();
}
/*
* expand a file name if it includes shell meta characters
*/
char *
expand(name)
char name[];
{
static char xname[BUFSIZ];
char cmdbuf[BUFSIZ];
register int pid, l, rc;
register char *cp, *Shell;
int s, pivec[2], (*sigint)();
if (!anyof(name, "~{[*?$`'\"\\"))
return(name);
/* sigint = signal(SIGINT, SIG_IGN); */
if (pipe(pivec) < 0) {
perror("pipe");
/* signal(SIGINT, sigint) */
return(name);
}
sprintf(cmdbuf, "echo %s", name);
if ((pid = vfork()) == 0) {
Shell = value(SHELL);
if (Shell == NOSTR)
Shell = _PATH_BSHELL;
close(pivec[0]);
close(1);
dup(pivec[1]);
close(pivec[1]);
close(2);
shell_uid();
execl(Shell, Shell, "-c", cmdbuf, 0);
_exit(1);
}
if (pid == -1) {
perror("fork");
close(pivec[0]);
close(pivec[1]);
return(NOSTR);
}
close(pivec[1]);
l = read(pivec[0], xname, BUFSIZ);
close(pivec[0]);
while (wait(&s) != pid);
;
s &= 0377;
if (s != 0 && s != SIGPIPE) {
fprintf(stderr, "\"Echo\" failed\n");
return(NOSTR);
}
if (l < 0) {
perror("read");
return(NOSTR);
}
if (l == 0) {
fprintf(stderr, "\"%s\": No match\n", name);
return(NOSTR);
}
if (l == BUFSIZ) {
fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
return(NOSTR);
}
xname[l] = 0;
for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
;
*++cp = '\0';
return(xname);
}
/*
* Are any of the characters in the two strings the same?
*/
anyof(s1, s2)
register char *s1, *s2;
{
register int c;
while (c = *s1++)
if (any(c, s2))
return(1);
return(0);
}

64
usr.bin/tip/cmdtab.c Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 1983, 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[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
extern int shell(), getfl(), sendfile(), chdirectory();
extern int finish(), help(), pipefile(), pipeout(), consh(), variable();
extern int cu_take(), cu_put(), dollar(), genbrk(), suspend();
esctable_t etable[] = {
{ '!', NORM, "shell", shell },
{ '<', NORM, "receive file from remote host", getfl },
{ '>', NORM, "send file to remote host", sendfile },
{ 't', NORM, "take file from remote UNIX", cu_take },
{ 'p', NORM, "put file to remote UNIX", cu_put },
{ '|', NORM, "pipe remote file", pipefile },
{ '$', NORM, "pipe local command to remote host", pipeout },
#ifdef CONNECT
{ 'C', NORM, "connect program to remote host",consh },
#endif
{ 'c', NORM, "change directory", chdirectory },
{ '.', NORM, "exit from tip", finish },
{CTRL('d'),NORM,"exit from tip", finish },
{CTRL('y'),NORM,"suspend tip (local+remote)", suspend },
{CTRL('z'),NORM,"suspend tip (local only)", suspend },
{ 's', NORM, "set variable", variable },
{ '?', NORM, "get this summary", help },
{ '#', NORM, "send break", genbrk },
{ 0, 0, 0 }
};

132
usr.bin/tip/cu.c Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 1983, 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[] = "@(#)cu.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
void cleanup();
/*
* Botch the interface to look like cu's
*/
cumain(argc, argv)
char *argv[];
{
register int i;
static char sbuf[12];
if (argc < 2) {
printf("usage: cu telno [-t] [-s speed] [-a acu] [-l line] [-#]\n");
exit(8);
}
CU = DV = NOSTR;
BR = DEFBR;
for (; argc > 1; argv++, argc--) {
if (argv[1][0] != '-')
PN = argv[1];
else switch (argv[1][1]) {
case 't':
HW = 1, DU = -1;
--argc;
continue;
case 'a':
CU = argv[2]; ++argv; --argc;
break;
case 's':
if (argc < 3 || speed(atoi(argv[2])) == 0) {
fprintf(stderr, "cu: unsupported speed %s\n",
argv[2]);
exit(3);
}
BR = atoi(argv[2]); ++argv; --argc;
break;
case 'l':
DV = argv[2]; ++argv; --argc;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (CU)
CU[strlen(CU)-1] = argv[1][1];
if (DV)
DV[strlen(DV)-1] = argv[1][1];
break;
default:
printf("Bad flag %s", argv[1]);
break;
}
}
signal(SIGINT, cleanup);
signal(SIGQUIT, cleanup);
signal(SIGHUP, cleanup);
signal(SIGTERM, cleanup);
/*
* The "cu" host name is used to define the
* attributes of the generic dialer.
*/
(void)sprintf(sbuf, "cu%d", BR);
if ((i = hunt(sbuf)) == 0) {
printf("all ports busy\n");
exit(3);
}
if (i == -1) {
printf("link down\n");
(void)uu_unlock(uucplock);
exit(3);
}
setbuf(stdout, NULL);
loginit();
user_uid();
vinit();
setparity("none");
boolean(value(VERBOSE)) = 0;
if (HW)
ttysetup(speed(BR));
if (connect()) {
printf("Connect failed\n");
daemon_uid();
(void)uu_unlock(uucplock);
exit(1);
}
if (!HW)
ttysetup(speed(BR));
}

93
usr.bin/tip/hunt.c Normal file
View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 1983, 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[] = "@(#)hunt.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
extern char *getremote();
extern char *rindex();
static jmp_buf deadline;
static int deadfl;
void
dead()
{
deadfl = 1;
longjmp(deadline, 1);
}
hunt(name)
char *name;
{
register char *cp;
sig_t f;
f = signal(SIGALRM, dead);
while (cp = getremote(name)) {
deadfl = 0;
uucplock = rindex(cp, '/')+1;
if (uu_lock(uucplock) < 0)
continue;
/*
* Straight through call units, such as the BIZCOMP,
* VADIC and the DF, must indicate they're hardwired in
* order to get an open file descriptor placed in FD.
* Otherwise, as for a DN-11, the open will have to
* be done in the "open" routine.
*/
if (!HW)
break;
if (setjmp(deadline) == 0) {
alarm(10);
FD = open(cp, O_RDWR);
}
alarm(0);
if (FD < 0) {
perror(cp);
deadfl = 1;
}
if (!deadfl) {
ioctl(FD, TIOCEXCL, 0);
ioctl(FD, TIOCHPCL, 0);
signal(SIGALRM, SIG_DFL);
return ((int)cp);
}
(void)uu_unlock(uucplock);
}
signal(SIGALRM, f);
return (deadfl ? -1 : (int)cp);
}

86
usr.bin/tip/log.c Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (c) 1983, 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[] = "@(#)log.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
#ifdef ACULOG
static FILE *flog = NULL;
/*
* Log file maintenance routines
*/
logent(group, num, acu, message)
char *group, *num, *acu, *message;
{
char *user, *timestamp;
struct passwd *pwd;
long t;
if (flog == NULL)
return;
if (flock(fileno(flog), LOCK_EX) < 0) {
perror("tip: flock");
return;
}
if ((user = getlogin()) == NOSTR)
if ((pwd = getpwuid(getuid())) == NOPWD)
user = "???";
else
user = pwd->pw_name;
t = time(0);
timestamp = ctime(&t);
timestamp[24] = '\0';
fprintf(flog, "%s (%s) <%s, %s, %s> %s\n",
user, timestamp, group,
#ifdef PRISTINE
"",
#else
num,
#endif
acu, message);
(void) fflush(flog);
(void) flock(fileno(flog), LOCK_UN);
}
loginit()
{
flog = fopen(value(LOG), "a");
if (flog == NULL)
fprintf(stderr, "can't open log file %s.\r\n", value(LOG));
}
#endif

58
usr.bin/tip/partab.c Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 1983, 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[] = "@(#)partab.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Even parity table for 0-0177
*/
char evenpartab[] = {
0000,0201,0202,0003,0204,0005,0006,0207,
0210,0011,0012,0213,0014,0215,0216,0017,
0220,0021,0022,0223,0024,0225,0226,0027,
0030,0231,0232,0033,0234,0035,0036,0237,
0240,0041,0042,0243,0044,0245,0246,0047,
0050,0251,0252,0053,0254,0055,0056,0257,
0060,0261,0262,0063,0264,0065,0066,0267,
0270,0071,0072,0273,0074,0275,0276,0077,
0300,0101,0102,0303,0104,0305,0306,0107,
0110,0311,0312,0113,0314,0115,0116,0317,
0120,0321,0322,0123,0324,0125,0126,0327,
0330,0131,0132,0333,0134,0335,0336,0137,
0140,0341,0342,0143,0344,0145,0146,0347,
0350,0151,0152,0353,0154,0355,0356,0157,
0360,0161,0162,0363,0164,0365,0366,0167,
0170,0371,0372,0173,0374,0175,0176,0377,
};

426
usr.bin/tip/remcap.c Normal file
View File

@ -0,0 +1,426 @@
/*
* Copyright (c) 1983, 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[] = "@(#)remcap.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* remcap - routines for dealing with the remote host data base
*
* derived from termcap
*/
#include <sys/types.h>
#include <fcntl.h>
#include <ctype.h>
#include <stdlib.h>
#include "pathnames.h"
#ifndef BUFSIZ
#define BUFSIZ 1024
#endif
#define MAXHOP 32 /* max number of tc= indirections */
#define tgetent rgetent
#define tnchktc rnchktc
#define tnamatch rnamatch
#define tgetnum rgetnum
#define tgetflag rgetflag
#define tgetstr rgetstr
#define E_TERMCAP RM = _PATH_REMOTE
#define V_TERMCAP "REMOTE"
#define V_TERM "HOST"
char *RM;
/*
* termcap - routines for dealing with the terminal capability data base
*
* BUG: Should use a "last" pointer in tbuf, so that searching
* for capabilities alphabetically would not be a n**2/2
* process when large numbers of capabilities are given.
* Note: If we add a last pointer now we will screw up the
* tc capability. We really should compile termcap.
*
* Essentially all the work here is scanning and decoding escapes
* in string capabilities. We don't use stdio because the editor
* doesn't, and because living w/o it is not hard.
*/
static char *tbuf;
static int hopcount; /* detect infinite loops in termcap, init 0 */
static char *tskip();
char *tgetstr();
static char *tdecode();
static char *remotefile;
/*
* Get an entry for terminal name in buffer bp,
* from the termcap file. Parse is very rudimentary;
* we just notice escaped newlines.
*/
tgetent(bp, name)
char *bp, *name;
{
char lbuf[BUFSIZ], *cp, *p;
int rc1, rc2;
remotefile = cp = getenv(V_TERMCAP);
if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) {
remotefile = cp = _PATH_REMOTE;
return (getent(bp, name, cp));
} else {
if ((rc1 = getent(bp, name, cp)) != 1)
*bp = '\0';
remotefile = cp = _PATH_REMOTE;
rc2 = getent(lbuf, name, cp);
if (rc1 != 1 && rc2 != 1)
return (rc2);
if (rc2 == 1) {
p = lbuf;
if (rc1 == 1)
while (*p++ != ':')
;
if (strlen(bp) + strlen(p) > BUFSIZ) {
write(2, "Remcap entry too long\n", 23);
return (-1);
}
strcat(bp, p);
}
tbuf = bp;
return (1);
}
}
getent(bp, name, cp)
char *bp, *name, *cp;
{
register int c;
register int i = 0, cnt = 0;
char ibuf[BUFSIZ], *cp2;
int tf;
tbuf = bp;
tf = 0;
/*
* TERMCAP can have one of two things in it. It can be the
* name of a file to use instead of /etc/termcap. In this
* case it better start with a "/". Or it can be an entry to
* use so we don't have to read the file. In this case it
* has to already have the newlines crunched out.
*/
if (cp && *cp) {
if (*cp!='/') {
cp2 = getenv(V_TERM);
if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
strcpy(bp,cp);
return (tnchktc());
} else
tf = open(E_TERMCAP, O_RDONLY);
} else
tf = open(RM = cp, O_RDONLY);
}
if (tf == 0)
tf = open(E_TERMCAP, O_RDONLY);
if (tf < 0)
return (-1);
for (;;) {
cp = bp;
for (;;) {
if (i == cnt) {
cnt = read(tf, ibuf, BUFSIZ);
if (cnt <= 0) {
close(tf);
return (0);
}
i = 0;
}
c = ibuf[i++];
if (c == '\n') {
if (cp > bp && cp[-1] == '\\') {
cp--;
continue;
}
break;
}
if (cp >= bp+BUFSIZ) {
write(2,"Remcap entry too long\n", 23);
break;
} else
*cp++ = c;
}
*cp = 0;
/*
* The real work for the match.
*/
if (tnamatch(name)) {
close(tf);
return (tnchktc());
}
}
}
/*
* tnchktc: check the last entry, see if it's tc=xxx. If so,
* recursively find xxx and append that entry (minus the names)
* to take the place of the tc=xxx entry. This allows termcap
* entries to say "like an HP2621 but doesn't turn on the labels".
* Note that this works because of the left to right scan.
*/
tnchktc()
{
register char *p, *q;
char tcname[16]; /* name of similar terminal */
char tcbuf[BUFSIZ];
char *holdtbuf = tbuf;
int l;
char *cp;
p = tbuf + strlen(tbuf) - 2; /* before the last colon */
while (*--p != ':')
if (p<tbuf) {
write(2, "Bad remcap entry\n", 18);
return (0);
}
p++;
/* p now points to beginning of last field */
if (p[0] != 't' || p[1] != 'c')
return (1);
strcpy(tcname, p+3);
q = tcname;
while (*q && *q != ':')
q++;
*q = 0;
if (++hopcount > MAXHOP) {
write(2, "Infinite tc= loop\n", 18);
return (0);
}
if (getent(tcbuf, tcname, remotefile) != 1) {
if (strcmp(remotefile, _PATH_REMOTE) == 0)
return (0);
else if (getent(tcbuf, tcname, _PATH_REMOTE) != 1)
return (0);
}
for (q = tcbuf; *q++ != ':'; )
;
l = p - holdtbuf + strlen(q);
if (l > BUFSIZ) {
write(2, "Remcap entry too long\n", 23);
q[BUFSIZ - (p-holdtbuf)] = 0;
}
strcpy(p, q);
tbuf = holdtbuf;
return (1);
}
/*
* Tnamatch deals with name matching. The first field of the termcap
* entry is a sequence of names separated by |'s, so we compare
* against each such name. The normal : terminator after the last
* name (before the first field) stops us.
*/
tnamatch(np)
char *np;
{
register char *Np, *Bp;
Bp = tbuf;
if (*Bp == '#')
return (0);
for (;;) {
for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
continue;
if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
return (1);
while (*Bp && *Bp != ':' && *Bp != '|')
Bp++;
if (*Bp == 0 || *Bp == ':')
return (0);
Bp++;
}
}
/*
* Skip to the next field. Notice that this is very dumb, not
* knowing about \: escapes or any such. If necessary, :'s can be put
* into the termcap file in octal.
*/
static char *
tskip(bp)
register char *bp;
{
while (*bp && *bp != ':')
bp++;
if (*bp == ':')
bp++;
return (bp);
}
/*
* Return the (numeric) option id.
* Numeric options look like
* li#80
* i.e. the option string is separated from the numeric value by
* a # character. If the option is not found we return -1.
* Note that we handle octal numbers beginning with 0.
*/
tgetnum(id)
char *id;
{
register int i, base;
register char *bp = tbuf;
for (;;) {
bp = tskip(bp);
if (*bp == 0)
return (-1);
if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
continue;
if (*bp == '@')
return (-1);
if (*bp != '#')
continue;
bp++;
base = 10;
if (*bp == '0')
base = 8;
i = 0;
while (isdigit(*bp))
i *= base, i += *bp++ - '0';
return (i);
}
}
/*
* Handle a flag option.
* Flag options are given "naked", i.e. followed by a : or the end
* of the buffer. Return 1 if we find the option, or 0 if it is
* not given.
*/
tgetflag(id)
char *id;
{
register char *bp = tbuf;
for (;;) {
bp = tskip(bp);
if (!*bp)
return (0);
if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
if (!*bp || *bp == ':')
return (1);
else if (*bp == '@')
return (0);
}
}
}
/*
* Get a string valued option.
* These are given as
* cl=^Z
* Much decoding is done on the strings, and the strings are
* placed in area, which is a ref parameter which is updated.
* No checking on area overflow.
*/
char *
tgetstr(id, area)
char *id, **area;
{
register char *bp = tbuf;
for (;;) {
bp = tskip(bp);
if (!*bp)
return (0);
if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
continue;
if (*bp == '@')
return (0);
if (*bp != '=')
continue;
bp++;
return (tdecode(bp, area));
}
}
/*
* Tdecode does the grung work to decode the
* string capability escapes.
*/
static char *
tdecode(str, area)
register char *str;
char **area;
{
register char *cp;
register int c;
register char *dp;
int i;
cp = *area;
while ((c = *str++) && c != ':') {
switch (c) {
case '^':
c = *str++ & 037;
break;
case '\\':
dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
c = *str++;
nextc:
if (*dp++ == c) {
c = *dp++;
break;
}
dp++;
if (*dp)
goto nextc;
if (isdigit(c)) {
c -= '0', i = 2;
do
c <<= 3, c |= *str++ - '0';
while (--i && isdigit(*str));
}
break;
}
*cp++ = c;
}
*cp++ = 0;
str = *area;
*area = cp;
return (str);
}

226
usr.bin/tip/remote.c Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 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) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)remote.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include "pathnames.h"
#include "tip.h"
/*
* Attributes to be gleened from remote host description
* data base.
*/
static char **caps[] = {
&AT, &DV, &CM, &CU, &EL, &IE, &OE, &PN, &PR, &DI,
&ES, &EX, &FO, &RC, &RE, &PA
};
static char *capstrings[] = {
"at", "dv", "cm", "cu", "el", "ie", "oe", "pn", "pr",
"di", "es", "ex", "fo", "rc", "re", "pa", 0
};
static char *db_array[3] = { _PATH_REMOTE, 0, 0 };
#define cgetflag(f) (cgetcap(bp, f, ':') != NULL)
static
getremcap(host)
register char *host;
{
register char **p, ***q;
char *bp;
char *rempath;
int stat;
rempath = getenv("REMOTE");
if (rempath != NULL)
if (*rempath != '/')
/* we have an entry */
cgetset(rempath);
else { /* we have a path */
db_array[1] = rempath;
db_array[2] = _PATH_REMOTE;
}
if ((stat = cgetent(&bp, db_array, host)) < 0) {
if (DV ||
host[0] == '/' && access(DV = host, R_OK | W_OK) == 0) {
CU = DV;
HO = host;
HW = 1;
DU = 0;
if (!BR)
BR = DEFBR;
FS = DEFFS;
return;
}
switch(stat) {
case -1:
fprintf(stderr, "tip: unknown host %s\n", host);
break;
case -2:
fprintf(stderr,
"tip: can't open host description file\n");
break;
case -3:
fprintf(stderr,
"tip: possible reference loop in host description file\n");
break;
}
exit(3);
}
for (p = capstrings, q = caps; *p != NULL; p++, q++)
if (**q == NULL)
cgetstr(bp, *p, *q);
if (!BR && (cgetnum(bp, "br", &BR) == -1))
BR = DEFBR;
if (cgetnum(bp, "fs", &FS) == -1)
FS = DEFFS;
if (DU < 0)
DU = 0;
else
DU = cgetflag("du");
if (DV == NOSTR) {
fprintf(stderr, "%s: missing device spec\n", host);
exit(3);
}
if (DU && CU == NOSTR)
CU = DV;
if (DU && PN == NOSTR) {
fprintf(stderr, "%s: missing phone number\n", host);
exit(3);
}
HD = cgetflag("hd");
/*
* This effectively eliminates the "hw" attribute
* from the description file
*/
if (!HW)
HW = (CU == NOSTR) || (DU && equal(DV, CU));
HO = host;
/*
* see if uppercase mode should be turned on initially
*/
if (cgetflag("ra"))
boolean(value(RAISE)) = 1;
if (cgetflag("ec"))
boolean(value(ECHOCHECK)) = 1;
if (cgetflag("be"))
boolean(value(BEAUTIFY)) = 1;
if (cgetflag("nb"))
boolean(value(BEAUTIFY)) = 0;
if (cgetflag("sc"))
boolean(value(SCRIPT)) = 1;
if (cgetflag("tb"))
boolean(value(TABEXPAND)) = 1;
if (cgetflag("vb"))
boolean(value(VERBOSE)) = 1;
if (cgetflag("nv"))
boolean(value(VERBOSE)) = 0;
if (cgetflag("ta"))
boolean(value(TAND)) = 1;
if (cgetflag("nt"))
boolean(value(TAND)) = 0;
if (cgetflag("rw"))
boolean(value(RAWFTP)) = 1;
if (cgetflag("hd"))
boolean(value(HALFDUPLEX)) = 1;
if (RE == NOSTR)
RE = (char *)"tip.record";
if (EX == NOSTR)
EX = (char *)"\t\n\b\f";
if (ES != NOSTR)
vstring("es", ES);
if (FO != NOSTR)
vstring("fo", FO);
if (PR != NOSTR)
vstring("pr", PR);
if (RC != NOSTR)
vstring("rc", RC);
if (cgetnum(bp, "dl", &DL) == -1)
DL = 0;
if (cgetnum(bp, "cl", &CL) == -1)
CL = 0;
if (cgetnum(bp, "et", &ET) == -1)
ET = 10;
}
char *
getremote(host)
char *host;
{
register char *cp;
static char *next;
static int lookedup = 0;
if (!lookedup) {
if (host == NOSTR && (host = getenv("HOST")) == NOSTR) {
fprintf(stderr, "tip: no host specified\n");
exit(3);
}
getremcap(host);
next = DV;
lookedup++;
}
/*
* We return a new device each time we're called (to allow
* a rotary action to be simulated)
*/
if (next == NOSTR)
return (NOSTR);
if ((cp = index(next, ',')) == NULL) {
DV = next;
next = NOSTR;
} else {
*cp++ = '\0';
DV = next;
next = cp;
}
return (DV);
}

451
usr.bin/tip/tip.1 Normal file
View File

@ -0,0 +1,451 @@
.\" Copyright (c) 1980, 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.
.\"
.\" @(#)tip.1 8.4 (Berkeley) 4/18/94
.\"
.Dd April 18, 1994
.Dt TIP 1
.Os BSD 4
.Sh NAME
.Nm tip ,
.Nm cu
.Nd connect to a remote system
.Sh SYNOPSIS
.Nm tip
.Op Fl v
.Fl Ns Ns Ar speed
.Ar system\-name
.Nm tip
.Op Fl v
.Fl Ns Ns Ar speed
.Ar phone\-number
.Nm cu
.Ar phone\-number
.Op Fl t
.Op Fl s Ar speed
.Op Fl a Ar acu
.Op Fl l Ar line
.Op Fl #
.Sh DESCRIPTION
.Nm Tip
and
.Ar cu
establish a full-duplex connection to another machine,
giving the appearance of being logged in directly on the
remote cpu. It goes without saying that you must have a login
on the machine (or equivalent) to which you wish to connect.
The preferred interface is
.Nm tip .
The
.Ar cu
interface is included for those people attached to the
``call
.Ux Ns ''
command of version 7. This manual page
describes only
.Nm tip .
.Pp
Available Option:
.Bl -tag -width indent
.It Fl v
Set verbose mode.
.El
.Pp
Typed characters are normally transmitted directly to the remote
machine (which does the echoing as well). A tilde (`~') appearing
as the first character of a line is an escape signal; the following
are recognized:
.Bl -tag -width flag
.It Ic \&~^D No or Ic \&~ .
Drop the connection and exit
(you may still be logged in on the
remote machine).
.It Ic \&~c Op Ar name
Change directory to
.Ar name
(no argument
implies change to your home directory).
.It Ic \&~!
Escape to a shell (exiting the shell will
return you to tip).
.It Ic \&~>
Copy file from local to remote.
.Nm Tip
prompts for the name of a local file to transmit.
.It Ic \&~<
Copy file from remote to local.
.Nm Tip
prompts first for the name of the file to be sent, then for
a command to be executed on the remote machine.
.It Ic \&~p Ar from Op Ar to
Send a file to a remote
.Ux
host. The put command causes the remote
.Ux
system to run the command string ``cat > 'to''', while
.Nm tip
sends it the ``from''
file. If the ``to'' file isn't specified the ``from'' file name is used.
This command is actually a
.Ux
specific version of the ``~>'' command.
.It Ic \&~t Ar from Op Ar to
Take a file from a remote
.Ux
host.
As in the put command the ``to'' file
defaults to the ``from'' file name if it isn't specified.
The remote host
executes the command string ``cat 'from';echo ^A'' to send the file to
.Nm tip .
.It Ic \&~|
Pipe the output from a remote command to a local
.Ux
process.
The command string sent to the local
.Ux
system is processed by the shell.
.It Ic \&~$
Pipe the output from a local
.Ux
process to the remote host.
The command string sent to the local
.Ux
system is processed by the shell.
.It Ic \&~C
Fork a child process on the local system to perform special protocols
such as \s-1XMODEM\s+1. The child program will be run with the following
somewhat unusual arrangement of file descriptors:
.nf
.in +1i
0 <-> local tty in
1 <-> local tty out
2 <-> local tty out
3 <-> remote tty in
4 <-> remote tty out
.in -1i
.fi
.It Ic \&~#
Send a
.Dv BREAK
to the remote system.
For systems which don't support the
necessary
.Ar ioctl
call the break is simulated by a sequence of line speed changes
and
.Dv DEL
characters.
.It Ic \&~s
Set a variable (see the discussion below).
.It Ic \&~^Z
Stop
.Nm tip
(only available with job control).
.It Ic \&~^Y
Stop only the ``local side'' of
.Nm tip
(only available with job control);
the ``remote side'' of
.Nm tip ,
the side that displays output from the remote host, is left running.
.It Ic \&~?
Get a summary of the tilde escapes
.El
.Pp
.Nm Tip
uses the file
.Pa /etc/remote
to find how to reach a particular
system and to find out how it should operate while talking
to the system;
refer to
.Xr remote 5
for a full description.
Each system has a default baud rate with which to
establish a connection. If this value is not suitable, the baud rate
to be used may be specified on the command line, e.g.
.Ql "tip -300 mds" .
.Pp
When
.Nm tip
establishes a connection it sends out a
connection message to the remote system; the default value, if any,
is defined in
.Pa /etc/remote
(see
.Xr remote 5 ) .
.Pp
When
.Nm tip
prompts for an argument (e.g. during setup of
a file transfer) the line typed may be edited with the standard
erase and kill characters. A null line in response to a prompt,
or an interrupt, will abort the dialogue and return you to the
remote machine.
.Pp
.Nm Tip
guards against multiple users connecting to a remote system
by opening modems and terminal lines with exclusive access,
and by honoring the locking protocol used by
.Xr uucico 8 .
.Pp
During file transfers
.Nm tip
provides a running count of the number of lines transferred.
When using the ~> and ~< commands, the ``eofread'' and ``eofwrite''
variables are used to recognize end-of-file when reading, and
specify end-of-file when writing (see below). File transfers
normally depend on tandem mode for flow control. If the remote
system does not support tandem mode, ``echocheck'' may be set
to indicate
.Nm tip
should synchronize with the remote system on the echo of each
transmitted character.
.Pp
When
.Nm tip
must dial a phone number to connect to a system it will print
various messages indicating its actions.
.Nm Tip
supports the
.Tn DEC DN Ns-11
and
Racal-Vadic 831 auto-call-units;
the
.Tn DEC DF Ns \&02
and
.Tn DF Ns \&03 ,
Ventel 212+, Racal-Vadic 3451, and
Bizcomp 1031 and 1032 integral call unit/modems.
.Ss VARIABLES
.Nm Tip
maintains a set of
.Ar variables
which control its operation.
Some of these variables are read-only to normal users (root is allowed
to change anything of interest). Variables may be displayed
and set through the ``s'' escape. The syntax for variables is patterned
after
.Xr vi 1
and
.Xr Mail 1 .
Supplying ``all''
as an argument to the set command displays all variables readable by
the user. Alternatively, the user may request display of a particular
variable by attaching a `?' to the end. For example ``escape?''
displays the current escape character.
.Pp
Variables are numeric, string, character, or boolean values. Boolean
variables are set merely by specifying their name; they may be reset
by prepending a `!' to the name. Other variable types are set by
concatenating an `=' and the value. The entire assignment must not
have any blanks in it. A single set command may be used to interrogate
as well as set a number of variables.
Variables may be initialized at run time by placing set commands
(without the ``~s'' prefix in a file
.Pa .tiprc
in one's home directory). The
.Fl v
option causes
.Nm tip
to display the sets as they are made.
Certain common variables have abbreviations.
The following is a list of common variables,
their abbreviations, and their default values.
.Bl -tag -width Ar
.It Ar beautify
(bool) Discard unprintable characters when a session is being scripted;
abbreviated
.Ar be .
.It Ar baudrate
(num) The baud rate at which the connection was established;
abbreviated
.Ar ba .
.It Ar dialtimeout
(num) When dialing a phone number, the time (in seconds)
to wait for a connection to be established; abbreviated
.Ar dial .
.It Ar echocheck
(bool) Synchronize with the remote host during file transfer by
waiting for the echo of the last character transmitted; default is
.Ar off .
.It Ar eofread
(str) The set of characters which signify an end-of-transmission
during a ~< file transfer command; abbreviated
.Ar eofr .
.It Ar eofwrite
(str) The string sent to indicate end-of-transmission during
a ~> file transfer command; abbreviated
.Ar eofw .
.It Ar eol
(str) The set of characters which indicate an end-of-line.
.Nm Tip
will recognize escape characters only after an end-of-line.
.It Ar escape
(char) The command prefix (escape) character; abbreviated
.Ar es ;
default value is `~'.
.It Ar exceptions
(str) The set of characters which should not be discarded
due to the beautification switch; abbreviated
.Ar ex ;
default value is ``\et\en\ef\eb''.
.It Ar force
(char) The character used to force literal data transmission;
abbreviated
.Ar fo ;
default value is `^P'.
.It Ar framesize
(num) The amount of data (in bytes) to buffer between file system
writes when receiving files; abbreviated
.Ar fr .
.It Ar host
(str) The name of the host to which you are connected; abbreviated
.Ar ho .
.It Ar prompt
(char) The character which indicates an end-of-line on the remote
host; abbreviated
.Ar pr ;
default value is `\en'. This value is used to synchronize during
data transfers. The count of lines transferred during a file transfer
command is based on receipt of this character.
.It Ar raise
(bool) Upper case mapping mode; abbreviated
.Ar ra ;
default value is
.Ar off .
When this mode is enabled, all lower case letters will be mapped to
upper case by
.Nm tip
for transmission to the remote machine.
.It Ar raisechar
(char) The input character used to toggle upper case mapping mode;
abbreviated
.Ar rc ;
default value is `^A'.
.It Ar record
(str) The name of the file in which a session script is recorded;
abbreviated
.Ar rec ;
default value is ``tip.record''.
.It Ar script
(bool) Session scripting mode; abbreviated
.Ar sc ;
default is
.Ar off .
When
.Ar script
is
.Li true ,
.Nm tip
will record everything transmitted by the remote machine in
the script record file specified in
.Ar record .
If the
.Ar beautify
switch is on, only printable
.Tn ASCII
characters will be included in
the script file (those characters betwee 040 and 0177). The
variable
.Ar exceptions
is used to indicate characters which are an exception to the normal
beautification rules.
.It Ar tabexpand
(bool) Expand tabs to spaces during file transfers; abbreviated
.Ar tab ;
default value is
.Ar false .
Each tab is expanded to 8 spaces.
.It Ar verbose
(bool) Verbose mode; abbreviated
.Ar verb ;
default is
.Ar true .
When verbose mode is enabled,
.Nm tip
prints messages while dialing, shows the current number
of lines transferred during a file transfer operations,
and more.
.El
.Sh ENVIRONMENT
.Nm Tip
uses the following environment variables:
.Bl -tag -width Fl
.It Ev SHELL
(str) The name of the shell to use for the ~! command; default
value is ``/bin/sh'', or taken from the environment.
.It Ev HOME
(str) The home directory to use for the ~c command; default
value is taken from the environment.
.It Ev HOST
Check for a default host if none specified.
.El
.Pp
The variables
.Ev ${REMOTE}
and
.Ev ${PHONES}
are also exported.
.Sh FILES
.Bl -tag -width /var/spool/uucp/LCK..* -compact
.It Pa /etc/remote
Global system descriptions.
.It Pa /etc/phones
Global phone number data base.
.It ${REMOTE}
Private system descriptions.
.It ${PHONES}
Private phone numbers.
.It ~/.tiprc
Initialization file.
.It Pa tip.record
Record file.
.It /var/log/aculog
Line access log.
.It Pa /var/spool/uucp/LCK..*
Lock file to avoid conflicts with
.Xr uucp .
.El
.Sh DIAGNOSTICS
Diagnostics are, hopefully, self explanatory.
.Sh SEE ALSO
.Xr remote 5 ,
.Xr phones 5
.Sh HISTORY
The
.Nm tip
appeared command in
.Bx 4.2 .
.Sh BUGS
The full set of variables is undocumented and should, probably, be
pared down.

353
usr.bin/tip/value.c Normal file
View File

@ -0,0 +1,353 @@
/*
* Copyright (c) 1983, 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[] = "@(#)value.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
#define MIDDLE 35
static value_t *vlookup();
static int col = 0;
/*
* Variable manipulation
*/
vinit()
{
register value_t *p;
register char *cp;
FILE *f;
char file[256];
for (p = vtable; p->v_name != NULL; p++) {
if (p->v_type&ENVIRON)
if (cp = getenv(p->v_name))
p->v_value = cp;
if (p->v_type&IREMOTE)
number(p->v_value) = *address(p->v_value);
}
/*
* Read the .tiprc file in the HOME directory
* for sets
*/
strcpy(file, value(HOME));
strcat(file, "/.tiprc");
if ((f = fopen(file, "r")) != NULL) {
register char *tp;
while (fgets(file, sizeof(file)-1, f) != NULL) {
if (vflag)
printf("set %s", file);
if (tp = rindex(file, '\n'))
*tp = '\0';
vlex(file);
}
fclose(f);
}
/*
* To allow definition of exception prior to fork
*/
vtable[EXCEPTIONS].v_access &= ~(WRITE<<PUBLIC);
}
static int vaccess();
/*VARARGS1*/
vassign(p, v)
register value_t *p;
char *v;
{
if (!vaccess(p->v_access, WRITE)) {
printf("access denied\r\n");
return;
}
switch (p->v_type&TMASK) {
case STRING:
if (p->v_value && equal(p->v_value, v))
return;
if (!(p->v_type&(ENVIRON|INIT)))
free(p->v_value);
if ((p->v_value = malloc(size(v)+1)) == NOSTR) {
printf("out of core\r\n");
return;
}
p->v_type &= ~(ENVIRON|INIT);
strcpy(p->v_value, v);
break;
case NUMBER:
if (number(p->v_value) == number(v))
return;
number(p->v_value) = number(v);
break;
case BOOL:
if (boolean(p->v_value) == (*v != '!'))
return;
boolean(p->v_value) = (*v != '!');
break;
case CHAR:
if (character(p->v_value) == *v)
return;
character(p->v_value) = *v;
}
p->v_access |= CHANGED;
}
static void vprint();
vlex(s)
register char *s;
{
register value_t *p;
static void vtoken();
if (equal(s, "all")) {
for (p = vtable; p->v_name; p++)
if (vaccess(p->v_access, READ))
vprint(p);
} else {
register char *cp;
do {
if (cp = vinterp(s, ' '))
cp++;
vtoken(s);
s = cp;
} while (s);
}
if (col > 0) {
printf("\r\n");
col = 0;
}
}
static void
vtoken(s)
register char *s;
{
register value_t *p;
register char *cp;
char *expand();
if (cp = index(s, '=')) {
*cp = '\0';
if (p = vlookup(s)) {
cp++;
if (p->v_type&NUMBER)
vassign(p, atoi(cp));
else {
if (strcmp(s, "record") == 0)
cp = expand(cp);
vassign(p, cp);
}
return;
}
} else if (cp = index(s, '?')) {
*cp = '\0';
if ((p = vlookup(s)) && vaccess(p->v_access, READ)) {
vprint(p);
return;
}
} else {
if (*s != '!')
p = vlookup(s);
else
p = vlookup(s+1);
if (p != NOVAL) {
vassign(p, s);
return;
}
}
printf("%s: unknown variable\r\n", s);
}
static void
vprint(p)
register value_t *p;
{
register char *cp;
extern char *interp(), *ctrl();
if (col > 0 && col < MIDDLE)
while (col++ < MIDDLE)
putchar(' ');
col += size(p->v_name);
switch (p->v_type&TMASK) {
case BOOL:
if (boolean(p->v_value) == FALSE) {
col++;
putchar('!');
}
printf("%s", p->v_name);
break;
case STRING:
printf("%s=", p->v_name);
col++;
if (p->v_value) {
cp = interp(p->v_value, NULL);
col += size(cp);
printf("%s", cp);
}
break;
case NUMBER:
col += 6;
printf("%s=%-5d", p->v_name, number(p->v_value));
break;
case CHAR:
printf("%s=", p->v_name);
col++;
if (p->v_value) {
cp = ctrl(character(p->v_value));
col += size(cp);
printf("%s", cp);
}
break;
}
if (col >= MIDDLE) {
col = 0;
printf("\r\n");
return;
}
}
static int
vaccess(mode, rw)
register unsigned mode, rw;
{
if (mode & (rw<<PUBLIC))
return (1);
if (mode & (rw<<PRIVATE))
return (1);
return ((mode & (rw<<ROOT)) && getuid() == 0);
}
static value_t *
vlookup(s)
register char *s;
{
register value_t *p;
for (p = vtable; p->v_name; p++)
if (equal(p->v_name, s) || (p->v_abrev && equal(p->v_abrev, s)))
return (p);
return (NULL);
}
char *
vinterp(s, stop)
register char *s;
char stop;
{
register char *p = s, c;
int num;
while ((c = *s++) && c != stop)
switch (c) {
case '^':
if (*s)
*p++ = *s++ - 0100;
else
*p++ = c;
break;
case '\\':
num = 0;
c = *s++;
if (c >= '0' && c <= '7')
num = (num<<3)+(c-'0');
else {
register char *q = "n\nr\rt\tb\bf\f";
for (; *q; q++)
if (c == *q++) {
*p++ = *q;
goto cont;
}
*p++ = c;
cont:
break;
}
if ((c = *s++) >= '0' && c <= '7') {
num = (num<<3)+(c-'0');
if ((c = *s++) >= '0' && c <= '7')
num = (num<<3)+(c-'0');
else
s--;
} else
s--;
*p++ = num;
break;
default:
*p++ = c;
}
*p = '\0';
return (c == stop ? s-1 : NULL);
}
/*
* assign variable s with value v (for NUMBER or STRING or CHAR types)
*/
vstring(s,v)
register char *s;
register char *v;
{
register value_t *p;
char *expand();
p = vlookup(s);
if (p == 0)
return (1);
if (p->v_type&NUMBER)
vassign(p, atoi(v));
else {
if (strcmp(s, "record") == 0)
v = expand(v);
vassign(p, v);
}
return (0);
}

112
usr.bin/tip/vars.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (c) 1983, 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[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "tip.h"
#include "pathnames.h"
/*
* Definition of variables
*/
value_t vtable[] = {
{ "beautify", BOOL, (READ|WRITE)<<PUBLIC,
"be", (char *)TRUE },
{ "baudrate", NUMBER|IREMOTE|INIT, (READ<<PUBLIC)|(WRITE<<ROOT),
"ba", (char *)&BR },
{ "dialtimeout",NUMBER, (READ<<PUBLIC)|(WRITE<<ROOT),
"dial", (char *)60 },
{ "eofread", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"eofr", (char *)&IE },
{ "eofwrite", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"eofw", (char *)&OE },
{ "eol", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
NOSTR, (char *)&EL },
{ "escape", CHAR, (READ|WRITE)<<PUBLIC,
"es", (char *)'~' },
{ "exceptions", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
"ex", (char *)&EX },
{ "force", CHAR, (READ|WRITE)<<PUBLIC,
"fo", (char *)CTRL('p') },
{ "framesize", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"fr", (char *)&FS },
{ "host", STRING|IREMOTE|INIT, READ<<PUBLIC,
"ho", (char *)&HO },
{ "log", STRING|INIT, (READ|WRITE)<<ROOT,
NOSTR, _PATH_ACULOG },
{ "phones", STRING|INIT|IREMOTE, READ<<PUBLIC,
NOSTR, (char *)&PH },
{ "prompt", CHAR, (READ|WRITE)<<PUBLIC,
"pr", (char *)'\n' },
{ "raise", BOOL, (READ|WRITE)<<PUBLIC,
"ra", (char *)FALSE },
{ "raisechar", CHAR, (READ|WRITE)<<PUBLIC,
"rc", (char *)CTRL('a') },
{ "record", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
"rec", (char *)&RE },
{ "remote", STRING|INIT|IREMOTE, READ<<PUBLIC,
NOSTR, (char *)&RM },
{ "script", BOOL, (READ|WRITE)<<PUBLIC,
"sc", (char *)FALSE },
{ "tabexpand", BOOL, (READ|WRITE)<<PUBLIC,
"tab", (char *)FALSE },
{ "verbose", BOOL, (READ|WRITE)<<PUBLIC,
"verb", (char *)TRUE },
{ "SHELL", STRING|ENVIRON|INIT, (READ|WRITE)<<PUBLIC,
NULL, _PATH_BSHELL },
{ "HOME", STRING|ENVIRON, (READ|WRITE)<<PUBLIC,
NOSTR, NOSTR },
{ "echocheck", BOOL, (READ|WRITE)<<PUBLIC,
"ec", (char *)FALSE },
{ "disconnect", STRING|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"di", (char *)&DI },
{ "tandem", BOOL, (READ|WRITE)<<PUBLIC,
"ta", (char *)TRUE },
{ "linedelay", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"ldelay", (char *)&DL },
{ "chardelay", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"cdelay", (char *)&CL },
{ "etimeout", NUMBER|IREMOTE|INIT, (READ|WRITE)<<PUBLIC,
"et", (char *)&ET },
{ "rawftp", BOOL, (READ|WRITE)<<PUBLIC,
"raw", (char *)FALSE },
{ "halfduplex", BOOL, (READ|WRITE)<<PUBLIC,
"hdx", (char *)FALSE },
{ "localecho", BOOL, (READ|WRITE)<<PUBLIC,
"le", (char *)FALSE },
{ "parity", STRING|INIT|IREMOTE, (READ|WRITE)<<PUBLIC,
"par", (char *)&PA },
{ NOSTR, NULL, NULL, NOSTR, NOSTR }
};

View File

@ -0,0 +1,814 @@
/*-
* Copyright (c) 1985, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1985, 1986, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)acucntrl.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/* acucntrl - turn around tty line between dialin and dialout
*
* Usage: acucntrl {enable,disable} /dev/ttydX
*
* History:
* First written by Allan Wilkes (fisher!allan)
*
* Modified June 8,1983 by W.Sebok (astrovax!wls) to poke kernel rather
* than use kernel hack to turn on/off modem control, using subroutine
* stolen from program written by Tsutomu Shimomura
* {astrovax,escher}!tsutomu
*
* Worked over many times by W.Sebok (i.e. hacked to death)
*
* Operation:
* disable (i.e. setup for dialing out)
* (1) check input arguments
* (2) look in _PATH_UTMP to check that the line is not in use by another
* (3) disable modem control on terminal
* (4) check for carrier on device
* (5) change owner of device to real id
* (6) edit _PATH_TTYS, changing the first character of the appropriate
* line to 0
* (7) send a hangup to process 1 to poke init to disable getty
* (8) post uid name in capitals in _PATH_UTMP to let world know device
* has been grabbed
* (9) make sure that DTR is on
*
* enable (i.e.) restore for dialin
* (1) check input arguments
* (2) look in _PATH_UTMP to check that the line is not in use by another
* (3) make sure modem control on terminal is disabled
* (4) turn off DTR to make sure line is hung up
* (5) condition line: clear exclusive use and set hangup on close modes
* (6) turn on modem control
* (7) edit _PATH_TTYS, changing the first character of the appropriate
* line to 1
* (8) send a hangup to process 1 to poke init to enable getty
* (9) clear uid name for _PATH_UTMP
*/
/* #define SENSECARRIER */
#include "uucp.h"
#ifdef DIALINOUT
#include <sys/buf.h>
#include <signal.h>
#include <sys/conf.h>
#ifdef vax
#ifdef BSD4_2
#include <vaxuba/ubavar.h>
#else
#include <sys/ubavar.h>
#endif
#endif /* vax */
#include <sys/stat.h>
#include <nlist.h>
#include <sgtty.h>
#include <utmp.h>
#include <pwd.h>
#include <stdio.h>
#include <sys/file.h>
#include "pathnames.h"
#define NDZLINE 8 /* lines/dz */
#define NDHLINE 16 /* lines/dh */
#define NDMFLINE 8 /* lines/dmf */
#define DZ11 1
#define DH11 2
#define DMF 3
#define NLVALUE(val) (nl[val].n_value)
struct nlist nl[] = {
#define CDEVSW 0
{ "_cdevsw" },
#define DZOPEN 1
{ "_dzopen" },
#define DZINFO 2
{ "_dzinfo" },
#define NDZ11 3
{ "_dz_cnt" },
#define DZSCAR 4
{ "_dzsoftCAR" },
#define DHOPEN 5
{ "_dhopen" },
#define DHINFO 6
{ "_dhinfo" },
#define NDH11 7
{ "_ndh11" },
#define DHSCAR 8
{ "_dhsoftCAR" },
#define DMFOPEN 9
{ "_dmfopen" },
#define DMFINFO 10
{ "_dmfinfo" },
#define NDMF 11
{ "_ndmf" },
#define DMFSCAR 12
{ "_dmfsoftCAR" },
{ "\0" }
};
#define ENABLE 1
#define DISABLE 0
char Etcttys[] = _PATH_TTYS;
#ifdef BSD4_3
FILE *ttysfile, *nttysfile;
char NEtcttys[] = _PATH_NEWTTYS;
extern long ftell();
#endif BSD4_3
char Devhome[] = _PATH_DEV;
char usage[] = "Usage: acucntrl {dis|en}able ttydX\n";
struct utmp utmp;
char resettty, resetmodem;
int etcutmp;
off_t utmploc;
off_t ttyslnbeg;
extern int errno;
extern char *sys_errlist[];
off_t lseek();
#define NAMSIZ sizeof(utmp.ut_name)
#define LINSIZ sizeof(utmp.ut_line)
main(argc, argv)
int argc; char *argv[];
{
register char *p;
register int i;
char uname[NAMSIZ], Uname[NAMSIZ];
int enable ;
char *device;
int devfile;
int uid, gid;
struct passwd *getpwuid();
char *rindex();
/* check input arguments */
if (argc!=3 && argc != 4) {
fprintf(stderr, usage);
exit(1);
}
/* interpret command type */
if (prefix(argv[1], "disable") || strcmp(argv[1], "dialout")==0)
enable = 0;
else if (prefix(argv[1], "enable") || strcmp(argv[1], "dialin")==0)
enable = 1;
else {
fprintf(stderr, usage);
exit(1);
}
device = rindex(argv[2], '/');
device = (device == NULL) ? argv[2]: device+1;
opnttys(device);
#ifdef vax
/* Get nlist info */
nlist(_PATH_UNIX, nl);
#endif vax
/* Chdir to /dev */
if(chdir(Devhome) < 0) {
fprintf(stderr, "Cannot chdir to %s: %s\r\n",
Devhome, sys_errlist[errno]);
exit(1);
}
/* Get uid information */
uid = getuid();
gid = getgid();
p = getpwuid(uid)->pw_name;
if (p==NULL) {
fprintf(stderr, "cannot get uid name\n");
exit(1);
}
if (strcmp(p, "uucp") == 0 && argc == 4)
p = argv[3];
/* to upper case */
i = 0;
do {
uname[i] = *p;
Uname[i++] = (*p>='a' && *p<='z') ? (*p - ('a'-'A')) : *p;
} while (*p++ && i<NAMSIZ);
/* check to see if line is being used */
if( (etcutmp = open(_PATH_UTMP, 2)) < 0) {
fprintf(stderr, "On open %s open: %s\n",
_PATH_UTMP, sys_errlist[errno]);
exit(1);
}
(void)lseek(etcutmp, utmploc, 0);
i = read(etcutmp, (char *)&utmp, sizeof(struct utmp));
if(
i == sizeof(struct utmp) &&
utmp.ut_line[0] != '\0' &&
utmp.ut_name[0] != '\0' &&
(
!upcase(utmp.ut_name, NAMSIZ) ||
(
uid != 0 &&
strncmp(utmp.ut_name, Uname, NAMSIZ) != 0
)
)
) {
fprintf(stderr, "%s in use by %s\n", device, utmp.ut_name);
exit(2);
}
#ifndef sequent
/* Disable modem control */
if (setmodem(device, DISABLE) < 0) {
fprintf(stderr, "Unable to disable modem control\n");
exit(1);
}
#endif !sequent
if (enable) {
#ifdef sequent
if (setmodem(device, ENABLE) < 0) {
fprintf(stderr, "Cannot Enable modem control\n");
(void)setmodem(device, i);
exit(1);
}
#endif sequent
#ifndef sequent
if((devfile = open(device, 1)) < 0) {
fprintf(stderr, "On open of %s: %s\n",
device, sys_errlist[errno]);
(void)setmodem(device, resetmodem);
exit(1);
}
/* Try one last time to hang up */
if (ioctl(devfile, (int)TIOCCDTR, (char *)0) < 0)
fprintf(stderr, "On TIOCCDTR ioctl: %s\n",
sys_errlist[errno]);
if (ioctl(devfile, (int)TIOCNXCL, (char *)0) < 0)
fprintf(stderr,
"Cannot clear Exclusive Use on %s: %s\n",
device, sys_errlist[errno]);
if (ioctl(devfile, (int)TIOCHPCL, (char *)0) < 0)
fprintf(stderr,
"Cannot set hangup on close on %s: %s\n",
device, sys_errlist[errno]);
#endif !sequent
i = resetmodem;
#ifndef sequent
if (setmodem(device, ENABLE) < 0) {
fprintf(stderr, "Cannot Enable modem control\n");
(void)setmodem(device, i);
exit(1);
}
#endif sequent
resetmodem=i;
if (settys(ENABLE)) {
fprintf(stderr, "%s already enabled\n", device);
} else {
pokeinit(device, Uname, enable);
}
post(device, "");
} else {
#if defined(TIOCMGET) && defined(SENSECARRIER)
if (uid!=0) {
int linestat = 0;
/* check for presence of carrier */
sleep(2); /* need time after modem control turnoff */
if((devfile = open(device, 1)) < 0) {
fprintf(stderr, "On open of %s: %s\n",
device, sys_errlist[errno]);
(void)setmodem(device, resetmodem);
exit(1);
}
(void)ioctl(devfile, TIOCMGET, &linestat);
if (linestat&TIOCM_CAR) {
fprintf(stderr, "%s is in use (Carrier On)\n",
device);
(void)setmodem(device, resetmodem);
exit(2);
}
(void)close(devfile);
}
#endif TIOCMGET
/* chown device */
if(chown(device, uid, gid) < 0)
fprintf(stderr, "Cannot chown %s: %s\n",
device, sys_errlist[errno]);
/* poke init */
if(settys(DISABLE)) {
fprintf(stderr, "%s already disabled\n", device);
} else {
pokeinit(device, Uname, enable);
}
post(device, Uname);
#ifdef sequent
/* Disable modem control */
if (setmodem(device, DISABLE) < 0) {
fprintf(stderr, "Unable to disable modem control\n");
exit(1);
}
#endif sequent
if((devfile = open(device, O_RDWR|O_NDELAY)) < 0) {
fprintf(stderr, "On %s open: %s\n",
device, sys_errlist[errno]);
} else {
if(ioctl(devfile, (int)TIOCSDTR, (char *)0) < 0)
fprintf(stderr,
"Cannot set DTR on %s: %s\n",
device, sys_errlist[errno]);
}
}
exit(0);
}
/* return true if no lower case */
upcase(str, len)
register char *str;
register int len;
{
for (; *str, --len >= 0 ; str++)
if (*str>='a' && *str<='z')
return(0);
return(1);
}
/* Post name to public */
post(device, name)
char *device, *name;
{
(void)time((time_t *)&utmp.ut_time);
strncpy(utmp.ut_line, device, LINSIZ);
strncpy(utmp.ut_name, name, NAMSIZ);
if (lseek(etcutmp, utmploc, 0) < 0)
fprintf(stderr, "on lseek in %s: %s",
_PATH_UTMP, sys_errlist[errno]);
if (write(etcutmp, (char *)&utmp, sizeof(utmp)) < 0)
fprintf(stderr, "on write in %s: %s",
_PATH_UTMP, sys_errlist[errno]);
}
/* poke process 1 and wait for it to do its thing */
pokeinit(device, uname, enable)
char *uname, *device; int enable;
{
struct utmp utmp;
register int i;
post(device, uname);
/* poke init */
if (kill(1, SIGHUP)) {
fprintf(stderr,
"Cannot send hangup to init process: %s\n",
sys_errlist[errno]);
(void)settys(resettty);
(void)setmodem(device, resetmodem);
exit(1);
}
if (enable)
return;
/* wait till init has responded, clearing the utmp entry */
i = 100;
do {
sleep(1);
if (lseek(etcutmp, utmploc, 0) < 0)
fprintf(stderr, "On lseek in %s: %s",
_PATH_UTMP, sys_errlist[errno]);
if (read(etcutmp, (char *)&utmp, sizeof utmp) < 0)
fprintf(stderr, "On read from %s: %s",
_PATH_UTMP, sys_errlist[errno]);
} while (utmp.ut_name[0] != '\0' && --i > 0);
}
#ifdef BSD4_3
/* identify terminal line in ttys */
opnttys(device)
char *device;
{
register int ndevice;
register char *p;
char *index();
char linebuf[BUFSIZ];
ttysfile = NULL;
do {
if (ttysfile != NULL) {
fclose(ttysfile);
sleep(5);
}
ttysfile = fopen(Etcttys, "r");
if(ttysfile == NULL) {
fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
sys_errlist[errno]);
exit(1);
}
} while (flock(fileno(ttysfile), LOCK_NB|LOCK_EX) < 0);
nttysfile = fopen(NEtcttys, "w");
if(nttysfile == NULL) {
fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
sys_errlist[errno]);
exit(1);
}
ndevice = strlen(device);
#ifndef BRL4_2
utmploc = sizeof(utmp);
#else BRL4_2
utmploc = 0;
#endif BRL4_2
while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) {
if(strncmp(device, linebuf, ndevice) == 0)
return;
ttyslnbeg += strlen(linebuf);
if (linebuf[0] != '#' && linebuf[0] != '\0')
utmploc += sizeof(utmp);
if (fputs(linebuf, nttysfile) == NULL) {
fprintf(stderr, "On %s write: %s\n",
Etcttys, sys_errlist[errno]);
exit(1);
}
}
fprintf(stderr, "%s not found in %s\n", device, Etcttys);
exit(1);
}
/* modify appropriate line in _PATH_TTYS to turn on/off the device */
settys(enable)
int enable;
{
register char *cp, *cp2;
char lbuf[BUFSIZ];
int i;
char c1, c2;
(void) fseek(ttysfile, ttyslnbeg, 0);
if(fgets(lbuf, BUFSIZ, ttysfile) == NULL) {
fprintf(stderr, "On %s read: %s\n",
Etcttys, sys_errlist[errno]);
exit(1);
}
/* format is now */
/* ttyd0 std.100 dialup on secure # comment */
/* except, 2nd item may have embedded spaces inside quotes, Hubert */
cp = lbuf;
for (i=0;*cp && i<3;i++) {
if (*cp == '"') {
cp++;
while (*cp && *cp != '"')
cp++;
if (*cp != '\0')
cp++;
}else {
while (*cp && *cp != ' ' && *cp != '\t')
cp++;
}
while (*cp && (*cp == ' ' || *cp == '\t'))
cp++;
}
if (*cp == '\0') {
fprintf(stderr,"Badly formatted line in %s:\n%s",
_PATH_TTYS, lbuf);
exit(1);
}
c1 = *--cp;
*cp++ = '\0';
cp2 = cp;
while (*cp && *cp != ' ' && *cp != '\t' && *cp != '\n')
cp++;
if (*cp == '\0') {
fprintf(stderr,"Badly formatted line in %s:\n%s",
_PATH_TTYS, lbuf);
exit(1);
}
c2 = *cp;
*cp++ = '\0';
while (*cp && (*cp == ' ' || *cp == '\t'))
cp++;
resettty = strcmp("on", cp2) != 0;
fprintf(nttysfile,"%s%c%s%c%s", lbuf, c1, enable ? "on" : "off", c2, cp);
if (ferror(nttysfile)) {
fprintf(stderr, "On %s fprintf: %s\n",
NEtcttys, sys_errlist[errno]);
exit(1);
}
while(fgets(lbuf, sizeof(lbuf) - 1, ttysfile) != NULL) {
if (fputs(lbuf, nttysfile) == NULL) {
fprintf(stderr, "On %s write: %s\n",
NEtcttys, sys_errlist[errno]);
exit(1);
}
}
if (enable^resettty)
(void) unlink(NEtcttys);
else {
struct stat statb;
if (stat(Etcttys, &statb) == 0) {
fchmod(fileno(nttysfile) ,statb.st_mode);
fchown(fileno(nttysfile), statb.st_uid, statb.st_gid);
}
(void) rename(NEtcttys, Etcttys);
}
(void) fclose(nttysfile);
(void) fclose(ttysfile);
return enable^resettty;
}
#else !BSD4_3
/* identify terminal line in ttys */
opnttys(device)
char *device;
{
register FILE *ttysfile;
register int ndevice, lnsiz;
register char *p;
char *index();
char linebuf[BUFSIZ];
ttysfile = fopen(Etcttys, "r");
if(ttysfile == NULL) {
fprintf(stderr, "Cannot open %s: %s\n", Etcttys,
sys_errlist[errno]);
exit(1);
}
ndevice = strlen(device);
ttyslnbeg = 0;
utmploc = 0;
while(fgets(linebuf, sizeof(linebuf) - 1, ttysfile) != NULL) {
lnsiz = strlen(linebuf);
if ((p = index(linebuf, '\n')) != NULL)
*p = '\0';
if(strncmp(device, &linebuf[2], ndevice) == 0) {
(void)fclose(ttysfile);
#ifdef sequent
/* Why is the sequent off by one? */
utmploc += sizeof(utmp);
#endif sequent
return;
}
ttyslnbeg += lnsiz;
utmploc += sizeof(utmp);
}
fprintf(stderr, "%s not found in %s\n", device, Etcttys);
exit(1);
}
/* modify appropriate line in _PATH_TTYS to turn on/off the device */
settys(enable)
int enable;
{
int ittysfil;
char out, in;
ittysfil = open(Etcttys, 2);
if(ittysfil < 0) {
fprintf(stderr, "Cannot open %s for output: %s\n",
Etcttys, sys_errlist[errno]);
exit(1);
}
(void)lseek(ittysfil, ttyslnbeg, 0);
if(read(ittysfil, &in, 1)<0) {
fprintf(stderr, "On %s write: %s\n",
Etcttys, sys_errlist[errno]);
exit(1);
}
resettty = (in == '1');
out = enable ? '1' : '0';
(void)lseek(ittysfil, ttyslnbeg, 0);
if(write(ittysfil, &out, 1)<0) {
fprintf(stderr, "On %s write: %s\n",
Etcttys, sys_errlist[errno]);
exit(1);
}
(void)close(ittysfil);
return(in==out);
}
#endif !BSD4_3
#ifdef sequent
setmodem(ttyline, enable)
char *ttyline; int enable;
{
char *sysbuf[BUFSIZ];
sprintf(sysbuf,"/etc/ttyconfig /dev/%s -special %s", ttyline,
enable ? "-carrier" : "-nocarrier");
system(sysbuf);
}
#endif /* sequent */
#ifdef vax
/*
* Excerpted from (June 8, 1983 W.Sebok)
* > ttymodem.c - enable/disable modem control for tty lines.
* >
* > Knows about DZ11s and DH11/DM11s.
* > 23.3.83 - TS
* > modified to know about DMF's (hasn't been tested) Nov 8, 1984 - WLS
*/
setmodem(ttyline, enable)
char *ttyline; int enable;
{
dev_t dev;
int kmem;
int unit, line, nlines, addr, tflags;
int devtype=0;
char cflags; short sflags;
#ifdef BSD4_2
int flags;
#else
short flags;
#endif
struct uba_device *ubinfo;
struct stat statb;
struct cdevsw cdevsw;
if(nl[CDEVSW].n_type == 0) {
fprintf(stderr, "No namelist.\n");
return(-1);
}
if((kmem = open(_PATH_KMEM, 2)) < 0) {
fprintf(stderr, "%s open: %s\n", _PATH_KMEM,
sys_errlist[errno]);
return(-1);
}
if(stat(ttyline, &statb) < 0) {
fprintf(stderr, "%s stat: %s\n", ttyline, sys_errlist[errno]);
return(-1);
}
if((statb.st_mode&S_IFMT) != S_IFCHR) {
fprintf(stderr, "%s is not a character device.\n",ttyline);
return(-1);
}
dev = statb.st_rdev;
(void)lseek(kmem,
(off_t) &(((struct cdevsw *)NLVALUE(CDEVSW))[major(dev)]),0);
(void)read(kmem, (char *) &cdevsw, sizeof cdevsw);
if((int)(cdevsw.d_open) == NLVALUE(DZOPEN)) {
devtype = DZ11;
unit = minor(dev) / NDZLINE;
line = minor(dev) % NDZLINE;
addr = (int) &(((int *)NLVALUE(DZINFO))[unit]);
(void)lseek(kmem, (off_t) NLVALUE(NDZ11), 0);
} else if((int)(cdevsw.d_open) == NLVALUE(DHOPEN)) {
devtype = DH11;
unit = minor(dev) / NDHLINE;
line = minor(dev) % NDHLINE;
addr = (int) &(((int *)NLVALUE(DHINFO))[unit]);
(void)lseek(kmem, (off_t) NLVALUE(NDH11), 0);
} else if((int)(cdevsw.d_open) == NLVALUE(DMFOPEN)) {
devtype = DMF;
unit = minor(dev) / NDMFLINE;
line = minor(dev) % NDMFLINE;
addr = (int) &(((int *)NLVALUE(DMFINFO))[unit]);
(void)lseek(kmem, (off_t) NLVALUE(NDMF), 0);
} else {
fprintf(stderr, "Device %s (%d/%d) unknown.\n", ttyline,
major(dev), minor(dev));
return(-1);
}
(void)read(kmem, (char *) &nlines, sizeof nlines);
if(minor(dev) >= nlines) {
fprintf(stderr, "Sub-device %d does not exist (only %d).\n",
minor(dev), nlines);
return(-1);
}
(void)lseek(kmem, (off_t)addr, 0);
(void)read(kmem, (char *) &ubinfo, sizeof ubinfo);
(void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0);
(void)read(kmem, (char *) &flags, sizeof flags);
tflags = 1<<line;
resetmodem = ((flags&tflags) == 0);
flags = enable ? (flags & ~tflags) : (flags | tflags);
(void)lseek(kmem, (off_t) &(ubinfo->ui_flags), 0);
(void)write(kmem, (char *) &flags, sizeof flags);
switch(devtype) {
case DZ11:
if((addr = NLVALUE(DZSCAR)) == 0) {
fprintf(stderr, "No dzsoftCAR.\n");
return(-1);
}
cflags = flags;
(void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0);
(void)write(kmem, (char *) &cflags, sizeof cflags);
break;
case DH11:
if((addr = NLVALUE(DHSCAR)) == 0) {
fprintf(stderr, "No dhsoftCAR.\n");
return(-1);
}
sflags = flags;
(void)lseek(kmem, (off_t) &(((short *)addr)[unit]), 0);
(void)write(kmem, (char *) &sflags, sizeof sflags);
break;
case DMF:
if((addr = NLVALUE(DMFSCAR)) == 0) {
fprintf(stderr, "No dmfsoftCAR.\n");
return(-1);
}
cflags = flags;
(void)lseek(kmem, (off_t) &(((char *)addr)[unit]), 0);
(void)write(kmem, (char *) &cflags, sizeof cflags);
break;
default:
fprintf(stderr, "Unknown device type\n");
return(-1);
}
return(0);
}
#endif /* vax */
prefix(s1, s2)
register char *s1, *s2;
{
register char c;
while ((c = *s1++) == *s2++)
if (c == '\0')
return (1);
return (c == '\0');
}
#else /* !DIALINOUT */
main()
{
fprintf(stderr,"acucntrl is not supported on this system\n");
}
#endif /* !DIALINOUT */

View File

@ -0,0 +1,111 @@
.\" Copyright (c) 1986, 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.
.\"
.\" @(#)uupoll.8 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dt UUPOLL 8
.Os BSD 4.3
.Sh NAME
.Nm uupoll
.Nd poll a remote
.Tn UUCP
site
.Sh SYNOPSIS
.Nm uupoll
.Op Fl g Ns Ar grade
.Op Fl n
.Ar system
.Sh DESCRIPTION
.Nm Uupoll
is used to force a poll of a remote system. It queues a null job for the
remote system and then invokes
.Xr uucico 8 .
.Pp
The following options are available:
.Bl -tag -width Fl
.It Fl g Ns Ar grade
Only send jobs of grade
.Ar grade
or higher on this call.
.It Fl n
Queue the null job, but do not invoke
.Xr uucico .
.El
.Pp
.Nm Uupoll
is usually run by
.Xr cron 5
or by a user who wants to hurry a job along. A typical entry in
.Em crontab
could be:
.Bd -literal
0 0,8,16 * * * daemon /usr/bin/uupoll ihnp4
0 4,12,20 * * * daemon /usr/bin/uupoll ucbvax
.Ed
.Pp
This will poll
.Em ihnp4
at midnight, 0800, and 1600, and
.Em ucbvax
at 0400, noon, and 2000.
.Pp
If the local machine is already running
.Xr uucico
every
hour and has a limited number of outgoing modems, a more elegant approach
might be:
.Bd -literal
0 0,8,16 * * * daemon /usr/bin/uupoll -n ihnp4
0 4,12,20 * * * daemon /usr/bin/uupoll -n ucbvax
5 * * * * daemon /usr/lib/uucp/uucico -r1
.Ed
.Pp
This will queue null jobs for the remote sites at the top of hour; they
will be processed by
.Xr uucico
when it runs five minutes later.
.Sh FILES
.Bl -tag -width /usr/lib/uucp/UUCP -compact
.It Pa /usr/lib/uucp/UUCP
internal files/utilities
.It Pa /var/spool/uucp/
Spool directory
.El
.Sh SEE ALSO
.Xr uucp 1 ,
.Xr uux 1 ,
.Xr uucico 8
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.3 .

View File

@ -0,0 +1,129 @@
/*-
* Copyright (c) 1986, 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) 1986, 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)uupoll.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* Poll named system(s).
*
* The poll occurs even if recent attempts have failed,
* but not if L.sys prohibits the call (e.g. wrong time of day).
*
* Original Author: Tom Truscott (rti!trt)
*/
#include "uucp.h"
int TransferSucceeded = 1;
struct timeb Now;
main(argc, argv)
int argc;
char **argv;
{
char wrkpre[MAXFULLNAME];
char file[MAXFULLNAME];
char grade = 'A';
int nocall = 0;
int c;
char *sysname;
extern char *optarg;
extern int optind;
if (argc < 2) {
fprintf(stderr, "usage: uupoll [-gX] [-n] system ...\n");
cleanup(1);
}
if (chdir(Spool) < 0) {
syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
cleanup(1);
}
strcpy(Progname, "uupoll");
uucpname(Myname);
while ((c = getopt(argc, argv, "g:n")) != EOF)
switch(c) {
case 'g':
grade = *optarg;
break;
case 'n':
nocall++;
break;
case '?':
default:
fprintf(stderr, "unknown option %s\n",
argv[optind-1]);
}
while(optind < argc) {
sysname = argv[optind++];
if (strcmp(sysname, Myname) == SAME) {
fprintf(stderr, "This *is* %s!\n", Myname);
continue;
}
if (versys(&sysname)) {
fprintf(stderr, "%s: unknown system.\n", sysname);
continue;
}
/* Remove any STST file that might stop the poll */
sprintf(wrkpre, "%s/LCK..%.*s", LOCKDIR, MAXBASENAME, sysname);
if (access(wrkpre, 0) < 0)
rmstat(sysname);
sprintf(wrkpre, "%c.%.*s", CMDPRE, SYSNSIZE, sysname);
if (!iswrk(file, "chk", Spool, wrkpre)) {
sprintf(file, "%s/%c.%.*s%cPOLL", subdir(Spool, CMDPRE),
CMDPRE, SYSNSIZE, sysname, grade);
close(creat(file, 0666));
}
/* Attempt the call */
if (!nocall)
xuucico(sysname);
}
cleanup(0);
}
cleanup(code)
int code;
{
exit(code);
}

View File

@ -0,0 +1,9 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= uuq
CFLAGS+=-I${.CURDIR}/../includes
BINMODE=6555
DPADD= ${LIBCOMPAT}
LDADD= ${LIBUU} -lcompat
.include <bsd.prog.mk>

126
usr.bin/uucp/uuq/uuq.1 Normal file
View File

@ -0,0 +1,126 @@
.\" Copyright (c) 1988, 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.
.\"
.\" @(#)uuq.1 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dt UUQ 1
.Os BSD 4.3
.Sh NAME
.Nm uuq
.Nd examine or manipulate the uucp queue
.Sh SYNOPSIS
.Nm uuq
.Op Fl l
.Op Fl h
.Op Fl s Ns Ar system
.Op Fl u Ns Ar user
.Op Fl d Ns Ar jobno
.Op Fl r Ns Ar sdir
.Op Fl b Ns Ar baud
.Sh DESCRIPTION
.Nm Uuq
is used to examine (and possibly delete) entries in the uucp queue.
.Pp
When listing jobs,
.Nm uuq
uses a format reminiscent of
.Xr ls .
For the long format,
information for each job listed includes
job number, number of files to transfer, user who
spooled the job, number of bytes to send, type of command requested
(S for sending files, R for receiving files, X for remote uucp),
and file or command desired.
.Pp
Several options are available:
.Bl -tag -width Ar
.It Fl h
Print only the summary lines for each system. Summary lines give system
name, number of jobs for the system, and total number of bytes to send.
.It Fl l
Specifies a long format listing. The default is to list only the
job numbers sorted across the page.
.It Fl s Ns Ar system
Limit output to jobs for systems whose system names begin with
.Ar system .
.It Fl u Ns Ar user
Limit output to jobs for users whose login names begin with
.Ar user .
.It Fl d Ns Ar jobno
Delete job number
.Ar jobno
(as obtained from a previous
.Nm uuq
command)
from the uucp queue.
Only the
.Tn UUCP
Administrator is permitted to delete jobs.
.It Fl r Ns Ar sdir
Look for files in the spooling directory
.Ar sdir
instead of the default
directory.
.It Fl b Ns Ar baud
Use
.Ar baud
to compute the transfer time instead of the default
1200 baud.
.El
.Sh FILES
.Bl -tag -width /usr/spool/uucp/Dhostname./D.x -compact
.It Pa /usr/spool/uucp/
Default spool directory
.It Pa /usr/spool/uucp/C./C.*
Control files
.It Pa /usr/spool/uucp/D Ns Em hostname ./D.*
Outgoing data files
.It Pa /usr/spool/uucp/X./X.*
Outgoing execution files
.El
.Sh SEE ALSO
.Xr uucp 1 ,
.Xr uux 1 ,
.Xr uulog 1 ,
.Xr uusnap 8
.Sh BUGS
No information is available on work requested by the remote machine.
.Pp
The user who requests a remote uucp command is unknown.
.Pp
.Dq Li uq \-l
can be horrendously slow.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.3 .

435
usr.bin/uucp/uuq/uuq.c Normal file
View File

@ -0,0 +1,435 @@
/*-
* 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[] = "@(#)uuq.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* uuq - looks at uucp queues
*
* Lou Salkind
* New York University
*
*/
#include "uucp.h"
#include <stdio.h>
#ifdef NDIR
#include "libndir/ndir.h"
#else !NDIR
#include <sys/dir.h>
#endif !NDIR
#include <sys/stat.h>
#define NOSYS (struct sys *)0
#define W_TYPE wrkvec[0]
#define W_FILE1 wrkvec[1]
#define W_FILE2 wrkvec[2]
#define W_USER wrkvec[3]
#define W_OPTNS wrkvec[4]
#define W_DFILE wrkvec[5]
#define W_MODE wrkvec[6]
#define WSUFSIZE 5 /* work file name suffix size */
struct sys {
char s_name[8];
int s_njobs;
off_t s_bytes;
struct job *s_jobp;
struct sys *s_sysp;
};
struct job {
int j_files;
int j_flags;
char j_jobno[WSUFSIZE];
char j_user[22];
char j_fname[128];
char j_grade;
off_t j_bytes;
time_t j_date;
struct job *j_jobp;
};
struct sys *syshead;
struct sys *getsys();
int jcompare();
char *sysname;
char *user;
char *rmjob;
int hflag;
int lflag;
char *malloc(), *calloc();
double atof();
float baudrate = 2400.;
char Username[BUFSIZ];
char Filename[BUFSIZ];
int Maxulen = 0;
struct timeb Now;
main(argc, argv)
int argc;
char **argv;
{
register int i;
register struct sys *sp;
register struct job *jp;
struct job **sortjob;
int nsys;
extern char *optarg;
extern int optind;
strcpy(Progname, "uuq");
uucpname(Myname);
while ((i = getopt(argc, argv, "r:S:s:u:d:b:hl")) != EOF)
switch (i) {
case 'r':
case 'S':
Spool = optarg;
break;
case 's':
sysname = optarg;
if (strlen(sysname) > SYSNSIZE)
sysname[SYSNSIZE] = '\0';
break;
case 'u':
user = optarg;
break;
case 'd':
rmjob = optarg;
break;
case 'b':
baudrate = atof(optarg);
break;
case 'h':
hflag++;
break;
case 'l':
lflag++;
break;
default:
fprintf(stderr,
"usage: uuq [-l] [-h] [-ssystem] [-uuser] [-djobno] [-rspool] [-bbaudrate]\n");
exit(0);
}
subchdir(Spool);
baudrate *= 0.7; /* reduce speed because of protocol overhead */
baudrate *= 7.5; /* convert to chars/minute (60/8) */
gather();
nsys = 0;
for (sp = syshead; sp; sp = sp->s_sysp) {
if (sp->s_njobs == 0)
continue;
if (!hflag && nsys++ > 0)
putchar('\n');
printf("%s: %d %s", sp->s_name,
sp->s_njobs, sp->s_njobs > 1 ? "jobs" : "job");
if (lflag) {
float minutes;
int hours;
/* The 80 * njobs is because of the uucp handshaking */
minutes = (float)(sp->s_bytes + 80 * sp->s_njobs)/baudrate;
hours = minutes/60;
printf(", %ld bytes, ", sp->s_bytes);
if (minutes > 60){
printf("%d hour%s, ",hours,
hours > 1 ? "s": "");
minutes -= 60 * hours;
}
printf("%3.1f minutes (@ effective baudrate of %d)",
minutes,(int)(baudrate/6));
}
putchar('\n');
if (hflag)
continue;
/* sort them babies! */
sortjob = (struct job **)calloc(sp->s_njobs, sizeof (struct job *));
for (i=0, jp=sp->s_jobp; i < sp->s_njobs; i++, jp=jp->j_jobp)
sortjob[i] = jp;
qsort(sortjob, sp->s_njobs, sizeof (struct job *), jcompare);
for (i = 0; i < sp->s_njobs; i++) {
jp = sortjob[i];
if (lflag) {
printf("%s %2d %-*s%7ld%5.1f %-12.12s %c %.*s\n",
jp->j_jobno, jp->j_files, Maxulen, jp->j_user, jp->j_bytes, jp->j_bytes/baudrate,
ctime(&jp->j_date) + 4, jp->j_flags, sizeof (jp->j_fname), jp->j_fname
);
} else {
printf("%s", jp->j_jobno);
putchar((i+1)%10 ? '\t' : '\n');
}
/* There's no need to keep the force poll if jobs > 1*/
if (sp->s_njobs > 1 && strcmp("POLL", jp->j_jobno)==0) {
char pbuf[BUFSIZ];
sprintf(pbuf,"%s/%c.%s%cPOLL",
subdir(Spool, CMDPRE), CMDPRE,
sp->s_name, jp->j_grade);
(void) unlink(pbuf);
}
}
if (!lflag && (sp->s_njobs%10))
putchar('\n');
}
exit(0);
}
jcompare(j1, j2)
struct job **j1, **j2;
{
int delta;
delta = (*j1)->j_grade - (*j2)->j_grade;
if (delta)
return delta;
return(strcmp((*j1)->j_jobno,(*j2)->j_jobno));
}
/*
* Get all the command file names
*/
gather()
{
struct direct *d;
DIR *df;
/*
* Find all the spool files in the spooling directory
*/
if ((df = opendir(subdir(Spool, CMDPRE))) == NULL) {
fprintf(stderr, "can't examine spooling area\n");
exit(1);
}
for (;;) {
if ((d = readdir(df)) == NULL)
break;
if (d->d_namlen <= 2 || d->d_name[0] != CMDPRE ||
d->d_name[1] != '.')
continue;
if (analjob(d->d_name) < 0) {
fprintf(stderr, "out of memory\n");
break;
}
}
closedir(df);
}
/*
* analjob does the grunge work of verifying jobs
*/
#include <pwd.h>
analjob(filename)
char *filename;
{
struct job *jp;
struct sys *sp;
char sbuf[MAXNAMLEN+1], str[256], nbuf[256];
char *jptr, *wrkvec[20];
char grade;
FILE *fp, *df;
struct stat statb;
int files, gotname, i;
off_t bytes;
strncpy(sbuf, filename, MAXNAMLEN);
sbuf[MAXNAMLEN] = '\0';
jptr = sbuf + strlen(sbuf) - WSUFSIZE;
grade = *jptr;
*jptr++ = 0;
/*
* sbuf+2 now points to sysname name (null terminated)
* jptr now points to job number (null terminated)
*/
if (rmjob) {
if (strcmp(rmjob, jptr))
return(0);
} else {
if ((sp = getsys(sbuf+2)) == NOSYS)
return(0);
if (!lflag) {
/* SHOULD USE A SMALLER STRUCTURE HERE */
jp = (struct job *)malloc(sizeof(struct job));
if (jp == (struct job *)0)
return(-1);
strcpy(jp->j_jobno, jptr);
jp->j_jobp = sp->s_jobp;
jp->j_grade = grade;
sp->s_jobp = jp;
sp->s_njobs++;
return(1);
}
}
if ((fp = fopen(subfile(filename), "r")) == NULL) {
perror(subfile(filename));
return(0);
}
files = 0;
bytes = 0;
gotname = 0;
while (fgets(str, sizeof str, fp)) {
if (getargs(str, wrkvec, 20) <= 0)
continue;
if (rmjob) {
int myuid;
struct passwd *pw;
/*
* Make sure person who is removing data files is
* the person who created it or root.
*/
myuid = getuid();
pw = getpwnam(W_USER);
if (myuid && (pw == NULL || myuid != pw->pw_uid)) {
fprintf(stderr, "Permission denied.\n");
exit(1);
}
if (W_TYPE[0] == 'S' && !index(W_OPTNS, 'c')) {
unlink(subfile(W_DFILE));
fprintf(stderr, "Removing data file %s\n", W_DFILE);
}
continue;
}
if (user && (W_TYPE[0] == 'X' || !prefix(user, W_USER))) {
fclose(fp);
return(0);
}
files++;
if (W_TYPE[0] == 'S') {
if (strcmp(W_DFILE, "D.0") &&
stat(subfile(W_DFILE), &statb) >= 0)
bytes += statb.st_size;
else if (stat(subfile(W_FILE1), &statb) >= 0)
bytes += statb.st_size;
}
/* amusing heuristic */
#define isXfile(s) (s[0]=='D' && s[strlen(s)-WSUFSIZE]=='X')
if (gotname == 0 && isXfile(W_FILE1)) {
if ((df = fopen(subfile(W_FILE1), "r")) == NULL)
continue;
while (fgets(nbuf, sizeof nbuf, df)) {
nbuf[strlen(nbuf) - 1] = '\0';
if (nbuf[0] == 'C' && nbuf[1] == ' ') {
strcpy(Filename, nbuf+2);
gotname++;
} else if (nbuf[0] == 'R' && nbuf[1] == ' ') {
register char *p, *q, *r;
r = q = p = nbuf+2;
do {
if (*p == '!' || *p == '@'){
r = q;
q = p+1;
}
} while (*p++);
strcpy(Username, r);
W_USER = Username;
}
}
fclose(df);
}
}
fclose(fp);
if (rmjob) {
unlink(subfile(filename));
fprintf(stderr, "Removing command file %s\n", filename);
exit(0);
}
if (files == 0) {
static char *wtype = "X";
static char *wfile = "forced poll";
if (strcmp("POLL", &filename[strlen(filename)-4])) {
fprintf(stderr, "%.14s: empty command file\n", filename);
return(0);
}
W_TYPE = wtype;
W_FILE1 = wfile;
}
jp = (struct job *)malloc(sizeof(struct job));
if (jp == (struct job *)0)
return(-1);
strcpy(jp->j_jobno, jptr);
jp->j_files = files;
jp->j_bytes = bytes;
jp->j_grade = grade;
jp->j_flags = W_TYPE[0];
strncpy(jp->j_user, W_TYPE[0]=='X' ? "---" : W_USER, 20 );
jp->j_user[20] = '\0';
i = strlen(jp->j_user);
if (i > Maxulen)
Maxulen = i;
/* SHOULD ADD ALL INFORMATION IN THE WHILE LOOP */
if (gotname)
strncpy(jp->j_fname, Filename, sizeof jp->j_fname);
else
strncpy(jp->j_fname, W_FILE1, sizeof jp->j_fname);
stat(subfile(filename), &statb);
jp->j_date = statb.st_mtime;
jp->j_jobp = sp->s_jobp;
sp->s_jobp = jp;
sp->s_njobs++;
sp->s_bytes += jp->j_bytes;
return(1);
}
struct sys *
getsys(s)
register char *s;
{
register struct sys *sp;
for (sp = syshead; sp; sp = sp->s_sysp)
if (strcmp(s, sp->s_name) == 0)
return(sp);
if (sysname && !prefix(sysname, s))
return(NOSYS);
sp = (struct sys *)malloc(sizeof(struct sys));
if (sp == NOSYS)
return(NOSYS);
strcpy(sp->s_name, s);
sp->s_njobs = 0;
sp->s_jobp = (struct job *)0;
sp->s_sysp = syshead;
sp->s_bytes = 0;
syshead = sp;
return(sp);
}

View File

@ -0,0 +1,6 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= uusend
LINKS= ${BINDIR}/uusend ${BINDIR}/ruusend
.include <bsd.prog.mk>

View File

@ -0,0 +1,96 @@
.\" Copyright (c) 1980, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)uusend.1 8.3 (Berkeley) 2/16/94
.\"
.Dd February 16, 1994
.Dt UUSEND 1
.Os BSD 4
.Sh NAME
.Nm uusend
.Nd send a file to a remote host
.Sh SYNOPSIS
.Nm uusend
.Op Fl m Ar mode
.Ar sourcefile
.Ar sys1!sys2!..!remotefile
.Sh DESCRIPTION
.Nm Uusend
sends a file to a given location on a remote system.
The system need not be directly connected to the local
system, but a chain of
.Xr uucp 1
links must to connect the two systems.
.Pp
Available option:
.Bl -tag -width Fl
.It Fl m Ar mode
The mode of the file on the remote
end is taken from the octal number given.
Otherwise, the mode of the input file will be used.
.El
.Pp
The sourcefile
can be
.Ql Fl ,
meaning to use the standard input.
Both of these options are primarily intended for internal use of
.Nm uusend .
.Pp
The remotefile can include the
.Em ~userid
syntax.
.Sh DIAGNOSTICS
If anything goes wrong any further away than the first system down
the line, you will never hear about it.
.Sh SEE ALSO
.Xr uux 1 ,
.Xr uucp 1 ,
.Xr uuencode 1
.Sh BUGS
This command should not exist, since
.Xr uucp
should handle it.
.Pp
All systems along the line must have the
.Nm uusend
command available and allow remote execution of it.
.Pp
Some uucp systems have a bug where binary files cannot be the
input to a
.Xr uux 1
command. If this bug exists in any system along the line,
the file will show up severely munged.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.0 .

View File

@ -0,0 +1,403 @@
/*-
* Copyright (c) 1980, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1980, 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)uusend.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
/*
* uusend: primitive operation to allow uucp like copy of binary files
* but handle indirection over systems.
*
* usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile
* uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile
*
* Author: Mark Horton, May 1980.
*
* "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW
*
* Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail).
* Checks for illegal access to /usr/lib/uucp.
* February 1983 Christopher Woodbury
* Fixed mode set[ug]id loophole. 4/8/83 CCW
*
* Add '-f' to make uusend syntax more similar to UUCP. "destname"
* can now be a directory. June 1983 CCW
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <pwd.h>
/*
* define RECOVER to permit requests like 'uusend file sys1!sys2!~uucp'
* (abbreviation for 'uusend file sys1!sys2!~uucp/file').
* define DEBUG to keep log of uusend uusage.
* define RUUSEND if neighboring sites permit 'ruusend',
* which they certainly should to avoid security holes
*/
#define RECOVER
/*#define DEBUG "/usr/spool/uucp/uusend.log"/**/
FILE *in, *out;
FILE *dout;
extern FILE *popen();
extern char *index(), *strcpy(), *strcat(), *ctime();
#ifdef RUUSEND
int rsend;
#endif RUUSEND
int mode = -1; /* mode to chmod new file to */
char *nextsys; /* next system in the chain */
char dnbuf[200]; /* buffer for result of ~user/file */
char cmdbuf[256]; /* buffer to build uux command in */
char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */
struct passwd *user; /* entry in /etc/passwd for ~user */
struct passwd *getpwnam();
struct stat stbuf;
char *excl; /* location of first ! in destname */
char *sl; /* location of first / in destname */
char *sourcename; /* argv[1] */
char *destname; /* argv[2] */
char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */
#ifdef RECOVER
char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */
char *filename; /* file name from end of destname */
char *getfname(); /* routine to get filename from destname */
int fflg;
char f[100]; /* name of default output file */
#else !RECOVER
char *f = ""; /* so we waste a little space */
#endif !RECOVER
main(argc, argv)
int argc;
char **argv;
{
register int c;
long count;
extern char **environ;
#ifdef DEBUG
long t;
umask(022);
dout = fopen(DEBUG, "a");
if (dout == NULL) {
printf("Cannot append to %s\n", DEBUG);
exit(1);
}
freopen(DEBUG, "a", stdout);
fprintf(dout, "\nuusend run: ");
for (c=0; c<argc; c++)
fprintf(dout, "%s ", argv[c]);
time(&t);
fprintf(dout, "%s", ctime(&t));
#endif DEBUG
#ifdef RUUSEND
if(argv[0][0] == 'r')
rsend++;
#endif RUUSEND
while (argc > 1 && argv[1][0] == '-' && argv[1][1]) {
switch(argv[1][1]) {
case 'm':
sscanf(argv[2], "%o", &mode);
mode &= 0777; /* fix set[ug]id loophole */
argc--; argv++;
break;
case 'r': /* -r flag for uux */
rflg = "-r ";
break;
#ifdef RECOVER
case 'f':
fflg++;
strcpy(f, argv[1]);
break;
#endif RECOVER
default:
fprintf(stderr, "Bad flag: %s\n", argv[1]);
break;
}
argc--; argv++;
}
if (argc != 3) {
fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n");
exit(1);
}
sourcename = argv[1];
destname = argv[2];
if (sourcename[0] == '-')
in = stdin;
else {
#ifdef RUUSEND
if (rsend) {
fprintf(stderr, "illegal input\n");
exit(2);
}
#endif RUUSEND
in = fopen(sourcename, "r");
if (in == NULL) {
perror(argv[1]);
exit(2);
}
if (!fflg || f[2] == '\0') {
strcpy(f, "-f");
strcat(f, getfname(sourcename));
fflg++;
}
}
excl = index(destname, '!');
if (excl) {
/*
* destname is on a remote system.
*/
nextsys = destname;
*excl++ = 0;
destname = excl;
if (mode < 0) {
fstat(fileno(in), &stbuf);
mode = stbuf.st_mode & 0777;
}
#ifdef RUUSEND
sprintf(cmdbuf,"uux -gn -z %s- \"%s!ruusend %s -m %o - (%s)\"",
#else !RUUSEND
sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"",
#endif !RUUSEND
rflg, nextsys, f, mode, destname);
#ifdef DEBUG
fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf);
#endif DEBUG
out = popen(cmdbuf, "w");
} else {
/*
* destname is local.
*/
if (destname[0] == '~') {
#ifdef DEBUG
fprintf(dout, "before ~: '%s'\n", destname);
fflush(dout);
#endif DEBUG
sl = index(destname, '/');
#ifdef RECOVER
if (sl == NULL && !fflg) {
fprintf(stderr, "Illegal ~user\n");
exit(3);
}
for (sl = destname; *sl != '\0'; sl++)
; /* boy, is this a hack! */
#else !RECOVER
if (sl == NULL) {
fprintf(stderr, "Illegal ~user\n");
exit(3);
}
*sl++ = 0;
#endif !RECOVER
user = getpwnam(destname+1);
if (user == NULL) {
fprintf(stderr, "No such user as %s\n",
destname);
#ifdef RECOVER
if ((filename =getfname(sl)) == NULL &&
!fflg)
exit(4);
strcpy(dnbuf, UUPUB);
if (fflg)
strcat(dnbuf, &f[2]);
else
strcat(dnbuf, filename);
}
else {
strcpy(dnbuf, user->pw_dir);
strcat(dnbuf, "/");
strcat(dnbuf, sl);
}
#else !RECOVER
exit(4);
}
strcpy(dnbuf, user->pw_dir);
strcat(dnbuf, "/");
strcat(dnbuf, sl);
#endif !RECOVER
destname = dnbuf;
}
#ifdef RECOVER
else
destname = strcpy(dnbuf, destname);
#endif !RECOVER
if(strncmp(UULIB, destname, strlen(UULIB)) == 0) {
fprintf(stderr, "illegal file: %s", destname);
exit(4);
}
#ifdef RECOVER
if (stat(destname, &stbuf) == 0 &&
(stbuf.st_mode & S_IFMT) == S_IFDIR &&
fflg) {
strcat(destname, "/");
strcat(destname, &f[2]);
}
#endif RECOVER
out = fopen(destname, "w");
#ifdef DEBUG
fprintf(dout, "local, file='%s'\n", destname);
#endif DEBUG
if (out == NULL) {
perror(destname);
#ifdef RECOVER
if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0)
exit(5); /* forget it! */
filename = getfname(destname);
if (destname == dnbuf) /* cmdbuf is scratch */
filename = strcpy(cmdbuf, filename);
destname = strcpy(dnbuf, UUPUB);
if (user != NULL) {
strcat(destname, user->pw_name);
if (stat(destname, &stbuf) == -1) {
mkdir(destname, 0777);
}
strcat(destname, "/");
}
if (fflg)
strcat(destname, &f[2]);
else
strcat(destname, filename);
if ((out = fopen(destname, "w")) == NULL)
exit(5); /* all for naught! */
#else !RECOVER
exit(5);
#endif !RECOVER
}
if (mode > 0)
chmod(destname, mode); /* don't bother to check it */
}
/*
* Now, in any case, copy from in to out.
*/
count = 0;
while ((c=getc(in)) != EOF) {
putc(c, out);
count++;
}
#ifdef DEBUG
fprintf(dout, "count %ld bytes\n", count);
fclose(dout);
#endif DEBUG
fclose(in);
fclose(out); /* really should pclose in that case */
exit(0);
}
/*
* Return the ptr in sp at which the character c appears;
* NULL if not found. Included so I don't have to fight the
* index/strchr battle.
*/
#define NULL 0
char *
index(sp, c)
register char *sp, c;
{
do {
if (*sp == c)
return(sp);
} while (*sp++);
return(NULL);
}
#ifdef RECOVER
char *
getfname(p)
register char *p;
{
register char *s;
s = p;
while (*p != '\0')
p++;
if (p == s)
return (NULL);
for (;p != s; p--)
if (*p == '/') {
p++;
break;
}
return (p);
}
#ifndef BSD4_2
makedir(dirname, mode)
char *dirname;
int mode;
{
register int pid;
int retcode, status;
switch ((pid = fork())) {
case -1: /* error */
return (-1);
case 0: /* child */
umask(0);
execl("/bin/mkdir", "mkdir", dirname, (char *)0);
exit(1);
/* NOTREACHED */
default: /* parent */
while ((retcode=wait(&status)) != pid && retcode != -1)
;
if (retcode == -1)
return -1;
else {
chmod(dirname, mode);
return status;
}
}
/* NOTREACHED */
}
#endif !BSD4_2
#endif RECOVER

View File

@ -0,0 +1,80 @@
.\" Copyright (c) 1983, 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.
.\"
.\" @(#)uusnap.8 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dt UUSNAP 8
.Os BSD 4.2
.Sh NAME
.Nm uusnap
.Nd show snapshot of the
.Tn UUCP
system
.Sh SYNOPSIS
.Nm uusnap
.Sh DESCRIPTION
.Nm Uusnap
displays in tabular format a synopsis of the current
.Tn UUCP
situation. The format of each line is as follows:
.Bd -literal -offset indent -compact
site N Cmds N Data N Xqts Message
.Ed
Where "site" is the name of the site with work, "N" is a count of
each of the three possible types of work (command, data, or remote execute),
and "Message" is the current status message for that
site as found in the
.Tn STST
file.
.Pp
Included in "Message" may be the time left before
.Tn UUCP
can re-try the
call, and the count of the number of times that
.Tn UUCP
has tried
(unsuccessfully) to reach the site.
.Sh SEE ALSO
.Xr uucp 1 ,
.Xr uux 1 ,
.Xr uuq 1 ,
.Xr uucico 8
.Rs
.%T "UUCP Implementation Guide"
.Re
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

View File

@ -0,0 +1,348 @@
/*-
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rick Adams. Originally by RJKing WECo-MG6565 May 83.
*
* 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[] = "@(#)uusnap.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#include "uucp.h"
#include <sys/stat.h>
#ifdef NDIR
#include "ndir.h"
#else
#include <sys/dir.h>
#endif
#include <ctype.h>
#define NSYSTEM 300 /* max # of systems queued */
#define CMDSLEN 5 /* Length of trailer */
#define DATALEN 5 /* Length of trailer */
#define XEQTLEN 5 /* Length of trailer */
#define NUMCTRS 3 /* # file types to count */
#define CMDTYPE 0 /* Index into scnt.cntr */
#define DATTYPE 1 /* Index into scnt.cntr */
#define XEQTYPE 2 /* Index into scnt.cntr */
struct scnt { /* System count structure */
char name[MAXBASENAME+1]; /* Name of system */
short cntr[NUMCTRS]; /* Count */
char stst[32]; /* STST Message */
time_t locked; /* If LCK..sys present */
int st_type; /* STST Type */
int st_count; /* STST Count */
time_t st_lastime; /* STST Last time tried */
time_t st_retry; /* STST Secs to retry */
};
int sndx; /* Number of systems */
struct scnt sys[NSYSTEM]; /* Systems queued */
int xqtisrunning = 0;
main()
{
register int i, j, nlen = 0;
time_t curtime, t;
dodir(CMDSDIR, "C.", CMDSLEN, '\0', CMDTYPE);
dodir(DATADIR, "D.", DATALEN, '\0', DATTYPE);
dodir(XEQTDIR, "X.", XEQTLEN, 'X', XEQTYPE);
getstst(SPOOL);
time(&curtime);
for(i=0; i<sndx; ++i)
if((j = strlen(sys[i].name)) > nlen)
nlen = j;
for(i=0; i<sndx; ++i) {
t = (sys[i].st_lastime +sys[i].st_retry) - curtime;
/* decide if STST text is worth printing */
if (-t < ONEDAY*2 && sys[i].st_type == SS_WRONGTIME) {
sys[i].stst[0] = '\0';
if (sys[i].cntr[0]+sys[i].cntr[1]+sys[i].cntr[2] == 0)
continue; /* ignore entire line */
}
printf("%-*.*s ", nlen, nlen, sys[i].name);
if(sys[i].cntr[CMDTYPE])
printf("%3.d Cmd%s ", sys[i].cntr[CMDTYPE],
sys[i].cntr[CMDTYPE]>1?"s":" ");
else
printf(" --- ");
if(sys[i].cntr[DATTYPE])
printf("%3.d Data ", sys[i].cntr[DATTYPE]);
else
printf(" --- ");
if(sys[i].cntr[XEQTYPE])
printf("%3.d Xqt%s ", sys[i].cntr[XEQTYPE],
sys[i].cntr[XEQTYPE]>1?"s":" ");
else
printf(" --- ");
if(*sys[i].stst == '\0' || sys[i].locked > sys[i].st_lastime) {
if(sys[i].locked)
printf("LOCKED\n");
else
printf("\n");
continue;
}
printf("%s ", sys[i].stst);
/* decide if STST info is worth pursuing */
if (-t < ONEDAY*2 && (sys[i].st_count == 0
|| sys[i].st_type == SS_WRONGTIME
|| (sys[i].st_type == SS_INPROGRESS && sys[i].locked))) {
printf("\n");
continue;
}
t = (sys[i].st_lastime +sys[i].st_retry) - curtime;
if (-t < ONEDAY*2 && sys[i].st_type != SS_FAIL)
t = 0;
if (sys[i].st_count > MAXRECALLS)
printf("at MAX RECALLS");
else if (-t >= ONEDAY*2)
printf("%ld days ago", (long)-t/ONEDAY);
else if (t <= 0)
printf("Retry time reached");
else if (t < 60)
printf("Retry time %ld sec%s", (long)(t%60),
(t%60)!=1? "s": "");
else
printf("Retry time %ld min%s", (long)(t/60),
(t/60)!=1? "s": "");
if(sys[i].st_count > 1)
printf(" Count: %d\n", sys[i].st_count);
else
printf("\n");
}
if (xqtisrunning)
printf("\nUuxqt is running\n");
exit(0);
}
dodir(dnam, prfx, flen, fchr, type)
char *dnam, *prfx;
int flen;
char fchr;
int type;
{
register struct direct *dentp;
register DIR *dirp;
register int i, fnamlen, plen;
char fnam[MAXNAMLEN+1];
plen = strlen(prfx);
if(chdir(dnam) < 0) {
perror(dnam);
exit(1);
}
if ((dirp = opendir(".")) == NULL) {
perror(dnam);
exit(1);
}
while((dentp = readdir(dirp)) != NULL) {
if(*dentp->d_name == '.')
continue;
if(strncmp(dentp->d_name, prfx, plen) != SAME) {
fprintf(stderr, "strange file (%s) in %s\n",
dentp->d_name, dnam);
continue;
}
strcpy(fnam, &dentp->d_name[plen]);
fnamlen = strlen(fnam);
if(flen > 0) {
fnamlen -= flen;
fnam[fnamlen] = '\0';
fnamlen = MAXBASENAME; /* yes, after = '\0'*/
} else {
for(; fnamlen>0; --fnamlen) {
if(fnam[fnamlen] == fchr) {
fnam[fnamlen] = '\0';
break;
}
}
fnamlen = MAXBASENAME;
}
for(i=0; i<sndx; ++i) {
if(strncmp(fnam, sys[i].name, fnamlen) == SAME) {
++sys[i].cntr[type];
break;
}
}
if(i == sndx) {
strcpy(sys[i].name, fnam);
++sys[i].cntr[type];
if(++sndx >= NSYSTEM) {
sndx = NSYSTEM-1;
fprintf(stderr,"Too many system names.\n");
}
}
}
closedir(dirp);
}
getstst(sdir)
char *sdir;
{
register int i, csys;
register char *tp;
char fnam[MAXNAMLEN+1], buff[128];
register struct direct *dentp;
register DIR *dirp;
register FILE *st;
struct stat stbuf;
long atol();
if (chdir(sdir) < 0) {
perror(sdir);
exit(1);
}
if ((dirp = opendir(LOCKDIR)) == NULL) {
perror(sdir);
exit(1);
}
while ((dentp = readdir(dirp)) != NULL) {
if (strcmp(&dentp->d_name[5], X_LOCK) == SAME) {
xqtisrunning++;
continue;
}
if(strncmp(dentp->d_name, "LCK..", 5) == SAME) {
if(strncmp(&dentp->d_name[5], "tty", 3) == SAME ||
strncmp(&dentp->d_name[5], "cul", 3) == SAME)
continue;
strcpy(fnam, dentp->d_name);
for(csys=0; csys<sndx; ++csys) {
if(strncmp(&fnam[5], sys[csys].name, SYSNSIZE)
== SAME)
break;
}
strcpy(sys[csys].name, &fnam[5]);
if(csys == sndx) {
++sndx;
}
if (stat(fnam, &stbuf) < 0)
sys[csys].locked = 1;
else
sys[csys].locked = stbuf.st_mtime;
continue;
}
}
closedir(dirp);
if (chdir("STST") < 0) {
perror("STST");
exit(1);
}
if ((dirp = opendir(".")) == NULL) {
perror("STST");
exit(1);
}
while ((dentp = readdir(dirp)) != NULL) {
if(*dentp->d_name == '.')
continue;
strcpy(fnam, dentp->d_name);
for(csys=0; csys<sndx; ++csys) {
if(strncmp(fnam, sys[csys].name, SYSNSIZE) == SAME)
break;
}
strcpy(sys[csys].name, fnam);
if(csys == sndx) {
++sndx;
}
if((st = fopen(fnam, "r")) == NULL) {
sys[csys].stst[0] = '\0';
continue;
}
buff[0] = '\0';
fgets(buff, sizeof(buff), st);
fclose(st);
if(tp = rindex(buff, ' '))
*tp = '\0'; /* drop system name */
else
continue;
for(i=0, tp=buff; i<4; ++i, ++tp)
if((tp = index(tp, ' ')) == NULL)
break;
if(i != 4)
continue;
strncpy(sys[csys].stst, tp, sizeof(sys[csys].stst));
tp = buff;
sys[csys].st_type = atoi(tp);
tp = index(tp+1, ' ');
sys[csys].st_count = atoi(tp+1);
tp = index(tp+1, ' ');
sys[csys].st_lastime = atol(tp+1);
tp = index(tp+1, ' ');
sys[csys].st_retry = atol(tp+1);
}
}
/*
* Return the ptr in sp at which the character c appears;
* NULL if not found
*/
char *
index(sp, c)
register char *sp, c;
{
do {
if (*sp == c)
return sp;
} while (*sp++);
return NULL;
}
/*
* Return the ptr in sp at which the character c last
* appears; NULL if not found
*/
char *
rindex(sp, c)
register char *sp, c;
{
register char *r;
r = NULL;
do {
if (*sp == c)
r = sp;
} while (*sp++);
return r;
}

7
usr.bin/whatis/Makefile Normal file
View File

@ -0,0 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= whatis
SRCS= whatis.c config.c
.PATH: ${.CURDIR}/../man
.include <bsd.prog.mk>

105
usr.bin/whatis/whatis.1 Normal file
View File

@ -0,0 +1,105 @@
.\" Copyright (c) 1989, 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.
.\"
.\" @(#)whatis.1 8.1 (Berkeley) 6/6/93
.\"
.Dd June 6, 1993
.Dt WHATIS 1
.Os BSD 4
.Sh NAME
.Nm whatis
.Nd describe what a command is
.Sh SYNOPSIS
.Nm whatis
.Op Fl M Ar path
.Op Fl m Ar path
.Ar command Ar ...
.Sh DESCRIPTION
.Nm Whatis
looks up a given command and gives the header line from the manual page.
You can then use the
.Xr man 1
command to get more information.
.Pp
The options are as follows:
.Bl -tag -width Fl
.It Fl M Ar path
Override the list of standard directories
.Nm whatis
searches for its database named
.Dq Pa whatis.db .
The supplied
.Ar path
must be a colon
.Dq \&:
separated list of directories.
This search path may also be set using the environment variable
.Ev MANPATH .
.It Fl m Ar path
Augment the list of standard directories
.Nm whatis
searches for its database named
.Dq Pa whatis.db .
The supplied
.Ar path
must be a colon
.Dq \&:
separated list of directories.
These directories will be searched before the standard directories
or the directories supplied with the
.Fl M
option or the
.Ev MANPATH
environment variable are searched.
.El
.Sh ENVIRONMENT
.Bl -tag -width MANPATH
.It Ev MANPATH
The standard search path used by
.Xr man 1
may be overridden by specifying a path in the
.Ev MANPATH
environment variable.
.El
.Sh FILES
.Bl -tag -width whatis.db
.It Pa whatis.db
name of the whatis database
.El
.Sh SEE ALSO
.Xr apropos 1 ,
.Xr man 1 ,
.Xr whereis 1
.Sh HISTORY
The
.Nm
command appeared in
.Bx 3.0 .

218
usr.bin/whatis/whatis.c Normal file
View File

@ -0,0 +1,218 @@
/*
* 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[] = "@(#)whatis.c 8.5 (Berkeley) 1/2/94";
#endif /* not lint */
#include <sys/param.h>
#include <sys/queue.h>
#include <ctype.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../man/config.h"
#include "../man/pathnames.h"
#define MAXLINELEN 256 /* max line handled */
static int *found, foundman;
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
ENTRY *ep;
TAG *tp;
int ch, rv;
char *beg, *conffile, **p, *p_augment, *p_path;
conffile = NULL;
p_augment = p_path = NULL;
while ((ch = getopt(argc, argv, "C:M:m:P:")) != EOF)
switch (ch) {
case 'C':
conffile = optarg;
break;
case 'M':
case 'P': /* backward compatible */
p_path = optarg;
break;
case 'm':
p_augment = optarg;
break;
case '?':
default:
usage();
}
argv += optind;
argc -= optind;
if (argc < 1)
usage();
if ((found = malloc((u_int)argc * sizeof(int))) == NULL)
err(1, NULL);
memset(found, 0, argc * sizeof(int));
for (p = argv; *p; ++p) /* trim full paths */
if (beg = rindex(*p, '/'))
*p = beg + 1;
if (p_augment)
whatis(argv, p_augment, 1);
if (p_path || (p_path = getenv("MANPATH")))
whatis(argv, p_path, 1);
else {
config(conffile);
ep = (tp = getlist("_whatdb")) == NULL ?
NULL : tp->list.tqh_first;
for (; ep != NULL; ep = ep->q.tqe_next)
whatis(argv, ep->s, 0);
}
if (!foundman) {
fprintf(stderr, "whatis: no %s file found.\n", _PATH_WHATIS);
exit(1);
}
rv = 1;
for (p = argv; *p; ++p)
if (found[p - argv])
rv = 0;
else
printf("%s: not found\n", *p);
exit(rv);
}
whatis(argv, path, buildpath)
char **argv, *path;
int buildpath;
{
register char *end, *name, **p;
char buf[MAXLINELEN + 1], wbuf[MAXLINELEN + 1];
for (name = path; name; name = end) { /* through name list */
if (end = index(name, ':'))
*end++ = '\0';
if (buildpath) {
char hold[MAXPATHLEN + 1];
(void)sprintf(hold, "%s/%s", name, _PATH_WHATIS);
name = hold;
}
if (!freopen(name, "r", stdin))
continue;
foundman = 1;
/* for each file found */
while (fgets(buf, sizeof(buf), stdin)) {
dashtrunc(buf, wbuf);
for (p = argv; *p; ++p)
if (match(wbuf, *p)) {
printf("%s", buf);
found[p - argv] = 1;
/* only print line once */
while (*++p)
if (match(wbuf, *p))
found[p - argv] = 1;
break;
}
}
}
}
/*
* match --
* match a full word
*/
match(bp, str)
register char *bp, *str;
{
register int len;
register char *start;
if (!*str || !*bp)
return(0);
for (len = strlen(str);;) {
for (; *bp && !isdigit(*bp) && !isalpha(*bp); ++bp);
if (!*bp)
break;
for (start = bp++;
*bp && (*bp == '_' || isdigit(*bp) || isalpha(*bp)); ++bp);
if (bp - start == len && !strncasecmp(start, str, len))
return(1);
}
return(0);
}
/*
* dashtrunc --
* truncate a string at " - "
*/
dashtrunc(from, to)
register char *from, *to;
{
register int ch;
for (; (ch = *from) && ch != '\n' &&
(ch != ' ' || from[1] != '-' || from[2] != ' '); ++from)
*to++ = ch;
*to = '\0';
}
/*
* usage --
* print usage message and die
*/
usage()
{
(void)fprintf(stderr,
"usage: whatis [-C file] [-M path] [-m path] command ...\n");
exit(1);
}