Import Lite2's src/sbin, except for XNSrouted and routed. All relevant

files in src/sbin are off the vendor branch, so this doesn't change the
active versions.
This commit is contained in:
Bruce Evans 1997-07-02 00:25:26 +00:00
parent c46940197c
commit 25e43cba72
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/CSRG/dist/; revision=27163
19 changed files with 9671 additions and 0 deletions

209
sbin/badsect/badsect.c Normal file
View File

@ -0,0 +1,209 @@
/*
* Copyright (c) 1981, 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1981, 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)badsect.c 8.2 (Berkeley) 5/4/95";
#endif /* not lint */
/*
* badsect
*
* Badsect takes a list of file-system relative sector numbers
* and makes files containing the blocks of which these sectors are a part.
* It can be used to contain sectors which have problems if these sectors
* are not part of the bad file for the pack (see bad144). For instance,
* this program can be used if the driver for the file system in question
* does not support bad block forwarding.
*/
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
union {
struct fs fs;
char fsx[SBSIZE];
} ufs;
#define sblock ufs.fs
union {
struct cg cg;
char cgx[MAXBSIZE];
} ucg;
#define acg ucg.cg
struct fs *fs;
int fso, fsi;
int errs;
long dev_bsize = 1;
char buf[MAXBSIZE];
void rdfs __P((daddr_t, int, char *));
int chkuse __P((daddr_t, int));
int
main(argc, argv)
int argc;
char *argv[];
{
daddr_t number;
struct stat stbuf, devstat;
register struct direct *dp;
DIR *dirp;
char name[BUFSIZ];
if (argc < 3) {
fprintf(stderr, "usage: badsect bbdir blkno [ blkno ]\n");
exit(1);
}
if (chdir(argv[1]) < 0 || stat(".", &stbuf) < 0) {
perror(argv[1]);
exit(2);
}
strcpy(name, _PATH_DEV);
if ((dirp = opendir(name)) == NULL) {
perror(name);
exit(3);
}
while ((dp = readdir(dirp)) != NULL) {
strcpy(&name[5], dp->d_name);
if (stat(name, &devstat) < 0) {
perror(name);
exit(4);
}
if (stbuf.st_dev == devstat.st_rdev &&
(devstat.st_mode & IFMT) == IFBLK)
break;
}
closedir(dirp);
if (dp == NULL) {
printf("Cannot find dev 0%o corresponding to %s\n",
stbuf.st_rdev, argv[1]);
exit(5);
}
if ((fsi = open(name, 0)) < 0) {
perror(name);
exit(6);
}
fs = &sblock;
rdfs(SBOFF, SBSIZE, (char *)fs);
dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
for (argc -= 2, argv += 2; argc > 0; argc--, argv++) {
number = atoi(*argv);
if (chkuse(number, 1))
continue;
if (mknod(*argv, IFMT|0600, dbtofsb(fs, number)) < 0) {
perror(*argv);
errs++;
}
}
printf("Don't forget to run ``fsck %s''\n", name);
exit(errs);
}
int
chkuse(blkno, cnt)
daddr_t blkno;
int cnt;
{
int cg;
daddr_t fsbn, bn;
fsbn = dbtofsb(fs, blkno);
if ((unsigned)(fsbn+cnt) > fs->fs_size) {
printf("block %d out of range of file system\n", blkno);
return (1);
}
cg = dtog(fs, fsbn);
if (fsbn < cgdmin(fs, cg)) {
if (cg == 0 || (fsbn+cnt) > cgsblock(fs, cg)) {
printf("block %d in non-data area: cannot attach\n",
blkno);
return (1);
}
} else {
if ((fsbn+cnt) > cgbase(fs, cg+1)) {
printf("block %d in non-data area: cannot attach\n",
blkno);
return (1);
}
}
rdfs(fsbtodb(fs, cgtod(fs, cg)), (int)sblock.fs_cgsize,
(char *)&acg);
if (!cg_chkmagic(&acg)) {
fprintf(stderr, "cg %d: bad magic number\n", cg);
errs++;
return (1);
}
bn = dtogd(fs, fsbn);
if (isclr(cg_blksfree(&acg), bn))
printf("Warning: sector %d is in use\n", blkno);
return (0);
}
/*
* read a block from the file system
*/
void
rdfs(bno, size, bf)
daddr_t bno;
int size;
char *bf;
{
int n;
if (lseek(fsi, (off_t)bno * dev_bsize, SEEK_SET) < 0) {
printf("seek error: %ld\n", bno);
perror("rdfs");
exit(1);
}
n = read(fsi, bf, size);
if (n != size) {
printf("read error: %ld\n", bno);
perror("rdfs");
exit(1);
}
}

131
sbin/clri/clri.c Normal file
View File

@ -0,0 +1,131 @@
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Rich $alz of BBN Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1990, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)clri.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
int
main(argc, argv)
int argc;
char *argv[];
{
register struct fs *sbp;
register struct dinode *ip;
register int fd;
struct dinode ibuf[MAXBSIZE / sizeof (struct dinode)];
long generation, bsize;
off_t offset;
int inonum;
char *fs, sblock[SBSIZE];
if (argc < 3) {
(void)fprintf(stderr, "usage: clri filesystem inode ...\n");
exit(1);
}
fs = *++argv;
/* get the superblock. */
if ((fd = open(fs, O_RDWR, 0)) < 0)
err(1, "%s", fs);
if (lseek(fd, (off_t)(SBLOCK * DEV_BSIZE), SEEK_SET) < 0)
err(1, "%s", fs);
if (read(fd, sblock, sizeof(sblock)) != sizeof(sblock))
errx(1, "%s: can't read superblock", fs);
sbp = (struct fs *)sblock;
if (sbp->fs_magic != FS_MAGIC)
errx(1, "%s: superblock magic number 0x%x, not 0x%x",
fs, sbp->fs_magic, FS_MAGIC);
bsize = sbp->fs_bsize;
/* remaining arguments are inode numbers. */
while (*++argv) {
/* get the inode number. */
if ((inonum = atoi(*argv)) <= 0)
errx(1, "%s is not a valid inode number", *argv);
(void)printf("clearing %d\n", inonum);
/* read in the appropriate block. */
offset = ino_to_fsba(sbp, inonum); /* inode to fs blk */
offset = fsbtodb(sbp, offset); /* fs blk disk blk */
offset *= DEV_BSIZE; /* disk blk to bytes */
/* seek and read the block */
if (lseek(fd, offset, SEEK_SET) < 0)
err(1, "%s", fs);
if (read(fd, ibuf, bsize) != bsize)
err(1, "%s", fs);
/* get the inode within the block. */
ip = &ibuf[ino_to_fsbo(sbp, inonum)];
/* clear the inode, and bump the generation count. */
generation = ip->di_gen + 1;
memset(ip, 0, sizeof(*ip));
ip->di_gen = generation;
/* backup and write the block */
if (lseek(fd, (off_t)-bsize, SEEK_CUR) < 0)
err(1, "%s", fs);
if (write(fd, ibuf, bsize) != bsize)
err(1, "%s", fs);
(void)fsync(fd);
}
(void)close(fd);
exit(0);
}

View File

@ -0,0 +1,388 @@
.\" Copyright (c) 1987, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" Symmetric Computer Systems.
.\"
.\" 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.
.\"
.\" @(#)disklabel.5.5 8.2 (Berkeley) 5/6/94
.\"
.Dd May 6, 1994
.Dt DISKLABEL 5
.Os
.Sh NAME
.Nm disklabel
.Nd disk pack label
.Sh SYNOPSIS
.Fd #include <sys/disklabel.h>
.Sh DESCRIPTION
Each disk or disk pack on a system may contain a disk label
which provides detailed information
about the geometry of the disk and the partitions into which the disk
is divided.
It should be initialized when the disk is formatted,
and may be changed later with the
.Xr disklabel 8
program.
This information is used by the system disk driver and by the bootstrap
program to determine how to program the drive
and where to find the filesystems on the disk partitions.
Additional information is used by the filesystem in order
to use the disk most efficiently and to locate important filesystem information.
The description of each partition contains an identifier for the partition
type (standard filesystem, swap area, etc.).
The filesystem updates the in-core copy of the label if it contains
incomplete information about the filesystem.
.Pp
The label is located in sector number
.Dv LABELSECTOR
of the drive, usually sector 0 where it may be found
without any information about the disk geometry.
It is at an offset
.Dv LABELOFFSET
from the beginning of the sector, to allow room for the initial bootstrap.
The disk sector containing the label is normally made read-only
so that it is not accidentally overwritten by pack-to-pack copies
or swap operations;
the
.Dv DIOCWLABEL
.Xr ioctl 2 ,
which is done as needed by the
.Xr disklabel
program.
.Pp
A copy of the in-core label for a disk can be obtained with the
.Dv DIOCGDINFO
.Xr ioctl ;
this works with a file descriptor for a block or character (``raw'') device
for any partition of the disk.
The in-core copy of the label is set by the
.Dv DIOCSDINFO
.Xr ioctl .
The offset of a partition cannot generally be changed while it is open,
nor can it be made smaller while it is open.
One exception is that any change is allowed if no label was found
on the disk, and the driver was able to construct only a skeletal label
without partition information.
Finally, the
.Dv DIOCWDINFO
.Xr ioctl
operation sets the in-core label and then updates the on-disk label;
there must be an existing label on the disk for this operation to succeed.
Thus, the initial label for a disk or disk pack must be installed
by writing to the raw disk.
All of these operations are normally done using
.Xr disklabel .
.Pp
The format of the disk label, as specified in
.Aw Pa sys/disklabel.h ,
is
.Bd -literal
/*
* Disk description table, see disktab(5)
*/
#define DISKTAB "/etc/disktab"
/*
* Each disk has a label which includes information about the hardware
* disk geometry, filesystem partitions, and drive specific information.
* The label is in block 0 or 1, possibly offset from the beginning
* to leave room for a bootstrap, etc.
*/
#ifndef LABELSECTOR
#define LABELSECTOR 0 /* sector containing label */
#endif
#ifndef LABELOFFSET
#define LABELOFFSET 64 /* offset of label in sector */
#endif
#define DISKMAGIC ((u_long) 0x82564557) /* The disk magic number */
#ifndef MAXPARTITIONS
#define MAXPARTITIONS 8
#endif
#ifndef LOCORE
struct disklabel {
u_long d_magic; /* the magic number */
short d_type; /* drive type */
short d_subtype; /* controller/d_type specific */
char d_typename[16]; /* type name, e.g. "eagle" */
/*
* d_packname contains the pack identifier and is returned when
* the disklabel is read off the disk or in-core copy.
* d_boot0 and d_boot1 are the (optional) names of the
* primary (block 0) and secondary (block 1-15) bootstraps
* as found in /usr/mdec. These are returned when using
* getdiskbyname(3)
to retrieve the values from /etc/disktab.
*/
#if defined(KERNEL) || defined(STANDALONE)
char d_packname[16]; /* pack identifier */
#else
union {
char un_d_packname[16]; /* pack identifier */
struct {
char *un_d_boot0; /* primary bootstrap name */
char *un_d_boot1; /* secondary bootstrap name */
} un_b;
} d_un;
#define d_packname d_un.un_d_packname
#define d_boot0 d_un.un_b.un_d_boot0
#define d_boot1 d_un.un_b.un_d_boot1
#endif /* ! KERNEL or STANDALONE */
/* disk geometry: */
u_long d_secsize; /* # of bytes per sector */
u_long d_nsectors; /* # of data sectors per track */
u_long d_ntracks; /* # of tracks per cylinder */
u_long d_ncylinders; /* # of data cylinders per unit */
u_long d_secpercyl; /* # of data sectors per cylinder */
u_long d_secperunit; /* # of data sectors per unit */
/*
* Spares (bad sector replacements) below
* are not counted in d_nsectors or d_secpercyl.
* Spare sectors are assumed to be physical sectors
* which occupy space at the end of each track and/or cylinder.
*/
u_short d_sparespertrack; /* # of spare sectors per track */
u_short d_sparespercyl; /* # of spare sectors per cylinder */
/*
* Alternate cylinders include maintenance, replacement,
* configuration description areas, etc.
*/
u_long d_acylinders; /* # of alt. cylinders per unit */
/* hardware characteristics: */
/*
* d_interleave, d_trackskew and d_cylskew describe perturbations
* in the media format used to compensate for a slow controller.
* Interleave is physical sector interleave, set up by the formatter
* or controller when formatting. When interleaving is in use,
* logically adjacent sectors are not physically contiguous,
* but instead are separated by some number of sectors.
* It is specified as the ratio of physical sectors traversed
* per logical sector. Thus an interleave of 1:1 implies contiguous
* layout, while 2:1 implies that logical sector 0 is separated
* by one sector from logical sector 1.
* d_trackskew is the offset of sector 0 on track N
* relative to sector 0 on track N-1 on the same cylinder.
* Finally, d_cylskew is the offset of sector 0 on cylinder N
* relative to sector 0 on cylinder N-1.
*/
u_short d_rpm; /* rotational speed */
u_short d_interleave; /* hardware sector interleave */
u_short d_trackskew; /* sector 0 skew, per track */
u_short d_cylskew; /* sector 0 skew, per cylinder */
u_long d_headswitch; /* head switch time, usec */
u_long d_trkseek; /* track-to-track seek, usec */
u_long d_flags; /* generic flags */
#define NDDATA 5
u_long d_drivedata[NDDATA]; /* drive-type specific information */
#define NSPARE 5
u_long d_spare[NSPARE]; /* reserved for future use */
u_long d_magic2; /* the magic number (again) */
u_short d_checksum; /* xor of data incl. partitions */
/* filesystem and partition information: */
u_short d_npartitions; /* number of partitions in following */
u_long d_bbsize; /* size of boot area at sn0, bytes */
u_long d_sbsize; /* max size of fs superblock, bytes */
struct partition { /* the partition table */
u_long p_size; /* number of sectors in partition */
u_long p_offset; /* starting sector */
u_long p_fsize; /* filesystem basic fragment size */
u_char p_fstype; /* filesystem type, see below */
u_char p_frag; /* filesystem fragments per block */
union {
u_short cpg; /* UFS: FS cylinders per group */
u_short sgs; /* LFS: FS segment shift */
} __partition_u1;
#define p_cpg __partition_u1.cpg
#define p_sgs __partition_u1.sgs
u_short p_cpg; /* filesystem cylinders per group */
} d_partitions[MAXPARTITIONS]; /* actually may be more */
};
/* d_type values: */
#define DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
#define DTYPE_MSCP 2 /* MSCP */
#define DTYPE_DEC 3 /* other DEC (rk, rl) */
#define DTYPE_SCSI 4 /* SCSI */
#define DTYPE_ESDI 5 /* ESDI interface */
#define DTYPE_ST506 6 /* ST506 etc. */
#define DTYPE_HPIB 7 /* CS/80 on HP-IB */
#define DTYPE_HPFL 8 /* HP Fiber-link */
#define DTYPE_FLOPPY 10 /* floppy */
#ifdef DKTYPENAMES
static char *dktypenames[] = {
"unknown",
"SMD",
"MSCP",
"old DEC",
"SCSI",
"ESDI",
"ST506",
"HP-IB",
"HP-FL",
"type 9",
"floppy",
0
};
#define DKMAXTYPES (sizeof(dktypenames) / sizeof(dktypenames[0]) - 1)
#endif
/*
* Filesystem type and version.
* Used to interpret other filesystem-specific
* per-partition information.
*/
#define FS_UNUSED 0 /* unused */
#define FS_SWAP 1 /* swap */
#define FS_V6 2 /* Sixth Edition */
#define FS_V7 3 /* Seventh Edition */
#define FS_SYSV 4 /* System V */
#define FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
#define FS_V8 6 /* Eighth Edition, 4K blocks */
#define FS_BSDFFS 7 /* 4.2BSD fast file system */
#define FS_MSDOS 8 /* MSDOS file system */
#define FS_BSDLFS 9 /* 4.4BSD log-structured file system */
#define FS_OTHER 10 /* in use, but unknown/unsupported */
#define FS_HPFS 11 /* OS/2 high-performance file system */
#define FS_ISO9660 12 /* ISO 9660, normally CD-ROM */
#define FS_BOOT 13 /* partition contains bootstrap */
#ifdef DKTYPENAMES
static char *fstypenames[] = {
"unused",
"swap",
"Version 6",
"Version 7",
"System V",
"4.1BSD",
"Eighth Edition",
"4.2BSD",
"MSDOS",
"4.4LFS",
"unknown",
"HPFS",
"ISO9660",
"boot",
0
};
#define FSMAXTYPES (sizeof(fstypenames) / sizeof(fstypenames[0]) - 1)
#endif
/*
* flags shared by various drives:
*/
#define D_REMOVABLE 0x01 /* removable media */
#define D_ECC 0x02 /* supports ECC */
#define D_BADSECT 0x04 /* supports bad sector forw. */
#define D_RAMDISK 0x08 /* disk emulator */
#define D_CHAIN 0x10 /* can do back-back transfers */
/*
* Drive data for SMD.
*/
#define d_smdflags d_drivedata[0]
#define D_SSE 0x1 /* supports skip sectoring */
#define d_mindist d_drivedata[1]
#define d_maxdist d_drivedata[2]
#define d_sdist d_drivedata[3]
/*
* Drive data for ST506.
*/
#define d_precompcyl d_drivedata[0]
#define d_gap3 d_drivedata[1] /* used only when formatting */
/*
* Drive data for SCSI.
*/
#define d_blind d_drivedata[0]
#ifndef LOCORE
/*
* Structure used to perform a format
* or other raw operation, returning data
* and/or register values.
* Register identification and format
* are device- and driver-dependent.
*/
struct format_op {
char *df_buf;
int df_count; /* value-result */
daddr_t df_startblk;
int df_reg[8]; /* result */
};
/*
* Structure used internally to retrieve
* information about a partition on a disk.
*/
struct partinfo {
struct disklabel *disklab;
struct partition *part;
};
/*
* Disk-specific ioctls.
*/
/* get and set disklabel; DIOCGPART used internally */
#define DIOCGDINFO _IOR('d', 101, struct disklabel) /* get */
#define DIOCSDINFO _IOW('d', 102, struct disklabel) /* set */
#define DIOCWDINFO _IOW('d', 103, struct disklabel) /* set, update disk */
#define DIOCGPART _IOW('d', 104, struct partinfo) /* get partition */
/* do format operation, read or write */
#define DIOCRFORMAT _IOWR('d', 105, struct format_op)
#define DIOCWFORMAT _IOWR('d', 106, struct format_op)
#define DIOCSSTEP _IOW('d', 107, int) /* set step rate */
#define DIOCSRETRIES _IOW('d', 108, int) /* set # of retries */
#define DIOCWLABEL _IOW('d', 109, int) /* write en/disable label */
#define DIOCSBAD _IOW('d', 110, struct dkbad) /* set kernel dkbad */
#endif LOCORE
.Ed
.Sh SEE ALSO
.Xr disktab 5 ,
.Xr disklabel 8
.Sh HISTORY
The
.Nm disklabel
function was introduced in
.Bx 4.3 Tahoe .

