diff options
Diffstat (limited to 'sbin')
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); +} |