summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/adjkerntz/Makefile4
-rw-r--r--sbin/adjkerntz/adjkerntz.8122
-rw-r--r--sbin/adjkerntz/adjkerntz.c224
-rw-r--r--sbin/adjkerntz/pathnames.h36
-rw-r--r--sbin/comcontrol/Makefile6
-rw-r--r--sbin/comcontrol/comcontrol.874
-rw-r--r--sbin/comcontrol/comcontrol.c112
-rw-r--r--sbin/fdisk/Makefile9
-rw-r--r--sbin/fdisk/fdisk.8178
-rw-r--r--sbin/fdisk/fdisk.c686
-rw-r--r--sbin/ft/Makefile7
-rw-r--r--sbin/ft/ft.886
-rw-r--r--sbin/ft/ft.c432
-rw-r--r--sbin/ft/ftecc.c422
-rw-r--r--sbin/i386/comcontrol/Makefile6
-rw-r--r--sbin/i386/comcontrol/comcontrol.874
-rw-r--r--sbin/i386/comcontrol/comcontrol.c112
-rw-r--r--sbin/i386/fdisk/Makefile9
-rw-r--r--sbin/i386/fdisk/fdisk.8178
-rw-r--r--sbin/i386/fdisk/fdisk.c686
-rw-r--r--sbin/i386/ft/Makefile7
-rw-r--r--sbin/i386/ft/ft.886
-rw-r--r--sbin/i386/ft/ft.c432
-rw-r--r--sbin/i386/ft/ftecc.c422
-rw-r--r--sbin/ldconfig/Makefile13
-rw-r--r--sbin/ldconfig/ldconfig.8100
-rw-r--r--sbin/ldconfig/ldconfig.c426
-rw-r--r--sbin/sysctl/Makefile6
-rw-r--r--sbin/sysctl/pathconf.c229
-rw-r--r--sbin/sysctl/sysctl.8208
-rw-r--r--sbin/sysctl/sysctl.c572
31 files changed, 5964 insertions, 0 deletions
diff --git a/sbin/adjkerntz/Makefile b/sbin/adjkerntz/Makefile
new file mode 100644
index 0000000..1ac5047
--- /dev/null
+++ b/sbin/adjkerntz/Makefile
@@ -0,0 +1,4 @@
+PROG= adjkerntz
+MAN8= adjkerntz.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/adjkerntz/adjkerntz.8 b/sbin/adjkerntz/adjkerntz.8
new file mode 100644
index 0000000..ac8fb5f
--- /dev/null
+++ b/sbin/adjkerntz/adjkerntz.8
@@ -0,0 +1,122 @@
+.\" Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.
+.\" 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.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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.
+.\"
+.Dd December 15, 1993
+.Dt ADJKERNTZ 8
+.Os FreeBSD
+.Sh NAME
+.Nm adjkerntz
+.Nd "adjusts the kernel time if the machine runs wall CMOS clock"
+.Sh SYNOPSIS
+.Nm adjkerntz
+.Fl i
+.Op Fl v
+.Nm adjkerntz
+.Fl a
+.Op Fl v
+.Sh DESCRIPTION
+.Nm Adjkerntz
+fixes kernel time (makes it UTC) using the current wall CMOS clock value,
+the current time zone rule and the kernel timezone value. The adjustment is
+enabled only if the file
+.Pa /etc/wall_cmos_clock
+exists, in other cases it is assumed that the machine runs UTC CMOS clock and
+.Nm adjkerntz
+does nothing.
+.Pp
+The adjustment is needed at boot stage and when a time zone
+change occurs, so
+.Nm adjkerntz
+can be called in two forms:
+.Bl -tag -width 4n
+.It Cm Fl i
+initialization call from
+.Pa /etc/rc
+(before any daemons are started).
+.Nm Adjkerntz
+makes the first adjustment and the initial time zone offset is stored into
+.Pa /var/run/.adjkerntz
+for following subsequent
+.Nm adjkerntz
+calls.
+.It Cm Fl a
+This form is needed, when time zone changes occur.
+.Nm Adjkerntz
+uses the previously stored
+time zone offset and the changed time zone rule to
+produce the new time zone offset, fix the kernel time and store the new
+offset into
+.Pa /var/run/.adjkerntz
+too.
+It is recommended to use this form in root's
+.Xr crontab 5
+near 3am,
+since this time matches most modern time zone changes.
+.It Cm Fl v
+This option is for diagnostic purposes. It causes
+.Nm adjkerntz
+to print differences between the old and new time zone offsets
+to stdout.
+.El
+.Pp
+.Nm Adjkerntz
+clears the kernel timezone structure and makes kernel always run at UTC
+time zone.
+Super-user privilege is required for all operations.
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev TZ
+Time zone change rule, see
+.Xr tzset 3 ;
+not needed when
+.Xr zic 8
+is used.
+.Sh FILES
+.Bl -tag -width /etc/wall_cmos_clock -compact
+.It Pa /etc/localtime
+Link to the current zone info file, see
+.Xr zic 8 .
+.It Pa /etc/wall_cmos_clock
+Empty file.
+Presence of it indicates that the machine runs wall CMOS clock,
+absence indicates UTC CMOS clock.
+.It Pa /var/run/.adjkerntz
+Text file with the stored current time zone offset in seconds.
+.Sh SEE ALSO
+.Xr tzset 3 ,
+.Xr zic 8 ,
+.Xr rc 8 ,
+.Xr crontab 5
+.Sh DIAGNOSTICS
+No diagnostics, unless \-v option is specified.
+If any error occurs, an error message printed to stderr and
+.Nm adjkerntz
+exits with return code greater than zero.
+.Sh AUTHOR
+Andrew A. Chernov <ache@astral.msk.su>
+.Sh HISTORY
+The
+.Nm adjkerntz
+command appeared in FreeBSD 1.0.1
+
diff --git a/sbin/adjkerntz/adjkerntz.c b/sbin/adjkerntz/adjkerntz.c
new file mode 100644
index 0000000..53a871a
--- /dev/null
+++ b/sbin/adjkerntz/adjkerntz.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#)Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/*
+ * Andrew A. Chernov <ache@astral.msk.su> Dec 20 1993
+ *
+ * Fix kernel time value if machine run wall CMOS clock
+ * (and /etc/wall_cmos_clock file present)
+ * using zoneinfo rules or direct TZ environment variable set.
+ * Use Joerg Wunsch idea for seconds accurate offset calculation
+ * with Garrett Wollman and Bruce Evans fixes.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "pathnames.h"
+
+char storage[] = _PATH_OFFSET;
+
+int main(argc, argv)
+ int argc;
+ char **argv;
+{
+ struct tm local, utc;
+ struct timeval tv, *stv;
+ struct timezone tz, *stz;
+ /* Avoid time_t here, can be unsigned long or worse */
+ long offset, oldoffset, utcsec, localsec, diff;
+ time_t initial_sec, final_sec;
+ int ch, init = -1, verbose = 0;
+ FILE *f;
+
+ while ((ch = getopt(argc, argv, "aiv")) != EOF)
+ switch((char)ch) {
+ case 'i': /* initial call, save offset */
+ if (init != -1)
+ goto usage;
+ init = 1;
+ break;
+ case 'a': /* adjustment call, use saved offset */
+ if (init != -1)
+ goto usage;
+ init = 0;
+ break;
+ case 'v': /* verbose */
+ verbose = 1;
+ break;
+ default:
+ usage:
+ fprintf(stderr, "Usage:\n\
+\tadjkerntz -i [-v]\t(initial call from /etc/rc)\n\
+\tadjkerntz -a [-v]\t(adjustment call from crontab)\n");
+ return 2;
+ }
+ if (init == -1)
+ goto usage;
+
+ if (access(_PATH_CLOCK, F_OK))
+ return 0;
+
+ /* Restore saved offset */
+
+ if (!init) {
+ if ((f = fopen(storage, "r")) == NULL) {
+ perror(storage);
+ return 1;
+ }
+ if (fscanf(f, "%ld", &oldoffset) != 1) {
+ fprintf(stderr, "Misformatted offset in %s\n",
+ storage);
+ return 1;
+ }
+ (void) fclose(f);
+ }
+ else
+ oldoffset = 0;
+
+/****** Critical section, do all things as fast as possible ******/
+
+ /* get local CMOS clock and possible kernel offset */
+ if (gettimeofday(&tv, &tz)) {
+ perror("gettimeofday");
+ return 1;
+ }
+
+ /* get the actual local timezone difference */
+ initial_sec = tv.tv_sec;
+ local = *localtime(&initial_sec);
+ utc = *gmtime(&initial_sec);
+ utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */
+ /* because it assumed local time */
+
+ /* calculate local CMOS diff from GMT */
+
+ utcsec = mktime(&utc);
+ localsec = mktime(&local);
+ if (utcsec == -1 || localsec == -1) {
+ /*
+ * XXX user can only control local time, and it is
+ * unacceptable to fail here for -i. 2:30 am in the
+ * middle of the nonexistent hour means 3:30 am.
+ */
+ fprintf(stderr,
+ "Nonexistent local time - try again in an hour\n");
+ return 1;
+ }
+ offset = utcsec - localsec;
+
+ /* correct the kerneltime for this diffs */
+ /* subtract kernel offset, if present, old offset too */
+
+ diff = offset - tz.tz_minuteswest * 60 - oldoffset;
+
+ if (diff != 0) {
+
+ /* Yet one step for final time */
+
+ final_sec = tv.tv_sec + diff;
+
+ /* get the actual local timezone difference */
+ local = *localtime(&final_sec);
+ utc = *gmtime(&final_sec);
+ utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */
+ /* because it assumed local time */
+
+ utcsec = mktime(&utc);
+ localsec = mktime(&local);
+ if (utcsec == -1 || localsec == -1) {
+ /*
+ * XXX as above. The user has even less control,
+ * but perhaps we never get here.
+ */
+ fprintf(stderr,
+ "Nonexistent (final) local time - try again in an hour\n");
+ return 1;
+ }
+ offset = utcsec - localsec;
+
+ /* correct the kerneltime for this diffs */
+ /* subtract kernel offset, if present, old offset too */
+
+ diff = offset - tz.tz_minuteswest * 60 - oldoffset;
+
+ if (diff != 0) {
+ tv.tv_sec += diff;
+ tv.tv_usec = 0; /* we are restarting here... */
+ stv = &tv;
+ }
+ else
+ stv = NULL;
+ }
+ else
+ stv = NULL;
+
+ if (tz.tz_dsttime != 0 || tz.tz_minuteswest != 0) {
+ tz.tz_dsttime = tz.tz_minuteswest = 0; /* zone info is garbage */
+ stz = &tz;
+ }
+ else
+ stz = NULL;
+
+ if (stz != NULL || stv != NULL) {
+ if (settimeofday(stv, stz)) {
+ perror("settimeofday");
+ return 1;
+ }
+ }
+
+/****** End of critical section ******/
+
+ if (verbose)
+ printf("Calculated zone offset difference: %ld seconds\n",
+ diff);
+
+ if (offset != oldoffset) {
+ (void) umask(022);
+ /* Save offset for next calls from crontab */
+ if ((f = fopen(storage, "w")) == NULL) {
+ perror(storage);
+ return 1;
+ }
+ fprintf(f, "%ld\n", offset);
+ if (fclose(f)) {
+ perror(storage);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/sbin/adjkerntz/pathnames.h b/sbin/adjkerntz/pathnames.h
new file mode 100644
index 0000000..a8b751f
--- /dev/null
+++ b/sbin/adjkerntz/pathnames.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 1993 by Andrew A. Chernov, Moscow, Russia.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``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.
+ */
+
+#include <paths.h>
+
+/*
+ * Offset file name started with '.', because "adjkerntz -i"
+ * called in /etc/rc before cleaning '*' in /var/run,
+ * and this file should be keeped after it.
+ */
+#define _PATH_OFFSET "/var/run/.adjkerntz"
+
+#define _PATH_CLOCK "/etc/wall_cmos_clock"
diff --git a/sbin/comcontrol/Makefile b/sbin/comcontrol/Makefile
new file mode 100644
index 0000000..abc8d0a
--- /dev/null
+++ b/sbin/comcontrol/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 5.4 (Berkeley) 6/5/91
+
+PROG= comcontrol
+MAN8= comcontrol.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/comcontrol/comcontrol.8 b/sbin/comcontrol/comcontrol.8
new file mode 100644
index 0000000..8da3e01
--- /dev/null
+++ b/sbin/comcontrol/comcontrol.8
@@ -0,0 +1,74 @@
+.Dd December 10, 1993
+.Dt COMCONTROL 8
+.Os FreeBSD
+.Sh NAME
+.Nm comcontrol
+.Nd "control the bidirectional status of a sio port and waiting time after DTR drop"
+.Sh SYNOPSIS
+.Nm comcontrol
+.Ar sio_special_device
+.Op Cm bidir | Fl bidir
+.Op Cm dtrwait Ar ticks
+.Sh DESCRIPTION
+.Nm Comcontrol
+is used to examine and modify the bidirectional status
+of a specified
+sio communications port
+and its waiting time after DTR drop.
+By default (if
+.Ar sio_special_device
+only specified),
+.Nm comcontrol
+will print the current port state
+(if kernel was built with
+.Cm options COM_BIDIR )
+as either
+.Cm bidir
+to indicate that bidirectional operation is enabled or
+.Fl bidir
+to indicate that it is disabled, string
+.Cm dtrwait
+and current waiting time in ticks
+after DTR drop.
+To modify the status of the port or waiting time, simply
+specify the desired new state
+and/or new waiting time
+on the command line. All users with
+read access to the
+.Ar sio_special_device
+can use
+.Nm comcontrol
+to get the port's status and current waiting time.
+Only root can set a port's status and waiting time.
+By default, each port is initially unidirectional, waiting time is
+2 seconds.
+.Pp
+The standard way to use
+.Nm comcontrol
+is to put invocations of it in the
+.Ar /etc/rc.local
+startup script.
+.Sh SEE ALSO
+.Xr sio 4
+.Sh FILES
+.Bl -tag -width Pa
+.It Pa /dev/ttyd?
+.Sh DIAGNOSTICS
+.Cm TIOCMSBIDIR: Inappropriate ioctl for device.
+.Pp
+This indicates attempt to change port status on
+a non-sio special device file,
+or the kernel has not been built with
+.Cm options COM_BIDIR .
+For more information concerning reconfiguration
+of your kernel see
+.Ar /usr/src/sys/i386/doc/config_options.doc.
+.Sh AUTHOR
+Christopher G. Demetriou
+.Sh BUGS
+It is strongly recommended that you do *not*
+change the bidirectional status of a port while there are programs
+using the port. Read that as: if you do, and it breaks, don't yell
+at me; that's a really weird thing to do.
+.Sh HISTORY
+Originally part of cgd's com package patches, version 0.2.1, to 386BSD 0.1.
diff --git a/sbin/comcontrol/comcontrol.c b/sbin/comcontrol/comcontrol.c
new file mode 100644
index 0000000..e88e3d8
--- /dev/null
+++ b/sbin/comcontrol/comcontrol.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1992 Christopher G. Demetriou
+ * 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. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ */
+
+/* comcontrol.c */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+
+void usage(char *progname)
+{
+ fprintf(stderr, "usage: %s <filename> [[-]bidir] [dtrwait <n>]\n", progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res;
+ int dtrwait;
+
+ if ((argc < 2) || (argc > 5)) usage(argv[0]);
+
+ fd = open(argv[1], O_RDONLY|O_NONBLOCK, 0);
+ if (fd < 0) {
+ fprintf(stderr, "%s: couldn't open file %s\n", argv[0], argv[1]);
+ perror("open");
+ exit(1);
+ }
+
+ if (argc == 2) {
+ if (ioctl(fd, TIOCMGBIDIR, &res) >= 0) {
+ if (!res) printf("-");
+ printf("bidir ");
+ }
+ if (ioctl(fd, TIOCMGDTRWAIT, &dtrwait) < 0) {
+ perror("TIOCMGDTRWAIT");
+ exit(1);
+ }
+ printf("dtrwait %d\n", dtrwait);
+ } else {
+ char *prg = argv[0];
+
+ res = dtrwait = -1;
+ while (argv[2] != NULL) {
+ if (!strcmp(argv[2],"bidir")) {
+ if (res >= 0)
+ usage(prg);
+ res = 1;
+ argv++;
+ } else if (!strcmp(argv[2],"-bidir")) {
+ if (res >= 0)
+ usage(prg);
+ res = 0;
+ argv++;
+ } else if (!strcmp(argv[2],"dtrwait")) {
+ if (dtrwait >= 0)
+ usage(prg);
+ if (argv[3] == NULL || !isdigit(argv[3][0]))
+ usage(prg);
+ dtrwait = atoi(argv[3]);
+ argv += 2;
+ } else {
+ usage(prg);
+ }
+ }
+ if (res >= 0) {
+ if (ioctl(fd, TIOCMSBIDIR, &res) < 0) {
+ perror("TIOCMSBIDIR");
+ exit(1);
+ }
+ }
+ if (dtrwait >= 0) {
+ if (ioctl(fd, TIOCMSDTRWAIT, &dtrwait) < 0) {
+ perror("TIOCMSDTRWAIT");
+ exit(1);
+ }
+ }
+ }
+
+ close(fd);
+ exit(0);
+}
diff --git a/sbin/fdisk/Makefile b/sbin/fdisk/Makefile
new file mode 100644
index 0000000..78b1c9a
--- /dev/null
+++ b/sbin/fdisk/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 1.1 (Julian Elischer) 3/28/93
+#
+#
+
+PROG= fdisk
+SRCS= fdisk.c
+MAN8= fdisk.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/fdisk/fdisk.8 b/sbin/fdisk/fdisk.8
new file mode 100644
index 0000000..5eb2dea
--- /dev/null
+++ b/sbin/fdisk/fdisk.8
@@ -0,0 +1,178 @@
+.Dd April 4, 1993
+.Dt FDISK 8
+.\".Os BSD 4
+.Sh NAME
+.Nm fdisk
+.Nd DOS partition maintainance program
+.Sh SYNOPSIS
+.Nm
+.Op Fl i
+.Op Fl u
+.Op disk
+.Bl -tag -width time
+.It Fl i
+Initializes sector 0 of the disk.
+.It Fl u
+Is used for updating (editing) sector 0 of the disk.
+.El
+.Sh PROLOGUE
+In order for the BIOS to boot the kernel,
+certain conventions must be adhered to.
+Sector 0 of the disk must contain boot code,
+a partition table,
+and a magic number.
+BIOS partitions can be used to break the disk up into several pieces.
+The BIOS brings in sector 0
+(does it really use the code?)
+and verifies the magic number.
+It then searches the 4 BIOS partitions described by sector 0
+to determine which of them is
+.Em active.
+This boot then brings in the secondary boot block from the
+.Em active
+partition and runs it.
+Under DOS,
+you could have one or more partitions with one
+.Em active.
+The DOS
+.Nm
+program can be used to divide space on the disk into partitions and set one
+.Em active.
+.Sh DESCRIPTION
+The 386bsd program
+.Nm
+serves a similar purpose to the DOS program.
+When called with no arguments, it prints the sector 0 partition table.
+An example follows:
+
+.Bd -literal
+ ******* Working on device /dev/rwd0d *******
+ parameters extracted from in-core disklabel are:
+ cylinders=769 heads=15 sectors/track=33 (495 blks/cyl)
+
+ parameters to be used for BIOS calculations are:
+ cylinders=769 heads=15 sectors/track=33 (495 blks/cyl)
+
+ Warning: BIOS sector numbering starts with sector 1
+ Information from DOS bootblock is:
+ The data for partition 0 is:
+ sysid 165,(386BSD)
+ start 495, size 380160 (185 Meg), flag 0
+ beg: cyl 1/ sector 1/ head 0;
+ end: cyl 768/ sector 33/ head 14
+ The data for partition 1 is:
+ sysid 164,(unknown)
+ start 378180, size 2475 (1 Meg), flag 0
+ beg: cyl 764/ sector 1/ head 0;
+ end: cyl 768/ sector 33/ head 14
+ The data for partition 2 is:
+ <UNUSED>
+ The data for partition 3 is:
+ sysid 99,(ISC UNIX, other System V/386, GNU HURD or Mach)
+ start 380656, size 224234 (109 Meg), flag 80
+ beg: cyl 769/ sector 2/ head 0;
+ end: cyl 197/ sector 33/ head 14
+.Ed
+.Pp
+The disk is divided into three parititions that happen to fill the disk.
+The second partition overlaps the end of the first.
+(Used for debugging purposes)
+.Bl -tag -width "cyl, sector and head"
+.It Em "sysid"
+is used to label the partition. 386bsd reserves the
+magic number 165 decimal (A5 in hex).
+.It Em "start and size"
+fields provide the start address
+and size of a parition in sectors.
+.It Em "flag 80"
+specifies that this is the active partition.
+.It Em "cyl, sector and head"
+fields are used to specify the beginning address
+and end address for the parititon.
+.It Em "Note:"
+these numbers are calculated using BIOS's understanding of the disk geometry
+and saved in the bootblock.
+.El
+.Pp
+The flags
+.Fl i
+or
+.Fl u
+are used to indicate that the paritition data is to be updated.
+The
+.Nm
+program will enter a conversational mode.
+This mode is designed not to change any data unless you explicitly tell it to.
+.Nm
+selects defaults for its questions to guarantee the above behavior.
+.Pp
+It displays each partition
+and ask if you want to edit it.
+If you say yes,
+it will step through each field showing the old value
+and asking for a new one.
+When you are done with a partition,
+.Nm
+will display it and ask if it is correct.
+.Nm
+will then procede to the next entry.
+.Pp
+Getting the
+.Em cyl, sector,
+and
+.Em head
+fields correct is tricky.
+So by default,
+they will be calculated for you;
+you can specify them if you choose.
+.Pp
+After all the partitions are processed,
+you are given the option to change the
+.Em active
+partition.
+Finally,
+when the all the data for the first sector has been accumulated,
+you are asked if you really want to rewrite sector 0.
+Only if you answer yes,
+will the data be written to disk.
+.Pp
+The difference between the
+.Fl u
+flag and
+.Fl i
+flag is that
+the
+.Fl u
+flag just edits the fields as they appear on the disk.
+While the
+.Fl i
+flag is used to "initialize" sector 0;
+it will setup the last BIOS partition to use the whole disk for 386bsd;
+and make it active.
+.Sh NOTES
+.Pp
+The automatic calculation of starting cylinder etc. uses
+a set of figures that represent what the BIOS thinks is the
+geometry of the drive.
+These figures are by default taken from the incore disklabel,
+but the program initially gives you an oportunity to change them.
+This allows the user to create a bootblock that can work with drives
+that use geometry translation under the BIOS.
+.Pp
+If you hand craft your disk layout,
+please make sure that the 386bsd partition starts on a cylinder boundary.
+A number of decisions made later may assume this.
+(This might not be necessary later.)
+.Pp
+Editing an existing partition will most likely cause you to
+lose all the data in that partition.
+.Pp
+You should run this program interactively once or twice to see how it works.
+This is completely safe as long as you answer the last question in the negative.
+There are subtleties
+that the program detects
+that are not fully explained in this manual page.
+.Sh SEE ALSO
+.Xr disklabel 8
+.Sh BUGS
+One less now, but probably more
diff --git a/sbin/fdisk/fdisk.c b/sbin/fdisk/fdisk.c
new file mode 100644
index 0000000..7fb728d
--- /dev/null
+++ b/sbin/fdisk/fdisk.c
@@ -0,0 +1,686 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <sys/types.h>
+#include <sys/disklabel.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+int iotest;
+
+#define LBUF 100
+static char lbuf[LBUF];
+
+/*
+ *
+ * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992
+ *
+ * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University
+ * Copyright (c) 1989 Robert. V. Baron
+ * Created.
+ */
+
+#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
+#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
+#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
+
+#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
+
+#define SECSIZE 512
+
+char *disk = "/dev/rwd0d";
+char *name;
+
+struct disklabel disklabel; /* disk parameters */
+
+int cyls, sectors, heads, cylsecs, disksecs;
+
+struct mboot
+{
+ unsigned char padding[2]; /* force the longs to be long alligned */
+ unsigned char bootinst[DOSPARTOFF];
+ struct dos_partition parts[4];
+ unsigned short int signature;
+};
+struct mboot mboot;
+
+#define ACTIVE 0x80
+#define BOOT_MAGIC 0xAA55
+
+int dos_cyls;
+int dos_heads;
+int dos_sectors;
+int dos_cylsecs;
+
+#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
+#define DOSCYL(c) (c & 0xff)
+static int dos();
+char *get_type();
+static int partition = -1;
+
+
+static int a_flag = 0; /* set active partition */
+static int i_flag = 0; /* replace partition data */
+static int u_flag = 0; /* update partition data */
+
+static unsigned char bootcode[] = {
+0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
+0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
+0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
+0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
+0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
+0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
+0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
+0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
+0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
+'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
+ 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
+'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
+ 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
+'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
+ 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
+'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
+ 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+struct part_type
+{
+ unsigned char type;
+ char *name;
+}part_types[] =
+{
+ {0x00, "unused"}
+ ,{0x01, "Primary DOS with 12 bit FAT"}
+ ,{0x02, "XENIX / filesystem"}
+ ,{0x03, "XENIX /usr filesystem"}
+ ,{0x04, "Primary DOS with 16 bit FAT"}
+ ,{0x05, "Extended DOS"}
+ ,{0x06, "Primary 'big' DOS (> 32MB)"}
+ ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
+ ,{0x08, "AIX filesystem"}
+ ,{0x09, "AIX boot partition or Coherent"}
+ ,{0x0A, "OS/2 Boot Manager or OPUS"}
+ ,{0x10, "OPUS"}
+ ,{0x40, "VENIX 286"}
+ ,{0x50, "DM"}
+ ,{0x51, "DM"}
+ ,{0x52, "CP/M or Microport SysV/AT"}
+ ,{0x56, "GB"}
+ ,{0x61, "Speed"}
+ ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
+ ,{0x64, "Novell Netware 2.xx"}
+ ,{0x65, "Novell Netware 3.xx"}
+ ,{0x75, "PCIX"}
+ ,{0x80, "Minix 1.1 ... 1.4a"}
+ ,{0x81, "Minix 1.4b ... 1.5.10"}
+ ,{0x82, "Linux"}
+ ,{0x93, "Amoeba filesystem"}
+ ,{0x94, "Amoeba bad block table"}
+ ,{0xA5, "386BSD"}
+ ,{0xB7, "BSDI BSD/386 filesystem"}
+ ,{0xB8, "BSDI BSD/386 swap"}
+ ,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
+ ,{0xE1, "Speed"}
+ ,{0xE3, "Speed"}
+ ,{0xE4, "Speed"}
+ ,{0xF1, "Speed"}
+ ,{0xF2, "DOS 3.3+ Secondary"}
+ ,{0xF4, "Speed"}
+ ,{0xFF, "BBT (Bad Blocks Table)"}
+};
+
+
+main(argc, argv)
+char **argv;
+{
+int i;
+
+ name = *argv;
+ {register char *cp = name;
+ while (*cp) if (*cp++ == '/') name = cp;
+ }
+
+ for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
+ if (*token++ != '-' || !*token)
+ break;
+ else { register int flag;
+ for ( ; flag = *token++ ; ) {
+ switch (flag) {
+ case '0':
+ partition = 0;
+ break;
+ case '1':
+ partition = 1;
+ break;
+ case '2':
+ partition = 2;
+ break;
+ case '3':
+ partition = 3;
+ break;
+ case 'a':
+ a_flag = 1;
+ break;
+ case 'i':
+ i_flag = 1;
+ case 'u':
+ u_flag = 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+ }
+ }
+
+ if (argc > 0)
+ disk = argv[0];
+
+ if (open_disk(u_flag) < 0)
+ exit(1);
+
+ printf("******* Working on device %s *******\n",disk);
+ if(u_flag)
+ {
+ get_params_to_use();
+ }
+ else
+ {
+ print_params();
+ }
+
+ if (read_s0())
+ init_sector0(1);
+
+ printf("Warning: BIOS sector numbering starts with sector 1\n");
+ printf("Information from DOS bootblock is:\n");
+ if (partition == -1)
+ for (i = 0; i < NDOSPART; i++)
+ change_part(i);
+ else
+ change_part(partition);
+
+ if (u_flag || a_flag)
+ change_active(partition);
+
+ if (u_flag || a_flag) {
+ printf("\nWe haven't changed the partition table yet. ");
+ printf("This is your last chance.\n");
+ print_s0(-1);
+ if (ok("Should we write new partition table?"))
+ write_s0();
+ }
+
+ exit(0);
+
+usage:
+ printf("fdisk {-a|-i|-r} {disk}\n");
+}
+
+print_s0(which)
+{
+int i;
+
+ print_params();
+ printf("Information from DOS bootblock is:\n");
+ if (which == -1)
+ for (i = 0; i < NDOSPART; i++)
+ printf("%d: ", i), print_part(i);
+ else
+ print_part(which);
+}
+
+static struct dos_partition mtpart = { 0 };
+
+print_part(i)
+{
+struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
+
+
+ if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
+ printf("<UNUSED>\n");
+ return;
+ }
+ printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
+ printf(" start %d, size %d (%d Meg), flag %x\n",
+ partp->dp_start,
+ partp->dp_size, partp->dp_size * 512 / (1024 * 1024),
+ partp->dp_flag);
+ printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
+ ,DPCYL(partp->dp_scyl, partp->dp_ssect)
+ ,DPSECT(partp->dp_ssect)
+ ,partp->dp_shd
+ ,DPCYL(partp->dp_ecyl, partp->dp_esect)
+ ,DPSECT(partp->dp_esect)
+ ,partp->dp_ehd);
+}
+
+init_sector0(start)
+{
+struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
+int size = disksecs - start;
+int rest;
+
+ memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
+ mboot.signature = BOOT_MAGIC;
+
+ partp->dp_typ = DOSPTYP_386BSD;
+ partp->dp_flag = ACTIVE;
+ partp->dp_start = start;
+ partp->dp_size = size;
+
+ dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
+ dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
+}
+
+change_part(i)
+{
+struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
+
+ printf("The data for partition %d is:\n", i);
+ print_part(i);
+
+ if (u_flag && ok("Do you want to change it?")) {
+ int tmp;
+
+ if (i_flag) {
+ bzero((char *)partp, sizeof (struct dos_partition));
+ if (i == 3) {
+ init_sector0(1);
+ printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
+ print_part(i);
+ }
+ }
+
+ do {
+ Decimal("sysid", partp->dp_typ, tmp);
+ Decimal("start", partp->dp_start, tmp);
+ Decimal("size", partp->dp_size, tmp);
+
+ if (ok("Explicitly specifiy beg/end address ?"))
+ {
+ int tsec,tcyl,thd;
+ tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
+ thd = partp->dp_shd;
+ tsec = DPSECT(partp->dp_ssect);
+ Decimal("beginning cylinder", tcyl, tmp);
+ Decimal("beginning head", thd, tmp);
+ Decimal("beginning sector", tsec, tmp);
+ partp->dp_scyl = DOSCYL(tcyl);
+ partp->dp_ssect = DOSSECT(tsec,tcyl);
+ partp->dp_shd = thd;
+
+ tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
+ thd = partp->dp_ehd;
+ tsec = DPSECT(partp->dp_esect);
+ Decimal("ending cylinder", tcyl, tmp);
+ Decimal("ending head", thd, tmp);
+ Decimal("ending sector", tsec, tmp);
+ partp->dp_ecyl = DOSCYL(tcyl);
+ partp->dp_esect = DOSSECT(tsec,tcyl);
+ partp->dp_ehd = thd;
+ } else {
+ dos(partp->dp_start,
+ &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
+ dos(partp->dp_start+partp->dp_size - 1,
+ &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
+ }
+
+ print_part(i);
+ } while (!ok("Are we happy with this entry?"));
+ }
+}
+
+print_params()
+{
+ printf("parameters extracted from in-core disklabel are:\n");
+ printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
+ ,cyls,heads,sectors,cylsecs);
+ if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
+ printf(" Figures below won't work with BIOS for partitions not in cyl 1\n");
+ printf("parameters to be used for BIOS calculations are:\n");
+ printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
+ ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
+}
+
+change_active(which)
+{
+int i;
+int active = 3, tmp;
+struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
+
+ if (a_flag && which != -1)
+ active = which;
+ if (ok("Do you want to change the active partition?")) {
+ do
+ Decimal("active partition", active, tmp);
+ while(!ok("Are you happy with this choice"));
+ }
+ for (i = 0; i < NDOSPART; i++)
+ partp[i].dp_flag = 0;
+ partp[active].dp_flag = ACTIVE;
+}
+
+get_params_to_use()
+{
+ int tmp;
+ print_params();
+ if (ok("Do you want to change our idea of what BIOS thinks ?"))
+ {
+ do
+ {
+ Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
+ Decimal("BIOS's idea of #heads", dos_heads, tmp);
+ Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
+ dos_cylsecs = dos_heads * dos_sectors;
+ print_params();
+ }
+ while(!ok("Are you happy with this choice"));
+ }
+}
+
+/***********************************************\
+* Change real numbers into strange dos numbers *
+\***********************************************/
+static
+dos(sec, c, s, h)
+int sec;
+unsigned char *c, *s, *h;
+{
+int cy;
+int hd;
+
+ cy = sec / ( dos_cylsecs );
+ sec = sec - cy * ( dos_cylsecs );
+
+ hd = sec / dos_sectors;
+ sec = (sec - hd * dos_sectors) + 1;
+
+ *h = hd;
+ *c = cy & 0xff;
+ *s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
+}
+
+int fd;
+
+ /* Getting device status */
+
+open_disk(u_flag)
+{
+struct stat st;
+
+ if (stat(disk, &st) == -1) {
+ fprintf(stderr, "%s: Can't get file status of %s\n",
+ name, disk);
+ return -1;
+ } else if ( !(st.st_mode & S_IFCHR) ) {
+ fprintf(stderr,"%s: Device %s is not character special\n",
+ name, disk);
+ return -1;
+ }
+ if ((fd = open(disk, u_flag?O_RDWR:O_RDONLY)) == -1) {
+ fprintf(stderr,"%s: Can't open device %s\n", name, disk);
+ return -1;
+ }
+ if (get_params(0) == -1) {
+ fprintf(stderr, "%s: Can't get disk parameters on %s\n",
+ name, disk);
+ return -1;
+ }
+ return fd;
+}
+
+
+read_disk(sector, buf)
+{
+ lseek(fd,(sector * 512), 0);
+ return read(fd, buf, 512);
+}
+
+write_disk(sector, buf)
+{
+ lseek(fd,(sector * 512), 0);
+ return write(fd, buf, 512);
+}
+
+get_params(verbose)
+{
+
+ if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
+ return -1;
+ }
+
+ dos_cyls = cyls = disklabel.d_ncylinders;
+ dos_heads = heads = disklabel.d_ntracks;
+ dos_sectors = sectors = disklabel.d_nsectors;
+ dos_cylsecs = cylsecs = heads * sectors;
+ disksecs = cyls * heads * sectors;
+
+ return (disksecs);
+}
+
+
+read_s0()
+{
+ if (read_disk(0, (char *) mboot.bootinst) == -1) {
+ fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
+ return -1;
+ }
+ if (mboot.signature != BOOT_MAGIC) {
+ fprintf(stderr, "%s: Invalid fdisk partition table found\n",
+ name);
+ /* So should we initialize things */
+ return -1;
+ }
+ return 0;
+}
+
+write_s0()
+{
+ int flag;
+ if (iotest) {
+ print_s0(-1);
+ return 0;
+ }
+ /*
+ * write enable label sector before write (if necessary),
+ * disable after writing.
+ * needed if the disklabel protected area also protects
+ * sector 0. (e.g. empty disk)
+ */
+ flag = 1;
+ if (ioctl(fd, DIOCWLABEL, &flag) < 0)
+ perror("ioctl DIOCWLABEL");
+ if (write_disk(0, (char *) mboot.bootinst) == -1) {
+ fprintf(stderr, "%s: Can't write fdisk partition table\n",
+ name);
+ return -1;
+ flag = 0;
+ (void) ioctl(fd, DIOCWLABEL, &flag);
+ }
+}
+
+
+
+ok(str)
+char *str;
+{
+ printf("%s [n] ", str);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (*lbuf &&
+ (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
+ !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
+ return 1;
+ else
+ return 0;
+}
+
+decimal(str, num, deflt)
+char *str;
+int *num;
+{
+int acc = 0, c;
+char *cp;
+
+ while (1) {
+ printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (!*lbuf)
+ return 0;
+
+ cp = lbuf;
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c)
+ return 0;
+ while (c = *cp++) {
+ if (c <= '9' && c >= '0')
+ acc = acc * 10 + c - '0';
+ else
+ break;
+ }
+ if (c == ' ' || c == '\t')
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c) {
+ *num = acc;
+ return 1;
+ } else
+ printf("%s is an invalid decimal number. Try again\n",
+ lbuf);
+ }
+
+}
+
+hex(str, num, deflt)
+char *str;
+int *num;
+{
+int acc = 0, c;
+char *cp;
+
+ while (1) {
+ printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (!*lbuf)
+ return 0;
+
+ cp = lbuf;
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c)
+ return 0;
+ while (c = *cp++) {
+ if (c <= '9' && c >= '0')
+ acc = (acc << 4) + c - '0';
+ else if (c <= 'f' && c >= 'a')
+ acc = (acc << 4) + c - 'a' + 10;
+ else if (c <= 'F' && c >= 'A')
+ acc = (acc << 4) + c - 'A' + 10;
+ else
+ break;
+ }
+ if (c == ' ' || c == '\t')
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c) {
+ *num = acc;
+ return 1;
+ } else
+ printf("%s is an invalid hex number. Try again\n",
+ lbuf);
+ }
+
+}
+
+string(str, ans)
+char *str;
+char **ans;
+{
+int c;
+char *cp = lbuf;
+
+ while (1) {
+ printf("Supply a string value for \"%s\" [%s] ", str, *ans);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (!*lbuf)
+ return 0;
+
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (c == '"') {
+ c = *++cp;
+ *ans = cp;
+ while ((c = *cp) && c != '"') cp++;
+ } else {
+ *ans = cp;
+ while ((c = *cp) && c != ' ' && c != '\t') cp++;
+ }
+
+ if (c)
+ *cp = 0;
+ return 1;
+ }
+}
+
+char *get_type(type)
+int type;
+{
+ int numentries = (sizeof(part_types)/sizeof(struct part_type));
+ int counter = 0;
+ struct part_type *ptr = part_types;
+
+
+ while(counter < numentries)
+ {
+ if(ptr->type == type)
+ {
+ return(ptr->name);
+ }
+ ptr++;
+ counter++;
+ }
+ return("unknown");
+}
diff --git a/sbin/ft/Makefile b/sbin/ft/Makefile
new file mode 100644
index 0000000..3fb1b74
--- /dev/null
+++ b/sbin/ft/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= ft
+MAN8= ft.8
+SRCS= ft.c ftecc.c
+
+.include <bsd.prog.mk>
diff --git a/sbin/ft/ft.8 b/sbin/ft/ft.8
new file mode 100644
index 0000000..477f09b
--- /dev/null
+++ b/sbin/ft/ft.8
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1980, 1989, 1991 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.
+.\"
+.\" @(#)ft.8
+.\"
+.Dd February 7, 1994
+.Dt FT 8
+.Os BSD 4
+.Sh NAME
+.Nm ft
+.Nd QIC 40/80 floppy tape drive controller
+.Sh SYNOPSIS
+.Nm ft
+.Op Fl f Ar tape
+.Op Fl description
+.Sh DESCRIPTION
+The
+.Nm ft
+command allows multi-volume dump, extract, and view of tape labels, for
+any pre-formatted QIC-40/80 tapes. It is totally system dependent,
+and has nothing to do with the QIC standards.
+.Pp
+.Nm ft
+is used primarily as a filter for tape i/o.
+For example, to save and compress the /usr directory to tape:
+.Bd -literal -offset indent
+% tar cvzf - /usr | ft "/usr save"
+.Ed
+.Pp
+To extract /usr from tape:
+.Bd -literal -offset indent
+% ft | tar xvzf -
+.Ed
+.Sh SEE ALSO
+.Xr qtar 1
+.Sh BUGS
+Formatting/Verifying is in the works. You will need to use your
+existing backup program to do this for the time being.
+.Sh NOTES
+The floppy tape driver supports tape drives such as the Colorado
+Jumbo, Mountain Summit Express, some Archive/Conner models, and
+probably many others. These tape drives attach between your floppy
+disk controller card and your existing floppy disks' ribbon cable.
+This driver does not currently support attachments via a proprietary
+tape controller card or by the parallel port.
+.Pp
+QIC-40/80 drives are more CPU intensive than a SCSI drive. This is
+really only a factor if your machine is networked or has multiple concurrent
+users. For personal use (i.e. your typical home Unix user), response time
+is perfectly acceptable. The tape drives cannot detect write errors.
+Instead, they make up for it by using CRC's, error correction, and bad
+spot mapping. Formatting time is extremely long because of this. The
+drive makes a first pass over the entire tape writing out sectors. It
+then makes a second pass at a slower rate than usual (for sensitivity)
+to detect bad spots on the tape. Typically it takes an hour to format
+a single QIC-80 (120Mb uncompressed) tape.
+.Sh AUTHOR
+Steve Gerakines <steve2@genesis.nred.ma.us>
diff --git a/sbin/ft/ft.c b/sbin/ft/ft.c
new file mode 100644
index 0000000..4aa92f8
--- /dev/null
+++ b/sbin/ft/ft.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 1993 Steve Gerakines
+ *
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * ft.c - simple floppy tape filter
+ *
+ * 01/28/94 v0.3b (Jim Babb)
+ * Fixed bug when all sectors in a segment are marked bad.
+ *
+ * 10/30/93 v0.3
+ * Minor revisions. Seems pretty stable.
+ *
+ * 09/02/93 v0.2 pl01
+ * Initial revision.
+ *
+ * usage: ftfilt [ -f tape ] [ description ]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/ftape.h>
+
+#define DEFQIC "/dev/rft0"
+
+char buff[QCV_SEGSIZE]; /* scratch buffer */
+char hbuff[QCV_SEGSIZE]; /* header buffer */
+QIC_Header *hptr = (QIC_Header *)hbuff; /* header structure */
+int hsn = -1; /* segment number of header */
+int dhsn = -1; /* segment number of duplicate header */
+int tfd; /* tape file descriptor */
+QIC_Geom geo; /* tape geometry */
+int tvno = 1; /* tape volume number */
+int tvlast; /* TRUE if last volume in set */
+long tvsize = 0; /* tape volume size in bytes */
+long tvtime = NULL; /* tape change time */
+char *tvnote = ""; /* tape note */
+
+/* Lookup the badmap for a given track and segment. */
+#define BADMAP(t,s) hptr->qh_badmap[(t)*geo.g_segtrk+(s)]
+
+/* Retrieve values from a character array. */
+#define UL_VAL(s,p) (*((ULONG *)&(s)[p]))
+#define US_VAL(s,p) (*((USHORT *)&(s)[p]))
+
+#define equal(s1,s2) (strcmp(s1, s2) == 0)
+
+
+
+/* Entry */
+main(int argc, char *argv[])
+{
+ int r, s;
+ char *tape, *getenv();
+
+ if (argc > 2 && (equal(argv[1], "-t") || equal(argv[1], "-f"))) {
+ argc -= 2;
+ tape = argv[2];
+ argv += 2;
+ } else
+ if ((tape = getenv("TAPE")) == NULL)
+ tape = DEFQIC;
+ if (argc > 1) {
+ tvnote = argv[1];
+ if (strlen(tvnote) > 18) argv[1][18] = '\0';
+ }
+
+ /* Open the tape device */
+ if ((tfd = open(tape, 2)) < 0) {
+ perror(tape);
+ exit(1);
+ }
+
+ if (!isatty(0))
+ do_write();
+ else if (!isatty(1))
+ do_read();
+ else
+ do_getname();
+
+ close(tfd);
+ exit(0);
+}
+
+
+/* Check status of tape drive */
+int check_stat(int fd, int wr)
+{
+ int r, s;
+ int sawit = 0;
+
+ /* get tape status */
+ if (ioctl(fd, QIOSTATUS, &s) < 0) {
+ fprintf(stderr, "could not get drive status\n");
+ return(1);
+ }
+
+ /* wait for the tape drive to become ready */
+ while ((s & QS_READY) == 0) {
+ if (!sawit) {
+ fprintf(stderr, "waiting for drive to become ready...\n");
+ sawit = 1;
+ }
+ sleep(2);
+ if (ioctl(fd, QIOSTATUS, &s) < 0) {
+ fprintf(stderr, "could not get drive status\n");
+ return(1);
+ }
+ }
+
+ if ((s & QS_FMTOK) == 0) {
+ fprintf(stderr, "tape is not formatted\n");
+ return(2);
+ }
+
+ if (wr && (s & QS_RDONLY) != 0) {
+ fprintf(stderr, "tape is write protected\n");
+ return(3);
+ }
+
+ return(0);
+}
+
+
+
+ULONG qtimeval(time_t t)
+{
+ struct tm *tp;
+ ULONG r;
+
+ tp = localtime(&t);
+ r = 2678400 * tp->tm_mon +
+ 86400 *(tp->tm_mday-1) +
+ 3600 * tp->tm_hour +
+ 60 * tp->tm_min +
+ tp->tm_sec;
+ r |= (tp->tm_year - 70) << 25;
+ return(r);
+}
+
+/* Return tm struct from QIC date format. */
+struct tm *qtime(UCHAR *qt)
+{
+ ULONG *vp = (ULONG *)qt;
+ struct tm t;
+ ULONG v;
+ time_t tv;
+
+ v = *vp;
+ t.tm_year = ((v >> 25) & 0x7f)+70; v &= 0x1ffffff;
+ t.tm_mon = v / 2678400; v %= 2678400;
+ t.tm_mday = v / 86400 + 1; v %= 86400;
+ t.tm_hour = v / 3600; v %= 3600;
+ t.tm_min = v / 60; v %= 60;
+ t.tm_sec = v;
+ t.tm_wday = 0; /* XXX - let mktime do the real work */
+ t.tm_yday = 0;
+ t.tm_isdst = 0;
+ t.tm_gmtoff = 0;
+ t.tm_zone = NULL;
+ tv = mktime(&t);
+ return(localtime(&tv));
+}
+
+/* Return a string, zero terminated */
+char *qstr(char *str, int nchar)
+{
+ static char tstr[256];
+ strncpy(tstr, str, nchar);
+ tstr[nchar] = '\0';
+ return(tstr);
+}
+
+/* Read header from tape */
+get_header(int fd)
+{
+ int r, sn, bytes;
+ QIC_Segment s;
+ int gothdr = 0;
+
+ if (ioctl(fd, QIOGEOM, &geo) < 0) {
+ fprintf(stderr, "couldn't determine tape geometry\n");
+ return(1);
+ }
+
+ /* Get the header and duplicate */
+ for (sn = 0; sn < 16; sn++) {
+ s.sg_trk = 0;
+ s.sg_seg = sn;
+ s.sg_badmap = 0;
+ s.sg_data = (UCHAR *)&buff[0];
+ ioctl(fd, QIOREAD, &s);
+ r = check_parity(s.sg_data, 0, s.sg_crcmap);
+ if (s.sg_data[0] == 0x55 && s.sg_data[1] == 0xaa &&
+ s.sg_data[2] == 0x55 && s.sg_data[3] == 0xaa) {
+ if (hsn >= 0) {
+ dhsn = sn;
+ if (!r && !gothdr) {
+ fprintf(stderr, "using secondary header\n");
+ bcopy(s.sg_data, hbuff, QCV_SEGSIZE);
+ gothdr = 1;
+ }
+ break;
+ }
+ hsn = sn;
+ if (!r) {
+ bcopy(s.sg_data, hbuff, QCV_SEGSIZE);
+ gothdr = 1;
+ } else {
+ fprintf(stderr, "too many errors in primary header\n");
+ }
+ }
+ }
+
+ if (!gothdr) {
+ fprintf(stderr, "couldn't read header segment\n");
+ ioctl(fd, QIOREWIND);
+ return(1);
+ }
+
+ return(0);
+}
+
+
+ask_vol(int vn)
+{
+ FILE *inp;
+ int fd;
+ char c;
+
+ if ((fd = open("/dev/tty", 2)) < 0) {
+ fprintf(stderr, "argh!! can't open /dev/tty\n");
+ exit(1);
+ }
+
+ fprintf(stderr, "Insert ftfilt volume %02d and press enter:", vn);
+ read(fd, &c, 1);
+ close(fd);
+}
+
+
+/* Return the name of the tape only. */
+do_getname()
+{
+ if (check_stat(tfd, 0)) exit(1);
+ if (get_header(tfd)) exit(1);
+ fprintf(stderr, "\"%s\" - %s",
+ qstr(hptr->qh_tname,44), asctime(qtime(hptr->qh_chgdate)));
+ ioctl(tfd, QIOREWIND);
+}
+
+
+/* Extract data from tape to stdout */
+do_read()
+{
+ int sno, vno, sbytes, r;
+ long curpos;
+ char *hname;
+ QIC_Segment s;
+
+ /* Process multiple volumes if necessary */
+ vno = 1;
+ for (;;) {
+ if (check_stat(tfd, 0)) {
+ ask_vol(vno);
+ continue;
+ }
+ if (get_header(tfd)) {
+ ask_vol(vno);
+ continue;
+ }
+
+ /* extract volume and header info from label */
+ hname = hptr->qh_tname;
+ hname[43] = '\0';
+ tvno = atoi(&hname[11]);
+ tvlast = (hname[10] == '*') ? 1 : 0;
+ tvsize = atoi(&hname[14]);
+ tvnote = &hname[25];
+ if (vno != tvno || strncmp(hname, "ftfilt", 6) != 0) {
+ fprintf(stderr, "Incorrect volume inserted. This tape is:\n");
+ fprintf(stderr,"\"%s\" - %s\n", hname,
+ asctime(qtime(hptr->qh_chgdate)));
+ ask_vol(vno);
+ continue;
+ }
+
+ /* Process this volume */
+ curpos = 0;
+ for (sno = hptr->qh_first; tvsize > 0; sno++) {
+ s.sg_trk = sno / geo.g_segtrk;
+ s.sg_seg = sno % geo.g_segtrk;
+ s.sg_badmap = BADMAP(s.sg_trk,s.sg_seg);
+ sbytes = sect_bytes(s.sg_badmap) - QCV_ECCSIZE;
+ s.sg_data = (UCHAR *)&buff[0];
+
+ /* skip segments with *all* sectors flagged as bad */
+ if (sbytes > 0) {
+ if (ioctl(tfd, QIOREAD, &s) < 0) perror("QIOREAD");
+ r = check_parity(s.sg_data, s.sg_badmap, s.sg_crcmap);
+ if (r) fprintf(stderr, "** warning: ecc failed at byte %ld\n",
+ curpos);
+ if (tvsize < sbytes) sbytes = tvsize;
+ write(1, s.sg_data, sbytes);
+ tvsize -= sbytes;
+ curpos += sbytes;
+ }
+ }
+ if (tvlast) break;
+ ioctl(tfd, QIOREWIND);
+ ask_vol(++vno);
+ }
+ ioctl(tfd, QIOREWIND);
+ return(0);
+}
+
+
+/* Dump data from stdin to tape */
+do_write()
+{
+ int sno, vno, amt, sbytes;
+ int c, maxseg, r;
+ ULONG qnow;
+ QIC_Segment s;
+ char tmpstr[80];
+
+ qnow = qtimeval(time(NULL));
+ vno = 1;
+
+ for (;;) {
+ if (check_stat(tfd, 1)) {
+ ask_vol(vno);
+ continue;
+ }
+ if (get_header(tfd)) {
+ ask_vol(vno);
+ continue;
+ }
+
+ maxseg = geo.g_segtrk * geo.g_trktape - 1;
+ sno = hptr->qh_first;
+ tvno = vno;
+ tvsize = 0;
+ tvlast = 0;
+
+ /* Process until end of volume or end of data */
+ for (sno = hptr->qh_first; sno < maxseg && tvlast == 0; ++sno) {
+ /* Prepare to load the next segment */
+ s.sg_trk = sno / geo.g_segtrk;
+ s.sg_seg = sno % geo.g_segtrk;
+ s.sg_badmap = BADMAP(s.sg_trk,s.sg_seg);
+ sbytes = sect_bytes(s.sg_badmap) - QCV_ECCSIZE;
+ s.sg_data = (UCHAR *)&buff[0];
+
+ /* Ugh. Loop to get the full amt. */
+ for (amt = 0; amt < sbytes; amt += r) {
+ r = read(0, &s.sg_data[amt], sbytes - amt);
+ if (r <= 0) {
+ tvlast = 1;
+ break;
+ }
+ }
+ /* skip the segment if *all* sectors are flagged as bad */
+ if (amt) {
+ if (amt < sbytes)
+ bzero(&s.sg_data[amt], sbytes - amt);
+ r = set_parity(s.sg_data, s.sg_badmap);
+ if (r) fprintf(stderr, "** warning: ecc problem !!\n");
+ if (ioctl(tfd, QIOWRITE, &s) < 0) {
+ perror("QIOWRITE");
+ exit(1);
+ }
+ tvsize += amt;
+ }
+ }
+
+ /* Build new header info */
+ /* ftfilt vol*xx yyyyyyyyyy note56789012345678 */
+ /* 01234567890123456789012345678901234567890123 */
+
+ sprintf(tmpstr, "ftfilt vol%s%02d %010d %s",
+ (tvlast) ? "*" : " ", tvno, tvsize, tvnote);
+ strncpy(hptr->qh_tname, tmpstr, 44);
+ UL_VAL(hptr->qh_chgdate,0) = qnow;
+
+ /* Update the header for this volume */
+ if (hsn >= 0) {
+ s.sg_trk = hsn / geo.g_segtrk;
+ s.sg_seg = hsn % geo.g_segtrk;
+ s.sg_badmap = 0;
+ s.sg_data = (UCHAR *)hbuff;
+ r = set_parity(s.sg_data, s.sg_badmap);
+ if (r) fprintf(stderr, "** warning: header ecc problem !!\n");
+ if (ioctl(tfd, QIOWRITE, &s) < 0) {
+ perror("QIOWRITE");
+ exit(1);
+ }
+ }
+ if (dhsn >= 0) {
+ s.sg_trk = dhsn / geo.g_segtrk;
+ s.sg_seg = dhsn % geo.g_segtrk;
+ s.sg_badmap = 0;
+ s.sg_data = (UCHAR *)hbuff;
+ r = set_parity(s.sg_data, s.sg_badmap);
+ if (r) fprintf(stderr, "** warning: duphdr ecc problem !!\n");
+ if (ioctl(tfd, QIOWRITE, &s) < 0) {
+ perror("QIOWRITE");
+ exit(1);
+ }
+ }
+ ioctl(tfd, QIOREWIND);
+ if (tvlast) break;
+ ask_vol(++vno);
+ }
+ return(0);
+}
diff --git a/sbin/ft/ftecc.c b/sbin/ft/ftecc.c
new file mode 100644
index 0000000..e499644
--- /dev/null
+++ b/sbin/ft/ftecc.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 1994 Steve Gerakines
+ *
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * ftecc.c - QIC-40/80 Reed-Solomon error correction
+ * 03/22/94 v0.4
+ * Major re-write. It can handle everything required by QIC now.
+ *
+ * 09/14/93 v0.2 pl01
+ * Modified slightly to fit with my driver. Based entirely upon David
+ * L. Brown's package.
+ */
+#include <sys/ftape.h>
+
+/* Inverse matrix */
+struct inv_mat {
+ UCHAR log_denom; /* Log of the denominator */
+ UCHAR zs[3][3]; /* The matrix */
+};
+
+
+/*
+ * Powers of x, modulo 255.
+ */
+static UCHAR alpha_power[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+ 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4,
+ 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb,
+ 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd,
+ 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31,
+ 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67,
+ 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc,
+ 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b,
+ 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4,
+ 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26,
+ 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21,
+ 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba,
+ 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30,
+ 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0,
+ 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3,
+ 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a,
+ 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9,
+ 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44,
+ 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef,
+ 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85,
+ 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6,
+ 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf,
+ 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff,
+ 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58,
+ 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a,
+ 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24,
+ 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8,
+ 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64,
+ 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2,
+ 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda,
+ 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77,
+ 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01
+};
+
+
+/*
+ * Log table, modulo 255 + 1.
+ */
+static UCHAR alpha_log[] = {
+ 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a,
+ 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a,
+ 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1,
+ 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3,
+ 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83,
+ 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4,
+ 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35,
+ 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38,
+ 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70,
+ 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48,
+ 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24,
+ 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15,
+ 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f,
+ 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10,
+ 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7,
+ 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b,
+ 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08,
+ 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a,
+ 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91,
+ 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb,
+ 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2,
+ 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf,
+ 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52,
+ 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86,
+ 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc,
+ 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc,
+ 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8,
+ 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44,
+ 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1,
+ 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97,
+ 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5,
+ 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7
+};
+
+
+/*
+ * Return number of sectors available in a segment.
+ */
+int
+sect_count(ULONG badmap)
+{
+ int i, amt;
+
+ for (amt = QCV_BLKSEG, i = 0; i < QCV_BLKSEG; i++)
+ if (badmap & (1 << i)) amt--;
+ return(amt);
+}
+
+
+/*
+ * Return number of bytes available in a segment.
+ */
+int
+sect_bytes(ULONG badmap)
+{
+ int i, amt;
+
+ for (amt = QCV_SEGSIZE, i = 0; i < QCV_BLKSEG; i++)
+ if (badmap & (1 << i)) amt -= QCV_BLKSIZE;
+ return(amt);
+}
+
+
+/*
+ * Multiply two numbers in the field.
+ */
+static UCHAR
+multiply(UCHAR a, UCHAR b)
+{
+ if (!a || !b) return(0);
+ return(alpha_power[(alpha_log[a] + alpha_log[b]) % 255]);
+}
+
+
+/*
+ * Multiply by an exponent.
+ */
+static UCHAR
+multiply_out(UCHAR a, int b)
+{
+ if (!a) return(0);
+ return(alpha_power[(alpha_log[a] + b) % 255]);
+}
+
+
+/*
+ * Divide two numbers.
+ */
+static UCHAR
+divide(UCHAR a, UCHAR b)
+{
+ int tmp;
+
+ if (!a || !b) return(0);
+ tmp = alpha_log[a] - alpha_log[b];
+ if (tmp < 0) tmp += 255;
+ return (alpha_power[tmp]);
+}
+
+
+/*
+ * Divide using exponent.
+ */
+static UCHAR
+divide_out(UCHAR a, UCHAR b)
+{
+ int tmp;
+
+ if (!a) return 0;
+ tmp = alpha_log[a] - b;
+ if (tmp < 0) tmp += 255;
+ return (alpha_power[tmp]);
+}
+
+
+/*
+ * This returns the value z^{a-b}.
+ */
+static UCHAR
+z_of_ab(UCHAR a, UCHAR b)
+{
+ int tmp = a - b;
+
+ if (tmp < 0) tmp += 255;
+ return(alpha_power[tmp % 255]);
+}
+
+
+/*
+ * Calculate the inverse matrix for two or three errors. Returns 0
+ * if there is no inverse or 1 if successful.
+ */
+static int
+calculate_inverse(int nerrs, int *pblk, struct inv_mat *inv)
+{
+ /* First some variables to remember some of the results. */
+ UCHAR z20, z10, z21, z12, z01, z02;
+ UCHAR i0, i1, i2;
+
+ if (nerrs < 2) return(1);
+ if (nerrs > 3) return(0);
+
+ i0 = pblk[0]; i1 = pblk[1]; i2 = pblk[2];
+ if (nerrs == 2) {
+ /* 2 errs */
+ z01 = alpha_power[255 - i0];
+ z02 = alpha_power[255 - i1];
+ inv->log_denom = (z01 ^ z02);
+ if (!inv->log_denom) return(0);
+ inv->log_denom = 255 - alpha_log[inv->log_denom];
+
+ inv->zs[0][0] = multiply_out( 1, inv->log_denom);
+ inv->zs[0][1] = multiply_out(z02, inv->log_denom);
+ inv->zs[1][0] = multiply_out( 1, inv->log_denom);
+ inv->zs[1][1] = multiply_out(z01, inv->log_denom);
+ } else {
+ /* 3 errs */
+ z20 = z_of_ab (i2, i0);
+ z10 = z_of_ab (i1, i0);
+ z21 = z_of_ab (i2, i1);
+ z12 = z_of_ab (i1, i2);
+ z01 = z_of_ab (i0, i1);
+ z02 = z_of_ab (i0, i2);
+ inv->log_denom = (z20 ^ z10 ^ z21 ^ z12 ^ z01 ^ z02);
+ if (!inv->log_denom) return(0);
+ inv->log_denom = 255 - alpha_log[inv->log_denom];
+
+ inv->zs[0][0] = multiply_out(alpha_power[i1] ^ alpha_power[i2],
+ inv->log_denom);
+ inv->zs[0][1] = multiply_out(z21 ^ z12, inv->log_denom);
+ inv->zs[0][2] = multiply_out(alpha_power[255-i1] ^ alpha_power[255-i2],
+ inv->log_denom);
+ inv->zs[1][0] = multiply_out(alpha_power[i0] ^ alpha_power[i2],
+ inv->log_denom);
+ inv->zs[1][1] = multiply_out(z20 ^ z02, inv->log_denom);
+ inv->zs[1][2] = multiply_out(alpha_power[255-i0] ^ alpha_power[255-i2],
+ inv->log_denom);
+ inv->zs[2][0] = multiply_out(alpha_power[i0] ^ alpha_power[i1],
+ inv->log_denom);
+ inv->zs[2][1] = multiply_out(z10 ^ z01, inv->log_denom);
+ inv->zs[2][2] = multiply_out(alpha_power[255-i0] ^ alpha_power[255-i1],
+ inv->log_denom);
+ }
+ return(1);
+}
+
+
+/*
+ * Determine the error magnitudes for a given matrix and syndromes.
+ */
+static void
+determine(int nerrs, struct inv_mat *inv, UCHAR *ss, UCHAR *es)
+{
+ UCHAR tmp;
+ int i, j;
+
+ for (i = 0; i < nerrs; i++) {
+ es[i] = 0;
+ for (j = 0; j < nerrs; j++)
+ es[i] ^= multiply(ss[j], inv->zs[i][j]);
+ }
+}
+
+
+/*
+ * Compute the 3 syndrome values.
+ */
+static int
+compute_syndromes(UCHAR *data, int nblks, int col, UCHAR *ss)
+{
+ UCHAR r0, r1, r2, t1, t2;
+ UCHAR *rptr;
+ int row;
+
+ rptr = &data[col];
+ r0 = r1 = r2 = 0;
+ for (row = 0; row < nblks; row++, rptr += QCV_BLKSIZE) {
+ t1 = *rptr ^ r0;
+ t2 = multiply(0xc0, t1);
+ r0 = t2 ^ r1;
+ r1 = t2 ^ r2;
+ r2 = t1;
+ }
+ if (r0 || r1 || r2) {
+ ss[0] = divide_out(r0 ^ divide_out(r1 ^ divide_out(r2, 1), 1), nblks);
+ ss[1] = r0 ^ r1 ^ r2;
+ ss[2] = multiply_out(r0 ^ multiply_out(r1 ^ multiply_out(r2, 1), 1), nblks);
+ return(0);
+ }
+ return(1);
+}
+
+
+/*
+ * Calculate the parity bytes for a segment, returns 0 on success (always).
+ */
+int
+set_parity (UCHAR *data, ULONG badmap)
+{
+ int col, row, max;
+ UCHAR r0, r1, r2, t1, t2;
+ UCHAR *rptr;
+
+ max = sect_count(badmap) - 3;
+ for (col = 0; col < QCV_BLKSIZE; col++, data++) {
+ rptr = data;
+ r0 = r1 = r2 = 0;
+ for (row = 0; row < max; row++, rptr += QCV_BLKSIZE) {
+ t1 = *rptr ^ r0;
+ t2 = multiply(0xc0, t1);
+ r0 = t2 ^ r1;
+ r1 = t2 ^ r2;
+ r2 = t1;
+ }
+ *rptr = r0; rptr += QCV_BLKSIZE;
+ *rptr = r1; rptr += QCV_BLKSIZE;
+ *rptr = r2;
+ }
+ return(0);
+}
+
+
+/*
+ * Check and correct errors in a block. Returns 0 on success,
+ * 1 if failed.
+ */
+int
+check_parity(UCHAR *data, ULONG badmap, ULONG crcmap)
+{
+ int crcerrs, eblk[3];
+ int col, row;
+ int i, j, nblks;
+ UCHAR ss[3], es[3];
+ int i1, i2, saverrs;
+ struct inv_mat inv;
+
+ nblks = sect_count(badmap);
+
+ /* Count the number of CRC errors and note their locations. */
+ crcerrs = 0;
+ if (crcmap) {
+ for (i = 0; i < nblks; i++) {
+ if (crcmap & (1 << i)) {
+ eblk[crcerrs++] = i;
+ if (crcerrs >= 3) break;
+ }
+ }
+ }
+
+ /* Calculate the inverse matrix */
+ if (!calculate_inverse(crcerrs, eblk, &inv)) return(1);
+
+ /* Scan each column for problems and attempt to correct. */
+ for (col = 0; col < QCV_BLKSIZE; col++) {
+ if (compute_syndromes(data, nblks, col, ss)) continue;
+ es[0] = es[1] = es[2] = 0;
+
+ /* Analyze the error situation. */
+ switch (crcerrs) {
+ case 0: /* 0 errors >0 failures */
+ if (!ss[0]) return(1);
+ eblk[crcerrs] = alpha_log[divide(ss[1], ss[0])];
+ if (eblk[crcerrs] >= nblks) return(1);
+ es[0] = ss[1];
+ crcerrs++;
+ break;
+
+ case 1: /* 1 error (+ possible failures) */
+ i1 = ss[2] ^ multiply_out(ss[1], eblk[0]);
+ i2 = ss[1] ^ multiply_out(ss[0], eblk[0]);
+ if (!i1 && !i2) { /* only 1 error */
+ inv.zs[0][0] = alpha_power[eblk[0]];
+ inv.log_denom = 0;
+ } else if (!i1 || !i2) { /* too many errors */
+ return(1);
+ } else { /* add failure */
+ eblk[crcerrs] = alpha_log[divide(i1, i2)];
+ if (eblk[crcerrs] >= nblks) return(1);
+ crcerrs++;
+ if (!calculate_inverse(crcerrs, eblk, &inv)) return(1);
+ }
+ determine(crcerrs, &inv, ss, es);
+ break;
+
+ case 2: /* 2 errors */
+ case 3: /* 3 errors */
+ determine(crcerrs, &inv, ss, es);
+ break;
+
+ default:
+ return(1);
+ }
+
+ /* Make corrections. */
+ for (i = 0; i < crcerrs; i++) {
+ data[eblk[i] * QCV_BLKSIZE+col] ^= es[i];
+ ss[0] ^= divide_out(es[i], eblk[i]);
+ ss[1] ^= es[i];
+ ss[2] ^= multiply_out(es[i], eblk[i]);
+ }
+ if (ss[0] || ss[1] || ss[2]) return(1);
+ }
+ return(0);
+}
diff --git a/sbin/i386/comcontrol/Makefile b/sbin/i386/comcontrol/Makefile
new file mode 100644
index 0000000..abc8d0a
--- /dev/null
+++ b/sbin/i386/comcontrol/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 5.4 (Berkeley) 6/5/91
+
+PROG= comcontrol
+MAN8= comcontrol.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/i386/comcontrol/comcontrol.8 b/sbin/i386/comcontrol/comcontrol.8
new file mode 100644
index 0000000..8da3e01
--- /dev/null
+++ b/sbin/i386/comcontrol/comcontrol.8
@@ -0,0 +1,74 @@
+.Dd December 10, 1993
+.Dt COMCONTROL 8
+.Os FreeBSD
+.Sh NAME
+.Nm comcontrol
+.Nd "control the bidirectional status of a sio port and waiting time after DTR drop"
+.Sh SYNOPSIS
+.Nm comcontrol
+.Ar sio_special_device
+.Op Cm bidir | Fl bidir
+.Op Cm dtrwait Ar ticks
+.Sh DESCRIPTION
+.Nm Comcontrol
+is used to examine and modify the bidirectional status
+of a specified
+sio communications port
+and its waiting time after DTR drop.
+By default (if
+.Ar sio_special_device
+only specified),
+.Nm comcontrol
+will print the current port state
+(if kernel was built with
+.Cm options COM_BIDIR )
+as either
+.Cm bidir
+to indicate that bidirectional operation is enabled or
+.Fl bidir
+to indicate that it is disabled, string
+.Cm dtrwait
+and current waiting time in ticks
+after DTR drop.
+To modify the status of the port or waiting time, simply
+specify the desired new state
+and/or new waiting time
+on the command line. All users with
+read access to the
+.Ar sio_special_device
+can use
+.Nm comcontrol
+to get the port's status and current waiting time.
+Only root can set a port's status and waiting time.
+By default, each port is initially unidirectional, waiting time is
+2 seconds.
+.Pp
+The standard way to use
+.Nm comcontrol
+is to put invocations of it in the
+.Ar /etc/rc.local
+startup script.
+.Sh SEE ALSO
+.Xr sio 4
+.Sh FILES
+.Bl -tag -width Pa
+.It Pa /dev/ttyd?
+.Sh DIAGNOSTICS
+.Cm TIOCMSBIDIR: Inappropriate ioctl for device.
+.Pp
+This indicates attempt to change port status on
+a non-sio special device file,
+or the kernel has not been built with
+.Cm options COM_BIDIR .
+For more information concerning reconfiguration
+of your kernel see
+.Ar /usr/src/sys/i386/doc/config_options.doc.
+.Sh AUTHOR
+Christopher G. Demetriou
+.Sh BUGS
+It is strongly recommended that you do *not*
+change the bidirectional status of a port while there are programs
+using the port. Read that as: if you do, and it breaks, don't yell
+at me; that's a really weird thing to do.
+.Sh HISTORY
+Originally part of cgd's com package patches, version 0.2.1, to 386BSD 0.1.
diff --git a/sbin/i386/comcontrol/comcontrol.c b/sbin/i386/comcontrol/comcontrol.c
new file mode 100644
index 0000000..e88e3d8
--- /dev/null
+++ b/sbin/i386/comcontrol/comcontrol.c
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 1992 Christopher G. Demetriou
+ * 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. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ */
+
+/* comcontrol.c */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+
+void usage(char *progname)
+{
+ fprintf(stderr, "usage: %s <filename> [[-]bidir] [dtrwait <n>]\n", progname);
+ exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+ int fd;
+ int res;
+ int dtrwait;
+
+ if ((argc < 2) || (argc > 5)) usage(argv[0]);
+
+ fd = open(argv[1], O_RDONLY|O_NONBLOCK, 0);
+ if (fd < 0) {
+ fprintf(stderr, "%s: couldn't open file %s\n", argv[0], argv[1]);
+ perror("open");
+ exit(1);
+ }
+
+ if (argc == 2) {
+ if (ioctl(fd, TIOCMGBIDIR, &res) >= 0) {
+ if (!res) printf("-");
+ printf("bidir ");
+ }
+ if (ioctl(fd, TIOCMGDTRWAIT, &dtrwait) < 0) {
+ perror("TIOCMGDTRWAIT");
+ exit(1);
+ }
+ printf("dtrwait %d\n", dtrwait);
+ } else {
+ char *prg = argv[0];
+
+ res = dtrwait = -1;
+ while (argv[2] != NULL) {
+ if (!strcmp(argv[2],"bidir")) {
+ if (res >= 0)
+ usage(prg);
+ res = 1;
+ argv++;
+ } else if (!strcmp(argv[2],"-bidir")) {
+ if (res >= 0)
+ usage(prg);
+ res = 0;
+ argv++;
+ } else if (!strcmp(argv[2],"dtrwait")) {
+ if (dtrwait >= 0)
+ usage(prg);
+ if (argv[3] == NULL || !isdigit(argv[3][0]))
+ usage(prg);
+ dtrwait = atoi(argv[3]);
+ argv += 2;
+ } else {
+ usage(prg);
+ }
+ }
+ if (res >= 0) {
+ if (ioctl(fd, TIOCMSBIDIR, &res) < 0) {
+ perror("TIOCMSBIDIR");
+ exit(1);
+ }
+ }
+ if (dtrwait >= 0) {
+ if (ioctl(fd, TIOCMSDTRWAIT, &dtrwait) < 0) {
+ perror("TIOCMSDTRWAIT");
+ exit(1);
+ }
+ }
+ }
+
+ close(fd);
+ exit(0);
+}
diff --git a/sbin/i386/fdisk/Makefile b/sbin/i386/fdisk/Makefile
new file mode 100644
index 0000000..78b1c9a
--- /dev/null
+++ b/sbin/i386/fdisk/Makefile
@@ -0,0 +1,9 @@
+# @(#)Makefile 1.1 (Julian Elischer) 3/28/93
+#
+#
+
+PROG= fdisk
+SRCS= fdisk.c
+MAN8= fdisk.8
+
+.include <bsd.prog.mk>
diff --git a/sbin/i386/fdisk/fdisk.8 b/sbin/i386/fdisk/fdisk.8
new file mode 100644
index 0000000..5eb2dea
--- /dev/null
+++ b/sbin/i386/fdisk/fdisk.8
@@ -0,0 +1,178 @@
+.Dd April 4, 1993
+.Dt FDISK 8
+.\".Os BSD 4
+.Sh NAME
+.Nm fdisk
+.Nd DOS partition maintainance program
+.Sh SYNOPSIS
+.Nm
+.Op Fl i
+.Op Fl u
+.Op disk
+.Bl -tag -width time
+.It Fl i
+Initializes sector 0 of the disk.
+.It Fl u
+Is used for updating (editing) sector 0 of the disk.
+.El
+.Sh PROLOGUE
+In order for the BIOS to boot the kernel,
+certain conventions must be adhered to.
+Sector 0 of the disk must contain boot code,
+a partition table,
+and a magic number.
+BIOS partitions can be used to break the disk up into several pieces.
+The BIOS brings in sector 0
+(does it really use the code?)
+and verifies the magic number.
+It then searches the 4 BIOS partitions described by sector 0
+to determine which of them is
+.Em active.
+This boot then brings in the secondary boot block from the
+.Em active
+partition and runs it.
+Under DOS,
+you could have one or more partitions with one
+.Em active.
+The DOS
+.Nm
+program can be used to divide space on the disk into partitions and set one
+.Em active.
+.Sh DESCRIPTION
+The 386bsd program
+.Nm
+serves a similar purpose to the DOS program.
+When called with no arguments, it prints the sector 0 partition table.
+An example follows:
+
+.Bd -literal
+ ******* Working on device /dev/rwd0d *******
+ parameters extracted from in-core disklabel are:
+ cylinders=769 heads=15 sectors/track=33 (495 blks/cyl)
+
+ parameters to be used for BIOS calculations are:
+ cylinders=769 heads=15 sectors/track=33 (495 blks/cyl)
+
+ Warning: BIOS sector numbering starts with sector 1
+ Information from DOS bootblock is:
+ The data for partition 0 is:
+ sysid 165,(386BSD)
+ start 495, size 380160 (185 Meg), flag 0
+ beg: cyl 1/ sector 1/ head 0;
+ end: cyl 768/ sector 33/ head 14
+ The data for partition 1 is:
+ sysid 164,(unknown)
+ start 378180, size 2475 (1 Meg), flag 0
+ beg: cyl 764/ sector 1/ head 0;
+ end: cyl 768/ sector 33/ head 14
+ The data for partition 2 is:
+ <UNUSED>
+ The data for partition 3 is:
+ sysid 99,(ISC UNIX, other System V/386, GNU HURD or Mach)
+ start 380656, size 224234 (109 Meg), flag 80
+ beg: cyl 769/ sector 2/ head 0;
+ end: cyl 197/ sector 33/ head 14
+.Ed
+.Pp
+The disk is divided into three parititions that happen to fill the disk.
+The second partition overlaps the end of the first.
+(Used for debugging purposes)
+.Bl -tag -width "cyl, sector and head"
+.It Em "sysid"
+is used to label the partition. 386bsd reserves the
+magic number 165 decimal (A5 in hex).
+.It Em "start and size"
+fields provide the start address
+and size of a parition in sectors.
+.It Em "flag 80"
+specifies that this is the active partition.
+.It Em "cyl, sector and head"
+fields are used to specify the beginning address
+and end address for the parititon.
+.It Em "Note:"
+these numbers are calculated using BIOS's understanding of the disk geometry
+and saved in the bootblock.
+.El
+.Pp
+The flags
+.Fl i
+or
+.Fl u
+are used to indicate that the paritition data is to be updated.
+The
+.Nm
+program will enter a conversational mode.
+This mode is designed not to change any data unless you explicitly tell it to.
+.Nm
+selects defaults for its questions to guarantee the above behavior.
+.Pp
+It displays each partition
+and ask if you want to edit it.
+If you say yes,
+it will step through each field showing the old value
+and asking for a new one.
+When you are done with a partition,
+.Nm
+will display it and ask if it is correct.
+.Nm
+will then procede to the next entry.
+.Pp
+Getting the
+.Em cyl, sector,
+and
+.Em head
+fields correct is tricky.
+So by default,
+they will be calculated for you;
+you can specify them if you choose.
+.Pp
+After all the partitions are processed,
+you are given the option to change the
+.Em active
+partition.
+Finally,
+when the all the data for the first sector has been accumulated,
+you are asked if you really want to rewrite sector 0.
+Only if you answer yes,
+will the data be written to disk.
+.Pp
+The difference between the
+.Fl u
+flag and
+.Fl i
+flag is that
+the
+.Fl u
+flag just edits the fields as they appear on the disk.
+While the
+.Fl i
+flag is used to "initialize" sector 0;
+it will setup the last BIOS partition to use the whole disk for 386bsd;
+and make it active.
+.Sh NOTES
+.Pp
+The automatic calculation of starting cylinder etc. uses
+a set of figures that represent what the BIOS thinks is the
+geometry of the drive.
+These figures are by default taken from the incore disklabel,
+but the program initially gives you an oportunity to change them.
+This allows the user to create a bootblock that can work with drives
+that use geometry translation under the BIOS.
+.Pp
+If you hand craft your disk layout,
+please make sure that the 386bsd partition starts on a cylinder boundary.
+A number of decisions made later may assume this.
+(This might not be necessary later.)
+.Pp
+Editing an existing partition will most likely cause you to
+lose all the data in that partition.
+.Pp
+You should run this program interactively once or twice to see how it works.
+This is completely safe as long as you answer the last question in the negative.
+There are subtleties
+that the program detects
+that are not fully explained in this manual page.
+.Sh SEE ALSO
+.Xr disklabel 8
+.Sh BUGS
+One less now, but probably more
diff --git a/sbin/i386/fdisk/fdisk.c b/sbin/i386/fdisk/fdisk.c
new file mode 100644
index 0000000..7fb728d
--- /dev/null
+++ b/sbin/i386/fdisk/fdisk.c
@@ -0,0 +1,686 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+#include <sys/types.h>
+#include <sys/disklabel.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+
+int iotest;
+
+#define LBUF 100
+static char lbuf[LBUF];
+
+/*
+ *
+ * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992
+ *
+ * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University
+ * Copyright (c) 1989 Robert. V. Baron
+ * Created.
+ */
+
+#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
+#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp
+#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
+
+#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
+
+#define SECSIZE 512
+
+char *disk = "/dev/rwd0d";
+char *name;
+
+struct disklabel disklabel; /* disk parameters */
+
+int cyls, sectors, heads, cylsecs, disksecs;
+
+struct mboot
+{
+ unsigned char padding[2]; /* force the longs to be long alligned */
+ unsigned char bootinst[DOSPARTOFF];
+ struct dos_partition parts[4];
+ unsigned short int signature;
+};
+struct mboot mboot;
+
+#define ACTIVE 0x80
+#define BOOT_MAGIC 0xAA55
+
+int dos_cyls;
+int dos_heads;
+int dos_sectors;
+int dos_cylsecs;
+
+#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0))
+#define DOSCYL(c) (c & 0xff)
+static int dos();
+char *get_type();
+static int partition = -1;
+
+
+static int a_flag = 0; /* set active partition */
+static int i_flag = 0; /* replace partition data */
+static int u_flag = 0; /* update partition data */
+
+static unsigned char bootcode[] = {
+0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
+0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
+0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
+0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
+0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
+0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
+0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
+0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
+0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
+'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
+ 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
+'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
+ 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
+'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
+ 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
+'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
+ 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+struct part_type
+{
+ unsigned char type;
+ char *name;
+}part_types[] =
+{
+ {0x00, "unused"}
+ ,{0x01, "Primary DOS with 12 bit FAT"}
+ ,{0x02, "XENIX / filesystem"}
+ ,{0x03, "XENIX /usr filesystem"}
+ ,{0x04, "Primary DOS with 16 bit FAT"}
+ ,{0x05, "Extended DOS"}
+ ,{0x06, "Primary 'big' DOS (> 32MB)"}
+ ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}
+ ,{0x08, "AIX filesystem"}
+ ,{0x09, "AIX boot partition or Coherent"}
+ ,{0x0A, "OS/2 Boot Manager or OPUS"}
+ ,{0x10, "OPUS"}
+ ,{0x40, "VENIX 286"}
+ ,{0x50, "DM"}
+ ,{0x51, "DM"}
+ ,{0x52, "CP/M or Microport SysV/AT"}
+ ,{0x56, "GB"}
+ ,{0x61, "Speed"}
+ ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
+ ,{0x64, "Novell Netware 2.xx"}
+ ,{0x65, "Novell Netware 3.xx"}
+ ,{0x75, "PCIX"}
+ ,{0x80, "Minix 1.1 ... 1.4a"}
+ ,{0x81, "Minix 1.4b ... 1.5.10"}
+ ,{0x82, "Linux"}
+ ,{0x93, "Amoeba filesystem"}
+ ,{0x94, "Amoeba bad block table"}
+ ,{0xA5, "386BSD"}
+ ,{0xB7, "BSDI BSD/386 filesystem"}
+ ,{0xB8, "BSDI BSD/386 swap"}
+ ,{0xDB, "Concurrent CPM or C.DOS or CTOS"}
+ ,{0xE1, "Speed"}
+ ,{0xE3, "Speed"}
+ ,{0xE4, "Speed"}
+ ,{0xF1, "Speed"}
+ ,{0xF2, "DOS 3.3+ Secondary"}
+ ,{0xF4, "Speed"}
+ ,{0xFF, "BBT (Bad Blocks Table)"}
+};
+
+
+main(argc, argv)
+char **argv;
+{
+int i;
+
+ name = *argv;
+ {register char *cp = name;
+ while (*cp) if (*cp++ == '/') name = cp;
+ }
+
+ for ( argv++ ; --argc ; argv++ ) { register char *token = *argv;
+ if (*token++ != '-' || !*token)
+ break;
+ else { register int flag;
+ for ( ; flag = *token++ ; ) {
+ switch (flag) {
+ case '0':
+ partition = 0;
+ break;
+ case '1':
+ partition = 1;
+ break;
+ case '2':
+ partition = 2;
+ break;
+ case '3':
+ partition = 3;
+ break;
+ case 'a':
+ a_flag = 1;
+ break;
+ case 'i':
+ i_flag = 1;
+ case 'u':
+ u_flag = 1;
+ break;
+ default:
+ goto usage;
+ }
+ }
+ }
+ }
+
+ if (argc > 0)
+ disk = argv[0];
+
+ if (open_disk(u_flag) < 0)
+ exit(1);
+
+ printf("******* Working on device %s *******\n",disk);
+ if(u_flag)
+ {
+ get_params_to_use();
+ }
+ else
+ {
+ print_params();
+ }
+
+ if (read_s0())
+ init_sector0(1);
+
+ printf("Warning: BIOS sector numbering starts with sector 1\n");
+ printf("Information from DOS bootblock is:\n");
+ if (partition == -1)
+ for (i = 0; i < NDOSPART; i++)
+ change_part(i);
+ else
+ change_part(partition);
+
+ if (u_flag || a_flag)
+ change_active(partition);
+
+ if (u_flag || a_flag) {
+ printf("\nWe haven't changed the partition table yet. ");
+ printf("This is your last chance.\n");
+ print_s0(-1);
+ if (ok("Should we write new partition table?"))
+ write_s0();
+ }
+
+ exit(0);
+
+usage:
+ printf("fdisk {-a|-i|-r} {disk}\n");
+}
+
+print_s0(which)
+{
+int i;
+
+ print_params();
+ printf("Information from DOS bootblock is:\n");
+ if (which == -1)
+ for (i = 0; i < NDOSPART; i++)
+ printf("%d: ", i), print_part(i);
+ else
+ print_part(which);
+}
+
+static struct dos_partition mtpart = { 0 };
+
+print_part(i)
+{
+struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
+
+
+ if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) {
+ printf("<UNUSED>\n");
+ return;
+ }
+ printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ));
+ printf(" start %d, size %d (%d Meg), flag %x\n",
+ partp->dp_start,
+ partp->dp_size, partp->dp_size * 512 / (1024 * 1024),
+ partp->dp_flag);
+ printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n"
+ ,DPCYL(partp->dp_scyl, partp->dp_ssect)
+ ,DPSECT(partp->dp_ssect)
+ ,partp->dp_shd
+ ,DPCYL(partp->dp_ecyl, partp->dp_esect)
+ ,DPSECT(partp->dp_esect)
+ ,partp->dp_ehd);
+}
+
+init_sector0(start)
+{
+struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]);
+int size = disksecs - start;
+int rest;
+
+ memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
+ mboot.signature = BOOT_MAGIC;
+
+ partp->dp_typ = DOSPTYP_386BSD;
+ partp->dp_flag = ACTIVE;
+ partp->dp_start = start;
+ partp->dp_size = size;
+
+ dos(partp->dp_start, &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
+ dos(partp->dp_start+partp->dp_size, &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
+}
+
+change_part(i)
+{
+struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i;
+
+ printf("The data for partition %d is:\n", i);
+ print_part(i);
+
+ if (u_flag && ok("Do you want to change it?")) {
+ int tmp;
+
+ if (i_flag) {
+ bzero((char *)partp, sizeof (struct dos_partition));
+ if (i == 3) {
+ init_sector0(1);
+ printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
+ print_part(i);
+ }
+ }
+
+ do {
+ Decimal("sysid", partp->dp_typ, tmp);
+ Decimal("start", partp->dp_start, tmp);
+ Decimal("size", partp->dp_size, tmp);
+
+ if (ok("Explicitly specifiy beg/end address ?"))
+ {
+ int tsec,tcyl,thd;
+ tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect);
+ thd = partp->dp_shd;
+ tsec = DPSECT(partp->dp_ssect);
+ Decimal("beginning cylinder", tcyl, tmp);
+ Decimal("beginning head", thd, tmp);
+ Decimal("beginning sector", tsec, tmp);
+ partp->dp_scyl = DOSCYL(tcyl);
+ partp->dp_ssect = DOSSECT(tsec,tcyl);
+ partp->dp_shd = thd;
+
+ tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect);
+ thd = partp->dp_ehd;
+ tsec = DPSECT(partp->dp_esect);
+ Decimal("ending cylinder", tcyl, tmp);
+ Decimal("ending head", thd, tmp);
+ Decimal("ending sector", tsec, tmp);
+ partp->dp_ecyl = DOSCYL(tcyl);
+ partp->dp_esect = DOSSECT(tsec,tcyl);
+ partp->dp_ehd = thd;
+ } else {
+ dos(partp->dp_start,
+ &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd);
+ dos(partp->dp_start+partp->dp_size - 1,
+ &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd);
+ }
+
+ print_part(i);
+ } while (!ok("Are we happy with this entry?"));
+ }
+}
+
+print_params()
+{
+ printf("parameters extracted from in-core disklabel are:\n");
+ printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
+ ,cyls,heads,sectors,cylsecs);
+ if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255))
+ printf(" Figures below won't work with BIOS for partitions not in cyl 1\n");
+ printf("parameters to be used for BIOS calculations are:\n");
+ printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
+ ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
+}
+
+change_active(which)
+{
+int i;
+int active = 3, tmp;
+struct dos_partition *partp = ((struct dos_partition *) &mboot.parts);
+
+ if (a_flag && which != -1)
+ active = which;
+ if (ok("Do you want to change the active partition?")) {
+ do
+ Decimal("active partition", active, tmp);
+ while(!ok("Are you happy with this choice"));
+ }
+ for (i = 0; i < NDOSPART; i++)
+ partp[i].dp_flag = 0;
+ partp[active].dp_flag = ACTIVE;
+}
+
+get_params_to_use()
+{
+ int tmp;
+ print_params();
+ if (ok("Do you want to change our idea of what BIOS thinks ?"))
+ {
+ do
+ {
+ Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
+ Decimal("BIOS's idea of #heads", dos_heads, tmp);
+ Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
+ dos_cylsecs = dos_heads * dos_sectors;
+ print_params();
+ }
+ while(!ok("Are you happy with this choice"));
+ }
+}
+
+/***********************************************\
+* Change real numbers into strange dos numbers *
+\***********************************************/
+static
+dos(sec, c, s, h)
+int sec;
+unsigned char *c, *s, *h;
+{
+int cy;
+int hd;
+
+ cy = sec / ( dos_cylsecs );
+ sec = sec - cy * ( dos_cylsecs );
+
+ hd = sec / dos_sectors;
+ sec = (sec - hd * dos_sectors) + 1;
+
+ *h = hd;
+ *c = cy & 0xff;
+ *s = (sec & 0x3f) | ( (cy & 0x300) >> 2);
+}
+
+int fd;
+
+ /* Getting device status */
+
+open_disk(u_flag)
+{
+struct stat st;
+
+ if (stat(disk, &st) == -1) {
+ fprintf(stderr, "%s: Can't get file status of %s\n",
+ name, disk);
+ return -1;
+ } else if ( !(st.st_mode & S_IFCHR) ) {
+ fprintf(stderr,"%s: Device %s is not character special\n",
+ name, disk);
+ return -1;
+ }
+ if ((fd = open(disk, u_flag?O_RDWR:O_RDONLY)) == -1) {
+ fprintf(stderr,"%s: Can't open device %s\n", name, disk);
+ return -1;
+ }
+ if (get_params(0) == -1) {
+ fprintf(stderr, "%s: Can't get disk parameters on %s\n",
+ name, disk);
+ return -1;
+ }
+ return fd;
+}
+
+
+read_disk(sector, buf)
+{
+ lseek(fd,(sector * 512), 0);
+ return read(fd, buf, 512);
+}
+
+write_disk(sector, buf)
+{
+ lseek(fd,(sector * 512), 0);
+ return write(fd, buf, 512);
+}
+
+get_params(verbose)
+{
+
+ if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
+ return -1;
+ }
+
+ dos_cyls = cyls = disklabel.d_ncylinders;
+ dos_heads = heads = disklabel.d_ntracks;
+ dos_sectors = sectors = disklabel.d_nsectors;
+ dos_cylsecs = cylsecs = heads * sectors;
+ disksecs = cyls * heads * sectors;
+
+ return (disksecs);
+}
+
+
+read_s0()
+{
+ if (read_disk(0, (char *) mboot.bootinst) == -1) {
+ fprintf(stderr, "%s: Can't read fdisk partition table\n", name);
+ return -1;
+ }
+ if (mboot.signature != BOOT_MAGIC) {
+ fprintf(stderr, "%s: Invalid fdisk partition table found\n",
+ name);
+ /* So should we initialize things */
+ return -1;
+ }
+ return 0;
+}
+
+write_s0()
+{
+ int flag;
+ if (iotest) {
+ print_s0(-1);
+ return 0;
+ }
+ /*
+ * write enable label sector before write (if necessary),
+ * disable after writing.
+ * needed if the disklabel protected area also protects
+ * sector 0. (e.g. empty disk)
+ */
+ flag = 1;
+ if (ioctl(fd, DIOCWLABEL, &flag) < 0)
+ perror("ioctl DIOCWLABEL");
+ if (write_disk(0, (char *) mboot.bootinst) == -1) {
+ fprintf(stderr, "%s: Can't write fdisk partition table\n",
+ name);
+ return -1;
+ flag = 0;
+ (void) ioctl(fd, DIOCWLABEL, &flag);
+ }
+}
+
+
+
+ok(str)
+char *str;
+{
+ printf("%s [n] ", str);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (*lbuf &&
+ (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
+ !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
+ return 1;
+ else
+ return 0;
+}
+
+decimal(str, num, deflt)
+char *str;
+int *num;
+{
+int acc = 0, c;
+char *cp;
+
+ while (1) {
+ printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (!*lbuf)
+ return 0;
+
+ cp = lbuf;
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c)
+ return 0;
+ while (c = *cp++) {
+ if (c <= '9' && c >= '0')
+ acc = acc * 10 + c - '0';
+ else
+ break;
+ }
+ if (c == ' ' || c == '\t')
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c) {
+ *num = acc;
+ return 1;
+ } else
+ printf("%s is an invalid decimal number. Try again\n",
+ lbuf);
+ }
+
+}
+
+hex(str, num, deflt)
+char *str;
+int *num;
+{
+int acc = 0, c;
+char *cp;
+
+ while (1) {
+ printf("Supply a hex value for \"%s\" [%x] ", str, deflt);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (!*lbuf)
+ return 0;
+
+ cp = lbuf;
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c)
+ return 0;
+ while (c = *cp++) {
+ if (c <= '9' && c >= '0')
+ acc = (acc << 4) + c - '0';
+ else if (c <= 'f' && c >= 'a')
+ acc = (acc << 4) + c - 'a' + 10;
+ else if (c <= 'F' && c >= 'A')
+ acc = (acc << 4) + c - 'A' + 10;
+ else
+ break;
+ }
+ if (c == ' ' || c == '\t')
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (!c) {
+ *num = acc;
+ return 1;
+ } else
+ printf("%s is an invalid hex number. Try again\n",
+ lbuf);
+ }
+
+}
+
+string(str, ans)
+char *str;
+char **ans;
+{
+int c;
+char *cp = lbuf;
+
+ while (1) {
+ printf("Supply a string value for \"%s\" [%s] ", str, *ans);
+ fgets(lbuf, LBUF, stdin);
+ lbuf[strlen(lbuf)-1] = 0;
+
+ if (!*lbuf)
+ return 0;
+
+ while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
+ if (c == '"') {
+ c = *++cp;
+ *ans = cp;
+ while ((c = *cp) && c != '"') cp++;
+ } else {
+ *ans = cp;
+ while ((c = *cp) && c != ' ' && c != '\t') cp++;
+ }
+
+ if (c)
+ *cp = 0;
+ return 1;
+ }
+}
+
+char *get_type(type)
+int type;
+{
+ int numentries = (sizeof(part_types)/sizeof(struct part_type));
+ int counter = 0;
+ struct part_type *ptr = part_types;
+
+
+ while(counter < numentries)
+ {
+ if(ptr->type == type)
+ {
+ return(ptr->name);
+ }
+ ptr++;
+ counter++;
+ }
+ return("unknown");
+}
diff --git a/sbin/i386/ft/Makefile b/sbin/i386/ft/Makefile
new file mode 100644
index 0000000..3fb1b74
--- /dev/null
+++ b/sbin/i386/ft/Makefile
@@ -0,0 +1,7 @@
+# $Id$
+
+PROG= ft
+MAN8= ft.8
+SRCS= ft.c ftecc.c
+
+.include <bsd.prog.mk>
diff --git a/sbin/i386/ft/ft.8 b/sbin/i386/ft/ft.8
new file mode 100644
index 0000000..477f09b
--- /dev/null
+++ b/sbin/i386/ft/ft.8
@@ -0,0 +1,86 @@
+.\" Copyright (c) 1980, 1989, 1991 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.
+.\"
+.\" @(#)ft.8
+.\"
+.Dd February 7, 1994
+.Dt FT 8
+.Os BSD 4
+.Sh NAME
+.Nm ft
+.Nd QIC 40/80 floppy tape drive controller
+.Sh SYNOPSIS
+.Nm ft
+.Op Fl f Ar tape
+.Op Fl description
+.Sh DESCRIPTION
+The
+.Nm ft
+command allows multi-volume dump, extract, and view of tape labels, for
+any pre-formatted QIC-40/80 tapes. It is totally system dependent,
+and has nothing to do with the QIC standards.
+.Pp
+.Nm ft
+is used primarily as a filter for tape i/o.
+For example, to save and compress the /usr directory to tape:
+.Bd -literal -offset indent
+% tar cvzf - /usr | ft "/usr save"
+.Ed
+.Pp
+To extract /usr from tape:
+.Bd -literal -offset indent
+% ft | tar xvzf -
+.Ed
+.Sh SEE ALSO
+.Xr qtar 1
+.Sh BUGS
+Formatting/Verifying is in the works. You will need to use your
+existing backup program to do this for the time being.
+.Sh NOTES
+The floppy tape driver supports tape drives such as the Colorado
+Jumbo, Mountain Summit Express, some Archive/Conner models, and
+probably many others. These tape drives attach between your floppy
+disk controller card and your existing floppy disks' ribbon cable.
+This driver does not currently support attachments via a proprietary
+tape controller card or by the parallel port.
+.Pp
+QIC-40/80 drives are more CPU intensive than a SCSI drive. This is
+really only a factor if your machine is networked or has multiple concurrent
+users. For personal use (i.e. your typical home Unix user), response time
+is perfectly acceptable. The tape drives cannot detect write errors.
+Instead, they make up for it by using CRC's, error correction, and bad
+spot mapping. Formatting time is extremely long because of this. The
+drive makes a first pass over the entire tape writing out sectors. It
+then makes a second pass at a slower rate than usual (for sensitivity)
+to detect bad spots on the tape. Typically it takes an hour to format
+a single QIC-80 (120Mb uncompressed) tape.
+.Sh AUTHOR
+Steve Gerakines <steve2@genesis.nred.ma.us>
diff --git a/sbin/i386/ft/ft.c b/sbin/i386/ft/ft.c
new file mode 100644
index 0000000..4aa92f8
--- /dev/null
+++ b/sbin/i386/ft/ft.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 1993 Steve Gerakines
+ *
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * ft.c - simple floppy tape filter
+ *
+ * 01/28/94 v0.3b (Jim Babb)
+ * Fixed bug when all sectors in a segment are marked bad.
+ *
+ * 10/30/93 v0.3
+ * Minor revisions. Seems pretty stable.
+ *
+ * 09/02/93 v0.2 pl01
+ * Initial revision.
+ *
+ * usage: ftfilt [ -f tape ] [ description ]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/ftape.h>
+
+#define DEFQIC "/dev/rft0"
+
+char buff[QCV_SEGSIZE]; /* scratch buffer */
+char hbuff[QCV_SEGSIZE]; /* header buffer */
+QIC_Header *hptr = (QIC_Header *)hbuff; /* header structure */
+int hsn = -1; /* segment number of header */
+int dhsn = -1; /* segment number of duplicate header */
+int tfd; /* tape file descriptor */
+QIC_Geom geo; /* tape geometry */
+int tvno = 1; /* tape volume number */
+int tvlast; /* TRUE if last volume in set */
+long tvsize = 0; /* tape volume size in bytes */
+long tvtime = NULL; /* tape change time */
+char *tvnote = ""; /* tape note */
+
+/* Lookup the badmap for a given track and segment. */
+#define BADMAP(t,s) hptr->qh_badmap[(t)*geo.g_segtrk+(s)]
+
+/* Retrieve values from a character array. */
+#define UL_VAL(s,p) (*((ULONG *)&(s)[p]))
+#define US_VAL(s,p) (*((USHORT *)&(s)[p]))
+
+#define equal(s1,s2) (strcmp(s1, s2) == 0)
+
+
+
+/* Entry */
+main(int argc, char *argv[])
+{
+ int r, s;
+ char *tape, *getenv();
+
+ if (argc > 2 && (equal(argv[1], "-t") || equal(argv[1], "-f"))) {
+ argc -= 2;
+ tape = argv[2];
+ argv += 2;
+ } else
+ if ((tape = getenv("TAPE")) == NULL)
+ tape = DEFQIC;
+ if (argc > 1) {
+ tvnote = argv[1];
+ if (strlen(tvnote) > 18) argv[1][18] = '\0';
+ }
+
+ /* Open the tape device */
+ if ((tfd = open(tape, 2)) < 0) {
+ perror(tape);
+ exit(1);
+ }
+
+ if (!isatty(0))
+ do_write();
+ else if (!isatty(1))
+ do_read();
+ else
+ do_getname();
+
+ close(tfd);
+ exit(0);
+}
+
+
+/* Check status of tape drive */
+int check_stat(int fd, int wr)
+{
+ int r, s;
+ int sawit = 0;
+
+ /* get tape status */
+ if (ioctl(fd, QIOSTATUS, &s) < 0) {
+ fprintf(stderr, "could not get drive status\n");
+ return(1);
+ }
+
+ /* wait for the tape drive to become ready */
+ while ((s & QS_READY) == 0) {
+ if (!sawit) {
+ fprintf(stderr, "waiting for drive to become ready...\n");
+ sawit = 1;
+ }
+ sleep(2);
+ if (ioctl(fd, QIOSTATUS, &s) < 0) {
+ fprintf(stderr, "could not get drive status\n");
+ return(1);
+ }
+ }
+
+ if ((s & QS_FMTOK) == 0) {
+ fprintf(stderr, "tape is not formatted\n");
+ return(2);
+ }
+
+ if (wr && (s & QS_RDONLY) != 0) {
+ fprintf(stderr, "tape is write protected\n");
+ return(3);
+ }
+
+ return(0);
+}
+
+
+
+ULONG qtimeval(time_t t)
+{
+ struct tm *tp;
+ ULONG r;
+
+ tp = localtime(&t);
+ r = 2678400 * tp->tm_mon +
+ 86400 *(tp->tm_mday-1) +
+ 3600 * tp->tm_hour +
+ 60 * tp->tm_min +
+ tp->tm_sec;
+ r |= (tp->tm_year - 70) << 25;
+ return(r);
+}
+
+/* Return tm struct from QIC date format. */
+struct tm *qtime(UCHAR *qt)
+{
+ ULONG *vp = (ULONG *)qt;
+ struct tm t;
+ ULONG v;
+ time_t tv;
+
+ v = *vp;
+ t.tm_year = ((v >> 25) & 0x7f)+70; v &= 0x1ffffff;
+ t.tm_mon = v / 2678400; v %= 2678400;
+ t.tm_mday = v / 86400 + 1; v %= 86400;
+ t.tm_hour = v / 3600; v %= 3600;
+ t.tm_min = v / 60; v %= 60;
+ t.tm_sec = v;
+ t.tm_wday = 0; /* XXX - let mktime do the real work */
+ t.tm_yday = 0;
+ t.tm_isdst = 0;
+ t.tm_gmtoff = 0;
+ t.tm_zone = NULL;
+ tv = mktime(&t);
+ return(localtime(&tv));
+}
+
+/* Return a string, zero terminated */
+char *qstr(char *str, int nchar)
+{
+ static char tstr[256];
+ strncpy(tstr, str, nchar);
+ tstr[nchar] = '\0';
+ return(tstr);
+}
+
+/* Read header from tape */
+get_header(int fd)
+{
+ int r, sn, bytes;
+ QIC_Segment s;
+ int gothdr = 0;
+
+ if (ioctl(fd, QIOGEOM, &geo) < 0) {
+ fprintf(stderr, "couldn't determine tape geometry\n");
+ return(1);
+ }
+
+ /* Get the header and duplicate */
+ for (sn = 0; sn < 16; sn++) {
+ s.sg_trk = 0;
+ s.sg_seg = sn;
+ s.sg_badmap = 0;
+ s.sg_data = (UCHAR *)&buff[0];
+ ioctl(fd, QIOREAD, &s);
+ r = check_parity(s.sg_data, 0, s.sg_crcmap);
+ if (s.sg_data[0] == 0x55 && s.sg_data[1] == 0xaa &&
+ s.sg_data[2] == 0x55 && s.sg_data[3] == 0xaa) {
+ if (hsn >= 0) {
+ dhsn = sn;
+ if (!r && !gothdr) {
+ fprintf(stderr, "using secondary header\n");
+ bcopy(s.sg_data, hbuff, QCV_SEGSIZE);
+ gothdr = 1;
+ }
+ break;
+ }
+ hsn = sn;
+ if (!r) {
+ bcopy(s.sg_data, hbuff, QCV_SEGSIZE);
+ gothdr = 1;
+ } else {
+ fprintf(stderr, "too many errors in primary header\n");
+ }
+ }
+ }
+
+ if (!gothdr) {
+ fprintf(stderr, "couldn't read header segment\n");
+ ioctl(fd, QIOREWIND);
+ return(1);
+ }
+
+ return(0);
+}
+
+
+ask_vol(int vn)
+{
+ FILE *inp;
+ int fd;
+ char c;
+
+ if ((fd = open("/dev/tty", 2)) < 0) {
+ fprintf(stderr, "argh!! can't open /dev/tty\n");
+ exit(1);
+ }
+
+ fprintf(stderr, "Insert ftfilt volume %02d and press enter:", vn);
+ read(fd, &c, 1);
+ close(fd);
+}
+
+
+/* Return the name of the tape only. */
+do_getname()
+{
+ if (check_stat(tfd, 0)) exit(1);
+ if (get_header(tfd)) exit(1);
+ fprintf(stderr, "\"%s\" - %s",
+ qstr(hptr->qh_tname,44), asctime(qtime(hptr->qh_chgdate)));
+ ioctl(tfd, QIOREWIND);
+}
+
+
+/* Extract data from tape to stdout */
+do_read()
+{
+ int sno, vno, sbytes, r;
+ long curpos;
+ char *hname;
+ QIC_Segment s;
+
+ /* Process multiple volumes if necessary */
+ vno = 1;
+ for (;;) {
+ if (check_stat(tfd, 0)) {
+ ask_vol(vno);
+ continue;
+ }
+ if (get_header(tfd)) {
+ ask_vol(vno);
+ continue;
+ }
+
+ /* extract volume and header info from label */
+ hname = hptr->qh_tname;
+ hname[43] = '\0';
+ tvno = atoi(&hname[11]);
+ tvlast = (hname[10] == '*') ? 1 : 0;
+ tvsize = atoi(&hname[14]);
+ tvnote = &hname[25];
+ if (vno != tvno || strncmp(hname, "ftfilt", 6) != 0) {
+ fprintf(stderr, "Incorrect volume inserted. This tape is:\n");
+ fprintf(stderr,"\"%s\" - %s\n", hname,
+ asctime(qtime(hptr->qh_chgdate)));
+ ask_vol(vno);
+ continue;
+ }
+
+ /* Process this volume */
+ curpos = 0;
+ for (sno = hptr->qh_first; tvsize > 0; sno++) {
+ s.sg_trk = sno / geo.g_segtrk;
+ s.sg_seg = sno % geo.g_segtrk;
+ s.sg_badmap = BADMAP(s.sg_trk,s.sg_seg);
+ sbytes = sect_bytes(s.sg_badmap) - QCV_ECCSIZE;
+ s.sg_data = (UCHAR *)&buff[0];
+
+ /* skip segments with *all* sectors flagged as bad */
+ if (sbytes > 0) {
+ if (ioctl(tfd, QIOREAD, &s) < 0) perror("QIOREAD");
+ r = check_parity(s.sg_data, s.sg_badmap, s.sg_crcmap);
+ if (r) fprintf(stderr, "** warning: ecc failed at byte %ld\n",
+ curpos);
+ if (tvsize < sbytes) sbytes = tvsize;
+ write(1, s.sg_data, sbytes);
+ tvsize -= sbytes;
+ curpos += sbytes;
+ }
+ }
+ if (tvlast) break;
+ ioctl(tfd, QIOREWIND);
+ ask_vol(++vno);
+ }
+ ioctl(tfd, QIOREWIND);
+ return(0);
+}
+
+
+/* Dump data from stdin to tape */
+do_write()
+{
+ int sno, vno, amt, sbytes;
+ int c, maxseg, r;
+ ULONG qnow;
+ QIC_Segment s;
+ char tmpstr[80];
+
+ qnow = qtimeval(time(NULL));
+ vno = 1;
+
+ for (;;) {
+ if (check_stat(tfd, 1)) {
+ ask_vol(vno);
+ continue;
+ }
+ if (get_header(tfd)) {
+ ask_vol(vno);
+ continue;
+ }
+
+ maxseg = geo.g_segtrk * geo.g_trktape - 1;
+ sno = hptr->qh_first;
+ tvno = vno;
+ tvsize = 0;
+ tvlast = 0;
+
+ /* Process until end of volume or end of data */
+ for (sno = hptr->qh_first; sno < maxseg && tvlast == 0; ++sno) {
+ /* Prepare to load the next segment */
+ s.sg_trk = sno / geo.g_segtrk;
+ s.sg_seg = sno % geo.g_segtrk;
+ s.sg_badmap = BADMAP(s.sg_trk,s.sg_seg);
+ sbytes = sect_bytes(s.sg_badmap) - QCV_ECCSIZE;
+ s.sg_data = (UCHAR *)&buff[0];
+
+ /* Ugh. Loop to get the full amt. */
+ for (amt = 0; amt < sbytes; amt += r) {
+ r = read(0, &s.sg_data[amt], sbytes - amt);
+ if (r <= 0) {
+ tvlast = 1;
+ break;
+ }
+ }
+ /* skip the segment if *all* sectors are flagged as bad */
+ if (amt) {
+ if (amt < sbytes)
+ bzero(&s.sg_data[amt], sbytes - amt);
+ r = set_parity(s.sg_data, s.sg_badmap);
+ if (r) fprintf(stderr, "** warning: ecc problem !!\n");
+ if (ioctl(tfd, QIOWRITE, &s) < 0) {
+ perror("QIOWRITE");
+ exit(1);
+ }
+ tvsize += amt;
+ }
+ }
+
+ /* Build new header info */
+ /* ftfilt vol*xx yyyyyyyyyy note56789012345678 */
+ /* 01234567890123456789012345678901234567890123 */
+
+ sprintf(tmpstr, "ftfilt vol%s%02d %010d %s",
+ (tvlast) ? "*" : " ", tvno, tvsize, tvnote);
+ strncpy(hptr->qh_tname, tmpstr, 44);
+ UL_VAL(hptr->qh_chgdate,0) = qnow;
+
+ /* Update the header for this volume */
+ if (hsn >= 0) {
+ s.sg_trk = hsn / geo.g_segtrk;
+ s.sg_seg = hsn % geo.g_segtrk;
+ s.sg_badmap = 0;
+ s.sg_data = (UCHAR *)hbuff;
+ r = set_parity(s.sg_data, s.sg_badmap);
+ if (r) fprintf(stderr, "** warning: header ecc problem !!\n");
+ if (ioctl(tfd, QIOWRITE, &s) < 0) {
+ perror("QIOWRITE");
+ exit(1);
+ }
+ }
+ if (dhsn >= 0) {
+ s.sg_trk = dhsn / geo.g_segtrk;
+ s.sg_seg = dhsn % geo.g_segtrk;
+ s.sg_badmap = 0;
+ s.sg_data = (UCHAR *)hbuff;
+ r = set_parity(s.sg_data, s.sg_badmap);
+ if (r) fprintf(stderr, "** warning: duphdr ecc problem !!\n");
+ if (ioctl(tfd, QIOWRITE, &s) < 0) {
+ perror("QIOWRITE");
+ exit(1);
+ }
+ }
+ ioctl(tfd, QIOREWIND);
+ if (tvlast) break;
+ ask_vol(++vno);
+ }
+ return(0);
+}
diff --git a/sbin/i386/ft/ftecc.c b/sbin/i386/ft/ftecc.c
new file mode 100644
index 0000000..e499644
--- /dev/null
+++ b/sbin/i386/ft/ftecc.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 1994 Steve Gerakines
+ *
+ * This is freely redistributable software. You may do anything you
+ * wish with it, so long as the above notice stays intact.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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.
+ *
+ * ftecc.c - QIC-40/80 Reed-Solomon error correction
+ * 03/22/94 v0.4
+ * Major re-write. It can handle everything required by QIC now.
+ *
+ * 09/14/93 v0.2 pl01
+ * Modified slightly to fit with my driver. Based entirely upon David
+ * L. Brown's package.
+ */
+#include <sys/ftape.h>
+
+/* Inverse matrix */
+struct inv_mat {
+ UCHAR log_denom; /* Log of the denominator */
+ UCHAR zs[3][3]; /* The matrix */
+};
+
+
+/*
+ * Powers of x, modulo 255.
+ */
+static UCHAR alpha_power[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+ 0x87, 0x89, 0x95, 0xad, 0xdd, 0x3d, 0x7a, 0xf4,
+ 0x6f, 0xde, 0x3b, 0x76, 0xec, 0x5f, 0xbe, 0xfb,
+ 0x71, 0xe2, 0x43, 0x86, 0x8b, 0x91, 0xa5, 0xcd,
+ 0x1d, 0x3a, 0x74, 0xe8, 0x57, 0xae, 0xdb, 0x31,
+ 0x62, 0xc4, 0x0f, 0x1e, 0x3c, 0x78, 0xf0, 0x67,
+ 0xce, 0x1b, 0x36, 0x6c, 0xd8, 0x37, 0x6e, 0xdc,
+ 0x3f, 0x7e, 0xfc, 0x7f, 0xfe, 0x7b, 0xf6, 0x6b,
+ 0xd6, 0x2b, 0x56, 0xac, 0xdf, 0x39, 0x72, 0xe4,
+ 0x4f, 0x9e, 0xbb, 0xf1, 0x65, 0xca, 0x13, 0x26,
+ 0x4c, 0x98, 0xb7, 0xe9, 0x55, 0xaa, 0xd3, 0x21,
+ 0x42, 0x84, 0x8f, 0x99, 0xb5, 0xed, 0x5d, 0xba,
+ 0xf3, 0x61, 0xc2, 0x03, 0x06, 0x0c, 0x18, 0x30,
+ 0x60, 0xc0, 0x07, 0x0e, 0x1c, 0x38, 0x70, 0xe0,
+ 0x47, 0x8e, 0x9b, 0xb1, 0xe5, 0x4d, 0x9a, 0xb3,
+ 0xe1, 0x45, 0x8a, 0x93, 0xa1, 0xc5, 0x0d, 0x1a,
+ 0x34, 0x68, 0xd0, 0x27, 0x4e, 0x9c, 0xbf, 0xf9,
+ 0x75, 0xea, 0x53, 0xa6, 0xcb, 0x11, 0x22, 0x44,
+ 0x88, 0x97, 0xa9, 0xd5, 0x2d, 0x5a, 0xb4, 0xef,
+ 0x59, 0xb2, 0xe3, 0x41, 0x82, 0x83, 0x81, 0x85,
+ 0x8d, 0x9d, 0xbd, 0xfd, 0x7d, 0xfa, 0x73, 0xe6,
+ 0x4b, 0x96, 0xab, 0xd1, 0x25, 0x4a, 0x94, 0xaf,
+ 0xd9, 0x35, 0x6a, 0xd4, 0x2f, 0x5e, 0xbc, 0xff,
+ 0x79, 0xf2, 0x63, 0xc6, 0x0b, 0x16, 0x2c, 0x58,
+ 0xb0, 0xe7, 0x49, 0x92, 0xa3, 0xc1, 0x05, 0x0a,
+ 0x14, 0x28, 0x50, 0xa0, 0xc7, 0x09, 0x12, 0x24,
+ 0x48, 0x90, 0xa7, 0xc9, 0x15, 0x2a, 0x54, 0xa8,
+ 0xd7, 0x29, 0x52, 0xa4, 0xcf, 0x19, 0x32, 0x64,
+ 0xc8, 0x17, 0x2e, 0x5c, 0xb8, 0xf7, 0x69, 0xd2,
+ 0x23, 0x46, 0x8c, 0x9f, 0xb9, 0xf5, 0x6d, 0xda,
+ 0x33, 0x66, 0xcc, 0x1f, 0x3e, 0x7c, 0xf8, 0x77,
+ 0xee, 0x5b, 0xb6, 0xeb, 0x51, 0xa2, 0xc3, 0x01
+};
+
+
+/*
+ * Log table, modulo 255 + 1.
+ */
+static UCHAR alpha_log[] = {
+ 0xff, 0x00, 0x01, 0x63, 0x02, 0xc6, 0x64, 0x6a,
+ 0x03, 0xcd, 0xc7, 0xbc, 0x65, 0x7e, 0x6b, 0x2a,
+ 0x04, 0x8d, 0xce, 0x4e, 0xc8, 0xd4, 0xbd, 0xe1,
+ 0x66, 0xdd, 0x7f, 0x31, 0x6c, 0x20, 0x2b, 0xf3,
+ 0x05, 0x57, 0x8e, 0xe8, 0xcf, 0xac, 0x4f, 0x83,
+ 0xc9, 0xd9, 0xd5, 0x41, 0xbe, 0x94, 0xe2, 0xb4,
+ 0x67, 0x27, 0xde, 0xf0, 0x80, 0xb1, 0x32, 0x35,
+ 0x6d, 0x45, 0x21, 0x12, 0x2c, 0x0d, 0xf4, 0x38,
+ 0x06, 0x9b, 0x58, 0x1a, 0x8f, 0x79, 0xe9, 0x70,
+ 0xd0, 0xc2, 0xad, 0xa8, 0x50, 0x75, 0x84, 0x48,
+ 0xca, 0xfc, 0xda, 0x8a, 0xd6, 0x54, 0x42, 0x24,
+ 0xbf, 0x98, 0x95, 0xf9, 0xe3, 0x5e, 0xb5, 0x15,
+ 0x68, 0x61, 0x28, 0xba, 0xdf, 0x4c, 0xf1, 0x2f,
+ 0x81, 0xe6, 0xb2, 0x3f, 0x33, 0xee, 0x36, 0x10,
+ 0x6e, 0x18, 0x46, 0xa6, 0x22, 0x88, 0x13, 0xf7,
+ 0x2d, 0xb8, 0x0e, 0x3d, 0xf5, 0xa4, 0x39, 0x3b,
+ 0x07, 0x9e, 0x9c, 0x9d, 0x59, 0x9f, 0x1b, 0x08,
+ 0x90, 0x09, 0x7a, 0x1c, 0xea, 0xa0, 0x71, 0x5a,
+ 0xd1, 0x1d, 0xc3, 0x7b, 0xae, 0x0a, 0xa9, 0x91,
+ 0x51, 0x5b, 0x76, 0x72, 0x85, 0xa1, 0x49, 0xeb,
+ 0xcb, 0x7c, 0xfd, 0xc4, 0xdb, 0x1e, 0x8b, 0xd2,
+ 0xd7, 0x92, 0x55, 0xaa, 0x43, 0x0b, 0x25, 0xaf,
+ 0xc0, 0x73, 0x99, 0x77, 0x96, 0x5c, 0xfa, 0x52,
+ 0xe4, 0xec, 0x5f, 0x4a, 0xb6, 0xa2, 0x16, 0x86,
+ 0x69, 0xc5, 0x62, 0xfe, 0x29, 0x7d, 0xbb, 0xcc,
+ 0xe0, 0xd3, 0x4d, 0x8c, 0xf2, 0x1f, 0x30, 0xdc,
+ 0x82, 0xab, 0xe7, 0x56, 0xb3, 0x93, 0x40, 0xd8,
+ 0x34, 0xb0, 0xef, 0x26, 0x37, 0x0c, 0x11, 0x44,
+ 0x6f, 0x78, 0x19, 0x9a, 0x47, 0x74, 0xa7, 0xc1,
+ 0x23, 0x53, 0x89, 0xfb, 0x14, 0x5d, 0xf8, 0x97,
+ 0x2e, 0x4b, 0xb9, 0x60, 0x0f, 0xed, 0x3e, 0xe5,
+ 0xf6, 0x87, 0xa5, 0x17, 0x3a, 0xa3, 0x3c, 0xb7
+};
+
+
+/*
+ * Return number of sectors available in a segment.
+ */
+int
+sect_count(ULONG badmap)
+{
+ int i, amt;
+
+ for (amt = QCV_BLKSEG, i = 0; i < QCV_BLKSEG; i++)
+ if (badmap & (1 << i)) amt--;
+ return(amt);
+}
+
+
+/*
+ * Return number of bytes available in a segment.
+ */
+int
+sect_bytes(ULONG badmap)
+{
+ int i, amt;
+
+ for (amt = QCV_SEGSIZE, i = 0; i < QCV_BLKSEG; i++)
+ if (badmap & (1 << i)) amt -= QCV_BLKSIZE;
+ return(amt);
+}
+
+
+/*
+ * Multiply two numbers in the field.
+ */
+static UCHAR
+multiply(UCHAR a, UCHAR b)
+{
+ if (!a || !b) return(0);
+ return(alpha_power[(alpha_log[a] + alpha_log[b]) % 255]);
+}
+
+
+/*
+ * Multiply by an exponent.
+ */
+static UCHAR
+multiply_out(UCHAR a, int b)
+{
+ if (!a) return(0);
+ return(alpha_power[(alpha_log[a] + b) % 255]);
+}
+
+
+/*
+ * Divide two numbers.
+ */
+static UCHAR
+divide(UCHAR a, UCHAR b)
+{
+ int tmp;
+
+ if (!a || !b) return(0);
+ tmp = alpha_log[a] - alpha_log[b];
+ if (tmp < 0) tmp += 255;
+ return (alpha_power[tmp]);
+}
+
+
+/*
+ * Divide using exponent.
+ */
+static UCHAR
+divide_out(UCHAR a, UCHAR b)
+{
+ int tmp;
+
+ if (!a) return 0;
+ tmp = alpha_log[a] - b;
+ if (tmp < 0) tmp += 255;
+ return (alpha_power[tmp]);
+}
+
+
+/*
+ * This returns the value z^{a-b}.
+ */
+static UCHAR
+z_of_ab(UCHAR a, UCHAR b)
+{
+ int tmp = a - b;
+
+ if (tmp < 0) tmp += 255;
+ return(alpha_power[tmp % 255]);
+}
+
+
+/*
+ * Calculate the inverse matrix for two or three errors. Returns 0
+ * if there is no inverse or 1 if successful.
+ */
+static int
+calculate_inverse(int nerrs, int *pblk, struct inv_mat *inv)
+{
+ /* First some variables to remember some of the results. */
+ UCHAR z20, z10, z21, z12, z01, z02;
+ UCHAR i0, i1, i2;
+
+ if (nerrs < 2) return(1);
+ if (nerrs > 3) return(0);
+
+ i0 = pblk[0]; i1 = pblk[1]; i2 = pblk[2];
+ if (nerrs == 2) {
+ /* 2 errs */
+ z01 = alpha_power[255 - i0];
+ z02 = alpha_power[255 - i1];
+ inv->log_denom = (z01 ^ z02);
+ if (!inv->log_denom) return(0);
+ inv->log_denom = 255 - alpha_log[inv->log_denom];
+
+ inv->zs[0][0] = multiply_out( 1, inv->log_denom);
+ inv->zs[0][1] = multiply_out(z02, inv->log_denom);
+ inv->zs[1][0] = multiply_out( 1, inv->log_denom);
+ inv->zs[1][1] = multiply_out(z01, inv->log_denom);
+ } else {
+ /* 3 errs */
+ z20 = z_of_ab (i2, i0);
+ z10 = z_of_ab (i1, i0);
+ z21 = z_of_ab (i2, i1);
+ z12 = z_of_ab (i1, i2);
+ z01 = z_of_ab (i0, i1);
+ z02 = z_of_ab (i0, i2);
+ inv->log_denom = (z20 ^ z10 ^ z21 ^ z12 ^ z01 ^ z02);
+ if (!inv->log_denom) return(0);
+ inv->log_denom = 255 - alpha_log[inv->log_denom];
+
+ inv->zs[0][0] = multiply_out(alpha_power[i1] ^ alpha_power[i2],
+ inv->log_denom);
+ inv->zs[0][1] = multiply_out(z21 ^ z12, inv->log_denom);
+ inv->zs[0][2] = multiply_out(alpha_power[255-i1] ^ alpha_power[255-i2],
+ inv->log_denom);
+ inv->zs[1][0] = multiply_out(alpha_power[i0] ^ alpha_power[i2],
+ inv->log_denom);
+ inv->zs[1][1] = multiply_out(z20 ^ z02, inv->log_denom);
+ inv->zs[1][2] = multiply_out(alpha_power[255-i0] ^ alpha_power[255-i2],
+ inv->log_denom);
+ inv->zs[2][0] = multiply_out(alpha_power[i0] ^ alpha_power[i1],
+ inv->log_denom);
+ inv->zs[2][1] = multiply_out(z10 ^ z01, inv->log_denom);
+ inv->zs[2][2] = multiply_out(alpha_power[255-i0] ^ alpha_power[255-i1],
+ inv->log_denom);
+ }
+ return(1);
+}
+
+
+/*
+ * Determine the error magnitudes for a given matrix and syndromes.
+ */
+static void
+determine(int nerrs, struct inv_mat *inv, UCHAR *ss, UCHAR *es)
+{
+ UCHAR tmp;
+ int i, j;
+
+ for (i = 0; i < nerrs; i++) {
+ es[i] = 0;
+ for (j = 0; j < nerrs; j++)
+ es[i] ^= multiply(ss[j], inv->zs[i][j]);
+ }
+}
+
+
+/*
+ * Compute the 3 syndrome values.
+ */
+static int
+compute_syndromes(UCHAR *data, int nblks, int col, UCHAR *ss)
+{
+ UCHAR r0, r1, r2, t1, t2;
+ UCHAR *rptr;
+ int row;
+
+ rptr = &data[col];
+ r0 = r1 = r2 = 0;
+ for (row = 0; row < nblks; row++, rptr += QCV_BLKSIZE) {
+ t1 = *rptr ^ r0;
+ t2 = multiply(0xc0, t1);
+ r0 = t2 ^ r1;
+ r1 = t2 ^ r2;
+ r2 = t1;
+ }
+ if (r0 || r1 || r2) {
+ ss[0] = divide_out(r0 ^ divide_out(r1 ^ divide_out(r2, 1), 1), nblks);
+ ss[1] = r0 ^ r1 ^ r2;
+ ss[2] = multiply_out(r0 ^ multiply_out(r1 ^ multiply_out(r2, 1), 1), nblks);
+ return(0);
+ }
+ return(1);
+}
+
+
+/*
+ * Calculate the parity bytes for a segment, returns 0 on success (always).
+ */
+int
+set_parity (UCHAR *data, ULONG badmap)
+{
+ int col, row, max;
+ UCHAR r0, r1, r2, t1, t2;
+ UCHAR *rptr;
+
+ max = sect_count(badmap) - 3;
+ for (col = 0; col < QCV_BLKSIZE; col++, data++) {
+ rptr = data;
+ r0 = r1 = r2 = 0;
+ for (row = 0; row < max; row++, rptr += QCV_BLKSIZE) {
+ t1 = *rptr ^ r0;
+ t2 = multiply(0xc0, t1);
+ r0 = t2 ^ r1;
+ r1 = t2 ^ r2;
+ r2 = t1;
+ }
+ *rptr = r0; rptr += QCV_BLKSIZE;
+ *rptr = r1; rptr += QCV_BLKSIZE;
+ *rptr = r2;
+ }
+ return(0);
+}
+
+
+/*
+ * Check and correct errors in a block. Returns 0 on success,
+ * 1 if failed.
+ */
+int
+check_parity(UCHAR *data, ULONG badmap, ULONG crcmap)
+{
+ int crcerrs, eblk[3];
+ int col, row;
+ int i, j, nblks;
+ UCHAR ss[3], es[3];
+ int i1, i2, saverrs;
+ struct inv_mat inv;
+
+ nblks = sect_count(badmap);
+
+ /* Count the number of CRC errors and note their locations. */
+ crcerrs = 0;
+ if (crcmap) {
+ for (i = 0; i < nblks; i++) {
+ if (crcmap & (1 << i)) {
+ eblk[crcerrs++] = i;
+ if (crcerrs >= 3) break;
+ }
+ }
+ }
+
+ /* Calculate the inverse matrix */
+ if (!calculate_inverse(crcerrs, eblk, &inv)) return(1);
+
+ /* Scan each column for problems and attempt to correct. */
+ for (col = 0; col < QCV_BLKSIZE; col++) {
+ if (compute_syndromes(data, nblks, col, ss)) continue;
+ es[0] = es[1] = es[2] = 0;
+
+ /* Analyze the error situation. */
+ switch (crcerrs) {
+ case 0: /* 0 errors >0 failures */
+ if (!ss[0]) return(1);
+ eblk[crcerrs] = alpha_log[divide(ss[1], ss[0])];
+ if (eblk[crcerrs] >= nblks) return(1);
+ es[0] = ss[1];
+ crcerrs++;
+ break;
+
+ case 1: /* 1 error (+ possible failures) */
+ i1 = ss[2] ^ multiply_out(ss[1], eblk[0]);
+ i2 = ss[1] ^ multiply_out(ss[0], eblk[0]);
+ if (!i1 && !i2) { /* only 1 error */
+ inv.zs[0][0] = alpha_power[eblk[0]];
+ inv.log_denom = 0;
+ } else if (!i1 || !i2) { /* too many errors */
+ return(1);
+ } else { /* add failure */
+ eblk[crcerrs] = alpha_log[divide(i1, i2)];
+ if (eblk[crcerrs] >= nblks) return(1);
+ crcerrs++;
+ if (!calculate_inverse(crcerrs, eblk, &inv)) return(1);
+ }
+ determine(crcerrs, &inv, ss, es);
+ break;
+
+ case 2: /* 2 errors */
+ case 3: /* 3 errors */
+ determine(crcerrs, &inv, ss, es);
+ break;
+
+ default:
+ return(1);
+ }
+
+ /* Make corrections. */
+ for (i = 0; i < crcerrs; i++) {
+ data[eblk[i] * QCV_BLKSIZE+col] ^= es[i];
+ ss[0] ^= divide_out(es[i], eblk[i]);
+ ss[1] ^= es[i];
+ ss[2] ^= multiply_out(es[i], eblk[i]);
+ }
+ if (ss[0] || ss[1] || ss[2]) return(1);
+ }
+ return(0);
+}
diff --git a/sbin/ldconfig/Makefile b/sbin/ldconfig/Makefile
new file mode 100644
index 0000000..28cbe51
--- /dev/null
+++ b/sbin/ldconfig/Makefile
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.6 1994/02/13 20:42:18 jkh Exp $
+
+PROG= ldconfig
+SRCS= ldconfig.c shlib.c etc.c
+LDDIR?= $(.CURDIR)/..
+CFLAGS+=-I$(LDDIR) -I$(.CURDIR) -I$(LDDIR)/$(MACHINE)
+LDFLAGS+=-static
+BINDIR= /sbin
+MAN8= ldconfig.8
+
+.PATH: $(LDDIR) $(LDDIR)/$(MACHINE)
+
+.include <bsd.prog.mk>
diff --git a/sbin/ldconfig/ldconfig.8 b/sbin/ldconfig/ldconfig.8
new file mode 100644
index 0000000..32c35af
--- /dev/null
+++ b/sbin/ldconfig/ldconfig.8
@@ -0,0 +1,100 @@
+.Dd October 3, 1993
+.Dt LDCONFIG 8
+.Os FreeBSD 1.1
+.Sh NAME
+.Nm ldconfig
+.Nd configure the shared library cache
+.Sh SYNOPSIS
+.Nm ldconfig
+.Op Fl rsv
+.Op Ar directory Ar ...
+.Sh DESCRIPTION
+.Nm
+is used to prepare a set of
+.Dq hints
+for use by the run-time linker
+.Xr ld.so
+to facilitate quick lookup of shared libraries available in multiple
+directories. It scans a set of built-in system directories and any
+.Ar directories
+specified on the command line (in the given order) looking for shared
+libraries and stores the results in the file
+.Xr /var/run/ld.so.hints
+to forstall the overhead that would otherwise result from the
+directory search operations
+.Xr ld.so
+would have to perform to load the required shared libraries.
+.Pp
+The shared libraries so found will be automatically available for loading
+if needed by the program being prepared for execution. This obviates the need
+for storing search paths within the executable.
+.Pp
+The
+.Ev LD_LIBRARY_PATH
+environment variable can be used to override the use of
+directories (or the order thereof) from the cache or to specify additional
+directories where shared libraries might be found.
+.Ev LD_LIBRARY_PATH
+is a
+.Sq \:
+separated list of directory paths which are searched by
+.Xr ld.so
+when it needs to load a shared library. It can be viewed as the run-time
+equivalent of the
+.Fl L
+switch of
+.Xr ld.
+.Pp
+.Nm Ldconfig
+is typically run as part of the boot sequence.
+.Pp
+The following options recognized by
+.Nm ldconfig:
+.Bl -tag -width indent
+.It Fl r
+Lists the current contents of
+.Xr ld.so.hints
+on the standard output. The hints file will not be modified.
+.It Fl s
+Do not scan
+.Nm ldconfig
+\'s builtin system directories
+.Sq /usr/lib
+,
+.Sq /usr/X386/lib
+and
+.Sq /usr/local/lib
+for shared libraries.
+.It Fl v
+Switch on verbose mode.
+.Sh Security
+Special care must be taken when loading shared libraries into the address
+space of
+.Ev set-user-Id
+programs. Whenever such a program is run,
+.Xr ld.so
+will only load shared libraries from the
+.Ev ld.so.hints
+file. In particular, the
+.Ev LD_LIBRARY_PATH
+is not used to search for libraries. Thus, the role of ldconfig is dual. In
+addition to building a set of hints for quick lookup, it also serves to
+specify the trusted collection of directories from which shared objects can
+be safely loaded. It is presumed that the set of directories specified to
+.Nm ldconfig
+are under control of the system's administrator.
+.Xr ld.so
+further assists set-user-Id programs by erasing the
+.Ev LD_LIBRARY_PATH
+from the environment.
+
+.Sh FILES
+.Xr /var/run/ld.so.hints
+.Sh SEE ALSO
+.Xr ld 1 ,
+.Xr link 5
+.Sh HISTORY
+A
+.Nm
+utility first appeared in SunOS 4.0, it appeared in its current form
+in FreeBSD 1.1.
diff --git a/sbin/ldconfig/ldconfig.c b/sbin/ldconfig/ldconfig.c
new file mode 100644
index 0000000..fafe176
--- /dev/null
+++ b/sbin/ldconfig/ldconfig.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 1993 Paul Kranenburg
+ * 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 Paul Kranenburg.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ * $Id: ldconfig.c,v 1.4 1993/12/02 01:03:16 jkh Exp $
+ */
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ar.h>
+#include <ranlib.h>
+#include <a.out.h>
+#include <stab.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "ld.h"
+
+#undef major
+#undef minor
+
+char *progname;
+static int verbose;
+static int nostd;
+static int justread;
+
+struct shlib_list {
+ /* Internal list of shared libraries found */
+ char *name;
+ char *path;
+ int dewey[MAXDEWEY];
+ int ndewey;
+#define major dewey[0]
+#define minor dewey[1]
+ struct shlib_list *next;
+};
+
+static struct shlib_list *shlib_head = NULL, **shlib_tail = &shlib_head;
+
+static void enter __P((char *, char *, char *, int *, int));
+static int dodir __P((char *, int));
+static int build_hints __P((void));
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ int i, c;
+ int rval = 0;
+ extern int optind;
+
+ if ((progname = strrchr(argv[0], '/')) == NULL)
+ progname = argv[0];
+ else
+ progname++;
+
+ while ((c = getopt(argc, argv, "rsv")) != EOF) {
+ switch (c) {
+ case 'v':
+ verbose = 1;
+ break;
+ case 's':
+ nostd = 1;
+ break;
+ case 'r':
+ justread = 1;
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [-v] [dir ...]\n", progname);
+ exit(1);
+ break;
+ }
+ }
+
+ if (justread)
+ return listhints();
+
+ if (!nostd)
+ std_search_dirs(NULL);
+
+ for (i = 0; i < n_search_dirs; i++)
+ rval |= dodir(search_dirs[i], 1);
+
+ for (i = optind; i < argc; i++)
+ rval |= dodir(argv[i], 0);
+
+ rval |= build_hints();
+
+ return rval;
+}
+
+int
+dodir(dir, silent)
+char *dir;
+int silent;
+{
+ DIR *dd;
+ struct dirent *dp;
+ char name[MAXPATHLEN], rest[MAXPATHLEN];
+ int dewey[MAXDEWEY], ndewey;
+
+ if ((dd = opendir(dir)) == NULL) {
+ if (!silent || errno != ENOENT)
+ perror(dir);
+ return -1;
+ }
+
+ while ((dp = readdir(dd)) != NULL) {
+ int n;
+
+ name[0] = rest[0] = '\0';
+
+ n = sscanf(dp->d_name, "lib%[^.].so.%s",
+ name, rest);
+
+ if (n < 2 || rest[0] == '\0')
+ continue;
+
+ ndewey = getdewey(dewey, rest);
+ enter(dir, dp->d_name, name, dewey, ndewey);
+ }
+
+ return 0;
+}
+
+static void
+enter(dir, file, name, dewey, ndewey)
+char *dir, *file, *name;
+int dewey[], ndewey;
+{
+ struct shlib_list *shp;
+
+ for (shp = shlib_head; shp; shp = shp->next) {
+ if (strcmp(name, shp->name) != 0 || major != shp->major)
+ continue;
+
+ /* Name matches existing entry */
+ if (cmpndewey(dewey, ndewey, shp->dewey, shp->ndewey) > 0) {
+
+ /* Update this entry with higher versioned lib */
+ if (verbose)
+ printf("Updating lib%s.%d.%d to %s/%s\n",
+ shp->name, shp->major, shp->minor,
+ dir, file);
+
+ free(shp->name);
+ shp->name = strdup(name);
+ free(shp->path);
+ shp->path = concat(dir, "/", file);
+ bcopy(dewey, shp->dewey, sizeof(shp->dewey));
+ shp->ndewey = ndewey;
+ }
+ break;
+ }
+
+ if (shp)
+ /* Name exists: older version or just updated */
+ return;
+
+ /* Allocate new list element */
+ if (verbose)
+ printf("Adding %s/%s\n", dir, file);
+
+ shp = (struct shlib_list *)xmalloc(sizeof *shp);
+ shp->name = strdup(name);
+ shp->path = concat(dir, "/", file);
+ bcopy(dewey, shp->dewey, MAXDEWEY);
+ shp->ndewey = ndewey;
+ shp->next = NULL;
+
+ *shlib_tail = shp;
+ shlib_tail = &shp->next;
+}
+
+
+#if DEBUG
+/* test */
+#undef _PATH_LD_HINTS
+#define _PATH_LD_HINTS "./ld.so.hints"
+#endif
+
+int
+hinthash(cp, vmajor, vminor)
+char *cp;
+int vmajor, vminor;
+{
+ int k = 0;
+
+ while (*cp)
+ k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
+
+ k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
+ k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
+
+ return k;
+}
+
+int
+build_hints()
+{
+ struct hints_header hdr;
+ struct hints_bucket *blist;
+ struct shlib_list *shp;
+ char *strtab;
+ int i, n, str_index = 0;
+ int strtab_sz = 0; /* Total length of strings */
+ int nhints = 0; /* Total number of hints */
+ int fd;
+ char *tmpfile;
+
+ for (shp = shlib_head; shp; shp = shp->next) {
+ strtab_sz += 1 + strlen(shp->name);
+ strtab_sz += 1 + strlen(shp->path);
+ nhints++;
+ }
+
+ /* Fill hints file header */
+ hdr.hh_magic = HH_MAGIC;
+ hdr.hh_version = LD_HINTS_VERSION_1;
+ hdr.hh_nbucket = 1 * nhints;
+ n = hdr.hh_nbucket * sizeof(struct hints_bucket);
+ hdr.hh_hashtab = sizeof(struct hints_header);
+ hdr.hh_strtab = hdr.hh_hashtab + n;
+ hdr.hh_strtab_sz = strtab_sz;
+ hdr.hh_ehints = hdr.hh_strtab + hdr.hh_strtab_sz;
+
+ if (verbose)
+ printf("Totals: entries %d, buckets %d, string size %d\n",
+ nhints, hdr.hh_nbucket, strtab_sz);
+
+ /* Allocate buckets and string table */
+ blist = (struct hints_bucket *)xmalloc(n);
+ bzero((char *)blist, n);
+ for (i = 0; i < hdr.hh_nbucket; i++)
+ /* Empty all buckets */
+ blist[i].hi_next = -1;
+
+ strtab = (char *)xmalloc(strtab_sz);
+
+ /* Enter all */
+ for (shp = shlib_head; shp; shp = shp->next) {
+ struct hints_bucket *bp;
+
+ bp = blist +
+ (hinthash(shp->name, shp->major, shp->minor) % hdr.hh_nbucket);
+
+ if (bp->hi_pathx) {
+ int i;
+
+ for (i = 0; i < hdr.hh_nbucket; i++) {
+ if (blist[i].hi_pathx == 0)
+ break;
+ }
+ if (i == hdr.hh_nbucket) {
+ fprintf(stderr, "Bummer!\n");
+ return -1;
+ }
+ while (bp->hi_next != -1)
+ bp = &blist[bp->hi_next];
+ bp->hi_next = i;
+ bp = blist + i;
+ }
+
+ /* Insert strings in string table */
+ bp->hi_namex = str_index;
+ strcpy(strtab + str_index, shp->name);
+ str_index += 1 + strlen(shp->name);
+
+ bp->hi_pathx = str_index;
+ strcpy(strtab + str_index, shp->path);
+ str_index += 1 + strlen(shp->path);
+
+ /* Copy versions */
+ bcopy(shp->dewey, bp->hi_dewey, sizeof(bp->hi_dewey));
+ bp->hi_ndewey = shp->ndewey;
+ }
+
+ tmpfile = concat(_PATH_LD_HINTS, "+", "");
+ if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0444)) == -1) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ if (write(fd, &hdr, sizeof(struct hints_header)) !=
+ sizeof(struct hints_header)) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ if (write(fd, blist, hdr.hh_nbucket * sizeof(struct hints_bucket)) !=
+ hdr.hh_nbucket * sizeof(struct hints_bucket)) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ if (write(fd, strtab, strtab_sz) != strtab_sz) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ if (close(fd) != 0) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ /* Install it */
+ if (unlink(_PATH_LD_HINTS) != 0 && errno != ENOENT) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ if (rename(tmpfile, _PATH_LD_HINTS) != 0) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+listhints()
+{
+ int fd;
+ caddr_t addr;
+ long msize;
+ struct hints_header *hdr;
+ struct hints_bucket *blist;
+ char *strtab;
+ int i;
+
+ if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ msize = PAGSIZ;
+ addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
+
+ if (addr == (caddr_t)-1) {
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+
+ hdr = (struct hints_header *)addr;
+ if (HH_BADMAG(*hdr)) {
+ fprintf(stderr, "%s: Bad magic: %d\n");
+ return -1;
+ }
+
+ if (hdr->hh_version != LD_HINTS_VERSION_1) {
+ fprintf(stderr, "Unsupported version: %d\n", hdr->hh_version);
+ return -1;
+ }
+
+ if (hdr->hh_ehints > msize) {
+ if (mmap(addr+msize, hdr->hh_ehints - msize,
+ PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED,
+ fd, msize) != (caddr_t)(addr+msize)) {
+
+ perror(_PATH_LD_HINTS);
+ return -1;
+ }
+ }
+ close(fd);
+
+ blist = (struct hints_bucket *)(addr + hdr->hh_hashtab);
+ strtab = (char *)(addr + hdr->hh_strtab);
+
+ printf("%s:\n", _PATH_LD_HINTS);
+ for (i = 0; i < hdr->hh_nbucket; i++) {
+ struct hints_bucket *bp = &blist[i];
+
+ /* Sanity check */
+ if (bp->hi_namex >= hdr->hh_strtab_sz) {
+ fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex);
+ return -1;
+ }
+ if (bp->hi_pathx >= hdr->hh_strtab_sz) {
+ fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx);
+ return -1;
+ }
+
+ printf("\t%d:-l%s.%d.%d => %s (%d -> %d)\n",
+ i,
+ strtab + bp->hi_namex, bp->hi_major, bp->hi_minor,
+ strtab + bp->hi_pathx,
+ hinthash(strtab+bp->hi_namex, bp->hi_major, bp->hi_minor)
+ % hdr->hh_nbucket,
+ bp->hi_next);
+ }
+
+ return 0;
+}
+
diff --git a/sbin/sysctl/Makefile b/sbin/sysctl/Makefile
new file mode 100644
index 0000000..40d12d2
--- /dev/null
+++ b/sbin/sysctl/Makefile
@@ -0,0 +1,6 @@
+# @(#)Makefile 8.1 (Berkeley) 6/6/93
+
+PROG= sysctl
+MAN8= sysctl.0
+
+.include <bsd.prog.mk>
diff --git a/sbin/sysctl/pathconf.c b/sbin/sysctl/pathconf.c
new file mode 100644
index 0000000..4b60ccf
--- /dev/null
+++ b/sbin/sysctl/pathconf.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)pathconf.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/unistd.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define PC_NAMES { \
+ { 0, 0 }, \
+ { "link_max", CTLTYPE_INT }, \
+ { "max_canon", CTLTYPE_INT }, \
+ { "max_input", CTLTYPE_INT }, \
+ { "name_max", CTLTYPE_INT }, \
+ { "path_max", CTLTYPE_INT }, \
+ { "pipe_buf", CTLTYPE_INT }, \
+ { "chown_restricted", CTLTYPE_INT }, \
+ { "no_trunc", CTLTYPE_INT }, \
+ { "vdisable", CTLTYPE_INT }, \
+}
+#define PC_MAXID 10
+
+struct ctlname pcnames[] = PC_NAMES;
+char names[BUFSIZ];
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list pclist = { pcnames, PC_MAXID };
+
+int Aflag, aflag, nflag, wflag, stdinflag;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ char *path;
+ int ch;
+
+ while ((ch = getopt(argc, argv, "Aan")) != EOF) {
+ switch (ch) {
+
+ case 'A':
+ Aflag = 1;
+ break;
+
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ usage();
+ path = *argv++;
+ if (strcmp(path, "-") == 0)
+ stdinflag = 1;
+ argc--;
+ if (Aflag || aflag) {
+ listall(path, &pclist);
+ exit(0);
+ }
+ if (argc == 0)
+ usage();
+ while (argc-- > 0)
+ parse(path, *argv, 1);
+ exit(0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+listall(path, lp)
+ char *path;
+ struct list *lp;
+{
+ int lvl2;
+
+ if (lp->list == 0)
+ return;
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ parse(path, lp->list[lvl2].ctl_name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into an index.
+ * Lookup and print out the attribute if it exists.
+ */
+parse(pathname, string, flags)
+ char *pathname;
+ char *string;
+ int flags;
+{
+ int indx, value;
+ char *bufp, buf[BUFSIZ];
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((indx = findname(string, "top", &bufp, &pclist)) == -1)
+ return;
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
+ return;
+ }
+ if (stdinflag)
+ value = fpathconf(0, indx);
+ else
+ value = pathconf(pathname, indx);
+ if (value == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case EOPNOTSUPP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%d\n", value);
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ return (-1);
+ }
+ return (i);
+}
+
+usage()
+{
+
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n",
+ "pathname [-n] variable ...",
+ "pathname [-n] -a", "pathname [-n] -A");
+ exit(1);
+}
diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8
new file mode 100644
index 0000000..9def509
--- /dev/null
+++ b/sbin/sysctl/sysctl.8
@@ -0,0 +1,208 @@
+.\" 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.
+.\"
+.\" @(#)sysctl.8 8.1 (Berkeley) 6/6/93
+.\"
+.Dd "June 6, 1993"
+.Dt SYSCTL 8
+.Os
+.Sh NAME
+.Nm sysctl
+.Nd get or set kernel state
+.Sh SYNOPSIS
+.Nm sysctl
+.Op Fl n
+.Ar name ...
+.Nm sysctl
+.Op Fl n
+.Fl w
+.Ar name=value ...
+.Nm sysctl
+.Op Fl n
+.Fl aA
+.Sh DESCRIPTION
+The
+.Nm sysctl
+utility retrieves kernel state and allows processes with
+appropriate privilege to set kernel state.
+The state to be retrieved or set is described using a
+``Management Information Base'' (``MIB'') style name,
+described as a dotted set of components.
+The
+.Fl a
+flag can be used to list all the currently available string or integer values.
+The
+.Fl A
+flag will list all the known MIB names including tables.
+Those with string or integer values will be printed as with the
+.Fl a
+flag; for the table values,
+the name of the utility to retrieve them is given.
+.Pp
+The
+.Fl n
+flag specifies that the printing of the field name should be
+suppressed and that only its value should be output.
+This flag is useful for setting shell variables.
+For example, to save the pagesize in variable psize, use:
+.Bd -literal -offset indent -compact
+set psize=`sysctl -n hw.pagesize`
+.Ed
+.Pp
+If just a MIB style name is given,
+the corresponding value is retrieved.
+If a value is to be set, the
+.Fl w
+flag must be specified and the MIB name followed
+by an equal sign and the new value to be used.
+.Pp
+The information available from
+.Nm sysctl
+consists of integers, strings, and tables.
+The tabular information can only be retrieved by special
+purpose programs such as
+.Nm ps ,
+.Nm systat ,
+and
+.Nm netstat .
+The string and integer information is summaried below.
+For a detailed description of these variable see
+.Xr sysctl 3 .
+The changeable column indicates whether a process with appropriate
+privilege can change the value.
+.Bl -column net.inet.ip.forwardingxxxxxx integerxxx
+.It Sy Name Type Changeable
+.It kern.ostype string no
+.It kern.osrelease string no
+.It kern.osrevision integer no
+.It kern.version string no
+.It kern.maxvnodes integer yes
+.It kern.maxproc integer yes
+.It kern.maxfiles integer yes
+.It kern.argmax integer no
+.It kern.securelevel integer raise only
+.It kern.hostname string yes
+.It kern.hostid integer yes
+.It kern.clockrate struct no
+.It kern.posix1version integer no
+.It kern.ngroups integer no
+.It kern.job_control integer no
+.It kern.saved_ids integer no
+.It kern.link_max integer no
+.It kern.max_canon integer no
+.It kern.max_input integer no
+.It kern.name_max integer no
+.It kern.path_max integer no
+.It kern.pipe_buf integer no
+.It kern.chown_restricted integer no
+.It kern.no_trunc integer no
+.It kern.vdisable integer no
+.It kern.boottime struct no
+.It vm.loadavg struct no
+.It machdep.console_device dev_t no
+.It net.inet.ip.forwarding integer yes
+.It net.inet.ip.redirect integer yes
+.It net.inet.ip.ttl integer yes
+.It net.inet.icmp.maskrepl integer yes
+.It net.inet.udp.checksum integer yes
+.It hw.machine string no
+.It hw.model string no
+.It hw.ncpu integer no
+.It hw.byteorder integer no
+.It hw.physmem integer no
+.It hw.usermem integer no
+.It hw.pagesize integer no
+.It user.cs_path string no
+.It user.bc_base_max integer no
+.It user.bc_dim_max integer no
+.It user.bc_scale_max integer no
+.It user.bc_string_max integer no
+.It user.coll_weights_max integer no
+.It user.expr_nest_max integer no
+.It user.line_max integer no
+.It user.re_dup_max integer no
+.It user.posix2_version integer no
+.It user.posix2_c_bind integer no
+.It user.posix2_c_dev integer no
+.It user.posix2_char_term integer no
+.It user.posix2_fort_dev integer no
+.It user.posix2_fort_run integer no
+.It user.posix2_localedef integer no
+.It user.posix2_sw_dev integer no
+.It user.posix2_upe integer no
+.El
+.Sh EXAMPLES
+.Pp
+For example, to retrieve the maximum number of processes allowed
+in the system, one would use the follow request:
+.Bd -literal -offset indent -compact
+sysctl kern.maxproc
+.Ed
+.Pp
+To set the maximum number of processes allowed
+in the system to 1000, one would use the follow request:
+.Bd -literal -offset indent -compact
+sysctl -w kern.maxproc=1000
+.Ed
+.Pp
+Information about the system clock rate may be obtained with:
+.Bd -literal -offset indent -compact
+sysctl kern.clockrate
+.Ed
+.Pp
+Information about the load average history may be obtained with
+.Bd -literal -offset indent -compact
+sysctl vm.loadavg
+.Ed
+.Sh FILES
+.Bl -tag -width <netinet/icmpXvar.h> -compact
+.It Pa <sys/sysctl.h>
+definitions for top level identifiers, second level kernel and hardware
+identifiers, and user level identifiers
+.It Pa <sys/socket.h>
+definitions for second level network identifiers
+.It Pa <sys/gmon.h>
+definitions for third level profiling identifiers
+.It Pa <vm/vm_param.h>
+definitions for second level virtual memory identifiers
+.It Pa <netinet/in.h>
+definitions for third level Internet identifiers and
+fourth level IP identifiers
+.It Pa <netinet/icmp_var.h>
+definitions for fourth level ICMP identifiers
+.It Pa <netinet/udp_var.h>
+definitions for fourth level UDP identifiers
+.El
+.Sh SEE ALSO
+.Xr sysctl 3
+.Sh HISTORY
+.Nm sysctl
+first appeared in 4.4BSD.
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c
new file mode 100644
index 0000000..a342686
--- /dev/null
+++ b/sbin/sysctl/sysctl.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)sysctl.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/gmon.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <vm/vm_param.h>
+#include <machine/cpu.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+#include <netinet/ip_var.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct ctlname topname[] = CTL_NAMES;
+struct ctlname kernname[] = CTL_KERN_NAMES;
+struct ctlname vmname[] = CTL_VM_NAMES;
+struct ctlname netname[] = CTL_NET_NAMES;
+struct ctlname hwname[] = CTL_HW_NAMES;
+struct ctlname username[] = CTL_USER_NAMES;
+struct ctlname debugname[CTL_DEBUG_MAXID];
+#ifdef CTL_MACHDEP_NAMES
+struct ctlname machdepname[] = CTL_MACHDEP_NAMES;
+#endif
+char names[BUFSIZ];
+
+struct list {
+ struct ctlname *list;
+ int size;
+};
+struct list toplist = { topname, CTL_MAXID };
+struct list secondlevel[] = {
+ { 0, 0 }, /* CTL_UNSPEC */
+ { kernname, KERN_MAXID }, /* CTL_KERN */
+ { vmname, VM_MAXID }, /* CTL_VM */
+ { 0, 0 }, /* CTL_FS */
+ { netname, NET_MAXID }, /* CTL_NET */
+ { 0, CTL_DEBUG_MAXID }, /* CTL_DEBUG */
+ { hwname, HW_MAXID }, /* CTL_HW */
+#ifdef CTL_MACHDEP_NAMES
+ { machdepname, CPU_MAXID }, /* CTL_MACHDEP */
+#else
+ { 0, 0 }, /* CTL_MACHDEP */
+#endif
+ { username, USER_MAXID }, /* CTL_USER_NAMES */
+};
+
+int Aflag, aflag, nflag, wflag;
+
+/*
+ * Variables requiring special processing.
+ */
+#define CLOCK 0x00000001
+#define BOOTTIME 0x00000002
+#define CONSDEV 0x00000004
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch, lvl1;
+
+ while ((ch = getopt(argc, argv, "Aanw")) != EOF) {
+ switch (ch) {
+
+ case 'A':
+ Aflag = 1;
+ break;
+
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'n':
+ nflag = 1;
+ break;
+
+ case 'w':
+ wflag = 1;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (Aflag || aflag) {
+ debuginit();
+ for (lvl1 = 1; lvl1 < CTL_MAXID; lvl1++)
+ listall(topname[lvl1].ctl_name, &secondlevel[lvl1]);
+ exit(0);
+ }
+ if (argc == 0)
+ usage();
+ while (argc-- > 0)
+ parse(*argv, 1);
+ exit(0);
+}
+
+/*
+ * List all variables known to the system.
+ */
+listall(prefix, lp)
+ char *prefix;
+ struct list *lp;
+{
+ int lvl2;
+ char *cp, name[BUFSIZ];
+
+ if (lp->list == 0)
+ return;
+ strcpy(name, prefix);
+ cp = &name[strlen(name)];
+ *cp++ = '.';
+ for (lvl2 = 0; lvl2 < lp->size; lvl2++) {
+ if (lp->list[lvl2].ctl_name == 0)
+ continue;
+ strcpy(cp, lp->list[lvl2].ctl_name);
+ parse(name, Aflag);
+ }
+}
+
+/*
+ * Parse a name into a MIB entry.
+ * Lookup and print out the MIB entry if it exists.
+ * Set a new value if requested.
+ */
+parse(string, flags)
+ char *string;
+ int flags;
+{
+ int indx, type, state, size, len;
+ int special = 0;
+ void *newval = 0;
+ int intval, newsize = 0;
+ quad_t quadval;
+ struct list *lp;
+ int mib[CTL_MAXNAME];
+ char *cp, *bufp, buf[BUFSIZ], strval[BUFSIZ];
+
+ bufp = buf;
+ snprintf(buf, BUFSIZ, "%s", string);
+ if ((cp = strchr(string, '=')) != NULL) {
+ if (!wflag) {
+ fprintf(stderr, "Must specify -w to set variables\n");
+ exit(2);
+ }
+ *strchr(buf, '=') = '\0';
+ *cp++ = '\0';
+ while (isspace(*cp))
+ cp++;
+ newval = cp;
+ newsize = strlen(cp);
+ }
+ if ((indx = findname(string, "top", &bufp, &toplist)) == -1)
+ return;
+ mib[0] = indx;
+ if (indx == CTL_DEBUG)
+ debuginit();
+ lp = &secondlevel[indx];
+ if (lp->list == 0) {
+ fprintf(stderr, "%s: class is not implemented\n",
+ topname[indx]);
+ return;
+ }
+ if (bufp == NULL) {
+ listall(topname[indx].ctl_name, lp);
+ return;
+ }
+ if ((indx = findname(string, "second", &bufp, lp)) == -1)
+ return;
+ mib[1] = indx;
+ type = lp->list[indx].ctl_type;
+ len = 2;
+ switch (mib[0]) {
+
+ case CTL_KERN:
+ switch (mib[1]) {
+ case KERN_PROF:
+ mib[2] = GPROF_STATE;
+ size = sizeof state;
+ if (sysctl(mib, 3, &state, &size, NULL, 0) < 0) {
+ if (flags == 0)
+ return;
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stderr,
+ "kernel is not compiled for profiling\n");
+ return;
+ }
+ if (!nflag)
+ fprintf(stdout, "%s: %s\n", string,
+ state == GMON_PROF_OFF ? "off" : "running");
+ return;
+ case KERN_VNODE:
+ case KERN_FILE:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use pstat to view %s information\n", string);
+ return;
+ case KERN_PROC:
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use ps to view %s information\n", string);
+ return;
+ case KERN_CLOCKRATE:
+ special |= CLOCK;
+ break;
+ case KERN_BOOTTIME:
+ special |= BOOTTIME;
+ break;
+ }
+ break;
+
+ case CTL_HW:
+ break;
+
+ case CTL_VM:
+ if (mib[1] == VM_LOADAVG) {
+ double loads[3];
+
+ getloadavg(loads, 3);
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout, "%.2f %.2f %.2f\n",
+ loads[0], loads[1], loads[2]);
+ return;
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr,
+ "Use vmstat or systat to view %s information\n", string);
+ return;
+
+ case CTL_NET:
+ if (mib[1] == PF_INET) {
+ len = sysctl_inet(string, &bufp, mib, flags, &type);
+ if (len >= 0)
+ break;
+ return;
+ }
+ if (flags == 0)
+ return;
+ fprintf(stderr, "Use netstat to view %s information\n", string);
+ return;
+
+ case CTL_DEBUG:
+ mib[2] = CTL_DEBUG_VALUE;
+ len = 3;
+ break;
+
+ case CTL_MACHDEP:
+#ifdef CPU_CONSDEV
+ if (mib[1] == CPU_CONSDEV)
+ special |= CONSDEV;
+#endif
+ break;
+
+ case CTL_FS:
+ case CTL_USER:
+ break;
+
+ default:
+ fprintf(stderr, "Illegal top level value: %d\n", mib[0]);
+ return;
+
+ }
+ if (bufp) {
+ fprintf(stderr, "name %s in %s is unknown\n", *bufp, string);
+ return;
+ }
+ if (newsize > 0) {
+ switch (type) {
+ case CTLTYPE_INT:
+ intval = atoi(newval);
+ newval = &intval;
+ newsize = sizeof intval;
+ break;
+
+ case CTLTYPE_QUAD:
+ sscanf(newval, "%qd", &quadval);
+ newval = &quadval;
+ newsize = sizeof quadval;
+ break;
+ }
+ }
+ size = BUFSIZ;
+ if (sysctl(mib, len, buf, &size, newsize ? newval : 0, newsize) == -1) {
+ if (flags == 0)
+ return;
+ switch (errno) {
+ case EOPNOTSUPP:
+ fprintf(stderr, "%s: value is not available\n", string);
+ return;
+ case ENOTDIR:
+ fprintf(stderr, "%s: specification is incomplete\n",
+ string);
+ return;
+ case ENOMEM:
+ fprintf(stderr, "%s: type is unknown to this program\n",
+ string);
+ return;
+ default:
+ perror(string);
+ return;
+ }
+ }
+ if (special & CLOCK) {
+ struct clockinfo *clkp = (struct clockinfo *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s: ", string);
+ fprintf(stdout,
+ "hz = %d, tick = %d, profhz = %d, stathz = %d\n",
+ clkp->hz, clkp->tick, clkp->profhz, clkp->stathz);
+ return;
+ }
+ if (special & BOOTTIME) {
+ struct timeval *btp = (struct timeval *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ ctime(&btp->tv_sec));
+ else
+ fprintf(stdout, "%d\n", btp->tv_sec);
+ return;
+ }
+ if (special & CONSDEV) {
+ dev_t dev = *(dev_t *)buf;
+
+ if (!nflag)
+ fprintf(stdout, "%s = %s\n", string,
+ devname(dev, S_IFCHR));
+ else
+ fprintf(stdout, "0x%x\n", dev);
+ return;
+ }
+ switch (type) {
+ case CTLTYPE_INT:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%d\n", *(int *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %d -> ", string,
+ *(int *)buf);
+ fprintf(stdout, "%d\n", *(int *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRING:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%s\n", buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %s -> ", string, buf);
+ fprintf(stdout, "%s\n", newval);
+ }
+ return;
+
+ case CTLTYPE_QUAD:
+ if (newsize == 0) {
+ if (!nflag)
+ fprintf(stdout, "%s = ", string);
+ fprintf(stdout, "%qd\n", *(quad_t *)buf);
+ } else {
+ if (!nflag)
+ fprintf(stdout, "%s: %qd -> ", string,
+ *(quad_t *)buf);
+ fprintf(stdout, "%qd\n", *(quad_t *)newval);
+ }
+ return;
+
+ case CTLTYPE_STRUCT:
+ fprintf(stderr, "%s: unknown structure returned\n",
+ string);
+ return;
+
+ default:
+ case CTLTYPE_NODE:
+ fprintf(stderr, "%s: unknown type returned\n",
+ string);
+ return;
+ }
+}
+
+/*
+ * Initialize the set of debugging names
+ */
+debuginit()
+{
+ int mib[3], size, loc, i;
+
+ if (secondlevel[CTL_DEBUG].list != 0)
+ return;
+ secondlevel[CTL_DEBUG].list = debugname;
+ mib[0] = CTL_DEBUG;
+ mib[2] = CTL_DEBUG_NAME;
+ for (loc = 0, i = 0; i < CTL_DEBUG_MAXID; i++) {
+ mib[1] = i;
+ size = BUFSIZ - loc;
+ if (sysctl(mib, 3, &names[loc], &size, NULL, 0) == -1)
+ continue;
+ debugname[i].ctl_name = &names[loc];
+ debugname[i].ctl_type = CTLTYPE_INT;
+ loc += size;
+ }
+}
+
+struct ctlname inetname[] = CTL_IPPROTO_NAMES;
+struct ctlname ipname[] = IPCTL_NAMES;
+struct ctlname icmpname[] = ICMPCTL_NAMES;
+struct ctlname udpname[] = UDPCTL_NAMES;
+struct list inetlist = { inetname, IPPROTO_MAXID };
+struct list inetvars[] = {
+ { ipname, IPCTL_MAXID }, /* ip */
+ { icmpname, ICMPCTL_MAXID }, /* icmp */
+ { 0, 0 }, /* igmp */
+ { 0, 0 }, /* ggmp */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }, /* tcp */
+ { 0, 0 },
+ { 0, 0 }, /* egp */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }, /* pup */
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { udpname, UDPCTL_MAXID }, /* udp */
+};
+
+/*
+ * handle internet requests
+ */
+sysctl_inet(string, bufpp, mib, flags, typep)
+ char *string;
+ char **bufpp;
+ int mib[];
+ int flags;
+ int *typep;
+{
+ struct list *lp;
+ int indx;
+
+ if (*bufpp == NULL) {
+ listall(string, &inetlist);
+ return (-1);
+ }
+ if ((indx = findname(string, "third", bufpp, &inetlist)) == -1)
+ return (-1);
+ mib[2] = indx;
+ if (indx <= IPPROTO_UDP && inetvars[indx].list != NULL)
+ lp = &inetvars[indx];
+ else if (!flags)
+ return (-1);
+ else {
+ fprintf(stderr, "%s: no variables defined for this protocol\n",
+ string);
+ return (-1);
+ }
+ if (*bufpp == NULL) {
+ listall(string, lp);
+ return (-1);
+ }
+ if ((indx = findname(string, "fourth", bufpp, lp)) == -1)
+ return (-1);
+ mib[3] = indx;
+ *typep = lp->list[indx].ctl_type;
+ return (4);
+}
+
+/*
+ * Scan a list of names searching for a particular name.
+ */
+findname(string, level, bufp, namelist)
+ char *string;
+ char *level;
+ char **bufp;
+ struct list *namelist;
+{
+ char *name;
+ int i;
+
+ if (namelist->list == 0 || (name = strsep(bufp, ".")) == NULL) {
+ fprintf(stderr, "%s: incomplete specification\n", string);
+ return (-1);
+ }
+ for (i = 0; i < namelist->size; i++)
+ if (namelist->list[i].ctl_name != NULL &&
+ strcmp(name, namelist->list[i].ctl_name) == 0)
+ break;
+ if (i == namelist->size) {
+ fprintf(stderr, "%s level name %s in %s is invalid\n",
+ level, name, string);
+ return (-1);
+ }
+ return (i);
+}
+
+usage()
+{
+
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n",
+ "sysctl [-n] variable ...", "sysctl [-n] -w variable=value ...",
+ "sysctl [-n] -a", "sysctl [-n] -A");
+ exit(1);
+}
OpenPOWER on IntegriCloud