1315
sbin/disklabel/disklabel.c Normal file

File diff suppressed because it is too large Load Diff

69
sbin/fastboot/fastboot.8 Normal file
View File

@ -0,0 +1,69 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)fastboot.8 8.1 (Berkeley) 6/5/93
.\"
.Dd June 5, 1993
.Dt FASTBOOT 8
.Os BSD 4.2
.Sh NAME
.Nm fastboot ,
.Nm fasthalt
.Nd "reboot/halt the system without checking the disks"
.Sh SYNOPSIS
.Nm fastboot
.Op Ar boot-options
.Nm fasthalt
.Op Ar halt-options
.Sh DESCRIPTION
.Nm Fastboot
and
.Nm fasthalt
are shell scripts which reboot and halt the system without
checking the file systems. This is done by creating a
file
.Pa /fastboot ,
then invoking the
.Xr reboot
program. The system startup script,
.Pa /etc/rc ,
looks for this file and, if present, skips the normal
invocation of
.Xr fsck 8 .
.Sh SEE ALSO
.Xr halt 8 ,
.Xr reboot 8 ,
.Xr rc 8
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

277
sbin/ifconfig/ifconfig.8 Normal file
View File

@ -0,0 +1,277 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94
.\"
.Dd June 1, 1994
.Dt IFCONFIG 8
.Os BSD 4.2
.Sh NAME
.Nm ifconfig
.Nd configure network interface parameters
.Sh SYNOPSIS
.Nm ifconfig
.Ar interface address_family
.Oo
.Ar address
.Op Ar dest_address
.Oc
.Op Ar parameters
.Nm ifconfig
.Ar interface
.Op Ar protocol_family
.Sh DESCRIPTION
.Nm Ifconfig
is used to assign an address
to a network interface and/or configure
network interface parameters.
.Nm Ifconfig
must be used at boot time to define the network address
of each interface present on a machine; it may also be used at
a later time to redefine an interface's address
or other operating parameters.
.Pp
Available operands for
.Nm ifconfig:
.Bl -tag -width Ds
.It Ar Address
For the
.Tn DARPA-Internet
family,
the address is either a host name present in the host name data
base,
.Xr hosts 5 ,
or a
.Tn DARPA
Internet address expressed in the Internet standard
.Dq dot notation .
For the Xerox Network Systems(tm) family,
addresses are
.Ar net:a.b.c.d.e.f ,
where
.Ar net
is the assigned network number (in decimal),
and each of the six bytes of the host number,
.Ar a
through
.Ar f ,
are specified in hexadecimal.
The host number may be omitted on 10Mb/s Ethernet interfaces,
which use the hardware physical address,
and on interfaces other than the first.
For the
.Tn ISO
family, addresses are specified as a long hexadecimal string,
as in the Xerox family. However, two consecutive dots imply a zero
byte, and the dots are optional, if the user wishes to (carefully)
count out long strings of digits in network byte order.
.It Ar address_family
Specifies the
.Ar address family
which affects interpretation of the remaining parameters.
Since an interface can receive transmissions in differing protocols
with different naming schemes, specifying the address family is recommeded.
The address or protocol families currently
supported are
.Dq inet ,
.Dq iso ,
and
.Dq ns .
.It Ar Interface
The
.Ar interface
parameter is a string of the form
.Dq name unit ,
for example,
.Dq en0
.El
.Pp
The following parameters may be set with
.Nm ifconfig :
.Bl -tag -width dest_addressxx
.It Cm alias
Establish an additional network address for this interface.
This is sometimes useful when changing network numbers, and
one wishes to accept packets addressed to the old interface.
.It Cm arp
Enable the use of the Address Resolution Protocol in mapping
between network level addresses and link level addresses (default).
This is currently implemented for mapping between
.Tn DARPA
Internet
addresses and 10Mb/s Ethernet addresses.
.It Fl arp
Disable the use of the Address Resolution Protocol.
.It Cm broadcast
(Inet only)
Specify the address to use to represent broadcasts to the
network.
The default broadcast address is the address with a host part of all 1's.
.It Cm debug
Enable driver dependent debugging code; usually, this turns on
extra console error logging.
.It Fl debug
Disable driver dependent debugging code.
.ne 1i
.It Cm delete
Remove the network address specified.
This would be used if you incorrectly specified an alias, or it
was no longer needed.
If you have incorrectly set an NS address having the side effect
of specifying the host portion, removing all NS addresses will
allow you to respecify the host portion.
.It Cm dest_address
Specify the address of the correspondent on the other end
of a point to point link.
.It Cm down
Mark an interface ``down''. When an interface is
marked ``down'', the system will not attempt to
transmit messages through that interface.
If possible, the interface will be reset to disable reception as well.
This action does not automatically disable routes using the interface.
.It Cm ipdst
This is used to specify an Internet host who is willing to receive
ip packets encapsulating NS packets bound for a remote network.
An apparent point to point link is constructed, and
the address specified will be taken as the NS address and network
of the destination.
IP encapsulation of
.Tn CLNP
packets is done differently.
.It Cm metric Ar n
Set the routing metric of the interface to
.Ar n ,
default 0.
The routing metric is used by the routing protocol
.Pq Xr routed 8 .
Higher metrics have the effect of making a route
less favorable; metrics are counted as addition hops
to the destination network or host.
.It Cm netmask Ar mask
(Inet and ISO)
Specify how much of the address to reserve for subdividing
networks into sub-networks.
The mask includes the network part of the local address
and the subnet part, which is taken from the host field of the address.
The mask can be specified as a single hexadecimal number
with a leading 0x, with a dot-notation Internet address,
or with a pseudo-network name listed in the network table
.Xr networks 5 .
The mask contains 1's for the bit positions in the 32-bit address
which are to be used for the network and subnet parts,
and 0's for the host part.
The mask should contain at least the standard network portion,
and the subnet field should be contiguous with the network
portion.
.\" see
.\" Xr eon 5 .
.It Cm nsellength Ar n
.Pf ( Tn ISO
only)
This specifies a trailing number of bytes for a received
.Tn NSAP
used for local identification, the remaining leading part of which is
taken to be the
.Tn NET
(Network Entity Title).
The default value is 1, which is conformant to US
.Tn GOSIP .
When an ISO address is set in an ifconfig command,
it is really the
.Tn NSAP
which is being specified.
For example, in
.Tn US GOSIP ,
20 hex digits should be
specified in the
.Tn ISO NSAP
to be assigned to the interface.
There is some evidence that a number different from 1 may be useful
for
.Tn AFI
37 type addresses.
.It Cm trailers
Request the use of a ``trailer'' link level encapsulation when
sending (default).
If a network interface supports
.Cm trailers ,
the system will, when possible, encapsulate outgoing
messages in a manner which minimizes the number of
memory to memory copy operations performed by the receiver.
On networks that support the Address Resolution Protocol (see
.Xr arp 4 ;
currently, only 10 Mb/s Ethernet),
this flag indicates that the system should request that other
systems use trailers when sending to this host.
Similarly, trailer encapsulations will be sent to other
hosts that have made such requests.
Currently used by Internet protocols only.
.It Fl trailers
Disable the use of a ``trailer'' link level encapsulation.
.It Cm link[0-2]
Enable special processing of the link level of the interface.
These three options are interface specific in actual effect, however,
they are in general used to select special modes of operation. An example
of this is to enable SLIP compression. Currently, only used by SLIP.
.ne 1i
.It Fl link[0-2]
Disable special processing at the link level with the specified interface.
.It Cm up
Mark an interface ``up''.
This may be used to enable an interface after an ``ifconfig down.''
It happens automatically when setting the first address on an interface.
If the interface was reset when previously marked down,
the hardware will be re-initialized.
.El
.Pp
.Pp
.Nm Ifconfig
displays the current configuration for a network interface
when no optional parameters are supplied.
If a protocol family is specified,
Ifconfig will report only the details specific to that protocol family.
.Pp
Only the super-user may modify the configuration of a network interface.
.Sh DIAGNOSTICS
Messages indicating the specified interface does not exit, the
requested address is unknown, or the user is not privileged and
tried to alter an interface's configuration.
.Sh SEE ALSO
.Xr netstat 1 ,
.Xr netintro 4 ,
.Xr rc 8 ,
.Xr routed 8 ,
.\" .Xr eon 5
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

295
sbin/init/init.8 Normal file
View File

@ -0,0 +1,295 @@
.\" Copyright (c) 1980, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" Donn Seeley at Berkeley Software Design, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)init.8 8.6 (Berkeley) 5/26/95
.\"
.Dd May 26, 1995
.Dt INIT 8
.Os BSD 4
.Sh NAME
.Nm init
.Nd process control initialization
.Sh SYNOPSIS
.Nm init
.Sh DESCRIPTION
The
.Nm init
program
is the last stage of the boot process.
It normally runs the automatic reboot sequence as described in
.Xr reboot 8 ,
and if this succeeds, begins multi-user operation.
If the reboot scripts fail,
.Nm init
commences single user operation by giving
the super-user a shell on the console.
The
.Nm init
program may be passed parameters
from the boot program to
prevent the system from going multi-user and to instead execute
a single user shell without starting the normal daemons.
The system is then quiescent for maintenance work and may
later be made to go to multi-user by exiting the
single-user shell (with ^D).
This
causes
.Nm init
to run the
.Pa /etc/rc
start up command file in fastboot mode (skipping disk checks).
.Pp
If the
.Nm console
entry in the
.Xr ttys 5
file is marked ``insecure'',
then
.Nm init
will require that the superuser password be
entered before the system will start a single-user shell.
The password check is skipped if the
.Nm console
is marked as ``secure''.
.Pp
The kernel runs with four different levels of security.
Any superuser process can raise the security level, but only
.Nm init
can lower it.
Security levels are defined as follows:
.Bl -tag -width flag
.It Ic -1
Permanently insecure mode \- always run system in level 0 mode.
.It Ic 0
Insecure mode \- immutable and append-only flags may be turned off.
All devices may be read or written subject to their permissions.
.It Ic 1
Secure mode \- immutable and append-only flags may not be changed;
disks for mounted filesystems,
.Pa /dev/mem ,
and
.Pa /dev/kmem
are read-only.
The
.Xr settimeofday 2
system call can only advance the time.
.It Ic 2
Highly secure mode \- same as secure mode, plus disks are always
read-only whether mounted or not.
This level precludes tampering with filesystems by unmounting them,
but also inhibits running
.Xr newfs 8
while the system is multi-user.
.El
.Pp
Normally, the system runs in level 0 mode while single user
and in level 1 mode while multiuser.
If the level 2 mode is desired while running multiuser,
it can be set in the startup script
.Pa /etc/rc
using
.Xr sysctl 8 .
If it is desired to run the system in level 0 mode while multiuser,
the administrator must build a kernel with the variable
.Nm securelevel
defined in the file
.Pa /sys/compile/MACHINE/param.c
and initialize it to -1.
.Pp
In multi-user operation,
.Nm init
maintains
processes for the terminal ports found in the file
.Xr ttys 5 .
.Nm Init
reads this file, and executes the command found in the second field.
This command is usually
.Xr getty 8 ;
.Xr getty
opens and initializes the tty line
and
executes the
.Xr login
program.
The
.Xr login
program, when a valid user logs in,
executes a shell for that user. When this shell
dies, either because the user logged out
or an abnormal termination occurred (a signal),
the
.Nm init
program wakes up, deletes the user
from the
.Xr utmp 5
file of current users and records the logout in the
.Xr wtmp
file.
The cycle is
then restarted by
.Nm init
executing a new
.Xr getty
for the line.
.pl +1
.Pp
Line status (on, off, secure, getty, or window information)
may be changed in the
.Xr ttys
file without a reboot by sending the signal
.Dv SIGHUP
to
.Nm init
with the command
.Dq Li "kill \-s HUP 1" .
On receipt of this signal,
.Nm init
re-reads the
.Xr ttys
file.
When a line is turned off in
.Xr ttys ,
.Nm init
will send a SIGHUP signal to the controlling process
for the session associated with the line.
For any lines that were previously turned off in the
.Xr ttys
file and are now on,
.Nm init
executes a new
.Xr getty
to enable a new login.
If the getty or window field for a line is changed,
the change takes effect at the end of the current
login session (e.g., the next time
.Nm init
starts a process on the line).
If a line is commented out or deleted from
.Xr ttys ,
.Nm init
will not do anything at all to that line.
However, it will complain that the relationship between lines
in the
.Xr ttys
file and records in the
.Xr utmp
file is out of sync,
so this practice is not recommended.
.Pp
.Nm Init
will terminate multi-user operations and resume single-user mode
if sent a terminate
.Pq Dv TERM
signal, for example,
.Dq Li "kill \-s TERM 1" .
If there are processes outstanding that are deadlocked (because of
hardware or software failure),
.Xr init
will not wait for them all to die (which might take forever), but
will time out after 30 seconds and print a warning message.
.Pp
.Nm Init
will cease creating new
.Xr getty Ns 's
and allow the system to slowly die away, if it is sent a terminal stop
.Pq Dv TSTP
signal, i.e.
.Dq Li "kill \-s TSTP 1" .
A later hangup will resume full
multi-user operations, or a terminate will start a single user shell.
This hook is used by
.Xr reboot 8
and
.Xr halt 8 .
.Pp
The role of
.Nm init
is so critical that if it dies, the system will reboot itself
automatically.
If, at bootstrap time, the
.Xr init
process cannot be located, the system will panic with the message
``panic: "init died (signal %d, exit %d)''.
.Sh DIAGNOSTICS
.Bl -diag
.It "getty repeating too quickly on port %s, sleeping"
A process being started to service a line is exiting quickly
each time it is started.
This is often caused by a ringing or noisy terminal line.
.Em "Init will sleep for 10 seconds" ,
.Em "then continue trying to start the process" .
.Pp
.It "some processes would not die; ps axl advised."
A process
is hung and could not be killed when the system was shutting down.
This condition is usually caused by a process
that is stuck in a device driver because of
a persistent device error condition.
.El
.Sh FILES
.Bl -tag -width /var/log/wtmp -compact
.It Pa /dev/console
System console device.
.It Pa /dev/tty*
Terminal ports found in
.Xr ttys .
.It Pa /var/run/utmp
Record of Current users on the system.
.It Pa /var/log/wtmp
Record of all logins and logouts.
.It Pa /etc/ttys
The terminal initialization information file.
.It Pa /etc/rc
System startup commands.
.El
.Sh SEE ALSO
.Xr login 1 ,
.Xr kill 1 ,
.Xr sh 1 ,
.Xr ttys 5 ,
.Xr crash 8 ,
.Xr getty 8 ,
.Xr rc 8 ,
.Xr reboot 8 ,
.Xr halt 8 ,
.Xr shutdown 8
.Sh HISTORY
A
.Nm
command appeared in
.At v6 .
.Sh BUGS
Systems without
.Xr sysctl
behave as though they have security level \-1.

1297
sbin/init/init.c Normal file

File diff suppressed because it is too large Load Diff

328
sbin/ping/ping.8 Normal file
View File

