summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/apropos/Makefile7
-rw-r--r--usr.bin/apropos/apropos.1120
-rw-r--r--usr.bin/apropos/apropos.c224
-rw-r--r--usr.bin/ar/ar.1281
-rw-r--r--usr.bin/ar/ar.5.5146
-rw-r--r--usr.bin/ar/archive.c7
-rw-r--r--usr.bin/ar/misc.c7
-rw-r--r--usr.bin/ar/replace.c6
-rw-r--r--usr.bin/biff/biff.c29
-rw-r--r--usr.bin/cal/cal.16
-rw-r--r--usr.bin/calendar/calendar.c4
-rw-r--r--usr.bin/cap_mkdb/cap_mkdb.c15
-rw-r--r--usr.bin/chflags/chflags.19
-rw-r--r--usr.bin/ctags/ctags.c8
-rw-r--r--usr.bin/ftp/cmds.c13
-rw-r--r--usr.bin/ftp/cmdtab.c4
-rw-r--r--usr.bin/ftp/extern.h3
-rw-r--r--usr.bin/ftp/ftp.127
-rw-r--r--usr.bin/ftp/ftp.c76
-rw-r--r--usr.bin/ftp/ftp_var.h3
-rw-r--r--usr.bin/ftp/main.c5
-rw-r--r--usr.bin/ftp/ruserpass.c4
-rw-r--r--usr.bin/id/id.110
-rw-r--r--usr.bin/id/id.c4
-rw-r--r--usr.bin/kdump/kdump.c125
-rw-r--r--usr.bin/kdump/mkioctls35
-rw-r--r--usr.bin/ktrace/ktrace.c48
-rw-r--r--usr.bin/ktrace/subr.c4
-rw-r--r--usr.bin/lastcomm/lastcomm.c12
-rw-r--r--usr.bin/ld/Makefile7
-rw-r--r--usr.bin/ld/cplus-dem.c970
-rw-r--r--usr.bin/ld/ld.c4718
-rw-r--r--usr.bin/ld/symseg.h358
-rw-r--r--usr.bin/locate/bigram/locate.bigram.c7
-rw-r--r--usr.bin/locate/code/locate.code.c23
-rw-r--r--usr.bin/locate/locate/updatedb.csh4
-rw-r--r--usr.bin/login/login.16
-rw-r--r--usr.bin/lorder/lorder.16
-rw-r--r--usr.bin/m4/serv.c475
-rw-r--r--usr.bin/man/Makefile8
-rw-r--r--usr.bin/man/config.c176
-rw-r--r--usr.bin/man/config.h57
-rw-r--r--usr.bin/man/man.1188
-rw-r--r--usr.bin/man/man.c712
-rw-r--r--usr.bin/man/man.conf46
-rw-r--r--usr.bin/man/man.conf.5195
-rw-r--r--usr.bin/man/pathnames.h39
-rw-r--r--usr.bin/mklocale/Japanese158
-rw-r--r--usr.bin/more/output.c12
-rw-r--r--usr.bin/msgs/Makefile6
-rw-r--r--usr.bin/msgs/msgs.16
-rw-r--r--usr.bin/msgs/msgs.c9
-rw-r--r--usr.bin/nfsstat/nfsstat.c164
-rw-r--r--usr.bin/nice/nice.c9
-rw-r--r--usr.bin/passwd/kpasswd_proto.h54
-rw-r--r--usr.bin/passwd/krb_passwd.c319
-rw-r--r--usr.bin/patch/EXTERN.h15
-rw-r--r--usr.bin/patch/INTERN.h15
-rw-r--r--usr.bin/patch/config.h16
-rw-r--r--usr.bin/patch/patchlevel.h1
-rw-r--r--usr.bin/patch/version.c28
-rw-r--r--usr.bin/patch/version.h9
-rw-r--r--usr.bin/pr/pr.c75
-rw-r--r--usr.bin/printf/printf.c4
-rw-r--r--usr.bin/quota/quota.c24
-rw-r--r--usr.bin/ranlib/ranlib.5.570
-rw-r--r--usr.bin/rlogin/des_rw.c203
-rw-r--r--usr.bin/rlogin/rlogin.111
-rw-r--r--usr.bin/rlogin/rlogin.c358
-rw-r--r--usr.bin/rsh/rsh.112
-rw-r--r--usr.bin/rsh/rsh.c14
-rw-r--r--usr.bin/sccs/Makefile5
-rw-r--r--usr.bin/sccs/PSD.doc/Makefile7
-rw-r--r--usr.bin/sccs/PSD.doc/sccs.me1609
-rw-r--r--usr.bin/sccs/PSD.doc/spell.ok77
-rw-r--r--usr.bin/sccs/pathnames.h51
-rw-r--r--usr.bin/sccs/sccs.1398
-rw-r--r--usr.bin/sccs/sccs.c1621
-rw-r--r--usr.bin/sed/compile.c22
-rw-r--r--usr.bin/showmount/showmount.813
-rw-r--r--usr.bin/showmount/showmount.c62
-rw-r--r--usr.bin/split/split.c4
-rw-r--r--usr.bin/strip/strip.c71
-rw-r--r--usr.bin/tcopy/tcopy.c69
-rw-r--r--usr.bin/tip/acu.c196
-rw-r--r--usr.bin/tip/aculib/biz22.c187
-rw-r--r--usr.bin/tip/aculib/biz31.c248
-rw-r--r--usr.bin/tip/aculib/courier.c380
-rw-r--r--usr.bin/tip/aculib/df.c132
-rw-r--r--usr.bin/tip/aculib/dn11.c142
-rw-r--r--usr.bin/tip/aculib/hayes.c305
-rw-r--r--usr.bin/tip/aculib/t3000.c408
-rw-r--r--usr.bin/tip/aculib/v3451.c214
-rw-r--r--usr.bin/tip/aculib/v831.c259
-rw-r--r--usr.bin/tip/aculib/ventel.c251
-rw-r--r--usr.bin/tip/acutab.c97
-rw-r--r--usr.bin/tip/cmds.c888
-rw-r--r--usr.bin/tip/cmdtab.c64
-rw-r--r--usr.bin/tip/cu.c132
-rw-r--r--usr.bin/tip/hunt.c93
-rw-r--r--usr.bin/tip/log.c86
-rw-r--r--usr.bin/tip/partab.c58
-rw-r--r--usr.bin/tip/remcap.c426
-rw-r--r--usr.bin/tip/remote.c226
-rw-r--r--usr.bin/tip/tip.1451
-rw-r--r--usr.bin/tip/value.c353
-rw-r--r--usr.bin/tip/vars.c112
-rw-r--r--usr.bin/touch/touch.16
-rw-r--r--usr.bin/touch/touch.c4
-rw-r--r--usr.bin/tput/tput.c6
-rw-r--r--usr.bin/uucp/acucntrl/acucntrl.85
-rw-r--r--usr.bin/uucp/acucntrl/acucntrl.c814
-rw-r--r--usr.bin/uucp/uupoll/uupoll.8111
-rw-r--r--usr.bin/uucp/uupoll/uupoll.c129
-rw-r--r--usr.bin/uucp/uuq/Makefile9
-rw-r--r--usr.bin/uucp/uuq/uuq.1126
-rw-r--r--usr.bin/uucp/uuq/uuq.c435
-rw-r--r--usr.bin/uucp/uusend/Makefile6
-rw-r--r--usr.bin/uucp/uusend/uusend.196
-rw-r--r--usr.bin/uucp/uusend/uusend.c403
-rw-r--r--usr.bin/uucp/uusnap/uusnap.880
-rw-r--r--usr.bin/uucp/uusnap/uusnap.c348
-rw-r--r--usr.bin/vacation/vacation.18
-rw-r--r--usr.bin/vmstat/vmstat.c5
-rw-r--r--usr.bin/w/w.c10
-rw-r--r--usr.bin/wc/wc.c4
-rw-r--r--usr.bin/whatis/Makefile7
-rw-r--r--usr.bin/whatis/whatis.1105
-rw-r--r--usr.bin/whatis/whatis.c218
-rw-r--r--usr.bin/whois/whois.16
-rw-r--r--usr.bin/window/wwinit.c4
-rw-r--r--usr.bin/window/wwopen.c4
-rw-r--r--usr.bin/write/write.c73
133 files changed, 22784 insertions, 784 deletions
diff --git a/usr.bin/apropos/Makefile b/usr.bin/apropos/Makefile
new file mode 100644
index 0000000..028a42c
--- /dev/null
+++ b/usr.bin/apropos/Makefile
@@ -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>
diff --git a/usr.bin/apropos/apropos.1 b/usr.bin/apropos/apropos.1
new file mode 100644
index 0000000..eb68f37
--- /dev/null
+++ b/usr.bin/apropos/apropos.1
@@ -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 .
diff --git a/usr.bin/apropos/apropos.c b/usr.bin/apropos/apropos.c
new file mode 100644
index 0000000..112aada
--- /dev/null
+++ b/usr.bin/apropos/apropos.c
@@ -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);
+}
diff --git a/usr.bin/ar/ar.1 b/usr.bin/ar/ar.1
index 026aed6..fd5ce4f 100644
--- a/usr.bin/ar/ar.1
+++ b/usr.bin/ar/ar.1
@@ -32,119 +32,157 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)ar.1 8.1 (Berkeley) 6/29/93
+.\" @(#)ar.1 8.4 (Berkeley) 4/28/95
.\"
-.TH AR 1 "June 29, 1993"
-.AT 3
-.SH NAME
-ar \- create and maintain library archives
-.SH SYNOPSIS
-.nf
-.ft B
-ar -d [-Tv] archive file ...
-ar -m [-Tv] archive file ...
-ar -m [-abiTv] position archive file ...
-ar -p [-Tv] archive [file ...]
-ar -q [-cTv] archive file ...
-ar -r [-cuTv] archive file ...
-ar -r [-abciuTv] position archive file ...
-ar -t [-Tv] archive [file ...]
-ar -x [-ouTv] archive [file ...]
-.fi
-.ft R
-.SH DESCRIPTION
+.Dd "April 28, 1995"
+.Dt AR 1
+.Os
+.Sh NAME
+.Nm ar
+.Nd create and maintain library archives
+.Sh SYNOPSIS
+.Nm ar
+.Fl d
+.Op Fl \Tv
+.Ar archive file ...
+.Nm ar
+.Fl m
+.Op Fl \Tv
+.Ar archive file ...
+.Nm ar
+.Fl m
+.Op Fl abiTv
+.Ar position archive file ...
+.Nm ar
+.Fl p
+.Op Fl \Tv
+.Ar archive
+.Op Ar file ...
+.Nm ar
+.Fl q
+.Op Fl cTv
+.Ar archive file ...
+.Nm ar
+.Fl r
+.Op Fl cuTv
+.Ar archive file ...
+.Nm ar
+.Fl r
+.Op Fl abciuTv
+.Ar position archive file ...
+.Nm ar
+.Fl t
+.Op Fl \Tv
+.Ar archive
+.Op Ar file ...
+.Nm ar
+.Fl x
+.Op Fl ouTv
+.Ar archive
+.Op Ar file ...
+.Sh DESCRIPTION
The
-.I ar
+.Nm ar
utility creates and maintains groups of files combined into an archive.
Once an archive has been created, new files can be added and existing
files can be extracted, deleted, or replaced.
-.PP
+.Pp
Files are named in the archive by a single component, i.e., if a file
referenced by a path containing a slash (``/'') is archived it will be
named by the last component of that path.
When matching paths listed on the command line against file names stored
in the archive, only the last component of the path will be compared.
-.PP
+.Pp
All informational and error messages use the path listed on the command
line, if any was specified; otherwise the name in the archive is used.
If multiple files in the archive have the same name, and paths are listed
on the command line to ``select'' archive files for an operation, only the
-.B first
+.Em first
file with a matching name will be selected.
-.PP
+.Pp
The normal use of
-.I ar
+.Nm ar
is for the creation and maintenance of libraries suitable for use with
the loader (see
-.IR ld (1)),
+.Xr ld 1 ),
although it is not restricted to this purpose.
The options are as follows:
-.TP
-\-a
-A positioning modifier used with the options \-r and \-m.
+.Bl -tag -width indent
+.It Fl a
+A positioning modifier used with the options
+.Fl r
+and
+.Fl m .
The files are entered or moved
-.B after
+.Em after
the archive member
-.IR position ,
+.Ar position ,
which must be specified.
-.TP
-\-b
-A positioning modifier used with the options \-r and \-m.
+.It Fl b
+A positioning modifier used with the options
+.Fl r
+and
+.Fl m .
The files are entered or moved
-.B before
+.Em before
the archive member
-.IR position ,
+.Ar position ,
which must be specified.
-.TP
-\-c
+.It Fl c
Whenever an archive is created, an informational message to that effect
is written to standard error.
-If the \-c option is specified,
-.I ar
+If the
+.Fl c
+option is specified,
+.Nm ar
creates the archive silently.
-.TP
-\-d
+.It Fl d
Delete the specified archive files.
-.TP
-\-i
-Identical to the \-b option.
-.TP
-\-m
+.It Fl i
+Identical to the
+.Fl b
+option.
+.It Fl m
Move the specified archive files within the archive.
-If one of the options \-a, \-b or \-i is specified, the files are moved
-before or after the
-.I position
+If one of the options
+.Fl a ,
+.Fl b
+or
+.Fl i
+is specified, the files are moved before or after the
+.Ar position
file in the archive.
If none of those options are specified, the files are moved
to the end of the archive.
-.TP
-\-o
+.It Fl o
Set the access and modification times of extracted files to the
modification time of the file when it was entered into the archive.
This will fail if the user is not the owner of the extracted file
or the super-user.
-.TP
-\-p
+.It Fl p
Write the contents of the specified archive files to the standard output.
If no files are specified, the contents of all the files in the archive
are written in the order they appear in the archive.
-.TP
-\-q
+.It Fl q
(Quickly) append the specified files to the archive.
If the archive does not exist a new archive file is created.
-Much faster than the \-r option, when creating a large archive
+Much faster than the
+.Fl r
+option, when creating a large archive
piece-by-piece, as no checking is done to see if the files already
exist in the archive.
-.TP
-\-r
+.It Fl r
Replace or add the specified files to the archive.
If the archive does not exist a new archive file is created.
Files that replace existing files do not change the order of the files
within the archive.
-New files are appended to the archive unless one of the options \-a, \-b
-or \-i is specified.
-.TP
-\-T
+New files are appended to the archive unless one of the options
+.Fl a ,
+.Fl b
+or
+.Fl i
+is specified.
+.It Fl T
Select and/or name archive members using only the first fifteen characters
of the archive member or command line file name.
The historic archive format had sixteen bytes for the name, but some
@@ -155,103 +193,128 @@ characters can subsequently be confused.
A warning message is printed to the standard error output if any file
names are truncated.
(See
-.IR ar (5)
+.Xr ar 5
for more information.)
-.TP
-\-t
+.It Fl t
List the specified files in the order in which they appear in the archive,
each on a separate line.
If no files are specified, all files in the archive are listed.
-.TP
-\-u
+.It Fl u
Update files.
-When used with the \-r option, files in the archive will be replaced
+When used with the
+.Fl r
+option, files in the archive will be replaced
only if the disk file has a newer modification time than the file in
the archive.
-When used with the \-x option, files in the archive will be extracted
+When used with the
+.Fl x
+option, files in the archive will be extracted
only if the archive file has a newer modification time than the file
on disk.
-.TP
-\-v
+.It Fl v
Provide verbose output.
-When used with the \-d, \-m, \-q or \-x options,
-.I ar
+When used with the
+.Fl d ,
+.Fl m ,
+.Fl q
+or
+.Fl x
+options,
+.Nm ar
gives a file-by-file description of the archive modification.
This description consists of three, white-space separated fields: the
option letter, a dash (``-'') and the file name.
-When used with the \-r option,
-.I ar
+When used with the
+.Fl r
+option,
+.Nm ar
displays the description as above, but the initial letter is an ``a'' if
the file is added to the archive and an ``r'' if the file replaces a file
already in the archive.
-.IP
-When used with the \-p option,
+.Pp
+When used with the
+.Fl p
+option,
the name of each printed file,
enclosed in less-than (``<'') and greater-than (``>'') characters,
is written to the standard output before
the contents of the file;
it is preceded by a single newline character, and
followed by two newline characters.
-.IP
-When used with the \-t option,
-.I ar
+.Pp
+When used with the
+.Fl t
+option,
+.Nm ar
displays an ``ls -l'' style listing of information about the members of
the archive.
This listing consists of eight, white-space separated fields:
the file permissions (see
-.IR strmode (3)),
+.Xr strmode 3 ),
the decimal user and group ID's separated by a single slash (``/''),
the file size (in bytes), the file modification time (in the
-.IR date (1)
+.Xr date 1
format ``%b %e %H:%M %Y''), and the name of the file.
-.TP
-\-x
+.It Fl x
Extract the specified archive members into the files named by the command
line arguments.
If no members are specified, all the members of the archive are extracted into
the current directory.
-.IP
+.Pp
If the file does not exist, it is created; if it does exist, the owner
and group will be unchanged.
The file access and modification times are the time of the extraction
-(but see the \-o option).
+(but see the
+.Fl o
+option).
The file permissions will be set to those of the file when it was entered
into the archive; this will fail if the user is not the owner of the
extracted file or the super-user.
-.PP
+.El
+.Pp
The
-.I ar
+.Nm ar
utility exits 0 on success, and >0 if an error occurs.
-.SH ENVIRONMENT
-.TP
-TMPDIR
+.Sh ENVIRONMENT
+.Bl -tag -width indent -compact
+.It Ev TMPDIR
The pathname of the directory to use when creating temporary files.
-.SH FILES
-.TP 14
-/tmp
+.El
+.Sh FILES
+.Bl -tag -width indent -compact
+.It Pa /tmp
default temporary file directory
-.TP 14
-ar.XXXXXX
+.It Pa ar.XXXXXX
temporary file names
-.SH COMPATIBILITY
+.El
+.Sh COMPATIBILITY
By default,
-.I ar
+.Nm ar
writes archives that may be incompatible with historic archives, as
the format used for storing archive members with names longer than
fifteen characters has changed.
This implementation of
-.I ar
+.Nm ar
is backward compatible with previous versions of
-.I ar
-in that it can read and write (using the \-T option) historic archives.
-The \-T option is provided for compatibility only, and will be deleted
+.Nm ar
+in that it can read and write (using the
+.Fl T
+option) historic archives.
+The
+.Fl T
+option is provided for compatibility only, and will be deleted
in a future release.
See
-.IR ar (5)
+.Xr ar 5
for more information.
.SH STANDARDS
The
-.I ar
-utility is expected to offer a superset of the POSIX 1003.2 functionality.
-.SH "SEE ALSO"
-ld(1), ranlib(1), strmode(3), ar(5)
+.Nm ar
+utility is expected to offer a superset of the
+.St -p1003.2
+functionality.
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr ranlib 1 ,
+.Xr strmode 3 ,
+.Xr ar 5
diff --git a/usr.bin/ar/ar.5.5 b/usr.bin/ar/ar.5.5
new file mode 100644
index 0000000..2ab5b2d
--- /dev/null
+++ b/usr.bin/ar/ar.5.5
@@ -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.
diff --git a/usr.bin/ar/archive.c b/usr.bin/ar/archive.c
index 10897d9..9dd6b20 100644
--- a/usr.bin/ar/archive.c
+++ b/usr.bin/ar/archive.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)archive.c 8.3 (Berkeley) 4/2/94";
+static char sccsid[] = "@(#)archive.c 8.4 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
@@ -221,7 +221,7 @@ put_arobj(cfp, sb)
if (options & AR_TR) {
if (lname > OLDARMAXNAME) {
(void)fflush(stdout);
- warnx("warning: %s truncated to %.*s\n",
+ warnx("warning: %s truncated to %.*s",
name, OLDARMAXNAME, name);
(void)fflush(stderr);
}
@@ -299,7 +299,8 @@ copy_ar(cfp, size)
error(cfp->rname);
}
- if (cfp->flags & RPAD && size & 1 && (nr = read(from, buf, 1)) != 1) {
+ if (cfp->flags & RPAD && (size + chdr.lname) & 1 &&
+ (nr = read(from, buf, 1)) != 1) {
if (nr == 0)
badfmt();
error(cfp->rname);
diff --git a/usr.bin/ar/misc.c b/usr.bin/ar/misc.c
index d182fa9..f9c0d14 100644
--- a/usr.bin/ar/misc.c
+++ b/usr.bin/ar/misc.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)misc.c 8.3 (Berkeley) 4/2/94";
+static char sccsid[] = "@(#)misc.c 8.4 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
@@ -136,7 +136,8 @@ void
badfmt()
{
- errx(1, "%s: %s", archive, strerror(EFTYPE));
+ errno = EFTYPE;
+ err(1, "%s", archive);
}
void
@@ -144,5 +145,5 @@ error(name)
char *name;
{
- errx(1, "%s", name);
+ err(1, "%s", name);
}
diff --git a/usr.bin/ar/replace.c b/usr.bin/ar/replace.c
index cc12781..4500b90 100644
--- a/usr.bin/ar/replace.c
+++ b/usr.bin/ar/replace.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)replace.c 8.3 (Berkeley) 4/2/94";
+static char sccsid[] = "@(#)replace.c 8.4 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
@@ -102,8 +102,10 @@ replace(argv)
goto useold;
}
(void)fstat(sfd, &sb);
- if (options & AR_U && sb.st_mtime <= chdr.date)
+ if (options & AR_U && sb.st_mtime <= chdr.date) {
+ (void)close(sfd);
goto useold;
+ }
if (options & AR_V)
(void)printf("r - %s\n", file);
diff --git a/usr.bin/biff/biff.c b/usr.bin/biff/biff.c
index 8d816bf..0c5fd33 100644
--- a/usr.bin/biff/biff.c
+++ b/usr.bin/biff/biff.c
@@ -38,20 +38,22 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)biff.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)biff.c 8.2 (Berkeley) 4/29/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
+
+#include <err.h>
#include <errno.h>
-#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
static void usage __P((void));
-static void err __P((char *));
+int
main(argc, argv)
int argc;
char *argv[];
@@ -60,7 +62,6 @@ main(argc, argv)
int ch;
char *name;
-
while ((ch = getopt(argc, argv, "")) != EOF)
switch(ch) {
case '?':
@@ -70,13 +71,11 @@ main(argc, argv)
argc -= optind;
argv += optind;
- if ((name = ttyname(STDERR_FILENO)) == NULL) {
- (void)fprintf(stderr, "biff: unknown tty\n");
- exit(2);
- }
+ if ((name = ttyname(STDERR_FILENO)) == NULL)
+ err(2, "tty");
if (stat(name, &sb))
- err(name);
+ err(2, "stat");
if (*argv == NULL) {
(void)printf("is %s\n", sb.st_mode&0100 ? "y" : "n");
@@ -86,11 +85,11 @@ main(argc, argv)
switch(argv[0][0]) {
case 'n':
if (chmod(name, sb.st_mode & ~0100) < 0)
- err(name);
+ err(2, name);
break;
case 'y':
if (chmod(name, sb.st_mode | 0100) < 0)
- err(name);
+ err(2, name);
break;
default:
usage();
@@ -99,14 +98,6 @@ main(argc, argv)
}
static void
-err(name)
- char *name;
-{
- (void)fprintf(stderr, "biff: %s: %s\n", name, strerror(errno));
- exit(2);
-}
-
-static void
usage()
{
(void)fprintf(stderr, "usage: biff [y | n]\n");
diff --git a/usr.bin/cal/cal.1 b/usr.bin/cal/cal.1
index 80d95b2..f1b5a91 100644
--- a/usr.bin/cal/cal.1
+++ b/usr.bin/cal/cal.1
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)cal.1 8.1 (Berkeley) 6/6/93
+.\" @(#)cal.1 8.2 (Berkeley) 4/28/95
.\"
-.Dd June 6, 1993
+.Dd April 28, 1995
.Dt CAL 1
.Os
.Sh NAME
@@ -43,7 +43,7 @@
.Sh SYNOPSIS
.Nm cal
.Op Fl jy
-.Op Ar month Op Ar year
+.Op Oo Ar month Oc Ar \ year
.Sh DESCRIPTION
.Nm Cal
displays a simple calendar.
diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c
index 95f1898..248d97d 100644
--- a/usr.bin/calendar/calendar.c
+++ b/usr.bin/calendar/calendar.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)calendar.c 8.3 (Berkeley) 3/25/94";
+static char sccsid[] = "@(#)calendar.c 8.4 (Berkeley) 1/7/95";
#endif /* not lint */
#include <sys/param.h>
@@ -301,7 +301,7 @@ opencal()
(void)close(pdes[1]);
}
(void)close(pdes[0]);
- execl(_PATH_CPP, "cpp", "-I.", _PATH_INCLUDE, NULL);
+ execl(_PATH_CPP, "cpp", "-P", "-I.", _PATH_INCLUDE, NULL);
(void)fprintf(stderr,
"calendar: execl: %s: %s.\n", _PATH_CPP, strerror(errno));
_exit(1);
diff --git a/usr.bin/cap_mkdb/cap_mkdb.c b/usr.bin/cap_mkdb/cap_mkdb.c
index f809c86..e3c3ce5 100644
--- a/usr.bin/cap_mkdb/cap_mkdb.c
+++ b/usr.bin/cap_mkdb/cap_mkdb.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)cap_mkdb.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)cap_mkdb.c 8.2 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
@@ -62,6 +62,15 @@ DB *capdbp;
int verbose;
char *capdb, *capname, buf[8 * 1024];
+HASHINFO openinfo = {
+ 4096, /* bsize */
+ 16, /* ffactor */
+ 256, /* nelem */
+ 2048 * 1024, /* cachesize */
+ NULL, /* hash() */
+ 0 /* lorder */
+};
+
/*
* Mkcapdb creates a capability hash database for quick retrieval of capability
* records. The database contains 2 types of entries: records and references
@@ -103,8 +112,8 @@ main(argc, argv)
(void)snprintf(buf, sizeof(buf), "%s.db", capname ? capname : *argv);
if ((capname = strdup(buf)) == NULL)
err(1, "");
- if ((capdbp = dbopen(capname,
- O_CREAT | O_TRUNC | O_RDWR, DEFFILEMODE, DB_HASH, NULL)) == NULL)
+ if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
+ DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
err(1, "%s", buf);
if (atexit(dounlink))
diff --git a/usr.bin/chflags/chflags.1 b/usr.bin/chflags/chflags.1
index 79c1a72..8b07e9a 100644
--- a/usr.bin/chflags/chflags.1
+++ b/usr.bin/chflags/chflags.1
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)chflags.1 8.2 (Berkeley) 3/31/94
+.\" @(#)chflags.1 8.4 (Berkeley) 5/2/95
.\"
-.Dd March 31, 1994
+.Dd May 2, 1995
.Dt CHFLAGS 1
.Os
.Sh NAME
@@ -80,7 +80,8 @@ Flags are a comma separated list of keywords.
The following keywords are currently defined:
.Bd -literal -offset indent compact
.\"arch nothing yet.
-dump set the dump flag
+opaque set the opaque flag (owner or super-user only)
+nodump set the nodump flag (owner or super-user only)
sappnd set the system append-only flag (super-user only)
schg set the system immutable flag (super-user only)
uappnd set the user append-only flag (owner or super-user only)
@@ -92,7 +93,7 @@ Putting the letters
before an option causes the flag to be turned off.
For example:
.Bd -literal -offset indent compact
-nodump the file should never be dumped
+nouchg the immutable bit should be cleared
.Ed
.Pp
Symbolic links do not have flags, so unless the
diff --git a/usr.bin/ctags/ctags.c b/usr.bin/ctags/ctags.c
index b2e2330..64f7c93 100644
--- a/usr.bin/ctags/ctags.c
+++ b/usr.bin/ctags/ctags.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1987, 1993, 1994
+ * 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
@@ -33,12 +33,12 @@
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1987, 1993, 1994\n\
+"@(#) 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[] = "@(#)ctags.c 8.3 (Berkeley) 4/2/94";
+static char sccsid[] = "@(#)ctags.c 8.4 (Berkeley) 2/7/95";
#endif /* not lint */
#include <err.h>
@@ -131,7 +131,7 @@ main(argc, argv)
argc -= optind;
if (!argc) {
usage: (void)fprintf(stderr,
- "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...");
+ "usage: ctags [-BFadtuwvx] [-f tagsfile] file ...\n");
exit(1);
}
diff --git a/usr.bin/ftp/cmds.c b/usr.bin/ftp/cmds.c
index 8da2b20..f64c73e 100644
--- a/usr.bin/ftp/cmds.c
+++ b/usr.bin/ftp/cmds.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)cmds.c 8.5 (Berkeley) 4/6/94";
+static char sccsid[] = "@(#)cmds.c 8.6 (Berkeley) 10/9/94";
#endif /* not lint */
/*
@@ -2010,6 +2010,17 @@ LOOP:
}
void
+setpassive(argc, argv)
+ int argc;
+ char *argv[];
+{
+
+ passivemode = !passivemode;
+ printf("Passive mode %s.\n", onoff(passivemode));
+ code = passivemode;
+}
+
+void
setsunique(argc, argv)
int argc;
char *argv[];
diff --git a/usr.bin/ftp/cmdtab.c b/usr.bin/ftp/cmdtab.c
index db3b755..1b6da8c 100644
--- a/usr.bin/ftp/cmdtab.c
+++ b/usr.bin/ftp/cmdtab.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)cmdtab.c 8.3 (Berkeley) 4/2/94";
+static char sccsid[] = "@(#)cmdtab.c 8.4 (Berkeley) 10/9/94";
#endif /* not lint */
#include <stdio.h>
@@ -94,6 +94,7 @@ char rmtstatushelp[]="show status of remote machine";
char runiquehelp[] = "toggle store unique for local files";
char resethelp[] = "clear queued command replies";
char sendhelp[] = "send one file";
+char passivehelp[] = "enter passive transfer mode";
char sitehelp[] = "send site specific command to remote server\n\t\tTry \"rhelp site\" or \"site help\" for more information";
char shellhelp[] = "escape to the shell";
char sizecmdhelp[] = "show size of remote file";
@@ -150,6 +151,7 @@ struct cmd cmdtab[] = {
{ "nlist", nlisthelp, 1, 1, 1, ls },
{ "ntrans", ntranshelp, 0, 0, 1, setntrans },
{ "open", connecthelp, 0, 0, 1, setpeer },
+ { "passive", passivehelp, 0, 0, 0, setpassive },
{ "prompt", prompthelp, 0, 0, 0, setprompt },
{ "proxy", proxyhelp, 0, 0, 1, doproxy },
{ "sendport", porthelp, 0, 0, 0, setport },
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h
index 349aea3..2a8bb26 100644
--- a/usr.bin/ftp/extern.h
+++ b/usr.bin/ftp/extern.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)extern.h 8.2 (Berkeley) 4/3/94
+ * @(#)extern.h 8.3 (Berkeley) 10/9/94
*/
struct timeval;
@@ -120,6 +120,7 @@ void setglob __P((int, char **));
void sethash __P((int, char **));
void setnmap __P((int, char **));
void setntrans __P((int, char **));
+void setpassive __P((int, char **));
void setpeer __P((int, char **));
void setport __P((int, char **));
void setprompt __P((int, char **));
diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1
index 417da08..79dcbae 100644
--- a/usr.bin/ftp/ftp.1
+++ b/usr.bin/ftp/ftp.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)ftp.1 8.2 (Berkeley) 12/30/93
+.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
-.Dd December 30, 1993
+.Dd October 9, 1994
.Dt FTP 1
.Os BSD 4.2
.Sh NAME
@@ -360,7 +360,7 @@ If no local file is specified, or if
is
.Sq Fl ,
the output is sent to the terminal.
-.It Ic macdefNs Ar macro-name
+.It Ic macdef Ar macro-name
Define a macro.
Subsequent lines are stored as the macro
.Ar macro-name ;
@@ -601,6 +601,27 @@ will also attempt to automatically log the user in to
the
.Tn FTP
server (see below).
+.It Ic passive
+Toggle passive mode. If passive mode is turned on
+(default is off), the ftp client will
+send a
+.Dv PASV
+command for all data connections instead of the usual
+.Dv PORT
+command. The
+.Dv PASV
+command requests that the remote server open a port for the data connection
+and return the address of that port. The remote server listens on that
+port and the client connects to it. When using the more traditional
+.Dv PORT
+command, the client listens on a port and sends that address to the remote
+server, who connects back to it. Passive mode is useful when using
+.Nm ftp
+through a gateway router or host that controls the directionality of
+traffic.
+(Note that though ftp servers are required to support the
+.Dv PASV
+command by RFC 1123, some do not.)
.It Ic prompt
Toggle interactive prompting.
Interactive prompting
diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c
index 19e8f8e..90eccb0 100644
--- a/usr.bin/ftp/ftp.c
+++ b/usr.bin/ftp/ftp.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ftp.c 8.4 (Berkeley) 4/6/94";
+static char sccsid[] = "@(#)ftp.c 8.6 (Berkeley) 10/27/94";
#endif /* not lint */
#include <sys/param.h>
@@ -646,10 +646,10 @@ sendrequest(cmd, local, remote, printnames)
}
break;
}
- (void) gettimeofday(&stop, (struct timezone *)0);
if (closefunc != NULL)
(*closefunc)(fin);
(void) fclose(dout);
+ (void) gettimeofday(&stop, (struct timezone *)0);
(void) getreply(0);
(void) signal(SIGINT, oldintr);
if (oldintp)
@@ -658,7 +658,6 @@ sendrequest(cmd, local, remote, printnames)
ptransfer("sent", bytes, &start, &stop);
return;
abort:
- (void) gettimeofday(&stop, (struct timezone *)0);
(void) signal(SIGINT, oldintr);
if (oldintp)
(void) signal(SIGPIPE, oldintp);
@@ -676,6 +675,7 @@ abort:
code = -1;
if (closefunc != NULL && fin != NULL)
(*closefunc)(fin);
+ (void) gettimeofday(&stop, (struct timezone *)0);
if (bytes > 0)
ptransfer("sent", bytes, &start, &stop);
}
@@ -955,8 +955,8 @@ break2:
(void) signal(SIGINT, oldintr);
if (oldintp)
(void) signal(SIGPIPE, oldintp);
- (void) gettimeofday(&stop, (struct timezone *)0);
(void) fclose(din);
+ (void) gettimeofday(&stop, (struct timezone *)0);
(void) getreply(0);
if (bytes > 0 && is_retr)
ptransfer("received", bytes, &start, &stop);
@@ -965,7 +965,6 @@ abort:
/* abort using RFC959 recommended IP,SYNC sequence */
- (void) gettimeofday(&stop, (struct timezone *)0);
if (oldintp)
(void) signal(SIGPIPE, oldintr);
(void) signal(SIGINT, SIG_IGN);
@@ -985,6 +984,7 @@ abort:
(*closefunc)(fout);
if (din)
(void) fclose(din);
+ (void) gettimeofday(&stop, (struct timezone *)0);
if (bytes > 0)
ptransfer("received", bytes, &start, &stop);
(void) signal(SIGINT, oldintr);
@@ -1000,6 +1000,62 @@ initconn()
char *p, *a;
int result, len, tmpno = 0;
int on = 1;
+ int a0, a1, a2, a3, p0, p1;
+
+ if (passivemode) {
+ data = socket(AF_INET, SOCK_STREAM, 0);
+ if (data < 0) {
+ perror("ftp: socket");
+ return(1);
+ }
+ if ((options & SO_DEBUG) &&
+ setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
+ sizeof (on)) < 0)
+ perror("ftp: setsockopt (ignored)");
+ if (command("PASV") != COMPLETE) {
+ printf("Passive mode refused.\n");
+ goto bad;
+ }
+
+ /*
+ * What we've got at this point is a string of comma
+ * separated one-byte unsigned integer values.
+ * The first four are the an IP address. The fifth is
+ * the MSB of the port number, the sixth is the LSB.
+ * From that we'll prepare a sockaddr_in.
+ */
+
+ if (sscanf(pasv,"%d,%d,%d,%d,%d,%d",
+ &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
+ printf("Passive mode address scan failure. "
+ "Shouldn't happen!\n");
+ goto bad;
+ }
+
+ bzero(&data_addr, sizeof(data_addr));
+ data_addr.sin_family = AF_INET;
+ a = (char *)&data_addr.sin_addr.s_addr;
+ a[0] = a0 & 0xff;
+ a[1] = a1 & 0xff;
+ a[2] = a2 & 0xff;
+ a[3] = a3 & 0xff;
+ p = (char *)&data_addr.sin_port;
+ p[0] = p0 & 0xff;
+ p[1] = p1 & 0xff;
+
+ if (connect(data, (struct sockaddr *)&data_addr,
+ sizeof(data_addr)) < 0) {
+ perror("ftp: connect");
+ goto bad;
+ }
+#ifdef IP_TOS
+ on = IPTOS_THROUGHPUT;
+ if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
+ sizeof(int)) < 0)
+ perror("ftp: setsockopt TOS (ignored)");
+#endif
+ return(0);
+ }
noport:
data_addr = myctladdr;
@@ -1070,6 +1126,9 @@ dataconn(lmode)
struct sockaddr_in from;
int s, fromlen = sizeof (from), tos;
+ if (passivemode)
+ return (fdopen(data, lmode));
+
s = accept(data, (struct sockaddr *) &from, &fromlen);
if (s < 0) {
warn("accept");
@@ -1093,15 +1152,16 @@ ptransfer(direction, bytes, t0, t1)
struct timeval *t0, *t1;
{
struct timeval td;
- float s, bs;
+ float s;
+ long bs;
if (verbose) {
tvsub(&td, t1, t0);
s = td.tv_sec + (td.tv_usec / 1000000.);
#define nz(x) ((x) == 0 ? 1 : (x))
bs = bytes / nz(s);
- printf("%ld bytes %s in %.2g seconds (%.2g Kbytes/s)\n",
- bytes, direction, s, bs / 1024.);
+ printf("%ld bytes %s in %.3g seconds (%ld bytes/s)\n",
+ bytes, direction, s, bs);
}
}
diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h
index 3a0d1bc..8252f5e 100644
--- a/usr.bin/ftp/ftp_var.h
+++ b/usr.bin/ftp/ftp_var.h
@@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * @(#)ftp_var.h 8.3 (Berkeley) 4/2/94
+ * @(#)ftp_var.h 8.4 (Berkeley) 10/9/94
*/
/*
@@ -66,6 +66,7 @@ int mapflag; /* use mapin mapout templates on file names */
int code; /* return/reply code for ftp command */
int crflag; /* if 1, strip car. rets. on ascii gets */
char pasv[64]; /* passive port for proxy data connection */
+int passivemode; /* passive mode enabled */
char *altarg; /* argv[1] with no shell-like preprocessing */
char ntin[17]; /* input translation table */
char ntout[17]; /* output translation table */
diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c
index 37fa85b..72c63cd 100644
--- a/usr.bin/ftp/main.c
+++ b/usr.bin/ftp/main.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 4/3/94";
+static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 10/9/94";
#endif /* not lint */
/*
@@ -78,7 +78,7 @@ main(argc, argv)
autologin = 1;
while ((ch = getopt(argc, argv, "dgintv")) != EOF) {
- switch (*cp) {
+ switch (ch) {
case 'd':
options |= SO_DEBUG;
debug++;
@@ -118,6 +118,7 @@ main(argc, argv)
verbose++;
cpend = 0; /* no pending replies */
proxy = 0; /* proxy not active */
+ passivemode = 0; /* passive mode not active */
crflag = 1; /* strip c.r. on ascii gets */
sendport = -1; /* not using ports */
/*
diff --git a/usr.bin/ftp/ruserpass.c b/usr.bin/ftp/ruserpass.c
index 07bb1f4..0a13fcd 100644
--- a/usr.bin/ftp/ruserpass.c
+++ b/usr.bin/ftp/ruserpass.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)ruserpass.c 8.3 (Berkeley) 4/2/94";
+static char sccsid[] = "@(#)ruserpass.c 8.4 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/types.h>
@@ -144,7 +144,7 @@ next:
}
break;
case PASSWD:
- if (strcmp(*aname, "anonymous") &&
+ if ((*aname == NULL || strcmp(*aname, "anonymous")) &&
fstat(fileno(cfile), &stb) >= 0 &&
(stb.st_mode & 077) != 0) {
warnx("Error: .netrc file is readable by others.");
diff --git a/usr.bin/id/id.1 b/usr.bin/id/id.1
index 99010fc..3bc454e 100644
--- a/usr.bin/id/id.1
+++ b/usr.bin/id/id.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1991, 1993
+.\" Copyright (c) 1991, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)id.1 8.1 (Berkeley) 6/6/93
+.\" @(#)id.1 8.2 (Berkeley) 5/5/94
.\"
-.Dd "June 6, 1993"
+.Dd "May 5, 1994"
.Dt ID 1
.Os BSD 4.4
.Sh NAME
@@ -134,6 +134,6 @@ command is equivalent to
.Dq Nm id Fl un .
.Pp
The
-.Nm
-command appears in
+.Nm id
+command first appeared in
.Bx 4.4 .
diff --git a/usr.bin/id/id.c b/usr.bin/id/id.c
index a2d6ea6..bf9218e 100644
--- a/usr.bin/id/id.c
+++ b/usr.bin/id/id.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)id.c 8.2 (Berkeley) 2/16/94";
+static char sccsid[] = "@(#)id.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
@@ -236,7 +236,7 @@ user(pw)
id = pw->pw_uid;
(void)printf("uid=%u(%s)", id, pw->pw_name);
(void)printf(" gid=%u", pw->pw_gid);
- if (gr = getgrgid(id))
+ if (gr = getgrgid(pw->pw_gid))
(void)printf("(%s)", gr->gr_name);
ngroups = NGROUPS + 1;
(void) getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups);
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index 988bbbc..5a1f279 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)kdump.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
@@ -51,10 +51,15 @@ static char sccsid[] = "@(#)kdump.c 8.1 (Berkeley) 6/6/93";
#define KERNEL
#include <sys/errno.h>
#undef KERNEL
-#include <vis.h>
+
+#include <err.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <vis.h>
+
#include "ktrace.h"
int timestamp, decimal, fancy = 1, tail, maxdata;
@@ -63,18 +68,17 @@ struct ktr_header ktr_header;
#define eqs(s1, s2) (strcmp((s1), (s2)) == 0)
+int
main(argc, argv)
int argc;
char *argv[];
{
- extern int optind;
- extern char *optarg;
int ch, ktrlen, size;
register void *m;
int trpoints = ALL_POINTS;
- while ((ch = getopt(argc,argv,"f:dlm:nRTt:")) != EOF)
- switch((char)ch) {
+ while ((ch = getopt(argc, argv, "f:dlm:nRTt:")) != -1)
+ switch (ch) {
case 'f':
tracefile = optarg;
break;
@@ -98,12 +102,8 @@ main(argc, argv)
break;
case 't':
trpoints = getpoints(optarg);
- if (trpoints < 0) {
- (void)fprintf(stderr,
- "kdump: unknown trace point in %s\n",
- optarg);
- exit(1);
- }
+ if (trpoints < 0)
+ errx(1, "unknown trace point in %s", optarg);
break;
default:
usage();
@@ -115,36 +115,23 @@ main(argc, argv)
usage();
m = (void *)malloc(size = 1025);
- if (m == NULL) {
- (void)fprintf(stderr, "kdump: %s.\n", strerror(ENOMEM));
- exit(1);
- }
- if (!freopen(tracefile, "r", stdin)) {
- (void)fprintf(stderr,
- "kdump: %s: %s.\n", tracefile, strerror(errno));
- exit(1);
- }
+ if (m == NULL)
+ errx(1, "%s", strerror(ENOMEM));
+ if (!freopen(tracefile, "r", stdin))
+ err(1, "%s", tracefile);
while (fread_tail(&ktr_header, sizeof(struct ktr_header), 1)) {
if (trpoints & (1<<ktr_header.ktr_type))
dumpheader(&ktr_header);
- if ((ktrlen = ktr_header.ktr_len) < 0) {
- (void)fprintf(stderr,
- "kdump: bogus length 0x%x\n", ktrlen);
- exit(1);
- }
+ if ((ktrlen = ktr_header.ktr_len) < 0)
+ errx(1, "bogus length 0x%x", ktrlen);
if (ktrlen > size) {
m = (void *)realloc(m, ktrlen+1);
- if (m == NULL) {
- (void)fprintf(stderr,
- "kdump: %s.\n", strerror(ENOMEM));
- exit(1);
- }
+ if (m == NULL)
+ errx(1, "%s", strerror(ENOMEM));
size = ktrlen;
}
- if (ktrlen && fread_tail(m, ktrlen, 1) == 0) {
- (void)fprintf(stderr, "kdump: data too short.\n");
- exit(1);
- }
+ if (ktrlen && fread_tail(m, ktrlen, 1) == 0)
+ errx(1, "data too short");
if ((trpoints & (1<<ktr_header.ktr_type)) == 0)
continue;
switch (ktr_header.ktr_type) {
@@ -244,55 +231,58 @@ static char *ptrace_ops[] = {
ktrsyscall(ktr)
register struct ktr_syscall *ktr;
{
- register narg = ktr->ktr_narg;
- register int *ip;
+ register argsize = ktr->ktr_argsize;
+ register register_t *ap;
char *ioctlname();
if (ktr->ktr_code >= nsyscalls || ktr->ktr_code < 0)
(void)printf("[%d]", ktr->ktr_code);
else
(void)printf("%s", syscallnames[ktr->ktr_code]);
- ip = (int *)((char *)ktr + sizeof(struct ktr_syscall));
- if (narg) {
+ ap = (register_t *)((char *)ktr + sizeof(struct ktr_syscall));
+ if (argsize) {
char c = '(';
if (fancy) {
if (ktr->ktr_code == SYS_ioctl) {
char *cp;
if (decimal)
- (void)printf("(%d", *ip);
+ (void)printf("(%ld", (long)*ap);
else
- (void)printf("(%#x", *ip);
- ip++;
- narg--;
- if ((cp = ioctlname(*ip)) != NULL)
+ (void)printf("(%#lx", (long)*ap);
+ ap++;
+ argsize -= sizeof(register_t);
+ if ((cp = ioctlname(*ap)) != NULL)
(void)printf(",%s", cp);
else {
if (decimal)
- (void)printf(",%d", *ip);
+ (void)printf(",%ld",
+ (long)*ap);
else
- (void)printf(",%#x ", *ip);
+ (void)printf(",%#lx ",
+ (long)*ap);
}
c = ',';
- ip++;
- narg--;
+ ap++;
+ argsize -= sizeof(register_t);
} else if (ktr->ktr_code == SYS_ptrace) {
- if (*ip <= PT_STEP && *ip >= 0)
- (void)printf("(%s", ptrace_ops[*ip]);
+ if (*ap >= 0 && *ap <=
+ sizeof(ptrace_ops) / sizeof(ptrace_ops[0]))
+ (void)printf("(%s", ptrace_ops[*ap]);
else
- (void)printf("(%d", *ip);
+ (void)printf("(%ld", (long)*ap);
c = ',';
- ip++;
- narg--;
+ ap++;
+ argsize -= sizeof(register_t);
}
}
- while (narg) {
+ while (argsize) {
if (decimal)
- (void)printf("%c%d", c, *ip);
+ (void)printf("%c%ld", c, (long)*ap);
else
- (void)printf("%c%#x", c, *ip);
+ (void)printf("%c%#lx", c, (long)*ap);
c = ',';
- ip++;
- narg--;
+ ap++;
+ argsize -= sizeof(register_t);
}
(void)putchar(')');
}
@@ -366,7 +356,7 @@ ktrgenio(ktr, len)
datalen = maxdata;
(void)printf(" \"");
col = 8;
- for (;datalen > 0; datalen--, dp++) {
+ for (; datalen > 0; datalen--, dp++) {
(void) vis(visbuf, *dp, VIS_CSTYLE, *(dp+1));
cp = visbuf;
/*
@@ -402,31 +392,22 @@ ktrgenio(ktr, len)
(void)printf("\"\n");
}
-char *signames[] = {
- "NULL", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", /* 1 - 6 */
- "EMT", "FPE", "KILL", "BUS", "SEGV", "SYS", /* 7 - 12 */
- "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", /* 13 - 18 */
- "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", /* 19 - 24 */
- "XFSZ", "VTALRM", "PROF", "WINCH", "29", "USR1", /* 25 - 30 */
- "USR2", NULL, /* 31 - 32 */
-};
-
ktrpsig(psig)
struct ktr_psig *psig;
{
- (void)printf("SIG%s ", signames[psig->signo]);
+ (void)printf("SIG%s ", sys_signame[psig->signo]);
if (psig->action == SIG_DFL)
(void)printf("SIG_DFL\n");
else
- (void)printf("caught handler=0x%x mask=0x%x code=0x%x\n",
- (u_int)psig->action, psig->mask, psig->code);
+ (void)printf("caught handler=0x%lx mask=0x%x code=0x%x\n",
+ (u_long)psig->action, psig->mask, psig->code);
}
ktrcsw(cs)
struct ktr_csw *cs;
{
(void)printf("%s %s\n", cs->out ? "stop" : "resume",
- cs->user ? "user" : "kernel");
+ cs->user ? "user" : "kernel");
}
usage()
diff --git a/usr.bin/kdump/mkioctls b/usr.bin/kdump/mkioctls
index acba53b..b165d05 100644
--- a/usr.bin/kdump/mkioctls
+++ b/usr.bin/kdump/mkioctls
@@ -1,3 +1,38 @@
+#!/bin/sh -
+#
+# Copyright (c) 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.
+#
+# @(#)mkioctls 8.2 (Berkeley) 4/28/95
+#
awk '
BEGIN {
print "#include <sys/param.h>"
diff --git a/usr.bin/ktrace/ktrace.c b/usr.bin/ktrace/ktrace.c
index 26606d7..f40dbaf 100644
--- a/usr.bin/ktrace/ktrace.c
+++ b/usr.bin/ktrace/ktrace.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)ktrace.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
@@ -48,15 +48,20 @@ static char sccsid[] = "@(#)ktrace.c 8.1 (Berkeley) 6/6/93";
#include <sys/errno.h>
#include <sys/uio.h>
#include <sys/ktrace.h>
+
+#include <err.h>
#include <stdio.h>
+#include <unistd.h>
+
#include "ktrace.h"
+void no_ktrace __P((int));
+void usage __P((void));
+
main(argc, argv)
int argc;
char **argv;
{
- extern int optind;
- extern char *optarg;
enum { NOTSET, CLEAR, CLEARALL } clear;
int append, ch, fd, inherit, ops, pid, pidset, trpoints;
char *tracefile;
@@ -97,8 +102,7 @@ main(argc, argv)
case 't':
trpoints = getpoints(optarg);
if (trpoints < 0) {
- (void)fprintf(stderr,
- "ktrace: unknown facility in %s\n", optarg);
+ warnx("unknown facility in %s", optarg);
usage();
}
break;
@@ -114,6 +118,7 @@ main(argc, argv)
if (inherit)
trpoints |= KTRFAC_INHERIT;
+ (void)signal(SIGSYS, no_ktrace);
if (clear != NOTSET) {
if (clear == CLEARALL) {
ops = KTROP_CLEAR | KTRFLAG_DESCEND;
@@ -123,24 +128,23 @@ main(argc, argv)
ops |= pid ? KTROP_CLEAR : KTROP_CLEARFILE;
if (ktrace(tracefile, ops, trpoints, pid) < 0)
- error(tracefile);
+ err(1, tracefile);
exit(0);
}
if ((fd = open(tracefile, O_CREAT | O_WRONLY | (append ? 0 : O_TRUNC),
DEFFILEMODE)) < 0)
- error(tracefile);
+ err(1, tracefile);
(void)close(fd);
if (*argv) {
if (ktrace(tracefile, ops, trpoints, getpid()) < 0)
- error();
+ err(1, tracefile);
execvp(argv[0], &argv[0]);
- error(argv[0]);
- exit(1);
+ err(1, "exec of '%s' failed", argv[0]);
}
else if (ktrace(tracefile, ops, trpoints, pid) < 0)
- error(tracefile);
+ err(1, tracefile);
exit(0);
}
@@ -150,27 +154,29 @@ rpid(p)
static int first;
if (first++) {
- (void)fprintf(stderr,
- "ktrace: only one -g or -p flag is permitted.\n");
+ warnx("only one -g or -p flag is permitted.");
usage();
}
if (!*p) {
- (void)fprintf(stderr, "ktrace: illegal process id.\n");
+ warnx("illegal process id.");
usage();
}
return(atoi(p));
}
-error(name)
- char *name;
-{
- (void)fprintf(stderr, "ktrace: %s: %s.\n", name, strerror(errno));
- exit(1);
-}
-
+void
usage()
{
(void)fprintf(stderr,
"usage:\tktrace [-aCcid] [-f trfile] [-g pgid] [-p pid] [-t [acgn]\n\tktrace [-aCcid] [-f trfile] [-t [acgn] command\n");
exit(1);
}
+
+void
+no_ktrace(sig)
+ int sig;
+{
+ (void)fprintf(stderr,
+"error:\tktrace() system call not supported in the running kernel\n\tre-compile kernel with 'options KTRACE'\n");
+ exit(1);
+}
diff --git a/usr.bin/ktrace/subr.c b/usr.bin/ktrace/subr.c
index 6076c24..015801d 100644
--- a/usr.bin/ktrace/subr.c
+++ b/usr.bin/ktrace/subr.c
@@ -32,7 +32,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)subr.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
@@ -41,7 +41,9 @@ static char sccsid[] = "@(#)subr.c 8.1 (Berkeley) 6/6/93";
#include <sys/proc.h>
#include <sys/time.h>
#include <sys/ktrace.h>
+
#include <stdio.h>
+
#include "ktrace.h"
getpoints(s)
diff --git a/usr.bin/lastcomm/lastcomm.c b/usr.bin/lastcomm/lastcomm.c
index 7c3c363..749d8cf 100644
--- a/usr.bin/lastcomm/lastcomm.c
+++ b/usr.bin/lastcomm/lastcomm.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)lastcomm.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)lastcomm.c 8.2 (Berkeley) 4/29/95";
#endif /* not lint */
#include <sys/param.h>
@@ -183,13 +183,10 @@ requested(argv, acp)
register char *argv[];
register struct acct *acp;
{
- register char *p;
-
do {
- p = user_from_uid(acp->ac_uid, 0);
- if (!strcmp(p, *argv))
+ if (!strcmp(user_from_uid(acp->ac_uid, 0), *argv))
return (1);
- if ((p = getdev(acp->ac_tty)) && !strcmp(p, *argv))
+ if (!strcmp(getdev(acp->ac_tty), *argv))
return (1);
if (!strncmp(acp->ac_comm, *argv, fldsiz(acct, ac_comm)))
return (1);
@@ -209,7 +206,8 @@ getdev(dev)
if (dev == lastdev) /* One-element cache. */
return (lastname);
lastdev = dev;
- lastname = devname(dev, S_IFCHR);
+ if ((lastname = devname(dev, S_IFCHR)) == NULL)
+ lastname = "??";
return (lastname);
}
diff --git a/usr.bin/ld/Makefile b/usr.bin/ld/Makefile
new file mode 100644
index 0000000..834a5c9
--- /dev/null
+++ b/usr.bin/ld/Makefile
@@ -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>
diff --git a/usr.bin/ld/cplus-dem.c b/usr.bin/ld/cplus-dem.c
new file mode 100644
index 0000000..b2e3050
--- /dev/null
+++ b/usr.bin/ld/cplus-dem.c
@@ -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;
+}
diff --git a/usr.bin/ld/ld.c b/usr.bin/ld/ld.c
new file mode 100644
index 0000000..f0b35f2
--- /dev/null
+++ b/usr.bin/ld/ld.c
@@ -0,0 +1,4718 @@
+/*-
+ * This code is derived from software copyrighted by the Free Software
+ * Foundation.
+ *
+ * Modified 1991 by Donn Seeley at UUNET Technologies, Inc.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)ld.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/* Linker `ld' for GNU
+ Copyright (C) 1988 Free Software Foundation, Inc.
+
+ 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. */
+
+/* Written by Richard Stallman with some help from Eric Albert.
+ Set, indirect, and warning symbol features added by Randy Smith. */
+
+/* Define how to initialize system-dependent header fields. */
+
+#include <ar.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+
+/* symseg.h defines the obsolete GNU debugging format; we should nuke it. */
+#define CORE_ADDR unsigned long /* For symseg.h */
+#include "symseg.h"
+
+#define N_SET_MAGIC(exec, val) ((exec).a_magic = val)
+
+/* If compiled with GNU C, use the built-in alloca */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#endif
+
+#define min(a,b) ((a) < (b) ? (a) : (b))
+
+/* Macro to control the number of undefined references printed */
+#define MAX_UREFS_PRINTED 10
+
+/* Size of a page; obtained from the operating system. */
+
+int page_size;
+
+/* Name this program was invoked by. */
+
+char *progname;
+
+/* System dependencies */
+
+/* Define this to specify the default executable format. */
+
+#ifndef DEFAULT_MAGIC
+#define DEFAULT_MAGIC ZMAGIC
+#endif
+
+#if defined(hp300) || defined(luna68k)
+#define INITIALIZE_HEADER outheader.a_mid = MID_HP300
+#endif
+
+#ifdef sparc
+#ifndef sun
+#define sun 1
+#endif
+#define INITIALIZE_HEADER \
+ (outheader.a_mid = MID_SUN_SPARC, outheader.a_toolversion = 1)
+#endif
+
+/*
+ * Ok. Following are the relocation information macros. If your
+ * system should not be able to use the default set (below), you must
+ * define the following:
+
+ * relocation_info: This must be typedef'd (or #define'd) to the type
+ * of structure that is stored in the relocation info section of your
+ * a.out files. Often this is defined in the a.out.h for your system.
+ *
+ * RELOC_ADDRESS (rval): Offset into the current section of the
+ * <whatever> to be relocated. *Must be an lvalue*.
+ *
+ * RELOC_EXTERN_P (rval): Is this relocation entry based on an
+ * external symbol (1), or was it fully resolved upon entering the
+ * loader (0) in which case some combination of the value in memory
+ * (if RELOC_MEMORY_ADD_P) and the extra (if RELOC_ADD_EXTRA) contains
+ * what the value of the relocation actually was. *Must be an lvalue*.
+ *
+ * RELOC_TYPE (rval): If this entry was fully resolved upon
+ * entering the loader, what type should it be relocated as?
+ *
+ * RELOC_SYMBOL (rval): If this entry was not fully resolved upon
+ * entering the loader, what is the index of it's symbol in the symbol
+ * table? *Must be a lvalue*.
+ *
+ * RELOC_MEMORY_ADD_P (rval): This should return true if the final
+ * relocation value output here should be added to memory, or if the
+ * section of memory described should simply be set to the relocation
+ * value.
+ *
+ * RELOC_ADD_EXTRA (rval): (Optional) This macro, if defined, gives
+ * an extra value to be added to the relocation value based on the
+ * individual relocation entry. *Must be an lvalue if defined*.
+ *
+ * RELOC_PCREL_P (rval): True if the relocation value described is
+ * pc relative.
+ *
+ * RELOC_VALUE_RIGHTSHIFT (rval): Number of bits right to shift the
+ * final relocation value before putting it where it belongs.
+ *
+ * RELOC_TARGET_SIZE (rval): log to the base 2 of the number of
+ * bytes of size this relocation entry describes; 1 byte == 0; 2 bytes
+ * == 1; 4 bytes == 2, and etc. This is somewhat redundant (we could
+ * do everything in terms of the bit operators below), but having this
+ * macro could end up producing better code on machines without fancy
+ * bit twiddling. Also, it's easier to understand/code big/little
+ * endian distinctions with this macro.
+ *
+ * RELOC_TARGET_BITPOS (rval): The starting bit position within the
+ * object described in RELOC_TARGET_SIZE in which the relocation value
+ * will go.
+ *
+ * RELOC_TARGET_BITSIZE (rval): How many bits are to be replaced
+ * with the bits of the relocation value. It may be assumed by the
+ * code that the relocation value will fit into this many bits. This
+ * may be larger than RELOC_TARGET_SIZE if such be useful.
+ *
+ *
+ * Things I haven't implemented
+ * ----------------------------
+ *
+ * Values for RELOC_TARGET_SIZE other than 0, 1, or 2.
+ *
+ * Pc relative relocation for External references.
+ *
+ *
+ */
+
+/* The following #if has been modifed for cross compilation */
+/* It originally read: #if defined(sun) && defined(sparc) */
+/* Marc Ullman, Stanford University Nov. 1 1989 */
+#if defined(sun) && (TARGET == SUN4)
+/* Sparc (Sun 4) macros */
+#undef relocation_info
+#define relocation_info reloc_info_sparc
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_index)
+#define RELOC_SYMBOL(r) ((r)->r_index)
+#define RELOC_MEMORY_SUB_P(r) 0
+#define RELOC_MEMORY_ADD_P(r) 0
+#define RELOC_ADD_EXTRA(r) ((r)->r_addend)
+#define RELOC_PCREL_P(r) \
+ ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
+#define RELOC_VALUE_RIGHTSHIFT(r) (reloc_target_rightshift[(r)->r_type])
+#define RELOC_TARGET_SIZE(r) (reloc_target_size[(r)->r_type])
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) (reloc_target_bitsize[(r)->r_type])
+
+/* Note that these are very dependent on the order of the enums in
+ enum reloc_type (in a.out.h); if they change the following must be
+ changed */
+/* Also note that the last few may be incorrect; I have no information */
+static int reloc_target_rightshift[] = {
+ 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
+};
+static int reloc_target_size[] = {
+ 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+};
+static int reloc_target_bitsize[] = {
+ 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
+};
+
+#define MAX_ALIGNMENT (sizeof (double))
+#endif
+
+/* Default macros */
+#ifndef RELOC_ADDRESS
+#define RELOC_ADDRESS(r) ((r)->r_address)
+#define RELOC_EXTERN_P(r) ((r)->r_extern)
+#define RELOC_TYPE(r) ((r)->r_symbolnum)
+#define RELOC_SYMBOL(r) ((r)->r_symbolnum)
+#define RELOC_MEMORY_SUB_P(r) 0
+#define RELOC_MEMORY_ADD_P(r) 1
+#undef RELOC_ADD_EXTRA
+#define RELOC_PCREL_P(r) ((r)->r_pcrel)
+#define RELOC_VALUE_RIGHTSHIFT(r) 0
+#define RELOC_TARGET_SIZE(r) ((r)->r_length)
+#define RELOC_TARGET_BITPOS(r) 0
+#define RELOC_TARGET_BITSIZE(r) 32
+#endif
+
+#ifndef MAX_ALIGNMENT
+#define MAX_ALIGNMENT (sizeof (int))
+#endif
+
+#ifdef nounderscore
+#define LPREFIX '.'
+#else
+#define LPREFIX 'L'
+#endif
+
+#ifndef TEXT_START
+#define TEXT_START(x) N_TXTADDR(x)
+#endif
+
+/* Special global symbol types understood by GNU LD. */
+
+/* The following type indicates the definition of a symbol as being
+ an indirect reference to another symbol. The other symbol
+ appears as an undefined reference, immediately following this symbol.
+
+ Indirection is asymmetrical. The other symbol's value will be used
+ to satisfy requests for the indirect symbol, but not vice versa.
+ If the other symbol does not have a definition, libraries will
+ be searched to find a definition.
+
+ So, for example, the following two lines placed in an assembler
+ input file would result in an object file which would direct gnu ld
+ to resolve all references to symbol "foo" as references to symbol
+ "bar".
+
+ .stabs "_foo",11,0,0,0
+ .stabs "_bar",1,0,0,0
+
+ Note that (11 == (N_INDR | N_EXT)) and (1 == (N_UNDF | N_EXT)). */
+
+#ifndef N_INDR
+#define N_INDR 0xa
+#endif
+
+/* The following symbols refer to set elements. These are expected
+ only in input to the loader; they should not appear in loader
+ output (unless relocatable output is requested). To be recognized
+ by the loader, the input symbols must have their N_EXT bit set.
+ All the N_SET[ATDB] symbols with the same name form one set. The
+ loader collects all of these elements at load time and outputs a
+ vector for each name.
+ Space (an array of 32 bit words) is allocated for the set in the
+ data section, and the n_value field of each set element value is
+ stored into one word of the array.
+ The first word of the array is the length of the set (number of
+ elements). The last word of the vector is set to zero for possible
+ use by incremental loaders. The array is ordered by the linkage
+ order; the first symbols which the linker encounters will be first
+ in the array.
+
+ In C syntax this looks like:
+
+ struct set_vector {
+ unsigned int length;
+ unsigned int vector[length];
+ unsigned int always_zero;
+ };
+
+ Before being placed into the array, each element is relocated
+ according to its type. This allows the loader to create an array
+ of pointers to objects automatically. N_SETA type symbols will not
+ be relocated.
+
+ The address of the set is made into an N_SETV symbol
+ whose name is the same as the name of the set.
+ This symbol acts like a N_DATA global symbol
+ in that it can satisfy undefined external references.
+
+ For the purposes of determining whether or not to load in a library
+ file, set element definitions are not considered "real
+ definitions"; they will not cause the loading of a library
+ member.
+
+ If relocatable output is requested, none of this processing is
+ done. The symbols are simply relocated and passed through to the
+ output file.
+
+ So, for example, the following three lines of assembler code
+ (whether in one file or scattered between several different ones)
+ will produce a three element vector (total length is five words;
+ see above), referenced by the symbol "_xyzzy", which will have the
+ addresses of the routines _init1, _init2, and _init3.
+
+ *NOTE*: If symbolic addresses are used in the n_value field of the
+ defining .stabs, those symbols must be defined in the same file as
+ that containing the .stabs.
+
+ .stabs "_xyzzy",23,0,0,_init1
+ .stabs "_xyzzy",23,0,0,_init2
+ .stabs "_xyzzy",23,0,0,_init3
+
+ Note that (23 == (N_SETT | N_EXT)). */
+
+#ifndef N_SETA
+#define N_SETA 0x14 /* Absolute set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETT
+#define N_SETT 0x16 /* Text set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETD
+#define N_SETD 0x18 /* Data set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+#ifndef N_SETB
+#define N_SETB 0x1A /* Bss set element symbol */
+#endif /* This is input to LD, in a .o file. */
+
+/* Macros dealing with the set element symbols defined in a.out.h */
+#define SET_ELEMENT_P(x) ((x)>=N_SETA&&(x)<=(N_SETB|N_EXT))
+#define TYPE_OF_SET_ELEMENT(x) ((x)-N_SETA+N_ABS)
+
+#ifndef N_SETV
+#define N_SETV 0x1C /* Pointer to set vector in data area. */
+#endif /* This is output from LD. */
+
+/* If a this type of symbol is encountered, its name is a warning
+ message to print each time the symbol referenced by the next symbol
+ table entry is referenced.
+
+ This feature may be used to allow backwards compatibility with
+ certain functions (eg. gets) but to discourage programmers from
+ their use.
+
+ So if, for example, you wanted to have ld print a warning whenever
+ the function "gets" was used in their C program, you would add the
+ following to the assembler file in which gets is defined:
+
+ .stabs "Obsolete function \"gets\" referenced",30,0,0,0
+ .stabs "_gets",1,0,0,0
+
+ These .stabs do not necessarily have to be in the same file as the
+ gets function, they simply must exist somewhere in the compilation. */
+
+#ifndef N_WARNING
+#define N_WARNING 0x1E /* Warning message to print if symbol
+ included */
+#endif /* This is input to ld */
+
+#ifndef __GNU_STAB__
+
+/* Line number for the data section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_DSLINE
+#define N_DSLINE (N_SLINE+N_DATA-N_TEXT)
+#endif
+
+/* Line number for the bss section. This is to be used to describe
+ the source location of a variable declaration. */
+#ifndef N_BSLINE
+#define N_BSLINE (N_SLINE+N_BSS-N_TEXT)
+#endif
+
+#endif /* not __GNU_STAB__ */
+
+/* Symbol table */
+
+/* Global symbol data is recorded in these structures,
+ one for each global symbol.
+ They are found via hashing in 'symtab', which points to a vector of buckets.
+ Each bucket is a chain of these structures through the link field. */
+
+typedef
+ struct glosym
+ {
+ /* Pointer to next symbol in this symbol's hash bucket. */
+ struct glosym *link;
+ /* Name of this symbol. */
+ char *name;
+ /* Value of this symbol as a global symbol. */
+ long value;
+ /* Chain of external 'nlist's in files for this symbol, both defs
+ and refs. */
+ struct nlist *refs;
+ /* Any warning message that might be associated with this symbol
+ from an N_WARNING symbol encountered. */
+ char *warning;
+ /* Nonzero means definitions of this symbol as common have been seen,
+ and the value here is the largest size specified by any of them. */
+ int max_common_size;
+ /* For relocatable_output, records the index of this global sym in the
+ symbol table to be written, with the first global sym given index 0.*/
+ int def_count;
+ /* Nonzero means a definition of this global symbol is known to exist.
+ Library members should not be loaded on its account. */
+ char defined;
+ /* Nonzero means a reference to this global symbol has been seen
+ in a file that is surely being loaded.
+ A value higher than 1 is the n_type code for the symbol's
+ definition. */
+ char referenced;
+ /* A count of the number of undefined references printed for a
+ specific symbol. If a symbol is unresolved at the end of
+ digest_symbols (and the loading run is supposed to produce
+ relocatable output) do_file_warnings keeps track of how many
+ unresolved reference error messages have been printed for
+ each symbol here. When the number hits MAX_UREFS_PRINTED,
+ messages stop. */
+ unsigned char undef_refs;
+ /* 1 means that this symbol has multiple definitions. 2 means
+ that it has multiple definitions, and some of them are set
+ elements, one of which has been printed out already. */
+ unsigned char multiply_defined;
+ /* Nonzero means print a message at all refs or defs of this symbol */
+ char trace;
+ }
+ symbol;
+
+/* Demangler for C++. */
+extern char *cplus_demangle ();
+
+/* Demangler function to use. */
+char *(*demangler)() = NULL;
+
+/* Number of buckets in symbol hash table */
+#define TABSIZE 1009
+
+/* The symbol hash table: a vector of TABSIZE pointers to struct glosym. */
+symbol *symtab[TABSIZE];
+
+/* Number of symbols in symbol hash table. */
+int num_hash_tab_syms = 0;
+
+/* Count the number of nlist entries that are for local symbols.
+ This count and the three following counts
+ are incremented as as symbols are entered in the symbol table. */
+int local_sym_count;
+
+/* Count number of nlist entries that are for local symbols
+ whose names don't start with L. */
+int non_L_local_sym_count;
+
+/* Count the number of nlist entries for debugger info. */
+int debugger_sym_count;
+
+/* Count the number of global symbols referenced and not defined. */
+int undefined_global_sym_count;
+
+/* Count the number of global symbols multiply defined. */
+int multiple_def_count;
+
+/* Count the number of defined global symbols.
+ Each symbol is counted only once
+ regardless of how many different nlist entries refer to it,
+ since the output file will need only one nlist entry for it.
+ This count is computed by `digest_symbols';
+ it is undefined while symbols are being loaded. */
+int defined_global_sym_count;
+
+/* Count the number of symbols defined through common declarations.
+ This count is kept in symdef_library, linear_library, and
+ enter_global_ref. It is incremented when the defined flag is set
+ in a symbol because of a common definition, and decremented when
+ the symbol is defined "for real" (ie. by something besides a common
+ definition). */
+int common_defined_global_count;
+
+/* Count the number of set element type symbols and the number of
+ separate vectors which these symbols will fit into. See the
+ GNU a.out.h for more info.
+ This count is computed by 'enter_file_symbols' */
+int set_symbol_count;
+int set_vector_count;
+
+/* Define a linked list of strings which define symbols which should
+ be treated as set elements even though they aren't. Any symbol
+ with a prefix matching one of these should be treated as a set
+ element.
+
+ This is to make up for deficiencies in many assemblers which aren't
+ willing to pass any stabs through to the loader which they don't
+ understand. */
+struct string_list_element {
+ char *str;
+ struct string_list_element *next;
+};
+
+struct string_list_element *set_element_prefixes;
+
+/* Count the number of definitions done indirectly (ie. done relative
+ to the value of some other symbol. */
+int global_indirect_count;
+
+/* Count the number of warning symbols encountered. */
+int warning_count;
+
+/* Total number of symbols to be written in the output file.
+ Computed by digest_symbols from the variables above. */
+int nsyms;
+
+
+/* Nonzero means ptr to symbol entry for symbol to use as start addr.
+ -e sets this. */
+symbol *entry_symbol;
+
+symbol *edata_symbol; /* the symbol _edata */
+symbol *etext_symbol; /* the symbol _etext */
+symbol *end_symbol; /* the symbol _end */
+
+/* Each input file, and each library member ("subfile") being loaded,
+ has a `file_entry' structure for it.
+
+ For files specified by command args, these are contained in the vector
+ which `file_table' points to.
+
+ For library members, they are dynamically allocated,
+ and chained through the `chain' field.
+ The chain is found in the `subfiles' field of the `file_entry'.
+ The `file_entry' objects for the members have `superfile' fields pointing
+ to the one for the library. */
+
+struct file_entry {
+ /* Name of this file. */
+ char *filename;
+ /* Name to use for the symbol giving address of text start */
+ /* Usually the same as filename, but for a file spec'd with -l
+ this is the -l switch itself rather than the filename. */
+ char *local_sym_name;
+
+ /* Describe the layout of the contents of the file */
+
+ /* The file's a.out header. */
+ struct exec header;
+ /* Offset in file of GDB symbol segment, or 0 if there is none. */
+ int symseg_offset;
+
+ /* Describe data from the file loaded into core */
+
+ /* Symbol table of the file. */
+ struct nlist *symbols;
+ /* Size in bytes of string table. */
+ int string_size;
+ /* Pointer to the string table.
+ The string table is not kept in core all the time,
+ but when it is in core, its address is here. */
+ char *strings;
+
+ /* Next two used only if `relocatable_output' or if needed for */
+ /* output of undefined reference line numbers. */
+
+ /* Text reloc info saved by `write_text' for `coptxtrel'. */
+ struct relocation_info *textrel;
+ /* Data reloc info saved by `write_data' for `copdatrel'. */
+ struct relocation_info *datarel;
+
+ /* Relation of this file's segments to the output file */
+
+ /* Start of this file's text seg in the output file core image. */
+ int text_start_address;
+ /* Start of this file's data seg in the output file core image. */
+ int data_start_address;
+ /* Start of this file's bss seg in the output file core image. */
+ int bss_start_address;
+ /* Offset in bytes in the output file symbol table
+ of the first local symbol for this file. Set by `write_file_symbols'. */
+ int local_syms_offset;
+
+ /* For library members only */
+
+ /* For a library, points to chain of entries for the library members. */
+ struct file_entry *subfiles;
+ /* For a library member, offset of the member within the archive.
+ Zero for files that are not library members. */
+ int starting_offset;
+ /* Size of contents of this file, if library member. */
+ int total_size;
+ /* For library member, points to the library's own entry. */
+ struct file_entry *superfile;
+ /* For library member, points to next entry for next member. */
+ struct file_entry *chain;
+
+ /* 1 if file is a library. */
+ char library_flag;
+
+ /* 1 if file's header has been read into this structure. */
+ char header_read_flag;
+
+ /* 1 means search a set of directories for this file. */
+ char search_dirs_flag;
+
+ /* 1 means this is base file of incremental load.
+ Do not load this file's text or data.
+ Also default text_start to after this file's bss. */
+ char just_syms_flag;
+};
+
+/* Vector of entries for input files specified by arguments.
+ These are all the input files except for members of specified libraries. */
+struct file_entry *file_table;
+
+/* Length of that vector. */
+int number_of_files;
+
+/* When loading the text and data, we can avoid doing a close
+ and another open between members of the same library.
+
+ These two variables remember the file that is currently open.
+ Both are zero if no file is open.
+
+ See `each_file' and `file_close'. */
+
+struct file_entry *input_file;
+int input_desc;
+
+/* The name of the file to write; "a.out" by default. */
+
+char *output_filename;
+
+/* Descriptor for writing that file with `mywrite'. */
+
+int outdesc;
+
+/* Header for that file (filled in by `write_header'). */
+
+struct exec outheader;
+
+#ifdef COFF_ENCAPSULATE
+struct coffheader coffheader;
+int need_coff_header;
+#endif
+
+/* The following are computed by `digest_symbols'. */
+
+int text_size; /* total size of text of all input files. */
+int data_size; /* total size of data of all input files. */
+int bss_size; /* total size of bss of all input files. */
+int text_reloc_size; /* total size of text relocation of all input files. */
+int data_reloc_size; /* total size of data relocation of all input */
+ /* files. */
+
+/* Specifications of start and length of the area reserved at the end
+ of the text segment for the set vectors. Computed in 'digest_symbols' */
+int set_sect_start;
+int set_sect_size;
+
+/* Pointer for in core storage for the above vectors, before they are
+ written. */
+unsigned long *set_vectors;
+
+/* Amount of cleared space to leave between the text and data segments. */
+
+int text_pad;
+
+/* Amount of bss segment to include as part of the data segment. */
+
+int data_pad;
+
+/* Format of __.SYMDEF:
+ First, a longword containing the size of the 'symdef' data that follows.
+ Second, zero or more 'symdef' structures.
+ Third, a longword containing the length of symbol name strings.
+ Fourth, zero or more symbol name strings (each followed by a null). */
+
+struct symdef {
+ int symbol_name_string_index;
+ int library_member_offset;
+};
+
+/* Record most of the command options. */
+
+/* Address we assume the text section will be loaded at.
+ We relocate symbols and text and data for this, but we do not
+ write any padding in the output file for it. */
+int text_start;
+
+/* Offset of default entry-pc within the text section. */
+int entry_offset;
+
+/* Address we decide the data section will be loaded at. */
+int data_start;
+
+/* `text-start' address is normally this much plus a page boundary.
+ This is not a user option; it is fixed for each system. */
+int text_start_alignment;
+
+/* Nonzero if -T was specified in the command line.
+ This prevents text_start from being set later to default values. */
+int T_flag_specified;
+
+/* Nonzero if -Tdata was specified in the command line.
+ This prevents data_start from being set later to default values. */
+int Tdata_flag_specified;
+
+/* Size to pad data section up to.
+ We simply increase the size of the data section, padding with zeros,
+ and reduce the size of the bss section to match. */
+int specified_data_size;
+
+/* Magic number to use for the output file, set by switch. */
+int magic;
+
+/* Nonzero means print names of input files as processed. */
+int trace_files;
+
+/* Which symbols should be stripped (omitted from the output):
+ none, all, or debugger symbols. */
+enum { STRIP_NONE, STRIP_ALL, STRIP_DEBUGGER } strip_symbols;
+
+/* Which local symbols should be omitted:
+ none, all, or those starting with L.
+ This is irrelevant if STRIP_NONE. */
+enum { DISCARD_NONE, DISCARD_ALL, DISCARD_L } discard_locals;
+
+/* Do we want to pad the text to a page boundary? */
+int padtext;
+
+/* 1 => write load map. */
+int write_map;
+
+/* 1 => write relocation into output file so can re-input it later. */
+int relocatable_output;
+
+/* 1 => assign space to common symbols even if `relocatable_output'. */
+int force_common_definition;
+
+/* Standard directories to search for files specified by -l. */
+char *standard_search_dirs[] =
+#ifdef STANDARD_SEARCH_DIRS
+ {STANDARD_SEARCH_DIRS};
+#else
+#ifdef NON_NATIVE
+ {"/usr/local/lib/gnu"};
+#else
+ {"/lib", "/usr/lib", "/usr/local/lib"};
+#endif
+#endif
+
+/* Actual vector of directories to search;
+ this contains those specified with -L plus the standard ones. */
+char **search_dirs;
+
+/* Length of the vector `search_dirs'. */
+int n_search_dirs;
+
+/* Non zero means to create the output executable. */
+/* Cleared by nonfatal errors. */
+int make_executable;
+
+/* Force the executable to be output, even if there are non-fatal
+ errors */
+int force_executable;
+
+/* Keep a list of any symbols referenced from the command line (so
+ that error messages for these guys can be generated). This list is
+ zero terminated. */
+struct glosym **cmdline_references;
+int cl_refs_allocated;
+
+void bcopy (), bzero ();
+int malloc (), realloc ();
+#ifndef alloca
+int alloca ();
+#endif
+int free ();
+
+int xmalloc ();
+int xrealloc ();
+void fatal ();
+void fatal_with_file ();
+void perror_name ();
+void perror_file ();
+void error ();
+
+void digest_symbols ();
+void print_symbols ();
+void load_symbols ();
+void decode_command ();
+void list_undefined_symbols ();
+void list_unresolved_references ();
+void write_output ();
+void write_header ();
+void write_text ();
+void read_file_relocation ();
+void write_data ();
+void write_rel ();
+void write_syms ();
+void write_symsegs ();
+void mywrite ();
+void symtab_init ();
+void padfile ();
+char *concat ();
+char *get_file_name ();
+symbol *getsym (), *getsym_soft ();
+
+int
+main (argc, argv)
+ char **argv;
+ int argc;
+{
+/* Added this to stop ld core-dumping on very large .o files. */
+#ifdef RLIMIT_STACK
+ /* Get rid of any avoidable limit on stack size. */
+ {
+ struct rlimit rlim;
+
+ /* Set the stack limit huge so that alloca does not fail. */
+ getrlimit (RLIMIT_STACK, &rlim);
+ rlim.rlim_cur = rlim.rlim_max;
+ setrlimit (RLIMIT_STACK, &rlim);
+ }
+#endif /* RLIMIT_STACK */
+
+ page_size = getpagesize ();
+ progname = argv[0];
+
+ /* Clear the cumulative info on the output file. */
+
+ text_size = 0;
+ data_size = 0;
+ bss_size = 0;
+ text_reloc_size = 0;
+ data_reloc_size = 0;
+
+ data_pad = 0;
+ text_pad = 0;
+
+ /* Initialize the data about options. */
+
+ specified_data_size = 0;
+ strip_symbols = STRIP_NONE;
+ trace_files = 0;
+ discard_locals = DISCARD_NONE;
+ padtext = 0;
+ entry_symbol = 0;
+ write_map = 0;
+ relocatable_output = 0;
+ force_common_definition = 0;
+ T_flag_specified = 0;
+ Tdata_flag_specified = 0;
+ magic = DEFAULT_MAGIC;
+ make_executable = 1;
+ force_executable = 0;
+ set_element_prefixes = 0;
+
+ /* Initialize the cumulative counts of symbols. */
+
+ local_sym_count = 0;
+ non_L_local_sym_count = 0;
+ debugger_sym_count = 0;
+ undefined_global_sym_count = 0;
+ set_symbol_count = 0;
+ set_vector_count = 0;
+ global_indirect_count = 0;
+ warning_count = 0;
+ multiple_def_count = 0;
+ common_defined_global_count = 0;
+
+ /* Keep a list of symbols referenced from the command line */
+ cl_refs_allocated = 10;
+ cmdline_references
+ = (struct glosym **) xmalloc (cl_refs_allocated
+ * sizeof(struct glosym *));
+ *cmdline_references = 0;
+
+ /* Completely decode ARGV. */
+
+ decode_command (argc, argv);
+
+ /* Create the symbols `etext', `edata' and `end'. */
+
+ if (!relocatable_output)
+ symtab_init ();
+
+ /* Determine whether to count the header as part of
+ the text size, and initialize the text size accordingly.
+ This depends on the kind of system and on the output format selected. */
+
+ N_SET_MAGIC (outheader, magic);
+#ifdef INITIALIZE_HEADER
+ INITIALIZE_HEADER;
+#endif
+
+ text_size = sizeof (struct exec);
+#ifdef COFF_ENCAPSULATE
+ if (relocatable_output == 0 && file_table[0].just_syms_flag == 0)
+ {
+ need_coff_header = 1;
+ /* set this flag now, since it will change the values of N_TXTOFF, etc */
+ N_SET_FLAGS (outheader, N_FLAGS_COFF_ENCAPSULATE);
+ text_size += sizeof (struct coffheader);
+ }
+#endif
+
+ text_size -= N_TXTOFF (outheader);
+
+ if (text_size < 0)
+ text_size = 0;
+ entry_offset = text_size;
+
+ if (!T_flag_specified && !relocatable_output)
+ text_start = TEXT_START (outheader);
+
+ /* The text-start address is normally this far past a page boundary. */
+ text_start_alignment = text_start % page_size;
+
+ /* Load symbols of all input files.
+ Also search all libraries and decide which library members to load. */
+
+ load_symbols ();
+
+ /* Compute where each file's sections go, and relocate symbols. */
+
+ digest_symbols ();
+
+ /* Print error messages for any missing symbols, for any warning
+ symbols, and possibly multiple definitions */
+
+ do_warnings (stderr);
+
+ /* Print a map, if requested. */
+
+ if (write_map) print_symbols (stdout);
+
+ /* Write the output file. */
+
+ if (make_executable || force_executable)
+ write_output ();
+
+ exit (!make_executable);
+}
+
+void decode_option ();
+
+/* Analyze a command line argument.
+ Return 0 if the argument is a filename.
+ Return 1 if the argument is a option complete in itself.
+ Return 2 if the argument is a option which uses an argument.
+
+ Thus, the value is the number of consecutive arguments
+ that are part of options. */
+
+int
+classify_arg (arg)
+ register char *arg;
+{
+ if (*arg != '-') return 0;
+ switch (arg[1])
+ {
+ case 'A':
+ case 'D':
+ case 'e':
+ case 'L':
+ case 'l':
+ case 'o':
+ case 'u':
+ case 'V':
+ case 'y':
+ if (arg[2])
+ return 1;
+ return 2;
+
+ case 'B':
+ if (! strcmp (&arg[2], "static"))
+ return 1;
+
+ case 'T':
+ if (arg[2] == 0)
+ return 2;
+ if (! strcmp (&arg[2], "text"))
+ return 2;
+ if (! strcmp (&arg[2], "data"))
+ return 2;
+ return 1;
+ }
+
+ return 1;
+}
+
+/* Process the command arguments,
+ setting up file_table with an entry for each input file,
+ and setting variables according to the options. */
+
+void
+decode_command (argc, argv)
+ char **argv;
+ int argc;
+{
+ register int i;
+ register struct file_entry *p;
+ char *cp;
+
+ number_of_files = 0;
+ output_filename = "a.out";
+
+ n_search_dirs = 0;
+ search_dirs = (char **) xmalloc (sizeof (char *));
+
+ /* First compute number_of_files so we know how long to make file_table. */
+ /* Also process most options completely. */
+
+ for (i = 1; i < argc; i++)
+ {
+ register int code = classify_arg (argv[i]);
+ if (code)
+ {
+ if (i + code > argc)
+ fatal ("no argument following %s\n", argv[i]);
+
+ decode_option (argv[i], argv[i+1]);
+
+ if (argv[i][1] == 'l' || argv[i][1] == 'A')
+ number_of_files++;
+
+ i += code - 1;
+ }
+ else
+ number_of_files++;
+ }
+
+ if (!number_of_files)
+ fatal ("no input files", 0);
+
+ p = file_table
+ = (struct file_entry *) xmalloc (number_of_files * sizeof (struct file_entry));
+ bzero (p, number_of_files * sizeof (struct file_entry));
+
+ /* Now scan again and fill in file_table. */
+ /* All options except -A and -l are ignored here. */
+
+ for (i = 1; i < argc; i++)
+ {
+ register int code = classify_arg (argv[i]);
+
+ if (code)
+ {
+ char *string;
+ if (code == 2)
+ string = argv[i+1];
+ else
+ string = &argv[i][2];
+
+ if (argv[i][1] == 'A')
+ {
+ if (p != file_table)
+ fatal ("-A specified before an input file other than the first");
+
+ p->filename = string;
+ p->local_sym_name = string;
+ p->just_syms_flag = 1;
+ p++;
+ }
+ if (argv[i][1] == 'l')
+ {
+ if (cp = rindex(string, '/'))
+ {
+ *cp++ = '\0';
+ cp = concat (string, "/lib", cp);
+ p->filename = concat (cp, ".a", "");
+ }
+ else
+ p->filename = concat ("lib", string, ".a");
+
+ p->local_sym_name = concat ("-l", string, "");
+ p->search_dirs_flag = 1;
+ p++;
+ }
+ i += code - 1;
+ }
+ else
+ {
+ p->filename = argv[i];
+ p->local_sym_name = argv[i];
+ p++;
+ }
+ }
+
+ /* Now check some option settings for consistency. */
+
+#ifdef NMAGIC
+ if ((magic == ZMAGIC || magic == NMAGIC)
+#else
+ if ((magic == ZMAGIC)
+#endif
+ && (text_start - text_start_alignment) & (page_size - 1))
+ fatal ("-T argument not multiple of page size, with sharable output", 0);
+
+ /* Append the standard search directories to the user-specified ones. */
+ {
+ int n = sizeof standard_search_dirs / sizeof standard_search_dirs[0];
+ n_search_dirs += n;
+ search_dirs
+ = (char **) xrealloc (search_dirs, n_search_dirs * sizeof (char *));
+ bcopy (standard_search_dirs, &search_dirs[n_search_dirs - n],
+ n * sizeof (char *));
+ }
+}
+
+
+void
+add_cmdline_ref (sp)
+ struct glosym *sp;
+{
+ struct glosym **ptr;
+
+ for (ptr = cmdline_references;
+ ptr < cmdline_references + cl_refs_allocated && *ptr;
+ ptr++)
+ ;
+
+ if (ptr >= cmdline_references + cl_refs_allocated - 1)
+ {
+ int diff = ptr - cmdline_references;
+
+ cl_refs_allocated *= 2;
+ cmdline_references = (struct glosym **)
+ xrealloc (cmdline_references,
+ cl_refs_allocated * sizeof (struct glosym *));
+ ptr = cmdline_references + diff;
+ }
+
+ *ptr++ = sp;
+ *ptr = (struct glosym *) 0;
+}
+
+int
+set_element_prefixed_p (name)
+ char *name;
+{
+ struct string_list_element *p;
+ int i;
+
+ for (p = set_element_prefixes; p; p = p->next)
+ {
+ for (i = 0; p->str[i] != '\0' && (p->str[i] == name[i]); i++)
+ ;
+
+ if (p->str[i] == '\0')
+ return 1;
+ }
+ return 0;
+}
+
+int parse ();
+
+/* Record an option and arrange to act on it later.
+ ARG should be the following command argument,
+ which may or may not be used by this option.
+
+ The `l' and `A' options are ignored here since they actually
+ specify input files. */
+
+void
+decode_option (swt, arg)
+ register char *swt, *arg;
+{
+ /* We get Bstatic from gcc on suns. */
+ if (! strcmp (swt + 1, "Bstatic"))
+ return;
+ if (! strcmp (swt + 1, "Ttext"))
+ {
+ text_start = parse (arg, "%x", "invalid argument to -Ttext");
+ T_flag_specified = 1;
+ return;
+ }
+ if (! strcmp (swt + 1, "Tdata"))
+ {
+ data_start = parse (arg, "%x", "invalid argument to -Tdata");
+ Tdata_flag_specified = 1;
+ return;
+ }
+ if (! strcmp (swt + 1, "noinhibit-exec"))
+ {
+ force_executable = 1;
+ return;
+ }
+
+ if (swt[2] != 0)
+ arg = &swt[2];
+
+ switch (swt[1])
+ {
+ case 'A':
+ return;
+
+ case 'D':
+ specified_data_size = parse (arg, "%x", "invalid argument to -D");
+ return;
+
+ case 'd':
+ force_common_definition = 1;
+ return;
+
+ case 'e':
+ entry_symbol = getsym (arg);
+ if (!entry_symbol->defined && !entry_symbol->referenced)
+ undefined_global_sym_count++;
+ entry_symbol->referenced = 1;
+ add_cmdline_ref (entry_symbol);
+ return;
+
+ case 'l':
+ /* If linking with libg++, use the C++ demangler. */
+ if (arg != NULL && strcmp (arg, "g++") == 0)
+ demangler = cplus_demangle;
+ return;
+
+ case 'L':
+ n_search_dirs++;
+ search_dirs
+ = (char **) xrealloc (search_dirs, n_search_dirs * sizeof (char *));
+ search_dirs[n_search_dirs - 1] = arg;
+ return;
+
+ case 'M':
+ write_map = 1;
+ return;
+
+ case 'N':
+ magic = OMAGIC;
+ return;
+
+#ifdef NMAGIC
+ case 'n':
+ magic = NMAGIC;
+ return;
+#endif
+
+ case 'o':
+ output_filename = arg;
+ return;
+
+ case 'p':
+ padtext = 1;
+ return;
+
+ case 'r':
+ relocatable_output = 1;
+ magic = OMAGIC;
+ text_start = 0;
+ return;
+
+ case 'S':
+ strip_symbols = STRIP_DEBUGGER;
+ return;
+
+ case 's':
+ strip_symbols = STRIP_ALL;
+ return;
+
+ case 'T':
+ text_start = parse (arg, "%x", "invalid argument to -T");
+ T_flag_specified = 1;
+ return;
+
+ case 't':
+ trace_files = 1;
+ return;
+
+ case 'u':
+ {
+ register symbol *sp = getsym (arg);
+ if (!sp->defined && !sp->referenced)
+ undefined_global_sym_count++;
+ sp->referenced = 1;
+ add_cmdline_ref (sp);
+ }
+ return;
+
+ case 'V':
+ {
+ struct string_list_element *new
+ = (struct string_list_element *)
+ xmalloc (sizeof (struct string_list_element));
+
+ new->str = arg;
+ new->next = set_element_prefixes;
+ set_element_prefixes = new;
+ return;
+ }
+
+ case 'X':
+ discard_locals = DISCARD_L;
+ return;
+
+ case 'x':
+ discard_locals = DISCARD_ALL;
+ return;
+
+ case 'y':
+ {
+ register symbol *sp = getsym (&swt[2]);
+ sp->trace = 1;
+ }
+ return;
+
+ case 'z':
+ magic = ZMAGIC;
+ return;
+
+ default:
+ fatal ("invalid command option `%s'", swt);
+ }
+}
+
+/** Convenient functions for operating on one or all files being */
+ /** loaded. */
+void print_file_name ();
+
+/* Call FUNCTION on each input file entry.
+ Do not call for entries for libraries;
+ instead, call once for each library member that is being loaded.
+
+ FUNCTION receives two arguments: the entry, and ARG. */
+
+void
+each_file (function, arg)
+ register void (*function)();
+ register int arg;
+{
+ register int i;
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->library_flag)
+ {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain)
+ (*function) (subentry, arg);
+ }
+ else
+ (*function) (entry, arg);
+ }
+}
+
+/* Call FUNCTION on each input file entry until it returns a non-zero
+ value. Return this value.
+ Do not call for entries for libraries;
+ instead, call once for each library member that is being loaded.
+
+ FUNCTION receives two arguments: the entry, and ARG. It must be a
+ function returning unsigned long (though this can probably be fudged). */
+
+unsigned long
+check_each_file (function, arg)
+ register unsigned long (*function)();
+ register int arg;
+{
+ register int i;
+ register unsigned long return_val;
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->library_flag)
+ {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain)
+ if (return_val = (*function) (subentry, arg))
+ return return_val;
+ }
+ else
+ if (return_val = (*function) (entry, arg))
+ return return_val;
+ }
+ return 0;
+}
+
+/* Like `each_file' but ignore files that were just for symbol definitions. */
+
+void
+each_full_file (function, arg)
+ register void (*function)();
+ register int arg;
+{
+ register int i;
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ if (entry->just_syms_flag)
+ continue;
+ if (entry->library_flag)
+ {
+ register struct file_entry *subentry = entry->subfiles;
+ for (; subentry; subentry = subentry->chain)
+ (*function) (subentry, arg);
+ }
+ else
+ (*function) (entry, arg);
+ }
+}
+
+/* Close the input file that is now open. */
+
+void
+file_close ()
+{
+ close (input_desc);
+ input_desc = 0;
+ input_file = 0;
+}
+
+/* Open the input file specified by 'entry', and return a descriptor.
+ The open file is remembered; if the same file is opened twice in a row,
+ a new open is not actually done. */
+
+int
+file_open (entry)
+ register struct file_entry *entry;
+{
+ register int desc;
+
+ if (entry->superfile)
+ return file_open (entry->superfile);
+
+ if (entry == input_file)
+ return input_desc;
+
+ if (input_file) file_close ();
+
+ if (entry->search_dirs_flag)
+ {
+ int i;
+
+ for (i = 0; i < n_search_dirs; i++)
+ {
+ register char *string
+ = concat (search_dirs[i], "/", entry->filename);
+ desc = open (string, O_RDONLY, 0);
+ if (desc > 0)
+ {
+ entry->filename = string;
+ entry->search_dirs_flag = 0;
+ break;
+ }
+ free (string);
+ }
+ }
+ else
+ desc = open (entry->filename, O_RDONLY, 0);
+
+ if (desc > 0)
+ {
+ input_file = entry;
+ input_desc = desc;
+ return desc;
+ }
+
+ perror_file (entry);
+ /* NOTREACHED */
+}
+
+/* Print the filename of ENTRY on OUTFILE (a stdio stream),
+ and then a newline. */
+
+void
+prline_file_name (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ print_file_name (entry, outfile);
+ fprintf (outfile, "\n");
+}
+
+/* Print the filename of ENTRY on OUTFILE (a stdio stream). */
+
+void
+print_file_name (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ if (entry->superfile)
+ {
+ print_file_name (entry->superfile, outfile);
+ fprintf (outfile, "(%s)", entry->filename);
+ }
+ else
+ fprintf (outfile, "%s", entry->filename);
+}
+
+/* Return the filename of entry as a string (malloc'd for the purpose) */
+
+char *
+get_file_name (entry)
+ struct file_entry *entry;
+{
+ char *result, *supfile;
+ if (entry->superfile)
+ {
+ supfile = get_file_name (entry->superfile);
+ result = (char *) xmalloc (strlen (supfile)
+ + strlen (entry->filename) + 3);
+ sprintf (result, "%s(%s)", supfile, entry->filename);
+ free (supfile);
+ }
+ else
+ {
+ result = (char *) xmalloc (strlen (entry->filename) + 1);
+ strcpy (result, entry->filename);
+ }
+ return result;
+}
+
+/* Medium-level input routines for rel files. */
+
+/* Read a file's header into the proper place in the file_entry.
+ DESC is the descriptor on which the file is open.
+ ENTRY is the file's entry. */
+
+void
+read_header (desc, entry)
+ int desc;
+ register struct file_entry *entry;
+{
+ register int len;
+ struct exec *loc = (struct exec *) &entry->header;
+
+ lseek (desc, entry->starting_offset, 0);
+#ifdef COFF_ENCAPSULATE
+ if (entry->just_syms_flag)
+ lseek (desc, sizeof(coffheader), 1);
+#endif
+ len = read (desc, loc, sizeof (struct exec));
+ if (len != sizeof (struct exec))
+ fatal_with_file ("failure reading header of ", entry);
+ if (N_BADMAG (*loc))
+ fatal_with_file ("bad magic number in ", entry);
+
+ entry->header_read_flag = 1;
+}
+
+/* Read the symbols of file ENTRY into core.
+ Assume it is already open, on descriptor DESC.
+ Also read the length of the string table, which follows the symbol table,
+ but don't read the contents of the string table. */
+
+void
+read_entry_symbols (desc, entry)
+ struct file_entry *entry;
+ int desc;
+{
+ int str_size;
+
+ if (!entry->header_read_flag)
+ read_header (desc, entry);
+
+ entry->symbols = (struct nlist *) xmalloc (entry->header.a_syms);
+
+ lseek (desc, N_SYMOFF (entry->header) + entry->starting_offset, 0);
+ if (entry->header.a_syms != read (desc, entry->symbols, entry->header.a_syms))
+ fatal_with_file ("premature end of file in symbols of ", entry);
+
+ lseek (desc, N_STROFF (entry->header) + entry->starting_offset, 0);
+ if (sizeof str_size != read (desc, &str_size, sizeof str_size))
+ fatal_with_file ("bad string table size in ", entry);
+
+ entry->string_size = str_size;
+}
+
+/* Read the string table of file ENTRY into core.
+ Assume it is already open, on descriptor DESC.
+ Also record whether a GDB symbol segment follows the string table. */
+
+void
+read_entry_strings (desc, entry)
+ struct file_entry *entry;
+ int desc;
+{
+ int buffer;
+
+ if (!entry->header_read_flag)
+ read_header (desc, entry);
+
+ lseek (desc, N_STROFF (entry->header) + entry->starting_offset, 0);
+ if (entry->string_size != read (desc, entry->strings, entry->string_size))
+ fatal_with_file ("premature end of file in strings of ", entry);
+
+ /* While we are here, see if the file has a symbol segment at the end.
+ For a separate file, just try reading some more.
+ For a library member, compare current pos against total size. */
+ if (entry->superfile)
+ {
+ if (entry->total_size == N_STROFF (entry->header) + entry->string_size)
+ return;
+ }
+ else
+ {
+ buffer = read (desc, &buffer, sizeof buffer);
+ if (buffer == 0)
+ return;
+ if (buffer != sizeof buffer)
+ fatal_with_file ("premature end of file in GDB symbol segment of ", entry);
+ }
+ /* Don't try to do anything with symsegs. */
+ return;
+#if 0
+ /* eliminate warning of `statement not reached'. */
+ entry->symseg_offset = N_STROFF (entry->header) + entry->string_size;
+#endif
+}
+
+/* Read in the symbols of all input files. */
+
+void read_file_symbols (), read_entry_symbols (), read_entry_strings ();
+void enter_file_symbols (), enter_global_ref (), search_library ();
+
+void
+load_symbols ()
+{
+ register int i;
+
+ if (trace_files) fprintf (stderr, "Loading symbols:\n\n");
+
+ for (i = 0; i < number_of_files; i++)
+ {
+ register struct file_entry *entry = &file_table[i];
+ read_file_symbols (entry);
+ }
+
+ if (trace_files) fprintf (stderr, "\n");
+}
+
+/* If ENTRY is a rel file, read its symbol and string sections into core.
+ If it is a library, search it and load the appropriate members
+ (which means calling this function recursively on those members). */
+
+void
+read_file_symbols (entry)
+ register struct file_entry *entry;
+{
+ register int desc;
+ register int len;
+ struct exec hdr;
+
+ desc = file_open (entry);
+
+#ifdef COFF_ENCAPSULATE
+ if (entry->just_syms_flag)
+ lseek (desc, sizeof(coffheader),0);
+#endif
+
+ len = read (desc, &hdr, sizeof hdr);
+ if (len != sizeof hdr)
+ fatal_with_file ("failure reading header of ", entry);
+
+ if (!N_BADMAG (hdr))
+ {
+ read_entry_symbols (desc, entry);
+ entry->strings = (char *) alloca (entry->string_size);
+ read_entry_strings (desc, entry);
+ enter_file_symbols (entry);
+ entry->strings = 0;
+ }
+ else
+ {
+ char armag[SARMAG];
+
+ lseek (desc, 0, 0);
+ if (SARMAG != read (desc, armag, SARMAG) || strncmp (armag, ARMAG, SARMAG))
+ fatal_with_file ("malformed input file (not rel or archive) ", entry);
+ entry->library_flag = 1;
+ search_library (desc, entry);
+ }
+
+ file_close ();
+}
+
+/* Enter the external symbol defs and refs of ENTRY in the hash table. */
+
+void
+enter_file_symbols (entry)
+ struct file_entry *entry;
+{
+ register struct nlist
+ *p,
+ *end = entry->symbols + entry->header.a_syms / sizeof (struct nlist);
+
+ if (trace_files) prline_file_name (entry, stderr);
+
+ for (p = entry->symbols; p < end; p++)
+ {
+ if (p->n_type == (N_SETV | N_EXT)) continue;
+ if (set_element_prefixes
+ && set_element_prefixed_p (p->n_un.n_strx + entry->strings))
+ p->n_type += (N_SETA - N_ABS);
+
+ if (SET_ELEMENT_P (p->n_type))
+ {
+ set_symbol_count++;
+ if (!relocatable_output)
+ enter_global_ref (p, p->n_un.n_strx + entry->strings, entry);
+ }
+ else if (p->n_type == N_WARNING)
+ {
+ char *name = p->n_un.n_strx + entry->strings;
+
+ /* Grab the next entry. */
+ p++;
+ if (p->n_type != (N_UNDF | N_EXT))
+ {
+ fprintf (stderr, "%s: Warning symbol found in %s without external reference following.\n",
+ progname, entry->filename);
+ make_executable = 0;
+ p--; /* Process normally. */
+ }
+ else
+ {
+ symbol *sp;
+ char *sname = p->n_un.n_strx + entry->strings;
+ /* Deal with the warning symbol. */
+ enter_global_ref (p, p->n_un.n_strx + entry->strings, entry);
+ sp = getsym (sname);
+ sp->warning = (char *) xmalloc (strlen(name) + 1);
+ strcpy (sp->warning, name);
+ warning_count++;
+ }
+ }
+ else if (p->n_type & N_EXT)
+ enter_global_ref (p, p->n_un.n_strx + entry->strings, entry);
+ else if (p->n_un.n_strx && !(p->n_type & (N_STAB | N_EXT)))
+ {
+ if ((p->n_un.n_strx + entry->strings)[0] != LPREFIX)
+ non_L_local_sym_count++;
+ local_sym_count++;
+ }
+ else debugger_sym_count++;
+ }
+
+ /* Count one for the local symbol that we generate,
+ whose name is the file's name (usually) and whose address
+ is the start of the file's text. */
+
+ local_sym_count++;
+ non_L_local_sym_count++;
+}
+
+/* Enter one global symbol in the hash table.
+ NLIST_P points to the `struct nlist' read from the file
+ that describes the global symbol. NAME is the symbol's name.
+ ENTRY is the file entry for the file the symbol comes from.
+
+ The `struct nlist' is modified by placing it on a chain of
+ all such structs that refer to the same global symbol.
+ This chain starts in the `refs' field of the symbol table entry
+ and is chained through the `n_name'. */
+
+void
+enter_global_ref (nlist_p, name, entry)
+ register struct nlist *nlist_p;
+ char *name;
+ struct file_entry *entry;
+{
+ register symbol *sp = getsym (name);
+ register int type = nlist_p->n_type;
+ int oldref = sp->referenced;
+ int olddef = sp->defined;
+ int com = sp->defined && sp->max_common_size;
+
+ nlist_p->n_un.n_name = (char *) sp->refs;
+ sp->refs = nlist_p;
+
+ sp->referenced = 1;
+ if (type != (N_UNDF | N_EXT) || nlist_p->n_value)
+ {
+ if (!sp->defined || sp->defined == (N_UNDF | N_EXT))
+ sp->defined = type;
+
+ if (oldref && !olddef)
+ /* It used to be undefined and we're defining it. */
+ undefined_global_sym_count--;
+
+ if (!olddef && type == (N_UNDF | N_EXT) && nlist_p->n_value)
+ {
+ /* First definition and it's common. */
+ common_defined_global_count++;
+ sp->max_common_size = nlist_p->n_value;
+ }
+ else if (com && type != (N_UNDF | N_EXT))
+ {
+ /* It used to be common and we're defining it as
+ something else. */
+ common_defined_global_count--;
+ sp->max_common_size = 0;
+ }
+ else if (com && type == (N_UNDF | N_EXT)
+ && sp->max_common_size < nlist_p->n_value)
+ /* It used to be common and this is a new common entry to
+ which we need to pay attention. */
+ sp->max_common_size = nlist_p->n_value;
+
+ /* Are we defining it as a set element? */
+ if (SET_ELEMENT_P (type) && (!olddef || com))
+ set_vector_count++;
+ /* As an indirection? */
+ else if (type == (N_INDR | N_EXT))
+ {
+ /* Indirect symbols value should be modified to point
+ a symbol being equivalenced to. */
+ nlist_p->n_value
+ = (unsigned int) getsym ((nlist_p + 1)->n_un.n_strx
+ + entry->strings);
+ if ((symbol *) nlist_p->n_value == sp)
+ {
+ /* Somebody redefined a symbol to be itself. */
+ fprintf (stderr, "%s: Symbol %s indirected to itself.\n",
+ entry->filename, name);
+ /* Rewrite this symbol as being a global text symbol
+ with value 0. */
+ nlist_p->n_type = sp->defined = N_TEXT | N_EXT;
+ nlist_p->n_value = 0;
+ /* Don't make the output executable. */
+ make_executable = 0;
+ }
+ else
+ global_indirect_count++;
+ }
+ }
+ else
+ if (!oldref)
+#ifndef DOLLAR_KLUDGE
+ undefined_global_sym_count++;
+#else
+ {
+ if (entry->superfile && type == (N_UNDF | N_EXT) && name[1] == '$')
+ {
+ /* This is an (ISI?) $-conditional; skip it */
+ sp->referenced = 0;
+ if (sp->trace)
+ {
+ fprintf (stderr, "symbol %s is a $-conditional ignored in ", sp->name);
+ print_file_name (entry, stderr);
+ fprintf (stderr, "\n");
+ }
+ return;
+ }
+ else
+ undefined_global_sym_count++;
+ }
+#endif
+
+ if (sp == end_symbol && entry->just_syms_flag && !T_flag_specified)
+ text_start = nlist_p->n_value;
+
+ if (sp->trace)
+ {
+ register char *reftype;
+ switch (type & N_TYPE)
+ {
+ case N_UNDF:
+ if (nlist_p->n_value)
+ reftype = "defined as common";
+ else reftype = "referenced";
+ break;
+
+ case N_ABS:
+ reftype = "defined as absolute";
+ break;
+
+ case N_TEXT:
+ reftype = "defined in text section";
+ break;
+
+ case N_DATA:
+ reftype = "defined in data section";
+ break;
+
+ case N_BSS:
+ reftype = "defined in BSS section";
+ break;
+
+ case N_SETT:
+ reftype = "is a text set element";
+ break;
+
+ case N_SETD:
+ reftype = "is a data set element";
+ break;
+
+ case N_SETB:
+ reftype = "is a BSS set element";
+ break;
+
+ case N_SETA:
+ reftype = "is an absolute set element";
+ break;
+
+ case N_SETV:
+ reftype = "defined in data section as vector";
+ break;
+
+ case N_INDR:
+ reftype = (char *) alloca (23
+ + strlen ((nlist_p + 1)->n_un.n_strx
+ + entry->strings));
+ sprintf (reftype, "defined equivalent to %s",
+ (nlist_p + 1)->n_un.n_strx + entry->strings);
+ break;
+
+#ifdef sequent
+ case N_SHUNDF:
+ reftype = "shared undf";
+ break;
+
+/* These conflict with cases above.
+ case N_SHDATA:
+ reftype = "shared data";
+ break;
+
+ case N_SHBSS:
+ reftype = "shared BSS";
+ break;
+*/
+ default:
+ reftype = "I don't know this type";
+ break;
+#endif
+ }
+
+ fprintf (stderr, "symbol %s %s in ", sp->name, reftype);
+ print_file_name (entry, stderr);
+ fprintf (stderr, "\n");
+ }
+}
+
+/* This return 0 if the given file entry's symbol table does *not*
+ contain the nlist point entry, and it returns the files entry
+ pointer (cast to unsigned long) if it does. */
+
+unsigned long
+contains_symbol (entry, n_ptr)
+ struct file_entry *entry;
+ register struct nlist *n_ptr;
+{
+ if (n_ptr >= entry->symbols &&
+ n_ptr < (entry->symbols
+ + (entry->header.a_syms / sizeof (struct nlist))))
+ return (unsigned long) entry;
+ return 0;
+}
+
+
+/* Searching libraries */
+
+struct file_entry *decode_library_subfile ();
+void linear_library (), symdef_library ();
+
+/* Search the library ENTRY, already open on descriptor DESC.
+ This means deciding which library members to load,
+ making a chain of `struct file_entry' for those members,
+ and entering their global symbols in the hash table. */
+
+void
+search_library (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ int member_length;
+ register char *name;
+ register struct file_entry *subentry;
+
+ if (!undefined_global_sym_count) return;
+
+ /* Examine its first member, which starts SARMAG bytes in. */
+ subentry = decode_library_subfile (desc, entry, SARMAG, &member_length);
+ if (!subentry) return;
+
+ name = subentry->filename;
+ free (subentry);
+
+ /* Search via __.SYMDEF if that exists, else linearly. */
+
+ if (!strcmp (name, "__.SYMDEF"))
+ symdef_library (desc, entry, member_length);
+ else
+ linear_library (desc, entry);
+}
+
+/* Construct and return a file_entry for a library member.
+ The library's file_entry is library_entry, and the library is open on DESC.
+ SUBFILE_OFFSET is the byte index in the library of this member's header.
+ We store the length of the member into *LENGTH_LOC. */
+
+struct file_entry *
+decode_library_subfile (desc, library_entry, subfile_offset, length_loc)
+ int desc;
+ struct file_entry *library_entry;
+ int subfile_offset;
+ int *length_loc;
+{
+ int bytes_read;
+ register int namelen;
+ int member_length;
+ register char *name;
+ struct ar_hdr hdr1;
+ register struct file_entry *subentry;
+
+ lseek (desc, subfile_offset, 0);
+
+ bytes_read = read (desc, &hdr1, sizeof hdr1);
+ if (!bytes_read)
+ return 0; /* end of archive */
+
+ if (sizeof hdr1 != bytes_read)
+ fatal_with_file ("malformed library archive ", library_entry);
+
+ if (sscanf (hdr1.ar_size, "%d", &member_length) != 1)
+ fatal_with_file ("malformatted header of archive member in ", library_entry);
+
+ subentry = (struct file_entry *) xmalloc (sizeof (struct file_entry));
+ bzero (subentry, sizeof (struct file_entry));
+
+ for (namelen = 0;
+ namelen < sizeof hdr1.ar_name
+ && hdr1.ar_name[namelen] != 0 && hdr1.ar_name[namelen] != ' '
+ && hdr1.ar_name[namelen] != '/';
+ namelen++);
+
+ name = (char *) xmalloc (namelen+1);
+ strncpy (name, hdr1.ar_name, namelen);
+ name[namelen] = 0;
+
+ subentry->filename = name;
+ subentry->local_sym_name = name;
+ subentry->symbols = 0;
+ subentry->strings = 0;
+ subentry->subfiles = 0;
+ subentry->starting_offset = subfile_offset + sizeof hdr1;
+ subentry->superfile = library_entry;
+ subentry->library_flag = 0;
+ subentry->header_read_flag = 0;
+ subentry->just_syms_flag = 0;
+ subentry->chain = 0;
+ subentry->total_size = member_length;
+
+ (*length_loc) = member_length;
+
+ return subentry;
+}
+
+int subfile_wanted_p ();
+
+/* Search a library that has a __.SYMDEF member.
+ DESC is a descriptor on which the library is open.
+ The file pointer is assumed to point at the __.SYMDEF data.
+ ENTRY is the library's file_entry.
+ MEMBER_LENGTH is the length of the __.SYMDEF data. */
+
+void
+symdef_library (desc, entry, member_length)
+ int desc;
+ struct file_entry *entry;
+ int member_length;
+{
+ int *symdef_data = (int *) xmalloc (member_length);
+ register struct symdef *symdef_base;
+ char *sym_name_base;
+ int number_of_symdefs;
+ int length_of_strings;
+ int not_finished;
+ int bytes_read;
+ register int i;
+ struct file_entry *prev = 0;
+ int prev_offset = 0;
+
+ bytes_read = read (desc, symdef_data, member_length);
+ if (bytes_read != member_length)
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+
+ number_of_symdefs = *symdef_data / sizeof (struct symdef);
+ if (number_of_symdefs < 0 ||
+ number_of_symdefs * sizeof (struct symdef) + 2 * sizeof (int) > member_length)
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+
+ symdef_base = (struct symdef *) (symdef_data + 1);
+ length_of_strings = *(int *) (symdef_base + number_of_symdefs);
+
+ if (length_of_strings < 0
+ || number_of_symdefs * sizeof (struct symdef) + length_of_strings
+ + 2 * sizeof (int) > member_length)
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+
+ sym_name_base = sizeof (int) + (char *) (symdef_base + number_of_symdefs);
+
+ /* Check all the string indexes for validity. */
+
+ for (i = 0; i < number_of_symdefs; i++)
+ {
+ register int index = symdef_base[i].symbol_name_string_index;
+ if (index < 0 || index >= length_of_strings
+ || (index && *(sym_name_base + index - 1)))
+ fatal_with_file ("malformatted __.SYMDEF in ", entry);
+ }
+
+ /* Search the symdef data for members to load.
+ Do this until one whole pass finds nothing to load. */
+
+ not_finished = 1;
+ while (not_finished)
+ {
+ not_finished = 0;
+
+ /* Scan all the symbols mentioned in the symdef for ones that we need.
+ Load the library members that contain such symbols. */
+
+ for (i = 0;
+ (i < number_of_symdefs
+ && (undefined_global_sym_count || common_defined_global_count));
+ i++)
+ if (symdef_base[i].symbol_name_string_index >= 0)
+ {
+ register symbol *sp;
+
+ sp = getsym_soft (sym_name_base
+ + symdef_base[i].symbol_name_string_index);
+
+ /* If we find a symbol that appears to be needed, think carefully
+ about the archive member that the symbol is in. */
+
+ /*
+ * Per Mike Karels' recommendation, we no longer load library
+ * files if the only reference(s) that would be satisfied are
+ * 'common' references. This prevents some problems with name
+ * pollution (e.g. a global common 'utime' linked to a function).
+ */
+ if (sp && sp->referenced && !sp->defined)
+ {
+ int junk;
+ register int j;
+ register int offset = symdef_base[i].library_member_offset;
+ struct file_entry *subentry;
+
+ /* Don't think carefully about any archive member
+ more than once in a given pass. */
+
+ if (prev_offset == offset)
+ continue;
+ prev_offset = offset;
+
+ /* Read the symbol table of the archive member. */
+
+ subentry = decode_library_subfile (desc, entry, offset, &junk);
+ if (subentry == 0)
+ fatal ("invalid offset for %s in symbol table of %s",
+ sym_name_base
+ + symdef_base[i].symbol_name_string_index,
+ entry->filename);
+ read_entry_symbols (desc, subentry);
+ subentry->strings = (char *) malloc (subentry->string_size);
+ read_entry_strings (desc, subentry);
+
+ /* Now scan the symbol table and decide whether to load. */
+
+ if (!subfile_wanted_p (subentry))
+ {
+ free (subentry->symbols);
+ free (subentry);
+ }
+ else
+ {
+ /* This member is needed; load it.
+ Since we are loading something on this pass,
+ we must make another pass through the symdef data. */
+
+ not_finished = 1;
+
+ enter_file_symbols (subentry);
+
+ if (prev)
+ prev->chain = subentry;
+ else entry->subfiles = subentry;
+ prev = subentry;
+
+ /* Clear out this member's symbols from the symdef data
+ so that following passes won't waste time on them. */
+
+ for (j = 0; j < number_of_symdefs; j++)
+ {
+ if (symdef_base[j].library_member_offset == offset)
+ symdef_base[j].symbol_name_string_index = -1;
+ }
+ }
+
+ /* We'll read the strings again if we need them again. */
+ free (subentry->strings);
+ subentry->strings = 0;
+ }
+ }
+ }
+
+ free (symdef_data);
+}
+
+/* Search a library that has no __.SYMDEF.
+ ENTRY is the library's file_entry.
+ DESC is the descriptor it is open on. */
+
+void
+linear_library (desc, entry)
+ int desc;
+ struct file_entry *entry;
+{
+ register struct file_entry *prev = 0;
+ register int this_subfile_offset = SARMAG;
+
+ while (undefined_global_sym_count || common_defined_global_count)
+ {
+ int member_length;
+ register struct file_entry *subentry;
+
+ subentry = decode_library_subfile (desc, entry, this_subfile_offset,
+ &member_length);
+
+ if (!subentry) return;
+
+ read_entry_symbols (desc, subentry);
+ subentry->strings = (char *) alloca (subentry->string_size);
+ read_entry_strings (desc, subentry);
+
+ if (!subfile_wanted_p (subentry))
+ {
+ free (subentry->symbols);
+ free (subentry);
+ }
+ else
+ {
+ enter_file_symbols (subentry);
+
+ if (prev)
+ prev->chain = subentry;
+ else entry->subfiles = subentry;
+ prev = subentry;
+ subentry->strings = 0; /* Since space will dissapear on return */
+ }
+
+ this_subfile_offset += member_length + sizeof (struct ar_hdr);
+ if (this_subfile_offset & 1) this_subfile_offset++;
+ }
+}
+
+/* ENTRY is an entry for a library member.
+ Its symbols have been read into core, but not entered.
+ Return nonzero if we ought to load this member. */
+
+int
+subfile_wanted_p (entry)
+ struct file_entry *entry;
+{
+ register struct nlist *p;
+ register struct nlist *end
+ = entry->symbols + entry->header.a_syms / sizeof (struct nlist);
+#ifdef DOLLAR_KLUDGE
+ register int dollar_cond = 0;
+#endif
+
+ for (p = entry->symbols; p < end; p++)
+ {
+ register int type = p->n_type;
+ register char *name = p->n_un.n_strx + entry->strings;
+
+ /* If the symbol has an interesting definition, we could
+ potentially want it. */
+ if (type & N_EXT
+ && (type != (N_UNDF | N_EXT) || p->n_value
+
+#ifdef DOLLAR_KLUDGE
+ || name[1] == '$'
+#endif
+ )
+ && !SET_ELEMENT_P (type)
+ && !set_element_prefixed_p (name))
+ {
+ register symbol *sp = getsym_soft (name);
+
+#ifdef DOLLAR_KLUDGE
+ if (name[1] == '$')
+ {
+ sp = getsym_soft (&name[2]);
+ dollar_cond = 1;
+ if (!sp) continue;
+ if (sp->referenced)
+ {
+ if (write_map)
+ {
+ print_file_name (entry, stdout);
+ fprintf (stdout, " needed due to $-conditional %s\n", name);
+ }
+ return 1;
+ }
+ continue;
+ }
+#endif
+
+ /* If this symbol has not been hashed, we can't be looking for it. */
+
+ if (!sp) continue;
+
+ /*
+ * We don't load a file if it merely satisfies a common reference
+ * (see explanation above in symdef_library()).
+ */
+ if (sp->referenced && !sp->defined)
+ {
+ /* This is a symbol we are looking for. It is either
+ not yet defined or defined as a common. */
+#ifdef DOLLAR_KLUDGE
+ if (dollar_cond) continue;
+#endif
+ if (type == (N_UNDF | N_EXT))
+ {
+ /* Symbol being defined as common.
+ Remember this, but don't load subfile just for this. */
+
+ /* If it didn't used to be common, up the count of
+ common symbols. */
+ if (!sp->max_common_size)
+ common_defined_global_count++;
+
+ if (sp->max_common_size < p->n_value)
+ sp->max_common_size = p->n_value;
+ if (!sp->defined)
+ undefined_global_sym_count--;
+ sp->defined = 1;
+ continue;
+ }
+
+ if (write_map)
+ {
+ print_file_name (entry, stdout);
+ fprintf (stdout, " needed due to %s\n", sp->name);
+ }
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+void consider_file_section_lengths (), relocate_file_addresses ();
+
+/* Having entered all the global symbols and found the sizes of sections
+ of all files to be linked, make all appropriate deductions from this data.
+
+ We propagate global symbol values from definitions to references.
+ We compute the layout of the output file and where each input file's
+ contents fit into it. */
+
+void
+digest_symbols ()
+{
+ register int i;
+ int setv_fill_count;
+
+ if (trace_files)
+ fprintf (stderr, "Digesting symbol information:\n\n");
+
+ /* Compute total size of sections */
+
+ each_file (consider_file_section_lengths, 0);
+
+ /* If necessary, pad text section to full page in the file.
+ Include the padding in the text segment size. */
+
+ if (magic == ZMAGIC)
+ {
+ int text_end = text_size + N_TXTOFF (outheader);
+ text_pad = ((text_end + page_size - 1) & (- page_size)) - text_end;
+ text_size += text_pad;
+ }
+ if (padtext)
+ {
+ int text_end = text_size;
+ text_pad = ((text_end + page_size - 1) & (- page_size)) - text_end;
+ text_size += text_pad;
+ }
+
+#ifdef _N_BASEADDR
+ /* SunOS 4.1 N_TXTADDR depends on the value of outheader.a_entry. */
+ outheader.a_entry = N_PAGSIZ (outheader);
+#endif
+
+ outheader.a_text = text_size;
+#ifdef sequent
+ outheader.a_text += N_ADDRADJ (outheader);
+#endif
+
+ /* Make the data segment address start in memory on a suitable boundary. */
+
+ if (! Tdata_flag_specified)
+ data_start = N_DATADDR (outheader) + text_start - TEXT_START (outheader);
+
+ /* Set up the set element vector */
+
+ if (!relocatable_output)
+ {
+ /* The set sector size is the number of set elements + a word
+ for each symbol for the length word at the beginning of the
+ vector, plus a word for each symbol for a zero at the end of
+ the vector (for incremental linking). */
+ set_sect_size
+ = (2 * set_symbol_count + set_vector_count) * sizeof (unsigned long);
+ set_sect_start = data_start + data_size;
+ data_size += set_sect_size;
+ set_vectors = (unsigned long *) xmalloc (set_sect_size);
+ setv_fill_count = 0;
+ }
+
+ /* Compute start addresses of each file's sections and symbols. */
+
+ each_full_file (relocate_file_addresses, 0);
+
+ /* Now, for each symbol, verify that it is defined globally at most once.
+ Put the global value into the symbol entry.
+ Common symbols are allocated here, in the BSS section.
+ Each defined symbol is given a '->defined' field
+ which is the correct N_ code for its definition,
+ except in the case of common symbols with -r.
+ Then make all the references point at the symbol entry
+ instead of being chained together. */
+
+ defined_global_sym_count = 0;
+
+ for (i = 0; i < TABSIZE; i++)
+ {
+ register symbol *sp;
+ for (sp = symtab[i]; sp; sp = sp->link)
+ {
+ /* For each symbol */
+ register struct nlist *p, *next;
+ int defs = 0, com = sp->max_common_size;
+ struct nlist *first_definition;
+ for (p = sp->refs; p; p = next)
+ {
+ register int type = p->n_type;
+
+ if (SET_ELEMENT_P (type))
+ {
+ if (relocatable_output)
+ fatal ("internal: global ref to set element with -r");
+ if (!defs++)
+ {
+ sp->value = set_sect_start
+ + setv_fill_count++ * sizeof (unsigned long);
+ sp->defined = N_SETV | N_EXT;
+ first_definition = p;
+ }
+ else if ((sp->defined & ~N_EXT) != N_SETV)
+ {
+ sp->multiply_defined = 1;
+ multiple_def_count++;
+ }
+ set_vectors[setv_fill_count++] = p->n_value;
+ }
+ else if ((type & N_EXT) && type != (N_UNDF | N_EXT))
+ {
+ /* non-common definition */
+ if (defs++ && sp->value != p->n_value)
+ {
+ sp->multiply_defined = 1;
+ multiple_def_count++;
+ }
+ sp->value = p->n_value;
+ sp->defined = type;
+ first_definition = p;
+ }
+ next = (struct nlist *) p->n_un.n_name;
+ p->n_un.n_name = (char *) sp;
+ }
+ /* Allocate as common if defined as common and not defined for real */
+ if (com && !defs)
+ {
+ if (!relocatable_output || force_common_definition)
+ {
+ int align = sizeof (int);
+
+ /* Round up to nearest sizeof (int). I don't know
+ whether this is necessary or not (given that
+ alignment is taken care of later), but it's
+ traditional, so I'll leave it in. Note that if
+ this size alignment is ever removed, ALIGN above
+ will have to be initialized to 1 instead of
+ sizeof (int). */
+
+ com = (com + sizeof (int) - 1) & (- sizeof (int));
+
+ while (!(com & align))
+ align <<= 1;
+
+ align = align > MAX_ALIGNMENT ? MAX_ALIGNMENT : align;
+
+ bss_size = ((((bss_size + data_size + data_start)
+ + (align - 1)) & (- align))
+ - data_size - data_start);
+
+ sp->value = data_start + data_size + bss_size;
+ sp->defined = N_BSS | N_EXT;
+ bss_size += com;
+ if (write_map)
+ printf ("Allocating common %s: %x at %x\n",
+ sp->name, com, sp->value);
+ }
+ else
+ {
+ sp->defined = 0;
+ undefined_global_sym_count++;
+ }
+ }
+ /* Set length word at front of vector and zero byte at end.
+ Reverse the vector itself to put it in file order. */
+ if ((sp->defined & ~N_EXT) == N_SETV)
+ {
+ unsigned long length_word_index
+ = (sp->value - set_sect_start) / sizeof (unsigned long);
+ unsigned long i, tmp;
+
+ set_vectors[length_word_index]
+ = setv_fill_count - 1 - length_word_index;
+
+ /* Reverse the vector. */
+ for (i = 1;
+ i < (setv_fill_count - length_word_index - 1) / 2 + 1;
+ i++)
+ {
+ tmp = set_vectors[length_word_index + i];
+ set_vectors[length_word_index + i]
+ = set_vectors[setv_fill_count - i];
+ set_vectors[setv_fill_count - i] = tmp;
+ }
+
+ set_vectors[setv_fill_count++] = 0;
+ }
+ if (sp->defined)
+ defined_global_sym_count++;
+ }
+ }
+
+ if (end_symbol) /* These are null if -r. */
+ {
+ etext_symbol->value = text_size + text_start;
+ edata_symbol->value = data_start + data_size;
+ end_symbol->value = data_start + data_size + bss_size;
+ }
+
+ /* Figure the data_pad now, so that it overlaps with the bss addresses. */
+
+ if (specified_data_size && specified_data_size > data_size)
+ data_pad = specified_data_size - data_size;
+
+ if (magic == ZMAGIC)
+ data_pad = ((data_pad + data_size + page_size - 1) & (- page_size))
+ - data_size;
+
+ bss_size -= data_pad;
+ if (bss_size < 0) bss_size = 0;
+
+ data_size += data_pad;
+}
+
+/* Accumulate the section sizes of input file ENTRY
+ into the section sizes of the output file. */
+
+void
+consider_file_section_lengths (entry)
+ register struct file_entry *entry;
+{
+ if (entry->just_syms_flag)
+ return;
+
+ entry->text_start_address = text_size;
+ /* If there were any vectors, we need to chop them off */
+ text_size += entry->header.a_text;
+ entry->data_start_address = data_size;
+ data_size += entry->header.a_data;
+ entry->bss_start_address = bss_size;
+ bss_size += entry->header.a_bss;
+
+ text_reloc_size += entry->header.a_trsize;
+ data_reloc_size += entry->header.a_drsize;
+}
+
+/* Determine where the sections of ENTRY go into the output file,
+ whose total section sizes are already known.
+ Also relocate the addresses of the file's local and debugger symbols. */
+
+void
+relocate_file_addresses (entry)
+ register struct file_entry *entry;
+{
+ entry->text_start_address += text_start;
+ /* Note that `data_start' and `data_size' have not yet been
+ adjusted for `data_pad'. If they had been, we would get the wrong
+ results here. */
+ entry->data_start_address += data_start;
+ entry->bss_start_address += data_start + data_size;
+
+ {
+ register struct nlist *p;
+ register struct nlist *end
+ = entry->symbols + entry->header.a_syms / sizeof (struct nlist);
+
+ for (p = entry->symbols; p < end; p++)
+ {
+ /* If this belongs to a section, update it by the section's start address */
+ register int type = p->n_type & N_TYPE;
+
+ switch (type)
+ {
+ case N_TEXT:
+ case N_SETT:
+ p->n_value += entry->text_start_address;
+ break;
+ case N_DATA:
+ case N_SETV:
+ case N_SETD:
+ /* A symbol whose value is in the data section
+ is present in the input file as if the data section
+ started at an address equal to the length of the file's text. */
+ p->n_value += entry->data_start_address - entry->header.a_text;
+ break;
+ case N_BSS:
+ case N_SETB:
+ /* likewise for symbols with value in BSS. */
+ p->n_value += entry->bss_start_address
+ - entry->header.a_text - entry->header.a_data;
+ break;
+ }
+ }
+ }
+}
+
+void describe_file_sections (), list_file_locals ();
+
+/* Print a complete or partial map of the output file. */
+
+void
+print_symbols (outfile)
+ FILE *outfile;
+{
+ register int i;
+
+ fprintf (outfile, "\nFiles:\n\n");
+
+ each_file (describe_file_sections, outfile);
+
+ fprintf (outfile, "\nGlobal symbols:\n\n");
+
+ for (i = 0; i < TABSIZE; i++)
+ {
+ register symbol *sp;
+ for (sp = symtab[i]; sp; sp = sp->link)
+ {
+ if (sp->defined == 1)
+ fprintf (outfile, " %s: common, length 0x%x\n", sp->name, sp->max_common_size);
+ if (sp->defined)
+ fprintf (outfile, " %s: 0x%x\n", sp->name, sp->value);
+ else if (sp->referenced)
+ fprintf (outfile, " %s: undefined\n", sp->name);
+ }
+ }
+
+ each_file (list_file_locals, outfile);
+}
+
+void
+describe_file_sections (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ fprintf (outfile, " ");
+ print_file_name (entry, outfile);
+ if (entry->just_syms_flag)
+ fprintf (outfile, " symbols only\n", 0);
+ else
+ fprintf (outfile, " text %x(%x), data %x(%x), bss %x(%x) hex\n",
+ entry->text_start_address, entry->header.a_text,
+ entry->data_start_address, entry->header.a_data,
+ entry->bss_start_address, entry->header.a_bss);
+}
+
+void
+list_file_locals (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ register struct nlist
+ *p,
+ *end = entry->symbols + entry->header.a_syms / sizeof (struct nlist);
+
+ entry->strings = (char *) alloca (entry->string_size);
+ read_entry_strings (file_open (entry), entry);
+
+ fprintf (outfile, "\nLocal symbols of ");
+ print_file_name (entry, outfile);
+ fprintf (outfile, ":\n\n");
+
+ for (p = entry->symbols; p < end; p++)
+ /* If this is a definition,
+ update it if necessary by this file's start address. */
+ if (!(p->n_type & (N_STAB | N_EXT)))
+ fprintf (outfile, " %s: 0x%x\n",
+ entry->strings + p->n_un.n_strx, p->n_value);
+
+ entry->strings = 0; /* All done with them. */
+}
+
+
+/* Static vars for do_warnings and subroutines of it */
+int list_unresolved_refs; /* List unresolved refs */
+int list_warning_symbols; /* List warning syms */
+int list_multiple_defs; /* List multiple definitions */
+
+/*
+ * Structure for communication between do_file_warnings and it's
+ * helper routines. Will in practice be an array of three of these:
+ * 0) Current line, 1) Next line, 2) Source file info.
+ */
+struct line_debug_entry
+{
+ int line;
+ char *filename;
+ struct nlist *sym;
+};
+
+void qsort ();
+/*
+ * Helper routines for do_file_warnings.
+ */
+
+/* Return an integer less than, equal to, or greater than 0 as per the
+ relation between the two relocation entries. Used by qsort. */
+
+int
+relocation_entries_relation (rel1, rel2)
+ struct relocation_info *rel1, *rel2;
+{
+ return RELOC_ADDRESS(rel1) - RELOC_ADDRESS(rel2);
+}
+
+/* Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS
+ determines the type of the debugging symbol to look for (DSLINE or
+ SLINE). STATE_POINTER keeps track of the old and new locatiosn in
+ the file. It assumes that state_pointer[1] is valid; ie
+ that it.sym points into some entry in the symbol table. If
+ state_pointer[1].sym == 0, this routine should not be called. */
+
+int
+next_debug_entry (use_data_symbols, state_pointer)
+ register int use_data_symbols;
+ /* Next must be passed by reference! */
+ struct line_debug_entry state_pointer[3];
+{
+ register struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1,
+ /* Used to store source file */
+ *source = state_pointer + 2;
+ struct file_entry *entry = (struct file_entry *) source->sym;
+
+ current->sym = next->sym;
+ current->line = next->line;
+ current->filename = next->filename;
+
+ while (++(next->sym) < (entry->symbols
+ + entry->header.a_syms/sizeof (struct nlist)))
+ {
+ /* n_type is a char, and N_SOL, N_EINCL and N_BINCL are > 0x80, so
+ * may look negative...therefore, must mask to low bits
+ */
+ switch (next->sym->n_type & 0xff)
+ {
+ case N_SLINE:
+ if (use_data_symbols) continue;
+ next->line = next->sym->n_desc;
+ return 1;
+ case N_DSLINE:
+ if (!use_data_symbols) continue;
+ next->line = next->sym->n_desc;
+ return 1;
+#ifdef HAVE_SUN_STABS
+ case N_EINCL:
+ next->filename = source->filename;
+ continue;
+#endif
+ case N_SO:
+ source->filename = next->sym->n_un.n_strx + entry->strings;
+ source->line++;
+#ifdef HAVE_SUN_STABS
+ case N_BINCL:
+#endif
+ case N_SOL:
+ next->filename
+ = next->sym->n_un.n_strx + entry->strings;
+ default:
+ continue;
+ }
+ }
+ next->sym = (struct nlist *) 0;
+ return 0;
+}
+
+/* Create a structure to save the state of a scan through the debug
+ symbols. USE_DATA_SYMBOLS is set if we should be scanning for
+ DSLINE's instead of SLINE's. entry is the file entry which points
+ at the symbols to use. */
+
+struct line_debug_entry *
+init_debug_scan (use_data_symbols, entry)
+ int use_data_symbols;
+ struct file_entry *entry;
+{
+ struct line_debug_entry
+ *state_pointer
+ = (struct line_debug_entry *)
+ xmalloc (3 * sizeof (struct line_debug_entry));
+ register struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1,
+ *source = state_pointer + 2; /* Used to store source file */
+
+ struct nlist *tmp;
+
+ for (tmp = entry->symbols;
+ tmp < (entry->symbols
+ + entry->header.a_syms/sizeof (struct nlist));
+ tmp++)
+ if (tmp->n_type == (int) N_SO)
+ break;
+
+ if (tmp >= (entry->symbols
+ + entry->header.a_syms/sizeof (struct nlist)))
+ {
+ /* I believe this translates to "We lose" */
+ current->filename = next->filename = entry->filename;
+ current->line = next->line = -1;
+ current->sym = next->sym = (struct nlist *) 0;
+ return state_pointer;
+ }
+
+ next->line = source->line = 0;
+ next->filename = source->filename
+ = (tmp->n_un.n_strx + entry->strings);
+ source->sym = (struct nlist *) entry;
+ next->sym = tmp;
+
+ next_debug_entry (use_data_symbols, state_pointer); /* To setup next */
+
+ if (!next->sym) /* No line numbers for this section; */
+ /* setup output results as appropriate */
+ {
+ if (source->line)
+ {
+ current->filename = source->filename = entry->filename;
+ current->line = -1; /* Don't print lineno */
+ }
+ else
+ {
+ current->filename = source->filename;
+ current->line = 0;
+ }
+ return state_pointer;
+ }
+
+
+ next_debug_entry (use_data_symbols, state_pointer); /* To setup current */
+
+ return state_pointer;
+}
+
+/* Takes an ADDRESS (in either text or data space) and a STATE_POINTER
+ which describes the current location in the implied scan through
+ the debug symbols within the file which ADDRESS is within, and
+ returns the source line number which corresponds to ADDRESS. */
+
+int
+address_to_line (address, state_pointer)
+ unsigned long address;
+ /* Next must be passed by reference! */
+ struct line_debug_entry state_pointer[3];
+{
+ struct line_debug_entry
+ *current = state_pointer,
+ *next = state_pointer + 1;
+ struct line_debug_entry *tmp_pointer;
+
+ int use_data_symbols;
+
+ if (next->sym)
+ use_data_symbols = (next->sym->n_type & N_TYPE) == N_DATA;
+ else
+ return current->line;
+
+ /* Go back to the beginning if we've already passed it. */
+ if (current->sym->n_value > address)
+ {
+ tmp_pointer = init_debug_scan (use_data_symbols,
+ (struct file_entry *)
+ ((state_pointer + 2)->sym));
+ state_pointer[0] = tmp_pointer[0];
+ state_pointer[1] = tmp_pointer[1];
+ state_pointer[2] = tmp_pointer[2];
+ free (tmp_pointer);
+ }
+
+ /* If we're still in a bad way, return -1, meaning invalid line. */
+ if (current->sym->n_value > address)
+ return -1;
+
+ while (next->sym
+ && next->sym->n_value <= address
+ && next_debug_entry (use_data_symbols, state_pointer))
+ ;
+ return current->line;
+}
+
+
+/* Macros for manipulating bitvectors. */
+#define BIT_SET_P(bv, index) ((bv)[(index) >> 3] & 1 << ((index) & 0x7))
+#define SET_BIT(bv, index) ((bv)[(index) >> 3] |= 1 << ((index) & 0x7))
+
+/* This routine will scan through the relocation data of file ENTRY,
+ printing out references to undefined symbols and references to
+ symbols defined in files with N_WARNING symbols. If DATA_SEGMENT
+ is non-zero, it will scan the data relocation segment (and use
+ N_DSLINE symbols to track line number); otherwise it will scan the
+ text relocation segment. Warnings will be printed on the output
+ stream OUTFILE. Eventually, every nlist symbol mapped through will
+ be marked in the NLIST_BITVECTOR, so we don't repeat ourselves when
+ we scan the nlists themselves. */
+
+do_relocation_warnings (entry, data_segment, outfile, nlist_bitvector)
+ struct file_entry *entry;
+ int data_segment;
+ FILE *outfile;
+ unsigned char *nlist_bitvector;
+{
+ struct relocation_info
+ *reloc_start = data_segment ? entry->datarel : entry->textrel,
+ *reloc;
+ int reloc_size
+ = ((data_segment ? entry->header.a_drsize : entry->header.a_trsize)
+ / sizeof (struct relocation_info));
+ int start_of_segment
+ = (data_segment ? entry->data_start_address : entry->text_start_address);
+ struct nlist *start_of_syms = entry->symbols;
+ struct line_debug_entry *state_pointer
+ = init_debug_scan (data_segment != 0, entry);
+ register struct line_debug_entry
+ *current = state_pointer;
+ /* Assigned to generally static values; should not be written into. */
+ char *errfmt;
+ /* Assigned to alloca'd values cand copied into; should be freed
+ when done. */
+ char *errmsg;
+ int invalidate_line_number;
+
+ /* We need to sort the relocation info here. Sheesh, so much effort
+ for one lousy error optimization. */
+
+ qsort (reloc_start, reloc_size, sizeof (struct relocation_info),
+ relocation_entries_relation);
+
+ for (reloc = reloc_start;
+ reloc < (reloc_start + reloc_size);
+ reloc++)
+ {
+ register struct nlist *s;
+ register symbol *g;
+
+ /* If the relocation isn't resolved through a symbol, continue */
+ if (!RELOC_EXTERN_P(reloc))
+ continue;
+
+ s = &(entry->symbols[RELOC_SYMBOL(reloc)]);
+
+ /* Local symbols shouldn't ever be used by relocation info, so
+ the next should be safe.
+ This is, of course, wrong. References to local BSS symbols can be
+ the targets of relocation info, and they can (must) be
+ resolved through symbols. However, these must be defined properly,
+ (the assembler would have caught it otherwise), so we can
+ ignore these cases. */
+ if (!(s->n_type & N_EXT))
+ continue;
+
+ g = (symbol *) s->n_un.n_name;
+ errmsg = 0;
+
+ if (!g->defined && list_unresolved_refs) /* Reference */
+ {
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT (nlist_bitvector, s - start_of_syms);
+
+ if (g->undef_refs >= MAX_UREFS_PRINTED) /* Listed too many */
+ continue;
+
+ /* Undefined symbol which we should mention */
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED)
+ {
+ errfmt = "More undefined symbol %s refs follow";
+ invalidate_line_number = 1;
+ }
+ else
+ {
+ errfmt = "Undefined symbol %s referenced from %s segment";
+ invalidate_line_number = 0;
+ }
+ }
+ else /* Defined */
+ {
+ /* Potential symbol warning here */
+ if (!g->warning) continue;
+
+ /* Mark as being noted by relocation warning pass. */
+ SET_BIT (nlist_bitvector, s - start_of_syms);
+
+ errfmt = 0;
+ errmsg = g->warning;
+ invalidate_line_number = 0;
+ }
+
+
+ /* If errfmt == 0, errmsg has already been defined. */
+ if (errfmt != 0)
+ {
+ char *nm;
+
+ if (demangler == NULL || (nm = (*demangler)(g->name)) == NULL)
+ nm = g->name;
+ errmsg = (char *) xmalloc (strlen (errfmt) + strlen (nm) + 1);
+ sprintf (errmsg, errfmt, nm, data_segment ? "data" : "text");
+ if (nm != g->name)
+ free (nm);
+ }
+
+ address_to_line (RELOC_ADDRESS (reloc) + start_of_segment,
+ state_pointer);
+
+ if (current->line >=0)
+ fprintf (outfile, "%s:%d: %s\n", current->filename,
+ invalidate_line_number ? 0 : current->line, errmsg);
+ else
+ fprintf (outfile, "%s: %s\n", current->filename, errmsg);
+
+ if (errfmt != 0)
+ free (errmsg);
+ }
+
+ free (state_pointer);
+}
+
+/* Print on OUTFILE a list of all warnings generated by references
+ and/or definitions in the file ENTRY. List source file and line
+ number if possible, just the .o file if not. */
+
+void
+do_file_warnings (entry, outfile)
+ struct file_entry *entry;
+ FILE *outfile;
+{
+ int number_of_syms = entry->header.a_syms / sizeof (struct nlist);
+ unsigned char *nlist_bitvector
+ = (unsigned char *) alloca ((number_of_syms >> 3) + 1);
+ struct line_debug_entry *text_scan, *data_scan;
+ int i;
+ char *errfmt, *file_name;
+ int line_number;
+ int dont_allow_symbol_name;
+
+ bzero (nlist_bitvector, (number_of_syms >> 3) + 1);
+
+ /* Read in the files strings if they aren't available */
+ if (!entry->strings)
+ {
+ int desc;
+
+ entry->strings = (char *) alloca (entry->string_size);
+ desc = file_open (entry);
+ read_entry_strings (desc, entry);
+ }
+
+ read_file_relocation (entry);
+
+ /* Do text warnings based on a scan through the relocation info. */
+ do_relocation_warnings (entry, 0, outfile, nlist_bitvector);
+
+ /* Do data warnings based on a scan through the relocation info. */
+ do_relocation_warnings (entry, 1, outfile, nlist_bitvector);
+
+ /* Scan through all of the nlist entries in this file and pick up
+ anything that the scan through the relocation stuff didn't. */
+
+ text_scan = init_debug_scan (0, entry);
+ data_scan = init_debug_scan (1, entry);
+
+ for (i = 0; i < number_of_syms; i++)
+ {
+ struct nlist *s;
+ struct glosym *g;
+
+ s = entry->symbols + i;
+
+ if (!(s->n_type & N_EXT))
+ continue;
+
+ g = (symbol *) s->n_un.n_name;
+ dont_allow_symbol_name = 0;
+
+ if (list_multiple_defs && g->multiply_defined)
+ {
+ errfmt = "Definition of symbol %s (multiply defined)";
+ switch (s->n_type)
+ {
+ case N_TEXT | N_EXT:
+ line_number = address_to_line (s->n_value, text_scan);
+ file_name = text_scan[0].filename;
+ break;
+ case N_DATA | N_EXT:
+ line_number = address_to_line (s->n_value, data_scan);
+ file_name = data_scan[0].filename;
+ break;
+ case N_SETA | N_EXT:
+ case N_SETT | N_EXT:
+ case N_SETD | N_EXT:
+ case N_SETB | N_EXT:
+ if (g->multiply_defined == 2)
+ continue;
+ errfmt = "First set element definition of symbol %s (multiply defined)";
+ break;
+ default:
+ continue; /* Don't print out multiple defs
+ at references. */
+ }
+ }
+ else if (BIT_SET_P (nlist_bitvector, i))
+ continue;
+ else if (list_unresolved_refs && !g->defined)
+ {
+ if (g->undef_refs >= MAX_UREFS_PRINTED)
+ continue;
+
+ if (++(g->undef_refs) == MAX_UREFS_PRINTED)
+ errfmt = "More undefined \"%s\" refs follow";
+ else
+ errfmt = "Undefined symbol \"%s\" referenced";
+ line_number = -1;
+ }
+ else if (g->warning)
+ {
+ /* There are two cases in which we don't want to
+ do this. The first is if this is a definition instead of
+ a reference. The second is if it's the reference used by
+ the warning stabs itself. */
+ if (s->n_type != (N_EXT | N_UNDF)
+ || (i && (s-1)->n_type == N_WARNING))
+ continue;
+
+ errfmt = g->warning;
+ line_number = -1;
+ dont_allow_symbol_name = 1;
+ }
+ else
+ continue;
+
+ if (line_number == -1)
+ fprintf (outfile, "%s: ", entry->filename);
+ else
+ fprintf (outfile, "%s:%d: ", file_name, line_number);
+
+ if (dont_allow_symbol_name)
+ fprintf (outfile, "%s", errfmt);
+ else
+ {
+ char *nm;
+ if (demangler != NULL && (nm = (*demangler)(g->name)) != NULL)
+ {
+ fprintf (outfile, errfmt, nm);
+ free (nm);
+ }
+ else
+ fprintf (outfile, errfmt, g->name);
+ }
+
+ fputc ('\n', outfile);
+ }
+ free (text_scan);
+ free (data_scan);
+ entry->strings = 0; /* Since it will dissapear anyway. */
+}
+
+do_warnings (outfile)
+ FILE *outfile;
+{
+ list_unresolved_refs = !relocatable_output && undefined_global_sym_count;
+ list_warning_symbols = warning_count;
+ list_multiple_defs = multiple_def_count != 0;
+
+ if (!(list_unresolved_refs ||
+ list_warning_symbols ||
+ list_multiple_defs ))
+ /* No need to run this routine */
+ return;
+
+ each_file (do_file_warnings, outfile);
+
+ if (list_unresolved_refs || list_multiple_defs)
+ make_executable = 0;
+}
+
+/* Write the output file */
+
+void
+write_output ()
+{
+ struct stat statbuf;
+ int filemode;
+
+ (void) unlink (output_filename);
+ outdesc = open (output_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (outdesc < 0) perror_name (output_filename);
+
+ if (fstat (outdesc, &statbuf) < 0)
+ perror_name (output_filename);
+
+ (void) fchflags(outdesc, statbuf.st_flags | UF_NODUMP);
+
+ filemode = statbuf.st_mode;
+ (void) fchmod (outdesc, filemode & ~0111);
+
+ /* Output the a.out header. */
+ write_header ();
+
+ /* Output the text and data segments, relocating as we go. */
+ write_text ();
+ write_data ();
+
+ /* Output the merged relocation info, if requested with `-r'. */
+ if (relocatable_output)
+ write_rel ();
+
+ /* Output the symbol table (both globals and locals). */
+ write_syms ();
+
+ /* Copy any GDB symbol segments from input files. */
+ write_symsegs ();
+
+ if (fchmod (outdesc, filemode | 0111) == -1)
+ perror_name (output_filename);
+
+ close (outdesc);
+}
+
+void modify_location (), perform_relocation (), copy_text (), copy_data ();
+
+void
+write_header ()
+{
+ N_SET_MAGIC (outheader, magic);
+ outheader.a_text = text_size;
+#ifdef sequent
+ outheader.a_text += N_ADDRADJ (outheader);
+ if (entry_symbol == 0)
+ entry_symbol = getsym("start");
+#endif
+ outheader.a_data = data_size;
+ outheader.a_bss = bss_size;
+ outheader.a_entry = (entry_symbol ? entry_symbol->value
+ : text_start + entry_offset);
+#ifdef COFF_ENCAPSULATE
+ if (need_coff_header)
+ {
+ /* We are encapsulating BSD format within COFF format. */
+ struct coffscn *tp, *dp, *bp;
+
+ tp = &coffheader.scns[0];
+ dp = &coffheader.scns[1];
+ bp = &coffheader.scns[2];
+
+ strcpy (tp->s_name, ".text");
+ tp->s_paddr = text_start;
+ tp->s_vaddr = text_start;
+ tp->s_size = text_size;
+ tp->s_scnptr = sizeof (struct coffheader) + sizeof (struct exec);
+ tp->s_relptr = 0;
+ tp->s_lnnoptr = 0;
+ tp->s_nreloc = 0;
+ tp->s_nlnno = 0;
+ tp->s_flags = 0x20;
+ strcpy (dp->s_name, ".data");
+ dp->s_paddr = data_start;
+ dp->s_vaddr = data_start;
+ dp->s_size = data_size;
+ dp->s_scnptr = tp->s_scnptr + tp->s_size;
+ dp->s_relptr = 0;
+ dp->s_lnnoptr = 0;
+ dp->s_nreloc = 0;
+ dp->s_nlnno = 0;
+ dp->s_flags = 0x40;
+ strcpy (bp->s_name, ".bss");
+ bp->s_paddr = dp->s_vaddr + dp->s_size;
+ bp->s_vaddr = bp->s_paddr;
+ bp->s_size = bss_size;
+ bp->s_scnptr = 0;
+ bp->s_relptr = 0;
+ bp->s_lnnoptr = 0;
+ bp->s_nreloc = 0;
+ bp->s_nlnno = 0;
+ bp->s_flags = 0x80;
+
+ coffheader.f_magic = COFF_MAGIC;
+ coffheader.f_nscns = 3;
+ /* store an unlikely time so programs can
+ * tell that there is a bsd header
+ */
+ coffheader.f_timdat = 1;
+ coffheader.f_symptr = 0;
+ coffheader.f_nsyms = 0;
+ coffheader.f_opthdr = 28;
+ coffheader.f_flags = 0x103;
+ /* aouthdr */
+ coffheader.magic = ZMAGIC;
+ coffheader.vstamp = 0;
+ coffheader.tsize = tp->s_size;
+ coffheader.dsize = dp->s_size;
+ coffheader.bsize = bp->s_size;
+ coffheader.entry = outheader.a_entry;
+ coffheader.text_start = tp->s_vaddr;
+ coffheader.data_start = dp->s_vaddr;
+ }
+#endif
+
+#ifdef INITIALIZE_HEADER
+ INITIALIZE_HEADER;
+#endif
+
+ if (strip_symbols == STRIP_ALL)
+ nsyms = 0;
+ else
+ {
+ nsyms = (defined_global_sym_count
+ + undefined_global_sym_count);
+ if (discard_locals == DISCARD_L)
+ nsyms += non_L_local_sym_count;
+ else if (discard_locals == DISCARD_NONE)
+ nsyms += local_sym_count;
+ /* One extra for following reference on indirects */
+ if (relocatable_output)
+ nsyms += set_symbol_count + global_indirect_count;
+ }
+
+ if (strip_symbols == STRIP_NONE)
+ nsyms += debugger_sym_count;
+
+ outheader.a_syms = nsyms * sizeof (struct nlist);
+
+ if (relocatable_output)
+ {
+ outheader.a_trsize = text_reloc_size;
+ outheader.a_drsize = data_reloc_size;
+ }
+ else
+ {
+ outheader.a_trsize = 0;
+ outheader.a_drsize = 0;
+ }
+
+#ifdef COFF_ENCAPSULATE
+ if (need_coff_header)
+ mywrite (&coffheader, sizeof coffheader, 1, outdesc);
+#endif
+ mywrite (&outheader, sizeof (struct exec), 1, outdesc);
+
+ /* Output whatever padding is required in the executable file
+ between the header and the start of the text. */
+
+#ifndef COFF_ENCAPSULATE
+ padfile (N_TXTOFF (outheader) - sizeof outheader, outdesc);
+#endif
+}
+
+/* Relocate the text segment of each input file
+ and write to the output file. */
+
+void
+write_text ()
+{
+ if (trace_files)
+ fprintf (stderr, "Copying and relocating text:\n\n");
+
+ each_full_file (copy_text, 0);
+ file_close ();
+
+ if (trace_files)
+ fprintf (stderr, "\n");
+
+ padfile (text_pad, outdesc);
+}
+
+int
+text_offset (entry)
+ struct file_entry *entry;
+{
+ return entry->starting_offset + N_TXTOFF (entry->header);
+}
+
+/* Read in all of the relocation information */
+
+void
+read_relocation ()
+{
+ each_full_file (read_file_relocation, 0);
+}
+
+/* Read in the relocation sections of ENTRY if necessary */
+
+void
+read_file_relocation (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *reloc;
+ int desc;
+ int read_return;
+
+ desc = -1;
+ if (!entry->textrel)
+ {
+ reloc = (struct relocation_info *) xmalloc (entry->header.a_trsize);
+ desc = file_open (entry);
+ lseek (desc,
+ text_offset (entry) + entry->header.a_text + entry->header.a_data,
+ L_SET);
+ if (entry->header.a_trsize != (read_return = read (desc, reloc, entry->header.a_trsize)))
+ {
+ fprintf (stderr, "Return from read: %d\n", read_return);
+ fatal_with_file ("premature eof in text relocation of ", entry);
+ }
+ entry->textrel = reloc;
+ }
+
+ if (!entry->datarel)
+ {
+ reloc = (struct relocation_info *) xmalloc (entry->header.a_drsize);
+ if (desc == -1) desc = file_open (entry);
+ lseek (desc,
+ text_offset (entry) + entry->header.a_text
+ + entry->header.a_data + entry->header.a_trsize,
+ L_SET);
+ if (entry->header.a_drsize != read (desc, reloc, entry->header.a_drsize))
+ fatal_with_file ("premature eof in data relocation of ", entry);
+ entry->datarel = reloc;
+ }
+}
+
+/* Read the text segment contents of ENTRY, relocate them,
+ and write the result to the output file.
+ If `-r', save the text relocation for later reuse. */
+
+void
+copy_text (entry)
+ struct file_entry *entry;
+{
+ register char *bytes;
+ register int desc;
+ register struct relocation_info *reloc;
+
+ if (trace_files)
+ prline_file_name (entry, stderr);
+
+ desc = file_open (entry);
+
+ /* Allocate space for the file's text section */
+
+ bytes = (char *) alloca (entry->header.a_text);
+
+ /* Deal with relocation information however is appropriate */
+
+ if (entry->textrel) reloc = entry->textrel;
+ else if (relocatable_output)
+ {
+ read_file_relocation (entry);
+ reloc = entry->textrel;
+ }
+ else
+ {
+ reloc = (struct relocation_info *) alloca (entry->header.a_trsize);
+ lseek (desc, text_offset (entry) + entry->header.a_text + entry->header.a_data, 0);
+ if (entry->header.a_trsize != read (desc, reloc, entry->header.a_trsize))
+ fatal_with_file ("premature eof in text relocation of ", entry);
+ }
+
+ /* Read the text section into core. */
+
+ lseek (desc, text_offset (entry), 0);
+ if (entry->header.a_text != read (desc, bytes, entry->header.a_text))
+ fatal_with_file ("premature eof in text section of ", entry);
+
+
+ /* Relocate the text according to the text relocation. */
+
+ perform_relocation (bytes, entry->text_start_address, entry->header.a_text,
+ reloc, entry->header.a_trsize, entry);
+
+ /* Write the relocated text to the output file. */
+
+ mywrite (bytes, 1, entry->header.a_text, outdesc);
+}
+
+/* Relocate the data segment of each input file
+ and write to the output file. */
+
+void
+write_data ()
+{
+ if (trace_files)
+ fprintf (stderr, "Copying and relocating data:\n\n");
+
+ each_full_file (copy_data, 0);
+ file_close ();
+
+ /* Write out the set element vectors. See digest symbols for
+ description of length of the set vector section. */
+
+ if (set_vector_count)
+ mywrite (set_vectors, 2 * set_symbol_count + set_vector_count,
+ sizeof (unsigned long), outdesc);
+
+ if (trace_files)
+ fprintf (stderr, "\n");
+
+ padfile (data_pad, outdesc);
+}
+
+/* Read the data segment contents of ENTRY, relocate them,
+ and write the result to the output file.
+ If `-r', save the data relocation for later reuse.
+ See comments in `copy_text'. */
+
+void
+copy_data (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *reloc;
+ register char *bytes;
+ register int desc;
+
+ if (trace_files)
+ prline_file_name (entry, stderr);
+
+ desc = file_open (entry);
+
+ bytes = (char *) alloca (entry->header.a_data);
+
+ if (entry->datarel) reloc = entry->datarel;
+ else if (relocatable_output) /* Will need this again */
+ {
+ read_file_relocation (entry);
+ reloc = entry->datarel;
+ }
+ else
+ {
+ reloc = (struct relocation_info *) alloca (entry->header.a_drsize);
+ lseek (desc, text_offset (entry) + entry->header.a_text
+ + entry->header.a_data + entry->header.a_trsize,
+ 0);
+ if (entry->header.a_drsize != read (desc, reloc, entry->header.a_drsize))
+ fatal_with_file ("premature eof in data relocation of ", entry);
+ }
+
+ lseek (desc, text_offset (entry) + entry->header.a_text, 0);
+ if (entry->header.a_data != read (desc, bytes, entry->header.a_data))
+ fatal_with_file ("premature eof in data section of ", entry);
+
+ perform_relocation (bytes, entry->data_start_address - entry->header.a_text,
+ entry->header.a_data, reloc, entry->header.a_drsize, entry);
+
+ mywrite (bytes, 1, entry->header.a_data, outdesc);
+}
+
+/* Relocate ENTRY's text or data section contents.
+ DATA is the address of the contents, in core.
+ DATA_SIZE is the length of the contents.
+ PC_RELOCATION is the difference between the address of the contents
+ in the output file and its address in the input file.
+ RELOC_INFO is the address of the relocation info, in core.
+ RELOC_SIZE is its length in bytes. */
+/* This version is about to be severly hacked by Randy. Hope it
+ works afterwards. */
+void
+perform_relocation (data, pc_relocation, data_size, reloc_info, reloc_size, entry)
+ char *data;
+ struct relocation_info *reloc_info;
+ struct file_entry *entry;
+ int pc_relocation;
+ int data_size;
+ int reloc_size;
+{
+ register struct relocation_info *p = reloc_info;
+ struct relocation_info *end
+ = reloc_info + reloc_size / sizeof (struct relocation_info);
+ int text_relocation = entry->text_start_address;
+ int data_relocation = entry->data_start_address - entry->header.a_text;
+ int bss_relocation
+ = entry->bss_start_address - entry->header.a_text - entry->header.a_data;
+
+ for (; p < end; p++)
+ {
+ register int relocation = 0;
+ register int addr = RELOC_ADDRESS(p);
+ register unsigned int mask = 0;
+
+ if (addr >= data_size)
+ fatal_with_file ("relocation address out of range in ", entry);
+
+ if (RELOC_EXTERN_P(p))
+ {
+ int symindex = RELOC_SYMBOL (p) * sizeof (struct nlist);
+ symbol *sp = ((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name));
+
+#ifdef N_INDR
+ /* Resolve indirection */
+ if ((sp->defined & ~N_EXT) == N_INDR)
+ sp = (symbol *) sp->value;
+#endif
+
+ if (symindex >= entry->header.a_syms)
+ fatal_with_file ("relocation symbolnum out of range in ", entry);
+
+ /* If the symbol is undefined, leave it at zero. */
+ if (! sp->defined)
+ relocation = 0;
+ else
+ relocation = sp->value;
+ }
+ else switch (RELOC_TYPE(p))
+ {
+ case N_TEXT:
+ case N_TEXT | N_EXT:
+ relocation = text_relocation;
+ break;
+
+ case N_DATA:
+ case N_DATA | N_EXT:
+ /* A word that points to beginning of the the data section
+ initially contains not 0 but rather the "address" of that section
+ in the input file, which is the length of the file's text. */
+ relocation = data_relocation;
+ break;
+
+ case N_BSS:
+ case N_BSS | N_EXT:
+ /* Similarly, an input word pointing to the beginning of the bss
+ initially contains the length of text plus data of the file. */
+ relocation = bss_relocation;
+ break;
+
+ case N_ABS:
+ case N_ABS | N_EXT:
+ /* Don't know why this code would occur, but apparently it does. */
+ break;
+
+ default:
+ fatal_with_file ("nonexternal relocation code invalid in ", entry);
+ }
+
+#ifdef RELOC_ADD_EXTRA
+ relocation += RELOC_ADD_EXTRA(p);
+ if (relocatable_output)
+ {
+ /* Non-PC relative relocations which are absolute
+ or which have become non-external now have fixed
+ relocations. Set the ADD_EXTRA of this relocation
+ to be the relocation we have now determined. */
+ if (! RELOC_PCREL_P (p))
+ {
+ if ((int)p->r_type <= RELOC_32
+ || RELOC_EXTERN_P (p) == 0)
+ RELOC_ADD_EXTRA (p) = relocation;
+ }
+ /* External PC-relative relocations continue to move around;
+ update their relocations by the amount they have moved
+ so far. */
+ else if (RELOC_EXTERN_P (p))
+ RELOC_ADD_EXTRA (p) -= pc_relocation;
+ continue;
+ }
+#endif
+
+ if (RELOC_PCREL_P(p))
+ relocation -= pc_relocation;
+
+ relocation >>= RELOC_VALUE_RIGHTSHIFT(p);
+
+ /* Unshifted mask for relocation */
+ mask = 1 << RELOC_TARGET_BITSIZE(p) - 1;
+ mask |= mask - 1;
+ relocation &= mask;
+
+ /* Shift everything up to where it's going to be used */
+ relocation <<= RELOC_TARGET_BITPOS(p);
+ mask <<= RELOC_TARGET_BITPOS(p);
+
+ switch (RELOC_TARGET_SIZE(p))
+ {
+ case 0:
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= mask & *(char *) (data + addr);
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += mask & *(char *) (data + addr);
+ *(char *) (data + addr) &= ~mask;
+ *(char *) (data + addr) |= relocation;
+ break;
+
+ case 1:
+#ifdef tahoe
+ if (((int) data + addr & 1) == 0)
+ {
+#endif
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= mask & *(short *) (data + addr);
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += mask & *(short *) (data + addr);
+ *(short *) (data + addr) &= ~mask;
+ *(short *) (data + addr) |= relocation;
+#ifdef tahoe
+ }
+ /*
+ * The CCI Power 6 (aka Tahoe) architecture has byte-aligned
+ * instruction operands but requires data accesses to be aligned.
+ * Brain-damage...
+ */
+ else
+ {
+ unsigned char *da = (unsigned char *) (data + addr);
+ unsigned short s = da[0] << 8 | da[1];
+
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= mask & s;
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += mask & s;
+ s &= ~mask;
+ s |= relocation;
+ da[0] = s >> 8;
+ da[1] = s;
+ }
+#endif
+ break;
+
+ case 2:
+#ifndef _CROSS_TARGET_ARCH
+#ifdef tahoe
+ if (((int) data + addr & 3) == 0)
+ {
+#endif
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= mask & *(long *) (data + addr);
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += mask & *(long *) (data + addr);
+ *(long *) (data + addr) &= ~mask;
+ *(long *) (data + addr) |= relocation;
+#ifdef tahoe
+ }
+ else
+ {
+ unsigned char *da = (unsigned char *) (data + addr);
+ unsigned long l = da[0] << 24 | da[1] << 16 | da[2] << 8 | da[3];
+
+ if (RELOC_MEMORY_SUB_P(p))
+ relocation -= mask & l;
+ else if (RELOC_MEMORY_ADD_P(p))
+ relocation += mask & l;
+ l &= ~mask;
+ l |= relocation;
+ da[0] = l >> 24;
+ da[1] = l >> 16;
+ da[2] = l >> 8;
+ da[3] = l;
+ }
+#endif
+#else
+ /* Handle long word alignment requirements of SPARC architecture */
+ /* WARNING: This fix makes an assumption on byte ordering */
+ /* Marc Ullman, Stanford University Nov. 1 1989 */
+ if (RELOC_MEMORY_SUB_P(p)) {
+ relocation -= mask &
+ ((*(unsigned short *) (data + addr) << 16) |
+ *(unsigned short *) (data + addr + 2));
+ } else if (RELOC_MEMORY_ADD_P(p)) {
+ relocation += mask &
+ ((*(unsigned short *) (data + addr) << 16) |
+ *(unsigned short *) (data + addr + 2));
+ }
+ *(unsigned short *) (data + addr) &= (~mask >> 16);
+ *(unsigned short *) (data + addr + 2) &= (~mask & 0xffff);
+ *(unsigned short *) (data + addr) |= (relocation >> 16);
+ *(unsigned short *) (data + addr + 2) |= (relocation & 0xffff);
+#endif
+ break;
+
+ default:
+ fatal_with_file ("Unimplemented relocation field length in ", entry);
+ }
+ }
+}
+
+/* For relocatable_output only: write out the relocation,
+ relocating the addresses-to-be-relocated. */
+
+void coptxtrel (), copdatrel ();
+
+void
+write_rel ()
+{
+ register int i;
+ register int count = 0;
+
+ if (trace_files)
+ fprintf (stderr, "Writing text relocation:\n\n");
+
+ /* Assign each global symbol a sequence number, giving the order
+ in which `write_syms' will write it.
+ This is so we can store the proper symbolnum fields
+ in relocation entries we write. */
+
+ for (i = 0; i < TABSIZE; i++)
+ {
+ symbol *sp;
+ for (sp = symtab[i]; sp; sp = sp->link)
+ if (sp->referenced || sp->defined)
+ {
+ sp->def_count = count++;
+ /* Leave room for the reference required by N_INDR, if
+ necessary. */
+ if ((sp->defined & ~N_EXT) == N_INDR)
+ count++;
+ }
+ }
+ /* Correct, because if (relocatable_output), we will also be writing
+ whatever indirect blocks we have. */
+ if (count != defined_global_sym_count
+ + undefined_global_sym_count + global_indirect_count)
+ fatal ("internal error");
+
+ /* Write out the relocations of all files, remembered from copy_text. */
+
+ each_full_file (coptxtrel, 0);
+
+ if (trace_files)
+ fprintf (stderr, "\nWriting data relocation:\n\n");
+
+ each_full_file (copdatrel, 0);
+
+ if (trace_files)
+ fprintf (stderr, "\n");
+}
+
+void
+coptxtrel (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *p, *end;
+ register int reloc = entry->text_start_address;
+
+ p = entry->textrel;
+ end = (struct relocation_info *) (entry->header.a_trsize + (char *) p);
+ while (p < end)
+ {
+ RELOC_ADDRESS(p) += reloc;
+ if (RELOC_EXTERN_P(p))
+ {
+ register int symindex = RELOC_SYMBOL(p) * sizeof (struct nlist);
+ symbol *symptr = ((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name));
+
+ if (symindex >= entry->header.a_syms)
+ fatal_with_file ("relocation symbolnum out of range in ", entry);
+
+#ifdef N_INDR
+ /* Resolve indirection. */
+ if ((symptr->defined & ~N_EXT) == N_INDR)
+ symptr = (symbol *) symptr->value;
+#endif
+
+ /* If the symbol is now defined, change the external relocation
+ to an internal one. */
+
+ if (symptr->defined)
+ {
+ RELOC_EXTERN_P(p) = 0;
+ RELOC_SYMBOL(p) = (symptr->defined & N_TYPE);
+#ifdef RELOC_ADD_EXTRA
+ /* If we aren't going to be adding in the value in
+ memory on the next pass of the loader, then we need
+ to add it in from the relocation entry. Otherwise
+ the work we did in this pass is lost. */
+ if (!RELOC_MEMORY_ADD_P(p))
+ RELOC_ADD_EXTRA (p) += symptr->value;
+#endif
+ }
+ else
+ /* Debugger symbols come first, so have to start this
+ after them. */
+ RELOC_SYMBOL(p) = (symptr->def_count + nsyms
+ - defined_global_sym_count
+ - undefined_global_sym_count
+ - global_indirect_count);
+ }
+ p++;
+ }
+ mywrite (entry->textrel, 1, entry->header.a_trsize, outdesc);
+}
+
+void
+copdatrel (entry)
+ struct file_entry *entry;
+{
+ register struct relocation_info *p, *end;
+ /* Relocate the address of the relocation.
+ Old address is relative to start of the input file's data section.
+ New address is relative to start of the output file's data section. */
+ register int reloc = entry->data_start_address - text_size;
+
+ p = entry->datarel;
+ end = (struct relocation_info *) (entry->header.a_drsize + (char *) p);
+ while (p < end)
+ {
+ RELOC_ADDRESS(p) += reloc;
+ if (RELOC_EXTERN_P(p))
+ {
+ register int symindex = RELOC_SYMBOL(p) * sizeof (struct nlist);
+ symbol *symptr = ((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name));
+ int symtype;
+
+ if (symindex >= entry->header.a_syms)
+ fatal_with_file ("relocation symbolnum out of range in ", entry);
+
+#ifdef N_INDR
+ /* Resolve indirection. */
+ if ((symptr->defined & ~N_EXT) == N_INDR)
+ symptr = (symbol *) symptr->value;
+#endif
+
+ symtype = symptr->defined & N_TYPE;
+
+ if (force_common_definition
+ || symtype == N_DATA || symtype == N_TEXT || symtype == N_ABS)
+ {
+ RELOC_EXTERN_P(p) = 0;
+ RELOC_SYMBOL(p) = symtype;
+ }
+ else
+ /* Debugger symbols come first, so have to start this
+ after them. */
+ RELOC_SYMBOL(p)
+ = (((symbol *)
+ (((struct nlist *)
+ (((char *)entry->symbols) + symindex))
+ ->n_un.n_name))
+ ->def_count
+ + nsyms - defined_global_sym_count
+ - undefined_global_sym_count
+ - global_indirect_count);
+ }
+ p++;
+ }
+ mywrite (entry->datarel, 1, entry->header.a_drsize, outdesc);
+}
+
+void write_file_syms ();
+void write_string_table ();
+
+/* Offsets and current lengths of symbol and string tables in output file. */
+
+int symbol_table_offset;
+int symbol_table_len;
+
+/* Address in output file where string table starts. */
+int string_table_offset;
+
+/* Offset within string table
+ where the strings in `strtab_vector' should be written. */
+int string_table_len;
+
+/* Total size of string table strings allocated so far,
+ including strings in `strtab_vector'. */
+int strtab_size;
+
+/* Vector whose elements are strings to be added to the string table. */
+char **strtab_vector;
+
+/* Vector whose elements are the lengths of those strings. */
+int *strtab_lens;
+
+/* Index in `strtab_vector' at which the next string will be stored. */
+int strtab_index;
+
+/* Add the string NAME to the output file string table.
+ Record it in `strtab_vector' to be output later.
+ Return the index within the string table that this string will have. */
+
+int
+assign_string_table_index (name)
+ char *name;
+{
+ register int index = strtab_size;
+ register int len = strlen (name) + 1;
+
+ strtab_size += len;
+ strtab_vector[strtab_index] = name;
+ strtab_lens[strtab_index++] = len;
+
+ return index;
+}
+
+FILE *outstream = (FILE *) 0;
+
+/* Write the contents of `strtab_vector' into the string table.
+ This is done once for each file's local&debugger symbols
+ and once for the global symbols. */
+
+void
+write_string_table ()
+{
+ register int i;
+
+ lseek (outdesc, string_table_offset + string_table_len, 0);
+
+ if (!outstream)
+ outstream = fdopen (outdesc, "w");
+
+ for (i = 0; i < strtab_index; i++)
+ {
+ fwrite (strtab_vector[i], 1, strtab_lens[i], outstream);
+ string_table_len += strtab_lens[i];
+ }
+
+ fflush (outstream);
+
+ /* Report I/O error such as disk full. */
+ if (ferror (outstream))
+ perror_name (output_filename);
+}
+
+/* Write the symbol table and string table of the output file. */
+
+void
+write_syms ()
+{
+ /* Number of symbols written so far. */
+ int syms_written = 0;
+ register int i;
+ register symbol *sp;
+
+ /* Buffer big enough for all the global symbols. One
+ extra struct for each indirect symbol to hold the extra reference
+ following. */
+ struct nlist *buf
+ = (struct nlist *) alloca ((defined_global_sym_count
+ + undefined_global_sym_count
+ + global_indirect_count)
+ * sizeof (struct nlist));
+ /* Pointer for storing into BUF. */
+ register struct nlist *bufp = buf;
+
+ /* Size of string table includes the bytes that store the size. */
+ strtab_size = sizeof strtab_size;
+
+ symbol_table_offset = N_SYMOFF (outheader);
+ symbol_table_len = 0;
+ string_table_offset = N_STROFF (outheader);
+ string_table_len = strtab_size;
+
+ if (strip_symbols == STRIP_ALL)
+ return;
+
+ /* Write the local symbols defined by the various files. */
+
+ each_file (write_file_syms, &syms_written);
+ file_close ();
+
+ /* Now write out the global symbols. */
+
+ /* Allocate two vectors that record the data to generate the string
+ table from the global symbols written so far. This must include
+ extra space for the references following indirect outputs. */
+
+ strtab_vector = (char **) alloca ((num_hash_tab_syms
+ + global_indirect_count) * sizeof (char *));
+ strtab_lens = (int *) alloca ((num_hash_tab_syms
+ + global_indirect_count) * sizeof (int));
+ strtab_index = 0;
+
+ /* Scan the symbol hash table, bucket by bucket. */
+
+ for (i = 0; i < TABSIZE; i++)
+ for (sp = symtab[i]; sp; sp = sp->link)
+ {
+ struct nlist nl;
+
+ nl.n_other = 0;
+ nl.n_desc = 0;
+
+ /* Compute a `struct nlist' for the symbol. */
+
+ if (sp->defined || sp->referenced)
+ {
+ /* common condition needs to be before undefined condition */
+ /* because unallocated commons are set undefined in */
+ /* digest_symbols */
+ if (sp->defined > 1) /* defined with known type */
+ {
+ /* If the target of an indirect symbol has been
+ defined and we are outputting an executable,
+ resolve the indirection; it's no longer needed */
+ if (!relocatable_output
+ && ((sp->defined & N_TYPE) == N_INDR)
+ && (((symbol *) sp->value)->defined > 1))
+ {
+ symbol *newsp = (symbol *) sp->value;
+ nl.n_type = newsp->defined;
+ nl.n_value = newsp->value;
+ }
+ else
+ {
+ nl.n_type = sp->defined;
+ if (sp->defined != (N_INDR | N_EXT))
+ nl.n_value = sp->value;
+ else
+ nl.n_value = 0;
+ }
+ }
+ else if (sp->max_common_size) /* defined as common but not allocated. */
+ {
+ /* happens only with -r and not -d */
+ /* write out a common definition */
+ nl.n_type = N_UNDF | N_EXT;
+ nl.n_value = sp->max_common_size;
+ }
+ else if (!sp->defined) /* undefined -- legit only if -r */
+ {
+ nl.n_type = N_UNDF | N_EXT;
+ nl.n_value = 0;
+ }
+ else
+ fatal ("internal error: %s defined in mysterious way", sp->name);
+
+ /* Allocate string table space for the symbol name. */
+
+ nl.n_un.n_strx = assign_string_table_index (sp->name);
+
+ /* Output to the buffer and count it. */
+
+ *bufp++ = nl;
+ syms_written++;
+ if (nl.n_type == (N_INDR | N_EXT))
+ {
+ struct nlist xtra_ref;
+ xtra_ref.n_type = N_EXT | N_UNDF;
+ xtra_ref.n_un.n_strx
+ = assign_string_table_index (((symbol *) sp->value)->name);
+ xtra_ref.n_other = 0;
+ xtra_ref.n_desc = 0;
+ xtra_ref.n_value = 0;
+ *bufp++ = xtra_ref;
+ syms_written++;
+ }
+ }
+ }
+
+ /* Output the buffer full of `struct nlist's. */
+
+ lseek (outdesc, symbol_table_offset + symbol_table_len, 0);
+ mywrite (buf, sizeof (struct nlist), bufp - buf, outdesc);
+ symbol_table_len += sizeof (struct nlist) * (bufp - buf);
+
+ if (syms_written != nsyms)
+ fatal ("internal error: wrong number of symbols written into output file", 0);
+
+ if (symbol_table_offset + symbol_table_len != string_table_offset)
+ fatal ("internal error: inconsistent symbol table length", 0);
+
+ /* Now the total string table size is known, so write it.
+ We are already positioned at the right place in the file. */
+
+ mywrite (&strtab_size, sizeof (int), 1, outdesc); /* we're at right place */
+
+ /* Write the strings for the global symbols. */
+
+ write_string_table ();
+}
+
+/* Write the local and debugger symbols of file ENTRY.
+ Increment *SYMS_WRITTEN_ADDR for each symbol that is written. */
+
+/* Note that we do not combine identical names of local symbols.
+ dbx or gdb would be confused if we did that. */
+
+void
+write_file_syms (entry, syms_written_addr)
+ struct file_entry *entry;
+ int *syms_written_addr;
+{
+ register struct nlist *p = entry->symbols;
+ register struct nlist *end = p + entry->header.a_syms / sizeof (struct nlist);
+
+ /* Buffer to accumulate all the syms before writing them.
+ It has one extra slot for the local symbol we generate here. */
+ struct nlist *buf
+ = (struct nlist *) alloca (entry->header.a_syms + sizeof (struct nlist));
+ register struct nlist *bufp = buf;
+
+ /* Upper bound on number of syms to be written here. */
+ int max_syms = (entry->header.a_syms / sizeof (struct nlist)) + 1;
+
+ /* Make tables that record, for each symbol, its name and its name's length.
+ The elements are filled in by `assign_string_table_index'. */
+
+ strtab_vector = (char **) alloca (max_syms * sizeof (char *));
+ strtab_lens = (int *) alloca (max_syms * sizeof (int));
+ strtab_index = 0;
+
+ /* Generate a local symbol for the start of this file's text. */
+
+ if (discard_locals != DISCARD_ALL)
+ {
+ struct nlist nl;
+
+ nl.n_type = N_FN | N_EXT;
+ nl.n_un.n_strx = assign_string_table_index (entry->local_sym_name);
+ nl.n_value = entry->text_start_address;
+ nl.n_desc = 0;
+ nl.n_other = 0;
+ *bufp++ = nl;
+ (*syms_written_addr)++;
+ entry->local_syms_offset = *syms_written_addr * sizeof (struct nlist);
+ }
+
+ /* Read the file's string table. */
+
+ entry->strings = (char *) alloca (entry->string_size);
+ read_entry_strings (file_open (entry), entry);
+
+ for (; p < end; p++)
+ {
+ register int type = p->n_type;
+ register int write = 0;
+
+ /* WRITE gets 1 for a non-global symbol that should be written. */
+
+
+ if (SET_ELEMENT_P (type)) /* This occurs even if global. These */
+ /* types of symbols are never written */
+ /* globally, though they are stored */
+ /* globally. */
+ write = relocatable_output;
+ else if (!(type & (N_STAB | N_EXT)))
+ /* ordinary local symbol */
+ write = ((discard_locals != DISCARD_ALL)
+ && !(discard_locals == DISCARD_L &&
+ (p->n_un.n_strx + entry->strings)[0] == LPREFIX)
+ && type != N_WARNING);
+ else if (!(type & N_EXT))
+ /* debugger symbol */
+ write = (strip_symbols == STRIP_NONE);
+
+ if (write)
+ {
+ /* If this symbol has a name,
+ allocate space for it in the output string table. */
+
+ if (p->n_un.n_strx)
+ p->n_un.n_strx = assign_string_table_index (p->n_un.n_strx
+ + entry->strings);
+
+ /* Output this symbol to the buffer and count it. */
+
+ *bufp++ = *p;
+ (*syms_written_addr)++;
+ }
+ }
+
+ /* All the symbols are now in BUF; write them. */
+
+ lseek (outdesc, symbol_table_offset + symbol_table_len, 0);
+ mywrite (buf, sizeof (struct nlist), bufp - buf, outdesc);
+ symbol_table_len += sizeof (struct nlist) * (bufp - buf);
+
+ /* Write the string-table data for the symbols just written,
+ using the data in vectors `strtab_vector' and `strtab_lens'. */
+
+ write_string_table ();
+ entry->strings = 0; /* Since it will dissapear anyway. */
+}
+
+/* Copy any GDB symbol segments from the input files to the output file.
+ The contents of the symbol segment is copied without change
+ except that we store some information into the beginning of it. */
+
+void write_file_symseg ();
+
+void
+write_symsegs ()
+{
+ each_file (write_file_symseg, 0);
+}
+
+void
+write_file_symseg (entry)
+ struct file_entry *entry;
+{
+ char buffer[4096];
+ struct symbol_root root;
+ int indesc;
+ int len;
+
+ if (entry->symseg_offset == 0)
+ return;
+
+ /* This entry has a symbol segment. Read the root of the segment. */
+
+ indesc = file_open (entry);
+ lseek (indesc, entry->symseg_offset + entry->starting_offset, 0);
+ if (sizeof root != read (indesc, &root, sizeof root))
+ fatal_with_file ("premature end of file in symbol segment of ", entry);
+
+ /* Store some relocation info into the root. */
+
+ root.ldsymoff = entry->local_syms_offset;
+ root.textrel = entry->text_start_address;
+ root.datarel = entry->data_start_address - entry->header.a_text;
+ root.bssrel = entry->bss_start_address
+ - entry->header.a_text - entry->header.a_data;
+ root.databeg = entry->data_start_address - root.datarel;
+ root.bssbeg = entry->bss_start_address - root.bssrel;
+
+ /* Write the modified root into the output file. */
+
+ mywrite (&root, sizeof root, 1, outdesc);
+
+ /* Copy the rest of the symbol segment unchanged. */
+
+ if (entry->superfile)
+ {
+ /* Library member: number of bytes to copy is determined
+ from the member's total size. */
+
+ int total = entry->total_size - entry->symseg_offset - sizeof root;
+
+ while (total > 0)
+ {
+ len = read (indesc, buffer, min (sizeof buffer, total));
+
+ if (len != min (sizeof buffer, total))
+ fatal_with_file ("premature end of file in symbol segment of ", entry);
+ total -= len;
+ mywrite (buffer, len, 1, outdesc);
+ }
+ }
+ else
+ {
+ /* A separate file: copy until end of file. */
+
+ while (len = read (indesc, buffer, sizeof buffer))
+ {
+ mywrite (buffer, len, 1, outdesc);
+ if (len < sizeof buffer)
+ break;
+ }
+ }
+
+ file_close ();
+}
+
+/* Create the symbol table entries for `etext', `edata' and `end'. */
+
+void
+symtab_init ()
+{
+#ifndef nounderscore
+ edata_symbol = getsym ("_edata");
+ etext_symbol = getsym ("_etext");
+ end_symbol = getsym ("_end");
+#else
+ edata_symbol = getsym ("edata");
+ etext_symbol = getsym ("etext");
+ end_symbol = getsym ("end");
+#endif
+
+#ifdef sun
+ {
+ symbol *dynamic_symbol = getsym ("__DYNAMIC");
+ dynamic_symbol->defined = N_ABS | N_EXT;
+ dynamic_symbol->referenced = 1;
+ dynamic_symbol->value = 0;
+ }
+#endif
+
+#ifdef sequent
+ {
+ symbol *_387_flt_symbol = getsym ("_387_flt");
+ _387_flt_symbol->defined = N_ABS | N_EXT;
+ _387_flt_symbol->referenced = 1;
+ _387_flt_symbol->value = 0;
+ }
+#endif
+
+ edata_symbol->defined = N_DATA | N_EXT;
+ etext_symbol->defined = N_TEXT | N_EXT;
+ end_symbol->defined = N_BSS | N_EXT;
+
+ edata_symbol->referenced = 1;
+ etext_symbol->referenced = 1;
+ end_symbol->referenced = 1;
+}
+
+/* Compute the hash code for symbol name KEY. */
+
+int
+hash_string (key)
+ char *key;
+{
+ register char *cp;
+ register int k;
+
+ cp = key;
+ k = 0;
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ return k;
+}
+
+/* Get the symbol table entry for the global symbol named KEY.
+ Create one if there is none. */
+
+symbol *
+getsym (key)
+ char *key;
+{
+ register int hashval;
+ register symbol *bp;
+
+ /* Determine the proper bucket. */
+
+ hashval = hash_string (key) % TABSIZE;
+
+ /* Search the bucket. */
+
+ for (bp = symtab[hashval]; bp; bp = bp->link)
+ if (! strcmp (key, bp->name))
+ return bp;
+
+ /* Nothing was found; create a new symbol table entry. */
+
+ bp = (symbol *) xmalloc (sizeof (symbol));
+ bp->refs = 0;
+ bp->name = (char *) xmalloc (strlen (key) + 1);
+ strcpy (bp->name, key);
+ bp->defined = 0;
+ bp->referenced = 0;
+ bp->trace = 0;
+ bp->value = 0;
+ bp->max_common_size = 0;
+ bp->warning = 0;
+ bp->undef_refs = 0;
+ bp->multiply_defined = 0;
+
+ /* Add the entry to the bucket. */
+
+ bp->link = symtab[hashval];
+ symtab[hashval] = bp;
+
+ ++num_hash_tab_syms;
+
+ return bp;
+}
+
+/* Like `getsym' but return 0 if the symbol is not already known. */
+
+symbol *
+getsym_soft (key)
+ char *key;
+{
+ register int hashval;
+ register symbol *bp;
+
+ /* Determine which bucket. */
+
+ hashval = hash_string (key) % TABSIZE;
+
+ /* Search the bucket. */
+
+ for (bp = symtab[hashval]; bp; bp = bp->link)
+ if (! strcmp (key, bp->name))
+ return bp;
+
+ return 0;
+}
+
+/* Report a fatal error.
+ STRING is a printf format string and ARG is one arg for it. */
+
+void
+fatal (string, arg)
+ char *string, *arg;
+{
+ fprintf (stderr, "ld: ");
+ fprintf (stderr, string, arg);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Report a fatal error. The error message is STRING
+ followed by the filename of ENTRY. */
+
+void
+fatal_with_file (string, entry)
+ char *string;
+ struct file_entry *entry;
+{
+ fprintf (stderr, "ld: ");
+ fprintf (stderr, string);
+ print_file_name (entry, stderr);
+ fprintf (stderr, "\n");
+ exit (1);
+}
+
+/* Report a fatal error using the message for the last failed system call,
+ followed by the string NAME. */
+
+void
+perror_name (name)
+ char *name;
+{
+ extern int errno;
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for %s");
+ else
+ s = "cannot open %s";
+ fatal (s, name);
+}
+
+/* Report a fatal error using the message for the last failed system call,
+ followed by the name of file ENTRY. */
+
+void
+perror_file (entry)
+ struct file_entry *entry;
+{
+ extern int errno;
+ char *s;
+
+ if (errno < sys_nerr)
+ s = concat ("", sys_errlist[errno], " for ");
+ else
+ s = "cannot open ";
+ fatal_with_file (s, entry);
+}
+
+/* Report a nonfatal error.
+ STRING is a format for printf, and ARG1 ... ARG3 are args for it. */
+
+void
+error (string, arg1, arg2, arg3)
+ char *string, *arg1, *arg2, *arg3;
+{
+ fprintf (stderr, "%s: ", progname);
+ fprintf (stderr, string, arg1, arg2, arg3);
+ fprintf (stderr, "\n");
+}
+
+
+/* Output COUNT*ELTSIZE bytes of data at BUF
+ to the descriptor DESC. */
+
+void
+mywrite (buf, count, eltsize, desc)
+ char *buf;
+ int count;
+ int eltsize;
+ int desc;
+{
+ register int val;
+ register int bytes = count * eltsize;
+
+ while (bytes > 0)
+ {
+ val = write (desc, buf, bytes);
+ if (val <= 0)
+ perror_name (output_filename);
+ buf += val;
+ bytes -= val;
+ }
+}
+
+/* Output PADDING zero-bytes to descriptor OUTDESC.
+ PADDING may be negative; in that case, do nothing. */
+
+void
+padfile (padding, outdesc)
+ int padding;
+ int outdesc;
+{
+ register char *buf;
+ if (padding <= 0)
+ return;
+
+ buf = (char *) alloca (padding);
+ bzero (buf, padding);
+ mywrite (buf, padding, 1, outdesc);
+}
+
+/* Return a newly-allocated string
+ whose contents concatenate the strings S1, S2, S3. */
+
+char *
+concat (s1, s2, s3)
+ char *s1, *s2, *s3;
+{
+ register int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ register char *result = (char *) xmalloc (len1 + len2 + len3 + 1);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ result[len1 + len2 + len3] = 0;
+
+ return result;
+}
+
+/* Parse the string ARG using scanf format FORMAT, and return the result.
+ If it does not parse, report fatal error
+ generating the error message using format string ERROR and ARG as arg. */
+
+int
+parse (arg, format, error)
+ char *arg, *format;
+{
+ int x;
+ if (1 != sscanf (arg, format, &x))
+ fatal (error, arg);
+ return x;
+}
+
+/* Like malloc but get fatal error if memory is exhausted. */
+
+int
+xmalloc (size)
+ int size;
+{
+ register int result = malloc (size);
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+/* Like realloc but get fatal error if memory is exhausted. */
+
+int
+xrealloc (ptr, size)
+ char *ptr;
+ int size;
+{
+ register int result = realloc (ptr, size);
+ if (!result)
+ fatal ("virtual memory exhausted", 0);
+ return result;
+}
+
+#ifdef USG
+
+void
+bzero (p, n)
+ char *p;
+{
+ memset (p, 0, n);
+}
+
+void
+bcopy (from, to, n)
+ char *from, *to;
+{
+ memcpy (to, from, n);
+}
+
+getpagesize ()
+{
+ return (4096);
+}
+
+#endif
+
+#if defined(sun) && (TARGET == SUN4)
+
+/* Don't use local pagesize to build for Sparc. */
+
+getpagesize ()
+{
+ return (8192);
+}
+#endif
diff --git a/usr.bin/ld/symseg.h b/usr.bin/ld/symseg.h
new file mode 100644
index 0000000..978d8be
--- /dev/null
+++ b/usr.bin/ld/symseg.h
@@ -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 */
+};
diff --git a/usr.bin/locate/bigram/locate.bigram.c b/usr.bin/locate/bigram/locate.bigram.c
index b58fac4..fc0cbb7 100644
--- a/usr.bin/locate/bigram/locate.bigram.c
+++ b/usr.bin/locate/bigram/locate.bigram.c
@@ -41,7 +41,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)locate.bigram.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)locate.bigram.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
/*
@@ -66,12 +66,12 @@ main ( )
/* skip longest common prefix */
for ( cp = path; *cp == *oldpath; cp++, oldpath++ )
- if ( *oldpath == NULL )
+ if ( *oldpath == '\0' )
break;
/*
* output post-residue bigrams only
*/
- while ( *cp != NULL && *(cp + 1) != NULL ) {
+ while ( *cp != '\0' && *(cp + 1) != '\0' ) {
putchar ( *cp++ );
putchar ( *cp++ );
putchar ( '\n' );
@@ -81,4 +81,5 @@ main ( )
else
path = buf1, oldpath = buf2;
}
+ return (0);
}
diff --git a/usr.bin/locate/code/locate.code.c b/usr.bin/locate/code/locate.code.c
index d3ec29f..5561dea 100644
--- a/usr.bin/locate/code/locate.code.c
+++ b/usr.bin/locate/code/locate.code.c
@@ -41,7 +41,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)locate.code.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)locate.code.c 8.4 (Berkeley) 5/4/95";
#endif /* not lint */
/*
@@ -80,11 +80,14 @@ static char sccsid[] = "@(#)locate.code.c 8.1 (Berkeley) 6/6/93";
*/
#include <sys/param.h>
+
#include <err.h>
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
+#include <unistd.h>
+
#include "locate.h"
#define BGBUFSIZE (NBG * 2) /* size of bigram buffer */
@@ -136,16 +139,14 @@ main(argc, argv)
*cp = '\0';
/* Squelch characters that would botch the decoding. */
- for (cp = path; *cp != NULL; cp++) {
- if ((u_char)*cp >= PARITY)
- *cp &= PARITY-1;
- else if (*cp <= SWITCH)
+ for (cp = path; *cp != '\0'; cp++) {
+ if ((u_char)*cp >= PARITY || *cp <= SWITCH)
*cp = '?';
}
/* Skip longest common prefix. */
for (cp = path; *cp == *oldpath; cp++, oldpath++)
- if (*oldpath == NULL)
+ if (*oldpath == '\0')
break;
count = cp - path;
diffcount = count - oldcount + OFFSET;
@@ -158,8 +159,8 @@ main(argc, argv)
if (putchar(diffcount) == EOF)
err(1, "stdout");
- while (*cp != NULL) {
- if (*(cp + 1) == NULL) {
+ while (*cp != '\0') {
+ if (*(cp + 1) == '\0') {
if (putchar(*cp) == EOF)
err(1, "stdout");
break;
@@ -197,10 +198,10 @@ bgindex(bg) /* Return location of bg in bigrams or -1. */
bg0 = bg[0];
bg1 = bg[1];
- for (p = bigrams; *p != NULL; p++)
+ for (p = bigrams; *p != '\0'; p++)
if (*p++ == bg0 && *p == bg1)
break;
- return (*p == NULL ? -1 : --p - bigrams);
+ return (*p == '\0' ? -1 : --p - bigrams);
}
void
diff --git a/usr.bin/locate/locate/updatedb.csh b/usr.bin/locate/locate/updatedb.csh
index 574d52a..bca8bab 100644
--- a/usr.bin/locate/locate/updatedb.csh
+++ b/usr.bin/locate/locate/updatedb.csh
@@ -34,13 +34,13 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
-# @(#)updatedb.csh 8.3 (Berkeley) 3/19/94
+# @(#)updatedb.csh 8.4 (Berkeley) 10/27/94
#
set SRCHPATHS = "/" # directories to be put in the database
set LIBDIR = /usr/libexec # for subprograms
# for temp files
-if (! $?TMPDIR) setenv TMPDIR = /var/tmp
+if (! $?TMPDIR) setenv TMPDIR /var/tmp
set FCODES = /var/db/locate.database # the database
set path = ( /bin /usr/bin )
diff --git a/usr.bin/login/login.1 b/usr.bin/login/login.1
index db59c1a..6c78b23 100644
--- a/usr.bin/login/login.1
+++ b/usr.bin/login/login.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)login.1 8.1 (Berkeley) 6/9/93
+.\" @(#)login.1 8.2 (Berkeley) 5/5/94
.\"
-.Dd June 9, 1993
+.Dd May 5, 1994
.Dt LOGIN 1
.Os BSD 4
.Sh NAME
@@ -125,6 +125,8 @@ message-of-the-day
disallows logins
.It Pa /var/run/utmp
current logins
+.It Pa /var/log/lastlog
+last login account records
.It Pa /var/log/wtmp
login account records
.It Pa /var/mail/user
diff --git a/usr.bin/lorder/lorder.1 b/usr.bin/lorder/lorder.1
index b5bfd57..387481f 100644
--- a/usr.bin/lorder/lorder.1
+++ b/usr.bin/lorder/lorder.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)lorder.1 8.1 (Berkeley) 6/6/93
+.\" @(#)lorder.1 8.2 (Berkeley) 4/28/95
.\"
-.Dd June 6, 1993
+.Dd April 28, 1995
.Dt LORDER 1
.Os
.Sh NAME
@@ -58,7 +58,7 @@ object modules so that all references may be resolved in a single
pass of the loader.
.Sh EXAMPLES
.Bd -literal -offset indent
-ar cr library.a `lorder ${OBJS} tsort`
+ar cr library.a `lorder ${OBJS} | tsort`
.Ed
.Sh SEE ALSO
.Xr ar 1 ,
diff --git a/usr.bin/m4/serv.c b/usr.bin/m4/serv.c
new file mode 100644
index 0000000..54a2e59
--- /dev/null
+++ b/usr.bin/m4/serv.c
@@ -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;
+}
diff --git a/usr.bin/man/Makefile b/usr.bin/man/Makefile
new file mode 100644
index 0000000..728d038
--- /dev/null
+++ b/usr.bin/man/Makefile
@@ -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>
diff --git a/usr.bin/man/config.c b/usr.bin/man/config.c
new file mode 100644
index 0000000..42780fa
--- /dev/null
+++ b/usr.bin/man/config.c
@@ -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);
+ }
+}
diff --git a/usr.bin/man/config.h b/usr.bin/man/config.h
new file mode 100644
index 0000000..52ea969
--- /dev/null
+++ b/usr.bin/man/config.h
@@ -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 *));
diff --git a/usr.bin/man/man.1 b/usr.bin/man/man.1
new file mode 100644
index 0000000..081e204
--- /dev/null
+++ b/usr.bin/man/man.1
@@ -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 .
diff --git a/usr.bin/man/man.c b/usr.bin/man/man.c
new file mode 100644
index 0000000..4f3b9e5
--- /dev/null
+++ b/usr.bin/man/man.c
@@ -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);
+}
diff --git a/usr.bin/man/man.conf b/usr.bin/man/man.conf
new file mode 100644
index 0000000..9faad52
--- /dev/null
+++ b/usr.bin/man/man.conf
@@ -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
diff --git a/usr.bin/man/man.conf.5 b/usr.bin/man/man.conf.5
new file mode 100644
index 0000000..353a302
--- /dev/null
+++ b/usr.bin/man/man.conf.5
@@ -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
diff --git a/usr.bin/man/pathnames.h b/usr.bin/man/pathnames.h
new file mode 100644
index 0000000..17284fe
--- /dev/null
+++ b/usr.bin/man/pathnames.h
@@ -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"
diff --git a/usr.bin/mklocale/Japanese b/usr.bin/mklocale/Japanese
new file mode 100644
index 0000000..55eb155
--- /dev/null
+++ b/usr.bin/mklocale/Japanese
@@ -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
diff --git a/usr.bin/more/output.c b/usr.bin/more/output.c
index c721f4e..21514ede 100644
--- a/usr.bin/more/output.c
+++ b/usr.bin/more/output.c
@@ -33,7 +33,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)output.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 4/27/95";
#endif /* not lint */
/*
@@ -204,15 +204,17 @@ error(s)
* edit() makes sure these messages can be seen before they
* are overwritten or scrolled away.
*/
- (void)write(2, s, strlen(s));
- (void)write(2, "\n", 1);
+ if (s != NULL) {
+ (void)write(2, s, strlen(s));
+ (void)write(2, "\n", 1);
+ }
return;
}
lower_left();
clear_eol();
so_enter();
- if (s) {
+ if (s != NULL) {
putstr(s);
putstr(" ");
}
@@ -226,7 +228,7 @@ error(s)
}
lower_left();
- if (strlen(s) + sizeof(return_to_continue) +
+ if ((s != NULL ? strlen(s) : 0) + sizeof(return_to_continue) +
so_width + se_width + 1 > sc_width)
/*
* Printing the message has probably scrolled the screen.
diff --git a/usr.bin/msgs/Makefile b/usr.bin/msgs/Makefile
index 09ef68d..2398907 100644
--- a/usr.bin/msgs/Makefile
+++ b/usr.bin/msgs/Makefile
@@ -1,7 +1,7 @@
-# @(#)Makefile 8.1 (Berkeley) 6/6/93
+# @(#)Makefile 8.2 (Berkeley) 4/28/95
PROG= msgs
-DPADD= ${LIBTERM} ${LIBCOMPAT}
-LDADD= -ltermlib -lcompat
+DPADD= ${LIBTERM}
+LDADD= -ltermlib
.include <bsd.prog.mk>
diff --git a/usr.bin/msgs/msgs.1 b/usr.bin/msgs/msgs.1
index 87d826a..fe61924 100644
--- a/usr.bin/msgs/msgs.1
+++ b/usr.bin/msgs/msgs.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)msgs.1 8.1 (Berkeley) 6/6/93
+.\" @(#)msgs.1 8.2 (Berkeley) 4/28/95
.\"
-.Dd June 6, 1993
+.Dd April 28, 1995
.Dt MSGS 1
.Os BSD 4
.Sh NAME
@@ -123,7 +123,7 @@ The
.Fl s
option is used for setting up the posting of messages. The line
.Pp
-.Dl msgs: \&"\&| /usr/ucb/msgs \-s\&"
+.Dl msgs: \&"\&| /usr/bin/msgs \-s\&"
.Pp
should be included in
.Pa /etc/aliases
diff --git a/usr.bin/msgs/msgs.c b/usr.bin/msgs/msgs.c
index 9a5311a..6804282 100644
--- a/usr.bin/msgs/msgs.c
+++ b/usr.bin/msgs/msgs.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
/*
@@ -70,16 +70,17 @@ static char sccsid[] = "@(#)msgs.c 8.1 (Berkeley) 6/6/93";
#include <sys/param.h>
#include <sys/dir.h>
+#include <sys/ioctl.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <pwd.h>
#include <setjmp.h>
-#include <sgtty.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "pathnames.h"
@@ -130,7 +131,6 @@ int nlines;
int Lpp = 0;
time_t t;
time_t keep;
-struct sgttyb otty;
char *mktemp();
char *nxtfld();
@@ -162,7 +162,6 @@ int argc; char *argv[];
setbuf(stdout, NULL);
#endif
- gtty(fileno(stdout), &otty);
time(&t);
setuid(uid = getuid());
ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
@@ -633,7 +632,7 @@ int length;
}
/* trick to force wait on output */
- stty(fileno(stdout), &otty);
+ tcdrain(fileno(stdout));
}
void
diff --git a/usr.bin/nfsstat/nfsstat.c b/usr.bin/nfsstat/nfsstat.c
index c57e658..c7ef75d 100644
--- a/usr.bin/nfsstat/nfsstat.c
+++ b/usr.bin/nfsstat/nfsstat.c
@@ -41,20 +41,14 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)nfsstat.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)nfsstat.c 8.2 (Berkeley) 3/31/95";
#endif /* not lint */
#include <sys/param.h>
-#if BSD >= 199103
-#define NEWVM
-#endif
-#ifndef NEWVM
-#include <sys/vmmac.h>
-#include <sys/ucred.h>
-#include <machine/pte.h>
-#endif
#include <sys/mount.h>
-#include <nfs/nfsv2.h>
+#include <sys/sysctl.h>
+#include <nfs/rpcv2.h>
+#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <signal.h>
#include <fcntl.h>
@@ -67,6 +61,7 @@ static char sccsid[] = "@(#)nfsstat.c 8.1 (Berkeley) 6/6/93";
#include <stdlib.h>
#include <string.h>
#include <paths.h>
+#include <err.h>
struct nlist nl[] = {
#define N_NFSSTAT 0
@@ -75,7 +70,12 @@ struct nlist nl[] = {
};
kvm_t *kd;
-void intpr(), printhdr(), sidewaysintpr(), usage();
+static int deadkernel = 0;
+
+void intpr __P((void));
+void printhdr __P((void));
+void sidewaysintpr __P((u_int));
+void usage __P((void));
main(argc, argv)
int argc;
@@ -123,38 +123,65 @@ main(argc, argv)
* Discard setgid privileges if not the running kernel so that bad
* guys can't print interesting stuff from kernel memory.
*/
- if (nlistf != NULL || memf != NULL)
+ if (nlistf != NULL || memf != NULL) {
setgid(getgid());
+ deadkernel = 1;
- if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == 0) {
- fprintf(stderr, "nfsstat: kvm_openfiles: %s\n", errbuf);
- exit(1);
- }
- if (kvm_nlist(kd, nl) != 0) {
- fprintf(stderr, "nfsstat: kvm_nlist: can't get names\n");
- exit(1);
+ if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY,
+ errbuf)) == 0) {
+ errx(1, "kvm_openfiles: %s", errbuf);
+ }
+ if (kvm_nlist(kd, nl) != 0) {
+ errx(1, "kvm_nlist: can't get names");
+ }
}
if (interval)
- sidewaysintpr(interval, nl[N_NFSSTAT].n_value);
+ sidewaysintpr(interval);
else
- intpr(nl[N_NFSSTAT].n_value);
+ intpr();
exit(0);
}
/*
+ * Read the nfs stats using sysctl(3) for live kernels, or kvm_read
+ * for dead ones.
+ */
+void
+readstats(stp)
+ struct nfsstats *stp;
+{
+ if(deadkernel) {
+ if(kvm_read(kd, (u_long)nl[N_NFSSTAT].n_value, stp,
+ sizeof *stp) < 0) {
+ err(1, "kvm_read");
+ }
+ } else {
+ int name[3];
+ size_t buflen = sizeof *stp;
+ struct vfsconf vfc;
+
+ if (getvfsbyname("nfs", &vfc) < 0)
+ err(1, "getvfsbyname: NFS not compiled into kernel");
+ name[0] = CTL_VFS;
+ name[1] = vfc.vfc_typenum;
+ name[2] = NFS_NFSSTATS;
+ if (sysctl(name, 3, stp, &buflen, (void *)0, (size_t)0) < 0) {
+ err(1, "sysctl");
+ }
+ }
+}
+
+/*
* Print a description of the nfs stats.
*/
void
-intpr(nfsstataddr)
- u_long nfsstataddr;
+intpr()
{
struct nfsstats nfsstats;
- if (kvm_read(kd, (u_long)nfsstataddr, (char *)&nfsstats, sizeof(struct nfsstats)) < 0) {
- fprintf(stderr, "nfsstat: kvm_read failed\n");
- exit(1);
- }
+ readstats(&nfsstats);
+
printf("Client Info:\n");
printf("Rpc Counts:\n");
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
@@ -171,7 +198,7 @@ intpr(nfsstataddr)
nfsstats.rpccnt[NFSPROC_REMOVE]);
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
- "Readdir", "Statfs", "RdirLook");
+ "Readdir", "RdirPlus", "Access");
printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
nfsstats.rpccnt[NFSPROC_RENAME],
nfsstats.rpccnt[NFSPROC_LINK],
@@ -179,11 +206,17 @@ intpr(nfsstataddr)
nfsstats.rpccnt[NFSPROC_MKDIR],
nfsstats.rpccnt[NFSPROC_RMDIR],
nfsstats.rpccnt[NFSPROC_READDIR],
- nfsstats.rpccnt[NFSPROC_STATFS],
- nfsstats.rpccnt[NQNFSPROC_READDIRLOOK]);
- printf("%9.9s %9.9s %9.9s\n",
+ nfsstats.rpccnt[NFSPROC_READDIRPLUS],
+ nfsstats.rpccnt[NFSPROC_ACCESS]);
+ printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
+ "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit",
"GLease", "Vacate", "Evict");
- printf("%9d %9d %9d\n",
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ nfsstats.rpccnt[NFSPROC_MKNOD],
+ nfsstats.rpccnt[NFSPROC_FSSTAT],
+ nfsstats.rpccnt[NFSPROC_FSINFO],
+ nfsstats.rpccnt[NFSPROC_PATHCONF],
+ nfsstats.rpccnt[NFSPROC_COMMIT],
nfsstats.rpccnt[NQNFSPROC_GETLEASE],
nfsstats.rpccnt[NQNFSPROC_VACATED],
nfsstats.rpccnt[NQNFSPROC_EVICTED]);
@@ -234,7 +267,7 @@ intpr(nfsstataddr)
nfsstats.srvrpccnt[NFSPROC_REMOVE]);
printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
- "Readdir", "Statfs", "RdirLook");
+ "Readdir", "RdirPlus", "Access");
printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
nfsstats.srvrpccnt[NFSPROC_RENAME],
nfsstats.srvrpccnt[NFSPROC_LINK],
@@ -242,11 +275,17 @@ intpr(nfsstataddr)
nfsstats.srvrpccnt[NFSPROC_MKDIR],
nfsstats.srvrpccnt[NFSPROC_RMDIR],
nfsstats.srvrpccnt[NFSPROC_READDIR],
- nfsstats.srvrpccnt[NFSPROC_STATFS],
- nfsstats.srvrpccnt[NQNFSPROC_READDIRLOOK]);
- printf("%9.9s %9.9s %9.9s\n",
+ nfsstats.srvrpccnt[NFSPROC_READDIRPLUS],
+ nfsstats.srvrpccnt[NFSPROC_ACCESS]);
+ printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
+ "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit",
"GLease", "Vacate", "Evict");
- printf("%9d %9d %9d\n",
+ printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
+ nfsstats.srvrpccnt[NFSPROC_MKNOD],
+ nfsstats.srvrpccnt[NFSPROC_FSSTAT],
+ nfsstats.srvrpccnt[NFSPROC_FSINFO],
+ nfsstats.srvrpccnt[NFSPROC_PATHCONF],
+ nfsstats.srvrpccnt[NFSPROC_COMMIT],
nfsstats.srvrpccnt[NQNFSPROC_GETLEASE],
nfsstats.srvrpccnt[NQNFSPROC_VACATED],
nfsstats.srvrpccnt[NQNFSPROC_EVICTED]);
@@ -269,6 +308,13 @@ intpr(nfsstataddr)
nfsstats.srvnqnfs_leases,
nfsstats.srvnqnfs_maxleases,
nfsstats.srvnqnfs_getleases);
+ printf("Server Write Gathering:\n");
+ printf("%9.9s %9.9s %9.9s\n",
+ "WriteOps", "WriteRPC", "Opsaved");
+ printf("%9d %9d %9d\n",
+ nfsstats.srvvop_writes,
+ nfsstats.srvrpccnt[NFSPROC_WRITE],
+ nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes);
}
u_char signalled; /* set if alarm goes off "early" */
@@ -280,9 +326,8 @@ u_char signalled; /* set if alarm goes off "early" */
* First line printed at top of screen is always cumulative.
*/
void
-sidewaysintpr(interval, off)
+sidewaysintpr(interval)
u_int interval;
- u_long off;
{
struct nfsstats nfsstats, lastst;
int hdrcnt, oldmask;
@@ -298,28 +343,27 @@ sidewaysintpr(interval, off)
printhdr();
hdrcnt = 20;
}
- if (kvm_read(kd, off, (char *)&nfsstats, sizeof nfsstats) < 0) {
- fprintf(stderr, "nfsstat: kvm_read failed\n");
- exit(1);
- }
+ readstats(&nfsstats);
printf("Client: %8d %8d %8d %8d %8d %8d %8d %8d\n",
- nfsstats.rpccnt[1]-lastst.rpccnt[1],
- nfsstats.rpccnt[4]-lastst.rpccnt[4],
- nfsstats.rpccnt[5]-lastst.rpccnt[5],
- nfsstats.rpccnt[6]-lastst.rpccnt[6],
- nfsstats.rpccnt[8]-lastst.rpccnt[8],
- nfsstats.rpccnt[11]-lastst.rpccnt[11],
- nfsstats.rpccnt[12]-lastst.rpccnt[12],
- nfsstats.rpccnt[16]-lastst.rpccnt[16]);
+ nfsstats.rpccnt[NFSPROC_GETATTR]-lastst.rpccnt[NFSPROC_GETATTR],
+ nfsstats.rpccnt[NFSPROC_LOOKUP]-lastst.rpccnt[NFSPROC_LOOKUP],
+ nfsstats.rpccnt[NFSPROC_READLINK]-lastst.rpccnt[NFSPROC_READLINK],
+ nfsstats.rpccnt[NFSPROC_READ]-lastst.rpccnt[NFSPROC_READ],
+ nfsstats.rpccnt[NFSPROC_WRITE]-lastst.rpccnt[NFSPROC_WRITE],
+ nfsstats.rpccnt[NFSPROC_RENAME]-lastst.rpccnt[NFSPROC_RENAME],
+ nfsstats.rpccnt[NFSPROC_ACCESS]-lastst.rpccnt[NFSPROC_ACCESS],
+ (nfsstats.rpccnt[NFSPROC_READDIR]-lastst.rpccnt[NFSPROC_READDIR])
+ +(nfsstats.rpccnt[NFSPROC_READDIRPLUS]-lastst.rpccnt[NFSPROC_READDIRPLUS]));
printf("Server: %8d %8d %8d %8d %8d %8d %8d %8d\n",
- nfsstats.srvrpccnt[1]-lastst.srvrpccnt[1],
- nfsstats.srvrpccnt[4]-lastst.srvrpccnt[4],
- nfsstats.srvrpccnt[5]-lastst.srvrpccnt[5],
- nfsstats.srvrpccnt[6]-lastst.srvrpccnt[6],
- nfsstats.srvrpccnt[8]-lastst.srvrpccnt[8],
- nfsstats.srvrpccnt[11]-lastst.srvrpccnt[11],
- nfsstats.srvrpccnt[12]-lastst.srvrpccnt[12],
- nfsstats.srvrpccnt[16]-lastst.srvrpccnt[16]);
+ nfsstats.srvrpccnt[NFSPROC_GETATTR]-lastst.srvrpccnt[NFSPROC_GETATTR],
+ nfsstats.srvrpccnt[NFSPROC_LOOKUP]-lastst.srvrpccnt[NFSPROC_LOOKUP],
+ nfsstats.srvrpccnt[NFSPROC_READLINK]-lastst.srvrpccnt[NFSPROC_READLINK],
+ nfsstats.srvrpccnt[NFSPROC_READ]-lastst.srvrpccnt[NFSPROC_READ],
+ nfsstats.srvrpccnt[NFSPROC_WRITE]-lastst.srvrpccnt[NFSPROC_WRITE],
+ nfsstats.srvrpccnt[NFSPROC_RENAME]-lastst.srvrpccnt[NFSPROC_RENAME],
+ nfsstats.srvrpccnt[NFSPROC_ACCESS]-lastst.srvrpccnt[NFSPROC_ACCESS],
+ (nfsstats.srvrpccnt[NFSPROC_READDIR]-lastst.srvrpccnt[NFSPROC_READDIR])
+ +(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]-lastst.srvrpccnt[NFSPROC_READDIRPLUS]));
lastst = nfsstats;
fflush(stdout);
oldmask = sigblock(sigmask(SIGALRM));
@@ -337,7 +381,7 @@ printhdr()
{
printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n",
"Getattr", "Lookup", "Readlink", "Read", "Write", "Rename",
- "Link", "Readdir");
+ "Access", "Readdir");
fflush(stdout);
}
diff --git a/usr.bin/nice/nice.c b/usr.bin/nice/nice.c
index 6b905d9..9805bfa 100644
--- a/usr.bin/nice/nice.c
+++ b/usr.bin/nice/nice.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)nice.c 8.2 (Berkeley) 4/16/94";
+static char sccsid[] = "@(#)nice.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
@@ -64,16 +64,17 @@ main(argc, argv)
{
int niceness = DEFNICE;
+ if (argv[1] == NULL)
+ usage();
if (argv[1][0] == '-')
if (argv[1][1] == '-' || isdigit(argv[1][1])) {
niceness = atoi(argv[1] + 1);
++argv;
+ if (argv[1] == NULL)
+ usage();
} else
errx(1, "illegal option -- %s", argv[1]);
- if (argv[1] == NULL)
- usage();
-
errno = 0;
niceness += getpriority(PRIO_PROCESS, 0);
if (errno)
diff --git a/usr.bin/passwd/kpasswd_proto.h b/usr.bin/passwd/kpasswd_proto.h
new file mode 100644
index 0000000..465d4c7
--- /dev/null
+++ b/usr.bin/passwd/kpasswd_proto.h
@@ -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"
diff --git a/usr.bin/passwd/krb_passwd.c b/usr.bin/passwd/krb_passwd.c
new file mode 100644
index 0000000..d4a0f15
--- /dev/null
+++ b/usr.bin/passwd/krb_passwd.c
@@ -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 */
diff --git a/usr.bin/patch/EXTERN.h b/usr.bin/patch/EXTERN.h
new file mode 100644
index 0000000..0271074
--- /dev/null
+++ b/usr.bin/patch/EXTERN.h
@@ -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
diff --git a/usr.bin/patch/INTERN.h b/usr.bin/patch/INTERN.h
new file mode 100644
index 0000000..8bf16f5
--- /dev/null
+++ b/usr.bin/patch/INTERN.h
@@ -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
diff --git a/usr.bin/patch/config.h b/usr.bin/patch/config.h
new file mode 100644
index 0000000..9318fe7
--- /dev/null
+++ b/usr.bin/patch/config.h
@@ -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 /**/
diff --git a/usr.bin/patch/patchlevel.h b/usr.bin/patch/patchlevel.h
new file mode 100644
index 0000000..618bca4
--- /dev/null
+++ b/usr.bin/patch/patchlevel.h
@@ -0,0 +1 @@
+#define PATCHLEVEL 9
diff --git a/usr.bin/patch/version.c b/usr.bin/patch/version.c
new file mode 100644
index 0000000..17dfb81
--- /dev/null
+++ b/usr.bin/patch/version.c
@@ -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
+}
diff --git a/usr.bin/patch/version.h b/usr.bin/patch/version.h
new file mode 100644
index 0000000..08fe68d
--- /dev/null
+++ b/usr.bin/patch/version.h
@@ -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();
diff --git a/usr.bin/pr/pr.c b/usr.bin/pr/pr.c
index bbc7e9b..0c2b6f3 100644
--- a/usr.bin/pr/pr.c
+++ b/usr.bin/pr/pr.c
@@ -42,7 +42,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)pr.c 8.2 (Berkeley) 4/16/94";
+static char sccsid[] = "@(#)pr.c 8.3 (Berkeley) 10/9/94";
#endif /* not lint */
#include <sys/types.h>
@@ -99,7 +99,7 @@ char *timefrmt; /* time conversion string */
/*
* misc globals
*/
-FILE *err; /* error message file pointer */
+FILE *errf; /* error message file pointer */
int addone; /* page length is odd with double space */
int errcnt; /* error count on file processing */
char digs[] = "0123456789"; /* page number translation map */
@@ -824,7 +824,7 @@ mulfile(argc, argv)
pgwd = ((colwd + 1) * clcnt) - 1;
}
if (colwd < 1) {
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: page width too small for %d columns\n", clcnt);
return(1);
}
@@ -1277,7 +1277,7 @@ nxtfile(argc, argv, fname, buf, dt)
return(inf);
if (gettimeofday(&tv, &tz) < 0) {
++errcnt;
- (void)fprintf(err, "pr: cannot get time of day, %s\n",
+ (void)fprintf(errf, "pr: cannot get time of day, %s\n",
strerror(errno));
eoptind = argc - 1;
return(NULL);
@@ -1300,7 +1300,7 @@ nxtfile(argc, argv, fname, buf, dt)
return(inf);
if (gettimeofday(&tv, &tz) < 0) {
++errcnt;
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: cannot get time of day, %s\n",
strerror(errno));
return(NULL);
@@ -1314,7 +1314,7 @@ nxtfile(argc, argv, fname, buf, dt)
++errcnt;
if (nodiag)
continue;
- (void)fprintf(err, "pr: Cannot open %s, %s\n",
+ (void)fprintf(errf, "pr: Cannot open %s, %s\n",
argv[eoptind], strerror(errno));
continue;
}
@@ -1331,7 +1331,7 @@ nxtfile(argc, argv, fname, buf, dt)
if (dt) {
if (gettimeofday(&tv, &tz) < 0) {
++errcnt;
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: cannot get time of day, %s\n",
strerror(errno));
return(NULL);
@@ -1341,7 +1341,7 @@ nxtfile(argc, argv, fname, buf, dt)
if (fstat(fileno(inf), &statbuf) < 0) {
++errcnt;
(void)fclose(inf);
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: Cannot stat %s, %s\n",
argv[eoptind], strerror(errno));
return(NULL);
@@ -1361,7 +1361,7 @@ nxtfile(argc, argv, fname, buf, dt)
++errcnt;
if (inf != stdin)
(void)fclose(inf);
- (void)fputs("pr: time conversion failed\n", err);
+ (void)fputs("pr: time conversion failed\n", errf);
return(NULL);
}
return(inf);
@@ -1522,35 +1522,37 @@ flsh_errs()
char buf[BUFSIZ];
(void)fflush(stdout);
- (void)fflush(err);
- if (err == stderr)
+ (void)fflush(errf);
+ if (errf == stderr)
return;
- rewind(err);
- while (fgets(buf, BUFSIZ, err) != NULL)
+ rewind(errf);
+ while (fgets(buf, BUFSIZ, errf) != NULL)
(void)fputs(buf, stderr);
}
void
mfail()
{
- (void)fputs("pr: memory allocation failed\n", err);
+ (void)fputs("pr: memory allocation failed\n", errf);
}
void
pfail()
{
- (void)fprintf(err, "pr: write failure, %s\n", strerror(errno));
+ (void)fprintf(errf, "pr: write failure, %s\n", strerror(errno));
}
void
usage()
{
(void)fputs(
- "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",err);
+ "usage: pr [+page] [-col] [-adFmrt] [-e[ch][gap]] [-h header]\n",
+ errf);
(void)fputs(
- " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",err);
+ " [-i[ch][gap]] [-l line] [-n[ch][width]] [-o offset]\n",
+ errf);
(void)fputs(
- " [-s[ch]] [-w width] [-] [file ...]\n", err);
+ " [-s[ch]] [-w width] [-] [file ...]\n", errf);
}
/*
@@ -1572,24 +1574,25 @@ setup(argc, argv)
/*
* defer diagnostics until processing is done
*/
- if ((err = tmpfile()) == NULL) {
+ if ((errf = tmpfile()) == NULL) {
(void)fputs("Cannot defer diagnostic messages\n",stderr);
return(1);
}
} else
- err = stderr;
+ errf = stderr;
while ((c = egetopt(argc, argv, "#adFmrte?h:i?l:n?o:s?w:")) != EOF) {
switch (c) {
case '+':
if ((pgnm = atoi(eoptarg)) < 1) {
(void)fputs("pr: +page number must be 1 or more\n",
- err);
+ errf);
return(1);
}
break;
case '-':
if ((clcnt = atoi(eoptarg)) < 1) {
- (void)fputs("pr: -columns must be 1 or more\n",err);
+ (void)fputs("pr: -columns must be 1 or more\n",
+ errf);
return(1);
}
if (clcnt > 1)
@@ -1610,13 +1613,13 @@ setup(argc, argv)
if ((eoptarg != NULL) && isdigit(*eoptarg)) {
if ((ingap = atoi(eoptarg)) < 0) {
(void)fputs(
- "pr: -e gap must be 0 or more\n", err);
+ "pr: -e gap must be 0 or more\n", errf);
return(1);
}
if (ingap == 0)
ingap = INGAP;
} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: invalid value for -e %s\n", eoptarg);
return(1);
} else
@@ -1637,13 +1640,13 @@ setup(argc, argv)
if ((eoptarg != NULL) && isdigit(*eoptarg)) {
if ((ogap = atoi(eoptarg)) < 0) {
(void)fputs(
- "pr: -i gap must be 0 or more\n", err);
+ "pr: -i gap must be 0 or more\n", errf);
return(1);
}
if (ogap == 0)
ogap = OGAP;
} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: invalid value for -i %s\n", eoptarg);
return(1);
} else
@@ -1652,7 +1655,7 @@ setup(argc, argv)
case 'l':
if (!isdigit(*eoptarg) || ((lines=atoi(eoptarg)) < 1)) {
(void)fputs(
- "pr: Number of lines must be 1 or more\n",err);
+ "pr: Number of lines must be 1 or more\n",errf);
return(1);
}
break;
@@ -1667,11 +1670,11 @@ setup(argc, argv)
if ((eoptarg != NULL) && isdigit(*eoptarg)) {
if ((nmwd = atoi(eoptarg)) < 1) {
(void)fputs(
- "pr: -n width must be 1 or more\n",err);
+ "pr: -n width must be 1 or more\n",errf);
return(1);
}
} else if ((eoptarg != NULL) && (*eoptarg != '\0')) {
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: invalid value for -n %s\n", eoptarg);
return(1);
} else
@@ -1680,7 +1683,7 @@ setup(argc, argv)
case 'o':
if (!isdigit(*eoptarg) || ((offst = atoi(eoptarg))< 1)){
(void)fputs("pr: -o offset must be 1 or more\n",
- err);
+ errf);
return(1);
}
break;
@@ -1694,7 +1697,7 @@ setup(argc, argv)
else
schar = *eoptarg++;
if (*eoptarg != '\0') {
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: invalid value for -s %s\n", eoptarg);
return(1);
}
@@ -1706,7 +1709,7 @@ setup(argc, argv)
++wflag;
if (!isdigit(*eoptarg) || ((pgwd = atoi(eoptarg)) < 1)){
(void)fputs(
- "pr: -w width must be 1 or more \n",err);
+ "pr: -w width must be 1 or more \n",errf);
return(1);
}
break;
@@ -1731,11 +1734,11 @@ setup(argc, argv)
if (across) {
if (clcnt == 1) {
(void)fputs("pr: -a flag requires multiple columns\n",
- err);
+ errf);
return(1);
}
if (merge) {
- (void)fputs("pr: -m cannot be used with -a\n", err);
+ (void)fputs("pr: -m cannot be used with -a\n", errf);
return(1);
}
}
@@ -1758,7 +1761,7 @@ setup(argc, argv)
if (cflag) {
if (merge) {
(void)fputs(
- "pr: -m cannot be used with multiple columns\n", err);
+ "pr: -m cannot be used with multiple columns\n", errf);
return(1);
}
if (nmwd) {
@@ -1769,7 +1772,7 @@ setup(argc, argv)
pgwd = ((colwd + 1) * clcnt) - 1;
}
if (colwd < 1) {
- (void)fprintf(err,
+ (void)fprintf(errf,
"pr: page width is too small for %d columns\n",clcnt);
return(1);
}
diff --git a/usr.bin/printf/printf.c b/usr.bin/printf/printf.c
index 69f0c8e..82ffbda 100644
--- a/usr.bin/printf/printf.c
+++ b/usr.bin/printf/printf.c
@@ -40,7 +40,7 @@ static char copyright[] =
#endif
#ifndef lint
-static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93";
+static char sccsid[] = "@(#)printf.c 8.2 (Berkeley) 3/22/95";
#endif /* not lint */
#include <sys/types.h>
@@ -258,7 +258,7 @@ escape(fmt)
register char *store;
register int value, c;
- for (store = fmt; c = *fmt; ++fmt, ++store) {
+ for (store = fmt; (c = *fmt) != '\0'; ++fmt, ++store) {
if (c != '\\') {
*store = c;
continue;
diff --git a/usr.bin/quota/quota.c b/usr.bin/quota/quota.c
index 1d18a13..f7fadc2 100644
--- a/usr.bin/quota/quota.c
+++ b/usr.bin/quota/quota.c
@@ -41,7 +41,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)quota.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)quota.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
/*
@@ -50,13 +50,16 @@ static char sccsid[] = "@(#)quota.c 8.1 (Berkeley) 6/6/93";
#include <sys/param.h>
#include <sys/file.h>
#include <sys/stat.h>
+#include <sys/queue.h>
+
#include <ufs/ufs/quota.h>
-#include <stdio.h>
-#include <fstab.h>
+
#include <ctype.h>
-#include <pwd.h>
-#include <grp.h>
#include <errno.h>
+#include <fstab.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
char *qfname = QUOTAFILENAME;
char *qfextension[] = INITQFNAMES;
@@ -75,7 +78,8 @@ int vflag;
main(argc, argv)
char *argv[];
{
- int ngroups, gidset[NGROUPS];
+ int ngroups;
+ gid_t gidset[NGROUPS];
int i, gflag = 0, uflag = 0;
char ch;
extern char *optarg;
@@ -204,7 +208,8 @@ showgid(gid)
u_long gid;
{
struct group *grp = getgrgid(gid);
- int ngroups, gidset[NGROUPS];
+ int ngroups;
+ gid_t gidset[NGROUPS];
register int i;
char *name;
@@ -235,7 +240,8 @@ showgrpname(name)
char *name;
{
struct group *grp = getgrnam(name);
- int ngroups, gidset[NGROUPS];
+ int ngroups;
+ gid_t gidset[NGROUPS];
register int i;
if (grp == NULL) {
@@ -423,7 +429,7 @@ getprivs(id, quotatype)
free(qup);
continue;
}
- lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET);
+ lseek(fd, (off_t)(id * sizeof(struct dqblk)), L_SET);
switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) {
case 0: /* EOF */
/*
diff --git a/usr.bin/ranlib/ranlib.5.5 b/usr.bin/ranlib/ranlib.5.5
new file mode 100644
index 0000000..e953c51
--- /dev/null
+++ b/usr.bin/ranlib/ranlib.5.5
@@ -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
diff --git a/usr.bin/rlogin/des_rw.c b/usr.bin/rlogin/des_rw.c
new file mode 100644
index 0000000..dbe47f0
--- /dev/null
+++ b/usr.bin/rlogin/des_rw.c
@@ -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 */
diff --git a/usr.bin/rlogin/rlogin.1 b/usr.bin/rlogin/rlogin.1
index 60da3cc..979658a 100644
--- a/usr.bin/rlogin/rlogin.1
+++ b/usr.bin/rlogin/rlogin.1
@@ -29,21 +29,26 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)rlogin.1 8.1 (Berkeley) 6/6/93
+.\" @(#)rlogin.1 8.2 (Berkeley) 4/29/95
.\"
-.Dd June 6, 1993
+.Dd April 29, 1995
.Dt RLOGIN 1
.Os BSD 4.2
.Sh NAME
.Nm rlogin
.Nd remote login
.Sh SYNOPSIS
-.Ar rlogin
+.Nm rlogin
.Op Fl 8EKLdx
.Op Fl e Ar char
.Op Fl k Ar realm
.Op Fl l Ar username
.Ar host
+.Nm rlogin
+.Op Fl 8EKLdx
+.Op Fl e Ar char
+.Op Fl k Ar realm
+.Ar username@host
.Sh DESCRIPTION
.Nm Rlogin
starts a terminal session on a remote host
diff --git a/usr.bin/rlogin/rlogin.c b/usr.bin/rlogin/rlogin.c
index 5439c48..4aee20e 100644
--- a/usr.bin/rlogin/rlogin.c
+++ b/usr.bin/rlogin/rlogin.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)rlogin.c 8.4 (Berkeley) 4/29/95";
#endif /* not lint */
/*
@@ -49,6 +49,7 @@ static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
+#include <sys/ioctl.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -59,7 +60,7 @@ static char sccsid[] = "@(#)rlogin.c 8.1 (Berkeley) 6/6/93";
#include <netdb.h>
#include <pwd.h>
#include <setjmp.h>
-#include <sgtty.h>
+#include <termios.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -98,11 +99,6 @@ int eight, litout, rem;
int noescape;
u_char escapechar = '~';
-char *speeds[] = {
- "0", "50", "75", "110", "134", "150", "200", "300", "600", "1200",
- "1800", "2400", "4800", "9600", "19200", "38400"
-};
-
#ifdef OLDSUN
struct winsize {
unsigned short ws_row, ws_col;
@@ -115,7 +111,7 @@ struct winsize winsize;
void catch_child __P((int));
void copytochild __P((int));
-__dead void doit __P((long));
+__dead void doit __P((sigset_t *));
__dead void done __P((int));
void echo __P((char));
u_int getescape __P((char *));
@@ -123,9 +119,10 @@ void lostpeer __P((int));
void mode __P((int));
void msg __P((char *));
void oob __P((int));
-int reader __P((int));
+int reader __P((sigset_t *));
void sendwindow __P((void));
void setsignal __P((int));
+int speed __P((int));
void sigwinch __P((int));
void stop __P((char));
__dead void usage __P((void));
@@ -144,25 +141,24 @@ main(argc, argv)
int argc;
char *argv[];
{
- extern char *optarg;
- extern int optind;
struct passwd *pw;
struct servent *sp;
- struct sgttyb ttyb;
- long omask;
- int argoff, ch, dflag, one, uid;
+ sigset_t smask;
+ uid_t uid;
+ int argoff, ch, dflag, one;
char *host, *p, *user, term[1024];
+ struct sigaction sa;
argoff = dflag = 0;
one = 1;
host = user = NULL;
- if (p = rindex(argv[0], '/'))
+ if (p = strrchr(argv[0], '/'))
++p;
else
p = argv[0];
- if (strcmp(p, "rlogin"))
+ if (strcmp(p, "rlogin") != 0)
host = p;
/* handle "rlogin host flags" */
@@ -231,9 +227,17 @@ main(argc, argv)
if (*argv)
usage();
- if (!(pw = getpwuid(uid = getuid()))) {
- (void)fprintf(stderr, "rlogin: unknown user id.\n");
- exit(1);
+ if (!(pw = getpwuid(uid = getuid())))
+ errx(1, "unknown user id.");
+ /* Accept user1@host format, though "-l user2" overrides user1 */
+ p = strchr(host, '@');
+ if (p) {
+ *p = '\0';
+ if (!user && p > host)
+ user = host;
+ host = p + 1;
+ if (*host == '\0')
+ usage();
}
if (!user)
user = pw->pw_name;
@@ -251,30 +255,34 @@ main(argc, argv)
#endif
if (sp == NULL)
sp = getservbyname("login", "tcp");
- if (sp == NULL) {
- (void)fprintf(stderr, "rlogin: login/tcp: unknown service.\n");
- exit(1);
- }
+ if (sp == NULL)
+ errx(1, "login/tcp: unknown service.");
- (void)strcpy(term, (p = getenv("TERM")) ? p : "network");
- if (ioctl(0, TIOCGETP, &ttyb) == 0) {
- (void)strcat(term, "/");
- (void)strcat(term, speeds[(int)ttyb.sg_ospeed]);
- }
+ (void)snprintf(term, sizeof(term), "%s/%d",
+ ((p = getenv("TERM")) ? p : "network"),
+ speed(0));
(void)get_window_size(0, &winsize);
- (void)signal(SIGPIPE, lostpeer);
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = lostpeer;
+ (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
/* will use SIGUSR1 for window size hack, so hold it off */
- omask = sigblock(sigmask(SIGURG) | sigmask(SIGUSR1));
+ sigemptyset(&smask);
+ sigaddset(&smask, SIGURG);
+ sigaddset(&smask, SIGUSR1);
+ (void)sigprocmask(SIG_SETMASK, &smask, &smask);
/*
* We set SIGURG and SIGUSR1 below so that an
* incoming signal will be held pending rather than being
* discarded. Note that these routines will be ready to get
* a signal by the time that they are unblocked below.
*/
- (void)signal(SIGURG, copytochild);
- (void)signal(SIGUSR1, writeroob);
+ sa.sa_handler = copytochild;
+ (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
+ sa.sa_handler = writeroob;
+ (void)sigaction(SIGUSR1, &sa, (struct sigaction *) 0);
#ifdef KERBEROS
try_connect:
@@ -283,11 +291,8 @@ try_connect:
/* Fully qualify hostname (needed for krb_realmofhost). */
hp = gethostbyname(host);
- if (hp != NULL && !(host = strdup(hp->h_name))) {
- (void)fprintf(stderr, "rlogin: %s\n",
- strerror(ENOMEM));
- exit(1);
- }
+ if (hp != NULL && !(host = strdup(hp->h_name)))
+ errx(1, "%s", strerror(ENOMEM));
rem = KSUCCESS;
errno = 0;
@@ -305,11 +310,8 @@ try_connect:
if (rem < 0) {
use_kerberos = 0;
sp = getservbyname("login", "tcp");
- if (sp == NULL) {
- (void)fprintf(stderr,
- "rlogin: unknown service login/tcp.\n");
- exit(1);
- }
+ if (sp == NULL)
+ errx(1, "unknown service login/tcp.");
if (errno == ECONNREFUSED)
warning("remote host doesn't support Kerberos");
if (errno == ENOENT)
@@ -318,11 +320,8 @@ try_connect:
}
} else {
#ifdef CRYPT
- if (doencrypt) {
- (void)fprintf(stderr,
- "rlogin: the -x flag requires Kerberos authentication.\n");
- exit(1);
- }
+ if (doencrypt)
+ errx(1, "the -x flag requires Kerberos authentication.");
#endif /* CRYPT */
rem = rcmd(&host, sp->s_port, pw->pw_name, user, term, 0);
}
@@ -335,52 +334,77 @@ try_connect:
if (dflag &&
setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) < 0)
- (void)fprintf(stderr, "rlogin: setsockopt: %s.\n",
- strerror(errno));
+ warn("setsockopt DEBUG (ignored)");
one = IPTOS_LOWDELAY;
if (setsockopt(rem, IPPROTO_IP, IP_TOS, (char *)&one, sizeof(int)) < 0)
- perror("rlogin: setsockopt TOS (ignored)");
+ warn("setsockopt TOS (ignored)");
(void)setuid(uid);
- doit(omask);
+ doit(&smask);
/*NOTREACHED*/
}
-int child, defflags, deflflags, tabflag;
-char deferase, defkill;
-struct tchars deftc;
-struct ltchars defltc;
-struct tchars notc = { -1, -1, -1, -1, -1, -1 };
-struct ltchars noltc = { -1, -1, -1, -1, -1, -1 };
+#if BSD >= 198810
+int
+speed(fd)
+ int fd;
+{
+ struct termios tt;
+
+ (void)tcgetattr(fd, &tt);
+
+ return ((int) cfgetispeed(&tt));
+}
+#else
+int speeds[] = { /* for older systems, B0 .. EXTB */
+ 0, 50, 75, 110,
+ 134, 150, 200, 300,
+ 600, 1200, 1800, 2400,
+ 4800, 9600, 19200, 38400
+};
+
+int
+speed(fd)
+ int fd;
+{
+ struct termios tt;
+
+ (void)tcgetattr(fd, &tt);
+
+ return (speeds[(int)cfgetispeed(&tt)]);
+}
+#endif
+
+pid_t child;
+struct termios deftt;
+struct termios nott;
void
-doit(omask)
- long omask;
+doit(smask)
+ sigset_t *smask;
{
- struct sgttyb sb;
-
- (void)ioctl(0, TIOCGETP, (char *)&sb);
- defflags = sb.sg_flags;
- tabflag = defflags & TBDELAY;
- defflags &= ECHO | CRMOD;
- deferase = sb.sg_erase;
- defkill = sb.sg_kill;
- (void)ioctl(0, TIOCLGET, &deflflags);
- (void)ioctl(0, TIOCGETC, &deftc);
- notc.t_startc = deftc.t_startc;
- notc.t_stopc = deftc.t_stopc;
- (void)ioctl(0, TIOCGLTC, &defltc);
- (void)signal(SIGINT, SIG_IGN);
+ int i;
+ struct sigaction sa;
+
+ for (i = 0; i < NCCS; i++)
+ nott.c_cc[i] = _POSIX_VDISABLE;
+ tcgetattr(0, &deftt);
+ nott.c_cc[VSTART] = deftt.c_cc[VSTART];
+ nott.c_cc[VSTOP] = deftt.c_cc[VSTOP];
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ (void)sigaction(SIGINT, &sa, (struct sigaction *) 0);
setsignal(SIGHUP);
setsignal(SIGQUIT);
child = fork();
if (child == -1) {
- (void)fprintf(stderr, "rlogin: fork: %s.\n", strerror(errno));
+ warn("fork");
done(1);
}
if (child == 0) {
mode(1);
- if (reader(omask) == 0) {
+ if (reader(smask) == 0) {
msg("connection closed.");
exit(0);
}
@@ -396,8 +420,9 @@ doit(omask)
* signals to the child. We can now unblock SIGURG and SIGUSR1
* that were set above.
*/
- (void)sigsetmask(omask);
- (void)signal(SIGCHLD, catch_child);
+ (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
+ sa.sa_handler = catch_child;
+ (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
writer();
msg("closed connection.");
done(0);
@@ -408,25 +433,41 @@ void
setsignal(sig)
int sig;
{
- int omask = sigblock(sigmask(sig));
+ struct sigaction sa;
+ sigset_t sigs;
+
+ sigemptyset(&sigs);
+ sigaddset(&sigs, sig);
+ sigprocmask(SIG_BLOCK, &sigs, &sigs);
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = exit;
+ sa.sa_flags = SA_RESTART;
+ (void)sigaction(sig, &sa, &sa);
+ if (sa.sa_handler == SIG_IGN)
+ (void)sigaction(sig, &sa, (struct sigaction *) 0);
- if (signal(sig, exit) == SIG_IGN)
- (void)signal(sig, SIG_IGN);
- (void)sigsetmask(omask);
+ (void)sigprocmask(SIG_SETMASK, &sigs, (sigset_t *) 0);
}
__dead void
done(status)
int status;
{
- int w, wstatus;
+ pid_t w;
+ int wstatus;
+ struct sigaction sa;
mode(0);
if (child > 0) {
/* make sure catch_child does not snap it up */
- (void)signal(SIGCHLD, SIG_DFL);
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ sa.sa_flags = 0;
+ (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
if (kill(child, SIGKILL) >= 0)
- while ((w = wait(&wstatus)) > 0 && w != child);
+ while ((w = wait(&wstatus)) > 0 && w != child)
+ continue;
}
exit(status);
}
@@ -441,9 +482,14 @@ void
writeroob(signo)
int signo;
{
+ struct sigaction sa;
+
if (dosigwinch == 0) {
sendwindow();
- (void)signal(SIGWINCH, sigwinch);
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = sigwinch;
+ sa.sa_flags = SA_RESTART;
+ (void)sigaction(SIGWINCH, &sa, (struct sigaction *) 0);
}
dosigwinch = 1;
}
@@ -452,16 +498,16 @@ void
catch_child(signo)
int signo;
{
- union wait status;
- int pid;
+ int status;
+ pid_t pid;
for (;;) {
- pid = wait3((int *)&status, WNOHANG|WUNTRACED, NULL);
+ pid = waitpid(-1, &status, WNOHANG|WUNTRACED);
if (pid == 0)
return;
/* if the child (reader) dies, just quit */
if (pid < 0 || (pid == child && !WIFSTOPPED(status)))
- done((int)(status.w_termsig | status.w_retcode));
+ done(WEXITSTATUS(status) | WTERMSIG(status));
}
/* NOTREACHED */
}
@@ -502,11 +548,11 @@ writer()
}
} else if (local) {
local = 0;
- if (c == '.' || c == deftc.t_eofc) {
+ if (c == '.' || c == deftt.c_cc[VEOF]) {
echo(c);
break;
}
- if (c == defltc.t_suspc || c == defltc.t_dsuspc) {
+ if (c == deftt.c_cc[VSUSP] || c == deftt.c_cc[VDSUSP]) {
bol = 1;
echo(c);
stop(c);
@@ -538,8 +584,8 @@ writer()
msg("line gone");
break;
}
- bol = c == defkill || c == deftc.t_eofc ||
- c == deftc.t_intrc || c == defltc.t_suspc ||
+ bol = c == deftt.c_cc[VKILL] || c == deftt.c_cc[VEOF] ||
+ c == deftt.c_cc[VINTR] || c == deftt.c_cc[VSUSP] ||
c == '\r' || c == '\n';
}
}
@@ -579,10 +625,16 @@ stop(cmdc)
char cmdc;
#endif
{
+ struct sigaction sa;
+
mode(0);
- (void)signal(SIGCHLD, SIG_IGN);
- (void)kill(cmdc == defltc.t_suspc ? 0 : getpid(), SIGTSTP);
- (void)signal(SIGCHLD, catch_child);
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = SA_RESTART;
+ (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
+ (void)kill(cmdc == deftt.c_cc[VSUSP] ? 0 : getpid(), SIGTSTP);
+ sa.sa_handler = catch_child;
+ (void)sigaction(SIGCHLD, &sa, (struct sigaction *) 0);
mode(1);
sigwinch(0); /* check for size changes */
}
@@ -594,7 +646,7 @@ sigwinch(signo)
struct winsize ws;
if (dosigwinch && get_window_size(0, &ws) == 0 &&
- bcmp(&ws, &winsize, sizeof(ws))) {
+ memcmp(&ws, &winsize, sizeof(ws))) {
winsize = ws;
sendwindow();
}
@@ -636,14 +688,15 @@ sendwindow()
#define WRITING 2
jmp_buf rcvtop;
-int ppid, rcvcnt, rcvstate;
+pid_t ppid;
+int rcvcnt, rcvstate;
char rcvbuf[8 * 1024];
void
oob(signo)
int signo;
{
- struct sgttyb sb;
+ struct termios tt;
int atmark, n, out, rcvd;
char waste[BUFSIZ], mark;
@@ -678,29 +731,24 @@ oob(signo)
(void)kill(ppid, SIGUSR1);
}
if (!eight && (mark & TIOCPKT_NOSTOP)) {
- (void)ioctl(0, TIOCGETP, (char *)&sb);
- sb.sg_flags &= ~CBREAK;
- sb.sg_flags |= RAW;
- (void)ioctl(0, TIOCSETN, (char *)&sb);
- notc.t_stopc = -1;
- notc.t_startc = -1;
- (void)ioctl(0, TIOCSETC, (char *)&notc);
+ tcgetattr(0, &tt);
+ tt.c_iflag &= ~(IXON | IXOFF);
+ tt.c_cc[VSTOP] = _POSIX_VDISABLE;
+ tt.c_cc[VSTART] = _POSIX_VDISABLE;
+ tcsetattr(0, TCSANOW, &tt);
}
if (!eight && (mark & TIOCPKT_DOSTOP)) {
- (void)ioctl(0, TIOCGETP, (char *)&sb);
- sb.sg_flags &= ~RAW;
- sb.sg_flags |= CBREAK;
- (void)ioctl(0, TIOCSETN, (char *)&sb);
- notc.t_stopc = deftc.t_stopc;
- notc.t_startc = deftc.t_startc;
- (void)ioctl(0, TIOCSETC, (char *)&notc);
+ tcgetattr(0, &tt);
+ tt.c_iflag |= (IXON|IXOFF);
+ tt.c_cc[VSTOP] = deftt.c_cc[VSTOP];
+ tt.c_cc[VSTART] = deftt.c_cc[VSTART];
+ tcsetattr(0, TCSANOW, &tt);
}
if (mark & TIOCPKT_FLUSHWRITE) {
(void)ioctl(1, TIOCFLUSH, (char *)&out);
for (;;) {
if (ioctl(rem, SIOCATMARK, &atmark) < 0) {
- (void)fprintf(stderr, "rlogin: ioctl: %s.\n",
- strerror(errno));
+ warn("ioctl SIOCATMARK (ignored)");
break;
}
if (atmark)
@@ -732,23 +780,29 @@ oob(signo)
/* reader: read from remote: line -> 1 */
int
-reader(omask)
- int omask;
+reader(smask)
+ sigset_t *smask;
{
- int pid, n, remaining;
+ pid_t pid;
+ int n, remaining;
char *bufp;
+ struct sigaction sa;
#if BSD >= 43 || defined(SUNOS4)
pid = getpid(); /* modern systems use positives for pid */
#else
pid = -getpid(); /* old broken systems use negatives */
#endif
- (void)signal(SIGTTOU, SIG_IGN);
- (void)signal(SIGURG, oob);
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ (void)sigaction(SIGTTOU, &sa, (struct sigaction *) 0);
+ sa.sa_handler = oob;
+ (void)sigaction(SIGURG, &sa, (struct sigaction *) 0);
ppid = getppid();
(void)fcntl(rem, F_SETOWN, pid);
(void)setjmp(rcvtop);
- (void)sigsetmask(omask);
+ (void)sigprocmask(SIG_SETMASK, smask, (sigset_t *) 0);
bufp = rcvbuf;
for (;;) {
while ((remaining = rcvcnt - (bufp - rcvbuf)) > 0) {
@@ -778,8 +832,7 @@ reader(omask)
if (rcvcnt < 0) {
if (errno == EINTR)
continue;
- (void)fprintf(stderr, "rlogin: read: %s.\n",
- strerror(errno));
+ warn("read");
return (-1);
}
}
@@ -789,49 +842,44 @@ void
mode(f)
int f;
{
- struct ltchars *ltc;
- struct sgttyb sb;
- struct tchars *tc;
- int lflags;
-
- (void)ioctl(0, TIOCGETP, (char *)&sb);
- (void)ioctl(0, TIOCLGET, (char *)&lflags);
- switch(f) {
+ struct termios tt;
+
+ switch (f) {
case 0:
- sb.sg_flags &= ~(CBREAK|RAW|TBDELAY);
- sb.sg_flags |= defflags|tabflag;
- tc = &deftc;
- ltc = &defltc;
- sb.sg_kill = defkill;
- sb.sg_erase = deferase;
- lflags = deflflags;
+ tcsetattr(0, TCSADRAIN, &deftt);
break;
case 1:
- sb.sg_flags |= (eight ? RAW : CBREAK);
- sb.sg_flags &= ~defflags;
- /* preserve tab delays, but turn off XTABS */
- if ((sb.sg_flags & TBDELAY) == XTABS)
- sb.sg_flags &= ~TBDELAY;
- tc = &notc;
- ltc = &noltc;
- sb.sg_kill = sb.sg_erase = -1;
- if (litout)
- lflags |= LLITOUT;
+ tt = deftt;
+ tt.c_oflag &= ~(OPOST);
+ tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ tt.c_iflag &= ~(ICRNL);
+ tt.c_cc[VMIN] = 1;
+ tt.c_cc[VTIME] = 0;
+ if (eight) {
+ tt.c_iflag &= ~(IXON | IXOFF | ISTRIP);
+ tt.c_cc[VSTOP] = _POSIX_VDISABLE;
+ tt.c_cc[VSTART] = _POSIX_VDISABLE;
+ }
+ /*if (litout)
+ lflags |= LLITOUT;*/
+ tcsetattr(0, TCSADRAIN, &tt);
break;
+
default:
return;
}
- (void)ioctl(0, TIOCSLTC, (char *)ltc);
- (void)ioctl(0, TIOCSETC, (char *)tc);
- (void)ioctl(0, TIOCSETN, (char *)&sb);
- (void)ioctl(0, TIOCLSET, (char *)&lflags);
}
void
lostpeer(signo)
int signo;
{
- (void)signal(SIGPIPE, SIG_IGN);
+ struct sigaction sa;
+
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART;
+ sa.sa_handler = SIG_IGN;
+ (void)sigaction(SIGPIPE, &sa, (struct sigaction *) 0);
msg("\007connection closed.");
done(1);
}
@@ -841,6 +889,7 @@ void
copytochild(signo)
int signo;
{
+
(void)kill(child, SIGURG);
}
@@ -848,6 +897,7 @@ void
msg(str)
char *str;
{
+
(void)fprintf(stderr, "rlogin: %s\r\n", str);
}
@@ -880,7 +930,7 @@ __dead void
usage()
{
(void)fprintf(stderr,
- "usage: rlogin [ -%s]%s[-e char] [ -l username ] host\n",
+ "usage: rlogin [ -%s]%s[-e char] [ -l username ] [username@]host\n",
#ifdef KERBEROS
#ifdef CRYPT
"8EKLx", " [-k realm] ");
diff --git a/usr.bin/rsh/rsh.1 b/usr.bin/rsh/rsh.1
index 908e7eb..78ec2f1 100644
--- a/usr.bin/rsh/rsh.1
+++ b/usr.bin/rsh/rsh.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)rsh.1 8.1 (Berkeley) 6/6/93
+.\" @(#)rsh.1 8.2 (Berkeley) 4/29/95
.\"
-.Dd June 6, 1993
+.Dd April 29, 1995
.Dt RSH 1
.Os BSD 4.2
.Sh NAME
@@ -43,6 +43,10 @@
.Op Fl k Ar realm
.Op Fl l Ar username
.Ar host
+.Nm rsh
+.Op Fl Kdnx
+.Op Fl k Ar realm
+.Ar username@host
.Op command
.Sh DESCRIPTION
.Nm Rsh
@@ -86,7 +90,9 @@ instead of the remote host's realm as determined by
By default, the remote username is the same as the local username.
The
.Fl l
-option allows the remote name to be specified.
+option or the
+.Pa username@host
+format allow the remote name to be specified.
Kerberos authentication is used, and authorization is determined
as in
.Xr rlogin 1 .
diff --git a/usr.bin/rsh/rsh.c b/usr.bin/rsh/rsh.c
index c663f79..7e3a530 100644
--- a/usr.bin/rsh/rsh.c
+++ b/usr.bin/rsh/rsh.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)rsh.c 8.3 (Berkeley) 4/6/94";
+static char sccsid[] = "@(#)rsh.c 8.4 (Berkeley) 4/29/95";
#endif /* not lint */
/*
@@ -189,6 +189,16 @@ main(argc, argv)
if (!(pw = getpwuid(uid = getuid())))
errx(1, "unknown user id");
+ /* Accept user1@host format, though "-l user2" overrides user1 */
+ p = strchr(host, '@');
+ if (p) {
+ *p = '\0';
+ if (!user && p > host)
+ user = host;
+ host = p + 1;
+ if (*host == '\0')
+ usage();
+ }
if (!user)
user = pw->pw_name;
@@ -466,7 +476,7 @@ usage()
{
(void)fprintf(stderr,
- "usage: rsh [-nd%s]%s[-l login] host [command]\n",
+ "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n",
#ifdef KERBEROS
#ifdef CRYPT
"x", " [-k realm] ");
diff --git a/usr.bin/sccs/Makefile b/usr.bin/sccs/Makefile
new file mode 100644
index 0000000..0ee9d1b
--- /dev/null
+++ b/usr.bin/sccs/Makefile
@@ -0,0 +1,5 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= sccs
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/sccs/PSD.doc/Makefile b/usr.bin/sccs/PSD.doc/Makefile
new file mode 100644
index 0000000..4e8ebba
--- /dev/null
+++ b/usr.bin/sccs/PSD.doc/Makefile
@@ -0,0 +1,7 @@
+# @(#)Makefile 8.2 (Berkeley) 5/23/94
+
+DIR= psd/14.sccs
+SRCS= sccs.me
+MACROS= -me
+
+.include <bsd.doc.mk>
diff --git a/usr.bin/sccs/PSD.doc/sccs.me b/usr.bin/sccs/PSD.doc/sccs.me
new file mode 100644
index 0000000..16dc3fb
--- /dev/null
+++ b/usr.bin/sccs/PSD.doc/sccs.me
@@ -0,0 +1,1609 @@
+.\" 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.
+.\"
+.\" @(#)sccs.me 8.2 (Berkeley) 6/1/94
+.\"
+.eh '\fRPSD:14-%\fP''\fRAn Introduction to the Source Code Control System\fP'
+.oh '\fRAn Introduction to the Source Code Control System\fP''\fRPSD:14-%\fP'
+.ds S \s-1SCCS\s0
+.ds I \s-1SID\s0
+.nr bi 8n
+.ev 1 \" only for keeps
+.ss 16
+.ev
+.\".he '\*S Introduction''%'
+.+c
+.(l C
+.sz 14
+.b
+An Introduction to the
+Source Code Control System
+.sz
+.r
+.sp
+Eric Allman
+.i "Project Ingres"
+.i "University of California at Berkeley"
+.)l
+.sp 3
+.pp
+.(f
+This is version 1.21 of this document.
+It was last modified on 12/5/80.
+.)f
+This document gives a quick introduction
+to using the Source Code Control System
+(\*S).
+The presentation is geared to programmers
+who are more concerned with
+what
+to do to get a task done
+rather than how it works;
+for this reason some of the examples
+are not well explained.
+For details of what the magic options do,
+see the section on
+.q "Further Information" .
+.(l F
+This is a working document.
+Please send any comments or suggestions
+to eric@Berkeley.Edu.
+.)l
+.sh 1 "Introduction"
+.pp
+\*S is a source management system.
+Such a system maintains a record of versions of a system;
+a record is kept with each set of changes
+of what the changes are,
+why they were made,
+and who made them and when.
+Old versions can be recovered,
+and different versions can be maintained simultaneously.
+In projects with more than one person,
+\*S will insure that two people are not
+editing the same file at the same time.
+.pp
+All versions of your program,
+plus the log and other information,
+is kept in a file called the
+.q "s-file" .
+There are three major operations
+that can be performed on the s-file:
+.np
+Get a file for compilation (not for editing).
+This operation retrieves a version of the file
+from the s-file.
+By default, the latest version is retrieved.
+This file is intended for compilation, printing, or whatever;
+it is specifically NOT intended to be edited
+or changed in any way;
+any changes made to a file retrieved
+in this way will probably be lost.
+.np
+Get a file for editing.
+This operation also retrieves a version of the file
+from the s-file,
+but this file is intended to be edited and then
+incorporated back into the s-file.
+Only one person may be editing a file at one time.
+.np
+Merge a file back into the s-file.
+This is the companion operation to (2).
+A new version number is assigned,
+and comments are saved explaining why this change was made.
+.sh 1 "Learning the Lingo"
+.pp
+There are a number of terms that are worth learning
+before we go any farther.
+.sh 2 "S-file"
+.pp
+The s-file
+is a single file that holds all the different versions
+of your file.
+The s-file is stored in
+differential format;
+.i i.e. ,
+only the differences between versions are stored,
+rather than the entire text of the new version.
+This saves disk space
+and allows selective changes to be removed later.
+Also included in the s-file
+is some header information for each version,
+including the comments given by the person who
+created the version explaining why the changes were made.
+.sh 2 "Deltas"
+.pp
+Each set of changes to the s-file
+(which is approximately [but not exactly!] equivalent
+to a version of the file)
+is called a
+.i delta .
+Although technically a delta only includes the
+.i changes
+made,
+in practice
+it is usual for
+each delta to be made with respect to
+all the deltas that have occurred before\**.
+.(f
+\**This matches normal usage, where the previous changes are not saved
+at all,
+so all changes are automatically based on all other changes
+that have happened through history.
+.)f
+However,
+it is possible to get a version of the file
+that has selected deltas removed out of the middle
+of the list of changes \*-
+equivalent to removing your changes later.
+.sh 2 "\*I's (or, version numbers)"
+.pp
+A \*I
+(\*S Id)
+is a number that represents a delta.
+This is normally a two-part number
+consisting of a
+.q release
+number and a
+.q level
+number.
+Normally the release number stays the same,
+however,
+it is possible to move into a new release
+if some major change is being made.
+.pp
+Since all past deltas are normally applied,
+the \*I of the final delta applied
+can be used to represent a version number of the file
+as a whole.
+.sh 2 "Id keywords"
+.pp
+When you get a version of a file
+with intent to compile and install it
+(\c
+.i i.e. ,
+something other than edit it),
+some special keywords are expanded inline
+by \*S.
+These
+.i "Id Keywords"
+can be used to include the current version number
+or other information into the file.
+All id keywords are of the form
+.b % \c
+.i x \c
+.b % ,
+where
+.i x
+is an upper case letter.
+For example,
+.b %\&I\&%
+is the \*I of the latest delta applied,
+.b %\&W\&%
+includes the module name,
+\*I,
+and a mark that makes it findable by a program,
+and
+.b %\&G\&%
+is the date of the latest delta applied.
+There are many others,
+most of which are of dubious usefulness.
+.pp
+When you get a file for editing,
+the id keywords are not expanded;
+this is so that after you put them back in to the s-file,
+they will be expanded automatically on each new version.
+But notice: if you were to get them
+expanded accidently,
+then your file would appear to be the same version
+forever more,
+which would of course defeat the purpose.
+Also,
+if you should install a version of the program
+without expanding the id keywords,
+it will be impossible to tell what version it is
+(since all it will have is
+.q %\&W\&%
+or whatever).
+.sh 1 "Creating \*S Files"
+.pp
+To put source files
+into
+\*S
+format, run the following shell script from csh:
+.(b
+mkdir SCCS save
+foreach i (*.[ch])
+ sccs admin \-i$i $i
+ mv $i save/$i
+end
+.)b
+This will put the named files
+into s-files
+in the subdirectory
+.q SCCS
+The files will be removed from the current directory
+and hidden away in the directory
+.q save ,
+so the next thing you will probably want to do
+is to get all the files
+(described below).
+When you are convinced that
+\*S has correctly created the s-files,
+you should remove the directory
+.q save .
+.pp
+If you want to have id keywords in the files,
+it is best to put them in before you create the s-files.
+If you do not,
+.i admin
+will print
+.q "No Id Keywords (cm7)" ,
+which is a warning message only.
+.sh 1 "Getting Files for Compilation"
+.pp
+To get a copy of the latest version
+of a file,
+run
+.(b
+sccs get prog.c
+.)b
+\*S will respond:
+.(b
+1.1
+87 lines
+.)b
+meaning that version 1.1 was retrieved\**
+.(f
+\**Actually,
+the \*I of the final delta applied was 1.1.
+.)f
+and that it has 87 lines.
+The file
+.i prog.c
+will be created
+in the current directory.
+The file will be read-only
+to remind you that you are not
+supposed to change it.
+.pp
+This copy of the file
+should not be changed,
+since \*S is unable
+to merge the changes
+back into the s-file.
+If you do make changes,
+they will be lost the next time
+someone does a
+.i get .
+.sh 1 "Changing Files (or, Creating Deltas)"
+.sh 2 "Getting a copy to edit"
+.pp
+To edit a source file,
+you must first get it,
+requesting permission to edit it\**:
+.(f
+\**The
+.q "edit"
+command is equivalent to using the \-e
+flag to
+.i "get" ,
+as:
+.(l
+sccs get \-e prog.c
+.)l
+Keep this in mind when reading other documentation.
+.)f
+.(b
+sccs edit prog.c
+.)b
+The response will be the same as with
+.i get
+except that it will also say:
+.(b
+New delta 1.2
+.)b
+You then edit it,
+using a standard text editor:
+.(b
+vi prog.c
+.)b
+.sh 2 "Merging the changes back into the s-file"
+.pp
+When the desired changes are made,
+you can put your changes into the
+\*S
+file using the
+.i delta
+command:
+.(b
+sccs delta prog.c
+.)b
+.pp
+Delta will prompt you for
+.q "comments?"
+before it merges the changes in.
+At this prompt you should type a one-line description
+of what the changes mean
+(more lines can be entered by ending each line
+except the last with a backslash\**).
+.(f
+\**Yes, this is a stupid default.
+.)f
+.i Delta
+will then type:
+.(b
+1.2
+5 inserted
+3 deleted
+84 unchanged
+.)b
+saying that delta 1.2 was created,
+and it inserted five lines,
+removed three lines,
+and left 84 lines unchanged\**.
+.(f
+\**Changes to a line are counted as a line deleted
+and a line inserted.
+.)f
+The
+.i prog.c
+file will be removed;
+it can be retrieved
+using
+.i get .
+.sh 2 "When to make deltas"
+.pp
+It is probably unwise to make a delta
+before every recompilation or test;
+otherwise,
+you tend to get a lot of deltas with comments like
+.q "fixed compilation problem in previous delta"
+or
+.q "fixed botch in 1.3" .
+However,
+it is very important to delta everything
+before installing a module for general use.
+A good technique is to edit the files you need,
+make all necessary changes and tests,
+compiling and editing as often as necessary
+without making deltas.
+When you are satisfied that you have a working version,
+delta everything being edited,
+re-get them,
+and recompile everything.
+.sh 2 "What's going on: the info command"
+.pp
+To find out what files where being edited,
+you can use:
+.(b
+sccs info
+.)b
+to print out all the files being edited
+and other information such as the name of the user
+who did the edit.
+Also,
+the command:
+.(b
+sccs check
+.)b
+is nearly equivalent to the
+.i info
+command,
+except that it is silent if nothing is being edited,
+and returns non-zero exit status if anything is being edited;
+it can be used in an
+.q install
+entry in a makefile
+to abort the install
+if anything has not been properly deltaed.
+.pp
+If you know that everything being edited should be deltaed,
+you can use:
+.(b
+sccs delta \`sccs tell\`
+.)b
+The
+.i tell
+command is similar to
+.i info
+except that only the names of files being edited
+are output,
+one per line.
+.pp
+All of these commands take a
+.b \-b
+flag
+to ignore
+.q branches
+(alternate versions, described later)
+and the
+.b \-u
+flag to only give files being edited by you.
+The
+.b \-u
+flag takes an optional
+.i user
+argument,
+giving only files being edited by that user.
+For example,
+.(b
+sccs info \-ujohn
+.)b
+gives a listing of files being edited by john.
+.sh 2 "ID keywords"
+.pp
+Id keywords can be inserted into your file
+that will be expanded automatically by
+.i get .
+For example,
+a line such as:
+.(b
+static char SccsId[] = "%\&W\&%\et%\&G\&%";
+.)b
+will be replaced with something like:
+.(b
+static char SccsId[] = "@\&(#)prog.c 1.2 08/29/80";
+.)b
+This tells you
+the name and version
+of the source file
+and the time the delta was created.
+The string
+.q "@\&(#)"
+is a special string
+which signals the beginning
+of an
+\*S
+Id keyword.
+.sh 3 "The what command"
+.pp
+To find out what version of a program
+is being run,
+use:
+.(b
+sccs what prog.c /usr/bin/prog
+.)b
+which will print all strings
+it finds that
+begin with
+.q "@\&(#)" .
+This works on all types of files,
+including binaries and libraries.
+For example, the above command will output something like:
+.(b
+prog.c:
+ prog.c 1.2 08/29/80
+/usr/bin/prog:
+ prog.c 1.1 02/05/79
+.)b
+From this I can see
+that the source that I have in prog.c
+will not compile into the same version
+as the binary in /usr/bin/prog.
+.sh 3 "Where to put id keywords"
+.pp
+ID keywords can be inserted anywhere,
+including in comments,
+but
+Id Keywords that are compiled into the object module
+are especially useful,
+since it lets you find out what version of
+the object is being run,
+as well as the source.
+However,
+there is a cost:
+data space is used up to store
+the keywords,
+and on small address space machines
+this may be prohibitive.
+.pp
+When you put id keywords into header files,
+it is important that you assign them to different variables.
+For example, you might use:
+.(b
+static char AccessSid[] = "%\&W\&% %\&G\&%";
+.)b
+in the file
+.i access.h
+and:
+.(b
+static char OpsysSid[] = "%\&W\&% %\&G\&%";
+.)b
+in the file
+.i opsys.h .
+Otherwise,
+you will get compilation errors because
+.q SccsId
+is redefined.
+The problem with this is that if the header file
+is included by many modules that are loaded together,
+the version number of that header file is included
+in the object module many times;
+you may find it more to your taste
+to put id keywords in header files
+in comments.
+.sh 2 "Keeping \*I's consistent across files"
+.pp
+With some care,
+it is possible to keep the \*I's consistent
+in multi-file systems.
+The trick here is to always
+.i edit
+all files
+at once.
+The changes can then be made
+to whatever files are necessary
+and then all files
+(even those not changed)
+are redeltaed.
+This can be done fairly easily
+by just specifying the name of the directory
+that the \*S files are in:
+.(b
+sccs edit SCCS
+.)b
+which will
+.i edit
+all files in that directory.
+To make the delta, use:
+.(b
+sccs delta SCCS
+.)b
+You will be prompted for comments only once.
+.sh 2 "Creating new releases"
+.pp
+When you want to create a new release
+of a program,
+you can specify the release number you want to create
+on the
+.i edit
+command.
+For example:
+.(b
+sccs edit \-r2 prog.c
+.)b
+will cause the next delta to be in release two
+(that is,
+it will be numbered 2.1).
+Future deltas will automatically be in release two.
+To change the release number
+of an entire system,
+use:
+.(b
+sccs edit \-r2 SCCS
+.)b
+.sh 1 "Restoring Old Versions"
+.sh 2 "Reverting to old versions"
+.pp
+Suppose that after delta 1.2
+was stable
+you made and released a delta 1.3.
+But this introduced a bug,
+so you made a delta 1.4 to correct it.
+But 1.4 was still buggy,
+and you decided you wanted to go back
+to the old version.
+You could
+revert to delta 1.2
+by choosing the \*I in a get:
+.(b
+sccs get \-r1.2 prog.c
+.)b
+This will produce a version of
+.i prog.c
+that is delta 1.2
+that can be reinstalled so that work can proceed.
+.pp
+In some cases you don't know
+what the \*I of the delta you want is.
+However,
+you can revert to the version of the program
+that was running as of a certain date
+by using the
+.b \-c
+(cutoff) flag.
+For example,
+.(b
+sccs get \-c800722120000 prog.c
+.)b
+will retrieve whatever version was current
+as of July 22, 1980
+at 12:00 noon.
+Trailing components can be stripped off
+(defaulting to their highest legal value),
+and punctuation can be inserted in the obvious
+places;
+for example,
+the above line could be equivalently stated:
+.(b
+sccs get \-c"80/07/22 12:00:00" prog.c
+.)b
+.sh 2 "Selectively deleting old deltas"
+.pp
+Suppose that you later decided
+that you liked the changes in delta 1.4,
+but that delta 1.3 should be removed.
+You could do this by
+.i excluding
+delta 1.3:
+.(b
+sccs edit \-x1.3 prog.c
+.)b
+.ne 1i
+When delta 1.5 is made,
+it will include the changes made
+in delta 1.4,
+but will exclude the changes made
+in delta 1.3.
+You can exclude a range of deltas
+using a dash.
+For example,
+if you want to get rid of 1.3 and 1.4
+you can use:
+.(b
+sccs edit \-x1.3\-1.4 prog.c
+.)b
+which will exclude all deltas from 1.3 to 1.4.
+Alternatively,
+.(b
+sccs edit \-x1.3\-1 prog.c
+.)b
+will exclude a range of deltas
+from 1.3 to the current highest delta in release 1.
+.pp
+In certain cases when using
+.b \-x
+(or
+.b \-i ;
+see below)
+there will be conflicts
+between versions;
+for example, it may be necessary
+to both include and delete
+a particular line.
+If this happens,
+\*S always prints out a message
+telling the range of lines effected;
+these lines should then be examined very carefully
+to see if the version \*S got
+is ok.
+.pp
+Since each delta
+(in the sense of
+.q "a set of changes" )
+can be excluded at will,
+that this makes it most useful
+to put each semantically distinct change
+into its own delta.
+.sh 1 "Auditing Changes"
+.sh 2 "The prt command"
+.pp
+When you created a delta,
+you presumably gave a reason for the delta
+to the
+.q "comments?"
+prompt.
+To print out these comments later,
+use:
+.(b
+sccs prt prog.c
+.)b
+This will produce
+a report
+for each delta
+of the \*I,
+time and date of creation,
+user who created the delta,
+number of lines inserted, deleted, and unchanged,
+and the comments associated with the delta.
+For example, the output of the above command might be:
+.(b
+D 1.2 80/08/29 12:35:31 bill 2 1 00005/00003/00084
+removed "-q" option
+.sp \n(psu
+D 1.1 79/02/05 00:19:31 eric 1 0 00087/00000/00000
+date and time created 80/06/10 00:19:31 by eric
+.)b
+.sh 2 "Finding why lines were inserted"
+.pp
+To find out
+why you inserted lines,
+you can get a copy of the file
+with each line
+preceded by the \*I that created it:
+.(b
+sccs get \-m prog.c
+.)b
+You can then find out
+what this delta did
+by printing the comments using
+.i prt .
+.pp
+To find out what lines are associated with a particular delta
+(\c
+.i e.g. ,
+1.3),
+use:
+.(b
+sccs get \-m \-p prog.c \(bv grep \'^1.3\'
+.)b
+The
+.b \-p
+flag causes \*S to output the generated source
+to the standard output rather than to a file.
+.sh 2 "Finding what changes you have made"
+.pp
+When you are editing a file,
+you can find out what changes you have made using:
+.(b
+sccs diffs prog.c
+.)b
+Most of the ``diff'' flags can be used.
+To pass the
+.b \-c
+flag,
+use
+.b \-C .
+.pp
+To compare two versions that are in deltas,
+use:
+.(b
+sccs sccsdiff -r1.3 -r1.6 prog.c
+.)b
+to see the differences between delta 1.3 and delta 1.6.
+.sh 1 "Shorthand Notations"
+.pp
+There are several sequences of commands that get
+executed frequently.
+.i Sccs
+tries to make it easy to do these.
+.sh 2 "Delget"
+.pp
+A frequent requirement is to make a delta of some file
+and then get that file.
+This can be done by using:
+.(b
+sccs delget prog.c
+.)b
+which is entirely equivalent to using:
+.(b
+sccs delta prog.c
+sccs get prog.c
+.)b
+The
+.q deledit
+command is equivalent to
+.q delget
+except that the
+.q edit
+command is used
+instead of the
+.q get
+command.
+.sh 2 "Fix"
+.pp
+Frequently, there are small bugs
+in deltas,
+e.g., compilation errors,
+for which there is no reason to maintain an audit trail.
+To
+.i replace
+a delta, use:
+.(b
+sccs fix \-r1.4 prog.c
+.)b
+This will get a copy of delta 1.4 of prog.c for you to edit
+and then delete delta 1.4 from the \*S file.
+When you do a delta of prog.c,
+it will be delta 1.4 again.
+The \-r flag must be specified,
+and the delta that is specified must be a leaf delta,
+i.e., no other deltas may have been made subsequent
+to the creation of that delta.
+.sh 2 "Unedit"
+.pp
+If you found you edited a file
+that you did not want to edit,
+you can back out by using:
+.(b
+sccs unedit prog.c
+.)b
+.sh 2 "The \-d flag"
+.pp
+If you are working on a project
+where the \*S code is in a directory somewhere,
+you may be able to simplify things
+by using a shell alias.
+For example,
+the alias:
+.(b
+alias syssccs sccs \-d/usr/src
+.)b
+will allow you to issue commands such as:
+.(b
+syssccs edit cmd/who.c
+.)b
+which will look for the file
+.q "/usr/src/cmd/SCCS/who.c" .
+The file
+.q who.c
+will always be created in your current directory
+regardless of the value of the \-d flag.
+.sh 1 "Using \*S on a Project"
+.pp
+Working on a project with several people
+has its own set of special problems.
+The main problem occurs when two people
+modify a file at the same time.
+\*S prevents this by locking an s-file
+while it is being edited.
+.pp
+As a result,
+files should not be reserved for editing
+unless they are actually being edited at the time,
+since this will prevent other people on the project
+from making necessary changes.
+For example,
+a good scenario for working might be:
+.(b
+sccs edit a.c g.c t.c
+vi a.c g.c t.c
+# do testing of the (experimental) version
+sccs delget a.c g.c t.c
+sccs info
+# should respond "Nothing being edited"
+make install
+.)b
+.pp
+As a general rule,
+all source files should be deltaed
+before installing the program for general use.
+This will insure that it is possible
+to restore any version in use at any time.
+.sh 1 "Saving Yourself"
+.sh 2 "Recovering a munged edit file"
+.pp
+Sometimes you may find
+that you have destroyed or trashed
+a file that you were trying to edit\**.
+.(f
+\**Or given up and decided to start over.
+.)f
+Unfortunately,
+you can't just remove it
+and re-\c
+.i edit
+it;
+\*S keeps track
+of the fact
+that someone is trying to edit it,
+so it won't let you do it again.
+Neither can you just get it using
+.i get ,
+since that would expand the Id keywords.
+Instead,
+you can say:
+.(b
+sccs get \-k prog.c
+.)b
+This will not expand the Id keywords,
+so it is safe to do a delta
+with it.
+.pp
+Alternately,
+you can
+.i unedit
+and
+.i edit
+the file.
+.sh 2 "Restoring the s-file"
+.pp
+In particularly bad circumstances,
+the \*S file itself
+may get munged.
+The most common way this happens
+is that it gets edited.
+Since \*S keeps a checksum,
+you will get errors every time you read the file.
+To fix this checksum, use:
+.(b
+sccs admin \-z prog.c
+.)b
+.sh 1 "Using the Admin Command"
+.pp
+There are a number of parameters that can be set
+using the
+.i admin
+command.
+The most interesting of these are flags.
+Flags can be added by using the
+.b \-f
+flag.
+For example:
+.(b
+sccs admin \-fd1 prog.c
+.)b
+sets the
+.q d
+flag to the value
+.q 1 .
+This flag can be deleted by using:
+.(b
+sccs admin \-dd prog.c
+.)b
+The most useful flags are:
+.nr ii 7n
+.ip "b"
+Allow branches to be made using the
+\-b
+flag to
+.i edit .
+.ip "d\fISID\fP"
+Default \*I to be used on a
+.i get
+or
+.i edit .
+If this is just a release number
+it constrains the
+version
+to a particular release only.
+.ip "i"
+Give a fatal error
+if there are no Id Keywords in a file.
+This is useful to guarantee that a version of the
+file does not get merged into the s-file
+that has the Id Keywords inserted as constants
+instead of internal forms.
+.ip "y"
+The
+.q type
+of the module.
+Actually,
+the value of this flag is unused by \*S
+except that it replaces the
+.b %\&Y\&%
+keyword.
+.pp
+The
+.b \-t\fIfile\fR
+flag can be used
+to store descriptive text
+from
+.i file .
+This descriptive text might be the documentation
+or a design and implementation document.
+Using the
+.b \-t
+flag insures that if the \*S file is sent,
+the documentation will be sent also.
+If
+.i file
+is omitted,
+the descriptive text is deleted.
+To see the descriptive text,
+use
+.q "prt \-t" .
+.pp
+The
+.i admin
+command can be used safely
+any number of times on files.
+A file need not be gotten
+for
+.i admin
+to work.
+.sh 1 "Maintaining Different Versions (Branches)"
+.pp
+Sometimes it is convenient
+to maintain an experimental version of a program
+for an extended period
+while normal maintenance continues
+on the version in production.
+This can be done using a
+.q branch.
+Normally deltas continue in a straight line,
+each depending on the delta before.
+Creating a branch
+.q "forks off"
+a version of the program.
+.pp
+The ability to create branches
+must be enabled in advance using:
+.(b
+sccs admin \-fb prog.c
+.)b
+The
+.b \-fb
+flag can be specified when the
+\*S file is first created.
+.sh 2 "Creating a branch"
+.pp
+To create a branch, use:
+.(b
+sccs edit \-b prog.c
+.)b
+This will create a branch
+with (for example) \*I 1.5.1.1.
+The deltas for this version
+will be numbered
+1.5.1.\c
+.i n .
+.sh 2 "Getting from a branch"
+.pp
+Deltas in a branch are normally not included
+when you do a get.
+To get these versions,
+you will have to say:
+.(b
+sccs get \-r1.5.1 prog.c
+.)b
+.sh 2 "Merging a branch back into the main trunk"
+.pp
+At some point you will have finished the experiment,
+and if it was successful
+you will want to incorporate it into the release version.
+But in the meantime
+someone may have created a delta 1.6
+that you don't want to lose.
+The commands:
+.(b
+sccs edit \-i1.5.1.1\-1.5.1 prog.c
+sccs delta prog.c
+.)b
+will merge all of your changes
+into the release system.
+If some of the changes conflict,
+get will print an error;
+the generated result
+should be carefully examined
+before the delta is made.
+.sh 2 "A more detailed example"
+.pp
+The following technique might be used
+to maintain a different version of a program.
+First,
+create a directory to contain the new version:
+.(b
+mkdir ../newxyz
+cd ../newxyz
+.)b
+Edit a copy of the program
+on a branch:
+.(b
+sccs \-d../xyz edit prog.c
+.)b
+When using the old version,
+be sure to use the
+.b \-b
+flag to info, check, tell, and clean
+to avoid confusion.
+For example, use:
+.(b
+sccs info \-b
+.)b
+when in the directory
+.q xyz .
+.pp
+If you want to save a copy of the program
+(still on the branch)
+back in the s-file,
+you can use:
+.(b
+sccs -d../xyz deledit prog.c
+.)b
+which will do a delta on the branch
+and reedit it for you.
+.pp
+When the experiment is complete, merge it back into the s-file
+using delta:
+.(b
+sccs -d../xyz delta prog.c
+.)b
+At this point you must decide whether this version
+should be merged back into the trunk
+(\c
+.i i.e.
+the default version),
+which may have undergone changes.
+If so, it can be merged using the
+.b \-i
+flag to
+.i edit
+as described above.
+.sh 2 "A warning"
+.pp
+Branches should be kept to a minimum.
+After the first branch from the trunk,
+\*I's are assigned rather haphazardly,
+and the structure gets complex fast.
+.sh 1 "Using \*S with Make"
+.pp
+\*S and make can be made to work together
+with a little care.
+A few sample makefiles
+for common applications are shown.
+.pp
+There are a few basic entries that every makefile
+ought to have.
+These are:
+.nr ii 1i
+.ip a.out
+(or whatever the makefile generates.)
+This entry regenerates whatever this makefile is
+supposed to regenerate.
+If the makefile regenerates many things,
+this should be called
+.q all
+and should in turn
+have dependencies on everything
+the makefile can generate.
+.ip install
+Moves the objects to the final
+resting place,
+doing any special
+.i chmod 's
+or
+.i ranlib 's
+as appropriate.
+.ip sources
+Creates all the source files from \*S files.
+.ip clean
+Removes all files from the current directory
+that can be regenerated from \*S files.
+.ip print
+Prints the contents of the directory.
+.lp
+The examples shown below are only partial examples,
+and may omit some of these entries
+when they are deemed to be obvious.
+.pp
+The
+.i clean
+entry should not remove files that can be
+regenerated from the \*S files.
+It is sufficiently important to have the
+source files around at all times
+that the only time they should be removed
+is when the directory is being mothballed.
+To do this, the command:
+.(b
+sccs clean
+.)b
+can be used.
+This will remove all files for which an s-file
+exists,
+but which is not being edited.
+.sh 2 "To maintain single programs"
+.pp
+Frequently there are directories with several
+largely unrelated programs
+(such as simple commands).
+These can be put into a single makefile:
+.(b
+LDFLAGS= \-i \-s
+.sp \n(psu
+prog: prog.o
+ $(CC) $(LDFLAGS) \-o prog prog.o
+prog.o: prog.c prog.h
+.sp \n(psu
+example: example.o
+ $(CC) $(LDFLAGS) \-o example example.o
+example.o: example.c
+.sp \n(psu
+\&.DEFAULT:
+ sccs get $<
+.)b
+The trick here
+is that the .DEFAULT rule
+is called every time
+something is needed
+that does not exist,
+and no other rule exists to make it.
+The explicit dependency of the
+.b \&.o
+file on the
+.b \&.c
+file is important.
+Another way of doing the same thing is:
+.(b
+SRCS= prog.c prog.h example.c
+.sp \n(psu
+LDFLAGS= \-i \-s
+.sp \n(psu
+prog: prog.o
+ $(CC) $(LDFLAGS) \-o prog prog.o
+prog.o: prog.h
+.sp \n(psu
+example: example.o
+ $(CC) $(LDFLAGS) \-o example example.o
+.sp \n(psu
+sources: $(SRCS)
+$(SRCS):
+ sccs get $@
+.)b
+There are a couple of advantages to this approach:
+(1) the explicit dependencies of the .o on the .c files are
+not needed,
+(2) there is an entry called "sources" so if you want to get
+all the sources you can just say
+.q "make sources" ,
+and
+(3) the makefile is less likely to do confusing things
+since it won't try to
+.i get
+things that do not exist.
+.sh 2 "To maintain a library"
+.pp
+Libraries that are largely static
+are best updated using explicit commands,
+since
+.i make
+doesn't know about updating them properly.
+However,
+libraries that are in the process of being developed
+can be handled quite adequately.
+The problem is that the .o files
+have to be kept out of the library
+as well as in the library.
+.(b
+# configuration information
+OBJS= a.o b.o c.o d.o
+SRCS= a.c b.c c.c d.s x.h y.h z.h
+TARG= /usr/lib
+.sp \n(psu
+# programs
+GET= sccs get
+REL=
+AR= \-ar
+RANLIB= ranlib
+.sp \n(psu
+lib.a: $(OBJS)
+ $(AR) rvu lib.a $(OBJS)
+ $(RANLIB) lib.a
+.sp \n(psu
+install: lib.a
+ sccs check
+ cp lib.a $(TARG)/lib.a
+ $(RANLIB) $(TARG)/lib.a
+.sp \n(psu
+sources: $(SRCS)
+$(SRCS):
+ $(GET) $(REL) $@
+.sp \n(psu
+print: sources
+ pr *.h *.[cs]
+clean:
+ rm \-f *.o
+ rm \-f core a.out $(LIB)
+.)b
+.pp
+The
+.q "$(REL)"
+in the get
+can be used to get old versions
+easily; for example:
+.(b
+make b.o REL=\-r1.3
+.)b
+.pp
+The
+.i install
+entry includes the line
+.q "sccs check"
+before anything else.
+This guarantees that all the s-files
+are up to date
+(\c
+.i i.e. ,
+nothing is being edited),
+and will abort the
+.i make
+if this condition is not met.
+.sh 2 "To maintain a large program"
+.(b
+OBJS= a.o b.o c.o d.o
+SRCS= a.c b.c c.y d.s x.h y.h z.h
+.sp \n(psu
+GET= sccs get
+REL=
+.sp \n(psu
+a.out: $(OBJS)
+ $(CC) $(LDFLAGS) $(OBJS) $(LIBS)
+.sp \n(psu
+sources: $(SRCS)
+$(SRCS):
+ $(GET) $(REL) $@
+.)b
+(The
+.i print
+and
+.i clean
+entries are identical to the previous case.)
+This makefile requires copies of the source and object files
+to be kept during development.
+It is probably also wise to include lines of the form:
+.(b
+a.o: x.h y.h
+b.o: z.h
+c.o: x.h y.h z.h
+z.h: x.h
+.)b
+so that modules will be recompiled
+if header files change.
+.pp
+Since
+.i make
+does not do transitive closure on dependencies,
+you may find in some makefiles lines like:
+.(b
+z.h: x.h
+ touch z.h
+.)b
+This would be used in cases where file z.h
+has a line:
+.(b
+#include "x.h"
+.)b
+in order to bring the mod date of z.h in line
+with the mod date of x.h.
+When you have a makefile such as above,
+the
+.i touch
+command can be removed completely;
+the equivalent effect will be achieved
+by doing an automatic
+.i get
+on z.h.
+.sh 1 "Further Information"
+.pp
+The
+.i "SCCS/PWB User's Manual"
+gives a deeper description
+of how to use \*S.
+Of particular interest
+are the numbering of branches,
+the l-file,
+which gives a description of what deltas were used on a get,
+and certain other \*S commands.
+.pp
+The \*S manual pages
+are a good last resort.
+These should be read by software managers
+and by people who want to know
+everything about everything.
+.pp
+Both of these documents were written without the
+.i sccs
+front end in mind,
+so most of the examples are slightly different from those
+in this document.
+.bp
+.sz 12
+.ce
+.b "Quick Reference"
+.sz
+.sp 2
+.sh 1 Commands 1
+.pp
+The following commands should all be preceded with
+.q sccs .
+This list is not exhaustive;
+for more options see
+.i "Further Information" .
+.ip get 9n
+Gets files for compilation (not for editing).
+Id keywords are expanded.
+.ba 9n
+.nr ii 8n
+.ip \-r\fI\*I\fP
+Version to get.
+.ip \-p
+Send to standard output rather than to the actual file.
+.ip \-k
+Don't expand id keywords.
+.ip \-i\fIlist\fP
+List of deltas to include.
+.ip \-x\fIlist\fP
+List of deltas to exclude.
+.ip \-m
+Precede each line with \*I of creating delta.
+.ip \-c\fIdate\fP
+Don't apply any deltas created after
+.i date.
+.ba
+.ip edit 9n
+Gets files for editing.
+Id keywords are not expanded.
+Should be matched with a
+.i delta
+command.
+.ba 9n
+.nr ii 8n
+.ip \-r\fI\*I\fP
+Same as
+.i get .
+If
+.i \*I
+specifies a release that does not yet exist,
+the highest numbered delta is retrieved
+and the new delta is numbered with
+.i \*I .
+.ip \-b
+Create a branch.
+.ip \-i\fIlist\fP
+Same as
+.i get .
+.ip \-x\fIlist\fP
+Same as
+.i get .
+.ba
+.ip delta 9n
+Merge a file gotten using
+.i edit
+back into the s-file.
+Collect comments about why this delta was made.
+.ip unedit 9n
+Remove a file that has been edited previously
+without merging the changes into the s-file.
+.ip prt 9n
+Produce a report of changes.
+.ba 9n
+.nr ii 5n
+.ip \-t
+Print the descriptive text.
+.ip \-e
+Print (nearly) everything.
+.ba
+.ip info 9n
+Give a list of all files being edited.
+.ba 9n
+.nr ii 5n
+.ip \-b
+Ignore branches.
+.ip \-u[\fIuser\fP]
+Ignore files not being edited by
+.i user .
+.ba
+.ip check 9n
+Same as
+.i info ,
+except that nothing is printed if nothing is being edited
+and exit status is returned.
+.ip tell 9n
+Same as
+.i info ,
+except that one line is produced per file being edited containing
+only the file name.
+.ip clean 9n
+Remove all files that can be regenerated from the
+s-file.
+.ip what 9n
+Find and print id keywords.
+.ip admin 9n
+Create or set parameters on s-files.
+.ba 9n
+.nr ii 8n
+.ip \-i\fIfile\fP
+Create, using
+.i file
+as the initial contents.
+.ip \-z
+Rebuild the checksum in case
+the file has been trashed.
+.ip \-f\fIflag\fP
+Turn on the
+.i flag .
+.ip \-d\fIflag\fP
+Turn off (delete) the
+.i flag .
+.ip \-t\fIfile\fP
+Replace the descriptive text
+in the s-file with the contents of
+.i file .
+If
+.i file
+is omitted,
+the text is deleted.
+Useful for storing documentation
+or
+.q "design & implementation"
+documents to insure they get distributed with the
+s-file.
+.lp
+Useful flags are:
+.ip b
+Allow branches to be made using the \-b flag to
+.i edit.
+.ip d\fI\*I\fP
+Default \*I to be used
+on a
+.i get
+or
+.i edit .
+.ip i
+Cause
+.q "No Id Keywords"
+error message
+to be a fatal error rather than a warning.
+.ip t
+The module
+.q type ;
+the value of this flag replaces the
+.b %\&Y\&%
+keyword.
+.ba
+.ip fix 9n
+Remove a delta and reedit it.
+.ip delget 9n
+Do a
+.i delta
+followed by a
+.i get .
+.ip deledit 9n
+Do a
+.i delta
+followed by an
+.i edit .
+.sh 1 "Id Keywords"
+.nr ii 6n
+.ip "%\&Z\&%"
+Expands to
+.q @\&(#)
+for the
+.i what
+command to find.
+.ip "%\&M\&%"
+The current module name,
+.i e.g.,
+.q prog.c .
+.ip "%\&I\&%"
+The highest \*I applied.
+.ip "%\&W\&%"
+A shorthand for
+.q "%\&Z\&%%\&M\&% <tab> %\&I\&%" .
+.ip "%\&G\&%"
+The date of the delta
+corresponding to the
+.q "%\&I\&%"
+keyword.
+.ip "%\&R\&%"
+The current release number,
+.i i.e. ,
+the first component of the
+.q "%\&I\&%"
+keyword.
+.ip "%\&Y\&%"
+Replaced by the value of the
+.b t
+flag
+(set by
+.i admin ).
diff --git a/usr.bin/sccs/PSD.doc/spell.ok b/usr.bin/sccs/PSD.doc/spell.ok
new file mode 100644
index 0000000..fb2fe24
--- /dev/null
+++ b/usr.bin/sccs/PSD.doc/spell.ok
@@ -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
diff --git a/usr.bin/sccs/pathnames.h b/usr.bin/sccs/pathnames.h
new file mode 100644
index 0000000..4da6874
--- /dev/null
+++ b/usr.bin/sccs/pathnames.h
@@ -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"
diff --git a/usr.bin/sccs/sccs.1 b/usr.bin/sccs/sccs.1
new file mode 100644
index 0000000..7f4990c
--- /dev/null
+++ b/usr.bin/sccs/sccs.1
@@ -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.
diff --git a/usr.bin/sccs/sccs.c b/usr.bin/sccs/sccs.c
new file mode 100644
index 0000000..2dfd76d
--- /dev/null
+++ b/usr.bin/sccs/sccs.c
@@ -0,0 +1,1621 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sccs.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/dir.h>
+#include <signal.h>
+#include <sysexits.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include "pathnames.h"
+
+/*
+** SCCS.C -- human-oriented front end to the SCCS system.
+**
+** Without trying to add any functionality to speak of, this
+** program tries to make SCCS a little more accessible to human
+** types. The main thing it does is automatically put the
+** string "SCCS/s." on the front of names. Also, it has a
+** couple of things that are designed to shorten frequent
+** combinations, e.g., "delget" which expands to a "delta"
+** and a "get".
+**
+** This program can also function as a setuid front end.
+** To do this, you should copy the source, renaming it to
+** whatever you want, e.g., "syssccs". Change any defaults
+** in the program (e.g., syssccs might default -d to
+** "/usr/src/sys"). Then recompile and put the result
+** as setuid to whomever you want. In this mode, sccs
+** knows to not run setuid for certain programs in order
+** to preserve security, and so forth.
+**
+** Usage:
+** sccs [flags] command [args]
+**
+** Flags:
+** -d<dir> <dir> represents a directory to search
+** out of. It should be a full pathname
+** for general usage. E.g., if <dir> is
+** "/usr/src/sys", then a reference to the
+** file "dev/bio.c" becomes a reference to
+** "/usr/src/sys/dev/bio.c".
+** -p<path> prepends <path> to the final component
+** of the pathname. By default, this is
+** "SCCS". For example, in the -d example
+** above, the path then gets modified to
+** "/usr/src/sys/dev/SCCS/s.bio.c". In
+** more common usage (without the -d flag),
+** "prog.c" would get modified to
+** "SCCS/s.prog.c". In both cases, the
+** "s." gets automatically prepended.
+** -r run as the real user.
+**
+** Commands:
+** admin,
+** get,
+** delta,
+** rmdel,
+** cdc,
+** etc. Straight out of SCCS; only difference
+** is that pathnames get modified as
+** described above.
+** enter Front end doing "sccs admin -i<name> <name>"
+** create Macro for "enter" followed by "get".
+** edit Macro for "get -e".
+** unedit Removes a file being edited, knowing
+** about p-files, etc.
+** delget Macro for "delta" followed by "get".
+** deledit Macro for "delta" followed by "get -e".
+** branch Macro for "get -b -e", followed by "delta
+** -s -n", followd by "get -e -t -g".
+** diffs "diff" the specified version of files
+** and the checked-out version.
+** print Macro for "prs -e" followed by "get -p -m".
+** tell List what files are being edited.
+** info Print information about files being edited.
+** clean Remove all files that can be
+** regenerated from SCCS files.
+** check Like info, but return exit status, for
+** use in makefiles.
+** fix Remove a top delta & reedit, but save
+** the previous changes in that delta.
+**
+** Compilation Flags:
+** UIDUSER -- determine who the user is by looking at the
+** uid rather than the login name -- for machines
+** where SCCS gets the user in this way.
+** SCCSDIR -- if defined, forces the -d flag to take on
+** this value. This is so that the setuid
+** aspects of this program cannot be abused.
+** This flag also disables the -p flag.
+** SCCSPATH -- the default for the -p flag.
+** MYNAME -- the title this program should print when it
+** gives error messages.
+**
+** Compilation Instructions:
+** cc -O -n -s sccs.c
+** The flags listed above can be -D defined to simplify
+** recompilation for variant versions.
+**
+** Author:
+** Eric Allman, UCB/INGRES
+** Copyright 1980 Regents of the University of California
+*/
+
+
+/******************* Configuration Information ********************/
+
+# ifndef SCCSPATH
+# define SCCSPATH "SCCS" /* pathname in which to find s-files */
+# endif NOT SCCSPATH
+
+# ifndef MYNAME
+# define MYNAME "sccs" /* name used for printing errors */
+# endif NOT MYNAME
+
+/**************** End of Configuration Information ****************/
+
+typedef char bool;
+# define TRUE 1
+# define FALSE 0
+
+# define bitset(bit, word) ((bool) ((bit) & (word)))
+
+struct sccsprog
+{
+ char *sccsname; /* name of SCCS routine */
+ short sccsoper; /* opcode, see below */
+ short sccsflags; /* flags, see below */
+ char *sccspath; /* pathname of binary implementing */
+};
+
+/* values for sccsoper */
+# define PROG 0 /* call a program */
+# define CMACRO 1 /* command substitution macro */
+# define FIX 2 /* fix a delta */
+# define CLEAN 3 /* clean out recreatable files */
+# define UNEDIT 4 /* unedit a file */
+# define SHELL 5 /* call a shell file (like PROG) */
+# define DIFFS 6 /* diff between sccs & file out */
+# define DODIFF 7 /* internal call to diff program */
+# define ENTER 8 /* enter new files */
+
+/* bits for sccsflags */
+# define NO_SDOT 0001 /* no s. on front of args */
+# define REALUSER 0002 /* protected (e.g., admin) */
+
+/* modes for the "clean", "info", "check" ops */
+# define CLEANC 0 /* clean command */
+# define INFOC 1 /* info command */
+# define CHECKC 2 /* check command */
+# define TELLC 3 /* give list of files being edited */
+
+/*
+** Description of commands known to this program.
+** First argument puts the command into a class. Second arg is
+** info regarding treatment of this command. Third arg is a
+** list of flags this command accepts from macros, etc. Fourth
+** arg is the pathname of the implementing program, or the
+** macro definition, or the arg to a sub-algorithm.
+*/
+
+struct sccsprog SccsProg[] = {
+ "admin", PROG, REALUSER, _PATH_SCCSADMIN,
+ "cdc", PROG, 0, _PATH_SCCSRMDEL,
+ "comb", PROG, 0, _PATH_SCCSCOMB,
+ "delta", PROG, 0, _PATH_SCCSDELTA,
+ "get", PROG, 0, _PATH_SCCSGET,
+ "help", PROG, NO_SDOT, _PATH_SCCSHELP,
+ "prs", PROG, 0, _PATH_SCCSPRS,
+ "prt", PROG, 0, _PATH_SCCSPRT,
+ "rmdel", PROG, REALUSER, _PATH_SCCSRMDEL,
+ "val", PROG, 0, _PATH_SCCSVAL,
+ "what", PROG, NO_SDOT, _PATH_SCCSWHAT,
+ "sccsdiff", SHELL, REALUSER, _PATH_SCCSDIFF,
+ "edit", CMACRO, NO_SDOT, "get -e",
+ "delget", CMACRO, NO_SDOT, "delta:mysrp/get:ixbeskcl -t",
+ "deledit", CMACRO, NO_SDOT,
+ "delta:mysrp -n/get:ixbskcl -e -t -g",
+ "fix", FIX, NO_SDOT, NULL,
+ "clean", CLEAN, REALUSER|NO_SDOT,
+ (char *) CLEANC,
+ "info", CLEAN, REALUSER|NO_SDOT,
+ (char *) INFOC,
+ "check", CLEAN, REALUSER|NO_SDOT,
+ (char *) CHECKC,
+ "tell", CLEAN, REALUSER|NO_SDOT,
+ (char *) TELLC,
+ "unedit", UNEDIT, NO_SDOT, NULL,
+ "diffs", DIFFS, NO_SDOT|REALUSER,
+ NULL,
+ "-diff", DODIFF, NO_SDOT|REALUSER,
+ _PATH_SCCSBDIFF,
+ "print", CMACRO, 0, "prs -e/get -p -m -s",
+ "branch", CMACRO, NO_SDOT,
+ "get:ixrc -e -b/delta: -s -n -ybranch-place-holder/get:pl -e -t -g",
+ "enter", ENTER, NO_SDOT, NULL,
+ "create", CMACRO, NO_SDOT, "enter/get:ixbeskcl -t",
+ NULL, -1, 0, NULL
+};
+
+/* one line from a p-file */
+struct pfile
+{
+ char *p_osid; /* old SID */
+ char *p_nsid; /* new SID */
+ char *p_user; /* user who did edit */
+ char *p_date; /* date of get */
+ char *p_time; /* time of get */
+ char *p_aux; /* extra info at end */
+};
+
+char *SccsPath = SCCSPATH; /* pathname of SCCS files */
+# ifdef SCCSDIR
+char *SccsDir = SCCSDIR; /* directory to begin search from */
+# else
+char *SccsDir = "";
+# endif
+char MyName[] = MYNAME; /* name used in messages */
+int OutFile = -1; /* override output file for commands */
+bool RealUser; /* if set, running as real user */
+# ifdef DEBUG
+bool Debug; /* turn on tracing */
+# endif
+# ifndef V6
+extern char *getenv();
+# endif V6
+
+char *gstrcat(), *strcat();
+char *gstrncat(), *strncat();
+char *gstrcpy(), *strcpy();
+#define FBUFSIZ BUFSIZ
+#define PFILELG 120
+
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ register char *p;
+ extern struct sccsprog *lookup();
+ register int i;
+# ifndef V6
+# ifndef SCCSDIR
+ register struct passwd *pw;
+ extern struct passwd *getpwnam();
+ char buf[FBUFSIZ];
+
+ /* pull "SccsDir" out of the environment (possibly) */
+ p = getenv("PROJECTDIR");
+ if (p != NULL && p[0] != '\0')
+ {
+ if (p[0] == '/')
+ SccsDir = p;
+ else
+ {
+ pw = getpwnam(p);
+ if (pw == NULL)
+ {
+ usrerr("user %s does not exist", p);
+ exit(EX_USAGE);
+ }
+ gstrcpy(buf, pw->pw_dir, sizeof(buf));
+ gstrcat(buf, "/src", sizeof(buf));
+ if (access(buf, 0) < 0)
+ {
+ gstrcpy(buf, pw->pw_dir, sizeof(buf));
+ gstrcat(buf, "/source", sizeof(buf));
+ if (access(buf, 0) < 0)
+ {
+ usrerr("project %s has no source!", p);
+ exit(EX_USAGE);
+ }
+ }
+ SccsDir = buf;
+ }
+ }
+# endif SCCSDIR
+# endif V6
+
+ /*
+ ** Detect and decode flags intended for this program.
+ */
+
+ if (argc < 2)
+ {
+ fprintf(stderr, "Usage: %s [flags] command [flags]\n", MyName);
+ exit(EX_USAGE);
+ }
+ argv[argc] = NULL;
+
+ if (lookup(argv[0]) == NULL)
+ {
+ while ((p = *++argv) != NULL)
+ {
+ if (*p != '-')
+ break;
+ switch (*++p)
+ {
+ case 'r': /* run as real user */
+ setuid(getuid());
+ RealUser++;
+ break;
+
+# ifndef SCCSDIR
+ case 'p': /* path of sccs files */
+ SccsPath = ++p;
+ if (SccsPath[0] == '\0' && argv[1] != NULL)
+ SccsPath = *++argv;
+ break;
+
+ case 'd': /* directory to search from */
+ SccsDir = ++p;
+ if (SccsDir[0] == '\0' && argv[1] != NULL)
+ SccsDir = *++argv;
+ break;
+# endif
+
+# ifdef DEBUG
+ case 'T': /* trace */
+ Debug++;
+ break;
+# endif
+
+ default:
+ usrerr("unknown option -%s", p);
+ break;
+ }
+ }
+ if (SccsPath[0] == '\0')
+ SccsPath = ".";
+ }
+
+ i = command(argv, FALSE, "");
+ exit(i);
+}
+
+/*
+** COMMAND -- look up and perform a command
+**
+** This routine is the guts of this program. Given an
+** argument vector, it looks up the "command" (argv[0])
+** in the configuration table and does the necessary stuff.
+**
+** Parameters:
+** argv -- an argument vector to process.
+** forkflag -- if set, fork before executing the command.
+** editflag -- if set, only include flags listed in the
+** sccsklets field of the command descriptor.
+** arg0 -- a space-seperated list of arguments to insert
+** before argv.
+**
+** Returns:
+** zero -- command executed ok.
+** else -- error status.
+**
+** Side Effects:
+** none.
+*/
+
+command(argv, forkflag, arg0)
+ char **argv;
+ bool forkflag;
+ char *arg0;
+{
+ register struct sccsprog *cmd;
+ register char *p;
+ char buf[FBUFSIZ];
+ extern struct sccsprog *lookup();
+ char *nav[1000];
+ char **np;
+ register char **ap;
+ register int i;
+ register char *q;
+ extern bool unedit();
+ int rval = 0;
+ extern char *index();
+ extern char *makefile();
+ char *editchs;
+ extern char *tail();
+
+# ifdef DEBUG
+ if (Debug)
+ {
+ printf("command:\n\t\"%s\"\n", arg0);
+ for (np = argv; *np != NULL; np++)
+ printf("\t\"%s\"\n", *np);
+ }
+# endif
+
+ /*
+ ** Copy arguments.
+ ** Copy from arg0 & if necessary at most one arg
+ ** from argv[0].
+ */
+
+ np = ap = &nav[1];
+ editchs = NULL;
+ for (p = arg0, q = buf; *p != '\0' && *p != '/'; )
+ {
+ *np++ = q;
+ while (*p == ' ')
+ p++;
+ while (*p != ' ' && *p != '\0' && *p != '/' && *p != ':')
+ *q++ = *p++;
+ *q++ = '\0';
+ if (*p == ':')
+ {
+ editchs = q;
+ while (*++p != '\0' && *p != '/' && *p != ' ')
+ *q++ = *p;
+ *q++ = '\0';
+ }
+ }
+ *np = NULL;
+ if (*ap == NULL)
+ *np++ = *argv++;
+
+ /*
+ ** Look up command.
+ ** At this point, *ap is the command name.
+ */
+
+ cmd = lookup(*ap);
+ if (cmd == NULL)
+ {
+ usrerr("Unknown command \"%s\"", *ap);
+ return (EX_USAGE);
+ }
+
+ /*
+ ** Copy remaining arguments doing editing as appropriate.
+ */
+
+ for (; *argv != NULL; argv++)
+ {
+ p = *argv;
+ if (*p == '-')
+ {
+ if (p[1] == '\0' || editchs == NULL || index(editchs, p[1]) != NULL)
+ *np++ = p;
+ }
+ else
+ {
+ if (!bitset(NO_SDOT, cmd->sccsflags))
+ p = makefile(p);
+ if (p != NULL)
+ *np++ = p;
+ }
+ }
+ *np = NULL;
+
+ /*
+ ** Interpret operation associated with this command.
+ */
+
+ switch (cmd->sccsoper)
+ {
+ case SHELL: /* call a shell file */
+ *ap = cmd->sccspath;
+ *--ap = "sh";
+ rval = callprog(_PATH_BSHELL, cmd->sccsflags, ap, forkflag);
+ break;
+
+ case PROG: /* call an sccs prog */
+ rval = callprog(cmd->sccspath, cmd->sccsflags, ap, forkflag);
+ break;
+
+ case CMACRO: /* command macro */
+ /* step through & execute each part of the macro */
+ for (p = cmd->sccspath; *p != '\0'; p++)
+ {
+ q = p;
+ while (*p != '\0' && *p != '/')
+ p++;
+ rval = command(&ap[1], *p != '\0', q);
+ if (rval != 0)
+ break;
+ }
+ break;
+
+ case FIX: /* fix a delta */
+ if (ap[1]==0 || strncmp(ap[1], "-r", 2)!=0)
+ {
+ usrerr("-r flag needed for fix command");
+ rval = EX_USAGE;
+ break;
+ }
+
+ /* get the version with all changes */
+ rval = command(&ap[1], TRUE, "get -k");
+
+ /* now remove that version from the s-file */
+ if (rval == 0)
+ rval = command(&ap[1], TRUE, "rmdel:r");
+
+ /* and edit the old version (but don't clobber new vers) */
+ if (rval == 0)
+ rval = command(&ap[2], FALSE, "get -e -g");
+ break;
+
+ case CLEAN:
+ rval = clean((int) cmd->sccspath, ap);
+ break;
+
+ case UNEDIT:
+ for (argv = np = &ap[1]; *argv != NULL; argv++)
+ {
+ if (unedit(*argv))
+ *np++ = *argv;
+ }
+ *np = NULL;
+
+ /* get all the files that we unedited successfully */
+ if (np > &ap[1])
+ rval = command(&ap[1], FALSE, "get");
+ break;
+
+ case DIFFS: /* diff between s-file & edit file */
+ /* find the end of the flag arguments */
+ for (np = &ap[1]; *np != NULL && **np == '-'; np++)
+ continue;
+ argv = np;
+
+ /* for each file, do the diff */
+ p = argv[1];
+ while (*np != NULL)
+ {
+ /* messy, but we need a null terminated argv */
+ *argv = *np++;
+ argv[1] = NULL;
+ i = dodiff(ap, tail(*argv));
+ if (rval == 0)
+ rval = i;
+ argv[1] = p;
+ }
+ break;
+
+ case DODIFF: /* internal diff call */
+ setuid(getuid());
+ for (np = ap; *np != NULL; np++)
+ {
+ if ((*np)[0] == '-' && (*np)[1] == 'C')
+ (*np)[1] = 'c';
+ }
+
+ /* insert "-" argument */
+ np[1] = NULL;
+ np[0] = np[-1];
+ np[-1] = "-";
+
+ /* execute the diff program of choice */
+# ifndef V6
+ execvp("diff", ap);
+# endif
+ execv(cmd->sccspath, argv);
+ syserr("cannot exec %s", cmd->sccspath);
+ exit(EX_OSERR);
+
+ case ENTER: /* enter new sccs files */
+ /* skip over flag arguments */
+ for (np = &ap[1]; *np != NULL && **np == '-'; np++)
+ continue;
+ argv = np;
+
+ /* do an admin for each file */
+ p = argv[1];
+ while (*np != NULL)
+ {
+ printf("\n%s:\n", *np);
+ strcpy(buf, "-i");
+ gstrcat(buf, *np, sizeof(buf));
+ ap[0] = buf;
+ argv[0] = tail(*np);
+ argv[1] = NULL;
+ rval = command(ap, TRUE, "admin");
+ argv[1] = p;
+ if (rval == 0)
+ {
+ strcpy(buf, ",");
+ gstrcat(buf, tail(*np), sizeof(buf));
+ if (link(*np, buf) >= 0)
+ unlink(*np);
+ }
+ np++;
+ }
+ break;
+
+ default:
+ syserr("oper %d", cmd->sccsoper);
+ exit(EX_SOFTWARE);
+ }
+# ifdef DEBUG
+ if (Debug)
+ printf("command: rval=%d\n", rval);
+# endif
+ return (rval);
+}
+
+/*
+** LOOKUP -- look up an SCCS command name.
+**
+** Parameters:
+** name -- the name of the command to look up.
+**
+** Returns:
+** ptr to command descriptor for this command.
+** NULL if no such entry.
+**
+** Side Effects:
+** none.
+*/
+
+struct sccsprog *
+lookup(name)
+ char *name;
+{
+ register struct sccsprog *cmd;
+
+ for (cmd = SccsProg; cmd->sccsname != NULL; cmd++)
+ {
+ if (strcmp(cmd->sccsname, name) == 0)
+ return (cmd);
+ }
+ return (NULL);
+}
+
+/*
+** CALLPROG -- call a program
+**
+** Used to call the SCCS programs.
+**
+** Parameters:
+** progpath -- pathname of the program to call.
+** flags -- status flags from the command descriptors.
+** argv -- an argument vector to pass to the program.
+** forkflag -- if true, fork before calling, else just
+** exec.
+**
+** Returns:
+** The exit status of the program.
+** Nothing if forkflag == FALSE.
+**
+** Side Effects:
+** Can exit if forkflag == FALSE.
+*/
+
+callprog(progpath, flags, argv, forkflag)
+ char *progpath;
+ short flags;
+ char **argv;
+ bool forkflag;
+{
+ register int i;
+ register int wpid;
+ auto int st;
+ register int sigcode;
+ register int coredumped;
+ register const char *sigmsg;
+ char sigmsgbuf[10+1]; /* "Signal 127" + terminating '\0' */
+
+# ifdef DEBUG
+ if (Debug)
+ {
+ printf("callprog:\n");
+ for (i = 0; argv[i] != NULL; i++)
+ printf("\t\"%s\"\n", argv[i]);
+ }
+# endif
+
+ if (*argv == NULL)
+ return (-1);
+
+ /*
+ ** Fork if appropriate.
+ */
+
+ if (forkflag)
+ {
+# ifdef DEBUG
+ if (Debug)
+ printf("Forking\n");
+# endif
+ i = fork();
+ if (i < 0)
+ {
+ syserr("cannot fork");
+ exit(EX_OSERR);
+ }
+ else if (i > 0)
+ {
+ while ((wpid = wait(&st)) != -1 && wpid != i)
+ ;
+ if ((sigcode = st & 0377) == 0)
+ st = (st >> 8) & 0377;
+ else
+ {
+ coredumped = sigcode & 0200;
+ sigcode &= 0177;
+ if (sigcode != SIGINT && sigcode != SIGPIPE)
+ {
+ if (sigcode < NSIG)
+ sigmsg = sys_siglist[sigcode];
+ else
+ {
+ sprintf(sigmsgbuf, "Signal %d",
+ sigcode);
+ sigmsg = sigmsgbuf;
+ }
+ fprintf(stderr, "sccs: %s: %s%s", argv[0],
+ sigmsg,
+ coredumped ? " - core dumped": "");
+ }
+ st = EX_SOFTWARE;
+ }
+ if (OutFile >= 0)
+ {
+ close(OutFile);
+ OutFile = -1;
+ }
+ return (st);
+ }
+ }
+ else if (OutFile >= 0)
+ {
+ syserr("callprog: setting stdout w/o forking");
+ exit(EX_SOFTWARE);
+ }
+
+ /* set protection as appropriate */
+ if (bitset(REALUSER, flags))
+ setuid(getuid());
+
+ /* change standard input & output if needed */
+ if (OutFile >= 0)
+ {
+ close(1);
+ dup(OutFile);
+ close(OutFile);
+ }
+
+ /* call real SCCS program */
+ execv(progpath, argv);
+ syserr("cannot execute %s", progpath);
+ exit(EX_UNAVAILABLE);
+ /*NOTREACHED*/
+}
+
+/*
+** MAKEFILE -- make filename of SCCS file
+**
+** If the name passed is already the name of an SCCS file,
+** just return it. Otherwise, munge the name into the name
+** of the actual SCCS file.
+**
+** There are cases when it is not clear what you want to
+** do. For example, if SccsPath is an absolute pathname
+** and the name given is also an absolute pathname, we go
+** for SccsPath (& only use the last component of the name
+** passed) -- this is important for security reasons (if
+** sccs is being used as a setuid front end), but not
+** particularly intuitive.
+**
+** Parameters:
+** name -- the file name to be munged.
+**
+** Returns:
+** The pathname of the sccs file.
+** NULL on error.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+makefile(name)
+ char *name;
+{
+ register char *p;
+ char buf[3*FBUFSIZ];
+ extern char *malloc();
+ extern char *rindex();
+ extern bool safepath();
+ extern bool isdir();
+ register char *q;
+
+ p = rindex(name, '/');
+ if (p == NULL)
+ p = name;
+ else
+ p++;
+
+ /*
+ ** Check to see that the path is "safe", i.e., that we
+ ** are not letting some nasty person use the setuid part
+ ** of this program to look at or munge some presumably
+ ** hidden files.
+ */
+
+ if (SccsDir[0] == '/' && !safepath(name))
+ return (NULL);
+
+ /*
+ ** Create the base pathname.
+ */
+
+ /* first the directory part */
+ if (SccsDir[0] != '\0' && name[0] != '/' && strncmp(name, "./", 2) != 0)
+ {
+ gstrcpy(buf, SccsDir, sizeof(buf));
+ gstrcat(buf, "/", sizeof(buf));
+ }
+ else
+ gstrcpy(buf, "", sizeof(buf));
+
+ /* then the head of the pathname */
+ gstrncat(buf, name, p - name, sizeof(buf));
+ q = &buf[strlen(buf)];
+
+ /* now copy the final part of the name, in case useful */
+ gstrcpy(q, p, sizeof(buf));
+
+ /* so is it useful? */
+ if (strncmp(p, "s.", 2) != 0 && !isdir(buf))
+ {
+ /* sorry, no; copy the SCCS pathname & the "s." */
+ gstrcpy(q, SccsPath, sizeof(buf));
+ gstrcat(buf, "/s.", sizeof(buf));
+
+ /* and now the end of the name */
+ gstrcat(buf, p, sizeof(buf));
+ }
+
+ /* if i haven't changed it, why did I do all this? */
+ if (strcmp(buf, name) == 0)
+ p = name;
+ else
+ {
+ /* but if I have, squirrel it away */
+ p = malloc(strlen(buf) + 1);
+ if (p == NULL)
+ {
+ perror("Sccs: no mem");
+ exit(EX_OSERR);
+ }
+ strcpy(p, buf);
+ }
+
+ return (p);
+}
+
+/*
+** ISDIR -- return true if the argument is a directory.
+**
+** Parameters:
+** name -- the pathname of the file to check.
+**
+** Returns:
+** TRUE if 'name' is a directory, FALSE otherwise.
+**
+** Side Effects:
+** none.
+*/
+
+bool
+isdir(name)
+ char *name;
+{
+ struct stat stbuf;
+
+ return (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR);
+}
+
+/*
+** SAFEPATH -- determine whether a pathname is "safe"
+**
+** "Safe" pathnames only allow you to get deeper into the
+** directory structure, i.e., full pathnames and ".." are
+** not allowed.
+**
+** Parameters:
+** p -- the name to check.
+**
+** Returns:
+** TRUE -- if the path is safe.
+** FALSE -- if the path is not safe.
+**
+** Side Effects:
+** Prints a message if the path is not safe.
+*/
+
+bool
+safepath(p)
+ register char *p;
+{
+ extern char *index();
+
+ if (*p != '/')
+ {
+ while (strncmp(p, "../", 3) != 0 && strcmp(p, "..") != 0)
+ {
+ p = index(p, '/');
+ if (p == NULL)
+ return (TRUE);
+ p++;
+ }
+ }
+
+ printf("You may not use full pathnames or \"..\"\n");
+ return (FALSE);
+}
+
+/*
+** CLEAN -- clean out recreatable files
+**
+** Any file for which an "s." file exists but no "p." file
+** exists in the current directory is purged.
+**
+** Parameters:
+** mode -- tells whether this came from a "clean", "info", or
+** "check" command.
+** argv -- the rest of the argument vector.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** Removes files in the current directory.
+** Prints information regarding files being edited.
+** Exits if a "check" command.
+*/
+
+clean(mode, argv)
+ int mode;
+ char **argv;
+{
+ struct direct *dir;
+ char buf[FBUFSIZ];
+ char *bufend;
+ register DIR *dirp;
+ register char *basefile;
+ bool gotedit;
+ bool gotpfent;
+ FILE *pfp;
+ bool nobranch = FALSE;
+ extern struct pfile *getpfent();
+ register struct pfile *pf;
+ register char **ap;
+ extern char *username();
+ char *usernm = NULL;
+ char *subdir = NULL;
+ char *cmdname;
+
+ /*
+ ** Process the argv
+ */
+
+ cmdname = *argv;
+ for (ap = argv; *++ap != NULL; )
+ {
+ if (**ap == '-')
+ {
+ /* we have a flag */
+ switch ((*ap)[1])
+ {
+ case 'b':
+ nobranch = TRUE;
+ break;
+
+ case 'u':
+ if ((*ap)[2] != '\0')
+ usernm = &(*ap)[2];
+ else if (ap[1] != NULL && ap[1][0] != '-')
+ usernm = *++ap;
+ else
+ usernm = username();
+ break;
+ }
+ }
+ else
+ {
+ if (subdir != NULL)
+ usrerr("too many args");
+ else
+ subdir = *ap;
+ }
+ }
+
+ /*
+ ** Find and open the SCCS directory.
+ */
+
+ gstrcpy(buf, SccsDir, sizeof(buf));
+ if (buf[0] != '\0')
+ gstrcat(buf, "/", sizeof(buf));
+ if (subdir != NULL)
+ {
+ gstrcat(buf, subdir, sizeof(buf));
+ gstrcat(buf, "/", sizeof(buf));
+ }
+ gstrcat(buf, SccsPath, sizeof(buf));
+ bufend = &buf[strlen(buf)];
+
+ dirp = opendir(buf);
+ if (dirp == NULL)
+ {
+ usrerr("cannot open %s", buf);
+ return (EX_NOINPUT);
+ }
+
+ /*
+ ** Scan the SCCS directory looking for s. files.
+ ** gotedit tells whether we have tried to clean any
+ ** files that are being edited.
+ */
+
+ gotedit = FALSE;
+ while (dir = readdir(dirp)) {
+ if (strncmp(dir->d_name, "s.", 2) != 0)
+ continue;
+
+ /* got an s. file -- see if the p. file exists */
+ gstrcpy(bufend, "/p.", sizeof(buf));
+ basefile = bufend + 3;
+ gstrcpy(basefile, &dir->d_name[2], sizeof(buf));
+
+ /*
+ ** open and scan the p-file.
+ ** 'gotpfent' tells if we have found a valid p-file
+ ** entry.
+ */
+
+ pfp = fopen(buf, "r");
+ gotpfent = FALSE;
+ if (pfp != NULL)
+ {
+ /* the file exists -- report it's contents */
+ while ((pf = getpfent(pfp)) != NULL)
+ {
+ if (nobranch && isbranch(pf->p_nsid))
+ continue;
+ if (usernm != NULL && strcmp(usernm, pf->p_user) != 0 && mode != CLEANC)
+ continue;
+ gotedit = TRUE;
+ gotpfent = TRUE;
+ if (mode == TELLC)
+ {
+ printf("%s\n", basefile);
+ break;
+ }
+ printf("%12s: being edited: ", basefile);
+ putpfent(pf, stdout);
+ }
+ fclose(pfp);
+ }
+
+ /* the s. file exists and no p. file exists -- unlink the g-file */
+ if (mode == CLEANC && !gotpfent)
+ {
+ char unlinkbuf[FBUFSIZ];
+ gstrcpy(unlinkbuf, &dir->d_name[2], sizeof(unlinkbuf));
+ unlink(unlinkbuf);
+ }
+ }
+
+ /* cleanup & report results */
+ closedir(dirp);
+ if (!gotedit && mode == INFOC)
+ {
+ printf("Nothing being edited");
+ if (nobranch)
+ printf(" (on trunk)");
+ if (usernm == NULL)
+ printf("\n");
+ else
+ printf(" by %s\n", usernm);
+ }
+ if (mode == CHECKC)
+ exit(gotedit);
+ return (EX_OK);
+}
+
+/*
+** ISBRANCH -- is the SID a branch?
+**
+** Parameters:
+** sid -- the sid to check.
+**
+** Returns:
+** TRUE if the sid represents a branch.
+** FALSE otherwise.
+**
+** Side Effects:
+** none.
+*/
+
+isbranch(sid)
+ char *sid;
+{
+ register char *p;
+ int dots;
+
+ dots = 0;
+ for (p = sid; *p != '\0'; p++)
+ {
+ if (*p == '.')
+ dots++;
+ if (dots > 1)
+ return (TRUE);
+ }
+ return (FALSE);
+}
+
+/*
+** UNEDIT -- unedit a file
+**
+** Checks to see that the current user is actually editting
+** the file and arranges that s/he is not editting it.
+**
+** Parameters:
+** fn -- the name of the file to be unedited.
+**
+** Returns:
+** TRUE -- if the file was successfully unedited.
+** FALSE -- if the file was not unedited for some
+** reason.
+**
+** Side Effects:
+** fn is removed
+** entries are removed from pfile.
+*/
+
+bool
+unedit(fn)
+ char *fn;
+{
+ register FILE *pfp;
+ char *cp, *pfn;
+ static char tfn[] = _PATH_TMP;
+ FILE *tfp;
+ register char *q;
+ bool delete = FALSE;
+ bool others = FALSE;
+ char *myname;
+ extern char *username();
+ struct pfile *pent;
+ extern struct pfile *getpfent();
+ char buf[PFILELG];
+ extern char *makefile(), *rindex(), *tail();
+
+ /* make "s." filename & find the trailing component */
+ pfn = makefile(fn);
+ if (pfn == NULL)
+ return (FALSE);
+ q = rindex(pfn, '/');
+ if (q == NULL)
+ q = &pfn[-1];
+ if (q[1] != 's' || q[2] != '.')
+ {
+ usrerr("bad file name \"%s\"", fn);
+ return (FALSE);
+ }
+
+ /* turn "s." into "p." & try to open it */
+ *++q = 'p';
+
+ pfp = fopen(pfn, "r");
+ if (pfp == NULL)
+ {
+ printf("%12s: not being edited\n", fn);
+ return (FALSE);
+ }
+
+ /* create temp file for editing p-file */
+ mktemp(tfn);
+ tfp = fopen(tfn, "w");
+ if (tfp == NULL)
+ {
+ usrerr("cannot create \"%s\"", tfn);
+ exit(EX_OSERR);
+ }
+
+ /* figure out who I am */
+ myname = username();
+
+ /*
+ ** Copy p-file to temp file, doing deletions as needed.
+ */
+
+ while ((pent = getpfent(pfp)) != NULL)
+ {
+ if (strcmp(pent->p_user, myname) == 0)
+ {
+ /* a match */
+ delete++;
+ }
+ else
+ {
+ /* output it again */
+ putpfent(pent, tfp);
+ others++;
+ }
+ }
+
+ /*
+ * Before changing anything, make sure we can remove
+ * the file in question (assuming it exists).
+ */
+ if (delete) {
+ extern int errno;
+
+ cp = tail(fn);
+ errno = 0;
+ if (access(cp, 0) < 0 && errno != ENOENT)
+ goto bad;
+ if (errno == 0)
+ /*
+ * This is wrong, but the rest of the program
+ * has built in assumptions about "." as well,
+ * so why make unedit a special case?
+ */
+ if (access(".", 2) < 0) {
+ bad:
+ printf("%12s: can't remove\n", cp);
+ fclose(tfp);
+ fclose(pfp);
+ unlink(tfn);
+ return (FALSE);
+ }
+ }
+ /* do final cleanup */
+ if (others)
+ {
+ /* copy it back (perhaps it should be linked?) */
+ if (freopen(tfn, "r", tfp) == NULL)
+ {
+ syserr("cannot reopen \"%s\"", tfn);
+ exit(EX_OSERR);
+ }
+ if (freopen(pfn, "w", pfp) == NULL)
+ {
+ usrerr("cannot create \"%s\"", pfn);
+ return (FALSE);
+ }
+ while (fgets(buf, sizeof buf, tfp) != NULL)
+ fputs(buf, pfp);
+ }
+ else
+ {
+ /* it's empty -- remove it */
+ unlink(pfn);
+ }
+ fclose(tfp);
+ fclose(pfp);
+ unlink(tfn);
+
+ /* actually remove the g-file */
+ if (delete)
+ {
+ /*
+ * Since we've checked above, we can
+ * use the return from unlink to
+ * determine if the file existed or not.
+ */
+ if (unlink(cp) >= 0)
+ printf("%12s: removed\n", cp);
+ return (TRUE);
+ }
+ else
+ {
+ printf("%12s: not being edited by you\n", fn);
+ return (FALSE);
+ }
+}
+
+/*
+** DODIFF -- diff an s-file against a g-file
+**
+** Parameters:
+** getv -- argv for the 'get' command.
+** gfile -- name of the g-file to diff against.
+**
+** Returns:
+** Result of get.
+**
+** Side Effects:
+** none.
+*/
+
+dodiff(getv, gfile)
+ char **getv;
+ char *gfile;
+{
+ int pipev[2];
+ int rval;
+ register int i;
+ register int pid;
+ auto int st;
+ extern int errno;
+ sig_t osig;
+
+ printf("\n------- %s -------\n", gfile);
+ fflush(stdout);
+
+ /* create context for diff to run in */
+ if (pipe(pipev) < 0)
+ {
+ syserr("dodiff: pipe failed");
+ exit(EX_OSERR);
+ }
+ if ((pid = fork()) < 0)
+ {
+ syserr("dodiff: fork failed");
+ exit(EX_OSERR);
+ }
+ else if (pid > 0)
+ {
+ /* in parent; run get */
+ OutFile = pipev[1];
+ close(pipev[0]);
+ rval = command(&getv[1], TRUE, "get:rcixt -s -k -p");
+ osig = signal(SIGINT, SIG_IGN);
+ while (((i = wait(&st)) >= 0 && i != pid) || errno == EINTR)
+ errno = 0;
+ signal(SIGINT, osig);
+ /* ignore result of diff */
+ }
+ else
+ {
+ /* in child, run diff */
+ if (close(pipev[1]) < 0 || close(0) < 0 ||
+ dup(pipev[0]) != 0 || close(pipev[0]) < 0)
+ {
+ syserr("dodiff: magic failed");
+ exit(EX_OSERR);
+ }
+ command(&getv[1], FALSE, "-diff:elsfhbC");
+ }
+ return (rval);
+}
+
+/*
+** TAIL -- return tail of filename.
+**
+** Parameters:
+** fn -- the filename.
+**
+** Returns:
+** a pointer to the tail of the filename; e.g., given
+** "cmd/ls.c", "ls.c" is returned.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+tail(fn)
+ register char *fn;
+{
+ register char *p;
+
+ for (p = fn; *p != 0; p++)
+ if (*p == '/' && p[1] != '\0' && p[1] != '/')
+ fn = &p[1];
+ return (fn);
+}
+
+/*
+** GETPFENT -- get an entry from the p-file
+**
+** Parameters:
+** pfp -- p-file file pointer
+**
+** Returns:
+** pointer to p-file struct for next entry
+** NULL on EOF or error
+**
+** Side Effects:
+** Each call wipes out results of previous call.
+*/
+
+struct pfile *
+getpfent(pfp)
+ FILE *pfp;
+{
+ static struct pfile ent;
+ static char buf[PFILELG];
+ register char *p;
+ extern char *nextfield();
+
+ if (fgets(buf, sizeof buf, pfp) == NULL)
+ return (NULL);
+
+ ent.p_osid = p = buf;
+ ent.p_nsid = p = nextfield(p);
+ ent.p_user = p = nextfield(p);
+ ent.p_date = p = nextfield(p);
+ ent.p_time = p = nextfield(p);
+ ent.p_aux = p = nextfield(p);
+
+ return (&ent);
+}
+
+
+char *
+nextfield(p)
+ register char *p;
+{
+ if (p == NULL || *p == '\0')
+ return (NULL);
+ while (*p != ' ' && *p != '\n' && *p != '\0')
+ p++;
+ if (*p == '\n' || *p == '\0')
+ {
+ *p = '\0';
+ return (NULL);
+ }
+ *p++ = '\0';
+ return (p);
+}
+ /*
+** PUTPFENT -- output a p-file entry to a file
+**
+** Parameters:
+** pf -- the p-file entry
+** f -- the file to put it on.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** pf is written onto file f.
+*/
+
+putpfent(pf, f)
+ register struct pfile *pf;
+ register FILE *f;
+{
+ fprintf(f, "%s %s %s %s %s", pf->p_osid, pf->p_nsid,
+ pf->p_user, pf->p_date, pf->p_time);
+ if (pf->p_aux != NULL)
+ fprintf(f, " %s", pf->p_aux);
+ else
+ fprintf(f, "\n");
+}
+
+/*
+** USRERR -- issue user-level error
+**
+** Parameters:
+** f -- format string.
+** p1-p3 -- parameters to a printf.
+**
+** Returns:
+** -1
+**
+** Side Effects:
+** none.
+*/
+
+/*VARARGS1*/
+usrerr(f, p1, p2, p3)
+ char *f;
+{
+ fprintf(stderr, "\n%s: ", MyName);
+ fprintf(stderr, f, p1, p2, p3);
+ fprintf(stderr, "\n");
+
+ return (-1);
+}
+
+/*
+** SYSERR -- print system-generated error.
+**
+** Parameters:
+** f -- format string to a printf.
+** p1, p2, p3 -- parameters to f.
+**
+** Returns:
+** never.
+**
+** Side Effects:
+** none.
+*/
+
+/*VARARGS1*/
+syserr(f, p1, p2, p3)
+ char *f;
+{
+ extern int errno;
+
+ fprintf(stderr, "\n%s SYSERR: ", MyName);
+ fprintf(stderr, f, p1, p2, p3);
+ fprintf(stderr, "\n");
+ if (errno == 0)
+ exit(EX_SOFTWARE);
+ else
+ {
+ perror(NULL);
+ exit(EX_OSERR);
+ }
+}
+ /*
+** USERNAME -- return name of the current user
+**
+** Parameters:
+** none
+**
+** Returns:
+** name of current user
+**
+** Side Effects:
+** none
+*/
+
+char *
+username()
+{
+# ifdef UIDUSER
+ extern struct passwd *getpwuid();
+ register struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if (pw == NULL)
+ {
+ syserr("who are you? (uid=%d)", getuid());
+ exit(EX_OSERR);
+ }
+ return (pw->pw_name);
+# else
+ extern char *getlogin();
+ register char *p;
+
+ p = getenv("USER");
+ if (p == NULL || p[0] == '\0')
+ p = getlogin();
+ return (p);
+# endif UIDUSER
+}
+
+/*
+** Guarded string manipulation routines; the last argument
+** is the length of the buffer into which the strcpy or strcat
+** is to be done.
+*/
+char *gstrcat(to, from, length)
+ char *to, *from;
+ int length;
+{
+ if (strlen(from) + strlen(to) >= length) {
+ gstrbotch(to, from);
+ }
+ return(strcat(to, from));
+}
+
+char *gstrncat(to, from, n, length)
+ char *to, *from;
+ int n;
+ int length;
+{
+ if (n + strlen(to) >= length) {
+ gstrbotch(to, from);
+ }
+ return(strncat(to, from, n));
+}
+
+char *gstrcpy(to, from, length)
+ char *to, *from;
+ int length;
+{
+ if (strlen(from) >= length) {
+ gstrbotch(from, (char *)0);
+ }
+ return(strcpy(to, from));
+}
+gstrbotch(str1, str2)
+ char *str1, *str2;
+{
+ usrerr("Filename(s) too long: %s %s", str1, str2);
+}
diff --git a/usr.bin/sed/compile.c b/usr.bin/sed/compile.c
index 944a226..8ad1b2d 100644
--- a/usr.bin/sed/compile.c
+++ b/usr.bin/sed/compile.c
@@ -36,7 +36,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)compile.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)compile.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
@@ -175,7 +175,6 @@ semicolon: EATSPACE();
cmd->nonsel = cmd->inrange = 0;
/* First parse the addresses */
naddr = 0;
- cmd->a1 = cmd->a2 = NULL;
/* Valid characters to start an address */
#define addrchar(c) (strchr("0123456789/\\$", (c)))
@@ -185,16 +184,18 @@ semicolon: EATSPACE();
p = compile_addr(p, cmd->a1);
EATSPACE(); /* EXTENSION */
if (*p == ',') {
- naddr++;
p++;
EATSPACE(); /* EXTENSION */
+ naddr++;
cmd->a2 = xmalloc(sizeof(struct s_addr));
p = compile_addr(p, cmd->a2);
- }
- }
+ EATSPACE();
+ } else
+ cmd->a2 = 0;
+ } else
+ cmd->a1 = cmd->a2 = 0;
nonsel: /* Now parse the command */
- EATSPACE();
if (!*p)
err(COMPILE, "command expected");
cmd->code = *p;
@@ -208,8 +209,9 @@ nonsel: /* Now parse the command */
"command %c expects up to %d address(es), found %d", *p, fp->naddr, naddr);
switch (fp->args) {
case NONSEL: /* ! */
- cmd->nonsel = ! cmd->nonsel;
p++;
+ EATSPACE();
+ cmd->nonsel = ! cmd->nonsel;
goto nonsel;
case GROUP: /* { */
p++;
@@ -221,6 +223,12 @@ nonsel: /* Now parse the command */
*compile_stream("}", &cmd->u.c, p) = cmd2;
cmd->next = cmd2;
link = &cmd2->next;
+ /*
+ * Short-circuit command processing, since end of
+ * group is really just a noop.
+ */
+ cmd2->nonsel = 1;
+ cmd2->a1 = cmd2->a2 = 0;
break;
case EMPTY: /* d D g G h H l n N p P q x = \0 */
p++;
diff --git a/usr.bin/showmount/showmount.8 b/usr.bin/showmount/showmount.8
index fe84e1e..b4d1be6 100644
--- a/usr.bin/showmount/showmount.8
+++ b/usr.bin/showmount/showmount.8
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)showmount.8 8.2 (Berkeley) 12/11/93
+.\" @(#)showmount.8 8.3 (Berkeley) 3/29/95
.\"
-.Dd December 11, 1993
+.Dd March 29, 1995
.Dt SHOWMOUNT 8
.Os BSD 4
.Sh NAME
@@ -42,7 +42,7 @@
.Nd show remote nfs mounts on host
.Sh SYNOPSIS
.Nm showmount
-.Op Fl ade
+.Op Fl ade3
.Op Ar host
.Sh DESCRIPTION
.Nm Showmount
@@ -56,7 +56,10 @@ file systems mounted
on the host. See
.%T "NFS: Network File System Protocol Specification" ,
RFC 1094,
-Appendix A ,
+Appendix A,
+and
+.%T "NFS: Network File System Version 3 Protocol Specification" ,
+Appendix I,
for a detailed description of the protocol.
.Bl -tag -width Ds
.It Fl a
@@ -70,6 +73,8 @@ List directory paths of mount points instead of hosts
Show the
.Ar host Ns 's
exports list
+.It Fl 3
+Use mount protocol Version 3, compatible with NFS Version 3.
.El
.Sh SEE ALSO
.Xr mount 1 ,
diff --git a/usr.bin/showmount/showmount.c b/usr.bin/showmount/showmount.c
index e5a3752..2eb07c2 100644
--- a/usr.bin/showmount/showmount.c
+++ b/usr.bin/showmount/showmount.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1989, 1993
+ * Copyright (c) 1989, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
@@ -36,25 +36,29 @@
#ifndef lint
static char copyright[] =
-"@(#) Copyright (c) 1989, 1993\n\
+"@(#) Copyright (c) 1989, 1993, 1995\n\
The Regents of the University of California. All rights reserved.\n";
#endif not lint
#ifndef lint
-static char sccsid[] = "@(#)showmount.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)showmount.c 8.3 (Berkeley) 3/29/95";
#endif not lint
#include <sys/types.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <sys/socketvar.h>
+
#include <netdb.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
#include <nfs/rpcv2.h>
+
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
/* Constant defs */
#define ALL 1
@@ -84,29 +88,30 @@ struct exportslist {
static struct mountlist *mntdump;
static struct exportslist *exports;
static int type = 0;
-int xdr_mntdump(), xdr_exports();
+
+void print_dump __P((struct mountlist *));
+void usage __P((void));
+int xdr_mntdump __P((XDR *, struct mountlist **));
+int xdr_exports __P((XDR *, struct exportslist **));
/*
* This command queries the NFS mount daemon for it's mount list and/or
* it's exports list and prints them out.
* See "NFS: Network File System Protocol Specification, RFC1094, Appendix A"
+ * and the "Network File System Protocol XXX.."
* for detailed information on the protocol.
*/
+int
main(argc, argv)
int argc;
char **argv;
{
- register struct mountlist *mntp;
- register struct exportslist *exp;
- register struct grouplist *grp;
- extern char *optarg;
- extern int optind;
- register int rpcs = 0;
- char ch;
- char *host;
- int estat;
+ struct exportslist *exp;
+ struct grouplist *grp;
+ int estat, rpcs = 0, mntvers = 1;
+ char ch, *host;
- while ((ch = getopt(argc, argv, "ade")) != EOF)
+ while ((ch = getopt(argc, argv, "ade3")) != EOF)
switch((char)ch) {
case 'a':
if (type == 0) {
@@ -125,6 +130,9 @@ main(argc, argv)
case 'e':
rpcs |= DOEXPORTS;
break;
+ case '3':
+ mntvers = 3;
+ break;
case '?':
default:
usage();
@@ -141,19 +149,19 @@ main(argc, argv)
rpcs = DODUMP;
if (rpcs & DODUMP)
- if ((estat = callrpc(host, RPCPROG_MNT, RPCMNT_VER1,
+ if ((estat = callrpc(host, RPCPROG_MNT, mntvers,
RPCMNT_DUMP, xdr_void, (char *)0,
xdr_mntdump, (char *)&mntdump)) != 0) {
clnt_perrno(estat);
- fprintf(stderr, "Can't do Mountdump rpc\n");
+ fprintf(stderr, ": Can't do Mountdump rpc\n");
exit(1);
}
if (rpcs & DOEXPORTS)
- if ((estat = callrpc(host, RPCPROG_MNT, RPCMNT_VER1,
+ if ((estat = callrpc(host, RPCPROG_MNT, mntvers,
RPCMNT_EXPORT, xdr_void, (char *)0,
xdr_exports, (char *)&exports)) != 0) {
clnt_perrno(estat);
- fprintf(stderr, "Can't do Exports rpc\n");
+ fprintf(stderr, ": Can't do Exports rpc\n");
exit(1);
}
@@ -190,20 +198,20 @@ main(argc, argv)
exp = exp->ex_next;
}
}
+
+ exit(0);
}
/*
* Xdr routine for retrieving the mount dump list
*/
+int
xdr_mntdump(xdrsp, mlp)
XDR *xdrsp;
struct mountlist **mlp;
{
- register struct mountlist *mp;
- register struct mountlist *tp;
- register struct mountlist **otp;
- int val, val2;
- int bool;
+ struct mountlist *mp, **otp, *tp;
+ int bool, val, val2;
char *strp;
*mlp = (struct mountlist *)0;
@@ -276,12 +284,13 @@ next:
/*
* Xdr routine to retrieve exports list
*/
+int
xdr_exports(xdrsp, exp)
XDR *xdrsp;
struct exportslist **exp;
{
- register struct exportslist *ep;
- register struct grouplist *gp;
+ struct exportslist *ep;
+ struct grouplist *gp;
int bool, grpbool;
char *strp;
@@ -318,8 +327,10 @@ xdr_exports(xdrsp, exp)
return (1);
}
+void
usage()
{
+
fprintf(stderr, "usage: showmount [-ade] host\n");
exit(1);
}
@@ -327,6 +338,7 @@ usage()
/*
* Print the binary tree in inorder so that output is sorted.
*/
+void
print_dump(mp)
struct mountlist *mp;
{
diff --git a/usr.bin/split/split.c b/usr.bin/split/split.c
index 198532b..221ee31 100644
--- a/usr.bin/split/split.c
+++ b/usr.bin/split/split.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)split.c 8.2 (Berkeley) 4/16/94";
+static char sccsid[] = "@(#)split.c 8.3 (Berkeley) 4/25/94";
#endif /* not lint */
#include <sys/param.h>
@@ -110,7 +110,7 @@ main(argc, argv)
case 'l': /* Line count. */
if (numlines != 0)
usage();
- if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *p)
+ if ((numlines = strtol(optarg, &ep, 10)) <= 0 || *ep)
errx(1, "%s: illegal line count.", optarg);
break;
default:
diff --git a/usr.bin/strip/strip.c b/usr.bin/strip/strip.c
index 9de05f7..114d823 100644
--- a/usr.bin/strip/strip.c
+++ b/usr.bin/strip/strip.c
@@ -38,34 +38,32 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)strip.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)strip.c 8.3 (Berkeley) 5/16/95";
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
-#include <limits.h>
-#include <fcntl.h>
-#include <errno.h>
#include <a.out.h>
-#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
typedef struct exec EXEC;
typedef struct nlist NLIST;
#define strx n_un.n_strx
-void err __P((int, const char *fmt, ...));
void s_stab __P((const char *, int, EXEC *));
void s_sym __P((const char *, int, EXEC *));
void usage __P((void));
-int eval;
-
int
main(argc, argv)
int argc;
@@ -74,7 +72,7 @@ main(argc, argv)
register int fd, nb;
EXEC head;
void (*sfcn)__P((const char *, int, EXEC *));
- int ch;
+ int ch, eval;
char *fn;
sfcn = s_sym;
@@ -90,19 +88,29 @@ main(argc, argv)
argc -= optind;
argv += optind;
- while (fn = *argv++) {
- if ((fd = open(fn, O_RDWR)) < 0 ||
- (nb = read(fd, &head, sizeof(EXEC))) == -1) {
- err(0, "%s: %s", fn, strerror(errno));
+ for (eval = 0; (fn = *argv++) != NULL;) {
+ if ((fd = open(fn, O_RDWR)) < 0) {
+ warn("%s", fn);
+ eval = 1;
+ continue;
+ }
+ if ((nb = read(fd, &head, sizeof(EXEC))) == -1) {
+ warn("%s", fn);
+ (void)close(fd);
+ eval = 1;
continue;
}
if (nb != sizeof(EXEC) || N_BADMAG(head)) {
- err(0, "%s: %s", fn, strerror(EFTYPE));
+ warnx("%s: %s", fn, strerror(EFTYPE));
+ (void)close(fd);
+ eval = 1;
continue;
}
sfcn(fn, fd, &head);
- if (close(fd))
- err(0, "%s: %s", fn, strerror(errno));
+ if (close(fd)) {
+ warn("%s", fn);
+ eval = 1;
+ }
}
exit(eval);
}
@@ -226,34 +234,3 @@ usage()
(void)fprintf(stderr, "usage: strip [-d] file ...\n");
exit(1);
}
-
-#if __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-
-void
-#if __STDC__
-err(int fatal, const char *fmt, ...)
-#else
-err(fatal, fmt, va_alist)
- int fatal;
- char *fmt;
- va_dcl
-#endif
-{
- va_list ap;
-#if __STDC__
- va_start(ap, fmt);
-#else
- va_start(ap);
-#endif
- (void)fprintf(stderr, "strip: ");
- (void)vfprintf(stderr, fmt, ap);
- va_end(ap);
- (void)fprintf(stderr, "\n");
- if (fatal)
- exit(1);
- eval = 1;
-}
diff --git a/usr.bin/tcopy/tcopy.c b/usr.bin/tcopy/tcopy.c
index e717499..d54fc68 100644
--- a/usr.bin/tcopy/tcopy.c
+++ b/usr.bin/tcopy/tcopy.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1985, 1987, 1993
+ * Copyright (c) 1985, 1987, 1993, 1995
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94";
+static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95";
#endif /* not lint */
#include <sys/types.h>
@@ -46,6 +46,7 @@ static char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94";
#include <sys/ioctl.h>
#include <sys/mtio.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
@@ -60,7 +61,8 @@ static char sccsid[] = "@(#)tcopy.c 8.2 (Berkeley) 4/17/94";
#define NOCOUNT (-2)
int filen, guesslen, maxblk = MAXREC;
-long lastrec, record, size, tsize;
+long lastrec, record;
+off_t size, tsize;
FILE *msg = stdout;
void *getspace __P((int));
@@ -74,10 +76,10 @@ main(argc, argv)
int argc;
char *argv[];
{
- register int lastnread, nread, nw, inp, outp;
+ int ch, needeof, nw, inp, outp;
+ ssize_t lastnread, nread;
enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
sig_t oldsig;
- int ch, needeof;
char *buff, *inf;
guesslen = 1;
@@ -89,7 +91,7 @@ main(argc, argv)
case 's':
maxblk = atoi(optarg);
if (maxblk <= 0) {
- fprintf(stderr, "tcopy: illegal block size\n");
+ warnx("illegal block size");
usage();
}
guesslen = 0;
@@ -124,18 +126,15 @@ main(argc, argv)
inf = argv[0];
if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) {
- perror(argv[1]);
- exit(3);
+ err(3, argv[1]);
}
break;
default:
usage();
}
- if ((inp = open(inf, O_RDONLY, 0)) < 0) {
- perror(inf);
- exit(1);
- }
+ if ((inp = open(inf, O_RDONLY, 0)) < 0)
+ err(1, inf);
buff = getspace(maxblk);
@@ -155,10 +154,8 @@ main(argc, argv)
if (nread >= 0)
goto r1;
}
- fprintf(stderr, "read error, file %d, record %ld: ",
+ err(1, "read error, file %d, record %ld",
filen, record);
- perror("");
- exit(1);
} else if (nread != lastnread) {
if (lastnread != 0 && lastnread != NOCOUNT) {
if (lastrec == 0 && nread == 0)
@@ -184,11 +181,13 @@ r1: guesslen = 0;
}
nw = write(outp, buff, nread);
if (nw != nread) {
+ int error = errno;
fprintf(stderr,
"write error, file %d, record %ld: ",
filen, record);
if (nw == -1)
- perror("");
+ fprintf(stderr,
+ ": %s", strerror(error));
else
fprintf(stderr,
"write (%d) != read (%d)\n",
@@ -205,7 +204,7 @@ r1: guesslen = 0;
break;
}
fprintf(msg,
- "file %d: eof after %ld records: %ld bytes\n",
+ "file %d: eof after %ld records: %qd bytes\n",
filen, record, size);
needeof = 1;
filen++;
@@ -215,7 +214,7 @@ r1: guesslen = 0;
}
lastnread = nread;
}
- fprintf(msg, "total length: %ld bytes\n", tsize);
+ fprintf(msg, "total length: %qd bytes\n", tsize);
(void)signal(SIGINT, oldsig);
if (op == COPY || op == COPYVERIFY) {
writeop(outp, MTWEOF);
@@ -231,11 +230,11 @@ r1: guesslen = 0;
void
verify(inp, outp, outb)
- register int inp, outp;
- register char *outb;
+ int inp, outp;
+ char *outb;
{
- register int eot, inmaxblk, inn, outmaxblk, outn;
- register char *inb;
+ int eot, inmaxblk, inn, outmaxblk, outn;
+ char *inb;
inb = getspace(maxblk);
inmaxblk = outmaxblk = maxblk;
@@ -247,7 +246,7 @@ verify(inp, outp, outb)
if (inn >= 0)
goto r1;
}
- perror("tcopy: read error");
+ warn("read error");
break;
}
r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
@@ -257,7 +256,7 @@ r1: if ((outn = read(outp, outb, outmaxblk)) == -1) {
if (outn >= 0)
goto r2;
}
- perror("tcopy: read error");
+ warn("read error");
break;
}
r2: if (inn != outn) {
@@ -268,13 +267,15 @@ r2: if (inn != outn) {
}
if (!inn) {
if (eot++) {
- fprintf(msg, "tcopy: tapes are identical.\n");
+ fprintf(msg, "%s: tapes are identical.\n",
+ "tcopy");
return;
}
} else {
if (bcmp(inb, outb, inn)) {
fprintf(msg,
- "tcopy: tapes have different data.\n");
+ "%s: tapes have different data.\n",
+ "tcopy");
break;
}
eot = 0;
@@ -293,7 +294,7 @@ intr(signo)
else
fprintf(msg, "record %ld\n", lastrec);
fprintf(msg, "interrupt at file %d: record %ld\n", filen, record);
- fprintf(msg, "total length: %ld bytes\n", tsize + size);
+ fprintf(msg, "total length: %qd bytes\n", tsize + size);
exit(1);
}
@@ -303,10 +304,9 @@ getspace(blk)
{
void *bp;
- if ((bp = malloc((size_t)blk)) == NULL) {
- fprintf(stderr, "tcopy: no memory\n");
- exit(11);
- }
+ if ((bp = malloc((size_t)blk)) == NULL)
+ errx(11, "no memory");
+
return (bp);
}
@@ -318,15 +318,14 @@ writeop(fd, type)
op.mt_op = type;
op.mt_count = (daddr_t)1;
- if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) {
- perror("tcopy: tape op");
- exit(6);
- }
+ if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
+ err(6, "tape op");
}
void
usage()
{
+
fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n");
exit(1);
}
diff --git a/usr.bin/tip/acu.c b/usr.bin/tip/acu.c
new file mode 100644
index 0000000..f7bde99
--- /dev/null
+++ b/usr.bin/tip/acu.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/biz22.c b/usr.bin/tip/aculib/biz22.c
new file mode 100644
index 0000000..93c5e53
--- /dev/null
+++ b/usr.bin/tip/aculib/biz22.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/biz31.c b/usr.bin/tip/aculib/biz31.c
new file mode 100644
index 0000000..412974d
--- /dev/null
+++ b/usr.bin/tip/aculib/biz31.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/courier.c b/usr.bin/tip/aculib/courier.c
new file mode 100644
index 0000000..85f7b0d
--- /dev/null
+++ b/usr.bin/tip/aculib/courier.c
@@ -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;
+}
diff --git a/usr.bin/tip/aculib/df.c b/usr.bin/tip/aculib/df.c
new file mode 100644
index 0000000..5f294f9
--- /dev/null
+++ b/usr.bin/tip/aculib/df.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/dn11.c b/usr.bin/tip/aculib/dn11.c
new file mode 100644
index 0000000..152b376
--- /dev/null
+++ b/usr.bin/tip/aculib/dn11.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/hayes.c b/usr.bin/tip/aculib/hayes.c
new file mode 100644
index 0000000..a2196f4
--- /dev/null
+++ b/usr.bin/tip/aculib/hayes.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/t3000.c b/usr.bin/tip/aculib/t3000.c
new file mode 100644
index 0000000..5e07359
--- /dev/null
+++ b/usr.bin/tip/aculib/t3000.c
@@ -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;
+}
diff --git a/usr.bin/tip/aculib/v3451.c b/usr.bin/tip/aculib/v3451.c
new file mode 100644
index 0000000..1623a58
--- /dev/null
+++ b/usr.bin/tip/aculib/v3451.c
@@ -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');
+}
diff --git a/usr.bin/tip/aculib/v831.c b/usr.bin/tip/aculib/v831.c
new file mode 100644
index 0000000..38aa230
--- /dev/null
+++ b/usr.bin/tip/aculib/v831.c
@@ -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);
+}
diff --git a/usr.bin/tip/aculib/ventel.c b/usr.bin/tip/aculib/ventel.c
new file mode 100644
index 0000000..28b0d28
--- /dev/null
+++ b/usr.bin/tip/aculib/ventel.c
@@ -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);
+}
+
diff --git a/usr.bin/tip/acutab.c b/usr.bin/tip/acutab.c
new file mode 100644
index 0000000..112b43e
--- /dev/null
+++ b/usr.bin/tip/acutab.c
@@ -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
+};
+
diff --git a/usr.bin/tip/cmds.c b/usr.bin/tip/cmds.c
new file mode 100644
index 0000000..63bfee2
--- /dev/null
+++ b/usr.bin/tip/cmds.c
@@ -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);
+}
diff --git a/usr.bin/tip/cmdtab.c b/usr.bin/tip/cmdtab.c
new file mode 100644
index 0000000..f6bcb60
--- /dev/null
+++ b/usr.bin/tip/cmdtab.c
@@ -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 }
+};
diff --git a/usr.bin/tip/cu.c b/usr.bin/tip/cu.c
new file mode 100644
index 0000000..fae2b3c
--- /dev/null
+++ b/usr.bin/tip/cu.c
@@ -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));
+}
diff --git a/usr.bin/tip/hunt.c b/usr.bin/tip/hunt.c
new file mode 100644
index 0000000..650ac26
--- /dev/null
+++ b/usr.bin/tip/hunt.c
@@ -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);
+}
diff --git a/usr.bin/tip/log.c b/usr.bin/tip/log.c
new file mode 100644
index 0000000..5da2c45
--- /dev/null
+++ b/usr.bin/tip/log.c
@@ -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
diff --git a/usr.bin/tip/partab.c b/usr.bin/tip/partab.c
new file mode 100644
index 0000000..1da4e23
--- /dev/null
+++ b/usr.bin/tip/partab.c
@@ -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,
+};
diff --git a/usr.bin/tip/remcap.c b/usr.bin/tip/remcap.c
new file mode 100644
index 0000000..7a7e0c2
--- /dev/null
+++ b/usr.bin/tip/remcap.c
@@ -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);
+}
diff --git a/usr.bin/tip/remote.c b/usr.bin/tip/remote.c
new file mode 100644
index 0000000..9b86066
--- /dev/null
+++ b/usr.bin/tip/remote.c
@@ -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);
+}
diff --git a/usr.bin/tip/tip.1 b/usr.bin/tip/tip.1
new file mode 100644
index 0000000..10b8a3e
--- /dev/null
+++ b/usr.bin/tip/tip.1
@@ -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.
diff --git a/usr.bin/tip/value.c b/usr.bin/tip/value.c
new file mode 100644
index 0000000..ce29a21
--- /dev/null
+++ b/usr.bin/tip/value.c
@@ -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);
+}
diff --git a/usr.bin/tip/vars.c b/usr.bin/tip/vars.c
new file mode 100644
index 0000000..debe01b
--- /dev/null
+++ b/usr.bin/tip/vars.c
@@ -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 }
+};
diff --git a/usr.bin/touch/touch.1 b/usr.bin/touch/touch.1
index c6eeaa3..c620931 100644
--- a/usr.bin/touch/touch.1
+++ b/usr.bin/touch/touch.1
@@ -32,9 +32,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)touch.1 8.2 (Berkeley) 12/30/93
+.\" @(#)touch.1 8.3 (Berkeley) 4/28/95
.\"
-.Dd December 30, 1993
+.Dd April 28, 1995
.Dt TOUCH 1
.Os
.Sh NAME
@@ -44,7 +44,7 @@
.Nm touch
.Op Fl acfm
.Op Fl r Ar file
-.Op Fl t [[CC]YY]MMDDhhmm[.SS]
+.Op Fl t Ar [[CC]YY]MMDDhhmm[.SS]
.Ar file ...
.Sh DESCRIPTION
The
diff --git a/usr.bin/touch/touch.c b/usr.bin/touch/touch.c
index 46efb64..afaa537 100644
--- a/usr.bin/touch/touch.c
+++ b/usr.bin/touch/touch.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)touch.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)touch.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/types.h>
@@ -204,7 +204,7 @@ stime_arg1(arg, tvp)
switch(strlen(arg)) {
case 12: /* CCYYMMDDhhmm */
t->tm_year = ATOI2(arg);
- t->tm_year *= 1000;
+ t->tm_year *= 100;
yearset = 1;
/* FALLTHOUGH */
case 10: /* YYMMDDhhmm */
diff --git a/usr.bin/tput/tput.c b/usr.bin/tput/tput.c
index 8da0be7..f587492 100644
--- a/usr.bin/tput/tput.c
+++ b/usr.bin/tput/tput.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)tput.c 8.2 (Berkeley) 3/19/94";
+static char sccsid[] = "@(#)tput.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/termios.h>
@@ -183,11 +183,11 @@ process(cap, str, argv)
case 2:
if (*++argv == NULL || *argv[0] == '\0')
errx(2, errfew, 2, cap);
- arg_cols = atoi(*argv);
+ arg_rows = atoi(*argv);
if (*++argv == NULL || *argv[0] == '\0')
errx(2, errfew, 2, cap);
- arg_rows = atoi(*argv);
+ arg_cols = atoi(*argv);
(void) tputs(tgoto(str, arg_cols, arg_rows), arg_rows, outc);
break;
diff --git a/usr.bin/uucp/acucntrl/acucntrl.8 b/usr.bin/uucp/acucntrl/acucntrl.8
index 57ce495..7b6753d 100644
--- a/usr.bin/uucp/acucntrl/acucntrl.8
+++ b/usr.bin/uucp/acucntrl/acucntrl.8
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)acucntrl.8 8.2 (Berkeley) 12/11/93
+.\" @(#)acucntrl.8 8.3 (Berkeley) 6/1/94
.\"
-.TH ACUCNTRL 8 "December 11, 1993"
+.TH ACUCNTRL 8 "June 1, 1994"
.UC 6
.SH NAME
acucntrl \- turn around tty line between dialin and dialout
@@ -123,6 +123,7 @@ condition line: clear exclusive use and set hangup on close modes
turn on modem control
.IP 7)
edit /etc/ttys, changing the first character of the appropriate line to 1
+.ne 1i
.IP 8)
send a hangup to process 1 to poke init to enable getty
.IP 9)
diff --git a/usr.bin/uucp/acucntrl/acucntrl.c b/usr.bin/uucp/acucntrl/acucntrl.c
new file mode 100644
index 0000000..deba6ba
--- /dev/null
+++ b/usr.bin/uucp/acucntrl/acucntrl.c
@@ -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 */
diff --git a/usr.bin/uucp/uupoll/uupoll.8 b/usr.bin/uucp/uupoll/uupoll.8
new file mode 100644
index 0000000..f6ee49b
--- /dev/null
+++ b/usr.bin/uucp/uupoll/uupoll.8
@@ -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 .
diff --git a/usr.bin/uucp/uupoll/uupoll.c b/usr.bin/uucp/uupoll/uupoll.c
new file mode 100644
index 0000000..5d5e662
--- /dev/null
+++ b/usr.bin/uucp/uupoll/uupoll.c
@@ -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);
+}
diff --git a/usr.bin/uucp/uuq/Makefile b/usr.bin/uucp/uuq/Makefile
new file mode 100644
index 0000000..60dbe0b
--- /dev/null
+++ b/usr.bin/uucp/uuq/Makefile
@@ -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>
diff --git a/usr.bin/uucp/uuq/uuq.1 b/usr.bin/uucp/uuq/uuq.1
new file mode 100644
index 0000000..783d486
--- /dev/null
+++ b/usr.bin/uucp/uuq/uuq.1
@@ -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 .
diff --git a/usr.bin/uucp/uuq/uuq.c b/usr.bin/uucp/uuq/uuq.c
new file mode 100644
index 0000000..7abb25c
--- /dev/null
+++ b/usr.bin/uucp/uuq/uuq.c
@@ -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);
+}
diff --git a/usr.bin/uucp/uusend/Makefile b/usr.bin/uucp/uusend/Makefile
new file mode 100644
index 0000000..6c13fb4
--- /dev/null
+++ b/usr.bin/uucp/uusend/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= uusend
+LINKS= ${BINDIR}/uusend ${BINDIR}/ruusend
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/uucp/uusend/uusend.1 b/usr.bin/uucp/uusend/uusend.1
new file mode 100644
index 0000000..9379307
--- /dev/null
+++ b/usr.bin/uucp/uusend/uusend.1
@@ -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 .
diff --git a/usr.bin/uucp/uusend/uusend.c b/usr.bin/uucp/uusend/uusend.c
new file mode 100644
index 0000000..207108e
--- /dev/null
+++ b/usr.bin/uucp/uusend/uusend.c
@@ -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
diff --git a/usr.bin/uucp/uusnap/uusnap.8 b/usr.bin/uucp/uusnap/uusnap.8
new file mode 100644
index 0000000..92f0e330
--- /dev/null
+++ b/usr.bin/uucp/uusnap/uusnap.8
@@ -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 .
diff --git a/usr.bin/uucp/uusnap/uusnap.c b/usr.bin/uucp/uusnap/uusnap.c
new file mode 100644
index 0000000..565c52a
--- /dev/null
+++ b/usr.bin/uucp/uusnap/uusnap.c
@@ -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;
+}
diff --git a/usr.bin/vacation/vacation.1 b/usr.bin/vacation/vacation.1
index 0c74c39..f70d16c 100644
--- a/usr.bin/vacation/vacation.1
+++ b/usr.bin/vacation/vacation.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)vacation.1 8.1 (Berkeley) 6/16/93
+.\" @(#)vacation.1 8.2 (Berkeley) 4/28/95
.\"
-.Dd June 16, 1993
+.Dd April 28, 1995
.Dt VACATION 1
.Os BSD 4.3
.Sh NAME
@@ -114,8 +114,8 @@ case insensitive) nor is a notification sent if a
or
.Dq Precedence: junk
line is included in the mail headers.
-The people who have sent you messages are maintained as an
-.Xr ndbm 3
+The people who have sent you messages are maintained as a
+.Xr db 3
database in the file
.Pa .vacation.db
in your home directory.
diff --git a/usr.bin/vmstat/vmstat.c b/usr.bin/vmstat/vmstat.c
index 0f3f4ce..92c0dad 100644
--- a/usr.bin/vmstat/vmstat.c
+++ b/usr.bin/vmstat/vmstat.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
#endif /* not lint */
#include <sys/param.h>
@@ -582,6 +582,9 @@ dosum()
(void)printf("%9u pages active\n", sum.v_active_count);
(void)printf("%9u pages inactive\n", sum.v_inactive_count);
(void)printf("%9u bytes per page\n", sum.v_page_size);
+ (void)printf("%9u target inactive pages\n", sum.v_inactive_target);
+ (void)printf("%9u target free pages\n", sum.v_free_target);
+ (void)printf("%9u minimum free pages\n", sum.v_free_min);
#else
(void)printf("%9u sequential process pages freed\n", sum.v_seqfree);
(void)printf("%9u total reclaims (%d%% fast)\n", sum.v_pgrec,
diff --git a/usr.bin/w/w.c b/usr.bin/w/w.c
index 1a7b526..501938a 100644
--- a/usr.bin/w/w.c
+++ b/usr.bin/w/w.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)w.c 8.4 (Berkeley) 4/16/94";
+static char sccsid[] = "@(#)w.c 8.6 (Berkeley) 6/30/94";
#endif /* not lint */
/*
@@ -191,7 +191,8 @@ main(argc, argv)
*nextp = ep;
nextp = &(ep->next);
memmove(&(ep->utmp), &utmp, sizeof(struct utmp));
- stp = ttystat(ep->utmp.ut_line);
+ if (!(stp = ttystat(ep->utmp.ut_line)))
+ continue;
ep->tdev = stp->st_rdev;
#ifdef CPU_CONSDEV
/*
@@ -307,7 +308,8 @@ main(argc, argv)
p = hp->h_name;
}
if (x) {
- (void)snprintf(buf, sizeof(buf), "%s:%s", p, x);
+ (void)snprintf(buf, sizeof(buf), "%s:%.*s", p,
+ ep->utmp.ut_host + UT_HOSTSIZE - x, x);
p = buf;
}
(void)printf("%-*.*s %-2.2s %-*.*s ",
@@ -409,7 +411,7 @@ ttystat(line)
(void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s", _PATH_DEV, line);
if (stat(ttybuf, &sb))
- err(1, "%s", ttybuf);
+ return (NULL);
return (&sb);
}
diff --git a/usr.bin/wc/wc.c b/usr.bin/wc/wc.c
index a50196c..d37f494 100644
--- a/usr.bin/wc/wc.c
+++ b/usr.bin/wc/wc.c
@@ -38,7 +38,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)wc.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)wc.c 8.2 (Berkeley) 5/2/95";
#endif /* not lint */
#include <sys/param.h>
@@ -160,7 +160,7 @@ cnt(file)
if (dochar) {
if (fstat(fd, &sb))
err("%s: %s", file, strerror(errno));
- if (S_ISREG(sb.st_mode) || S_ISLNK(sb.st_mode)) {
+ if (S_ISREG(sb.st_mode)) {
(void)printf(" %7qu", sb.st_size);
tcharct += sb.st_size;
(void)close(fd);
diff --git a/usr.bin/whatis/Makefile b/usr.bin/whatis/Makefile
new file mode 100644
index 0000000..8655a7c
--- /dev/null
+++ b/usr.bin/whatis/Makefile
@@ -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>
diff --git a/usr.bin/whatis/whatis.1 b/usr.bin/whatis/whatis.1
new file mode 100644
index 0000000..0f1b0a1
--- /dev/null
+++ b/usr.bin/whatis/whatis.1
@@ -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 .
diff --git a/usr.bin/whatis/whatis.c b/usr.bin/whatis/whatis.c
new file mode 100644
index 0000000..904f0e4
--- /dev/null
+++ b/usr.bin/whatis/whatis.c
@@ -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);
+}
diff --git a/usr.bin/whois/whois.1 b/usr.bin/whois/whois.1
index dd9d81a..628a2a7 100644
--- a/usr.bin/whois/whois.1
+++ b/usr.bin/whois/whois.1
@@ -29,9 +29,9 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" @(#)whois.1 8.1 (Berkeley) 6/6/93
+.\" @(#)whois.1 8.2 (Berkeley) 6/20/94
.\"
-.Dd June 6, 1993
+.Dd June 20, 1994
.Dt WHOIS 1
.Os BSD 4.3
.Sh NAME
@@ -50,7 +50,7 @@ database.
The options are as follows:
.Bl -tag -width Ds
.It Fl h
-Use the specified host instead of the default NIC (nic.ddn.mil).
+Use the specified host instead of the default NIC (whois.internic.net).
.El
.Pp
The operands specified to
diff --git a/usr.bin/window/wwinit.c b/usr.bin/window/wwinit.c
index 0581126..1bf26f4 100644
--- a/usr.bin/window/wwinit.c
+++ b/usr.bin/window/wwinit.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)wwinit.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)wwinit.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include "ww.h"
@@ -50,7 +50,7 @@ wwinit()
char *kp;
int s;
- wwdtablesize = getdtablesize();
+ wwdtablesize = 3;
wwhead.ww_forw = &wwhead;
wwhead.ww_back = &wwhead;
diff --git a/usr.bin/window/wwopen.c b/usr.bin/window/wwopen.c
index c4fc96b..bddbb61 100644
--- a/usr.bin/window/wwopen.c
+++ b/usr.bin/window/wwopen.c
@@ -35,7 +35,7 @@
*/
#ifndef lint
-static char sccsid[] = "@(#)wwopen.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)wwopen.c 8.2 (Berkeley) 4/28/95";
#endif /* not lint */
#include "ww.h"
@@ -116,6 +116,8 @@ wwopen(flags, nrow, ncol, row, col, nline)
}
w->ww_obe = w->ww_ob + 512;
w->ww_obp = w->ww_obq = w->ww_ob;
+ if (w->ww_pty >= wwdtablesize)
+ wwdtablesize = w->ww_pty + 1;
}
w->ww_win = wwalloc(w->ww_w.t, w->ww_w.l,
diff --git a/usr.bin/write/write.c b/usr.bin/write/write.c
index 7d99f21..7ceedfb 100644
--- a/usr.bin/write/write.c
+++ b/usr.bin/write/write.c
@@ -41,7 +41,7 @@ static char copyright[] =
#endif /* not lint */
#ifndef lint
-static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93";
+static char sccsid[] = "@(#)write.c 8.2 (Berkeley) 4/27/95";
#endif /* not lint */
#include <sys/param.h>
@@ -49,6 +49,8 @@ static char sccsid[] = "@(#)write.c 8.1 (Berkeley) 6/6/93";
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
+
+#include <err.h>
#include <utmp.h>
#include <ctype.h>
#include <pwd.h>
@@ -75,23 +77,16 @@ main(argc, argv)
myttyfd = fileno(stdout);
else if (isatty(fileno(stderr)))
myttyfd = fileno(stderr);
- else {
- (void)fprintf(stderr, "write: can't find your tty\n");
- exit(1);
- }
- if (!(mytty = ttyname(myttyfd))) {
- (void)fprintf(stderr, "write: can't find your tty's name\n");
- exit(1);
- }
- if (cp = rindex(mytty, '/'))
+ else
+ errx(1, "can't find your tty");
+ if (!(mytty = ttyname(myttyfd)))
+ errx(1, "can't find your tty's name");
+ if (cp = strrchr(mytty, '/'))
mytty = cp + 1;
if (term_chk(mytty, &msgsok, &atime, 1))
exit(1);
- if (!msgsok) {
- (void)fprintf(stderr,
- "write: you have write permission turned off.\n");
- exit(1);
- }
+ if (!msgsok)
+ errx(1, "you have write permission turned off");
myuid = getuid();
@@ -104,20 +99,14 @@ main(argc, argv)
case 3:
if (!strncmp(argv[2], "/dev/", 5))
argv[2] += 5;
- if (utmp_chk(argv[1], argv[2])) {
- (void)fprintf(stderr,
- "write: %s is not logged in on %s.\n",
+ if (utmp_chk(argv[1], argv[2]))
+ errx(1, "%s is not logged in on %s",
argv[1], argv[2]);
- exit(1);
- }
if (term_chk(argv[2], &msgsok, &atime, 1))
exit(1);
- if (myuid && !msgsok) {
- (void)fprintf(stderr,
- "write: %s has messages disabled on %s\n",
+ if (myuid && !msgsok)
+ errx(1, "%s has messages disabled on %s",
argv[1], argv[2]);
- exit(1);
- }
do_write(argv[2], mytty, myuid);
break;
default:
@@ -172,10 +161,8 @@ search_utmp(user, tty, mytty, myuid)
int ufd, nloggedttys, nttys, msgsok, user_is_me;
char atty[UT_LINESIZE + 1];
- if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0) {
- perror("utmp");
- exit(1);
- }
+ if ((ufd = open(_PATH_UTMP, O_RDONLY)) < 0)
+ err(1, "%s", _PATH_UTMP);
nloggedttys = nttys = 0;
bestatime = 0;
@@ -201,23 +188,17 @@ search_utmp(user, tty, mytty, myuid)
}
(void)close(ufd);
- if (nloggedttys == 0) {
- (void)fprintf(stderr, "write: %s is not logged in\n", user);
- exit(1);
- }
+ if (nloggedttys == 0)
+ errx(1, "%s is not logged in", user);
if (nttys == 0) {
if (user_is_me) { /* ok, so write to yourself! */
(void)strcpy(tty, mytty);
return;
}
- (void)fprintf(stderr,
- "write: %s has messages disabled\n", user);
- exit(1);
- } else if (nttys > 1) {
- (void)fprintf(stderr,
- "write: %s is logged in more than once; writing to %s\n",
+ errx(1, "%s has messages disabled", user);
+ } else if (nttys > 1)
+ warnx("%s is logged in more than once; writing to %s",
user, tty);
- }
}
/*
@@ -235,8 +216,7 @@ term_chk(tty, msgsokP, atimeP, showerror)
(void)sprintf(path, "/dev/%s", tty);
if (stat(path, &s) < 0) {
if (showerror)
- (void)fprintf(stderr,
- "write: %s: %s\n", path, strerror(errno));
+ warn("%s", path);
return(1);
}
*msgsokP = (s.st_mode & (S_IWRITE >> 3)) != 0; /* group write bit */
@@ -265,10 +245,8 @@ do_write(tty, mytty, myuid)
login = "???";
(void)sprintf(path, "/dev/%s", tty);
- if ((freopen(path, "w", stdout)) == NULL) {
- (void)fprintf(stderr, "write: %s: %s\n", path, strerror(errno));
- exit(1);
- }
+ if ((freopen(path, "w", stdout)) == NULL)
+ err(1, "%s", path);
(void)signal(SIGINT, done);
(void)signal(SIGHUP, done);
@@ -320,7 +298,6 @@ wr_fputs(s)
}
return;
-err: (void)fprintf(stderr, "write: %s\n", strerror(errno));
- exit(1);
+err: err(1, NULL);
#undef PUTC
}
OpenPOWER on IntegriCloud