@ -0,0 +1,328 @@
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)ping.8 8.3 (Berkeley) 4/28/95
.\"
.Dd April 28, 1995
.Dt PING 8
.Os BSD 4.3
.Sh NAME
.Nm ping
.Nd send
.Tn ICMP ECHO_REQUEST
packets to network hosts
.Sh SYNOPSIS
.Nm ping
.Op Fl Rdfnqrv
.Op Fl c Ar count
.Op Fl i Ar wait
.Op Fl l Ar preload
.Op Fl p Ar pattern
.Op Fl s Ar packetsize
.Ar host
.Sh DESCRIPTION
.Nm Ping
uses the
.Tn ICMP
protocol's mandatory
.Tn ECHO_REQUEST
datagram to elicit an
.Tn ICMP ECHO_RESPONSE
from a host or gateway.
.Tn ECHO_REQUEST
datagrams (``pings'') have an IP and
.Tn ICMP
header,
followed by a
.Dq struct timeval
and then an arbitrary number of ``pad'' bytes used to fill out the
packet.
The options are as follows:
.Bl -tag -width Ds
.It Fl c Ar count
Stop after sending (and receiving)
.Ar count
.Tn ECHO_RESPONSE
packets.
.It Fl d
Set the
.Dv SO_DEBUG
option on the socket being used.
.It Fl f
Flood ping.
Outputs packets as fast as they come back or one hundred times per second,
whichever is more.
For every
.Tn ECHO_REQUEST
sent a period ``.'' is printed, while for every
.Tn ECHO_REPLY
received a backspace is printed.
This provides a rapid display of how many packets are being dropped.
Only the super-user may use this option.
.Bf -emphasis
This can be very hard on a network and should be used with caution.
.Ef
.It Fl i Ar wait
Wait
.Ar wait
seconds
.Em between sending each packet .
The default is to wait for one second between each packet.
This option is incompatible with the
.Fl f
option.
.It Fl l Ar preload
If
.Ar preload
is specified,
.Nm ping
sends that many packets as fast as possible before falling into its normal
mode of behavior.
.It Fl n
Numeric output only.
No attempt will be made to lookup symbolic names for host addresses.
.It Fl p Ar pattern
You may specify up to 16 ``pad'' bytes to fill out the packet you send.
This is useful for diagnosing data-dependent problems in a network.
For example,
.Dq Li \-p ff
will cause the sent packet to be filled with all
ones.
.It Fl q
Quiet output.
Nothing is displayed except the summary lines at startup time and
when finished.
.It Fl R
Record route.
Includes the
.Tn RECORD_ROUTE
option in the
.Tn ECHO_REQUEST
packet and displays
the route buffer on returned packets.
Note that the IP header is only large enough for nine such routes.
Many hosts ignore or discard this option.
.It Fl r
Bypass the normal routing tables and send directly to a host on an attached
network.
If the host is not on a directly-attached network, an error is returned.
This option can be used to ping a local host through an interface
that has no route through it (e.g., after the interface was dropped by
.Xr routed 8 ) .
.It Fl s Ar packetsize
Specifies the number of data bytes to be sent.
The default is 56, which translates into 64
.Tn ICMP
data bytes when combined
with the 8 bytes of
.Tn ICMP
header data.
.It Fl v
Verbose output.
.Tn ICMP
packets other than
.Tn ECHO_RESPONSE
that are received are listed.
.El
.Pp
When using
.Nm ping
for fault isolation, it should first be run on the local host, to verify
that the local network interface is up and running.
Then, hosts and gateways further and further away should be ``pinged''.
Round-trip times and packet loss statistics are computed.
If duplicate packets are received, they are not included in the packet
loss calculation, although the round trip time of these packets is used
in calculating the minimum/average/maximum round-trip time numbers.
When the specified number of packets have been sent (and received) or
if the program is terminated with a
.Dv SIGINT ,
a brief summary is displayed.
.Pp
This program is intended for use in network testing, measurement and
management.
Because of the load it can impose on the network, it is unwise to use
.Nm ping
during normal operations or from automated scripts.
.Sh ICMP PACKET DETAILS
An IP header without options is 20 bytes.
An
.Tn ICMP
.Tn ECHO_REQUEST
packet contains an additional 8 bytes worth
of
.Tn ICMP
header followed by an arbitrary amount of data.
When a
.Ar packetsize
is given, this indicated the size of this extra piece of data (the
default is 56).
Thus the amount of data received inside of an IP packet of type
.Tn ICMP
.Tn ECHO_REPLY
will always be 8 bytes more than the requested data space
(the
.Tn ICMP
header).
.Pp
If the data space is at least eight bytes large,
.Nm ping
uses the first eight bytes of this space to include a timestamp which
it uses in the computation of round trip times.
If less than eight bytes of pad are specified, no round trip times are
given.
.Sh DUPLICATE AND DAMAGED PACKETS
.Nm Ping
will report duplicate and damaged packets.
Duplicate packets should never occur, and seem to be caused by
inappropriate link-level retransmissions.
Duplicates may occur in many situations and are rarely (if ever) a
good sign, although the presence of low levels of duplicates may not
always be cause for alarm.
.Pp
Damaged packets are obviously serious cause for alarm and often
indicate broken hardware somewhere in the
.Nm ping
packet's path (in the network or in the hosts).
.Sh TRYING DIFFERENT DATA PATTERNS
The (inter)network layer should never treat packets differently depending
on the data contained in the data portion.
Unfortunately, data-dependent problems have been known to sneak into
networks and remain undetected for long periods of time.
In many cases the particular pattern that will have problems is something
that doesn't have sufficient ``transitions'', such as all ones or all
zeros, or a pattern right at the edge, such as almost all zeros.
It isn't necessarily enough to specify a data pattern of all zeros (for
example) on the command line because the pattern that is of interest is
at the data link level, and the relationship between what you type and
what the controllers transmit can be complicated.
.Pp
This means that if you have a data-dependent problem you will probably
have to do a lot of testing to find it.
If you are lucky, you may manage to find a file that either can't be sent
across your network or that takes much longer to transfer than other
similar length files.
You can then examine this file for repeated patterns that you can test
using the
.Fl p
option of
.Nm ping .
.Sh TTL DETAILS
The
.Tn TTL
value of an IP packet represents the maximum number of IP routers
that the packet can go through before being thrown away.
In current practice you can expect each router in the Internet to decrement
the
.Tn TTL
field by exactly one.
.Pp
The
.Tn TCP/IP
specification states that the
.Tn TTL
field for
.Tn TCP
packets should
be set to 60, but many systems use smaller values (4.3
.Tn BSD
uses 30, 4.2 used
15).
.Pp
The maximum possible value of this field is 255, and most Unix systems set
the
.Tn TTL
field of
.Tn ICMP ECHO_REQUEST
packets to 255.
This is why you will find you can ``ping'' some hosts, but not reach them
with
.Xr telnet 1
or
.Xr ftp 1 .
.Pp
In normal operation ping prints the ttl value from the packet it receives.
When a remote system receives a ping packet, it can do one of three things
with the
.Tn TTL
field in its response:
.Bl -bullet
.It
Not change it; this is what Berkeley Unix systems did before the
.Bx 4.3 tahoe
release.
In this case the
.Tn TTL
value in the received packet will be 255 minus the
number of routers in the round-trip path.
.It
Set it to 255; this is what current Berkeley Unix systems do.
In this case the
.Tn TTL
value in the received packet will be 255 minus the
number of routers in the path
.Xr from
the remote system
.Em to
the
.Nm ping Ns Em ing
host.
.It
Set it to some other value.
Some machines use the same value for
.Tn ICMP
packets that they use for
.Tn TCP
packets, for example either 30 or 60.
Others may use completely wild values.
.El
.Sh BUGS
Many Hosts and Gateways ignore the
.Tn RECORD_ROUTE
option.
.Pp
The maximum IP header length is too small for options like
.Tn RECORD_ROUTE
to
be completely useful.
There's not much that that can be done about this, however.
.Pp
Flood pinging is not recommended in general, and flood pinging the
broadcast address should only be done under very controlled conditions.
.Sh SEE ALSO
.Xr netstat 1 ,
.Xr ifconfig 8 ,
.Xr routed 8
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.3 .

986
sbin/ping/ping.c Normal file
View File

@ -0,0 +1,986 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Muuss.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1989, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)ping.c 8.3 (Berkeley) 4/28/95";
#endif /* not lint */
/*
* P I N G . C
*
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
* measure round-trip-delays and packet loss across network paths.
*
* Author -
* Mike Muuss
* U. S. Army Ballistic Research Laboratory
* December, 1983
*
* Status -
* Public Domain. Distribution Unlimited.
* Bugs -
* More statistics could always be gathered.
* This program has to run SUID to ROOT to access the ICMP socket.
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <netdb.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#define DEFDATALEN (64 - 8) /* default data length */
#define MAXIPLEN 60
#define MAXICMPLEN 76
#define MAXPACKET (65536 - 60 - 8)/* max packet size */
#define MAXWAIT 10 /* max seconds to wait for response */
#define NROUTES 9 /* number of record route slots */
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
#define SET(bit) (A(bit) |= B(bit))
#define CLR(bit) (A(bit) &= (~B(bit)))
#define TST(bit) (A(bit) & B(bit))
/* various options */
int options;
#define F_FLOOD 0x001
#define F_INTERVAL 0x002
#define F_NUMERIC 0x004
#define F_PINGFILLED 0x008
#define F_QUIET 0x010
#define F_RROUTE 0x020
#define F_SO_DEBUG 0x040
#define F_SO_DONTROUTE 0x080
#define F_VERBOSE 0x100
/*
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
* number of received sequence numbers we can keep track of. Change 128
* to 8192 for complete accuracy...
*/
#define MAX_DUP_CHK (8 * 128)
int mx_dup_ck = MAX_DUP_CHK;
char rcvd_tbl[MAX_DUP_CHK / 8];
struct sockaddr whereto; /* who to ping */
int datalen = DEFDATALEN;
int s; /* socket file descriptor */
u_char outpack[MAXPACKET];
char BSPACE = '\b'; /* characters written for flood */
char DOT = '.';
char *hostname;
int ident; /* process id to identify our packets */
/* counters */
long npackets; /* max packets to transmit */
long nreceived; /* # of packets we got back */
long nrepeats; /* number of duplicates */
long ntransmitted; /* sequence # for outbound packets = #sent */
int interval = 1; /* interval between packets */
/* timing */
int timing; /* flag to do timing */
double tmin = 999999999.0; /* minimum round trip time */
double tmax = 0.0; /* maximum round trip time */
double tsum = 0.0; /* sum of all times, for doing average */
char *pr_addr();
void catcher(), finish();
main(argc, argv)
int argc;
char **argv;
{
extern int errno, optind;
extern char *optarg;
struct timeval timeout;
struct hostent *hp;
struct sockaddr_in *to;
struct protoent *proto;
register int i;
int ch, fdmask, hold, packlen, preload;
u_char *datap, *packet;
char *target, hnamebuf[MAXHOSTNAMELEN], *malloc();
#ifdef IP_OPTIONS
char rspace[3 + 4 * NROUTES + 1]; /* record route space */
#endif
preload = 0;
datap = &outpack[8 + sizeof(struct timeval)];
while ((ch = getopt(argc, argv, "Rc:dfh:i:l:np:qrs:v")) != EOF)
switch(ch) {
case 'c':
npackets = atoi(optarg);
if (npackets <= 0) {
(void)fprintf(stderr,
"ping: bad number of packets to transmit.\n");
exit(1);
}
break;
case 'd':
options |= F_SO_DEBUG;
break;
case 'f':
if (getuid()) {
(void)fprintf(stderr,
"ping: %s\n", strerror(EPERM));
exit(1);
}
options |= F_FLOOD;
setbuf(stdout, (char *)NULL);
break;
case 'i': /* wait between sending packets */
interval = atoi(optarg);
if (interval <= 0) {
(void)fprintf(stderr,
"ping: bad timing interval.\n");
exit(1);
}
options |= F_INTERVAL;
break;
case 'l':
preload = atoi(optarg);
if (preload < 0) {
(void)fprintf(stderr,
"ping: bad preload value.\n");
exit(1);
}
break;
case 'n':
options |= F_NUMERIC;
break;
case 'p': /* fill buffer with user pattern */
options |= F_PINGFILLED;
fill((char *)datap, optarg);
break;
case 'q':
options |= F_QUIET;
break;
case 'R':
options |= F_RROUTE;
break;
case 'r':
options |= F_SO_DONTROUTE;
break;
case 's': /* size of packet to send */
datalen = atoi(optarg);
if (datalen > MAXPACKET) {
(void)fprintf(stderr,
"ping: packet size too large.\n");
exit(1);
}
if (datalen <= 0) {
(void)fprintf(stderr,
"ping: illegal packet size.\n");
exit(1);
}
break;
case 'v':
options |= F_VERBOSE;
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
target = *argv;
memset(&whereto, 0, sizeof(struct sockaddr));
to = (struct sockaddr_in *)&whereto;
to->sin_family = AF_INET;
to->sin_addr.s_addr = inet_addr(target);
if (to->sin_addr.s_addr != (u_int)-1)
hostname = target;
else {
hp = gethostbyname(target);
if (!hp) {
(void)fprintf(stderr,
"ping: unknown host %s\n", target);
exit(1);
}
to->sin_family = hp->h_addrtype;
memmove(&to->sin_addr, hp->h_addr, hp->h_length);
(void)strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1);
hostname = hnamebuf;
}
if (options & F_FLOOD && options & F_INTERVAL) {
(void)fprintf(stderr,
"ping: -f and -i incompatible options.\n");
exit(1);
}
if (datalen >= sizeof(struct timeval)) /* can we time transfer */
timing = 1;
packlen = datalen + MAXIPLEN + MAXICMPLEN;
if (!(packet = (u_char *)malloc((u_int)packlen))) {
(void)fprintf(stderr, "ping: out of memory.\n");
exit(1);
}
if (!(options & F_PINGFILLED))
for (i = 8; i < datalen; ++i)
*datap++ = i;
ident = getpid() & 0xFFFF;
if (!(proto = getprotobyname("icmp"))) {
(void)fprintf(stderr, "ping: unknown protocol icmp.\n");
exit(1);
}
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
perror("ping: socket");
exit(1);
}
hold = 1;
if (options & F_SO_DEBUG)
(void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
sizeof(hold));
if (options & F_SO_DONTROUTE)
(void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
sizeof(hold));
/* record route option */
if (options & F_RROUTE) {
#ifdef IP_OPTIONS
rspace[IPOPT_OPTVAL] = IPOPT_RR;
rspace[IPOPT_OLEN] = sizeof(rspace)-1;
rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
sizeof(rspace)) < 0) {
perror("ping: record route");
exit(1);
}
#else
(void)fprintf(stderr,
"ping: record route not available in this implementation.\n");
exit(1);
#endif /* IP_OPTIONS */
}
/*
* When pinging the broadcast address, you can get a lot of answers.
* Doing something so evil is useful if you are trying to stress the
* ethernet, or just want to fill the arp cache to get some stuff for
* /etc/ethers.
*/
hold = 48 * 1024;
(void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
sizeof(hold));
if (to->sin_family == AF_INET)
(void)printf("PING %s (%s): %d data bytes\n", hostname,
inet_ntoa(*(struct in_addr *)&to->sin_addr.s_addr),
datalen);
else
(void)printf("PING %s: %d data bytes\n", hostname, datalen);
(void)signal(SIGINT, finish);
(void)signal(SIGALRM, catcher);
while (preload--) /* fire off them quickies */
pinger();
if ((options & F_FLOOD) == 0)
catcher(); /* start things going */
for (;;) {
struct sockaddr_in from;
register int cc;
int fromlen;
if (options & F_FLOOD) {
pinger();
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
fdmask = 1 << s;
if (select(s + 1, (fd_set *)&fdmask, (fd_set *)NULL,
(fd_set *)NULL, &timeout) < 1)
continue;
}
fromlen = sizeof(from);
if ((cc = recvfrom(s, (char *)packet, packlen, 0,
(struct sockaddr *)&from, &fromlen)) < 0) {
if (errno == EINTR)
continue;
perror("ping: recvfrom");
continue;
}
pr_pack((char *)packet, cc, &from);
if (npackets && nreceived >= npackets)
break;
}
finish();
/* NOTREACHED */
}
/*
* catcher --
* This routine causes another PING to be transmitted, and then
* schedules another SIGALRM for 1 second from now.
*
* bug --
* Our sense of time will slowly skew (i.e., packets will not be
* launched exactly at 1-second intervals). This does not affect the
* quality of the delay and loss statistics.
*/
void
catcher()
{
int waittime;
pinger();
(void)signal(SIGALRM, catcher);
if (!npackets || ntransmitted < npackets)
alarm((u_int)interval);
else {
if (nreceived) {
waittime = 2 * tmax / 1000;
if (!waittime)
waittime = 1;
} else
waittime = MAXWAIT;
(void)signal(SIGALRM, finish);
(void)alarm((u_int)waittime);
}
}
/*
* pinger --
* Compose and transmit an ICMP ECHO REQUEST packet. The IP packet
* will be added on by the kernel. The ID field is our UNIX process ID,
* and the sequence number is an ascending integer. The first 8 bytes
* of the data portion are used to hold a UNIX "timeval" struct in VAX
* byte-order, to compute the round-trip time.
*/
pinger()
{
register struct icmp *icp;
register int cc;
int i;
icp = (struct icmp *)outpack;
icp->icmp_type = ICMP_ECHO;
icp->icmp_code = 0;
icp->icmp_cksum = 0;
icp->icmp_seq = ntransmitted++;
icp->icmp_id = ident; /* ID */
CLR(icp->icmp_seq % mx_dup_ck);
if (timing)
(void)gettimeofday((struct timeval *)&outpack[8],
(struct timezone *)NULL);
cc = datalen + 8; /* skips ICMP portion */
/* compute ICMP checksum here */
icp->icmp_cksum = in_cksum((u_short *)icp, cc);
i = sendto(s, (char *)outpack, cc, 0, &whereto,
sizeof(struct sockaddr));
if (i < 0 || i != cc) {
if (i < 0)
perror("ping: sendto");
(void)printf("ping: wrote %s %d chars, ret=%d\n",
hostname, cc, i);
}
if (!(options & F_QUIET) && options & F_FLOOD)
(void)write(STDOUT_FILENO, &DOT, 1);
}
/*
* pr_pack --
* Print out the packet, if it came from us. This logic is necessary
* because ALL readers of the ICMP socket get a copy of ALL ICMP packets
* which arrive ('tis only fair). This permits multiple copies of this
* program to be run without having intermingled output (or statistics!).
*/
pr_pack(buf, cc, from)
char *buf;
int cc;
struct sockaddr_in *from;
{
register struct icmp *icp;
register u_long l;
register int i, j;
register u_char *cp,*dp;
static int old_rrlen;
static char old_rr[MAX_IPOPTLEN];
struct ip *ip;
struct timeval tv, *tp;
double triptime;
int hlen, dupflag;
(void)gettimeofday(&tv, (struct timezone *)NULL);
/* Check the IP header */
ip = (struct ip *)buf;
hlen = ip->ip_hl << 2;
if (cc < hlen + ICMP_MINLEN) {
if (options & F_VERBOSE)
(void)fprintf(stderr,
"ping: packet too short (%d bytes) from %s\n", cc,
inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr));
return;
}
/* Now the ICMP part */
cc -= hlen;
icp = (struct icmp *)(buf + hlen);
if (icp->icmp_type == ICMP_ECHOREPLY) {
if (icp->icmp_id != ident)
return; /* 'Twas not our ECHO */
++nreceived;
if (timing) {
#ifndef icmp_data
tp = (struct timeval *)&icp->icmp_ip;
#else
tp = (struct timeval *)icp->icmp_data;
#endif
tvsub(&tv, tp);
triptime = ((double)tv.tv_sec) * 1000.0 +
((double)tv.tv_usec) / 1000.0;
tsum += triptime;
if (triptime < tmin)
tmin = triptime;
if (triptime > tmax)
tmax = triptime;
}
if (TST(icp->icmp_seq % mx_dup_ck)) {
++nrepeats;
--nreceived;
dupflag = 1;
} else {
SET(icp->icmp_seq % mx_dup_ck);
dupflag = 0;
}
if (options & F_QUIET)
return;
if (options & F_FLOOD)
(void)write(STDOUT_FILENO, &BSPACE, 1);
else {
(void)printf("%d bytes from %s: icmp_seq=%u", cc,
inet_ntoa(*(struct in_addr *)&from->sin_addr.s_addr),
icp->icmp_seq);
(void)printf(" ttl=%d", ip->ip_ttl);
if (timing)
(void)printf(" time=%g ms", triptime);
if (dupflag)
(void)printf(" (DUP!)");
/* check the data */
cp = (u_char*)&icp->icmp_data[8];
dp = &outpack[8 + sizeof(struct timeval)];
for (i = 8; i < datalen; ++i, ++cp, ++dp) {
if (*cp != *dp) {
(void)printf("\nwrong data byte #%d should be 0x%x but was 0x%x",
i, *dp, *cp);
cp = (u_char*)&icp->icmp_data[0];
for (i = 8; i < datalen; ++i, ++cp) {
if ((i % 32) == 8)
(void)printf("\n\t");
(void)printf("%x ", *cp);
}
break;
}
}
}
} else {
/* We've got something other than an ECHOREPLY */
if (!(options & F_VERBOSE))
return;
(void)printf("%d bytes from %s: ", cc,
pr_addr(from->sin_addr.s_addr));
pr_icmph(icp);
}
/* Display any IP options */
cp = (u_char *)buf + sizeof(struct ip);
for (; hlen > (int)sizeof(struct ip); --hlen, ++cp)
switch (*cp) {
case IPOPT_EOL:
hlen = 0;
break;
case IPOPT_LSRR:
(void)printf("\nLSRR: ");
hlen -= 2;
j = *++cp;
++cp;
if (j > IPOPT_MINOFF)
for (;;) {
l = *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
if (l == 0)
(void)printf("\t0.0.0.0");
else
(void)printf("\t%s", pr_addr(ntohl(l)));
hlen -= 4;
j -= 4;
if (j <= IPOPT_MINOFF)
break;
(void)putchar('\n');
}
break;
case IPOPT_RR:
j = *++cp; /* get length */
i = *++cp; /* and pointer */
hlen -= 2;
if (i > j)
i = j;
i -= IPOPT_MINOFF;
if (i <= 0)
continue;
if (i == old_rrlen
&& cp == (u_char *)buf + sizeof(struct ip) + 2
&& !memcmp(cp, old_rr, i)
&& !(options & F_FLOOD)) {
(void)printf("\t(same route)");
i = ((i + 3) / 4) * 4;
hlen -= i;
cp += i;
break;
}
old_rrlen = i;
memmove(old_rr, cp, i);
(void)printf("\nRR: ");
for (;;) {
l = *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
l = (l<<8) + *++cp;
if (l == 0)
(void)printf("\t0.0.0.0");
else
(void)printf("\t%s", pr_addr(ntohl(l)));
hlen -= 4;
i -= 4;
if (i <= 0)
break;
(void)putchar('\n');
}
break;
case IPOPT_NOP:
(void)printf("\nNOP");
break;
default:
(void)printf("\nunknown option %x", *cp);
break;
}
if (!(options & F_FLOOD)) {
(void)putchar('\n');
(void)fflush(stdout);
}
}
/*
* in_cksum --
* Checksum routine for Internet Protocol family headers (C Version)
*/
in_cksum(addr, len)
u_short *addr;
int len;
{
register int nleft = len;
register u_short *w = addr;
register int sum = 0;
u_short answer = 0;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
/*
* tvsub --
* Subtract 2 timeval structs: out = out - in. Out is assumed to
* be >= in.
*/
tvsub(out, in)
register struct timeval *out, *in;
{
if ((out->tv_usec -= in->tv_usec) < 0) {
--out->tv_sec;
out->tv_usec += 1000000;
}
out->tv_sec -= in->tv_sec;
}
/*
* finish --
* Print out statistics, and give up.
*/
void
finish()
{
register int i;
(void)signal(SIGINT, SIG_IGN);
(void)putchar('\n');
(void)fflush(stdout);
(void)printf("--- %s ping statistics ---\n", hostname);
(void)printf("%ld packets transmitted, ", ntransmitted);
(void)printf("%ld packets received, ", nreceived);
if (nrepeats)
(void)printf("+%ld duplicates, ", nrepeats);
if (ntransmitted)
if (nreceived > ntransmitted)
(void)printf("-- somebody's printing up packets!");
else
(void)printf("%d%% packet loss",
(int) (((ntransmitted - nreceived) * 100) /
ntransmitted));
(void)putchar('\n');
if (nreceived && timing) {
/* Only display average to microseconds */
i = 1000.0 * tsum / (nreceived + nrepeats);
(void)printf("round-trip min/avg/max = %g/%g/%g ms\n",
tmin, ((double)i) / 1000.0, tmax);
}
exit(0);
}
#ifdef notdef
static char *ttab[] = {
"Echo Reply", /* ip + seq + udata */
"Dest Unreachable", /* net, host, proto, port, frag, sr + IP */
"Source Quench", /* IP */
"Redirect", /* redirect type, gateway, + IP */
"Echo",
"Time Exceeded", /* transit, frag reassem + IP */
"Parameter Problem", /* pointer + IP */
"Timestamp", /* id + seq + three timestamps */
"Timestamp Reply", /* " */
"Info Request", /* id + sq */
"Info Reply" /* " */
};
#endif
/*
* pr_icmph --
* Print a descriptive string about an ICMP header.
*/
pr_icmph(icp)
struct icmp *icp;
{
switch(icp->icmp_type) {
case ICMP_ECHOREPLY:
(void)printf("Echo Reply\n");
/* XXX ID + Seq + Data */
break;
case ICMP_UNREACH:
switch(icp->icmp_code) {
case ICMP_UNREACH_NET:
(void)printf("Destination Net Unreachable\n");
break;
case ICMP_UNREACH_HOST:
(void)printf("Destination Host Unreachable\n");
break;
case ICMP_UNREACH_PROTOCOL:
(void)printf("Destination Protocol Unreachable\n");
break;
case ICMP_UNREACH_PORT:
(void)printf("Destination Port Unreachable\n");
break;
case ICMP_UNREACH_NEEDFRAG:
(void)printf("frag needed and DF set\n");
break;
case ICMP_UNREACH_SRCFAIL:
(void)printf("Source Route Failed\n");
break;
default:
(void)printf("Dest Unreachable, Bad Code: %d\n",
icp->icmp_code);
break;
}
/* Print returned IP header information */
#ifndef icmp_data
pr_retip(&icp->icmp_ip);
#else
pr_retip((struct ip *)icp->icmp_data);
#endif
break;
case ICMP_SOURCEQUENCH:
(void)printf("Source Quench\n");
#ifndef icmp_data
pr_retip(&icp->icmp_ip);
#else
pr_retip((struct ip *)icp->icmp_data);
#endif
break;
case ICMP_REDIRECT:
switch(icp->icmp_code) {
case ICMP_REDIRECT_NET:
(void)printf("Redirect Network");
break;
case ICMP_REDIRECT_HOST:
(void)printf("Redirect Host");
break;
case ICMP_REDIRECT_TOSNET:
(void)printf("Redirect Type of Service and Network");
break;
case ICMP_REDIRECT_TOSHOST:
(void)printf("Redirect Type of Service and Host");
break;
default:
(void)printf("Redirect, Bad Code: %d", icp->icmp_code);
break;
}
(void)printf("(New addr: 0x%08lx)\n", icp->icmp_gwaddr.s_addr);
#ifndef icmp_data
pr_retip(&icp->icmp_ip);
#else
pr_retip((struct ip *)icp->icmp_data);
#endif
break;
case ICMP_ECHO:
(void)printf("Echo Request\n");
/* XXX ID + Seq + Data */
break;
case ICMP_TIMXCEED:
switch(icp->icmp_code) {
case ICMP_TIMXCEED_INTRANS:
(void)printf("Time to live exceeded\n");
break;
case ICMP_TIMXCEED_REASS:
(void)printf("Frag reassembly time exceeded\n");
break;
default:
(void)printf("Time exceeded, Bad Code: %d\n",
icp->icmp_code);
break;
}
#ifndef icmp_data
pr_retip(&icp->icmp_ip);
#else
pr_retip((struct ip *)icp->icmp_data);
#endif
break;
case ICMP_PARAMPROB:
(void)printf("Parameter problem: pointer = 0x%02x\n",
icp->icmp_hun.ih_pptr);
#ifndef icmp_data
pr_retip(&icp->icmp_ip);
#else
pr_retip((struct ip *)icp->icmp_data);
#endif
break;
case ICMP_TSTAMP:
(void)printf("Timestamp\n");
/* XXX ID + Seq + 3 timestamps */
break;
case ICMP_TSTAMPREPLY:
(void)printf("Timestamp Reply\n");
/* XXX ID + Seq + 3 timestamps */
break;
case ICMP_IREQ:
(void)printf("Information Request\n");
/* XXX ID + Seq */
break;
case ICMP_IREQREPLY:
(void)printf("Information Reply\n");
/* XXX ID + Seq */
break;
#ifdef ICMP_MASKREQ
case ICMP_MASKREQ:
(void)printf("Address Mask Request\n");
break;
#endif
#ifdef ICMP_MASKREPLY
case ICMP_MASKREPLY:
(void)printf("Address Mask Reply\n");
break;
#endif
default:
(void)printf("Bad ICMP type: %d\n", icp->icmp_type);
}
}
/*
* pr_iph --
* Print an IP header with options.
*/
pr_iph(ip)
struct ip *ip;
{
int hlen;
u_char *cp;
hlen = ip->ip_hl << 2;
cp = (u_char *)ip + 20; /* point to options */
(void)printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
(void)printf(" %1x %1x %02x %04x %04x",
ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
(void)printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
(ip->ip_off) & 0x1fff);
(void)printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
(void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
(void)printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
/* dump and option bytes */
while (hlen-- > 20) {
(void)printf("%02x", *cp++);
}
(void)putchar('\n');
}
/*
* pr_addr --
* Return an ascii host address as a dotted quad and optionally with
* a hostname.
*/
char *
pr_addr(l)
u_long l;
{
struct hostent *hp;
static char buf[80];
if ((options & F_NUMERIC) ||
!(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
(void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
else
(void)sprintf(buf, "%s (%s)", hp->h_name,
inet_ntoa(*(struct in_addr *)&l));
return(buf);
}
/*
* pr_retip --
* Dump some info on a returned (via ICMP) IP packet.
*/
pr_retip(ip)
struct ip *ip;
{
int hlen;
u_char *cp;
pr_iph(ip);
hlen = ip->ip_hl << 2;
cp = (u_char *)ip + hlen;
if (ip->ip_p == 6)
(void)printf("TCP: from port %u, to port %u (decimal)\n",
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
else if (ip->ip_p == 17)
(void)printf("UDP: from port %u, to port %u (decimal)\n",
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
}
fill(bp, patp)
char *bp, *patp;
{
register int ii, jj, kk;
int pat[16];
char *cp;
for (cp = patp; *cp; cp++)
if (!isxdigit(*cp)) {
(void)fprintf(stderr,
"ping: patterns must be specified as hex digits.\n");
exit(1);
}
ii = sscanf(patp,
"%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x",
&pat[0], &pat[1], &pat[2], &pat[3], &pat[4], &pat[5], &pat[6],
&pat[7], &pat[8], &pat[9], &pat[10], &pat[11], &pat[12],
&pat[13], &pat[14], &pat[15]);
if (ii > 0)
for (kk = 0;
kk <= MAXPACKET - (8 + sizeof(struct timeval) + ii);
kk += ii)
for (jj = 0; jj < ii; ++jj)
bp[jj + kk] = pat[jj];
if (!(options & F_QUIET)) {
(void)printf("PATTERN: 0x");
for (jj = 0; jj < ii; ++jj)
(void)printf("%02x", bp[jj] & 0xFF);
(void)printf("\n");
}
}
usage()
{
(void)fprintf(stderr,
"usage: ping [-Rdfnqrv] [-c count] [-i wait] [-l preload]\n\t[-p pattern] [-s packetsize] host\n");
exit(1);
}

175
sbin/route/ccitt_addr.c Normal file
View File

@ -0,0 +1,175 @@
/*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ccitt_addr.c 8.2 (Berkeley) 4/28/95
*/
/*
* parse CCITT addresses
*
* Addresses must have the format: [hpr],x121address[,userdata][,protocol]
* items enclosed with square brackets are optional
* 'h' or 'p' means hi priority (packet size = 128; specific to Datapac
* and necessary only for X.25(76) and non-negotiating X.25(80) DTE's)
* 'r' means reverse charge (remote DTE pays for call).
* The x121address consists of an optional netid and dot, followed
* by a dte address.
*
* Frank Pronk
* The University of British Columbia
* Laboratory for Computational Vision
* Copyright (c) 1984
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netccitt/x25.h>
static char *copychar ();
ccitt_addr (addr, xp)
char *addr;
register struct sockaddr_x25 *xp;
{
register char *p, *ap, *limit;
int havenet = 0;
memset(xp, 0, sizeof (*xp));
xp->x25_family = AF_CCITT;
xp->x25_len = sizeof(*xp);
p = addr;
/*
* process optional priority and reverse charging flags
*/
if (*p == 'p' || *p == 'r' || *p == 'h') {
while (*p == 'p' || *p == 'r' || *p == 'h') {
if (*p == 'p' || *p == 'h')
xp->x25_opts.op_psize = X25_PS128;
else if (*p == 'r')
xp->x25_opts.op_flags |= X25_REVERSE_CHARGE;
p++;
}
if (*p != ',')
return (0);
p++;
}
if (*p == '\0')
return (0);
/*
* [network id:]X.121 address
*/
ap = xp->x25_addr;
limit = ap + sizeof (xp->x25_addr) - 1;
while (*p) {
if (*p == ',')
break;
if (*p == '.' || *p == ':') {
if (havenet)
return (0);
havenet++;
xp->x25_net = atoi (xp->x25_addr);
p++;
ap = xp->x25_addr;
*ap = '\0';
}
if (*p < '0' || *p > '9')
return (0);
if (ap >= limit)
return (0);
*ap++ = *p++;
}
if (*p == '\0')
return (1);
/*
* optional user data, bytes 4 to 16
*/
p++;
ap = xp->x25_udata + 4; /* first four bytes are protocol id */
limit = ap + sizeof (xp->x25_udata) - 4;
xp->x25_udlen = 4;
while (*p) {
if (*p == ',')
break;
if (ap >= limit)
return (0);
p = copychar (p, ap++);
xp->x25_udlen++;
}
if (xp->x25_udlen == 4)
xp->x25_udlen = 0;
if (*p == '\0')
return (1);
p++;
ap = xp->x25_udata; /* protocol id */
limit = ap + (xp->x25_udlen ? 4 : sizeof(xp->x25_udata));
while (*p) {
if (*p == ',')
return (0);
if (ap >= limit)
return (0);
p = copychar (p, ap++);
}
if (xp->x25_udlen == 0)
xp->x25_udlen = ap - xp->x25_udata;
return (1);
}
static char *
copychar (from, to)
register char *from, *to;
{
register int n;
if (*from != '\\' || from[1] < '0' || from[1] > '7') {
*to = *from++;
return (from);
}
n = *++from - '0';
from++;
if (*from >= '0' && *from <= '7') {
register int n1;
n = n*8 + *from++ - '0';
if (*from >= '0' && *from <= '7' && (n1 = n*8 + *from-'0') < 256) {
n = n1;
from++;
}
}
*to = n;
return (from);
}

325
sbin/route/route.8 Normal file
View File

@ -0,0 +1,325 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)route.8 8.4 (Berkeley) 6/1/94
.\"
.Dd June 1, 1994
.Dt ROUTE 8
.Os BSD 4.4
.Sh NAME
.Nm route
.Nd manually manipulate the routing tables.
.Sh SYNOPSIS
.Nm route
.Op Fl nqv
.Ar command
.Oo
.Op Ar modifiers
.Ar args
.Oc
.Sh DESCRIPTION
.Nm Route
is a utility used to manually manipulate the network
routing tables. It normally is not needed, as a
system routing table management daemon such as
.Xr routed 8 ,
should tend to this task.
.Pp
The
.Nm route :
utility supports a limited number of general options,
but a rich command language, enabling the user to specify
any arbitrary request that could be delivered via the
programmatic interface discussed in
.Xr route 4 .
.Pp
.Bl -tag -width Ds
.It Fl n
Bypasses attempts to print host and network names symbolically
when reporting actions. (The process of translating between symbolic
names and numerical equivalents can be quite time consuming, and
may require correct operation of the network; thus it may be expedient
to forgo this, especially when attempting to repair networking operations),
.It Fl v
(verbose) Print additional details.
.It Fl q
Suppress all output.
.El
.Pp
The
.Nm route :
utility provides six commands:
.Pp
.Bl -tag -width Fl -compact
.It Cm add
Add a route.
.It Cm flush
Remove all routes.
.It Cm delete
Delete a specific route.
.It Cm change
Change aspects of a route (such as its gateway).
.It Cm get
Lookup and display the route for a destination.
.It Cm monitor
Continuously report any changes to the routing information base,
routing lookup misses, or suspected network partitionings.
.El
.Pp
The monitor command has the syntax
.Pp
.Bd -filled -offset indent -compact
.Nm route Op Fl n
.Cm monitor
.Ed
.Pp
The flush command has the syntax
.Pp
.Bd -filled -offset indent -compact
.Nm route Op Fl n
.Cm flush
.Op Ar family
.Ed
.Pp
If the
.Cm flush
command is specified,
.Nm route
will ``flush'' the routing tables of all gateway entries.
When the address family may is specified by any of the
.Fl osi ,
.Fl xns ,
or
.Fl inet
modifiers, only routes having destinations with addresses in the
delineated family will be deleted.
.Pp
The other commands have the following syntax:
.Pp
.Bd -filled -offset indent -compact
.Nm route Op Fl n
.Ar command
.Op Fl net No \&| Fl host
.Ar destination gateway
.Ed
.Pp
where
.Ar destination
is the destination host or network,
.Ar gateway
is the next-hop intermediary via which packets should be routed.
Routes to a particular host may be distinguished from those to
a network by interpreting the Internet address specified as the
.Ar destination argument.
The optional modifiers
.Fl net
and
.Fl host
force the destination to be interpreted as a network or a host, respectively.
Otherwise, if the
.Ar destination
has a ``local address part'' of
INADDR_ANY ,
or if the
.Ar destination
is the symbolic name of a network, then the route is
assumed to be to a network; otherwise, it is presumed to be a
route to a host.
.Pp
For example,
.Li 128.32
is interpreted as
.Fl host Li 128.0.0.32 ;
.Li 128.32.130
is interpreted as
.Fl host Li 128.32.0.130 ;
.Fl net Li 128.32
is interpreted as
.Li 128.32.0.0;
and
.Fl net Li 128.32.130
is interpreted as
.Li 128.32.130.0 .
.Pp
If the destination is directly reachable
via an interface requiring
no intermediary system to act as a gateway, the
.Fl interface
modifier should be specified;
the gateway given is the address of this host on the common network,
indicating the interface to be used for transmission.
.Pp
The optional modifiers
.Fl xns ,
.Fl osi ,
and
.Fl link
specify that all subsequent addresses are in the
.Tn XNS
.Tn OSI
address families,
or are specified as link-level addresses,
and the names must be numeric specifications rather than
symbolic names.
.Pp
The optional
.Fl netmask
qualifier is intended
to achieve the effect of an
.Tn OSI
.Tn ESIS
redirect with the netmask option,
or to manually add subnet routes with
netmasks different from that of the implied network interface
(as would otherwise be communicated using the OSPF or ISIS routing protocols).
One specifies an additional ensuing address parameter
(to be interpreted as a network mask).
The implicit network mask generated in the AF_INET case
can be overridden by making sure this option follows the destination parameter.
.Pp
Routes have associated flags which influence operation of the protocols
when sending to destinations matched by the routes.
These flags may be set (or sometimes cleared)
by indicating the following corresponding modifiers:
.Bd -literal
-cloning RTF_CLONING - generates a new route on use
-xresolve RTF_XRESOLVE - emit mesg on use (for external lookup)
-iface ~RTF_GATEWAY - destination is directly reachable
-static RTF_STATIC - manually added route
-nostatic ~RTF_STATIC - pretend route added by kernel or daemon
-reject RTF_REJECT - emit an ICMP unreachable when matched
-blackhole RTF_BLACKHOLE - silently discard pkts (during updates)
-proto1 RTF_PROTO1 - set protocol specific routing flag #1
-proto2 RTF_PROTO2 - set protocol specific routing flag #2
-llinfo RTF_LLINFO - validly translates proto addr to link addr
.Ed
.Pp
The optional modifiers
.Fl rtt ,
.Fl rttvar ,
.Fl sendpipe ,
.Fl recvpipe ,
.Fl mtu ,
.Fl hopcount ,
.Fl expire ,
and
.Fl ssthresh
provide initial values to quantities maintained in the routing entry
by transport level protocols, such as TCP or TP4.
These may be individually locked by preceding each such modifier to
be locked by
the
.Fl lock
meta-modifier, or one can
specify that all ensuing metrics may be locked by the
.Fl lockrest
meta-modifier.
.Pp
In a
.Cm change
or
.Cm add
command where the destination and gateway are not sufficient to specify
the route (as in the
.Tn ISO
case where several interfaces may have the
same address), the
.Fl ifp
or
.Fl ifa
modifiers may be used to determine the interface or interface address.
.Pp
All symbolic names specified for a
.Ar destination
or
.Ar gateway
are looked up first as a host name using
.Xr gethostbyname 3 .
If this lookup fails,
.Xr getnetbyname 3
is then used to interpret the name as that of a network.
.Pp
.Nm Route
uses a routing socket and the new message types
RTM_ADD,
RTM_DELETE,
RTM_GET,
and
RTM_CHANGE.
As such, only the super-user may modify
the routing tables.
.ne 1i
.Sh DIAGNOSTICS
.Bl -tag -width Ds
.It Sy "add [host \&| network ] %s: gateway %s flags %x"
The specified route is being added to the tables. The
values printed are from the routing table entry supplied
in the
.Xr ioctl 2
call.
If the gateway address used was not the primary address of the gateway
(the first one returned by
.Xr gethostbyname 3 ) ,
the gateway address is printed numerically as well as symbolically.
.It Sy "delete [ host &| network ] %s: gateway %s flags %x"
As above, but when deleting an entry.
.It Sy "%s %s done"
When the
.Cm flush
command is specified, each routing table entry deleted
is indicated with a message of this form.
.It Sy "Network is unreachable"
An attempt to add a route failed because the gateway listed was not
on a directly-connected network.
The next-hop gateway must be given.
.It Sy "not in table"
A delete operation was attempted for an entry which
wasn't present in the tables.
.It Sy "routing table overflow"
An add operation was attempted, but the system was
low on resources and was unable to allocate memory
to create the new entry.
.El
.Sh SEE ALSO
.Xr netintro 4 ,
.Xr route 4 ,
.Xr esis 4 ,
.Xr routed 8 ,
.Xr XNSrouted 8
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .
.Sh BUGS
The first paragraph may have slightly exaggerated
.Xr routed Ns 's
abilities.

1415
sbin/route/route.c Normal file

File diff suppressed because it is too large Load Diff

649
sbin/savecore/savecore.c Normal file
View File

@ -0,0 +1,649 @@
/*-
* Copyright (c) 1986, 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1986, 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)savecore.c 8.5 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/syslog.h>
#include <sys/time.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <nlist.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tzfile.h>
#include <unistd.h>
#define ok(number) ((number) - KERNBASE)
struct nlist current_nl[] = { /* Namelist for currently running system. */
#define X_DUMPDEV 0
{ "_dumpdev" },
#define X_DUMPLO 1
{ "_dumplo" },
#define X_TIME 2
{ "_time" },
#define X_DUMPSIZE 3
{ "_dumpsize" },
#define X_VERSION 4
{ "_version" },
#define X_PANICSTR 5
{ "_panicstr" },
#define X_DUMPMAG 6
{ "_dumpmag" },
{ "" },
};
int cursyms[] = { X_DUMPDEV, X_DUMPLO, X_VERSION, X_DUMPMAG, -1 };
int dumpsyms[] = { X_TIME, X_DUMPSIZE, X_VERSION, X_PANICSTR, X_DUMPMAG, -1 };
struct nlist dump_nl[] = { /* Name list for dumped system. */
{ "_dumpdev" }, /* Entries MUST be the same as */
{ "_dumplo" }, /* those in current_nl[]. */
{ "_time" },
{ "_dumpsize" },
{ "_version" },
{ "_panicstr" },
{ "_dumpmag" },
{ "" },
};
/* Types match kernel declarations. */
long dumplo; /* where dump starts on dumpdev */
int dumpmag; /* magic number in dump */
int dumpsize; /* amount of memory dumped */
char *vmunix;
char *dirname; /* directory to save dumps in */
char *ddname; /* name of dump device */
dev_t dumpdev; /* dump device */
int dumpfd; /* read/write descriptor on block dev */
time_t now; /* current date */
char panic_mesg[1024];
int panicstr;
char vers[1024];
int clear, compress, force, verbose; /* flags */
void check_kmem __P((void));
int check_space __P((void));
void clear_dump __P((void));
int Create __P((char *, int));
int dump_exists __P((void));
char *find_dev __P((dev_t, int));
int get_crashtime __P((void));
void kmem_setup __P((void));
void log __P((int, char *, ...));
void Lseek __P((int, off_t, int));
int Open __P((char *, int rw));
int Read __P((int, void *, int));
char *rawname __P((char *s));
void save_core __P((void));
void usage __P((void));
void Write __P((int, void *, int));
int
main(argc, argv)
int argc;
char *argv[];
{
int ch;
openlog("savecore", LOG_PERROR, LOG_DAEMON);
while ((ch = getopt(argc, argv, "cdfN:vz")) != EOF)
switch(ch) {
case 'c':
clear = 1;
break;
case 'd': /* Not documented. */
case 'v':
verbose = 1;
break;
case 'f':
force = 1;
break;
case 'N':
vmunix = optarg;
break;
case 'z':
compress = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (!clear) {
if (argc != 1 && argc != 2)
usage();
dirname = argv[0];
}
if (argc == 2)
vmunix = argv[1];
(void)time(&now);
kmem_setup();
if (clear) {
clear_dump();
exit(0);
}
if (!dump_exists() && !force)
exit(1);
check_kmem();
if (panicstr)
syslog(LOG_ALERT, "reboot after panic: %s", panic_mesg);
else
syslog(LOG_ALERT, "reboot");
if ((!get_crashtime() || !check_space()) && !force)
exit(1);
save_core();
clear_dump();
exit(0);
}
void
kmem_setup()
{
FILE *fp;
int kmem, i;
char *dump_sys;
/*
* Some names we need for the currently running system, others for
* the system that was running when the dump was made. The values
* obtained from the current system are used to look for things in
* /dev/kmem that cannot be found in the dump_sys namelist, but are
* presumed to be the same (since the disk partitions are probably
* the same!)
*/
if ((nlist(_PATH_UNIX, current_nl)) == -1)
syslog(LOG_ERR, "%s: nlist: %s", _PATH_UNIX, strerror(errno));
for (i = 0; cursyms[i] != -1; i++)
if (current_nl[cursyms[i]].n_value == 0) {
syslog(LOG_ERR, "%s: %s not in namelist",
_PATH_UNIX, current_nl[cursyms[i]].n_name);
exit(1);
}
dump_sys = vmunix ? vmunix : _PATH_UNIX;
if ((nlist(dump_sys, dump_nl)) == -1)
syslog(LOG_ERR, "%s: nlist: %s", dump_sys, strerror(errno));
for (i = 0; dumpsyms[i] != -1; i++)
if (dump_nl[dumpsyms[i]].n_value == 0) {
syslog(LOG_ERR, "%s: %s not in namelist",
dump_sys, dump_nl[dumpsyms[i]].n_name);
exit(1);
}
kmem = Open(_PATH_KMEM, O_RDONLY);
Lseek(kmem, (off_t)current_nl[X_DUMPDEV].n_value, L_SET);
(void)Read(kmem, &dumpdev, sizeof(dumpdev));
if (dumpdev == NODEV) {
syslog(LOG_WARNING, "no core dump (no dumpdev)");
exit(1);
}
Lseek(kmem, (off_t)current_nl[X_DUMPLO].n_value, L_SET);
(void)Read(kmem, &dumplo, sizeof(dumplo));
if (verbose)
(void)printf("dumplo = %d (%d * %d)\n",
dumplo, dumplo/DEV_BSIZE, DEV_BSIZE);
Lseek(kmem, (off_t)current_nl[X_DUMPMAG].n_value, L_SET);
(void)Read(kmem, &dumpmag, sizeof(dumpmag));
dumplo *= DEV_BSIZE;
ddname = find_dev(dumpdev, S_IFBLK);
dumpfd = Open(ddname, O_RDWR);
fp = fdopen(kmem, "r");
if (fp == NULL) {
syslog(LOG_ERR, "%s: fdopen: %m", _PATH_KMEM);
exit(1);
}
if (vmunix)
return;
(void)fseek(fp, (off_t)current_nl[X_VERSION].n_value, L_SET);
(void)fgets(vers, sizeof(vers), fp);
/* Don't fclose(fp), we use dumpfd later. */
}
void
check_kmem()
{
register char *cp;
FILE *fp;
char core_vers[1024];
fp = fdopen(dumpfd, "r");
if (fp == NULL) {
syslog(LOG_ERR, "%s: fdopen: %m", ddname);
exit(1);
}
fseek(fp, (off_t)(dumplo + ok(dump_nl[X_VERSION].n_value)), L_SET);
fgets(core_vers, sizeof(core_vers), fp);
if (strcmp(vers, core_vers) && vmunix == 0)
syslog(LOG_WARNING,
"warning: %s version mismatch:\n\t%s\nand\t%s\n",
_PATH_UNIX, vers, core_vers);
(void)fseek(fp,
(off_t)(dumplo + ok(dump_nl[X_PANICSTR].n_value)), L_SET);
(void)fread(&panicstr, sizeof(panicstr), 1, fp);
if (panicstr) {
(void)fseek(fp, dumplo + ok(panicstr), L_SET);
cp = panic_mesg;
do
*cp = getc(fp);
while (*cp++ && cp < &panic_mesg[sizeof(panic_mesg)]);
}
/* Don't fclose(fp), we use dumpfd later. */
}
void
clear_dump()
{
long newdumplo;
newdumplo = 0;
Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
Write(dumpfd, &newdumplo, sizeof(newdumplo));
}
int
dump_exists()
{
int newdumpmag;
Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPMAG].n_value)), L_SET);
(void)Read(dumpfd, &newdumpmag, sizeof(newdumpmag));
if (newdumpmag != dumpmag) {
if (verbose)
syslog(LOG_WARNING, "magic number mismatch (%x != %x)",
newdumpmag, dumpmag);
syslog(LOG_WARNING, "no core dump");
return (0);
}
return (1);
}
char buf[1024 * 1024];
void
save_core()
{
register FILE *fp;
register int bounds, ifd, nr, nw, ofd;
char *rawp, path[MAXPATHLEN];
/*
* Get the current number and update the bounds file. Do the update
* now, because may fail later and don't want to overwrite anything.
*/
(void)snprintf(path, sizeof(path), "%s/bounds", dirname);
if ((fp = fopen(path, "r")) == NULL)
goto err1;
if (fgets(buf, sizeof(buf), fp) == NULL) {
if (ferror(fp))
err1: syslog(LOG_WARNING, "%s: %s", path, strerror(errno));
bounds = 0;
} else
bounds = atoi(buf);
if (fp != NULL)
(void)fclose(fp);
if ((fp = fopen(path, "w")) == NULL)
syslog(LOG_ERR, "%s: %m", path);
else {
(void)fprintf(fp, "%d\n", bounds + 1);
(void)fclose(fp);
}
(void)fclose(fp);
/* Create the core file. */
(void)snprintf(path, sizeof(path), "%s/vmcore.%d%s",
dirname, bounds, compress ? ".Z" : "");
if (compress) {
if ((fp = zopen(path, "w", 0)) == NULL) {
syslog(LOG_ERR, "%s: %s", path, strerror(errno));
exit(1);
}
} else
ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
/* Open the raw device. */
rawp = rawname(ddname);
if ((ifd = open(rawp, O_RDONLY)) == -1) {
syslog(LOG_WARNING, "%s: %m; using block device", rawp);
ifd = dumpfd;
}
/* Read the dump size. */
Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_DUMPSIZE].n_value)), L_SET);
(void)Read(dumpfd, &dumpsize, sizeof(dumpsize));
/* Seek to the start of the core. */
Lseek(ifd, (off_t)dumplo, L_SET);
/* Copy the core file. */
dumpsize *= NBPG;
syslog(LOG_NOTICE, "writing %score to %s",
compress ? "compressed " : "", path);
for (; dumpsize > 0; dumpsize -= nr) {
(void)printf("%6dK\r", dumpsize / 1024);
(void)fflush(stdout);
nr = read(ifd, buf, MIN(dumpsize, sizeof(buf)));
if (nr <= 0) {
if (nr == 0)
syslog(LOG_WARNING,
"WARNING: EOF on dump device");
else
syslog(LOG_ERR, "%s: %m", rawp);
goto err2;
}
if (compress)
nw = fwrite(buf, 1, nr, fp);
else
nw = write(ofd, buf, nr);
if (nw != nr) {
syslog(LOG_ERR, "%s: %s",
path, strerror(nw == 0 ? EIO : errno));
err2: syslog(LOG_WARNING,
"WARNING: vmcore may be incomplete");
(void)printf("\n");
exit(1);
}
}
(void)printf("\n");
(void)close(ifd);
if (compress)
(void)fclose(fp);
else
(void)close(ofd);
/* Copy the kernel. */
ifd = Open(vmunix ? vmunix : _PATH_UNIX, O_RDONLY);
(void)snprintf(path, sizeof(path), "%s/vmunix.%d%s",
dirname, bounds, compress ? ".Z" : "");
if (compress) {
if ((fp = zopen(path, "w", 0)) == NULL) {
syslog(LOG_ERR, "%s: %s", path, strerror(errno));
exit(1);
}
} else
ofd = Create(path, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
syslog(LOG_NOTICE, "writing %skernel to %s",
compress ? "compressed " : "", path);
while ((nr = read(ifd, buf, sizeof(buf))) > 0) {
if (compress)
nw = fwrite(buf, 1, nr, fp);
else
nw = write(ofd, buf, nr);
if (nw != nr) {
syslog(LOG_ERR, "%s: %s",
path, strerror(nw == 0 ? EIO : errno));
syslog(LOG_WARNING,
"WARNING: vmunix may be incomplete");
exit(1);
}
}
if (nr < 0) {
syslog(LOG_ERR, "%s: %s",
vmunix ? vmunix : _PATH_UNIX, strerror(errno));
syslog(LOG_WARNING,
"WARNING: vmunix may be incomplete");
exit(1);
}
if (compress)
(void)fclose(fp);
else
(void)close(ofd);
}
char *
find_dev(dev, type)
register dev_t dev;
register int type;
{
register DIR *dfd;
struct dirent *dir;
struct stat sb;
char *dp, devname[MAXPATHLEN + 1];
if ((dfd = opendir(_PATH_DEV)) == NULL) {
syslog(LOG_ERR, "%s: %s", _PATH_DEV, strerror(errno));
exit(1);
}
(void)strcpy(devname, _PATH_DEV);
while ((dir = readdir(dfd))) {
(void)strcpy(devname + sizeof(_PATH_DEV) - 1, dir->d_name);
if (lstat(devname, &sb)) {
syslog(LOG_ERR, "%s: %s", devname, strerror(errno));
continue;
}
if ((sb.st_mode & S_IFMT) != type)
continue;
if (dev == sb.st_rdev) {
closedir(dfd);
if ((dp = strdup(devname)) == NULL) {
syslog(LOG_ERR, "%s", strerror(errno));
exit(1);
}
return (dp);
}
}
closedir(dfd);
syslog(LOG_ERR, "can't find device %d/%d", major(dev), minor(dev));
exit(1);
}
char *
rawname(s)
char *s;
{
char *sl, name[MAXPATHLEN];
if ((sl = strrchr(s, '/')) == NULL || sl[1] == '0') {
syslog(LOG_ERR,
"can't make raw dump device name from %s", s);
return (s);
}
(void)snprintf(name, sizeof(name), "%.*s/r%s", sl - s, s, sl + 1);
if ((sl = strdup(name)) == NULL) {
syslog(LOG_ERR, "%s", strerror(errno));
exit(1);
}
return (sl);
}
int
get_crashtime()
{
time_t dumptime; /* Time the dump was taken. */
Lseek(dumpfd, (off_t)(dumplo + ok(dump_nl[X_TIME].n_value)), L_SET);
(void)Read(dumpfd, &dumptime, sizeof(dumptime));
if (dumptime == 0) {
if (verbose)
syslog(LOG_ERR, "dump time is zero");
return (0);
}
(void)printf("savecore: system went down at %s", ctime(&dumptime));
#define LEEWAY (7 * SECSPERDAY)
if (dumptime < now - LEEWAY || dumptime > now + LEEWAY) {
(void)printf("dump time is unreasonable\n");
return (0);
}
return (1);
}
int
check_space()
{
register FILE *fp;
char *tvmunix;
off_t minfree, spacefree, vmunixsize, needed;
struct stat st;
struct statfs fsbuf;
char buf[100], path[MAXPATHLEN];
tvmunix = vmunix ? vmunix : _PATH_UNIX;
if (stat(tvmunix, &st) < 0) {
syslog(LOG_ERR, "%s: %m", tvmunix);
exit(1);
}
vmunixsize = st.st_blocks * S_BLKSIZE;
if (statfs(dirname, &fsbuf) < 0) {
syslog(LOG_ERR, "%s: %m", dirname);
exit(1);
}
spacefree = (fsbuf.f_bavail * fsbuf.f_bsize) / 1024;
(void)snprintf(path, sizeof(path), "%s/minfree", dirname);
if ((fp = fopen(path, "r")) == NULL)
minfree = 0;
else {
if (fgets(buf, sizeof(buf), fp) == NULL)
minfree = 0;
else
minfree = atoi(buf);
(void)fclose(fp);
}
needed = (dumpsize + vmunixsize) / 1024;
if (minfree > 0 && spacefree - needed < minfree) {
syslog(LOG_WARNING,
"no dump, not enough free space on device");
return (0);
}
if (spacefree - needed < minfree)
syslog(LOG_WARNING,
"dump performed, but free space threshold crossed");
return (1);
}
int
Open(name, rw)
char *name;
int rw;
{
int fd;
if ((fd = open(name, rw, 0)) < 0) {
syslog(LOG_ERR, "%s: %m", name);
exit(1);
}
return (fd);
}
int
Read(fd, bp, size)
int fd, size;
void *bp;
{
int nr;
nr = read(fd, bp, size);
if (nr != size) {
syslog(LOG_ERR, "read: %m");
exit(1);
}
return (nr);
}
void
Lseek(fd, off, flag)
int fd, flag;
off_t off;
{
off_t ret;
ret = lseek(fd, off, flag);
if (ret == -1) {
syslog(LOG_ERR, "lseek: %m");
exit(1);
}
}
int
Create(file, mode)
char *file;
int mode;
{
register int fd;
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (fd < 0) {
syslog(LOG_ERR, "%s: %m", file);
exit(1);
}
return (fd);
}
void
Write(fd, bp, size)
int fd, size;
void *bp;
{
int n;
if ((n = write(fd, bp, size)) < size) {
syslog(LOG_ERR, "write: %s", strerror(n == -1 ? errno : EIO));
exit(1);
}
}
void
usage()
{
(void)syslog(LOG_ERR, "usage: savecore [-cfvz] [-N system] directory");
exit(1);
}

View File

@ -0,0 +1,664 @@
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)scsiformat.c 5.5 (Berkeley) 4/2/94
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)scsiformat.c 5.5 (Berkeley) 4/2/94";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <dev/scsi/scsi.h>
#include <dev/scsi/disk.h>
#include <dev/scsi/disktape.h>
#include <dev/scsi/scsi_ioctl.h>
#define COMPAT_HPSCSI
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int fd;
char *device;
void scsi_str __P((char *, char *, int));
void do_command __P((int, struct scsi_cdb *, void *, int));
void do_format __P((void));
void print_capacity __P((void));
void print_inquiry __P((void));
void prflags __P((int, const char *));
u_char *print_mode_page __P((u_char *));
void print_mode_sense __P((void));
void usage __P((void));
#define N2(c, d) (((c) << 8) | (d))
#define N3(b, c, d) (((b) << 16) | N2(c, d))
#define N4(a, b, c, d) (((a) << 24) | N3(b, c, d))
int sense_pctl;
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
int ch, readonly;
readonly = 0;
sense_pctl = SCSI_MSENSE_PCTL_CUR;
while ((ch = getopt(argc, argv, "rp:")) != EOF) {
switch(ch) {
case 'r':
readonly = 1;
break;
case 'p': /* mode sense page control */
switch (*optarg) {
case 'c':
sense_pctl = SCSI_MSENSE_PCTL_CUR;
break;
case 'd':
sense_pctl = SCSI_MSENSE_PCTL_DFLT;
break;
case 's':
sense_pctl = SCSI_MSENSE_PCTL_SAVED;
break;
case 'v':
(void)printf(
"*** note: for variable parameters, 1-bit means ``can write here''\n");
sense_pctl = SCSI_MSENSE_PCTL_VAR;
break;
}
/* FALLTHROUGH */
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
device = *argv;
fd = open(device, readonly ? O_RDONLY : O_RDWR, 0);
if (fd < 0) {
(void)fprintf(stderr,
"scsiformat: %s: %s\n", device, strerror(errno));
exit(1);
}
print_inquiry();
print_capacity();
print_mode_sense();
if (!readonly)
do_format();
exit(0);
}
/*
* Copy a counted string, trimming trailing blanks, and turning the
* result into a C-style string.
*/
void
scsi_str(src, dst, len)
register char *src, *dst;
register int len;
{
while (src[len - 1] == ' ') {
if (--len == 0) {
*dst = 0;
return;
}
}
bcopy(src, dst, len);
dst[len] = 0;
}
void
print_inquiry()
{
register struct scsi_inq_ansi *si;
int ver;
struct scsi_inquiry inqbuf;
char vendor[10], product[17], rev[5];
static struct scsi_cdb inq = {
CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
};
do_command(fd, &inq, &inqbuf, sizeof(inqbuf));
(void)printf("%s: ", device);
ver = (inqbuf.si_version >> VER_ANSI_SHIFT) & VER_ANSI_MASK;
if (ver != 1 && ver != 2) {
(void)printf("type 0x%x, qual 0x%x, ver 0x%x (ansi %d)\n",
inqbuf.si_type, inqbuf.si_qual, inqbuf.si_version, ver);
return;
}
si = (struct scsi_inq_ansi *)&inqbuf;
switch (si->si_type & TYPE_TYPE_MASK) {
case TYPE_DAD:
(void)printf("(disk)");
break;
case TYPE_WORM:
(void)printf("(WORM)");
break;
case TYPE_ROM:
(void)printf("(CD-ROM)");
break;
case TYPE_MO:
(void)printf("(MO-DISK)");
break;
case TYPE_JUKEBOX:
(void)printf("(jukebox)");
break;
default:
(void)printf("(??)");
break;
}
scsi_str(si->si_vendor, vendor, sizeof(si->si_vendor));
scsi_str(si->si_product, product, sizeof(si->si_product));
scsi_str(si->si_rev, rev, sizeof(si->si_rev));
(void)printf(" %s %s rev %s:", vendor, product, rev);
}
void
print_capacity()
{
struct scsi_rc rc; /* for READ CAPACITY */
static struct scsi_cdb cap = { CMD_READ_CAPACITY };
do_command(fd, &cap, &rc, sizeof(rc));
(void)printf(" %d blocks of %d bytes each\n",
N4(rc.rc_lbah, rc.rc_lbahm, rc.rc_lbalm, rc.rc_lbal) + 1,
N4(rc.rc_blh, rc.rc_blhm, rc.rc_bllm, rc.rc_bll));
}
void
print_mode_sense()
{
register u_char *cp, *ep;
register struct scsi_ms_bd *bd;
register int n, i, l, len, bdlen;
#ifdef TEN_BYTE_SENSE
struct {
struct scsi_ms10 ms;
u_char p[1023 - sizeof(struct scsi_ms10)];
} msbuf;
static struct scsi_cdb modesense = {
CMD_MODE_SENSE10, SCSI_MSENSE_DBD, 0, 0, 0, 0, 0,
sizeof(msbuf) >> 8, sizeof (msbuf), 0
};
CDB10(&modesense)->cdb_lbam = sense_pctl | SCSI_MS_PC_ALL;
do_command(fd, &modesense, &msbuf, sizeof(msbuf));
len = N2(msbuf.ms.ms_lenh, msbuf.ms.ms_lenl);
bdlen = N2(msbuf.ms.ms_bdlh, msbuf.ms.ms_bdll);
#else
struct {
struct scsi_ms6 ms;
u_char p[255 - sizeof(struct scsi_ms6)];
} msbuf;
static struct scsi_cdb modesense = {
CMD_MODE_SENSE6, 0, 0, 0, sizeof(msbuf), 0
};
CDB6(&modesense)->cdb_lbam = sense_pctl | SCSI_MS_PC_ALL;
do_command(fd, &modesense, &msbuf, sizeof(msbuf));
len = msbuf.ms.ms_len;
bdlen = msbuf.ms.ms_bdl;
#endif
(void)printf("\n%d bytes of mode sense data. ", len);
(void)printf("medium type 0x%x, %swrite protected\n",
msbuf.ms.ms_mt, msbuf.ms.ms_dsp & SCSI_MS_DSP_WP ? "" : "not ");
if ((n = bdlen) != 0) {
bd = (struct scsi_ms_bd *)msbuf.p;
for (n /= sizeof(*bd); --n >= 0; bd++) {
(void)printf("\tdensity code 0x%x, ", bd->bd_dc);
i = N3(bd->bd_nbh, bd->bd_nbm, bd->bd_nbl);
l = N3(bd->bd_blh, bd->bd_blm, bd->bd_bll);
if (i)
(void)printf("%d blocks of length %d\n", i, l);
else
(void)printf("all blocks of length %d\n", l);
}
}
/*
* Sense header lengths includes the sense header, while mode page
* lengths do not ... let's hear it for consistency!
*/
cp = msbuf.p + bdlen;
ep = msbuf.p + len - sizeof(msbuf.ms);
while (cp < ep)
cp = print_mode_page(cp);
}
void
prflags(v, cp)
int v;
register const char *cp;
{
register const char *np;
char f, sep;
for (sep = '<'; (f = *cp++) != 0; cp = np) {
for (np = cp; *np >= ' ';)
np++;
if ((v & (1 << (f - 1))) == 0)
continue;
printf("%c%.*s", sep, np - cp, cp);
sep = ',';
}
if (sep != '<')
putchar('>');
}
static char *
cache_policy(x)
int x;
{
static char rsvd[30];
switch (x) {
case SCSI_CACHE_DEFAULT:
return ("default");
case SCSI_CACHE_KEEPPF:
return ("toss cmd data, save prefetch");
case SCSI_CACHE_KEEPCMD:
return ("toss prefetch data, save cmd");
default:
(void)sprintf(rsvd, "reserved %d", x);
return (rsvd);
}
/* NOTREACHED */
}
u_char *
print_mode_page(cp)
u_char *cp;
{
register struct scsi_ms_page_hdr *mp;
int len, code, i;
u_char *tp;
const char *s;
mp = (struct scsi_ms_page_hdr *)cp;
code = mp->mp_psc & SCSI_MS_PC_MASK;
len = mp->mp_len;
(void)printf("\npage type %d%s (%d bytes): ",
code, mp->mp_psc & SCSI_MS_MP_SAVEABLE ? " (saveable)" : "", len);
switch (code) {
case SCSI_MS_PC_RWERRREC:
#define rw ((struct scsi_page_rwerrrec *)(mp + 1))
(void)printf("Read/Write Error Recovery parameters.\n");
(void)printf("\tflags = 0x%x", rw->rw_flags);
prflags(rw->rw_flags,
"\10AWRE\7ARRE\6TB\5RC\4EER\3PER\2DTE\1DCR");
(void)printf(",\n\t%d read retries, %d correction span bits,\n",
rw->rw_read_retry, rw->rw_corr_span);
(void)printf("\t%d head offsets, %d data strobe offsets%s\n",
rw->rw_hd_off, rw->rw_ds_off, len > 6 ? "," : ".");
if (len <= 6)
break;
(void)printf("\t%d write retries, ", rw->rw_write_retry);
i = N2(rw->rw_rtlh, rw->rw_rtll);
if (i != 0xffff)
(void)printf("%d", i);
else
(void)printf("no");
(void)printf(" recovery time limit.\n");
break;
#undef rw
case SCSI_MS_PC_DR:
#define dr ((struct scsi_page_dr *)(mp + 1))
(void)printf("Disconnect/Reconnect control.\n");
(void)printf("\tbuffer full ratio %d, buffer empty ratio %d,\n",
dr->dr_full, dr->dr_empty);
(void)printf("\ttime limits: %d bus inactivity, ",
N2(dr->dr_inacth, dr->dr_inactl));
(void)printf("%d disconnect, %d connect.\n",
N2(dr->dr_disconh, dr->dr_disconl),
N2(dr->dr_conh, dr->dr_conl));
(void)printf("\tmaximum burst size %d,\n",
N2(dr->dr_bursth, dr->dr_burstl));
switch (dr->dr_dtdc & SCSI_DR_DTDC_MASK) {
case SCSI_DR_DTDC_NONE:
s = "never";
break;
case SCSI_DR_DTDC_NOTDATA:
s = "during data transfer";
break;
case SCSI_DR_DTDC_RSVD:
s = "???";
break;
case SCSI_DR_DTDC_NOTD2:
s = "during and after data transfer";
break;
}
(void)printf("\tsuppress disconnect %s.\n", s);
break;
#undef dr
case SCSI_MS_PC_FMT:
#define fmt ((struct scsi_page_fmt *)(mp + 1))
(void)printf("Format parameters.\n");
(void)printf("\t%d tracks/zone, %d alt.sect./zone, ",
N2(fmt->fmt_tpzh, fmt->fmt_tpzl),
N2(fmt->fmt_aspzh, fmt->fmt_aspzl));
(void)printf("%d alt.tracks/zone,\n\t%d alt.tracks/vol., ",
N2(fmt->fmt_atpzh, fmt->fmt_atpzl),
N2(fmt->fmt_atpvh, fmt->fmt_atpvl));
(void)printf("%d sectors/track, %d bytes/phys.sector,\n",
N2(fmt->fmt_spth, fmt->fmt_sptl),
N2(fmt->fmt_dbppsh, fmt->fmt_dbppsl));
(void)printf("\tinterleave %d, track skew %d, cyl.skew %d,\n",
N2(fmt->fmt_ilh, fmt->fmt_ill),
N2(fmt->fmt_tsfh, fmt->fmt_tsfl),
N2(fmt->fmt_csfh, fmt->fmt_csfl));
(void)printf("\tdrive flags 0x%x", fmt->fmt_flags);
prflags(fmt->fmt_flags, "\10SSEC\7HSEC\6RMB\5SURF");
(void)printf(".\n");
break;
#undef fmt
case SCSI_MS_PC_RDGEOM:
#define rd ((struct scsi_page_rdgeom *)(mp + 1))
(void)printf("Disk Geometry parameters.\n");
(void)printf("\t%d cylinders, %d heads,\n",
N3(rd->rd_ncylh, rd->rd_ncylm, rd->rd_ncyll),
rd->rd_nheads);
(void)printf("\tstart write precompensation at cyl %d,\n",
N3(rd->rd_wpcylh, rd->rd_wpcylm, rd->rd_wpcyll));
(void)printf("\tstart reduced write current at cyl %d,\n",
N3(rd->rd_rwcylh, rd->rd_rwcylm, rd->rd_rwcyll));
(void)printf("\tseek step rate %f us, landing zone cyl %d,\n",
N2(rd->rd_steph, rd->rd_stepl) * 0.1,
N3(rd->rd_lcylh, rd->rd_lcylm, rd->rd_lcyll));
switch (rd->rd_rpl & SCSI_RD_RPL_MASK) {
case SCSI_RD_RPL_NONE:
s = "disabled or unsupported";
break;
case SCSI_RD_RPL_SLAVE:
s = "slave";
break;
case SCSI_RD_RPL_MASTER:
s = "master";
break;
case SCSI_RD_RPL_MCONTROL:
s = "master control";
break;
}
(void)printf("\trotational synch %s, offset %d/256%s\n",
s, rd->rd_roff, len > 18 ? "," : ".");
if (len > 18)
(void)printf("\trotation %d rpm.\n",
N2(rd->rd_rpmh, rd->rd_rpml));
break;
#undef rd
case SCSI_MS_PC_VERRREC:
#define v ((struct scsi_page_verrrec *)(mp + 1))
(void)printf("Verify Error Recovery parameters.\n");
(void)printf("\tflags = 0x%x", v->v_flags);
prflags(v->v_flags, "\4EER\3PER\2DTE\1DCR");
(void)printf(",\n\t%d verify retries, %d %s span bits,\n\t",
v->v_verify_retry, v->v_corr_span, "correction");
(void)printf("%d recovery time limit.\n",
N2(v->v_rtlh, v->v_rtll));
break;
#undef v
case SCSI_MS_PC_CACHE:
#define cache ((struct scsi_page_cache *)(mp + 1))
(void)printf("Caching Page.\n");
(void)printf("\tflags = 0x%x", cache->cache_flags);
prflags(cache->cache_flags, "\3WCE\2MF\1RCD");
(void)printf(
",\n\tread retention = %s, write retention = %s,\n",
cache_policy(SCSI_CACHE_RDPOLICY(cache->cache_reten)),
cache_policy(SCSI_CACHE_WRPOLICY(cache->cache_reten)));
(void)printf("\tdisable prefetch transfer length = %d,\n",
N2(cache->cache_dptlh, cache->cache_dptll));
(void)printf("\tmin prefetch = %d, max prefetch = %d, ",
N2(cache->cache_minpfh, cache->cache_minpfl),
N2(cache->cache_maxpfh, cache->cache_maxpfl));
(void)printf("max prefetch ceiling = %d.\n",
N2(cache->cache_mpch, cache->cache_mpcl));
break;
#undef cache
case SCSI_MS_PC_CTLMODE:
#define cm ((struct scsi_page_ctlmode *)(mp + 1))
(void)printf("Control Mode Page.\n");
(void)printf("\t%s report log-activity error conditions,\n",
cm->cm_rlec & SCSI_CM_RLEC ? "do" : "do not");
(void)printf("\tqueue algorithm modifier = %d, flags = 0x%x",
SCSI_CM_QMOD(cm->cm_qctl),
cm->cm_qctl & (SCSI_CM_QERR|SCSI_CM_DQUE));
prflags(cm->cm_qctl, "\2QERR\1DQUE");
(void)printf(",\n\tECA/AEN flags = 0x%x", cm->cm_ecaaen);
prflags(cm->cm_ecaaen, "\10ECA\3RAENP\2UUAENP\1EAENP");
(void)printf(", AEN holdoff period = %d ms.\n",
N2(cm->cm_aenholdh, cm->cm_aenholdl));
break;
#undef cm
/*
* Vendor Unique, but what the heck.
*/
case SCSI_MS_PC_CDCCACHECTL:
#define ccm ((struct scsi_page_CDCcachectlmode *)(mp + 1))
(void)printf("CDC-specific Cache Control Mode Page.\n");
(void)printf("\tflags = 0x%x", ccm->ccm_flags);
prflags(ccm->ccm_flags, "\7WIE\5ENABLE");
(void)printf(", table size = %d, prefetch threshold = %d\n",
SCSI_CDC_CCM_TBLSZ(ccm->ccm_flags),
ccm->ccm_pfthresh);
(void)printf("\tmaximum %s = %d, maximum %s = %d,\n",
"threshold", ccm->ccm_maxthresh,
"prefetch multiplier", ccm->ccm_maxpfmult);
(void)printf("\tminimum %s = %d, minimum %s = %d.\n",
"threshold", ccm->ccm_minthresh,
"prefetch multiplier", ccm->ccm_minpfmult);
break;
#undef ccm
default:
(void)printf("Unknown page type.");
for (tp = cp + sizeof(*mp), i = 0; i < len; ++i) {
if ((i & 7) == 0)
(void)printf("\n\t%2d: ", i);
(void)printf(" %02x", *tp++);
}
(void)printf(".\n");
break;
}
return (cp + sizeof(*mp) + len);
}
void
pr_sense(fd)
int fd;
{
static struct scsi_fmt_sense s;
register struct scsi_sense *sn;
if (ioctl(fd, SDIOCSENSE, &s) < 0)
(void)fprintf(stderr,
"scsiformat: SDIOCSENSE: %s\n", strerror(errno));
(void)printf("scsi status 0x%x", s.status);
if (s.status & STS_CHECKCOND) {
sn = (struct scsi_sense *)s.sense;
(void)printf(" sense class %d, code %d",
SENSE_ECLASS(sn), SENSE_ECODE(sn));
if (SENSE_ISXSENSE(sn)) {
(void)printf(", key %d", XSENSE_KEY(sn));
if (XSENSE_IVALID(sn))
(void)printf(", blk %d", XSENSE_INFO(sn));
}
}
(void)printf("\n");
}
void
do_format()
{
struct {
struct scsi_ms6 ms; /* mode select header */
struct scsi_ms_bd bd; /* block descriptor */
struct scsi_ms_page_hdr mp; /* ctl mode page hdr */
struct scsi_page_ctlmode cm; /* ctl mode page */
u_char pad[4]; /* ??? */
} msel;
u_char fmtbuf[128];
static struct scsi_cdb modeselect = {
CMD_MODE_SELECT6,
SCSI_MSEL_SCSI2_DATA | SCSI_MSEL_SAVEPAGES, 0, 0,
sizeof(msel), 0
};
static struct scsi_cdb format = { CMD_FORMAT_UNIT };
/* want mostly 0s; set them all zero here */
bzero(&msel, sizeof(msel));
/* one block descriptor */
msel.ms.ms_bdl = sizeof(struct scsi_ms_bd);
/* block length = 512 bytes */
msel.bd.bd_blm = 512 / 256;
msel.bd.bd_bll = 512 % 256;
/*
* In the following, the mystery pad region is copied from
* the original driver. I have no idea what it is for.
* (Anyone got SCSI-2 documents?)
*/
/* mode page parameters: report log-activity exception conditions */
msel.mp.mp_psc = SCSI_MS_PC_CTLMODE;
msel.mp.mp_len = sizeof(msel.cm) + sizeof(msel.pad);
msel.cm.cm_rlec = SCSI_CM_RLEC;
do_command(fd, &modeselect, &msel, sizeof(msel));
bzero(fmtbuf, sizeof(fmtbuf));
do_command(fd, &format, fmtbuf, sizeof(fmtbuf));
}
void
do_command(fd, cdb, buf, len)
int fd;
struct scsi_cdb *cdb;
void *buf;
int len;
{
static int on = 1, off = 0;
int user, ret;
bzero(buf, len);
if (ioctl(fd, SDIOCSFORMAT, &on) < 0) {
(void)fprintf(stderr,
"scsiformat: SDIOCSFORMAT (on): %s\n", strerror(errno));
if (ioctl(fd, SDIOCGFORMAT, &user) == 0 && user != 0)
(void)fprintf(stderr, "scsiformat: pid %d has it\n",
user);
return;
}
ret = ioctl(fd, SDIOCSCSICOMMAND, cdb);
#ifdef COMPAT_HPSCSI
if (ret < 0) {
static const char scsicmdlen[8] = { 6, 10, 0, 0, 0, 12, 0, 0 };
#define SCSICMDLEN(cmd) scsicmdlen[(cmd) >> 5]
struct scsi_fmt_cdb {
int len;
u_char cdb[28];
} sc;
#define OSDIOCSCSICOMMAND _IOW('S', 0x3, struct scsi_fmt_cdb)
sc.len = SCSICMDLEN(cdb->cdb_bytes[0]);
bcopy(cdb->cdb_bytes, sc.cdb, sc.len);
ret = ioctl(fd, OSDIOCSCSICOMMAND, &sc);
}
#endif
if (ret < 0)
(void)fprintf(stderr,
"scsiformat: SDIOCSCSICOMMAND: %s\n", strerror(errno));
else if (read(fd, buf, len) < 0) {
(void)fprintf(stderr,
"scsiformat: read: %s\n", strerror(errno));
pr_sense(fd);
}
if (ioctl(fd, SDIOCSFORMAT, &off) < 0)
(void)fprintf(stderr,
"scsiformat: SDIOCSFORMAT (off): %s\n", strerror(errno));
}
void
usage()
{
(void)fprintf(stderr, "usage: scsiformat [-r] [-p c|d|s|v] device\n");
exit(1);
}

162
sbin/shutdown/shutdown.8 Normal file
View File

@ -0,0 +1,162 @@
.\" Copyright (c) 1988, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)shutdown.8 8.2 (Berkeley) 4/27/95
.\"
.Dd April 27, 1995
.Dt SHUTDOWN 8
.Os BSD 4
.Sh NAME
.Nm shutdown
.Nd "close down the system at a given time"
.Sh SYNOPSIS
.Nm shutdown
.Op Fl
.Op Fl fhkrn
.Ar time
.Op Ar warning-message ...
.Sh DESCRIPTION
.Nm Shutdown
provides an automated shutdown procedure for super-users
to nicely notify users when the system is shutting down,
saving them from system administrators, hackers, and gurus, who
would otherwise not bother with such niceties.
.Pp
Available friendlinesses:
.Bl -tag -width time
.It Fl f
.Nm Shutdown
arranges, in the manner of
.Xr fastboot 8 ,
for the file systems
.Em not to be
checked on reboot.
.It Fl h
The system is halted at the specified
.Ar time
when
.Nm shutdown
execs
.Xr halt 8 .
.It Fl k
Kick everybody off.
The
.Fl k
option
does not actually halt the system, but leaves the
system multi-user with logins disabled (for all but super-user).
.It Fl n
Prevent the normal
.Xr sync 2
before stopping.
.It Fl r
.Nm Shutdown
execs
.Xr reboot 8
at the specified
.Ar time .
.It Ar time
.Ar Time
is the time at which
.Nm shutdown
will bring the system down and
may be the word
.Ar now
(indicating an immediate shutdown) or
specify a future time in one of two formats:
.Ar +number ,
or
.Ar yymmddhhmm ,
where the year, month, and day may be defaulted
to the current system values. The first form brings the system down in
.Ar number
minutes and the second at the absolute time specified.
.It Ar warning-message
Any other arguments comprise the warning message that is broadcast
to users currently logged into the system.
.It Fl
If
.Ql Fl
is supplied as an option, the warning message is read from the standard
input.
.El
.Pp
At intervals, becoming more frequent as apocalypse approaches
and starting at ten hours before shutdown, warning messages are displayed
on the terminals of all users logged in. Five minutes before
shutdown, or immediately if shutdown is in less than 5 minutes,
logins are disabled by creating
.Pa /etc/nologin
and copying the
warning message there. If this file exists when a user attempts to
log in,
.Xr login 1
prints its contents and exits. The file is
removed just before
.Nm shutdown
exits.
.Pp
At shutdown time a message is written in the system log, containing the
time of shutdown, who initiated the shutdown and the reason.
A terminate
signal is then sent to
.Xr init
to bring the system down to single-user state (depending on above
options).
The time of the shutdown and the warning message
are placed in
.Pa /etc/nologin
and should be used to
inform the users about when the system will be back up
and why it is going down (or anything else).
.Sh FILES
.Bl -tag -width /etc/nologin -compact
.It Pa /etc/nologin
tells login not to let anyone log in
.It Pa /fastboot
tells
.Xr rc 8
not to run fsck when rebooting
.El
.Sh SEE ALSO
.Xr login 1 ,
.Xr wall 1 ,
.Xr fastboot 8 ,
.Xr halt 8 ,
.Xr reboot 8
.Sh BACKWARD COMPATIBILITY
The hours and minutes in the second time format may be separated by
a colon (``:'') for backward compatibility.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.0 .

493
sbin/shutdown/shutdown.c Normal file
View File

@ -0,0 +1,493 @@
/*
* Copyright (c) 1988, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1988, 1990, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)shutdown.c 8.4 (Berkeley) 4/28/95";
#endif /* not lint */
#include <sys/param.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/syslog.h>
#include <ctype.h>
#include <fcntl.h>
#include <pwd.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tzfile.h>
#include <unistd.h>
#include "pathnames.h"
#ifdef DEBUG
#undef _PATH_NOLOGIN
#define _PATH_NOLOGIN "./nologin"
#undef _PATH_FASTBOOT
#define _PATH_FASTBOOT "./fastboot"
#endif
#define H *60*60
#define M *60
#define S *1
#define NOLOG_TIME 5*60
struct interval {
int timeleft, timetowait;
} tlist[] = {
10 H, 5 H, 5 H, 3 H, 2 H, 1 H, 1 H, 30 M,
30 M, 10 M, 20 M, 10 M, 10 M, 5 M, 5 M, 3 M,
2 M, 1 M, 1 M, 30 S, 30 S, 30 S,
0, 0,
};
#undef H
#undef M
#undef S
static time_t offset, shuttime;
static int dofast, dohalt, doreboot, killflg, mbuflen;
static char *nosync, *whom, mbuf[BUFSIZ];
void badtime __P((void));
void die_you_gravy_sucking_pig_dog __P((void));
void doitfast __P((void));
void finish __P((int));
void getoffset __P((char *));
void loop __P((void));
void nolog __P((void));
void timeout __P((int));
void timewarn __P((int));
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
register char *p, *endp;
struct passwd *pw;
int arglen, ch, len, readstdin;
#ifndef DEBUG
if (geteuid()) {
(void)fprintf(stderr, "shutdown: NOT super-user\n");
exit(1);
}
#endif
nosync = NULL;
readstdin = 0;
while ((ch = getopt(argc, argv, "-fhknr")) != EOF)
switch (ch) {
case '-':
readstdin = 1;
break;
case 'f':
dofast = 1;
break;
case 'h':
dohalt = 1;
break;
case 'k':
killflg = 1;
break;
case 'n':
nosync = "-n";
break;
case 'r':
doreboot = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
if (dofast && nosync) {
(void)fprintf(stderr,
"shutdown: incompatible switches -f and -n.\n");
usage();
}
if (doreboot && dohalt) {
(void)fprintf(stderr,
"shutdown: incompatible switches -h and -r.\n");
usage();
}
getoffset(*argv++);
if (*argv) {
for (p = mbuf, len = sizeof(mbuf); *argv; ++argv) {
arglen = strlen(*argv);
if ((len -= arglen) <= 2)
break;
if (p != mbuf)
*p++ = ' ';
memmove(p, *argv, arglen);
p += arglen;
}
*p = '\n';
*++p = '\0';
}
if (readstdin) {
p = mbuf;
endp = mbuf + sizeof(mbuf) - 2;
for (;;) {
if (!fgets(p, endp - p + 1, stdin))
break;
for (; *p && p < endp; ++p);
if (p == endp) {
*p = '\n';
*++p = '\0';
break;
}
}
}
mbuflen = strlen(mbuf);
if (offset)
(void)printf("Shutdown at %.24s.\n", ctime(&shuttime));
else
(void)printf("Shutdown NOW!\n");
if (!(whom = getlogin()))
whom = (pw = getpwuid(getuid())) ? pw->pw_name : "???";
#ifdef DEBUG
(void)putc('\n', stdout);
#else
(void)setpriority(PRIO_PROCESS, 0, PRIO_MIN);
{
int forkpid;
forkpid = fork();
if (forkpid == -1) {
perror("shutdown: fork");
exit(1);
}
if (forkpid) {
(void)printf("shutdown: [pid %d]\n", forkpid);
exit(0);
}
}
#endif
openlog("shutdown", LOG_CONS, LOG_AUTH);
loop();
/* NOTREACHED */
}
void
loop()
{
struct interval *tp;
u_int sltime;
int logged;
if (offset <= NOLOG_TIME) {
logged = 1;
nolog();
}
else
logged = 0;
tp = tlist;
if (tp->timeleft < offset)
(void)sleep((u_int)(offset - tp->timeleft));
else {
while (offset < tp->timeleft)
++tp;
/*
* Warn now, if going to sleep more than a fifth of
* the next wait time.
*/
if (sltime = offset - tp->timeleft) {
if (sltime > tp->timetowait / 5)
timewarn(offset);
(void)sleep(sltime);
}
}
for (;; ++tp) {
timewarn(tp->timeleft);
if (!logged && tp->timeleft <= NOLOG_TIME) {
logged = 1;
nolog();
}
(void)sleep((u_int)tp->timetowait);
if (!tp->timeleft)
break;
}
die_you_gravy_sucking_pig_dog();
}
static jmp_buf alarmbuf;
void
timewarn(timeleft)
int timeleft;
{
static int first;
static char hostname[MAXHOSTNAMELEN + 1];
FILE *pf;
char wcmd[MAXPATHLEN + 4];
if (!first++)
(void)gethostname(hostname, sizeof(hostname));
/* undoc -n option to wall suppresses normal wall banner */
(void)snprintf(wcmd, sizeof(wcmd), "%s -n", _PATH_WALL);
if (!(pf = popen(wcmd, "w"))) {
syslog(LOG_ERR, "shutdown: can't find %s: %m", _PATH_WALL);
return;
}
(void)fprintf(pf,
"\007*** %sSystem shutdown message from %s@%s ***\007\n",
timeleft ? "": "FINAL ", whom, hostname);
if (timeleft > 10*60)
(void)fprintf(pf, "System going down at %5.5s\n\n",
ctime(&shuttime) + 11);
else if (timeleft > 59)
(void)fprintf(pf, "System going down in %d minute%s\n\n",
timeleft / 60, (timeleft > 60) ? "s" : "");
else if (timeleft)
(void)fprintf(pf, "System going down in 30 seconds\n\n");
else
(void)fprintf(pf, "System going down IMMEDIATELY\n\n");
if (mbuflen)
(void)fwrite(mbuf, sizeof(*mbuf), mbuflen, pf);
/*
* play some games, just in case wall doesn't come back
* probably unecessary, given that wall is careful.
*/
if (!setjmp(alarmbuf)) {
(void)signal(SIGALRM, timeout);
(void)alarm((u_int)30);
(void)pclose(pf);
(void)alarm((u_int)0);
(void)signal(SIGALRM, SIG_DFL);
}
}
void
timeout(signo)
int signo;
{
longjmp(alarmbuf, 1);
}
void
die_you_gravy_sucking_pig_dog()
{
syslog(LOG_NOTICE, "%s by %s: %s",
doreboot ? "reboot" : dohalt ? "halt" : "shutdown", whom, mbuf);
(void)sleep(2);
(void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
if (killflg) {
(void)printf("\rbut you'll have to do it yourself\r\n");
finish(0);
}
if (dofast)
doitfast();
#ifdef DEBUG
if (doreboot)
(void)printf("reboot");
else if (dohalt)
(void)printf("halt");
if (nosync)
(void)printf(" no sync");
if (dofast)
(void)printf(" no fsck");
(void)printf("\nkill -HUP 1\n");
#else
if (doreboot) {
execle(_PATH_REBOOT, "reboot", "-l", nosync, 0);
syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_REBOOT);
perror("shutdown");
}
else if (dohalt) {
execle(_PATH_HALT, "halt", "-l", nosync, 0);
syslog(LOG_ERR, "shutdown: can't exec %s: %m.", _PATH_HALT);
perror("shutdown");
}
(void)kill(1, SIGTERM); /* to single user */
#endif
finish(0);
}
#define ATOI2(p) (p[0] - '0') * 10 + (p[1] - '0'); p += 2;
void
getoffset(timearg)
register char *timearg;
{
register struct tm *lt;
register char *p;
time_t now;
if (!strcasecmp(timearg, "now")) { /* now */
offset = 0;
return;
}
(void)time(&now);
if (*timearg == '+') { /* +minutes */
if (!isdigit(*++timearg))
badtime();
offset = atoi(timearg) * 60;
shuttime = now + offset;
return;
}
/* handle hh:mm by getting rid of the colon */
for (p = timearg; *p; ++p)
if (!isascii(*p) || !isdigit(*p))
if (*p == ':' && strlen(p) == 3) {
p[0] = p[1];
p[1] = p[2];
p[2] = '\0';
}
else
badtime();
unsetenv("TZ"); /* OUR timezone */
lt = localtime(&now); /* current time val */
switch(strlen(timearg)) {
case 10:
lt->tm_year = ATOI2(timearg);
/* FALLTHROUGH */
case 8:
lt->tm_mon = ATOI2(timearg);
if (--lt->tm_mon < 0 || lt->tm_mon > 11)
badtime();
/* FALLTHROUGH */
case 6:
lt->tm_mday = ATOI2(timearg);
if (lt->tm_mday < 1 || lt->tm_mday > 31)
badtime();
/* FALLTHROUGH */
case 4:
lt->tm_hour = ATOI2(timearg);
if (lt->tm_hour < 0 || lt->tm_hour > 23)
badtime();
lt->tm_min = ATOI2(timearg);
if (lt->tm_min < 0 || lt->tm_min > 59)
badtime();
lt->tm_sec = 0;
if ((shuttime = mktime(lt)) == -1)
badtime();
if ((offset = shuttime - now) < 0) {
(void)fprintf(stderr,
"shutdown: that time is already past.\n");
exit(1);
}
break;
default:
badtime();
}
}
#define FSMSG "fastboot file for fsck\n"
void
doitfast()
{
int fastfd;
if ((fastfd = open(_PATH_FASTBOOT, O_WRONLY|O_CREAT|O_TRUNC,
0664)) >= 0) {
(void)write(fastfd, FSMSG, sizeof(FSMSG) - 1);
(void)close(fastfd);
}
}
#define NOMSG "\n\nNO LOGINS: System going down at "
void
nolog()
{
int logfd;
char *ct;
(void)unlink(_PATH_NOLOGIN); /* in case linked to another file */
(void)signal(SIGINT, finish);
(void)signal(SIGHUP, finish);
(void)signal(SIGQUIT, finish);
(void)signal(SIGTERM, finish);
if ((logfd = open(_PATH_NOLOGIN, O_WRONLY|O_CREAT|O_TRUNC,
0664)) >= 0) {
(void)write(logfd, NOMSG, sizeof(NOMSG) - 1);
ct = ctime(&shuttime);
(void)write(logfd, ct + 11, 5);
(void)write(logfd, "\n\n", 2);
(void)write(logfd, mbuf, strlen(mbuf));
(void)close(logfd);
}
}
void
finish(signo)
int signo;
{
if (!killflg)
(void)unlink(_PATH_NOLOGIN);
exit(0);
}
void
badtime()
{
(void)fprintf(stderr, "shutdown: bad time format.\n");
exit(1);
}
void
usage()
{
fprintf(stderr, "usage: shutdown [-fhknr] shutdowntime [ message ]\n");
exit(1);
}

166
sbin/tunefs/tunefs.8 Normal file
View File

@ -0,0 +1,166 @@
.\" Copyright (c) 1983, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by the University of
.\" California, Berkeley and its contributors.
.\" 4. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)tunefs.8 8.3 (Berkeley) 5/3/95
.\"
.Dd May 3, 1995
.Dt TUNEFS 8
.Os BSD 4.2
.Sh NAME
.Nm tunefs
.Nd tune up an existing file system
.Sh SYNOPSIS
.Nm tunefs
.Op Fl AN
.Op Fl a Ar maxcontig
.Op Fl d Ar rotdelay
.Op Fl e Ar maxbpg
.Op Fl m Ar minfree
.Bk -words
.Op Fl o Ar optimize_preference
.Ek
.Op Fl t Ar trackskew
.Op Ar special | Ar filesys
.Sh DESCRIPTION
The
.Nm tunefs
program is designed to change the dynamic parameters of a file system
which affect the layout policies.
The
.Fl N
flag displays all the settable options
(after any changes from the tuning options)
but does not cause any of them to be changed.
The
.Fl A
flag causes the values to be updated in all the alternate
superblocks instead of just the standard superblock.
If this option is not used,
then use of a backup superblock by
.Xr fsck 8
will lose anything changed by
.Nm tunefs .
The
.Fl A
flag is ignored when the
.Fl N
flag is specified.
.Pp
The parameters which are to be changed are indicated by the flags
given below:
.Bl -tag -width Ds
.It Fl a Ar maxcontig
This specifies the maximum number of contiguous blocks that will
be laid out before forcing a rotational delay (see
.Fl d
below).
The default value is one, since most device drivers require
an interrupt per disk transfer.
Device drivers that can chain several buffers together in a single
transfer should set this to the maximum chain length.
.It Fl d Ar rotdelay
This specifies the expected time (in milliseconds)
to service a transfer completion
interrupt and initiate a new transfer on the same disk.
It is used to decide how much rotational spacing to place between
successive blocks in a file.
.It Fl e Ar maxbpg
This indicates the maximum number of blocks any single file can
allocate out of a cylinder group before it is forced to begin
allocating blocks from another cylinder group.
Typically this value is set to about one quarter of the total blocks
in a cylinder group.
The intent is to prevent any single file from using up all the
blocks in a single cylinder group,
thus degrading access times for all files subsequently allocated
in that cylinder group.
The effect of this limit is to cause big files to do long seeks
more frequently than if they were allowed to allocate all the blocks
in a cylinder group before seeking elsewhere.
For file systems with exclusively large files,
this parameter should be set higher.
.It Fl m Ar minfree
This value specifies the percentage of space held back
from normal users; the minimum free space threshold.
The default value used is 10%.
This value can be set to zero, however up to a factor of three
in throughput will be lost over the performance obtained at a 10%
threshold.
Note that if the value is raised above the current usage level,
users will be unable to allocate files until enough files have
been deleted to get under the higher threshold.
.It Fl o Ar optimize_preference
The file system can either try to minimize the time spent
allocating blocks, or it can attempt to minimize the space
fragmentation on the disk.
If the value of minfree (see above) is less than 10%,
then the file system should optimize for space to avoid
running out of full sized blocks.
For values of minfree greater than or equal to 10%,
fragmentation is unlikely to be problematical, and
the file system can be optimized for time.
.It Fl t Ar trackskew
This specifies the skew in sectors from one track to the next in a cylinder.
The default value is zero, indicating that each track in a cylinder begins at
the same rotational position.
.El
.Sh SEE ALSO
.Xr fs 5 ,
.Xr dumpfs 8 ,
.Xr fsck 8 ,
.Xr newfs 8 ,
.Xr mkfs 8
.Rs
.%A M. McKusick
.%A W. Joy
.%A S. Leffler
.%A R. Fabry
.%T "A Fast File System for UNIX"
.%J "ACM Transactions on Computer Systems 2"
.%N 3
.%P pp 181-197
.%D August 1984
.%O "(reprinted in the BSD System Manager's Manual, SMM:5)"
.Re
.Sh BUGS
This program should work on mounted and active file systems.
Because the super-block is not kept in the buffer cache,
the changes will only take effect if the program
is run on dismounted file systems.
To change the root file system, the system must be rebooted
after the file system is tuned.
.Pp
You can tune a file system, but you can't tune a fish.
.Sh HISTORY
The
.Nm
command appeared in
.Bx 4.2 .

327
sbin/tunefs/tunefs.c Normal file
View File

@ -0,0 +1,327 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1983, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#ifndef lint
static char sccsid[] = "@(#)tunefs.c 8.3 (Berkeley) 5/3/95";
#endif /* not lint */
/*
* tunefs: change layout parameters to an existing file system.
*/
#include <sys/param.h>
#include <sys/stat.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <errno.h>
#include <err.h>
#include <fcntl.h>
#include <fstab.h>
#include <stdio.h>
#include <paths.h>
#include <stdlib.h>
#include <unistd.h>
/* the optimization warning string template */
#define OPTWARN "should optimize for %s with minfree %s %d%%"
union {
struct fs sb;
char pad[MAXBSIZE];
} sbun;
#define sblock sbun.sb
int fi;
long dev_bsize = 1;
void bwrite(daddr_t, char *, int);
int bread(daddr_t, char *, int);
void getsb(struct fs *, char *);
void usage __P((void));
int
main(argc, argv)
int argc;
char *argv[];
{
char *cp, *special, *name;
struct stat st;
int i;
int Aflag = 0, Nflag = 0;
struct fstab *fs;
char *chg[2], device[MAXPATHLEN];
argc--, argv++;
if (argc < 2)
usage();
special = argv[argc - 1];
fs = getfsfile(special);
if (fs)
special = fs->fs_spec;
again:
if (stat(special, &st) < 0) {
if (*special != '/') {
if (*special == 'r')
special++;
(void)sprintf(device, "%s/%s", _PATH_DEV, special);
special = device;
goto again;
}
err(1, "%s", special);
}
if ((st.st_mode & S_IFMT) != S_IFBLK &&
(st.st_mode & S_IFMT) != S_IFCHR)
errx(10, "%s: not a block or character device", special);
getsb(&sblock, special);
chg[FS_OPTSPACE] = "space";
chg[FS_OPTTIME] = "time";
for (; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
for (cp = &argv[0][1]; *cp; cp++)
switch (*cp) {
case 'A':
Aflag++;
continue;
case 'N':
Nflag++;
continue;
case 'a':
name = "maximum contiguous block count";
if (argc < 1)
errx(10, "-a: missing %s", name);
argc--, argv++;
i = atoi(*argv);
if (i < 1)
errx(10, "%s must be >= 1 (was %s)",
name, *argv);
warnx("%s changes from %d to %d",
name, sblock.fs_maxcontig, i);
sblock.fs_maxcontig = i;
continue;
case 'd':
name =
"rotational delay between contiguous blocks";
if (argc < 1)
errx(10, "-d: missing %s", name);
argc--, argv++;
i = atoi(*argv);
warnx("%s changes from %dms to %dms",
name, sblock.fs_rotdelay, i);
sblock.fs_rotdelay = i;
continue;
case 'e':
name =
"maximum blocks per file in a cylinder group";
if (argc < 1)
errx(10, "-e: missing %s", name);
argc--, argv++;
i = atoi(*argv);
if (i < 1)
errx(10, "%s must be >= 1 (was %s)",
name, *argv);
warnx("%s changes from %d to %d",
name, sblock.fs_maxbpg, i);
sblock.fs_maxbpg = i;
continue;
case 'm':
name = "minimum percentage of free space";
if (argc < 1)
errx(10, "-m: missing %s", name);
argc--, argv++;
i = atoi(*argv);
if (i < 0 || i > 99)
errx(10, "bad %s (%s)", name, *argv);
warnx("%s changes from %d%% to %d%%",
name, sblock.fs_minfree, i);
sblock.fs_minfree = i;
if (i >= MINFREE &&
sblock.fs_optim == FS_OPTSPACE)
warnx(OPTWARN, "time", ">=", MINFREE);
if (i < MINFREE &&
sblock.fs_optim == FS_OPTTIME)
warnx(OPTWARN, "space", "<", MINFREE);
continue;
case 'o':
name = "optimization preference";
if (argc < 1)
errx(10, "-o: missing %s", name);
argc--, argv++;
if (strcmp(*argv, chg[FS_OPTSPACE]) == 0)
i = FS_OPTSPACE;
else if (strcmp(*argv, chg[FS_OPTTIME]) == 0)
i = FS_OPTTIME;
else
errx(10, "bad %s (options are `space' or `time')",
name);
if (sblock.fs_optim == i) {
warnx("%s remains unchanged as %s",
name, chg[i]);
continue;
}
warnx("%s changes from %s to %s",
name, chg[sblock.fs_optim], chg[i]);
sblock.fs_optim = i;
if (sblock.fs_minfree >= MINFREE &&
i == FS_OPTSPACE)
warnx(OPTWARN, "time", ">=", MINFREE);
if (sblock.fs_minfree < MINFREE &&
i == FS_OPTTIME)
warnx(OPTWARN, "space", "<", MINFREE);
continue;
case 't':
name = "track skew in sectors";
if (argc < 1)
errx(10, "-t: missing %s", name);
argc--, argv++;
i = atoi(*argv);
if (i < 0)
errx(10, "%s: %s must be >= 0",
*argv, name);
warnx("%s changes from %d to %d",
name, sblock.fs_trackskew, i);
sblock.fs_trackskew = i;
continue;
default:
usage();
}
}
if (argc != 1)
usage();
if (Nflag) {
fprintf(stdout, "tunefs: current settings\n");
fprintf(stdout, "\tmaximum contiguous block count %d\n",
sblock.fs_maxcontig);
fprintf(stdout,
"\trotational delay between contiguous blocks %dms\n",
sblock.fs_rotdelay);
fprintf(stdout,
"\tmaximum blocks per file in a cylinder group %d\n",
sblock.fs_maxbpg);
fprintf(stdout, "\tminimum percentage of free space %d%%\n",
sblock.fs_minfree);
fprintf(stdout, "\toptimization preference: %s\n",
chg[sblock.fs_optim]);
fprintf(stdout, "\ttrack skew %d sectors\n",
sblock.fs_trackskew);
fprintf(stdout, "tunefs: no changes made\n");
exit(0);
}
fi = open(special, 1);
if (fi < 0)
err(3, "cannot open %s for writing", special);
bwrite((daddr_t)SBOFF / dev_bsize, (char *)&sblock, SBSIZE);
if (Aflag)
for (i = 0; i < sblock.fs_ncg; i++)
bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)),
(char *)&sblock, SBSIZE);
close(fi);
exit(0);
}
void
usage()
{
fprintf(stderr, "Usage: tunefs [-AN] tuneup-options special-device\n");
fprintf(stderr, "where tuneup-options are:\n");
fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
fprintf(stderr, "\t-a maximum contiguous blocks\n");
fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
fprintf(stderr, "\t-m minimum percentage of free space\n");
fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
fprintf(stderr, "\t-t track skew in sectors\n");
exit(2);
}
void
getsb(fs, file)
register struct fs *fs;
char *file;
{
fi = open(file, 0);
if (fi < 0)
err(3, "cannot open %s for reading", file);
if (bread((daddr_t)SBOFF, (char *)fs, SBSIZE))
err(4, "%s: bad super block", file);
if (fs->fs_magic != FS_MAGIC)
err(5, "%s: bad magic number", file);
dev_bsize = fs->fs_fsize / fsbtodb(fs, 1);
close(fi);
}
void
bwrite(blk, buf, size)
daddr_t blk;
char *buf;
int size;
{
if (lseek(fi, (off_t)blk * dev_bsize, SEEK_SET) < 0)
err(6, "FS SEEK");
if (write(fi, buf, size) != size)
err(7, "FS WRITE");
}
int
bread(bno, buf, cnt)
daddr_t bno;
char *buf;
int cnt;
{
int i;
if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0)
return(1);
if ((i = read(fi, buf, cnt)) != cnt) {
for(i=0; i<sblock.fs_bsize; i++)
buf[i] = 0;
return (1);
}
return (0);
}