aboutsummaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/Makefile1
-rw-r--r--sbin/atacontrol/Makefile6
-rw-r--r--sbin/atacontrol/Makefile.depend18
-rw-r--r--sbin/atacontrol/atacontrol.8405
-rw-r--r--sbin/atacontrol/atacontrol.c644
-rw-r--r--sbin/camcontrol/camcontrol.8159
-rw-r--r--sbin/camcontrol/camcontrol.c1012
-rw-r--r--sbin/ccdconfig/ccdconfig.86
-rw-r--r--sbin/devd/devd.cc33
-rw-r--r--sbin/devd/devd.conf.59
-rw-r--r--sbin/devd/devd.hh7
-rw-r--r--sbin/dumpfs/dumpfs.c4
-rw-r--r--sbin/ffsinfo/ffsinfo.84
-rw-r--r--sbin/fsck_ffs/dir.c2
-rw-r--r--sbin/fsck_ffs/ea.c2
-rw-r--r--sbin/fsck_ffs/fsck.h92
-rw-r--r--sbin/fsck_ffs/fsutil.c264
-rw-r--r--sbin/fsck_ffs/inode.c57
-rw-r--r--sbin/fsck_ffs/main.c8
-rw-r--r--sbin/fsck_ffs/pass1.c39
-rw-r--r--sbin/fsck_ffs/pass5.c13
-rw-r--r--sbin/fsck_ffs/setup.c21
-rw-r--r--sbin/fsck_ffs/suj.c4
-rw-r--r--sbin/fsdb/fsdb.c7
-rw-r--r--sbin/fsdb/fsdbutil.c5
-rw-r--r--sbin/geom/class/concat/gconcat.84
-rw-r--r--sbin/geom/class/eli/geli.82
-rw-r--r--sbin/geom/class/eli/geom_eli.c37
-rw-r--r--sbin/geom/class/mirror/gmirror.84
-rw-r--r--sbin/geom/class/part/gpart.829
-rw-r--r--sbin/geom/class/raid/graid.810
-rw-r--r--sbin/geom/class/stripe/gstripe.87
-rw-r--r--sbin/gvinum/gvinum.89
-rw-r--r--sbin/hastctl/hastctl.812
-rw-r--r--sbin/hastctl/hastctl.c90
-rw-r--r--sbin/hastd/control.c18
-rw-r--r--sbin/hastd/hast.conf.511
-rw-r--r--sbin/hastd/hast.h21
-rw-r--r--sbin/hastd/hast_proto.c4
-rw-r--r--sbin/hastd/hastd.88
-rw-r--r--sbin/hastd/hastd.c21
-rw-r--r--sbin/hastd/parse.y41
-rw-r--r--sbin/hastd/primary.c204
-rw-r--r--sbin/hastd/refcnt.h57
-rw-r--r--sbin/hastd/secondary.c68
-rw-r--r--sbin/hastd/subr.c64
-rw-r--r--sbin/ipfw/ipfw.885
-rw-r--r--sbin/ipfw/ipfw2.c455
-rw-r--r--sbin/ipfw/ipfw2.h9
-rw-r--r--sbin/ipfw/ipv6.c25
-rw-r--r--sbin/kldload/kldload.82
-rw-r--r--sbin/ldconfig/ldconfig.828
-rw-r--r--sbin/ldconfig/ldconfig.c7
-rw-r--r--sbin/mount_cd9660/mount_cd9660.86
-rw-r--r--sbin/mount_cd9660/mount_cd9660.c6
-rw-r--r--sbin/mount_ext2fs/Makefile14
-rw-r--r--sbin/mount_ext2fs/Makefile.depend19
-rw-r--r--sbin/mount_ext2fs/mount_ext2fs.872
-rw-r--r--sbin/mount_ext2fs/mount_ext2fs.c125
-rw-r--r--sbin/mount_hpfs/Makefile14
-rw-r--r--sbin/mount_hpfs/mount_hpfs.8100
-rw-r--r--sbin/mount_hpfs/mount_hpfs.c244
-rw-r--r--sbin/mount_msdosfs/mount_msdosfs.c7
-rw-r--r--sbin/mount_nfs/mount_nfs.c13
-rw-r--r--sbin/mount_ntfs/Makefile20
-rw-r--r--sbin/mount_ntfs/Makefile.depend21
-rw-r--r--sbin/mount_ntfs/mount_ntfs.8173
-rw-r--r--sbin/mount_ntfs/mount_ntfs.c280
-rw-r--r--sbin/mount_nullfs/mount_nullfs.c5
-rw-r--r--sbin/mount_reiserfs/Makefile13
-rw-r--r--sbin/mount_reiserfs/Makefile.depend19
-rw-r--r--sbin/mount_reiserfs/mount_reiserfs.890
-rw-r--r--sbin/mount_reiserfs/mount_reiserfs.c108
-rw-r--r--sbin/mount_std/Makefile23
-rw-r--r--sbin/mount_std/Makefile.depend19
-rw-r--r--sbin/mount_std/mount_std.8167
-rw-r--r--sbin/mount_std/mount_std.c160
-rw-r--r--sbin/mount_udf/Makefile1
-rw-r--r--sbin/mount_udf/mount_udf.c46
-rw-r--r--sbin/mount_unionfs/mount_unionfs.c5
-rw-r--r--sbin/newfs/mkfs.c6
-rw-r--r--sbin/newfs/newfs.814
-rw-r--r--sbin/newfs/newfs.c11
-rw-r--r--sbin/newfs/newfs.h1
-rw-r--r--sbin/nvmecontrol/nvmecontrol.812
-rw-r--r--sbin/nvmecontrol/nvmecontrol.c101
-rw-r--r--sbin/reboot/boot_i386.87
-rw-r--r--sbin/recoverdisk/recoverdisk.c2
-rw-r--r--sbin/shutdown/shutdown.87
-rw-r--r--sbin/tunefs/tunefs.814
-rw-r--r--sbin/tunefs/tunefs.c43
91 files changed, 2767 insertions, 3375 deletions
diff --git a/sbin/Makefile b/sbin/Makefile
index 16d006da790c..47728449ba41 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -6,7 +6,6 @@
# XXX MISSING: icheck ncheck
SUBDIR=adjkerntz \
- atacontrol \
badsect \
camcontrol \
ccdconfig \
diff --git a/sbin/atacontrol/Makefile b/sbin/atacontrol/Makefile
deleted file mode 100644
index 9881273c2117..000000000000
--- a/sbin/atacontrol/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#$FreeBSD$
-
-PROG= atacontrol
-MAN= atacontrol.8
-
-.include <bsd.prog.mk>
diff --git a/sbin/atacontrol/Makefile.depend b/sbin/atacontrol/Makefile.depend
deleted file mode 100644
index 65ce5679ccda..000000000000
--- a/sbin/atacontrol/Makefile.depend
+++ /dev/null
@@ -1,18 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,}
-
-DIRDEPS = \
- gnu/lib/libgcc \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
- lib/libcompiler_rt \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/sbin/atacontrol/atacontrol.8 b/sbin/atacontrol/atacontrol.8
deleted file mode 100644
index 1468a012c489..000000000000
--- a/sbin/atacontrol/atacontrol.8
+++ /dev/null
@@ -1,405 +0,0 @@
-.\"
-.\" Copyright (c) 2000,2001,2002 Søren Schmidt <sos@FreeBSD.org>
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd October 9, 2011
-.Dt ATACONTROL 8
-.Os
-.Sh NAME
-.Nm atacontrol
-.Nd ATA device driver control program
-.Pp
-This utility was
-.Em deprecated
-in
-.Fx 9.0 .
-See
-.Sx NOTES .
-.Sh SYNOPSIS
-.Nm
-.Aq Ar command
-.Ar args
-.Pp
-.Nm
-.Ic attach
-.Ar channel
-.Nm
-.Ic detach
-.Ar channel
-.Nm
-.Ic reinit
-.Ar channel
-.Nm
-.Ic create
-.Ar type Oo Ar interleave Oc Ar disk0 ... diskN
-.Nm
-.Ic delete
-.Ar raid
-.Nm
-.Ic addspare
-.Ar raid disk
-.Nm
-.Ic rebuild
-.Ar raid
-.Nm
-.Ic status
-.Ar raid
-.Nm
-.Ic mode
-.Ar device
-.Op Ar mode
-.Nm
-.Ic info
-.Ar channel
-.Nm
-.Ic cap
-.Ar device
-.Nm
-.Ic spindown
-.Ar device
-.Op Ar seconds
-.Nm
-.Ic list
-.Sh DESCRIPTION
-The
-.Nm
-utility is a control program that provides the user access and control to the
-.Fx
-.Xr ata 4
-subsystem.
-.Pp
-The
-.Nm
-utility
-can cause severe system crashes and loss of data if used improperly.
-Please
-exercise caution when using this command!
-.Pp
-The
-.Ar channel
-argument is the ATA channel device (e.g., ata0) on which to operate.
-The following commands are supported:
-.Bl -tag -width ".Ic addspare"
-.It Ic attach
-Attach an ATA
-.Ar channel .
-Devices on the channel are probed and attached as
-is done on boot.
-.It Ic detach
-Detach an ATA
-.Ar channel .
-Devices on the channel are removed from the kernel,
-and all outstanding transfers etc.\& are returned back to the system marked
-as failed.
-.It Ic reinit
-Reinitialize an ATA
-.Ar channel .
-Both devices on the channel are reset and
-initialized to the parameters the ATA driver has stored internally.
-Devices that have gone bad and no longer respond to the probe, or devices
-that have physically been removed, are removed from the kernel.
-Likewise are devices that show up during a reset, probed and attached.
-.It Ic create
-Create a
-.Ar type
-ATA RAID.
-The type can be
-.Cm RAID0
-(stripe),
-.Cm RAID1
-(mirror),
-.Cm RAID0+1 ,
-.Cm SPAN
-or
-.Cm JBOD .
-In case the RAID has a
-.Cm RAID0
-component,
-the
-.Ar interleave
-must be specified in number of sectors.
-The RAID will be created
-of the individual disks named
-.Bk -words
-.Ar disk0 ... diskN .
-.Ek
-.Pp
-Although the ATA driver allows for creating an ATA RAID on disks with any
-controller, there are restrictions.
-It is only possible to boot on
-an array if it is either located on a
-.Dq real
-ATA RAID controller like
-the Promise or Highpoint controllers, or if the RAID declared is of
-.Cm RAID1
-or
-.Cm SPAN
-type; in case of a
-.Cm SPAN ,
-the partition to boot must
-reside on the first disk in the SPAN.
-.It Ic delete
-Delete a RAID array on a RAID capable ATA controller.
-.It Ic addspare
-Add a spare disk to an existing RAID.
-.It Ic rebuild
-Rebuild a RAID1 array on a RAID capable ATA controller.
-.It Ic status
-Get the status of an ATA RAID.
-.It Ic mode
-Without the
-.Ar mode
-argument, the current transfer mode of the
-device are printed.
-If the
-.Ar mode
-argument is given, the ATA driver
-is asked to change the transfer mode to the one given.
-The ATA driver
-will reject modes that are not supported by the hardware.
-Modes are given like
-.Dq Li PIO3 ,
-.Dq Li udma2 ,
-.Dq Li udma100 ,
-case does not matter.
-.Pp
-Currently supported modes are:
-.Cm BIOSPIO , PIO0 , PIO1 , PIO2 , PIO3 , PIO4 , WDMA2 , UDMA2
-(alias
-.Cm UDMA33 ) ,
-.Cm UDMA4
-(alias
-.Cm UDMA66 ) ,
-.Cm UDMA5
-(alias
-.Cm UDMA100 ) ,
-.Cm UDMA6
-(alias
-.Cm UDMA133 ) ,
-.Cm SATA150 , SATA300 , USB , USB1 , USB2
-and
-.Cm BIOSDMA .
-.It Ic cap
-Show detailed info about the device on
-.Ar device .
-.It Ic spindown
-Set or report timeout after which the
-.Ar device
-will be spun down.
-To arm the timeout the device needs at least one more request after
-setting the timeout.
-To disable spindown, set the timeout to zero.
-No further actions are needed in this case.
-.It Ic info
-Show info about the attached devices on the
-.Ar channel .
-The device name and manufacture/version strings are shown.
-.It Ic list
-Show info about all attached devices on all active controllers.
-.El
-.Sh EXAMPLES
-To get information on devices attached to a channel,
-use the command line:
-.Pp
-.Dl "atacontrol info ata0"
-.Pp
-To see the devices' current access modes, use the command line:
-.Pp
-.Dl "atacontrol mode ad0"
-.Pp
-which results in the modes of the devices being displayed as a string
-like this:
-.Pp
-.Dl "current mode = UDMA100"
-.Pp
-You can set the mode with
-.Nm
-and a string like the above,
-for example:
-.Pp
-.Dl "atacontrol mode ad0 PIO4"
-.Pp
-The new modes are set as soon as the
-.Nm
-command returns.
-.Pp
-The atacontrol command can also be used to create purely software
-RAID arrays in systems that do NOT have a "real" hardware RAID card
-such as a Highpoint or Promise card.
-A common scenario is a 1U server such as the HP DL320 G4 or G5.
-These servers contain a SATA controller that has 2 channels that can
-contain 2 disks per channel, but the servers are wired to only place
-a single SATA drive on each channel.
-These servers do have a "pseudo" RAID BIOS but it uses a proprietary
-format that is not compatible with the ata driver, and thus their
-RAID bios must be switched off.
-Another common scenario would be a Promise UDMA100 controller card
-that did not contain the Fasttrack RAID BIOS, but did contain 2
-UDMA channels.
-1 disk would be attached to one channel and the other disk would be
-attached to the other channel.
-It is NOT recommended to create such arrays on a primary/secondary
-pair on a SINGLE channel since the throughput of the mirror would be
-severely compromised, the ability to rebuild the array in the event
-of a disk failure would be greatly complicated, and if a disk
-controller electronics failed it could wedge the channel and take
-both disks in the mirror offline.
-(which would defeat the purpose of having a mirror in the first place)
-.Pp
-A quick and dirty way to create such a mirrored array on a new
-system is to boot off the FreeBSD install CD, do a minimal scratch
-install, abort out of the post install questions, and at the command
-line issue the command:
-.Pp
-.Dl "atacontrol create RAID1 ad4 ad6"
-.Pp
-then immediately issue a reboot and boot from the installation CD
-again, and during the installation, you will now see "ar0" listed
-as a disk to install on, and install on that instead of ad4, ad6, etc.
-.Pp
-To get information about the status of a RAID array in the system
-use the command line:
-.Pp
-.Dl "atacontrol status ar0"
-.Pp
-A typical output showing good health on a RAID array might be as
-follows:
-.Pp
-.Dl "ar0: ATA RAID1 subdisks: ad4 ad6 status: READY"
-.Pp
-If a disk drive in a RAID1 array dies the system will mark the disk
-in a DOWN state and change the array status to DEGRADED.
-This can ALSO happen in rare instances due to a power fluctuation or
-other event causing the system to not shutdown properly.
-In that case the output will look like the following:
-.Pp
-.Dl "ar0: ATA RAID1 subdisks: ad4 DOWN status: DEGRADED"
-.Pp
-For a mirrored RAID1 system the server WILL ALLOW you to remove a
-dead SATA disk drive (if the drive is in a hot-swap tray) without
-freezing up the system, so you can remove the disk and while you are
-obtaining a replacement the server can run from the active disk.
-The only caveat is that if the active disk is ad6, the system most
-likely will NOT be able to be rebooted since most systems only
-support booting from the first disk drive.
-.Pp
-To deactivate the DOWN disk ad6 to allow for it to be ejected, use
-the following:
-.Pp
-.Dl "atacontrol detach ata3"
-.Pp
-then eject or remove the disk.
-Note that this only works if the 2 disks in the mirror are on separate
-channels (which is the standard setup for 1-U servers like the HP DL320).
-When the new disk drive is obtained, make sure it is blank, then shut
-the system down.
-At this point, if the system has a RAID array card like a Highpoint or
-Promise controller, you may then boot it into the BIOS of the card and use
-the manufacturers RAID array rebuild utilities to rebuild the array.
-.Pp
-If the system has a pure software array and is not using a "real" ATA
-RAID controller, then shut the system down, make sure that the disk
-that was still working is moved to the bootable position (channel 0
-or whatever the BIOS allows the system to boot from) and the blank disk
-is placed in the secondary position, then boot the system into
-single-user mode and issue the command:
-.Pp
-.Dl "atacontrol addspare ar0 ad6"
-.Dl "atacontrol rebuild ar0"
-.Pp
-If the disk drive did NOT fail and the RAID array became unmirrored due
-to a software glitch or improper shutdown, then a slightly different
-process must be followed.
-Begin by issuing the detach command (this shows the detach for disk ad6,
-the primary master on channel 3):
-.Pp
-.Dl "atacontrol detach ata3"
-.Pp
-then reboot the system into single-user mode.
-(don't just init the system, reboot it so that both disks get probed)
-You will probably see TWO mirrored RAID arrays appear during the boot
-messages, ar0 and ar1.
-Issue the command:
-.Pp
-.Dl "atacontrol delete ar1"
-.Dl "atacontrol addspare ar0 ad6"
-.Pp
-Now a status command will show the array rebuilding.
-.Pp
-To spin down a disk after 30 minutes run
-.Pp
-.Dl "atacontrol spindown ad6 1800"
-.Dl "dd if=/dev/ad6 of=/dev/null count=1"
-.Pp
-While any IO on the disk will arm the timer, using
-.Xr dd 1
-on the raw device will work in all cases, as when the disk is not
-opened at all.
-You can check the current setting with
-.Pp
-.Dl "atacontrol spindown ad6"
-.Pp
-You should not set a spindown timeout on a disk with
-.Pa /
-or syslog logging on it as the disk will be worn out spinning down and
-up all the time.
-.Sh SEE ALSO
-.Xr ata 4 ,
-.Xr cam 4 ,
-.Xr camcontrol 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 4.6 .
-.Pp
-.Nm
-was deprecated in
-.Fx 9.0 .
-.Sh AUTHORS
-.An -nosplit
-The
-.Nm
-utility was written by
-.An S\(/oren Schmidt
-.Aq sos@FreeBSD.org .
-.Pp
-This manual page was written by
-.An S\(/oren Schmidt
-.Aq sos@FreeBSD.org .
-.Sh NOTES
-The
-.Nm
-utility was deprecated in
-.Fx 9.0 .
-When
-.Bd -ragged -offset indent
-.Cd "options ATA_CAM"
-.Ed
-.Pp
-is compiled into the kernel, then
-.Xr camcontrol 8
-must be used instead.
diff --git a/sbin/atacontrol/atacontrol.c b/sbin/atacontrol/atacontrol.c
deleted file mode 100644
index 4b9b74f0ed15..000000000000
--- a/sbin/atacontrol/atacontrol.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*-
- * Copyright (c) 2000 - 2006 Søren Schmidt <sos@FreeBSD.org>
- * 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,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/types.h>
-#include <sys/ata.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-static const char *
-mode2str(int mode)
-{
- switch (mode & 0xff) {
- case ATA_PIO: return "BIOSPIO";
- case ATA_PIO0: return "PIO0";
- case ATA_PIO1: return "PIO1";
- case ATA_PIO2: return "PIO2";
- case ATA_PIO3: return "PIO3";
- case ATA_PIO4: return "PIO4";
- case ATA_WDMA0: return "WDMA0";
- case ATA_WDMA1: return "WDMA1";
- case ATA_WDMA2: return "WDMA2";
- case ATA_UDMA0: return "UDMA0";
- case ATA_UDMA1: return "UDMA1";
- case ATA_UDMA2: return "UDMA33";
- case ATA_UDMA3: return "UDMA44";
- case ATA_UDMA4: return "UDMA66";
- case ATA_UDMA5: return "UDMA100";
- case ATA_UDMA6: return "UDMA133";
- case ATA_DMA: return "BIOSDMA";
- default: return "???";
- }
-}
-
-static const char *
-satarev2str(int mode)
-{
- switch ((mode & 0xff00) >> 8) {
- case 0: return "";
- case 1: return "SATA 1.5Gb/s";
- case 2: return "SATA 3Gb/s";
- case 3: return "SATA 6Gb/s";
- case 0xff: return "SATA";
- default: return "???";
- }
-}
-
-static int
-str2mode(char *str)
-{
- if (!strcasecmp(str, "BIOSPIO")) return ATA_PIO;
- if (!strcasecmp(str, "PIO0")) return ATA_PIO0;
- if (!strcasecmp(str, "PIO1")) return ATA_PIO1;
- if (!strcasecmp(str, "PIO2")) return ATA_PIO2;
- if (!strcasecmp(str, "PIO3")) return ATA_PIO3;
- if (!strcasecmp(str, "PIO4")) return ATA_PIO4;
- if (!strcasecmp(str, "WDMA0")) return ATA_WDMA0;
- if (!strcasecmp(str, "WDMA1")) return ATA_WDMA1;
- if (!strcasecmp(str, "WDMA2")) return ATA_WDMA2;
- if (!strcasecmp(str, "UDMA0")) return ATA_UDMA0;
- if (!strcasecmp(str, "UDMA16")) return ATA_UDMA0;
- if (!strcasecmp(str, "UDMA1")) return ATA_UDMA1;
- if (!strcasecmp(str, "UDMA25")) return ATA_UDMA1;
- if (!strcasecmp(str, "UDMA2")) return ATA_UDMA2;
- if (!strcasecmp(str, "UDMA33")) return ATA_UDMA2;
- if (!strcasecmp(str, "UDMA3")) return ATA_UDMA3;
- if (!strcasecmp(str, "UDMA44")) return ATA_UDMA3;
- if (!strcasecmp(str, "UDMA4")) return ATA_UDMA4;
- if (!strcasecmp(str, "UDMA66")) return ATA_UDMA4;
- if (!strcasecmp(str, "UDMA5")) return ATA_UDMA5;
- if (!strcasecmp(str, "UDMA100")) return ATA_UDMA5;
- if (!strcasecmp(str, "UDMA6")) return ATA_UDMA6;
- if (!strcasecmp(str, "UDMA133")) return ATA_UDMA6;
- if (!strcasecmp(str, "BIOSDMA")) return ATA_DMA;
- return -1;
-}
-
-static void
-usage(void)
-{
- fprintf(stderr,
- "usage: atacontrol <command> args:\n"
- " atacontrol list\n"
- " atacontrol info channel\n"
- " atacontrol attach channel\n"
- " atacontrol detach channel\n"
- " atacontrol reinit channel\n"
- " atacontrol create type [interleave] disk0 ... diskN\n"
- " atacontrol delete array\n"
- " atacontrol addspare array disk\n"
- " atacontrol rebuild array\n"
- " atacontrol status array\n"
- " atacontrol mode device [mode]\n"
- " atacontrol cap device\n"
- " atacontrol spindown device [seconds]\n"
- );
- exit(EX_USAGE);
-}
-
-static int
-version(int ver)
-{
- int bit;
-
- if (ver == 0xffff)
- return 0;
- for (bit = 15; bit >= 0; bit--)
- if (ver & (1<<bit))
- return bit;
- return 0;
-}
-
-static void
-param_print(struct ata_params *parm)
-{
- printf("<%.40s/%.8s> ", parm->model, parm->revision);
- if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
- if (parm->satacapabilities & ATA_SATA_GEN2)
- printf("SATA revision 2.x\n");
- else if (parm->satacapabilities & ATA_SATA_GEN1)
- printf("SATA revision 1.x\n");
- else
- printf("Unknown SATA revision\n");
- }
- else
- printf("ATA/ATAPI revision %d\n", version(parm->version_major));
-}
-
-static void
-cap_print(struct ata_params *parm)
-{
- u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
- ((u_int32_t)parm->lba_size_2 << 16);
-
- u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
- ((u_int64_t)parm->lba_size48_2 << 16) |
- ((u_int64_t)parm->lba_size48_3 << 32) |
- ((u_int64_t)parm->lba_size48_4 << 48);
-
- printf("\n");
- printf("Protocol ");
- if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
- if (parm->satacapabilities & ATA_SATA_GEN2)
- printf("SATA revision 2.x\n");
- else if (parm->satacapabilities & ATA_SATA_GEN1)
- printf("SATA revision 1.x\n");
- else
- printf("Unknown SATA revision\n");
- }
- else
- printf("ATA/ATAPI revision %d\n", version(parm->version_major));
- printf("device model %.40s\n", parm->model);
- printf("serial number %.20s\n", parm->serial);
- printf("firmware revision %.8s\n", parm->revision);
-
- printf("cylinders %d\n", parm->cylinders);
- printf("heads %d\n", parm->heads);
- printf("sectors/track %d\n", parm->sectors);
-
- if (parm->config == ATA_PROTO_CFA ||
- (parm->support.command2 & ATA_SUPPORT_CFA))
- printf("CFA supported\n");
-
- printf("lba%ssupported ",
- parm->capabilities1 & ATA_SUPPORT_LBA ? " " : " not ");
- if (lbasize)
- printf("%d sectors\n", lbasize);
- else
- printf("\n");
-
- printf("lba48%ssupported ",
- parm->support.command2 & ATA_SUPPORT_ADDRESS48 ? " " : " not ");
- if (lbasize48)
- printf("%ju sectors\n", (uintmax_t)lbasize48);
- else
- printf("\n");
-
- printf("dma%ssupported\n",
- parm->capabilities1 & ATA_SUPPORT_DMA ? " " : " not ");
-
- printf("overlap%ssupported\n",
- parm->capabilities1 & ATA_SUPPORT_OVERLAP ? " " : " not ");
-
- printf("\nFeature "
- "Support Enable Value Vendor\n");
-
- printf("write cache %s %s\n",
- parm->support.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no",
- parm->enabled.command1 & ATA_SUPPORT_WRITECACHE ? "yes" : "no");
-
- printf("read ahead %s %s\n",
- parm->support.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no",
- parm->enabled.command1 & ATA_SUPPORT_LOOKAHEAD ? "yes" : "no");
-
- if (parm->satacapabilities && parm->satacapabilities != 0xffff) {
- printf("Native Command Queuing (NCQ) %s %s"
- " %d/0x%02X\n",
- parm->satacapabilities & ATA_SUPPORT_NCQ ?
- "yes" : "no", " -",
- (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
- ATA_QUEUE_LEN(parm->queue) : 0,
- (parm->satacapabilities & ATA_SUPPORT_NCQ) ?
- ATA_QUEUE_LEN(parm->queue) : 0);
- }
- printf("Tagged Command Queuing (TCQ) %s %s %d/0x%02X\n",
- parm->support.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
- parm->enabled.command2 & ATA_SUPPORT_QUEUED ? "yes" : "no",
- ATA_QUEUE_LEN(parm->queue), ATA_QUEUE_LEN(parm->queue));
-
- printf("SMART %s %s\n",
- parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
- parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
-
- printf("microcode download %s %s\n",
- parm->support.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no",
- parm->enabled.command2 & ATA_SUPPORT_MICROCODE ? "yes" : "no");
-
- printf("security %s %s\n",
- parm->support.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no",
- parm->enabled.command1 & ATA_SUPPORT_SECURITY ? "yes" : "no");
-
- printf("power management %s %s\n",
- parm->support.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no",
- parm->enabled.command1 & ATA_SUPPORT_POWERMGT ? "yes" : "no");
-
- printf("advanced power management %s %s %d/0x%02X\n",
- parm->support.command2 & ATA_SUPPORT_APM ? "yes" : "no",
- parm->enabled.command2 & ATA_SUPPORT_APM ? "yes" : "no",
- parm->apm_value, parm->apm_value);
-
- printf("automatic acoustic management %s %s "
- "%d/0x%02X %d/0x%02X\n",
- parm->support.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
- parm->enabled.command2 & ATA_SUPPORT_AUTOACOUSTIC ? "yes" :"no",
- ATA_ACOUSTIC_CURRENT(parm->acoustic),
- ATA_ACOUSTIC_CURRENT(parm->acoustic),
- ATA_ACOUSTIC_VENDOR(parm->acoustic),
- ATA_ACOUSTIC_VENDOR(parm->acoustic));
-}
-
-static void
-ata_cap_print(int fd)
-{
- struct ata_params params;
-
- if (ioctl(fd, IOCATAGPARM, &params) < 0)
- err(1, "ioctl(IOCATAGPARM)");
- cap_print(&params);
-}
-
-static void
-info_print(int fd, int channel, int prchan)
-{
- struct ata_ioc_devices devices;
-
- devices.channel = channel;
-
- if (ioctl(fd, IOCATADEVICES, &devices) < 0) {
- if (!prchan)
- err(1, "ioctl(IOCATADEVICES)");
- return;
- }
- if (prchan)
- printf("ATA channel %d:\n", channel);
- printf("%sMaster: ", prchan ? " " : "");
- if (*devices.name[0]) {
- printf("%4.4s ", devices.name[0]);
- param_print(&devices.params[0]);
- }
- else
- printf(" no device present\n");
- printf("%sSlave: ", prchan ? " " : "");
- if (*devices.name[1]) {
- printf("%4.4s ", devices.name[1]);
- param_print(&devices.params[1]);
- }
- else
- printf(" no device present\n");
-}
-
-static void
-ata_spindown(int fd, const char *dev, const char *arg)
-{
- int tmo;
-
- if (arg != NULL) {
- tmo = strtoul(arg, NULL, 0);
- if (ioctl(fd, IOCATASSPINDOWN, &tmo) < 0)
- err(1, "ioctl(IOCATASSPINDOWN)");
- } else {
- if (ioctl(fd, IOCATAGSPINDOWN, &tmo) < 0)
- err(1, "ioctl(IOCATAGSPINDOWN)");
- if (tmo == 0)
- printf("%s: idle spin down disabled\n", dev);
- else
- printf("%s: spin down after %d seconds idle\n",
- dev, tmo);
- }
-}
-
-static int
-open_dev(const char *arg, int mode)
-{
- int disk, fd;
- char device[64];
-
- if (!(sscanf(arg, "ad%d", &disk) == 1 ||
- sscanf(arg, "acd%d", &disk) == 1 ||
- sscanf(arg, "afd%d", &disk) == 1 ||
- sscanf(arg, "ast%d", &disk) == 1)) {
- fprintf(stderr, "atacontrol: Invalid device %s\n", arg);
- exit(EX_USAGE);
- }
- sprintf(device, "/dev/%s", arg);
- if ((fd = open(device, mode)) < 0)
- err(1, "device not found");
- return (fd);
-}
-
-static int
-ar_arg(const char *arg)
-{
- int array;
-
- if (!(sscanf(arg, "ar%d", &array) == 1)) {
- fprintf(stderr, "atacontrol: Invalid array %s\n", arg);
- exit(EX_USAGE);
- }
- return (array);
-}
-
-static int
-ata_arg(const char *arg)
-{
- int channel;
-
- if (!(sscanf(arg, "ata%d", &channel) == 1)) {
- fprintf(stderr, "atacontrol: Invalid channel %s\n", arg);
- exit(EX_USAGE);
- }
- return (channel);
-}
-
-int
-main(int argc, char **argv)
-{
- int fd, mode, channel, array;
-
- if (feature_present("ata_cam")) {
- errx(1, "\nATA_CAM option is enabled in kernel.\n"
- "Please use camcontrol instead.");
- }
-
- if (argc < 2)
- usage();
-
- if (!strcmp(argv[1], "mode") && (argc == 3 || argc == 4)) {
- fd = open_dev(argv[2], O_RDONLY);
- if (argc == 4) {
- mode = str2mode(argv[3]);
- if (mode == -1)
- errx(1, "unknown mode");
- if (ioctl(fd, IOCATASMODE, &mode) < 0)
- warn("ioctl(IOCATASMODE)");
- }
- if (argc == 3 || argc == 4) {
- if (ioctl(fd, IOCATAGMODE, &mode) < 0)
- err(1, "ioctl(IOCATAGMODE)");
- printf("current mode = %s %s\n",
- mode2str(mode), satarev2str(mode));
- }
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "cap") && argc == 3) {
- fd = open_dev(argv[2], O_RDONLY);
- ata_cap_print(fd);
- exit(EX_OK);
- }
-
- if (!strcmp(argv[1], "spindown") && (argc == 3 || argc == 4)) {
- fd = open_dev(argv[2], O_RDONLY);
- ata_spindown(fd, argv[2], argv[3]);
- exit(EX_OK);
- }
-
- if ((fd = open("/dev/ata", O_RDWR)) < 0)
- err(1, "control device not found");
-
- if (!strcmp(argv[1], "list") && argc == 2) {
- int maxchannel;
-
- if (ioctl(fd, IOCATAGMAXCHANNEL, &maxchannel) < 0)
- err(1, "ioctl(IOCATAGMAXCHANNEL)");
- for (channel = 0; channel < maxchannel; channel++)
- info_print(fd, channel, 1);
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "info") && argc == 3) {
- channel = ata_arg(argv[2]);
- info_print(fd, channel, 0);
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "detach") && argc == 3) {
- channel = ata_arg(argv[2]);
- if (ioctl(fd, IOCATADETACH, &channel) < 0)
- err(1, "ioctl(IOCATADETACH)");
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "attach") && argc == 3) {
- channel = ata_arg(argv[2]);
- if (ioctl(fd, IOCATAATTACH, &channel) < 0)
- err(1, "ioctl(IOCATAATTACH)");
- info_print(fd, channel, 0);
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "reinit") && argc == 3) {
- channel = ata_arg(argv[2]);
- if (ioctl(fd, IOCATAREINIT, &channel) < 0)
- warn("ioctl(IOCATAREINIT)");
- info_print(fd, channel, 0);
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "create")) {
- int disk, dev, offset;
- struct ata_ioc_raid_config config;
-
- bzero(&config, sizeof(config));
- if (argc > 2) {
- if (!strcasecmp(argv[2], "RAID0") ||
- !strcasecmp(argv[2], "stripe"))
- config.type = AR_RAID0;
- if (!strcasecmp(argv[2], "RAID1") ||
- !strcasecmp(argv[2],"mirror"))
- config.type = AR_RAID1;
- if (!strcasecmp(argv[2], "RAID0+1") ||
- !strcasecmp(argv[2],"RAID10"))
- config.type = AR_RAID01;
- if (!strcasecmp(argv[2], "RAID5"))
- config.type = AR_RAID5;
- if (!strcasecmp(argv[2], "SPAN"))
- config.type = AR_SPAN;
- if (!strcasecmp(argv[2], "JBOD"))
- config.type = AR_JBOD;
- }
- if (!config.type) {
- fprintf(stderr, "atacontrol: Invalid RAID type %s\n",
- argv[2]);
- fprintf(stderr, "atacontrol: Valid RAID types: \n");
- fprintf(stderr, " stripe | mirror | "
- "RAID0 | RAID1 | RAID0+1 | RAID5 | "
- "SPAN | JBOD\n");
- exit(EX_USAGE);
- }
-
- if (config.type == AR_RAID0 ||
- config.type == AR_RAID01 ||
- config.type == AR_RAID5) {
- if (argc < 4 ||
- !sscanf(argv[3], "%d", &config.interleave) == 1) {
- fprintf(stderr,
- "atacontrol: Invalid interleave %s\n",
- argv[3]);
- exit(EX_USAGE);
- }
- offset = 4;
- }
- else
- offset = 3;
-
- for (disk = 0; disk < 16 && (offset + disk) < argc; disk++) {
- if (!(sscanf(argv[offset + disk], "ad%d", &dev) == 1)) {
- fprintf(stderr,
- "atacontrol: Invalid disk %s\n",
- argv[offset + disk]);
- exit(EX_USAGE);
- }
- config.disks[disk] = dev;
- }
-
- if ((config.type == AR_RAID1 || config.type == AR_RAID01) &&
- disk < 2) {
- fprintf(stderr, "atacontrol: At least 2 disks must be "
- "specified\n");
- exit(EX_USAGE);
- }
-
- config.total_disks = disk;
- if (ioctl(fd, IOCATARAIDCREATE, &config) < 0)
- err(1, "ioctl(IOCATARAIDCREATE)");
- else
- printf("ar%d created\n", config.lun);
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "delete") && argc == 3) {
- array = ar_arg(argv[2]);
- if (ioctl(fd, IOCATARAIDDELETE, &array) < 0)
- warn("ioctl(IOCATARAIDDELETE)");
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "addspare") && argc == 4) {
- struct ata_ioc_raid_config config;
-
- config.lun = ar_arg(argv[2]);
- if (!(sscanf(argv[3], "ad%d", &config.disks[0]) == 1)) {
- fprintf(stderr,
- "atacontrol: Invalid disk %s\n", argv[3]);
- usage();
- }
- if (ioctl(fd, IOCATARAIDADDSPARE, &config) < 0)
- warn("ioctl(IOCATARAIDADDSPARE)");
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "rebuild") && argc == 3) {
- array = ar_arg(argv[2]);
- if (ioctl(fd, IOCATARAIDREBUILD, &array) < 0)
- warn("ioctl(IOCATARAIDREBUILD)");
- else {
- char device[64];
- char *buffer;
- ssize_t len;
- int arfd;
-
- if (daemon(0, 1) == -1)
- err(1, "daemon");
- nice(20);
- snprintf(device, sizeof(device), "/dev/ar%d",
- array);
- if ((arfd = open(device, O_RDONLY)) == -1)
- err(1, "open %s", device);
- if ((buffer = malloc(1024 * 1024)) == NULL)
- err(1, "malloc");
- while ((len = read(arfd, buffer, 1024 * 1024)) > 0)
- ;
- if (len == -1)
- err(1, "read");
- else
- fprintf(stderr,
- "atacontrol: ar%d rebuild completed\n",
- array);
- free(buffer);
- close(arfd);
- }
- exit(EX_OK);
- }
- if (!strcmp(argv[1], "status") && argc == 3) {
- struct ata_ioc_raid_status status;
- int i, lun, state;
-
- status.lun = ar_arg(argv[2]);
- if (ioctl(fd, IOCATARAIDSTATUS, &status) < 0)
- err(1, "ioctl(IOCATARAIDSTATUS)");
-
- printf("ar%d: ATA ", status.lun);
- switch (status.type) {
- case AR_RAID0:
- printf("RAID0 stripesize=%d", status.interleave);
- break;
- case AR_RAID1:
- printf("RAID1");
- break;
- case AR_RAID01:
- printf("RAID0+1 stripesize=%d", status.interleave);
- break;
- case AR_RAID5:
- printf("RAID5 stripesize=%d", status.interleave);
- break;
- case AR_JBOD:
- printf("JBOD");
- break;
- case AR_SPAN:
- printf("SPAN");
- break;
- }
- printf(" status: ");
- switch (status.status) {
- case AR_READY:
- printf("READY\n");
- break;
- case AR_READY | AR_DEGRADED:
- printf("DEGRADED\n");
- break;
- case AR_READY | AR_DEGRADED | AR_REBUILDING:
- printf("REBUILDING %d%% completed\n",
- status.progress);
- break;
- default:
- printf("BROKEN\n");
- }
- printf(" subdisks:\n");
- for (i = 0; i < status.total_disks; i++) {
- printf(" %2d ", i);
- lun = status.disks[i].lun;
- state = status.disks[i].state;
- if (lun < 0)
- printf("---- ");
- else
- printf("ad%-2d ", lun);
- if (state & AR_DISK_ONLINE)
- printf("ONLINE");
- else if (state & AR_DISK_SPARE)
- printf("SPARE");
- else if (state & AR_DISK_PRESENT)
- printf("OFFLINE");
- else
- printf("MISSING");
- printf("\n");
- }
- exit(EX_OK);
- }
- usage();
- exit(EX_OK);
-}
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 66a45eb7af1d..7a13aa408220 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -228,6 +228,21 @@
.Op Fl y
.Op Fl s
.Nm
+.Ic security
+.Op device id
+.Op generic args
+.Op Fl d Ar pwd
+.Op Fl e Ar pwd
+.Op Fl f
+.Op Fl h Ar pwd
+.Op Fl k Ar pwd
+.Op Fl l Ar high|maximum
+.Op Fl q
+.Op Fl s Ar pwd
+.Op Fl T Ar timeout
+.Op Fl U Ar user|master
+.Op Fl y
+.Nm
.Ic help
.Sh DESCRIPTION
The
@@ -361,7 +376,7 @@ There are a couple of options to modify the output:
.It Fl c
Just print out a count of LUNs, not the actual LUN numbers.
.It Fl l
-Just print out the LUNs, and don't print out the count.
+Just print out the LUNs, and do not print out the count.
.It Fl r Ar reporttype
Specify the type of report to request from the target:
.Bl -tag -width 012345678
@@ -1072,6 +1087,124 @@ specifies automatic standby timer value in seconds. Value 0 disables timer.
.It Ic sleep
Put ATA device into SLEEP state. Note that the only way get device out of
this state may be reset.
+.It Ic security
+Update or report security settings, using an ATA identify command (0xec).
+By default,
+.Nm
+will print out the security support and associated settings of the device.
+The
+.Ic security
+command takes several arguments:
+.Bl -tag -width 0n
+.It Fl d Ar pwd
+.Pp
+Disable device security using the given password for the selected user according
+to the devices configured security level.
+.It Fl e Ar pwd
+.Pp
+Erase the device using the given password for the selected user.
+.Pp
+.Em WARNING! WARNING! WARNING!
+.Pp
+Issuing a secure erase will
+.Em ERASE ALL
+user data on the device and may take several hours to complete.
+.Pp
+When this command is used against an SSD drive all its cells will be marked as
+empty, restoring it to factory default write performance. For SSD's this action
+usually takes just a few seconds.
+.It Fl f
+.Pp
+Freeze the security configuration of the specified device.
+.Pp
+After command completion any other commands that update the device lock mode
+shall be command aborted.
+Frozen mode is disabled by power-off or hardware reset.
+.It Fl h Ar pwd
+.Pp
+Enhanced erase the device using the given password for the selected user.
+.Pp
+.Em WARNING! WARNING! WARNING!
+.Pp
+Issuing an enhanced secure erase will
+.Em ERASE ALL
+user data on the device and may take several hours to complete.
+.Pp
+An enhanced erase writes predetermined data patterns to all user data areas,
+all previously written user data shall be overwritten, including sectors that
+are no longer in use due to reallocation.
+.It Fl k Ar pwd
+.Pp
+Unlock the device using the given password for the selected user according to
+the devices configured security level.
+.It Fl l Ar high|maximum
+.Pp
+Specifies which security level to set when issuing a
+.Fl s Ar pwd
+command. The security level determines device behavior when the master
+password is used to unlock the device. When the security level is set to high
+the device requires the unlock command and the master password to unlock.
+When the security level is set to maximum the device requires a secure erase
+with the master password to unlock.
+.Pp
+This option must be used in conjunction with one of the security action commands.
+.Pp
+Defaults to
+.Em high
+.It Fl q
+.Pp
+Be quiet, do not print any status messages.
+This option will not disable the questions, however.
+To disable questions, use the
+.Fl y
+argument, below.
+.It Fl s Ar pwd
+.Pp
+Password the device (enable security) using the given password for the selected
+user. This option can be combined with other options such as
+.Fl e Em pwd
+.Pp
+A master password may be set in a addition to the user password. The purpose of
+the master password is to allow an administrator to establish a password that
+is kept secret from the user, and which may be used to unlock the device if the
+user password is lost.
+.Pp
+.Em Note:
+Setting the master password does not enable device security.
+.Pp
+If the master password is set and the drive supports a Master Revision Code
+feature the Master Password Revision Code will be decremented.
+.It Fl T Ar timeout
+.Pp
+Overrides the default timeout, specified in seconds, used for both
+.Fl e
+and
+.Fl h
+this is useful if your system has problems processing long timeouts correctly.
+.Pp
+Usually the timeout is calculated from the information stored on the drive if
+present, otherwise it defaults to 2 hours.
+.It Fl U Ar user|master
+.Pp
+Specifies which user to set / use for the running action command, valid values
+are user or master and defaults to master if not set.
+.Pp
+This option must be used in conjunction with one of the security action commands.
+.Pp
+Defaults to
+.Em master
+.It Fl y
+.Pp
+Confirm yes to dangerous options such as
+.Fl e
+without prompting for confirmation.
+.Pp
+.El
+If the password specified for any action commands doesn't match the configured
+password for the specified user the command will fail.
+.Pp
+The password in all cases is limited to 32 characters, longer passwords will
+fail.
.It Ic fwdownload
Program firmware of the named SCSI device using the image file provided.
.Pp
@@ -1240,6 +1373,30 @@ camcontrol smpcmd ses0 -v -r 4 "40 0 00 0" -R 1020 "s9 i1"
Send the SMP REPORT GENERAL command to ses0, and display the number of PHYs
it contains.
Display SMP errors if the command fails.
+.Bd -literal -offset indent
+camcontrol security ada0
+.Ed
+.Pp
+Report security support and settings for ada0
+.Bd -literal -offset indent
+camcontrol security ada0 -u user -s MyPass
+.Ed
+.Pp
+Enable security on device ada0 with the password MyPass
+.Bd -literal -offset indent
+camcontrol security ada0 -u user -e MyPass
+.Ed
+.Pp
+Secure erase ada0 which has had security enabled with user password MyPass
+.Pp
+.Em WARNING! WARNING! WARNING!
+.Pp
+This will
+.Em ERASE ALL
+data from the device, so backup your data before using!
+.Pp
+This command can be used used against an SSD drive to restoring it to
+factory default write performance.
.Sh SEE ALSO
.Xr cam 3 ,
.Xr cam_cdbparse 3 ,
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index a3c7f0515c9d..90ceb9a7075e 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -87,7 +87,8 @@ typedef enum {
CAM_CMD_SMP_PC = 0x00000019,
CAM_CMD_SMP_PHYLIST = 0x0000001a,
CAM_CMD_SMP_MANINFO = 0x0000001b,
- CAM_CMD_DOWNLOAD_FW = 0x0000001c
+ CAM_CMD_DOWNLOAD_FW = 0x0000001c,
+ CAM_CMD_SECURITY = 0x0000001d
} cam_cmdmask;
typedef enum {
@@ -140,6 +141,7 @@ static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
static const char smprg_opts[] = "l";
static const char smppc_opts[] = "a:A:d:lm:M:o:p:s:S:T:";
static const char smpphylist_opts[] = "lq";
+static char pwd_opt;
#endif
static struct camcontrol_opts option_table[] = {
@@ -183,6 +185,7 @@ static struct camcontrol_opts option_table[] = {
{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
+ {"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"},
#endif /* MINIMALISTIC */
{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
@@ -274,7 +277,10 @@ static int scsireportluns(struct cam_device *device, int argc, char **argv,
static int scsireadcapacity(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int atapm(struct cam_device *device, int argc, char **argv,
- char *combinedopt, int retry_count, int timeout);
+ char *combinedopt, int retry_count, int timeout);
+static int atasecurity(struct cam_device *device, int retry_count, int timeout,
+ int argc, char **argv, char *combinedopt);
+
#endif /* MINIMALISTIC */
#ifndef min
#define min(a,b) (((a)<(b))?(a):(b))
@@ -1328,55 +1334,93 @@ atacapprint(struct ata_params *parm)
printf("free-fall %s %s\n",
parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no",
parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no");
- printf("data set management (TRIM) %s\n",
- parm->support_dsm & ATA_SUPPORT_DSM_TRIM ? "yes" : "no");
+ printf("Data Set Management (DSM/TRIM) ");
+ if (parm->support_dsm & ATA_SUPPORT_DSM_TRIM) {
+ printf("yes\n");
+ printf("DSM - max 512byte blocks ");
+ if (parm->max_dsm_blocks == 0x00)
+ printf("yes not specified\n");
+ else
+ printf("yes %d\n",
+ parm->max_dsm_blocks);
+
+ printf("DSM - deterministic read ");
+ if (parm->support3 & ATA_SUPPORT_DRAT) {
+ if (parm->support3 & ATA_SUPPORT_RZAT)
+ printf("yes zeroed\n");
+ else
+ printf("yes any value\n");
+ } else {
+ printf("no\n");
+ }
+ } else {
+ printf("no\n");
+ }
}
static int
-ataidentify(struct cam_device *device, int retry_count, int timeout)
+scsi_cam_pass_16_send(struct cam_device *device, union ccb *ccb, int quiet)
{
- union ccb *ccb;
- struct ata_params *ident_buf;
- struct ccb_getdev cgd;
- u_int i, error = 0;
- int16_t *ptr;
+ struct ata_pass_16 *ata_pass_16;
+ struct ata_cmd ata_cmd;
- if (get_cgd(device, &cgd) != 0) {
- warnx("couldn't get CGD");
- return(1);
- }
- ccb = cam_getccb(device);
+ ata_pass_16 = (struct ata_pass_16 *)ccb->csio.cdb_io.cdb_bytes;
+ ata_cmd.command = ata_pass_16->command;
+ ata_cmd.control = ata_pass_16->control;
+ ata_cmd.features = ata_pass_16->features;
- if (ccb == NULL) {
- warnx("couldn't allocate CCB");
- return(1);
+ if (arglist & CAM_ARG_VERBOSE) {
+ warnx("sending ATA %s via pass_16 with timeout of %u msecs",
+ ata_op_string(&ata_cmd),
+ ccb->csio.ccb_h.timeout);
}
- /* cam_getccb cleans up the header, caller has to zero the payload */
- bzero(&(&ccb->ccb_h)[1],
- sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
- ptr = (uint16_t *)malloc(sizeof(struct ata_params));
+ if (arglist & CAM_ARG_ERR_RECOVER)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
- if (ptr == NULL) {
- cam_freeccb(ccb);
- warnx("can't malloc memory for identify\n");
- return(1);
+ if (cam_send_ccb(device, ccb) < 0) {
+ if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
+ warn("error sending ATA %s via pass_16",
+ ata_op_string(&ata_cmd));
+ }
+
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
+
+ return (1);
}
- bzero(ptr, sizeof(struct ata_params));
- cam_fill_ataio(&ccb->ataio,
- retry_count,
- NULL,
- /*flags*/CAM_DIR_IN,
- MSG_SIMPLE_Q_TAG,
- /*data_ptr*/(u_int8_t *)ptr,
- /*dxfer_len*/sizeof(struct ata_params),
- timeout ? timeout : 30 * 1000);
- if (cgd.protocol == PROTO_ATA)
- ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
- else
- ata_28bit_cmd(&ccb->ataio, ATA_ATAPI_IDENTIFY, 0, 0, 0);
+ if (!(ata_pass_16->flags & AP_FLAG_CHK_COND) &&
+ (ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
+ warnx("ATA %s via pass_16 failed",
+ ata_op_string(&ata_cmd));
+ }
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
+
+ return (1);
+ }
+
+ return (0);
+}
+
+
+static int
+ata_cam_send(struct cam_device *device, union ccb *ccb, int quiet)
+{
+ if (arglist & CAM_ARG_VERBOSE) {
+ warnx("sending ATA %s with timeout of %u msecs",
+ ata_op_string(&(ccb->ataio.cmd)),
+ ccb->ataio.ccb_h.timeout);
+ }
/* Disable freezing the device queue */
ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
@@ -1385,47 +1429,247 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
if (cam_send_ccb(device, ccb) < 0) {
- perror("error sending ATA identify");
+ if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
+ warn("error sending ATA %s",
+ ata_op_string(&(ccb->ataio.cmd)));
+ }
if (arglist & CAM_ARG_VERBOSE) {
cam_error_print(device, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
}
- free(ptr);
- cam_freeccb(ccb);
- return(1);
+ return (1);
}
if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
- error = 1;
+ if (quiet != 1 || arglist & CAM_ARG_VERBOSE) {
+ warnx("ATA %s failed: %d",
+ ata_op_string(&(ccb->ataio.cmd)), quiet);
+ }
if (arglist & CAM_ARG_VERBOSE) {
cam_error_print(device, ccb, CAM_ESF_ALL,
CAM_EPF_ALL, stderr);
}
+
+ return (1);
}
- cam_freeccb(ccb);
+ return (0);
+}
+
+static int
+ata_do_pass_16(struct cam_device *device, union ccb *ccb, int retries,
+ u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
+ u_int8_t tag_action, u_int8_t command, u_int8_t features,
+ u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
+ u_int16_t dxfer_len, int timeout, int quiet)
+{
+ if (data_ptr != NULL) {
+ ata_flags |= AP_FLAG_BYT_BLOK_BYTES |
+ AP_FLAG_TLEN_SECT_CNT;
+ if (flags & CAM_DIR_OUT)
+ ata_flags |= AP_FLAG_TDIR_TO_DEV;
+ else
+ ata_flags |= AP_FLAG_TDIR_FROM_DEV;
+ } else {
+ ata_flags |= AP_FLAG_TLEN_NO_DATA;
+ }
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+
+ scsi_ata_pass_16(&ccb->csio,
+ retries,
+ NULL,
+ flags,
+ tag_action,
+ protocol,
+ ata_flags,
+ features,
+ sector_count,
+ lba,
+ command,
+ /*control*/0,
+ data_ptr,
+ dxfer_len,
+ /*sense_len*/SSD_FULL_SIZE,
+ timeout);
+
+ return scsi_cam_pass_16_send(device, ccb, quiet);
+}
+
+static int
+ata_try_pass_16(struct cam_device *device)
+{
+ struct ccb_pathinq cpi;
+
+ if (get_cpi(device, &cpi) != 0) {
+ warnx("couldn't get CPI");
+ return (-1);
+ }
+
+ if (cpi.protocol == PROTO_SCSI) {
+ /* possibly compatible with pass_16 */
+ return (1);
+ }
+
+ /* likely not compatible with pass_16 */
+ return (0);
+}
+
+static int
+ata_do_28bit_cmd(struct cam_device *device, union ccb *ccb, int retries,
+ u_int32_t flags, u_int8_t protocol, u_int8_t tag_action,
+ u_int8_t command, u_int8_t features, u_int32_t lba,
+ u_int8_t sector_count, u_int8_t *data_ptr, u_int16_t dxfer_len,
+ int timeout, int quiet)
+{
+
+
+ switch (ata_try_pass_16(device)) {
+ case -1:
+ return (1);
+ case 1:
+ /* Try using SCSI Passthrough */
+ return ata_do_pass_16(device, ccb, retries, flags, protocol,
+ 0, tag_action, command, features, lba,
+ sector_count, data_ptr, dxfer_len,
+ timeout, quiet);
+ }
+
+ bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) -
+ sizeof(struct ccb_hdr));
+ cam_fill_ataio(&ccb->ataio,
+ retries,
+ NULL,
+ flags,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ timeout);
+
+ ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
+ return ata_cam_send(device, ccb, quiet);
+}
+
+static void
+dump_data(uint16_t *ptr, uint32_t len)
+{
+ u_int i;
+
+ for (i = 0; i < len / 2; i++) {
+ if ((i % 8) == 0)
+ printf(" %3d: ", i);
+ printf("%04hx ", ptr[i]);
+ if ((i % 8) == 7)
+ printf("\n");
+ }
+ if ((i % 8) != 7)
+ printf("\n");
+}
+
+static int
+ata_do_identify(struct cam_device *device, int retry_count, int timeout,
+ union ccb *ccb, struct ata_params** ident_bufp)
+{
+ struct ata_params *ident_buf;
+ struct ccb_pathinq cpi;
+ struct ccb_getdev cgd;
+ u_int i, error;
+ int16_t *ptr;
+ u_int8_t command, retry_command;
+
+ if (get_cpi(device, &cpi) != 0) {
+ warnx("couldn't get CPI");
+ return (-1);
+ }
+
+ /* Neither PROTO_ATAPI or PROTO_SATAPM are used in cpi.protocol */
+ if (cpi.protocol == PROTO_ATA) {
+ if (get_cgd(device, &cgd) != 0) {
+ warnx("couldn't get CGD");
+ return (-1);
+ }
+
+ command = (cgd.protocol == PROTO_ATA) ?
+ ATA_ATA_IDENTIFY : ATA_ATAPI_IDENTIFY;
+ retry_command = 0;
+ } else {
+ /* We don't know which for sure so try both */
+ command = ATA_ATA_IDENTIFY;
+ retry_command = ATA_ATAPI_IDENTIFY;
+ }
+
+ ptr = (uint16_t *)calloc(1, sizeof(struct ata_params));
+ if (ptr == NULL) {
+ warnx("can't calloc memory for identify\n");
+ return (1);
+ }
+
+ error = ata_do_28bit_cmd(device,
+ ccb,
+ /*retries*/retry_count,
+ /*flags*/CAM_DIR_IN,
+ /*protocol*/AP_PROTO_PIO_IN,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/command,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/(u_int8_t)sizeof(struct ata_params),
+ /*data_ptr*/(u_int8_t *)ptr,
+ /*dxfer_len*/sizeof(struct ata_params),
+ /*timeout*/timeout ? timeout : 30 * 1000,
+ /*quiet*/1);
if (error != 0) {
- free(ptr);
- return(error);
+ if (retry_command == 0) {
+ free(ptr);
+ return (1);
+ }
+ error = ata_do_28bit_cmd(device,
+ ccb,
+ /*retries*/retry_count,
+ /*flags*/CAM_DIR_IN,
+ /*protocol*/AP_PROTO_PIO_IN,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/retry_command,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/(u_int8_t)
+ sizeof(struct ata_params),
+ /*data_ptr*/(u_int8_t *)ptr,
+ /*dxfer_len*/sizeof(struct ata_params),
+ /*timeout*/timeout ? timeout : 30 * 1000,
+ /*quiet*/0);
+
+ if (error != 0) {
+ free(ptr);
+ return (1);
+ }
}
- for (i = 0; i < sizeof(struct ata_params) / 2; i++)
+ error = 1;
+ for (i = 0; i < sizeof(struct ata_params) / 2; i++) {
ptr[i] = le16toh(ptr[i]);
+ if (ptr[i] != 0)
+ error = 0;
+ }
+
if (arglist & CAM_ARG_VERBOSE) {
fprintf(stdout, "%s%d: Raw identify data:\n",
device->device_name, device->dev_unit_num);
- for (i = 0; i < sizeof(struct ata_params) / 2; i++) {
- if ((i % 8) == 0)
- fprintf(stdout, " %3d: ", i);
- fprintf(stdout, "%04x ", (uint16_t)ptr[i]);
- if ((i % 8) == 7)
- fprintf(stdout, "\n");
- }
+ dump_data(ptr, sizeof(struct ata_params));
}
+
+ /* check for invalid (all zero) response */
+ if (error != 0) {
+ warnx("Invalid identify response detected");
+ free(ptr);
+ return (error);
+ }
+
ident_buf = (struct ata_params *)ptr;
if (strncmp(ident_buf->model, "FX", 2) &&
strncmp(ident_buf->model, "NEC", 3) &&
@@ -1446,15 +1690,636 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
ata_bpack(ident_buf->media_serial, ident_buf->media_serial,
sizeof(ident_buf->media_serial));
- fprintf(stdout, "%s%d: ", device->device_name,
- device->dev_unit_num);
+ *ident_bufp = ident_buf;
+
+ return (0);
+}
+
+
+static int
+ataidentify(struct cam_device *device, int retry_count, int timeout)
+{
+ union ccb *ccb;
+ struct ata_params *ident_buf;
+
+ if ((ccb = cam_getccb(device)) == NULL) {
+ warnx("couldn't allocate CCB");
+ return (1);
+ }
+
+ if (ata_do_identify(device, retry_count, timeout, ccb, &ident_buf) != 0) {
+ cam_freeccb(ccb);
+ return (1);
+ }
+
+ printf("%s%d: ", device->device_name, device->dev_unit_num);
ata_print_ident(ident_buf);
camxferrate(device);
atacapprint(ident_buf);
free(ident_buf);
+ cam_freeccb(ccb);
- return(0);
+ return (0);
+}
+#endif /* MINIMALISTIC */
+
+
+#ifndef MINIMALISTIC
+enum {
+ ATA_SECURITY_ACTION_PRINT,
+ ATA_SECURITY_ACTION_FREEZE,
+ ATA_SECURITY_ACTION_UNLOCK,
+ ATA_SECURITY_ACTION_DISABLE,
+ ATA_SECURITY_ACTION_ERASE,
+ ATA_SECURITY_ACTION_ERASE_ENHANCED,
+ ATA_SECURITY_ACTION_SET_PASSWORD
+};
+
+static void
+atasecurity_print_time(u_int16_t tw)
+{
+
+ if (tw == 0)
+ printf("unspecified");
+ else if (tw >= 255)
+ printf("> 508 min");
+ else
+ printf("%i min", 2 * tw);
+}
+
+static u_int32_t
+atasecurity_erase_timeout_msecs(u_int16_t timeout)
+{
+
+ if (timeout == 0)
+ return 2 * 3600 * 1000; /* default: two hours */
+ else if (timeout > 255)
+ return (508 + 60) * 60 * 1000; /* spec says > 508 minutes */
+
+ return ((2 * timeout) + 5) * 60 * 1000; /* add a 5min margin */
+}
+
+
+static void
+atasecurity_notify(u_int8_t command, struct ata_security_password *pwd)
+{
+ struct ata_cmd cmd;
+
+ bzero(&cmd, sizeof(cmd));
+ cmd.command = command;
+ printf("Issuing %s", ata_op_string(&cmd));
+
+ if (pwd != NULL) {
+ char pass[sizeof(pwd->password)+1];
+
+ /* pwd->password may not be null terminated */
+ pass[sizeof(pwd->password)] = '\0';
+ strncpy(pass, pwd->password, sizeof(pwd->password));
+ printf(" password='%s', user='%s'",
+ pass,
+ (pwd->ctrl & ATA_SECURITY_PASSWORD_MASTER) ?
+ "master" : "user");
+
+ if (command == ATA_SECURITY_SET_PASSWORD) {
+ printf(", mode='%s'",
+ (pwd->ctrl & ATA_SECURITY_LEVEL_MAXIMUM) ?
+ "maximum" : "high");
+ }
+ }
+
+ printf("\n");
+}
+
+static int
+atasecurity_freeze(struct cam_device *device, union ccb *ccb,
+ int retry_count, u_int32_t timeout, int quiet)
+{
+
+ if (quiet == 0)
+ atasecurity_notify(ATA_SECURITY_FREEZE_LOCK, NULL);
+
+ return ata_do_28bit_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/AP_PROTO_NON_DATA,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SECURITY_FREEZE_LOCK,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ /*timeout*/timeout,
+ /*quiet*/0);
+}
+
+static int
+atasecurity_unlock(struct cam_device *device, union ccb *ccb,
+ int retry_count, u_int32_t timeout,
+ struct ata_security_password *pwd, int quiet)
+{
+
+ if (quiet == 0)
+ atasecurity_notify(ATA_SECURITY_UNLOCK, pwd);
+
+ return ata_do_28bit_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_OUT,
+ /*protocol*/AP_PROTO_PIO_OUT,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SECURITY_UNLOCK,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/(u_int8_t *)pwd,
+ /*dxfer_len*/sizeof(*pwd),
+ /*timeout*/timeout,
+ /*quiet*/0);
+}
+
+static int
+atasecurity_disable(struct cam_device *device, union ccb *ccb,
+ int retry_count, u_int32_t timeout,
+ struct ata_security_password *pwd, int quiet)
+{
+
+ if (quiet == 0)
+ atasecurity_notify(ATA_SECURITY_DISABLE_PASSWORD, pwd);
+ return ata_do_28bit_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_OUT,
+ /*protocol*/AP_PROTO_PIO_OUT,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SECURITY_DISABLE_PASSWORD,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/(u_int8_t *)pwd,
+ /*dxfer_len*/sizeof(*pwd),
+ /*timeout*/timeout,
+ /*quiet*/0);
+}
+
+
+static int
+atasecurity_erase_confirm(struct cam_device *device,
+ struct ata_params* ident_buf)
+{
+
+ printf("\nYou are about to ERASE ALL DATA from the following"
+ " device:\n%s%d,%s%d: ", device->device_name,
+ device->dev_unit_num, device->given_dev_name,
+ device->given_unit_number);
+ ata_print_ident(ident_buf);
+
+ for(;;) {
+ char str[50];
+ printf("\nAre you SURE you want to ERASE ALL DATA? (yes/no) ");
+
+ if (fgets(str, sizeof(str), stdin) != NULL) {
+ if (strncasecmp(str, "yes", 3) == 0) {
+ return (1);
+ } else if (strncasecmp(str, "no", 2) == 0) {
+ return (0);
+ } else {
+ printf("Please answer \"yes\" or "
+ "\"no\"\n");
+ }
+ }
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+atasecurity_erase(struct cam_device *device, union ccb *ccb,
+ int retry_count, u_int32_t timeout,
+ u_int32_t erase_timeout,
+ struct ata_security_password *pwd, int quiet)
+{
+ int error;
+
+ if (quiet == 0)
+ atasecurity_notify(ATA_SECURITY_ERASE_PREPARE, NULL);
+
+ error = ata_do_28bit_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/AP_PROTO_NON_DATA,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SECURITY_ERASE_PREPARE,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ /*timeout*/timeout,
+ /*quiet*/0);
+
+ if (error != 0)
+ return error;
+
+ if (quiet == 0)
+ atasecurity_notify(ATA_SECURITY_ERASE_UNIT, pwd);
+
+ error = ata_do_28bit_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_OUT,
+ /*protocol*/AP_PROTO_PIO_OUT,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SECURITY_ERASE_UNIT,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/(u_int8_t *)pwd,
+ /*dxfer_len*/sizeof(*pwd),
+ /*timeout*/erase_timeout,
+ /*quiet*/0);
+
+ if (error == 0 && quiet == 0)
+ printf("\nErase Complete\n");
+
+ return error;
+}
+
+static int
+atasecurity_set_password(struct cam_device *device, union ccb *ccb,
+ int retry_count, u_int32_t timeout,
+ struct ata_security_password *pwd, int quiet)
+{
+
+ if (quiet == 0)
+ atasecurity_notify(ATA_SECURITY_SET_PASSWORD, pwd);
+
+ return ata_do_28bit_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_OUT,
+ /*protocol*/AP_PROTO_PIO_OUT,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/ATA_SECURITY_SET_PASSWORD,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/(u_int8_t *)pwd,
+ /*dxfer_len*/sizeof(*pwd),
+ /*timeout*/timeout,
+ /*quiet*/0);
+}
+
+static void
+atasecurity_print(struct ata_params *parm)
+{
+
+ printf("\nSecurity Option Value\n");
+ if (arglist & CAM_ARG_VERBOSE) {
+ printf("status %04x\n",
+ parm->security_status);
+ }
+ printf("supported %s\n",
+ parm->security_status & ATA_SECURITY_SUPPORTED ? "yes" : "no");
+ if (!(parm->security_status & ATA_SECURITY_SUPPORTED))
+ return;
+ printf("enabled %s\n",
+ parm->security_status & ATA_SECURITY_ENABLED ? "yes" : "no");
+ printf("drive locked %s\n",
+ parm->security_status & ATA_SECURITY_LOCKED ? "yes" : "no");
+ printf("security config frozen %s\n",
+ parm->security_status & ATA_SECURITY_FROZEN ? "yes" : "no");
+ printf("count expired %s\n",
+ parm->security_status & ATA_SECURITY_COUNT_EXP ? "yes" : "no");
+ printf("security level %s\n",
+ parm->security_status & ATA_SECURITY_LEVEL ? "maximum" : "high");
+ printf("enhanced erase supported %s\n",
+ parm->security_status & ATA_SECURITY_ENH_SUPP ? "yes" : "no");
+ printf("erase time ");
+ atasecurity_print_time(parm->erase_time);
+ printf("\n");
+ printf("enhanced erase time ");
+ atasecurity_print_time(parm->enhanced_erase_time);
+ printf("\n");
+ printf("master password rev %04x%s\n",
+ parm->master_passwd_revision,
+ parm->master_passwd_revision == 0x0000 ||
+ parm->master_passwd_revision == 0xFFFF ? " (unsupported)" : "");
+}
+
+/*
+ * Validates and copies the password in optarg to the passed buffer.
+ * If the password in optarg is the same length as the buffer then
+ * the data will still be copied but no null termination will occur.
+ */
+static int
+ata_getpwd(u_int8_t *passwd, int max, char opt)
+{
+ int len;
+
+ len = strlen(optarg);
+ if (len > max) {
+ warnx("-%c password is too long", opt);
+ return (1);
+ } else if (len == 0) {
+ warnx("-%c password is missing", opt);
+ return (1);
+ } else if (optarg[0] == '-'){
+ warnx("-%c password starts with '-' (generic arg?)", opt);
+ return (1);
+ } else if (strlen(passwd) != 0 && strcmp(passwd, optarg) != 0) {
+ warnx("-%c password conflicts with existing password from -%c",
+ opt, pwd_opt);
+ return (1);
+ }
+
+ /* Callers pass in a buffer which does NOT need to be terminated */
+ strncpy(passwd, optarg, max);
+ pwd_opt = opt;
+
+ return (0);
+}
+
+static int
+atasecurity(struct cam_device *device, int retry_count, int timeout,
+ int argc, char **argv, char *combinedopt)
+{
+ union ccb *ccb;
+ struct ata_params *ident_buf;
+ int error, confirm, quiet, c, action, actions, setpwd;
+ int security_enabled, erase_timeout, pwdsize;
+ struct ata_security_password pwd;
+
+ actions = 0;
+ setpwd = 0;
+ erase_timeout = 0;
+ confirm = 0;
+ quiet = 0;
+
+ memset(&pwd, 0, sizeof(pwd));
+
+ /* default action is to print security information */
+ action = ATA_SECURITY_ACTION_PRINT;
+
+ /* user is master by default as its safer that way */
+ pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER;
+ pwdsize = sizeof(pwd.password);
+
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch(c){
+ case 'f':
+ action = ATA_SECURITY_ACTION_FREEZE;
+ actions++;
+ break;
+
+ case 'U':
+ if (strcasecmp(optarg, "user") == 0) {
+ pwd.ctrl |= ATA_SECURITY_PASSWORD_USER;
+ pwd.ctrl &= ~ATA_SECURITY_PASSWORD_MASTER;
+ } else if (strcasecmp(optarg, "master") != 0) {
+ pwd.ctrl |= ATA_SECURITY_PASSWORD_MASTER;
+ pwd.ctrl &= ~ATA_SECURITY_PASSWORD_USER;
+ } else {
+ warnx("-U argument '%s' is invalid (must be "
+ "'user' or 'master')", optarg);
+ return (1);
+ }
+ break;
+
+ case 'l':
+ if (strcasecmp(optarg, "high") == 0) {
+ pwd.ctrl |= ATA_SECURITY_LEVEL_HIGH;
+ pwd.ctrl &= ~ATA_SECURITY_LEVEL_MAXIMUM;
+ } else if (strcasecmp(optarg, "maximum") == 0) {
+ pwd.ctrl |= ATA_SECURITY_LEVEL_MAXIMUM;
+ pwd.ctrl &= ~ATA_SECURITY_LEVEL_HIGH;
+ } else {
+ warnx("-l argument '%s' is unknown (must be "
+ "'high' or 'maximum')", optarg);
+ return (1);
+ }
+ break;
+
+ case 'k':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ action = ATA_SECURITY_ACTION_UNLOCK;
+ actions++;
+ break;
+
+ case 'd':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ action = ATA_SECURITY_ACTION_DISABLE;
+ actions++;
+ break;
+
+ case 'e':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ action = ATA_SECURITY_ACTION_ERASE;
+ actions++;
+ break;
+
+ case 'h':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ pwd.ctrl |= ATA_SECURITY_ERASE_ENHANCED;
+ action = ATA_SECURITY_ACTION_ERASE_ENHANCED;
+ actions++;
+ break;
+
+ case 's':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ setpwd = 1;
+ if (action == ATA_SECURITY_ACTION_PRINT)
+ action = ATA_SECURITY_ACTION_SET_PASSWORD;
+ /*
+ * Don't increment action as this can be combined
+ * with other actions.
+ */
+ break;
+
+ case 'y':
+ confirm++;
+ break;
+
+ case 'q':
+ quiet++;
+ break;
+
+ case 'T':
+ erase_timeout = atoi(optarg) * 1000;
+ break;
+ }
+ }
+
+ if (actions > 1) {
+ warnx("too many security actions specified");
+ return (1);
+ }
+
+ if ((ccb = cam_getccb(device)) == NULL) {
+ warnx("couldn't allocate CCB");
+ return (1);
+ }
+
+ error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
+ if (error != 0) {
+ cam_freeccb(ccb);
+ return (1);
+ }
+
+ if (quiet == 0) {
+ printf("%s%d: ", device->device_name, device->dev_unit_num);
+ ata_print_ident(ident_buf);
+ camxferrate(device);
+ }
+
+ if (action == ATA_SECURITY_ACTION_PRINT) {
+ atasecurity_print(ident_buf);
+ free(ident_buf);
+ cam_freeccb(ccb);
+ return (0);
+ }
+
+ if ((ident_buf->support.command1 & ATA_SUPPORT_SECURITY) == 0) {
+ warnx("Security not supported");
+ free(ident_buf);
+ cam_freeccb(ccb);
+ return (1);
+ }
+
+ /* default timeout 15 seconds the same as linux hdparm */
+ timeout = timeout ? timeout : 15 * 1000;
+
+ security_enabled = ident_buf->security_status & ATA_SECURITY_ENABLED;
+
+ /* first set the password if requested */
+ if (setpwd == 1) {
+ /* confirm we can erase before setting the password if erasing */
+ if (confirm == 0 &&
+ (action == ATA_SECURITY_ACTION_ERASE_ENHANCED ||
+ action == ATA_SECURITY_ACTION_ERASE) &&
+ atasecurity_erase_confirm(device, ident_buf) == 0) {
+ cam_freeccb(ccb);
+ free(ident_buf);
+ return (error);
+ }
+
+ if (pwd.ctrl & ATA_SECURITY_PASSWORD_MASTER) {
+ pwd.revision = ident_buf->master_passwd_revision;
+ if (pwd.revision != 0 && pwd.revision != 0xfff &&
+ --pwd.revision == 0) {
+ pwd.revision = 0xfffe;
+ }
+ }
+ error = atasecurity_set_password(device, ccb, retry_count,
+ timeout, &pwd, quiet);
+ if (error != 0) {
+ cam_freeccb(ccb);
+ free(ident_buf);
+ return (error);
+ }
+ security_enabled = 1;
+ }
+
+ switch(action) {
+ case ATA_SECURITY_ACTION_FREEZE:
+ error = atasecurity_freeze(device, ccb, retry_count,
+ timeout, quiet);
+ break;
+
+ case ATA_SECURITY_ACTION_UNLOCK:
+ if (security_enabled) {
+ if (ident_buf->security_status & ATA_SECURITY_LOCKED) {
+ error = atasecurity_unlock(device, ccb,
+ retry_count, timeout, &pwd, quiet);
+ } else {
+ warnx("Can't unlock, drive is not locked");
+ error = 1;
+ }
+ } else {
+ warnx("Can't unlock, security is disabled");
+ error = 1;
+ }
+ break;
+
+ case ATA_SECURITY_ACTION_DISABLE:
+ if (security_enabled) {
+ /* First unlock the drive if its locked */
+ if (ident_buf->security_status & ATA_SECURITY_LOCKED) {
+ error = atasecurity_unlock(device, ccb,
+ retry_count,
+ timeout,
+ &pwd,
+ quiet);
+ }
+
+ if (error == 0) {
+ error = atasecurity_disable(device,
+ ccb,
+ retry_count,
+ timeout,
+ &pwd,
+ quiet);
+ }
+ } else {
+ warnx("Can't disable security (already disabled)");
+ error = 1;
+ }
+ break;
+
+ case ATA_SECURITY_ACTION_ERASE:
+ if (security_enabled) {
+ if (erase_timeout == 0) {
+ erase_timeout = atasecurity_erase_timeout_msecs(
+ ident_buf->erase_time);
+ }
+
+ error = atasecurity_erase(device, ccb, retry_count,
+ timeout, erase_timeout, &pwd,
+ quiet);
+ } else {
+ warnx("Can't secure erase (security is disabled)");
+ error = 1;
+ }
+ break;
+
+ case ATA_SECURITY_ACTION_ERASE_ENHANCED:
+ if (security_enabled) {
+ if (ident_buf->security_status & ATA_SECURITY_ENH_SUPP) {
+ if (erase_timeout == 0) {
+ erase_timeout =
+ atasecurity_erase_timeout_msecs(
+ ident_buf->enhanced_erase_time);
+ }
+
+ error = atasecurity_erase(device, ccb,
+ retry_count, timeout,
+ erase_timeout, &pwd,
+ quiet);
+ } else {
+ warnx("Enhanced erase is not supported");
+ error = 1;
+ }
+ } else {
+ warnx("Can't secure erase (enhanced), "
+ "(security is disabled)");
+ error = 1;
+ }
+ break;
+ }
+
+ cam_freeccb(ccb);
+ free(ident_buf);
+
+ return (error);
}
#endif /* MINIMALISTIC */
@@ -5833,6 +6698,10 @@ usage(int printlong)
" camcontrol standby [dev_id][generic args][-t time]\n"
" camcontrol sleep [dev_id][generic args]\n"
" camcontrol fwdownload [dev_id][generic args] <-f fw_image> [-y][-s]\n"
+" camcontrol security [dev_id][generic args]\n"
+" <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
+" [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n"
+" [-U <user|master>] [-y]\n"
#endif /* MINIMALISTIC */
" camcontrol help\n");
if (!printlong)
@@ -5869,6 +6738,7 @@ usage(int printlong)
"standby send the ATA STANDBY command to the named device\n"
"sleep send the ATA SLEEP command to the named device\n"
"fwdownload program firmware of the named device with the given image"
+"security report or send ATA security commands to the named device\n"
"help this message\n"
"Device Identifiers:\n"
"bus:target specify the bus and target, lun defaults to 0\n"
@@ -5965,7 +6835,24 @@ usage(int printlong)
"-f fw_image path to firmware image file\n"
"-y don't ask any questions\n"
"-s run in simulation mode\n"
-"-v print info for every firmware segment sent to device\n");
+"-v print info for every firmware segment sent to device\n"
+"security arguments:\n"
+"-d pwd disable security using the given password for the selected\n"
+" user\n"
+"-e pwd erase the device using the given pwd for the selected user\n"
+"-f freeze the security configuration of the specified device\n"
+"-h pwd enhanced erase the device using the given pwd for the\n"
+" selected user\n"
+"-k pwd unlock the device using the given pwd for the selected\n"
+" user\n"
+"-l <high|maximum> specifies which security level to set: high or maximum\n"
+"-q be quiet, do not print any status messages\n"
+"-s pwd password the device (enable security) using the given\n"
+" pwd for the selected user\n"
+"-T timeout overrides the timeout (seconds) used for erase operation\n"
+"-U <user|master> specifies which user to set: user or master\n"
+"-y don't ask any questions\n"
+);
#endif /* MINIMALISTIC */
}
@@ -6278,8 +7165,11 @@ main(int argc, char **argv)
case CAM_CMD_STANDBY:
case CAM_CMD_SLEEP:
error = atapm(cam_dev, argc, argv,
- combinedopt, retry_count,
- timeout);
+ combinedopt, retry_count, timeout);
+ break;
+ case CAM_CMD_SECURITY:
+ error = atasecurity(cam_dev, retry_count, timeout,
+ argc, argv, combinedopt);
break;
case CAM_CMD_DOWNLOAD_FW:
error = fwdownload(cam_dev, argc, argv, combinedopt,
diff --git a/sbin/ccdconfig/ccdconfig.8 b/sbin/ccdconfig/ccdconfig.8
index cc29f717528b..99a1762451ec 100644
--- a/sbin/ccdconfig/ccdconfig.8
+++ b/sbin/ccdconfig/ccdconfig.8
@@ -234,14 +234,14 @@ RAID controllers (see GENERIC),
or software RAID systems such as
.Xr geom 8
and
-.Xr vinum 8 .
+.Xr gvinum 8 .
.Sh SEE ALSO
.Xr dd 1 ,
.Xr ccd 4 ,
.Xr disklabel 8 ,
.Xr fdisk 8 ,
-.Xr rc 8 ,
-.Xr vinum 8
+.Xr gvinum 8 ,
+.Xr rc 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index 46f3623a3a6b..9448775b14c3 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -116,7 +116,7 @@ static struct pidfh *pfh;
int Dflag;
int dflag;
int nflag;
-int romeo_must_die = 0;
+static volatile sig_atomic_t romeo_must_die = 0;
static const char *configfile = CF;
@@ -319,7 +319,7 @@ media::do_match(config &c)
// the name of interest, first try device-name and fall back
// to subsystem if none exists.
value = c.get_variable("device-name");
- if (value.length() == 0)
+ if (value.empty())
value = c.get_variable("subsystem");
if (Dflag)
fprintf(stderr, "Testing media type of %s against 0x%x\n",
@@ -460,7 +460,7 @@ config::open_pidfile()
{
pid_t otherpid;
- if (_pidfile == "")
+ if (_pidfile.empty())
return;
pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid);
if (pfh == NULL) {
@@ -528,7 +528,7 @@ config::add_notify(int prio, event_proc *p)
void
config::set_pidfile(const char *fn)
{
- _pidfile = string(fn);
+ _pidfile = fn;
}
void
@@ -585,7 +585,7 @@ config::expand_one(const char *&src, string &dst)
src++;
// $$ -> $
if (*src == '$') {
- dst.append(src++, 1);
+ dst += *src++;
return;
}
@@ -593,7 +593,7 @@ config::expand_one(const char *&src, string &dst)
// Not sure if I want to support this or not, so for now we just pass
// it through.
if (*src == '(') {
- dst.append("$");
+ dst += '$';
count = 1;
/* If the string ends before ) is matched , return. */
while (count > 0 && *src) {
@@ -601,23 +601,23 @@ config::expand_one(const char *&src, string &dst)
count--;
else if (*src == '(')
count++;
- dst.append(src++, 1);
+ dst += *src++;
}
return;
}
- // ${^A-Za-z] -> $\1
+ // $[^A-Za-z] -> $\1
if (!isalpha(*src)) {
- dst.append("$");
- dst.append(src++, 1);
+ dst += '$';
+ dst += *src++;
return;
}
// $var -> replace with value
do {
- buffer.append(src++, 1);
+ buffer += *src++;
} while (is_id_char(*src));
- dst.append(get_variable(buffer.c_str()));
+ dst.append(get_variable(buffer));
}
const string
@@ -653,7 +653,7 @@ config::expand_string(const char *src, const char *prepend, const char *append)
}
bool
-config::chop_var(char *&buffer, char *&lhs, char *&rhs)
+config::chop_var(char *&buffer, char *&lhs, char *&rhs) const
{
char *walker;
@@ -912,9 +912,7 @@ event_loop(void)
server_fd = create_socket(PIPE);
accepting = 1;
max_fd = max(fd, server_fd) + 1;
- while (1) {
- if (romeo_must_die)
- break;
+ while (!romeo_must_die) {
if (!once && !dflag && !nflag) {
// Check to see if we have any events pending.
tv.tv_sec = 0;
@@ -1076,8 +1074,7 @@ set_variable(const char *var, const char *val)
static void
gensighand(int)
{
- romeo_must_die++;
- _exit(0);
+ romeo_must_die = 1;
}
static void
diff --git a/sbin/devd/devd.conf.5 b/sbin/devd/devd.conf.5
index 4c1893d366f7..311228ec28e7 100644
--- a/sbin/devd/devd.conf.5
+++ b/sbin/devd/devd.conf.5
@@ -41,7 +41,7 @@
.\" ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
.\" SOFTWARE.
.\"
-.Dd December 16, 2011
+.Dd February 22, 2013
.Dt DEVD.CONF 5
.Os
.Sh NAME
@@ -181,9 +181,8 @@ Valid media types are:
.Dq Li Tokenring ,
.Dq Li FDDI ,
.Dq Li 802.11 ,
-.Dq Li ATM ,
and
-.Dq Li CARP .
+.Dq Li ATM .
.It Ic subdevice Qq Ar string ;
This is shorthand for
.Dq Ic match Qo Li subdevice Qc Qq Ar string .
@@ -350,6 +349,7 @@ The network interface is attached to the system.
The network interface is detached from the system.
.El
.El
+.Pp
.It Li DEVFS
Events related to the
.Xr devfs 5
@@ -369,6 +369,7 @@ The
node is destroyed.
.El
.El
+.Pp
.It Li USB
Events related to the USB subsystem.
.Bl -tag -width ".Sy Subsystem" -compact
@@ -390,6 +391,7 @@ USB interface is attached to a device.
USB interface is detached from a device.
.El
.El
+.Pp
.It Li coretemp
Events related to the
.Xr coretemp 4
@@ -404,6 +406,7 @@ Notification that the CPU core has reached critical temperature.
String containing the temperature of the core that has become too hot.
.El
.El
+.Pp
.It Li kern
Events related to the kernel.
.Bl -tag -width ".Sy Subsystem" -compact
diff --git a/sbin/devd/devd.hh b/sbin/devd/devd.hh
index a48d07b4930c..c8a761015c41 100644
--- a/sbin/devd/devd.hh
+++ b/sbin/devd/devd.hh
@@ -41,8 +41,6 @@ class config;
class var_list
{
public:
- var_list() {}
- virtual ~var_list() {}
/** Set a variable in this var list.
*/
void set_variable(const std::string &var, const std::string &val);
@@ -68,7 +66,6 @@ private:
struct eps
{
public:
- eps() {}
virtual ~eps() {}
/** Does this eps match the current config?
*/
@@ -144,7 +141,7 @@ private:
class config
{
public:
- config() : _pidfile("") { push_var_table(); }
+ config() { push_var_table(); }
virtual ~config() { reset(); }
void add_attach(int, event_proc *);
void add_detach(int, event_proc *);
@@ -172,7 +169,7 @@ protected:
void parse_files_in_dir(const char *dirname);
void expand_one(const char *&src, std::string &dst);
bool is_id_char(char) const;
- bool chop_var(char *&buffer, char *&lhs, char *&rhs);
+ bool chop_var(char *&buffer, char *&lhs, char *&rhs) const;
private:
std::vector<std::string> _dir_list;
std::string _pidfile;
diff --git a/sbin/dumpfs/dumpfs.c b/sbin/dumpfs/dumpfs.c
index a41ca4dda719..6669d532d62e 100644
--- a/sbin/dumpfs/dumpfs.c
+++ b/sbin/dumpfs/dumpfs.c
@@ -241,8 +241,8 @@ dumpfs(const char *name)
afs.fs_sblkno, afs.fs_cblkno, afs.fs_iblkno, afs.fs_dblkno);
printf("cgrotor\t%d\tfmod\t%d\tronly\t%d\tclean\t%d\n",
afs.fs_cgrotor, afs.fs_fmod, afs.fs_ronly, afs.fs_clean);
- printf("avgfpdir %d\tavgfilesize %d\n",
- afs.fs_avgfpdir, afs.fs_avgfilesize);
+ printf("metaspace %jd\tavgfpdir %d\tavgfilesize %d\n",
+ afs.fs_metaspace, afs.fs_avgfpdir, afs.fs_avgfilesize);
printf("flags\t");
if (afs.fs_old_flags & FS_FLAGS_UPDATED)
fsflags = afs.fs_flags;
diff --git a/sbin/ffsinfo/ffsinfo.8 b/sbin/ffsinfo/ffsinfo.8
index aacf4280bf13..9753cf7c0cf8 100644
--- a/sbin/ffsinfo/ffsinfo.8
+++ b/sbin/ffsinfo/ffsinfo.8
@@ -125,9 +125,9 @@ with all available information.
.Xr dumpfs 8 ,
.Xr fsck 8 ,
.Xr growfs 8 ,
+.Xr gvinum 8 ,
.Xr newfs 8 ,
-.Xr tunefs 8 ,
-.Xr vinum 8
+.Xr tunefs 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index 7815fe6f3f51..965e3e398215 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -708,6 +708,6 @@ getdirblk(ufs2_daddr_t blkno, long size)
if (pdirbp != 0)
pdirbp->b_flags &= ~B_INUSE;
- pdirbp = getdatablk(blkno, size);
+ pdirbp = getdatablk(blkno, size, BT_DIRDATA);
return (pdirbp);
}
diff --git a/sbin/fsck_ffs/ea.c b/sbin/fsck_ffs/ea.c
index c1cf59dd667a..35170117a2fe 100644
--- a/sbin/fsck_ffs/ea.c
+++ b/sbin/fsck_ffs/ea.c
@@ -73,7 +73,7 @@ eascan(struct inodesc *idesc, struct ufs2_dinode *dp)
else
blksiz = sblock.fs_bsize;
printf("blksiz = %ju\n", (intmax_t)blksiz);
- bp = getdatablk(dp->di_extb[0], blksiz);
+ bp = getdatablk(dp->di_extb[0], blksiz, BT_EXTATTR);
cp = (u_char *)bp->b_un.b_buf;
for (n = 0; n < blksiz; n++) {
printf("%02x", cp[n]);
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 4717760acad9..7b45d4840b08 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -67,10 +67,13 @@
#include <stdlib.h>
#include <stdio.h>
+#include <sys/queue.h>
+
#define MAXDUP 10 /* limit on dup blks (per inode) */
#define MAXBAD 10 /* limit on bad blks (per inode) */
-#define MAXBUFSPACE 40*1024 /* maximum space to allocate to buffers */
-#define INOBUFSIZE 56*1024 /* size of buffer to read inodes in pass1 */
+#define MINBUFS 10 /* minimum number of buffers required */
+#define MAXBUFS 40 /* maximum space to allocate to buffers */
+#define INOBUFSIZE 64*1024 /* size of buffer to read inodes in pass1 */
union dinode {
struct ufs1_dinode dp1;
@@ -130,12 +133,12 @@ struct inostatlist {
* buffer cache structure.
*/
struct bufarea {
- struct bufarea *b_next; /* free list queue */
- struct bufarea *b_prev; /* free list queue */
+ TAILQ_ENTRY(bufarea) b_list; /* buffer list */
ufs2_daddr_t b_bno;
int b_size;
int b_errs;
int b_flags;
+ int b_type;
union {
char *b_buf; /* buffer space */
ufs1_daddr_t *b_indir1; /* UFS1 indirect block */
@@ -159,12 +162,42 @@ struct bufarea {
(bp)->b_un.b_indir2[i] = (val); \
} while (0)
-#define B_INUSE 1
+/*
+ * Buffer flags
+ */
+#define B_INUSE 0x00000001 /* Buffer is in use */
+/*
+ * Type of data in buffer
+ */
+#define BT_UNKNOWN 0 /* Buffer holds a superblock */
+#define BT_SUPERBLK 1 /* Buffer holds a superblock */
+#define BT_CYLGRP 2 /* Buffer holds a cylinder group map */
+#define BT_LEVEL1 3 /* Buffer holds single level indirect */
+#define BT_LEVEL2 4 /* Buffer holds double level indirect */
+#define BT_LEVEL3 5 /* Buffer holds triple level indirect */
+#define BT_EXTATTR 6 /* Buffer holds external attribute data */
+#define BT_INODES 7 /* Buffer holds external attribute data */
+#define BT_DIRDATA 8 /* Buffer holds directory data */
+#define BT_DATA 9 /* Buffer holds user data */
+#define BT_NUMBUFTYPES 10
+#define BT_NAMES { \
+ "unknown", \
+ "Superblock", \
+ "Cylinder Group", \
+ "Single Level Indirect", \
+ "Double Level Indirect", \
+ "Triple Level Indirect", \
+ "External Attribute", \
+ "Inode Block", \
+ "Directory Contents", \
+ "User Data" }
+long readcnt[BT_NUMBUFTYPES];
+long totalreadcnt[BT_NUMBUFTYPES];
+struct timespec readtime[BT_NUMBUFTYPES];
+struct timespec totalreadtime[BT_NUMBUFTYPES];
+struct timespec startprog;
-#define MINBUFS 5 /* minimum number of buffers required */
-struct bufarea bufhead; /* head of list of other blks in filesys */
struct bufarea sblk; /* file system superblock */
-struct bufarea cgblk; /* cylinder group blocks */
struct bufarea *pdirbp; /* current directory contents */
struct bufarea *pbp; /* current inode block */
@@ -174,16 +207,15 @@ struct bufarea *pbp; /* current inode block */
else \
(bp)->b_dirty = 1; \
} while (0)
-#define initbarea(bp) do { \
+#define initbarea(bp, type) do { \
(bp)->b_dirty = 0; \
(bp)->b_bno = (ufs2_daddr_t)-1; \
(bp)->b_flags = 0; \
+ (bp)->b_type = type; \
} while (0)
#define sbdirty() dirty(&sblk)
-#define cgdirty() dirty(&cgblk)
#define sblock (*sblk.b_un.b_fs)
-#define cgrp (*cgblk.b_un.b_cg)
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
ino_t cursnapshot;
@@ -326,6 +358,37 @@ struct ufs2_dinode ufs2_zino;
#define EEXIT 8 /* Standard error exit. */
+int flushentry(void);
+/*
+ * Wrapper for malloc() that flushes the cylinder group cache to try
+ * to get space.
+ */
+static inline void*
+Malloc(int size)
+{
+ void *retval;
+
+ while ((retval = malloc(size)) == NULL)
+ if (flushentry() == 0)
+ break;
+ return (retval);
+}
+
+/*
+ * Wrapper for calloc() that flushes the cylinder group cache to try
+ * to get space.
+ */
+static inline void*
+Calloc(int cnt, int size)
+{
+ void *retval;
+
+ while ((retval = calloc(cnt, size)) == NULL)
+ if (flushentry() == 0)
+ break;
+ return (retval);
+}
+
struct fstab;
@@ -343,7 +406,7 @@ void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
int changeino(ino_t dir, const char *name, ino_t newnum);
-int check_cgmagic(int cg, struct cg *cgp);
+int check_cgmagic(int cg, struct bufarea *cgbp);
int chkrange(ufs2_daddr_t blk, int cnt);
void ckfini(int markclean);
int ckinode(union dinode *dp, struct inodesc *);
@@ -354,6 +417,7 @@ int dirscan(struct inodesc *);
int dofix(struct inodesc *, const char *msg);
int eascan(struct inodesc *, struct ufs2_dinode *dp);
void fileerror(ino_t cwd, ino_t ino, const char *errmesg);
+void finalIOstats(void);
int findino(struct inodesc *);
int findname(struct inodesc *);
void flush(int fd, struct bufarea *bp);
@@ -362,7 +426,8 @@ void freeino(ino_t ino);
void freeinodebuf(void);
int ftypeok(union dinode *dp);
void getblk(struct bufarea *bp, ufs2_daddr_t blk, long size);
-struct bufarea *getdatablk(ufs2_daddr_t blkno, long size);
+struct bufarea *cgget(int cg);
+struct bufarea *getdatablk(ufs2_daddr_t blkno, long size, int type);
struct inoinfo *getinoinfo(ino_t inumber);
union dinode *getnextinode(ino_t inumber, int rebuildcg);
void getpathname(char *namebuf, ino_t curdir, ino_t ino);
@@ -372,6 +437,7 @@ void alarmhandler(int sig);
void inocleanup(void);
void inodirty(void);
struct inostat *inoinfo(ino_t inum);
+void IOstats(char *what);
int linkup(ino_t orphan, ino_t parentdir, char *name);
int makeentry(ino_t parent, ino_t ino, const char *name);
void panic(const char *fmt, ...) __printflike(1, 2);
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 9bf61d136333..9ebc342d6f02 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -56,17 +56,24 @@ __FBSDID("$FreeBSD$");
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+#include <time.h>
#include <unistd.h>
#include "fsck.h"
static void slowio_start(void);
static void slowio_end(void);
+static void printIOstats(void);
-long diskreads, totalreads; /* Disk cache statistics */
+static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */
+static struct timespec startpass, finishpass;
struct timeval slowio_starttime;
int slowio_delay_usec = 10000; /* Initial IO delay for background fsck */
int slowio_pollcnt;
+static struct bufarea cgblk; /* backup buffer for cylinder group blocks */
+static TAILQ_HEAD(buflist, bufarea) bufhead; /* head of buffer cache list */
+static int numbufs; /* size of buffer cache */
+static char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
int
ftypeok(union dinode *dp)
@@ -157,73 +164,158 @@ bufinit(void)
char *bufp;
pbp = pdirbp = (struct bufarea *)0;
- bufp = malloc((unsigned int)sblock.fs_bsize);
+ bufp = Malloc((unsigned int)sblock.fs_bsize);
if (bufp == 0)
errx(EEXIT, "cannot allocate buffer pool");
cgblk.b_un.b_buf = bufp;
- initbarea(&cgblk);
- bufhead.b_next = bufhead.b_prev = &bufhead;
- bufcnt = MAXBUFSPACE / sblock.fs_bsize;
+ initbarea(&cgblk, BT_CYLGRP);
+ TAILQ_INIT(&bufhead);
+ bufcnt = MAXBUFS;
if (bufcnt < MINBUFS)
bufcnt = MINBUFS;
for (i = 0; i < bufcnt; i++) {
- bp = (struct bufarea *)malloc(sizeof(struct bufarea));
- bufp = malloc((unsigned int)sblock.fs_bsize);
+ bp = (struct bufarea *)Malloc(sizeof(struct bufarea));
+ bufp = Malloc((unsigned int)sblock.fs_bsize);
if (bp == NULL || bufp == NULL) {
if (i >= MINBUFS)
break;
errx(EEXIT, "cannot allocate buffer pool");
}
bp->b_un.b_buf = bufp;
- bp->b_prev = &bufhead;
- bp->b_next = bufhead.b_next;
- bufhead.b_next->b_prev = bp;
- bufhead.b_next = bp;
- initbarea(bp);
+ TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
+ initbarea(bp, BT_UNKNOWN);
}
- bufhead.b_size = i; /* save number of buffers */
+ numbufs = i; /* save number of buffers */
+ for (i = 0; i < BT_NUMBUFTYPES; i++) {
+ readtime[i].tv_sec = totalreadtime[i].tv_sec = 0;
+ readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0;
+ readcnt[i] = totalreadcnt[i] = 0;
+ }
+}
+
+/*
+ * Manage cylinder group buffers.
+ */
+static struct bufarea *cgbufs; /* header for cylinder group cache */
+static int flushtries; /* number of tries to reclaim memory */
+
+struct bufarea *
+cgget(int cg)
+{
+ struct bufarea *cgbp;
+ struct cg *cgp;
+
+ if (cgbufs == NULL) {
+ cgbufs = Calloc(sblock.fs_ncg, sizeof(struct bufarea));
+ if (cgbufs == NULL)
+ errx(EEXIT, "cannot allocate cylinder group buffers");
+ }
+ cgbp = &cgbufs[cg];
+ if (cgbp->b_un.b_cg != NULL)
+ return (cgbp);
+ cgp = NULL;
+ if (flushtries == 0)
+ cgp = malloc((unsigned int)sblock.fs_cgsize);
+ if (cgp == NULL) {
+ getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
+ return (&cgblk);
+ }
+ cgbp->b_un.b_cg = cgp;
+ initbarea(cgbp, BT_CYLGRP);
+ getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize);
+ return (cgbp);
+}
+
+/*
+ * Attempt to flush a cylinder group cache entry.
+ * Return whether the flush was successful.
+ */
+int
+flushentry(void)
+{
+ struct bufarea *cgbp;
+
+ cgbp = &cgbufs[flushtries++];
+ if (cgbp->b_un.b_cg == NULL)
+ return (0);
+ flush(fswritefd, cgbp);
+ free(cgbp->b_un.b_buf);
+ cgbp->b_un.b_buf = NULL;
+ return (1);
}
/*
* Manage a cache of directory blocks.
*/
struct bufarea *
-getdatablk(ufs2_daddr_t blkno, long size)
+getdatablk(ufs2_daddr_t blkno, long size, int type)
{
struct bufarea *bp;
- for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
+ TAILQ_FOREACH(bp, &bufhead, b_list)
if (bp->b_bno == fsbtodb(&sblock, blkno))
goto foundit;
- for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
+ TAILQ_FOREACH_REVERSE(bp, &bufhead, buflist, b_list)
if ((bp->b_flags & B_INUSE) == 0)
break;
- if (bp == &bufhead)
+ if (bp == NULL)
errx(EEXIT, "deadlocked buffer pool");
+ bp->b_type = type;
getblk(bp, blkno, size);
/* fall through */
foundit:
- bp->b_prev->b_next = bp->b_next;
- bp->b_next->b_prev = bp->b_prev;
- bp->b_prev = &bufhead;
- bp->b_next = bufhead.b_next;
- bufhead.b_next->b_prev = bp;
- bufhead.b_next = bp;
+ if (debug && bp->b_type != type)
+ printf("Buffer type changed from %s to %s\n",
+ buftype[bp->b_type], buftype[type]);
+ TAILQ_REMOVE(&bufhead, bp, b_list);
+ TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
bp->b_flags |= B_INUSE;
return (bp);
}
+/*
+ * Timespec operations (from <sys/time.h>).
+ */
+#define timespecsub(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec -= (uvp)->tv_sec; \
+ (vvp)->tv_nsec -= (uvp)->tv_nsec; \
+ if ((vvp)->tv_nsec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_nsec += 1000000000; \
+ } \
+ } while (0)
+#define timespecadd(vvp, uvp) \
+ do { \
+ (vvp)->tv_sec += (uvp)->tv_sec; \
+ (vvp)->tv_nsec += (uvp)->tv_nsec; \
+ if ((vvp)->tv_nsec >= 1000000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_nsec -= 1000000000; \
+ } \
+ } while (0)
+
void
getblk(struct bufarea *bp, ufs2_daddr_t blk, long size)
{
ufs2_daddr_t dblk;
+ struct timespec start, finish;
- totalreads++;
dblk = fsbtodb(&sblock, blk);
- if (bp->b_bno != dblk) {
+ if (bp->b_bno == dblk) {
+ totalreads++;
+ } else {
flush(fswritefd, bp);
- diskreads++;
+ if (debug) {
+ readcnt[bp->b_type]++;
+ clock_gettime(CLOCK_REALTIME_PRECISE, &start);
+ }
bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size);
+ if (debug) {
+ clock_gettime(CLOCK_REALTIME_PRECISE, &finish);
+ timespecsub(&finish, &start);
+ timespecadd(&readtime[bp->b_type], &finish);
+ }
bp->b_bno = dblk;
bp->b_size = size;
}
@@ -274,7 +366,7 @@ void
ckfini(int markclean)
{
struct bufarea *bp, *nbp;
- int ofsmodified, cnt = 0;
+ int ofsmodified, cnt;
if (bkgrdflag) {
unlink(snapname);
@@ -295,6 +387,10 @@ ckfini(int markclean)
rerun = 1;
}
}
+ if (debug && totalreads > 0)
+ printf("cache with %d buffers missed %ld of %ld (%d%%)\n",
+ numbufs, totaldiskreads, totalreads,
+ (int)(totaldiskreads * 100 / totalreads));
if (fswritefd < 0) {
(void)close(fsreadfd);
return;
@@ -309,15 +405,23 @@ ckfini(int markclean)
}
flush(fswritefd, &cgblk);
free(cgblk.b_un.b_buf);
- for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) {
+ cnt = 0;
+ TAILQ_FOREACH_REVERSE_SAFE(bp, &bufhead, buflist, b_list, nbp) {
+ TAILQ_REMOVE(&bufhead, bp, b_list);
cnt++;
flush(fswritefd, bp);
- nbp = bp->b_prev;
free(bp->b_un.b_buf);
free((char *)bp);
}
- if (bufhead.b_size != cnt)
- errx(EEXIT, "panic: lost %d buffers", bufhead.b_size - cnt);
+ if (numbufs != cnt)
+ errx(EEXIT, "panic: lost %d buffers", numbufs - cnt);
+ for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
+ if (cgbufs[cnt].b_un.b_cg == NULL)
+ continue;
+ flush(fswritefd, &cgbufs[cnt]);
+ free(cgbufs[cnt].b_un.b_cg);
+ }
+ free(cgbufs);
pbp = pdirbp = (struct bufarea *)0;
if (cursnapshot == 0 && sblock.fs_clean != markclean) {
if ((sblock.fs_clean = markclean) != 0) {
@@ -343,13 +447,88 @@ ckfini(int markclean)
rerun = 1;
}
}
- if (debug && totalreads > 0)
- printf("cache missed %ld of %ld (%d%%)\n", diskreads,
- totalreads, (int)(diskreads * 100 / totalreads));
(void)close(fsreadfd);
(void)close(fswritefd);
}
+/*
+ * Print out I/O statistics.
+ */
+void
+IOstats(char *what)
+{
+ int i;
+
+ if (debug == 0)
+ return;
+ if (diskreads == 0) {
+ printf("%s: no I/O\n\n", what);
+ return;
+ }
+ if (startpass.tv_sec == 0)
+ startpass = startprog;
+ printf("%s: I/O statistics\n", what);
+ printIOstats();
+ totaldiskreads += diskreads;
+ diskreads = 0;
+ for (i = 0; i < BT_NUMBUFTYPES; i++) {
+ timespecadd(&totalreadtime[i], &readtime[i]);
+ totalreadcnt[i] += readcnt[i];
+ readtime[i].tv_sec = readtime[i].tv_nsec = 0;
+ readcnt[i] = 0;
+ }
+ clock_gettime(CLOCK_REALTIME_PRECISE, &startpass);
+}
+
+void
+finalIOstats(void)
+{
+ int i;
+
+ if (debug == 0)
+ return;
+ printf("Final I/O statistics\n");
+ totaldiskreads += diskreads;
+ diskreads = totaldiskreads;
+ startpass = startprog;
+ for (i = 0; i < BT_NUMBUFTYPES; i++) {
+ timespecadd(&totalreadtime[i], &readtime[i]);
+ totalreadcnt[i] += readcnt[i];
+ readtime[i] = totalreadtime[i];
+ readcnt[i] = totalreadcnt[i];
+ }
+ printIOstats();
+}
+
+static void printIOstats(void)
+{
+ long long msec, totalmsec;
+ int i;
+
+ clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass);
+ timespecsub(&finishpass, &startpass);
+ printf("Running time: %jd.%03ld sec\n",
+ (intmax_t)finishpass.tv_sec, finishpass.tv_nsec / 1000000);
+ printf("buffer reads by type:\n");
+ for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++)
+ totalmsec += readtime[i].tv_sec * 1000 +
+ readtime[i].tv_nsec / 1000000;
+ if (totalmsec == 0)
+ totalmsec = 1;
+ for (i = 0; i < BT_NUMBUFTYPES; i++) {
+ if (readcnt[i] == 0)
+ continue;
+ msec =
+ readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000;
+ printf("%21s:%8ld %2ld.%ld%% %4jd.%03ld sec %2lld.%lld%%\n",
+ buftype[i], readcnt[i], readcnt[i] * 100 / diskreads,
+ (readcnt[i] * 1000 / diskreads) % 10,
+ (intmax_t)readtime[i].tv_sec, readtime[i].tv_nsec / 1000000,
+ msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10);
+ }
+ printf("\n");
+}
+
int
blread(int fd, char *buf, ufs2_daddr_t blk, long size)
{
@@ -361,6 +540,8 @@ blread(int fd, char *buf, ufs2_daddr_t blk, long size)
offset *= dev_bsize;
if (bkgrdflag)
slowio_start();
+ totalreads++;
+ diskreads++;
if (lseek(fd, offset, 0) < 0)
rwerror("SEEK BLK", blk);
else if (read(fd, buf, (int)size) == size) {
@@ -442,8 +623,9 @@ blerase(int fd, ufs2_daddr_t blk, long size)
* test fails, offer an option to rebuild the whole cylinder group.
*/
int
-check_cgmagic(int cg, struct cg *cgp)
+check_cgmagic(int cg, struct bufarea *cgbp)
{
+ struct cg *cgp = cgbp->b_un.b_cg;
/*
* Extended cylinder group checks.
@@ -503,7 +685,7 @@ check_cgmagic(int cg, struct cg *cgp)
cgp->cg_nextfreeoff = cgp->cg_clusteroff +
howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
}
- cgdirty();
+ dirty(cgbp);
return (0);
}
@@ -514,7 +696,8 @@ ufs2_daddr_t
allocblk(long frags)
{
int i, j, k, cg, baseblk;
- struct cg *cgp = &cgrp;
+ struct bufarea *cgbp;
+ struct cg *cgp;
if (frags <= 0 || frags > sblock.fs_frag)
return (0);
@@ -530,8 +713,9 @@ allocblk(long frags)
continue;
}
cg = dtog(&sblock, i + j);
- getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
- if (!check_cgmagic(cg, cgp))
+ cgbp = cgget(cg);
+ cgp = cgbp->b_un.b_cg;
+ if (!check_cgmagic(cg, cgbp))
return (0);
baseblk = dtogd(&sblock, i + j);
for (k = 0; k < frags; k++) {
@@ -543,7 +727,7 @@ allocblk(long frags)
cgp->cg_cs.cs_nbfree--;
else
cgp->cg_cs.cs_nffree -= frags;
- cgdirty();
+ dirty(cgbp);
return (i + j);
}
}
diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c
index 389150a3d5f2..e8baf097c22f 100644
--- a/sbin/fsck_ffs/inode.c
+++ b/sbin/fsck_ffs/inode.c
@@ -52,7 +52,7 @@ __FBSDID("$FreeBSD$");
static ino_t startinum;
-static int iblock(struct inodesc *, long ilevel, off_t isize);
+static int iblock(struct inodesc *, long ilevel, off_t isize, int type);
int
ckinode(union dinode *dp, struct inodesc *idesc)
@@ -121,7 +121,7 @@ ckinode(union dinode *dp, struct inodesc *idesc)
sizepb *= NINDIR(&sblock);
if (DIP(&dino, di_ib[i])) {
idesc->id_blkno = DIP(&dino, di_ib[i]);
- ret = iblock(idesc, i + 1, remsize);
+ ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i);
if (ret & STOP)
return (ret);
} else {
@@ -151,7 +151,7 @@ ckinode(union dinode *dp, struct inodesc *idesc)
}
static int
-iblock(struct inodesc *idesc, long ilevel, off_t isize)
+iblock(struct inodesc *idesc, long ilevel, off_t isize, int type)
{
struct bufarea *bp;
int i, n, (*func)(struct inodesc *), nif;
@@ -168,7 +168,7 @@ iblock(struct inodesc *idesc, long ilevel, off_t isize)
func = dirscan;
if (chkrange(idesc->id_blkno, idesc->id_numfrags))
return (SKIP);
- bp = getdatablk(idesc->id_blkno, sblock.fs_bsize);
+ bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type);
ilevel--;
for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++)
sizepb *= NINDIR(&sblock);
@@ -199,7 +199,7 @@ iblock(struct inodesc *idesc, long ilevel, off_t isize)
if (ilevel == 0)
n = (*func)(idesc);
else
- n = iblock(idesc, ilevel, isize);
+ n = iblock(idesc, ilevel, isize, type);
if (n & STOP) {
bp->b_flags &= ~B_INUSE;
return (n);
@@ -292,7 +292,7 @@ ginode(ino_t inumber)
iblk = ino_to_fsba(&sblock, inumber);
if (pbp != 0)
pbp->b_flags &= ~B_INUSE;
- pbp = getdatablk(iblk, sblock.fs_bsize);
+ pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES);
startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock);
}
if (sblock.fs_magic == FS_UFS1_MAGIC)
@@ -306,8 +306,8 @@ ginode(ino_t inumber)
* over all the inodes in numerical order.
*/
static ino_t nextino, lastinum, lastvalidinum;
-static long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
-static caddr_t inodebuf;
+static long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
+static struct bufarea inobuf;
union dinode *
getnextinode(ino_t inumber, int rebuildcg)
@@ -315,7 +315,7 @@ getnextinode(ino_t inumber, int rebuildcg)
int j;
long size;
mode_t mode;
- ufs2_daddr_t ndb, dblk;
+ ufs2_daddr_t ndb, blk;
union dinode *dp;
static caddr_t nextinop;
@@ -323,9 +323,9 @@ getnextinode(ino_t inumber, int rebuildcg)
errx(EEXIT, "bad inode number %ju to nextinode",
(uintmax_t)inumber);
if (inumber >= lastinum) {
- readcnt++;
- dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
- if (readcnt % readpercg == 0) {
+ readcount++;
+ blk = ino_to_fsba(&sblock, lastinum);
+ if (readcount % readpercg == 0) {
size = partialsize;
lastinum += partialcnt;
} else {
@@ -333,14 +333,14 @@ getnextinode(ino_t inumber, int rebuildcg)
lastinum += fullcnt;
}
/*
- * If blread returns an error, it will already have zeroed
+ * If getblk encounters an error, it will already have zeroed
* out the buffer, so we do not need to do so here.
*/
- (void)blread(fsreadfd, inodebuf, dblk, size);
- nextinop = inodebuf;
+ getblk(&inobuf, blk, size);
+ nextinop = inobuf.b_un.b_buf;
}
dp = (union dinode *)nextinop;
- if (rebuildcg && nextinop == inodebuf) {
+ if (rebuildcg && nextinop == inobuf.b_un.b_buf) {
/*
* Try to determine if we have reached the end of the
* allocated inodes.
@@ -406,8 +406,8 @@ setinodebuf(ino_t inum)
startinum = 0;
nextino = inum;
lastinum = inum;
- readcnt = 0;
- if (inodebuf != NULL)
+ readcount = 0;
+ if (inobuf.b_un.b_buf != NULL)
return;
inobufsize = blkroundup(&sblock, INOBUFSIZE);
fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ?
@@ -422,7 +422,8 @@ setinodebuf(ino_t inum)
partialcnt = fullcnt;
partialsize = inobufsize;
}
- if ((inodebuf = malloc((unsigned)inobufsize)) == NULL)
+ initbarea(&inobuf, BT_INODES);
+ if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL)
errx(EEXIT, "cannot allocate space for inode buffer");
}
@@ -430,9 +431,9 @@ void
freeinodebuf(void)
{
- if (inodebuf != NULL)
- free((char *)inodebuf);
- inodebuf = NULL;
+ if (inobuf.b_un.b_buf != NULL)
+ free((char *)inobuf.b_un.b_buf);
+ inobuf.b_un.b_buf = NULL;
}
/*
@@ -453,7 +454,7 @@ cacheino(union dinode *dp, ino_t inumber)
else
blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
inp = (struct inoinfo *)
- malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
+ Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t));
if (inp == NULL)
errx(EEXIT, "cannot increase directory list");
inpp = &inphead[inumber % dirhash];
@@ -656,7 +657,8 @@ allocino(ino_t request, int type)
{
ino_t ino;
union dinode *dp;
- struct cg *cgp = &cgrp;
+ struct bufarea *cgbp;
+ struct cg *cgp;
int cg;
if (request == 0)
@@ -669,8 +671,9 @@ allocino(ino_t request, int type)
if (ino == maxino)
return (0);
cg = ino_to_cg(&sblock, ino);
- getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
- if (!check_cgmagic(cg, cgp))
+ cgbp = cgget(cg);
+ cgp = cgbp->b_un.b_cg;
+ if (!check_cgmagic(cg, cgbp))
return (0);
setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
cgp->cg_cs.cs_nifree--;
@@ -686,7 +689,7 @@ allocino(ino_t request, int type)
default:
return (0);
}
- cgdirty();
+ dirty(cgbp);
dp = ginode(ino);
DIP_SET(dp, di_db[0], allocblk((long)1));
if (DIP(dp, di_db[0]) == 0) {
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 69f157ab195e..27f17dbba050 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -424,7 +424,9 @@ checkfilesys(char *filesys)
printf("** Root file system\n");
printf("** Phase 1 - Check Blocks and Sizes\n");
}
+ clock_gettime(CLOCK_REALTIME_PRECISE, &startprog);
pass1();
+ IOstats("Pass1");
/*
* 1b: locate first references to duplicates, if any
@@ -437,6 +439,7 @@ checkfilesys(char *filesys)
usedsoftdep ? "softupdates" : "");
printf("** Phase 1b - Rescan For More DUPS\n");
pass1b();
+ IOstats("Pass1b");
}
/*
@@ -445,6 +448,7 @@ checkfilesys(char *filesys)
if (preen == 0)
printf("** Phase 2 - Check Pathnames\n");
pass2();
+ IOstats("Pass2");
/*
* 3: scan inodes looking for disconnected directories
@@ -452,6 +456,7 @@ checkfilesys(char *filesys)
if (preen == 0)
printf("** Phase 3 - Check Connectivity\n");
pass3();
+ IOstats("Pass3");
/*
* 4: scan inodes looking for disconnected files; check reference counts
@@ -459,6 +464,7 @@ checkfilesys(char *filesys)
if (preen == 0)
printf("** Phase 4 - Check Reference Counts\n");
pass4();
+ IOstats("Pass4");
/*
* 5: check and repair resource counts in cylinder groups
@@ -466,6 +472,7 @@ checkfilesys(char *filesys)
if (preen == 0)
printf("** Phase 5 - Check Cyl groups\n");
pass5();
+ IOstats("Pass5");
/*
* print out summary statistics
@@ -519,6 +526,7 @@ checkfilesys(char *filesys)
}
if (rerun)
resolved = 0;
+ finalIOstats();
/*
* Check to see if the file system is mounted read-write.
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index 08e84b94aff1..319954122863 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -61,6 +61,8 @@ pass1(void)
{
struct inostat *info;
struct inodesc idesc;
+ struct bufarea *cgbp;
+ struct cg *cgp;
ino_t inumber, inosused, mininos;
ufs2_daddr_t i, cgd;
u_int8_t *cp;
@@ -92,12 +94,13 @@ pass1(void)
for (c = 0; c < sblock.fs_ncg; c++) {
inumber = c * sblock.fs_ipg;
setinodebuf(inumber);
- getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
+ cgbp = cgget(c);
+ cgp = cgbp->b_un.b_cg;
rebuildcg = 0;
- if (!check_cgmagic(c, &cgrp))
+ if (!check_cgmagic(c, cgbp))
rebuildcg = 1;
if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) {
- inosused = cgrp.cg_initediblk;
+ inosused = cgp->cg_initediblk;
if (inosused > sblock.fs_ipg) {
pfatal(
"Too many initialized inodes (%ju > %d) in cylinder group %d\nReset to %d\n",
@@ -127,7 +130,7 @@ pass1(void)
* read only those inodes in from disk.
*/
if ((preen || inoopt) && usedsoftdep && !rebuildcg) {
- cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT];
+ cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT];
for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
if (*cp == 0)
continue;
@@ -149,7 +152,7 @@ pass1(void)
inostathead[c].il_stat = 0;
continue;
}
- info = calloc((unsigned)inosused, sizeof(struct inostat));
+ info = Calloc((unsigned)inosused, sizeof(struct inostat));
if (info == NULL)
errx(EEXIT, "cannot alloc %u bytes for inoinfo",
(unsigned)(sizeof(struct inostat) * inosused));
@@ -169,7 +172,7 @@ pass1(void)
* valid number for this cylinder group.
*/
if (checkinode(inumber, &idesc, rebuildcg) == 0 &&
- i > cgrp.cg_initediblk)
+ i > cgp->cg_initediblk)
break;
}
/*
@@ -181,16 +184,16 @@ pass1(void)
mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock));
if (inoopt && !preen && !rebuildcg &&
sblock.fs_magic == FS_UFS2_MAGIC &&
- cgrp.cg_initediblk > 2 * INOPB(&sblock) &&
- mininos < cgrp.cg_initediblk) {
- i = cgrp.cg_initediblk;
+ cgp->cg_initediblk > 2 * INOPB(&sblock) &&
+ mininos < cgp->cg_initediblk) {
+ i = cgp->cg_initediblk;
if (mininos < 2 * INOPB(&sblock))
- cgrp.cg_initediblk = 2 * INOPB(&sblock);
+ cgp->cg_initediblk = 2 * INOPB(&sblock);
else
- cgrp.cg_initediblk = mininos;
+ cgp->cg_initediblk = mininos;
pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n",
- c, i, cgrp.cg_initediblk, "VALID INODES");
- cgdirty();
+ c, i, cgp->cg_initediblk, "VALID INODES");
+ dirty(cgbp);
}
if (inosused < sblock.fs_ipg)
continue;
@@ -199,11 +202,11 @@ pass1(void)
inosused = 0;
else
inosused = lastino - (c * sblock.fs_ipg);
- if (rebuildcg && inosused > cgrp.cg_initediblk &&
+ if (rebuildcg && inosused > cgp->cg_initediblk &&
sblock.fs_magic == FS_UFS2_MAGIC) {
- cgrp.cg_initediblk = roundup(inosused, INOPB(&sblock));
+ cgp->cg_initediblk = roundup(inosused, INOPB(&sblock));
pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c,
- cgrp.cg_initediblk);
+ cgp->cg_initediblk);
}
/*
* If we were not able to determine in advance which inodes
@@ -219,7 +222,7 @@ pass1(void)
inostathead[c].il_stat = 0;
continue;
}
- info = calloc((unsigned)inosused, sizeof(struct inostat));
+ info = Calloc((unsigned)inosused, sizeof(struct inostat));
if (info == NULL)
errx(EEXIT, "cannot alloc %u bytes for inoinfo",
(unsigned)(sizeof(struct inostat) * inosused));
@@ -482,7 +485,7 @@ pass1check(struct inodesc *idesc)
}
return (STOP);
}
- new = (struct dups *)malloc(sizeof(struct dups));
+ new = (struct dups *)Malloc(sizeof(struct dups));
if (new == NULL) {
pfatal("DUP TABLE OVERFLOW.");
if (reply("CONTINUE") == 0) {
diff --git a/sbin/fsck_ffs/pass5.c b/sbin/fsck_ffs/pass5.c
index b95df7350a2e..146acecdb01f 100644
--- a/sbin/fsck_ffs/pass5.c
+++ b/sbin/fsck_ffs/pass5.c
@@ -59,14 +59,14 @@ pass5(void)
int c, i, j, blk, frags, basesize, mapsize;
int inomapsize, blkmapsize;
struct fs *fs = &sblock;
- struct cg *cg = &cgrp;
ufs2_daddr_t d, dbase, dmax, start;
int rewritecg = 0;
struct csum *cs;
struct csum_total cstotal;
struct inodesc idesc[3];
char buf[MAXBSIZE];
- struct cg *newcg = (struct cg *)buf;
+ struct cg *cg, *newcg = (struct cg *)buf;
+ struct bufarea *cgbp;
inoinfo(WINO)->ino_state = USTATE;
memset(newcg, 0, (size_t)fs->fs_cgsize);
@@ -162,7 +162,8 @@ pass5(void)
c * 100 / sblock.fs_ncg);
got_sigalarm = 0;
}
- getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
+ cgbp = cgget(c);
+ cg = cgbp->b_un.b_cg;
if (!cg_chkmagic(cg))
pfatal("CG %d: BAD MAGIC NUMBER\n", c);
newcg->cg_time = cg->cg_time;
@@ -324,14 +325,14 @@ pass5(void)
}
if (rewritecg) {
memmove(cg, newcg, (size_t)fs->fs_cgsize);
- cgdirty();
+ dirty(cgbp);
continue;
}
if (cursnapshot == 0 &&
memcmp(newcg, cg, basesize) != 0 &&
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
memmove(cg, newcg, (size_t)basesize);
- cgdirty();
+ dirty(cgbp);
}
if (bkgrdflag != 0 || usedsoftdep || debug)
update_maps(cg, newcg, bkgrdflag);
@@ -340,7 +341,7 @@ pass5(void)
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
memmove(cg_inosused(cg), cg_inosused(newcg),
(size_t)mapsize);
- cgdirty();
+ dirty(cgbp);
}
}
if (cursnapshot == 0 &&
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c
index ae0ea0519e42..85e954844319 100644
--- a/sbin/fsck_ffs/setup.c
+++ b/sbin/fsck_ffs/setup.c
@@ -240,7 +240,7 @@ setup(char *dev)
* read in the summary info.
*/
asked = 0;
- sblock.fs_csp = calloc(1, sblock.fs_cssize);
+ sblock.fs_csp = Calloc(1, sblock.fs_cssize);
if (sblock.fs_csp == NULL) {
printf("cannot alloc %u bytes for cg summary info\n",
(unsigned)sblock.fs_cssize);
@@ -249,6 +249,7 @@ setup(char *dev)
for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
size = sblock.fs_cssize - i < sblock.fs_bsize ?
sblock.fs_cssize - i : sblock.fs_bsize;
+ readcnt[sblk.b_type]++;
if (blread(fsreadfd, (char *)sblock.fs_csp + i,
fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
size) != 0 && !asked) {
@@ -264,13 +265,13 @@ setup(char *dev)
* allocate and initialize the necessary maps
*/
bmapsize = roundup(howmany(maxfsblock, CHAR_BIT), sizeof(short));
- blockmap = calloc((unsigned)bmapsize, sizeof (char));
+ blockmap = Calloc((unsigned)bmapsize, sizeof (char));
if (blockmap == NULL) {
printf("cannot alloc %u bytes for blockmap\n",
(unsigned)bmapsize);
goto badsb;
}
- inostathead = calloc((unsigned)(sblock.fs_ncg),
+ inostathead = Calloc((unsigned)(sblock.fs_ncg),
sizeof(struct inostatlist));
if (inostathead == NULL) {
printf("cannot alloc %u bytes for inostathead\n",
@@ -281,9 +282,9 @@ setup(char *dev)
dirhash = numdirs;
inplast = 0;
listmax = numdirs + 10;
- inpsort = (struct inoinfo **)calloc((unsigned)listmax,
+ inpsort = (struct inoinfo **)Calloc((unsigned)listmax,
sizeof(struct inoinfo *));
- inphead = (struct inoinfo **)calloc((unsigned)numdirs,
+ inphead = (struct inoinfo **)Calloc((unsigned)numdirs,
sizeof(struct inoinfo *));
if (inpsort == NULL || inphead == NULL) {
printf("cannot alloc %ju bytes for inphead\n",
@@ -322,6 +323,7 @@ readsb(int listerr)
if (bflag) {
super = bflag;
+ readcnt[sblk.b_type]++;
if ((blread(fsreadfd, (char *)&sblock, super, (long)SBLOCKSIZE)))
return (0);
if (sblock.fs_magic == FS_BAD_MAGIC) {
@@ -337,6 +339,7 @@ readsb(int listerr)
} else {
for (i = 0; sblock_try[i] != -1; i++) {
super = sblock_try[i] / dev_bsize;
+ readcnt[sblk.b_type]++;
if ((blread(fsreadfd, (char *)&sblock, super,
(long)SBLOCKSIZE)))
return (0);
@@ -439,10 +442,10 @@ sblock_init(void)
fswritefd = -1;
fsmodified = 0;
lfdir = 0;
- initbarea(&sblk);
- initbarea(&asblk);
- sblk.b_un.b_buf = malloc(SBLOCKSIZE);
- asblk.b_un.b_buf = malloc(SBLOCKSIZE);
+ initbarea(&sblk, BT_SUPERBLK);
+ initbarea(&asblk, BT_SUPERBLK);
+ sblk.b_un.b_buf = Malloc(SBLOCKSIZE);
+ asblk.b_un.b_buf = Malloc(SBLOCKSIZE);
if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL)
errx(EEXIT, "cannot allocate space for superblock");
if ((lp = getdisklabel(NULL, fsreadfd)))
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index ae4748716e2d..5fca0f5fbfdf 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -161,7 +161,7 @@ errmalloc(size_t n)
{
void *a;
- a = malloc(n);
+ a = Malloc(n);
if (a == NULL)
err(EX_OSERR, "malloc(%zu)", n);
return (a);
@@ -194,7 +194,7 @@ opendisk(const char *devnam)
{
if (disk != NULL)
return;
- disk = malloc(sizeof(*disk));
+ disk = Malloc(sizeof(*disk));
if (disk == NULL)
err(EX_OSERR, "malloc(%zu)", sizeof(*disk));
if (ufs_disk_fillout(disk, devnam) == -1) {
diff --git a/sbin/fsdb/fsdb.c b/sbin/fsdb/fsdb.c
index e169061e9f65..1315aeca0acb 100644
--- a/sbin/fsdb/fsdb.c
+++ b/sbin/fsdb/fsdb.c
@@ -441,7 +441,8 @@ CMDFUNCSTART(findblk)
ino_t inum, inosused;
uint32_t *wantedblk32;
uint64_t *wantedblk64;
- struct cg *cgp = &cgrp;
+ struct bufarea *cgbp;
+ struct cg *cgp;
int c, i, is_ufs2;
wantedblksize = (argc - 1);
@@ -473,8 +474,8 @@ CMDFUNCSTART(findblk)
*/
inum = c * sblock.fs_ipg;
/* Read cylinder group. */
- getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
- memcpy(cgp, cgblk.b_un.b_cg, sblock.fs_cgsize);
+ cgbp = cgget(c);
+ cgp = cgbp->b_un.b_cg;
/*
* Get a highest used inode number for a given cylinder group.
* For UFS1 all inodes initialized at the newfs stage.
diff --git a/sbin/fsdb/fsdbutil.c b/sbin/fsdb/fsdbutil.c
index eaea3db79fd5..ba0b64e72801 100644
--- a/sbin/fsdb/fsdbutil.c
+++ b/sbin/fsdb/fsdbutil.c
@@ -239,12 +239,11 @@ printindir(ufs2_daddr_t blk, int level, char *bufp)
/* for the final indirect level, don't use the cache */
bp = &buf;
bp->b_un.b_buf = bufp;
- bp->b_prev = bp->b_next = bp;
- initbarea(bp);
+ initbarea(bp, BT_UNKNOWN);
getblk(bp, blk, sblock.fs_bsize);
} else
- bp = getdatablk(blk, sblock.fs_bsize);
+ bp = getdatablk(blk, sblock.fs_bsize, BT_UNKNOWN);
cpl = charsperline();
for (i = charssofar = 0; i < NINDIR(&sblock); i++) {
diff --git a/sbin/geom/class/concat/gconcat.8 b/sbin/geom/class/concat/gconcat.8
index 2e1b79dadd1a..b797a1c24dc2 100644
--- a/sbin/geom/class/concat/gconcat.8
+++ b/sbin/geom/class/concat/gconcat.8
@@ -183,11 +183,11 @@ growfs /dev/concat/data
.Xr loader.conf 5 ,
.Xr geom 8 ,
.Xr growfs 8 ,
+.Xr gvinum 8 ,
.Xr mount 8 ,
.Xr newfs 8 ,
.Xr sysctl 8 ,
-.Xr umount 8 ,
-.Xr vinum 8
+.Xr umount 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/geom/class/eli/geli.8 b/sbin/geom/class/eli/geli.8
index 3cb1f211769f..263b8b238679 100644
--- a/sbin/geom/class/eli/geli.8
+++ b/sbin/geom/class/eli/geli.8
@@ -970,7 +970,7 @@ Enter passphrase:
supports two encryption modes:
.Nm XTS ,
which was standardized as
-.Nm IEE P1619
+.Nm IEEE P1619
and
.Nm CBC
with unpredictable IV.
diff --git a/sbin/geom/class/eli/geom_eli.c b/sbin/geom/class/eli/geom_eli.c
index f20980024bb7..3eee6f249b54 100644
--- a/sbin/geom/class/eli/geom_eli.c
+++ b/sbin/geom/class/eli/geom_eli.c
@@ -259,6 +259,8 @@ struct g_command class_commands[] = {
static int verbose = 0;
+#define BUFSIZE 1024
+
static int
eli_protect(struct gctl_req *req)
{
@@ -326,22 +328,6 @@ eli_main(struct gctl_req *req, unsigned int flags)
gctl_error(req, "Unknown command: %s.", name);
}
-static void
-arc4rand(unsigned char *buf, size_t size)
-{
- uint32_t *buf4;
- size_t size4;
- unsigned int i;
-
- buf4 = (uint32_t *)buf;
- size4 = size / 4;
-
- for (i = 0; i < size4; i++)
- buf4[i] = arc4random();
- for (i *= 4; i < size; i++)
- buf[i] = arc4random() % 0xff;
-}
-
static bool
eli_is_attached(const char *prov)
{
@@ -360,7 +346,7 @@ static int
eli_genkey_files(struct gctl_req *req, bool new, const char *type,
struct hmac_ctx *ctxp, char *passbuf, size_t passbufsize)
{
- char *p, buf[MAXPHYS], argname[16];
+ char *p, buf[BUFSIZE], argname[16];
const char *file;
int error, fd, i;
ssize_t done;
@@ -396,6 +382,8 @@ eli_genkey_files(struct gctl_req *req, bool new, const char *type,
while ((done = read(fd, buf, sizeof(buf))) > 0)
g_eli_crypto_hmac_update(ctxp, buf, done);
} else /* if (strcmp(type, "passfile") == 0) */ {
+ assert(strcmp(type, "passfile") == 0);
+
while ((done = read(fd, buf, sizeof(buf) - 1)) > 0) {
buf[done] = '\0';
p = strchr(buf, '\n');
@@ -445,7 +433,7 @@ eli_genkey_passphrase_prompt(struct gctl_req *req, bool new, char *passbuf,
}
if (new) {
- char tmpbuf[BUFSIZ];
+ char tmpbuf[BUFSIZE];
p = readpassphrase("Reenter new passphrase: ",
tmpbuf, sizeof(tmpbuf),
@@ -474,7 +462,7 @@ static int
eli_genkey_passphrase(struct gctl_req *req, struct g_eli_metadata *md, bool new,
struct hmac_ctx *ctxp)
{
- char passbuf[MAXPHYS];
+ char passbuf[BUFSIZE];
bool nopassphrase;
int nfiles;
@@ -813,8 +801,8 @@ eli_init(struct gctl_req *req)
}
md.md_keys = 0x01;
- arc4rand(md.md_salt, sizeof(md.md_salt));
- arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
+ arc4random_buf(md.md_salt, sizeof(md.md_salt));
+ arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
/* Generate user key. */
if (eli_genkey(req, &md, key, true) == NULL) {
@@ -1146,7 +1134,7 @@ eli_delkey_detached(struct gctl_req *req, const char *prov)
all = gctl_get_int(req, "all");
if (all)
- arc4rand(md.md_mkeys, sizeof(md.md_mkeys));
+ arc4random_buf(md.md_mkeys, sizeof(md.md_mkeys));
else {
force = gctl_get_int(req, "force");
val = gctl_get_intmax(req, "keyno");
@@ -1170,7 +1158,7 @@ eli_delkey_detached(struct gctl_req *req, const char *prov)
return;
}
mkeydst = md.md_mkeys + nkey * G_ELI_MKEYLEN;
- arc4rand(mkeydst, G_ELI_MKEYLEN);
+ arc4random_buf(mkeydst, G_ELI_MKEYLEN);
}
eli_metadata_store(req, prov, &md);
@@ -1262,13 +1250,14 @@ eli_trash_metadata(struct gctl_req *req, const char *prov, int fd, off_t offset)
error = 0;
do {
- arc4rand(sector, size);
+ arc4random_buf(sector, size);
if (pwrite(fd, sector, size, offset) != size) {
if (error == 0)
error = errno;
}
(void)g_flush(fd);
} while (--overwrites > 0);
+ free(sector);
if (error != 0) {
gctl_error(req, "Cannot trash metadata on provider %s: %s.",
prov, strerror(error));
diff --git a/sbin/geom/class/mirror/gmirror.8 b/sbin/geom/class/mirror/gmirror.8
index baaa827daf20..58ff8afcbc4c 100644
--- a/sbin/geom/class/mirror/gmirror.8
+++ b/sbin/geom/class/mirror/gmirror.8
@@ -340,11 +340,11 @@ there.
.Xr geom 4 ,
.Xr dumpon 8 ,
.Xr geom 8 ,
+.Xr gvinum 8 ,
.Xr mount 8 ,
.Xr newfs 8 ,
.Xr savecore 8 ,
-.Xr umount 8 ,
-.Xr vinum 8
+.Xr umount 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index 8843e5324954..73869009b540 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -31,33 +31,6 @@
.Nm gpart
.Nd "control utility for the disk partitioning GEOM class"
.Sh SYNOPSIS
-To add support for the disk partitioning GEOM class,
-place one or more of the following
-lines in the kernel configuration file:
-.Bd -ragged -offset indent
-.Cd "options GEOM_PART_APM"
-.Cd "options GEOM_PART_BSD"
-.Cd "options GEOM_PART_GPT"
-.Cd "options GEOM_PART_LDM"
-.Cd "options GEOM_PART_MBR"
-.Cd "options GEOM_PART_EBR"
-.Cd "options GEOM_PART_EBR_COMPAT"
-.Cd "options GEOM_PART_PC98"
-.Cd "options GEOM_PART_VTOC8"
-.Ed
-.Pp
-These options provide support for the various types of partitioning
-schemes supported by the
-.Ns Nm
-utility.
-See
-.Sx "PARTITIONING SCHEMES"
-below for more details.
-.Pp
-Usage of the
-.Ns Nm
-utility:
-.Pp
.\" ==== ADD ====
.Nm
.Cm add
@@ -583,7 +556,7 @@ The system partition for computers that use the Extensible Firmware
Interface (EFI).
In such cases, the GPT partitioning scheme is used and the
actual partition type for the system partition can also be specified as
-.Qq Li "!c12a7328-f81f-11d2-ba4b-00a0c93ec93ab" .
+.Qq Li "!c12a7328-f81f-11d2-ba4b-00a0c93ec93b" .
.It Cm freebsd
A
.Fx
diff --git a/sbin/geom/class/raid/graid.8 b/sbin/geom/class/raid/graid.8
index ed33e00ae977..47d7fa2c8690 100644
--- a/sbin/geom/class/raid/graid.8
+++ b/sbin/geom/class/raid/graid.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 16, 2013
+.Dd April 4, 2013
.Dt GRAID 8
.Os
.Sh NAME
@@ -242,8 +242,7 @@ RAID5 (3+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ disks).
Configurations not supported by NVIDIA MediaShield RAID BIOS, but enforceable
on your own risk: RAID1 (3+ disks).
.It Promise
-The format used by Promise and AMD/ATI RAID BIOSes and FreeBSD ataraid(4)
-driver.
+The format used by Promise and AMD/ATI RAID BIOSes.
Supports multiple volumes per array.
Each disk can be split to be used by up to two arbitrary volumes.
Supports configurations: RAID0 (2+ disks), RAID1 (2 disks),
@@ -305,13 +304,16 @@ Write errors are always considered as disk failures.
Time to wait for missing array components on startup.
.It Va kern.geom.raid. Ns Ar X Ns Va .enable : No 1
Enable taste for specific metadata or transformation module.
+.It Va kern.geom.raid.legacy_aliases : No 0
+Enable geom raid emulation of legacy /dev/ar%d devices.
+This should aid the upgrade of systems from legacy to modern releases.
.El
.Sh EXIT STATUS
Exit status is 0 on success, and non-zero if the command fails.
.Sh SEE ALSO
.Xr geom 4 ,
.Xr geom 8 ,
-.Xr vinum 8
+.Xr gvinum 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/geom/class/stripe/gstripe.8 b/sbin/geom/class/stripe/gstripe.8
index ee70184bdb3a..33ef30bf85ce 100644
--- a/sbin/geom/class/stripe/gstripe.8
+++ b/sbin/geom/class/stripe/gstripe.8
@@ -213,8 +213,6 @@ The
interleave is in number of bytes,
unlike
.Xr ccdconfig 8
-and
-.Xr atacontrol 8
which use the number of sectors.
A
.Xr ccdconfig 8
@@ -229,14 +227,13 @@ for
.Sh SEE ALSO
.Xr geom 4 ,
.Xr loader.conf 5 ,
-.Xr atacontrol 8 ,
.Xr ccdconfig 8 ,
.Xr geom 8 ,
+.Xr gvinum 8 ,
.Xr mount 8 ,
.Xr newfs 8 ,
.Xr sysctl 8 ,
-.Xr umount 8 ,
-.Xr vinum 8
+.Xr umount 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/gvinum/gvinum.8 b/sbin/gvinum/gvinum.8
index 4753d7988647..5d362762b9a4 100644
--- a/sbin/gvinum/gvinum.8
+++ b/sbin/gvinum/gvinum.8
@@ -388,7 +388,10 @@ documentation were added by
.An "Chris Jones"
through the 2005 Google Summer
of Code program.
-.Ic a partial rewrite of gvinum was done by "Lukas Ertl" and "Ulf Lilleengen"
+A partial rewrite of gvinum was done by
+.An "Lukas Ertl"
+and
+.An "Ulf Lilleengen"
through the 2007 Google Summer of Code program.
The documentation have been updated to reflect the new functionality.
.Sh AUTHORS
@@ -419,9 +422,9 @@ This may leave data unprotected and is perhaps unwise.
Currently,
.Nm
does not yet fully implement all of the functions found in
-.Xr vinum 4 .
+.Nm vinum .
Specifically, the following commands from
-.Xr vinum 4
+.Nm vinum
are not supported:
.Bl -tag -width indent
.It Ic debug
diff --git a/sbin/hastctl/hastctl.8 b/sbin/hastctl/hastctl.8
index 9266fc01cbbd..bdca80d721a6 100644
--- a/sbin/hastctl/hastctl.8
+++ b/sbin/hastctl/hastctl.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 10, 2011
+.Dd March 14, 2013
.Dt HASTCTL 8
.Os
.Sh NAME
@@ -49,6 +49,11 @@
.Aq init | primary | secondary
.Ar all | name ...
.Nm
+.Cm list
+.Op Fl d
+.Op Fl c Ar config
+.Op Ar all | name ...
+.Nm
.Cm status
.Op Fl d
.Op Fl c Ar config
@@ -139,8 +144,11 @@ GEOM provider
.Pa /dev/hast/<name>
will not be created on secondary node.
.El
+.It Cm list
+Present verbose status of the configured resources.
.It Cm status
-Present status of the configured resources.
+Present terse (and more easy machine-parseable) status of the configured
+resources.
.It Cm dump
Dump metadata stored on local component for the configured resources.
.El
diff --git a/sbin/hastctl/hastctl.c b/sbin/hastctl/hastctl.c
index 0bd47f275ef6..883a2980e976 100644
--- a/sbin/hastctl/hastctl.c
+++ b/sbin/hastctl/hastctl.c
@@ -31,21 +31,11 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
-#include <sys/disk.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/sysctl.h>
#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
#include <libutil.h>
-#include <limits.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <unistd.h>
#include <activemap.h>
@@ -70,7 +60,8 @@ enum {
CMD_CREATE,
CMD_ROLE,
CMD_STATUS,
- CMD_DUMP
+ CMD_DUMP,
+ CMD_LIST
};
static __dead2 void
@@ -85,6 +76,9 @@ usage(void)
" %s role [-d] [-c config] <init | primary | secondary> all | name ...\n",
getprogname());
fprintf(stderr,
+ " %s list [-d] [-c config] [all | name ...]\n",
+ getprogname());
+ fprintf(stderr,
" %s status [-d] [-c config] [all | name ...]\n",
getprogname());
fprintf(stderr,
@@ -297,7 +291,7 @@ control_set_role(struct nv *nv, const char *newrole)
}
static int
-control_status(struct nv *nv)
+control_list(struct nv *nv)
{
unsigned int ii;
const char *str;
@@ -342,15 +336,58 @@ control_status(struct nv *nv)
(intmax_t)nv_get_uint64(nv, "dirty%u", ii));
printf(" statistics:\n");
printf(" reads: %ju\n",
- (uint64_t)nv_get_uint64(nv, "stat_read%u", ii));
+ (uintmax_t)nv_get_uint64(nv, "stat_read%u", ii));
printf(" writes: %ju\n",
- (uint64_t)nv_get_uint64(nv, "stat_write%u", ii));
+ (uintmax_t)nv_get_uint64(nv, "stat_write%u", ii));
printf(" deletes: %ju\n",
- (uint64_t)nv_get_uint64(nv, "stat_delete%u", ii));
+ (uintmax_t)nv_get_uint64(nv, "stat_delete%u", ii));
printf(" flushes: %ju\n",
- (uint64_t)nv_get_uint64(nv, "stat_flush%u", ii));
+ (uintmax_t)nv_get_uint64(nv, "stat_flush%u", ii));
printf(" activemap updates: %ju\n",
- (uint64_t)nv_get_uint64(nv, "stat_activemap_update%u", ii));
+ (uintmax_t)nv_get_uint64(nv, "stat_activemap_update%u", ii));
+ printf(" local errors: "
+ "read: %ju, write: %ju, delete: %ju, flush: %ju\n",
+ (uintmax_t)nv_get_uint64(nv, "stat_read_error%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "stat_write_error%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "stat_delete_error%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "stat_flush_error%u", ii));
+ }
+ return (ret);
+}
+
+static int
+control_status(struct nv *nv)
+{
+ unsigned int ii;
+ const char *str;
+ int error, hprinted, ret;
+
+ hprinted = 0;
+ ret = 0;
+
+ for (ii = 0; ; ii++) {
+ str = nv_get_string(nv, "resource%u", ii);
+ if (str == NULL)
+ break;
+ if (!hprinted) {
+ printf("Name\tStatus\t Role\t\tComponents\n");
+ hprinted = 1;
+ }
+ printf("%s\t", str);
+ error = nv_get_int16(nv, "error%u", ii);
+ if (error != 0) {
+ if (ret == 0)
+ ret = error;
+ printf("ERR%d\n", error);
+ continue;
+ }
+ str = nv_get_string(nv, "status%u", ii);
+ printf("%-9s", (str != NULL) ? str : "-");
+ printf("%-15s", nv_get_string(nv, "role%u", ii));
+ printf("%s\t",
+ nv_get_string(nv, "localpath%u", ii));
+ printf("%s\n",
+ nv_get_string(nv, "remoteaddr%u", ii));
}
return (ret);
}
@@ -375,6 +412,9 @@ main(int argc, char *argv[])
} else if (strcmp(argv[1], "role") == 0) {
cmd = CMD_ROLE;
optstr = "c:dh";
+ } else if (strcmp(argv[1], "list") == 0) {
+ cmd = CMD_LIST;
+ optstr = "c:dh";
} else if (strcmp(argv[1], "status") == 0) {
cmd = CMD_STATUS;
optstr = "c:dh";
@@ -463,8 +503,19 @@ main(int argc, char *argv[])
for (ii = 0; ii < argc - 1; ii++)
nv_add_string(nv, argv[ii + 1], "resource%d", ii);
break;
+ case CMD_LIST:
+ /* Obtain verbose status of the given resources. */
+ nv = nv_alloc();
+ nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd");
+ if (argc == 0)
+ nv_add_string(nv, "all", "resource%d", 0);
+ else {
+ for (ii = 0; ii < argc; ii++)
+ nv_add_string(nv, argv[ii], "resource%d", ii);
+ }
+ break;
case CMD_STATUS:
- /* Obtain status of the given resources. */
+ /* Obtain brief status of the given resources. */
nv = nv_alloc();
nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd");
if (argc == 0)
@@ -518,6 +569,9 @@ main(int argc, char *argv[])
case CMD_ROLE:
error = control_set_role(nv, argv[0]);
break;
+ case CMD_LIST:
+ error = control_list(nv);
+ break;
case CMD_STATUS:
error = control_status(nv);
break;
diff --git a/sbin/hastd/control.c b/sbin/hastd/control.c
index 925fd32645cb..3619fc61ff09 100644
--- a/sbin/hastd/control.c
+++ b/sbin/hastd/control.c
@@ -207,6 +207,14 @@ control_status_worker(struct hast_resource *res, struct nv *nvout,
"stat_flush%u", no);
nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_activemap_update"),
"stat_activemap_update%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_read_error"),
+ "stat_read_error%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_write_error"),
+ "stat_write_error%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_delete_error"),
+ "stat_delete_error%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_flush_error"),
+ "stat_flush_error%u", no);
end:
if (cnvin != NULL)
nv_free(cnvin);
@@ -459,6 +467,16 @@ ctrl_thread(void *arg)
nv_add_uint64(nvout, res->hr_stat_flush, "stat_flush");
nv_add_uint64(nvout, res->hr_stat_activemap_update,
"stat_activemap_update");
+ nv_add_uint64(nvout, res->hr_stat_read_error,
+ "stat_read_error");
+ nv_add_uint64(nvout, res->hr_stat_write_error +
+ res->hr_stat_activemap_write_error,
+ "stat_write_error");
+ nv_add_uint64(nvout, res->hr_stat_delete_error,
+ "stat_delete_error");
+ nv_add_uint64(nvout, res->hr_stat_flush_error +
+ res->hr_stat_activemap_flush_error,
+ "stat_flush_error");
nv_add_int16(nvout, 0, "error");
break;
case CONTROL_RELOAD:
diff --git a/sbin/hastd/hast.conf.5 b/sbin/hastd/hast.conf.5
index f6368bcf913e..3d921e46c039 100644
--- a/sbin/hastd/hast.conf.5
+++ b/sbin/hastd/hast.conf.5
@@ -129,9 +129,13 @@ The
.Aq node
argument can be replaced either by a full hostname as obtained by
.Xr gethostname 3 ,
-only first part of the hostname, or by node's UUID as found in the
+only first part of the hostname, by node's UUID as found in the
.Va kern.hostuuid
.Xr sysctl 8
+variable
+or by node's hostid as found in the
+.Va kern.hostid
+.Xr sysctl 8
variable.
.Pp
The following statements are available:
@@ -208,15 +212,12 @@ to the application was lost.
The risk of such a situation is very small.
The
.Ic memsync
-replication mode is currently not implemented.
+replication mode is the default.
.It Ic fullsync
.Pp
Mark the write operation as completed when local as well as remote
write completes.
This is the safest and the slowest replication mode.
-The
-.Ic fullsync
-replication mode is the default.
.It Ic async
.Pp
The write operation is reported as complete right after the local write
diff --git a/sbin/hastd/hast.h b/sbin/hastd/hast.h
index 263e98410944..b757994a19b5 100644
--- a/sbin/hastd/hast.h
+++ b/sbin/hastd/hast.h
@@ -53,8 +53,9 @@
* Version history:
* 0 - initial version
* 1 - HIO_KEEPALIVE added
+ * 2 - "memsync" and "received" attributes added for memsync mode
*/
-#define HAST_PROTO_VERSION 1
+#define HAST_PROTO_VERSION 2
#define EHAST_OK 0
#define EHAST_NOENTRY 1
@@ -142,8 +143,10 @@ struct hastd_config {
struct hast_resource {
/* Resource name. */
char hr_name[NAME_MAX];
- /* Replication mode (HAST_REPLICATION_*). */
+ /* Negotiated replication mode (HAST_REPLICATION_*). */
int hr_replication;
+ /* Configured replication mode (HAST_REPLICATION_*). */
+ int hr_original_replication;
/* Provider name that will appear in /dev/hast/. */
char hr_provname[NAME_MAX];
/* Synchronization extent size. */
@@ -156,6 +159,8 @@ struct hast_resource {
int hr_compression;
/* Checksum algorithm. */
int hr_checksum;
+ /* Protocol version. */
+ int hr_version;
/* Path to local component. */
char hr_localpath[PATH_MAX];
@@ -234,6 +239,18 @@ struct hast_resource {
uint64_t hr_stat_flush;
/* Number of activemap updates. */
uint64_t hr_stat_activemap_update;
+ /* Number of local read errors. */
+ uint64_t hr_stat_read_error;
+ /* Number of local write errors. */
+ uint64_t hr_stat_write_error;
+ /* Number of local delete errors. */
+ uint64_t hr_stat_delete_error;
+ /* Number of flush errors. */
+ uint64_t hr_stat_flush_error;
+ /* Number of activemap write errors. */
+ uint64_t hr_stat_activemap_write_error;
+ /* Number of activemap flush errors. */
+ uint64_t hr_stat_activemap_flush_error;
/* Next resource. */
TAILQ_ENTRY(hast_resource) hr_next;
diff --git a/sbin/hastd/hast_proto.c b/sbin/hastd/hast_proto.c
index 039e76715870..dd41fb1aaba4 100644
--- a/sbin/hastd/hast_proto.c
+++ b/sbin/hastd/hast_proto.c
@@ -112,7 +112,7 @@ hast_proto_send(const struct hast_resource *res, struct proto_conn *conn,
if (eb == NULL)
goto end;
- hdr.version = HAST_PROTO_VERSION;
+ hdr.version = res != NULL ? res->hr_version : HAST_PROTO_VERSION;
hdr.size = htole32((uint32_t)ebuf_size(eb));
if (ebuf_add_head(eb, &hdr, sizeof(hdr)) == -1)
goto end;
@@ -144,7 +144,7 @@ hast_proto_recv_hdr(const struct proto_conn *conn, struct nv **nvp)
if (proto_recv(conn, &hdr, sizeof(hdr)) == -1)
goto fail;
- if (hdr.version != HAST_PROTO_VERSION) {
+ if (hdr.version > HAST_PROTO_VERSION) {
errno = ERPCMISMATCH;
goto fail;
}
diff --git a/sbin/hastd/hastd.8 b/sbin/hastd/hastd.8
index 457b837f4bed..b614f366b687 100644
--- a/sbin/hastd/hastd.8
+++ b/sbin/hastd/hastd.8
@@ -51,7 +51,7 @@ Only one machine (cluster node) can actively use storage provided by
This machine is called primary.
The
.Nm
-daemon operates on block level, which makes it transparent for file
+daemon operates on block level, which makes it transparent to file
systems and applications.
.Pp
There is one main
@@ -68,7 +68,7 @@ The exact format is:
hastd: <resource name> (<role>)
.Ed
.Pp
-When (and only when)
+If (and only if)
.Nm
operates in primary role for the given resource, corresponding
.Pa /dev/hast/<name>
@@ -77,8 +77,8 @@ File systems and applications can use this provider to send I/O
requests to.
Every write, delete and flush operation
.Dv ( BIO_WRITE , BIO_DELETE , BIO_FLUSH )
-is send to local component and synchronously replicated
-to the remote (secondary) node if it is available.
+is send to local component and replicated to the remote (secondary) node if it
+is available.
Read operations
.Dv ( BIO_READ )
are handled locally unless I/O error occurs or local version of the data
diff --git a/sbin/hastd/hastd.c b/sbin/hastd/hastd.c
index ccce81daad7f..06b38e91331f 100644
--- a/sbin/hastd/hastd.c
+++ b/sbin/hastd/hastd.c
@@ -68,7 +68,7 @@ static struct hastd_config *cfg;
bool sigexit_received = false;
/* Path to pidfile. */
static const char *pidfile;
-/* PID file handle. */
+/* Pidfile handle. */
struct pidfh *pfh;
/* Do we run in foreground? */
static bool foreground;
@@ -748,6 +748,7 @@ listen_accept(struct hastd_listen *lst)
const char *resname;
const unsigned char *token;
char laddr[256], raddr[256];
+ uint8_t version;
size_t size;
pid_t pid;
int status;
@@ -797,6 +798,20 @@ listen_accept(struct hastd_listen *lst)
goto close;
}
pjdlog_debug(2, "%s: resource=%s", raddr, resname);
+ version = nv_get_uint8(nvin, "version");
+ pjdlog_debug(2, "%s: version=%hhu", raddr, version);
+ if (version == 0) {
+ /*
+ * If no version is sent, it means this is protocol version 1.
+ */
+ version = 1;
+ }
+ if (version > HAST_PROTO_VERSION) {
+ pjdlog_info("Remote protocol version %hhu is not supported, falling back to version %hhu.",
+ version, (unsigned char)HAST_PROTO_VERSION);
+ version = HAST_PROTO_VERSION;
+ }
+ pjdlog_debug(1, "Negotiated protocol version %hhu.", version);
token = nv_get_uint8_array(nvin, &size, "token");
/*
* NULL token means that this is first connection.
@@ -910,8 +925,10 @@ listen_accept(struct hastd_listen *lst)
*/
if (token == NULL) {
+ res->hr_version = version;
arc4random_buf(res->hr_token, sizeof(res->hr_token));
nvout = nv_alloc();
+ nv_add_uint8(nvout, version, "version");
nv_add_uint8_array(nvout, res->hr_token,
sizeof(res->hr_token), "token");
if (nv_error(nvout) != 0) {
@@ -922,7 +939,7 @@ listen_accept(struct hastd_listen *lst)
strerror(nv_error(nvout)));
goto fail;
}
- if (hast_proto_send(NULL, conn, nvout, NULL, 0) == -1) {
+ if (hast_proto_send(res, conn, nvout, NULL, 0) == -1) {
int error = errno;
pjdlog_errno(LOG_ERR, "Unable to send response to %s",
diff --git a/sbin/hastd/parse.y b/sbin/hastd/parse.y
index 04ea7ab2513e..bd0690a02abf 100644
--- a/sbin/hastd/parse.y
+++ b/sbin/hastd/parse.y
@@ -236,6 +236,7 @@ replication_statement: REPLICATION replication_type
case 1:
PJDLOG_ASSERT(curres != NULL);
curres->hr_replication = $2;
+ curres->hr_original_replication = $2;
break;
default:
PJDLOG_ABORT("replication at wrong depth level");
@@ -533,8 +534,10 @@ resource_start: STR
curres->hr_role = HAST_ROLE_INIT;
curres->hr_previous_role = HAST_ROLE_INIT;
curres->hr_replication = -1;
+ curres->hr_original_replication = -1;
curres->hr_checksum = -1;
curres->hr_compression = -1;
+ curres->hr_version = 1;
curres->hr_timeout = -1;
curres->hr_exec[0] = '\0';
curres->hr_provname[0] = '\0';
@@ -724,6 +727,7 @@ static int
isitme(const char *name)
{
char buf[MAXHOSTNAMELEN];
+ unsigned long hostid;
char *pos;
size_t bufsize;
@@ -738,7 +742,7 @@ isitme(const char *name)
return (1);
/*
- * Now check if it matches first part of the host name.
+ * Check if it matches first part of the host name.
*/
pos = strchr(buf, '.');
if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
@@ -747,7 +751,7 @@ isitme(const char *name)
}
/*
- * At the end check if name is equal to our host's UUID.
+ * Check if it matches host UUID.
*/
bufsize = sizeof(buf);
if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
@@ -758,6 +762,18 @@ isitme(const char *name)
return (1);
/*
+ * Check if it matches hostid.
+ */
+ bufsize = sizeof(hostid);
+ if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) {
+ pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed");
+ return (-1);
+ }
+ (void)snprintf(buf, sizeof(buf), "hostid%lu", hostid);
+ if (strcmp(buf, name) == 0)
+ return (1);
+
+ /*
* Looks like this isn't about us.
*/
return (0);
@@ -769,7 +785,7 @@ family_supported(int family)
int sock;
sock = socket(family, SOCK_STREAM, 0);
- if (sock == -1 && errno == EAFNOSUPPORT)
+ if (sock == -1 && errno == EPROTONOSUPPORT)
return (false);
if (sock >= 0)
(void)close(sock);
@@ -781,6 +797,7 @@ node_names(char **namesp)
{
static char names[MAXHOSTNAMELEN * 3];
char buf[MAXHOSTNAMELEN];
+ unsigned long hostid;
char *pos;
size_t bufsize;
@@ -808,6 +825,16 @@ node_names(char **namesp)
return (-1);
}
(void)strlcat(names, buf, sizeof(names));
+ (void)strlcat(names, ", ", sizeof(names));
+
+ /* Host ID. */
+ bufsize = sizeof(hostid);
+ if (sysctlbyname("kern.hostid", &hostid, &bufsize, NULL, 0) < 0) {
+ pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostid) failed");
+ return (-1);
+ }
+ (void)snprintf(buf, sizeof(buf), "hostid%lu", hostid);
+ (void)strlcat(names, buf, sizeof(names));
*namesp = names;
@@ -833,7 +860,7 @@ yy_config_parse(const char *config, bool exitonerror)
lineno = 0;
depth0_timeout = HAST_TIMEOUT;
- depth0_replication = HAST_REPLICATION_FULLSYNC;
+ depth0_replication = HAST_REPLICATION_MEMSYNC;
depth0_checksum = HAST_CHECKSUM_NONE;
depth0_compression = HAST_COMPRESSION_HOLE;
strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
@@ -943,11 +970,7 @@ yy_config_parse(const char *config, bool exitonerror)
* Use global or default setting.
*/
curres->hr_replication = depth0_replication;
- }
- if (curres->hr_replication == HAST_REPLICATION_MEMSYNC) {
- pjdlog_warning("Replication mode \"%s\" is not implemented, falling back to \"%s\".",
- "memsync", "fullsync");
- curres->hr_replication = HAST_REPLICATION_FULLSYNC;
+ curres->hr_original_replication = depth0_replication;
}
if (curres->hr_checksum == -1) {
/*
diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c
index 88159cb6bec1..a9dfa2b1cc4c 100644
--- a/sbin/hastd/primary.c
+++ b/sbin/hastd/primary.c
@@ -35,7 +35,6 @@ __FBSDID("$FreeBSD$");
#include <sys/time.h>
#include <sys/bio.h>
#include <sys/disk.h>
-#include <sys/refcount.h>
#include <sys/stat.h>
#include <geom/gate/g_gate.h>
@@ -65,6 +64,7 @@ __FBSDID("$FreeBSD$");
#include "metadata.h"
#include "proto.h"
#include "pjdlog.h"
+#include "refcnt.h"
#include "subr.h"
#include "synch.h"
@@ -303,6 +303,7 @@ hast_activemap_flush(struct hast_resource *res)
if (pwrite(res->hr_localfd, buf, size, METADATA_SIZE) !=
(ssize_t)size) {
pjdlog_errno(LOG_ERR, "Unable to flush activemap to disk");
+ res->hr_stat_activemap_write_error++;
return (-1);
}
if (res->hr_metaflush == 1 && g_flush(res->hr_localfd) == -1) {
@@ -313,6 +314,7 @@ hast_activemap_flush(struct hast_resource *res)
} else {
pjdlog_errno(LOG_ERR,
"Unable to flush disk cache on activemap update");
+ res->hr_stat_activemap_flush_error++;
return (-1);
}
}
@@ -543,7 +545,7 @@ primary_connect(struct hast_resource *res, struct proto_conn **connp)
return (0);
}
-
+
/*
* Function instructs GEOM_GATE to handle reads directly from within the kernel.
*/
@@ -577,6 +579,7 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
int32_t extentsize;
int64_t datasize;
uint32_t mapsize;
+ uint8_t version;
size_t size;
int error;
@@ -597,6 +600,7 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
*/
nvout = nv_alloc();
nv_add_string(nvout, res->hr_name, "resource");
+ nv_add_uint8(nvout, HAST_PROTO_VERSION, "version");
if (nv_error(nvout) != 0) {
pjdlog_common(LOG_WARNING, 0, nv_error(nvout),
"Unable to allocate header for connection with %s",
@@ -626,6 +630,20 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
nv_free(nvin);
goto close;
}
+ version = nv_get_uint8(nvin, "version");
+ if (version == 0) {
+ /*
+ * If no version is sent, it means this is protocol version 1.
+ */
+ version = 1;
+ }
+ if (version > HAST_PROTO_VERSION) {
+ pjdlog_warning("Invalid version received (%hhu).", version);
+ nv_free(nvin);
+ goto close;
+ }
+ res->hr_version = version;
+ pjdlog_debug(1, "Negotiated protocol version %d.", res->hr_version);
token = nv_get_uint8_array(nvin, &size, "token");
if (token == NULL) {
pjdlog_warning("Handshake header from %s has no 'token' field.",
@@ -776,6 +794,16 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
pjdlog_errno(LOG_WARNING, "Unable to set connection direction");
#endif
pjdlog_info("Connected to %s.", res->hr_remoteaddr);
+ if (res->hr_original_replication == HAST_REPLICATION_MEMSYNC &&
+ res->hr_version < 2) {
+ pjdlog_warning("The 'memsync' replication mode is not supported by the remote node, falling back to 'fullsync' mode.");
+ res->hr_replication = HAST_REPLICATION_FULLSYNC;
+ } else if (res->hr_replication != res->hr_original_replication) {
+ /*
+ * This is in case hastd disconnected and was upgraded.
+ */
+ res->hr_replication = res->hr_original_replication;
+ }
if (inp != NULL && outp != NULL) {
*inp = in;
*outp = out;
@@ -1009,7 +1037,8 @@ hastd_primary(struct hast_resource *res)
}
static void
-reqlog(int loglevel, int debuglevel, struct g_gate_ctl_io *ggio, const char *fmt, ...)
+reqlog(int loglevel, int debuglevel, struct g_gate_ctl_io *ggio,
+ const char *fmt, ...)
{
char msg[1024];
va_list ap;
@@ -1020,21 +1049,18 @@ reqlog(int loglevel, int debuglevel, struct g_gate_ctl_io *ggio, const char *fmt
switch (ggio->gctl_cmd) {
case BIO_READ:
(void)snprlcat(msg, sizeof(msg), "READ(%ju, %ju).",
- (uintmax_t)ggio->gctl_offset,
- (uintmax_t)ggio->gctl_length);
+ (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length);
break;
case BIO_DELETE:
(void)snprlcat(msg, sizeof(msg), "DELETE(%ju, %ju).",
- (uintmax_t)ggio->gctl_offset,
- (uintmax_t)ggio->gctl_length);
+ (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length);
break;
case BIO_FLUSH:
(void)snprlcat(msg, sizeof(msg), "FLUSH.");
break;
case BIO_WRITE:
(void)snprlcat(msg, sizeof(msg), "WRITE(%ju, %ju).",
- (uintmax_t)ggio->gctl_offset,
- (uintmax_t)ggio->gctl_length);
+ (uintmax_t)ggio->gctl_offset, (uintmax_t)ggio->gctl_length);
break;
default:
(void)snprlcat(msg, sizeof(msg), "UNKNOWN(%u).",
@@ -1274,8 +1300,13 @@ ggate_recv_thread(void *arg)
}
pjdlog_debug(2,
"ggate_recv: (%p) Moving request to the send queues.", hio);
- refcount_init(&hio->hio_countdown, ncomps);
- for (ii = ncomp; ii < ncomp + ncomps; ii++)
+ hio->hio_countdown = ncomps;
+ if (hio->hio_replication == HAST_REPLICATION_MEMSYNC &&
+ ggio->gctl_cmd == BIO_WRITE) {
+ /* Each remote request needs two responses in memsync. */
+ hio->hio_countdown++;
+ }
+ for (ii = ncomp; ii < ncomps; ii++)
QUEUE_INSERT1(hio, send, ii);
}
/* NOTREACHED */
@@ -1346,8 +1377,7 @@ local_send_thread(void *arg)
} else {
hio->hio_errors[ncomp] = 0;
if (hio->hio_replication ==
- HAST_REPLICATION_ASYNC &&
- !ISSYNCREQ(hio)) {
+ HAST_REPLICATION_ASYNC) {
ggio->gctl_error = 0;
write_complete(res, hio);
}
@@ -1385,8 +1415,42 @@ local_send_thread(void *arg)
}
break;
}
- if (!refcount_release(&hio->hio_countdown))
- continue;
+
+ if (hio->hio_replication != HAST_REPLICATION_MEMSYNC ||
+ ggio->gctl_cmd != BIO_WRITE || ISSYNCREQ(hio)) {
+ if (refcnt_release(&hio->hio_countdown) > 0)
+ continue;
+ } else {
+ /*
+ * Depending on hio_countdown value, requests finished
+ * in the following order:
+ * 0: remote memsync, remote final, local write
+ * 1: remote memsync, local write, (remote final)
+ * 2: local write, (remote memsync), (remote final)
+ */
+ switch (refcnt_release(&hio->hio_countdown)) {
+ case 0:
+ /*
+ * Local write finished as last.
+ */
+ break;
+ case 1:
+ /*
+ * Local write finished after remote memsync
+ * reply arrvied. We can complete the write now.
+ */
+ if (hio->hio_errors[0] == 0)
+ write_complete(res, hio);
+ continue;
+ case 2:
+ /*
+ * Local write finished as first.
+ */
+ continue;
+ default:
+ PJDLOG_ABORT("Invalid hio_countdown.");
+ }
+ }
if (ISSYNCREQ(hio)) {
mtx_lock(&sync_lock);
SYNCREQDONE(hio);
@@ -1508,6 +1572,10 @@ remote_send_thread(void *arg)
nv_add_uint64(nv, (uint64_t)ggio->gctl_seq, "seq");
nv_add_uint64(nv, offset, "offset");
nv_add_uint64(nv, length, "length");
+ if (hio->hio_replication == HAST_REPLICATION_MEMSYNC &&
+ ggio->gctl_cmd == BIO_WRITE && !ISSYNCREQ(hio)) {
+ nv_add_uint8(nv, 1, "memsync");
+ }
if (nv_error(nv) != 0) {
hio->hio_errors[ncomp] = nv_error(nv);
pjdlog_debug(2,
@@ -1568,7 +1636,7 @@ remote_send_thread(void *arg)
done_queue:
nv_free(nv);
if (ISSYNCREQ(hio)) {
- if (!refcount_release(&hio->hio_countdown))
+ if (refcnt_release(&hio->hio_countdown) > 0)
continue;
mtx_lock(&sync_lock);
SYNCREQDONE(hio);
@@ -1583,8 +1651,10 @@ done_queue:
(void)hast_activemap_flush(res);
}
mtx_unlock(&res->hr_amp_lock);
+ if (hio->hio_replication == HAST_REPLICATION_MEMSYNC)
+ (void)refcnt_release(&hio->hio_countdown);
}
- if (!refcount_release(&hio->hio_countdown))
+ if (refcnt_release(&hio->hio_countdown) > 0)
continue;
pjdlog_debug(2,
"remote_send: (%p) Moving request to the done queue.",
@@ -1608,6 +1678,7 @@ remote_recv_thread(void *arg)
struct nv *nv;
unsigned int ncomp;
uint64_t seq;
+ bool memsyncack;
int error;
/* Remote component is 1 for now. */
@@ -1623,6 +1694,8 @@ remote_recv_thread(void *arg)
}
mtx_unlock(&hio_recv_list_lock[ncomp]);
+ memsyncack = false;
+
rw_rlock(&hio_remote_lock[ncomp]);
if (!ISCONNECTED(res, ncomp)) {
rw_unlock(&hio_remote_lock[ncomp]);
@@ -1652,6 +1725,7 @@ remote_recv_thread(void *arg)
nv_free(nv);
continue;
}
+ memsyncack = nv_exists(nv, "received");
mtx_lock(&hio_recv_list_lock[ncomp]);
TAILQ_FOREACH(hio, &hio_recv_list[ncomp], hio_next[ncomp]) {
if (hio->hio_ggio.gctl_seq == seq) {
@@ -1707,8 +1781,80 @@ remote_recv_thread(void *arg)
hio->hio_errors[ncomp] = 0;
nv_free(nv);
done_queue:
- if (!refcount_release(&hio->hio_countdown))
- continue;
+ if (hio->hio_replication != HAST_REPLICATION_MEMSYNC ||
+ hio->hio_ggio.gctl_cmd != BIO_WRITE || ISSYNCREQ(hio)) {
+ if (refcnt_release(&hio->hio_countdown) > 0)
+ continue;
+ } else {
+ /*
+ * Depending on hio_countdown value, requests finished
+ * in the following order:
+ *
+ * 0: local write, remote memsync, remote final
+ * or
+ * 0: remote memsync, local write, remote final
+ *
+ * 1: local write, remote memsync, (remote final)
+ * or
+ * 1: remote memsync, remote final, (local write)
+ *
+ * 2: remote memsync, (local write), (remote final)
+ * or
+ * 2: remote memsync, (remote final), (local write)
+ */
+ switch (refcnt_release(&hio->hio_countdown)) {
+ case 0:
+ /*
+ * Remote final reply arrived.
+ */
+ PJDLOG_ASSERT(!memsyncack);
+ break;
+ case 1:
+ if (memsyncack) {
+ /*
+ * Local request already finished, so we
+ * can complete the write.
+ */
+ if (hio->hio_errors[0] == 0)
+ write_complete(res, hio);
+ /*
+ * We still need to wait for final
+ * remote reply.
+ */
+ pjdlog_debug(2,
+ "remote_recv: (%p) Moving request back to the recv queue.",
+ hio);
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ TAILQ_INSERT_TAIL(&hio_recv_list[ncomp],
+ hio, hio_next[ncomp]);
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ } else {
+ /*
+ * Remote final reply arrived before
+ * local write finished.
+ * Nothing to do in such case.
+ */
+ }
+ continue;
+ case 2:
+ /*
+ * We received remote memsync reply even before
+ * local write finished.
+ */
+ PJDLOG_ASSERT(memsyncack);
+
+ pjdlog_debug(2,
+ "remote_recv: (%p) Moving request back to the recv queue.",
+ hio);
+ mtx_lock(&hio_recv_list_lock[ncomp]);
+ TAILQ_INSERT_TAIL(&hio_recv_list[ncomp], hio,
+ hio_next[ncomp]);
+ mtx_unlock(&hio_recv_list_lock[ncomp]);
+ continue;
+ default:
+ PJDLOG_ABORT("Invalid hio_countdown.");
+ }
+ }
if (ISSYNCREQ(hio)) {
mtx_lock(&sync_lock);
SYNCREQDONE(hio);
@@ -1792,6 +1938,22 @@ ggate_send_thread(void *arg)
"G_GATE_CMD_DONE failed");
}
}
+ if (hio->hio_errors[0]) {
+ switch (ggio->gctl_cmd) {
+ case BIO_READ:
+ res->hr_stat_read_error++;
+ break;
+ case BIO_WRITE:
+ res->hr_stat_write_error++;
+ break;
+ case BIO_DELETE:
+ res->hr_stat_delete_error++;
+ break;
+ case BIO_FLUSH:
+ res->hr_stat_flush_error++;
+ break;
+ }
+ }
pjdlog_debug(2,
"ggate_send: (%p) Moving request to the free queue.", hio);
QUEUE_INSERT2(hio, free);
@@ -1977,7 +2139,7 @@ sync_thread(void *arg __unused)
ncomp = 1;
}
mtx_unlock(&metadata_lock);
- refcount_init(&hio->hio_countdown, 1);
+ hio->hio_countdown = 1;
QUEUE_INSERT1(hio, send, ncomp);
/*
@@ -2027,7 +2189,7 @@ sync_thread(void *arg __unused)
pjdlog_debug(2, "sync: (%p) Moving request to the send queue.",
hio);
- refcount_init(&hio->hio_countdown, 1);
+ hio->hio_countdown = 1;
QUEUE_INSERT1(hio, send, ncomp);
/*
diff --git a/sbin/hastd/refcnt.h b/sbin/hastd/refcnt.h
new file mode 100644
index 000000000000..a989df04885d
--- /dev/null
+++ b/sbin/hastd/refcnt.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2005 John Baldwin <jhb@FreeBSD.org>
+ * 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. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __REFCNT_H__
+#define __REFCNT_H__
+
+#include <machine/atomic.h>
+
+#include "pjdlog.h"
+
+static __inline void
+refcnt_acquire(volatile unsigned int *count)
+{
+
+ atomic_add_acq_int(count, 1);
+}
+
+static __inline unsigned int
+refcnt_release(volatile unsigned int *count)
+{
+ unsigned int old;
+
+ /* XXX: Should this have a rel membar? */
+ old = atomic_fetchadd_int(count, -1);
+ PJDLOG_ASSERT(old > 0);
+ return (old - 1);
+}
+
+#endif /* ! __REFCNT_H__ */
diff --git a/sbin/hastd/secondary.c b/sbin/hastd/secondary.c
index 8ebcd48efb51..c0c67c6ee43e 100644
--- a/sbin/hastd/secondary.c
+++ b/sbin/hastd/secondary.c
@@ -71,6 +71,7 @@ struct hio {
uint8_t hio_cmd;
uint64_t hio_offset;
uint64_t hio_length;
+ bool hio_memsync;
TAILQ_ENTRY(hio) hio_next;
};
@@ -135,6 +136,22 @@ hio_clear(struct hio *hio)
hio->hio_cmd = HIO_UNDEF;
hio->hio_offset = 0;
hio->hio_length = 0;
+ hio->hio_memsync = false;
+}
+
+static void
+hio_copy(const struct hio *srchio, struct hio *dsthio)
+{
+
+ /*
+ * We don't copy hio_error, hio_data and hio_next fields.
+ */
+
+ dsthio->hio_seq = srchio->hio_seq;
+ dsthio->hio_cmd = srchio->hio_cmd;
+ dsthio->hio_offset = srchio->hio_offset;
+ dsthio->hio_length = srchio->hio_length;
+ dsthio->hio_memsync = srchio->hio_memsync;
}
static void
@@ -543,8 +560,10 @@ requnpack(struct hast_resource *res, struct hio *hio, struct nv *nv)
case HIO_FLUSH:
case HIO_KEEPALIVE:
break;
- case HIO_READ:
case HIO_WRITE:
+ hio->hio_memsync = nv_exists(nv, "memsync");
+ /* FALLTHROUGH */
+ case HIO_READ:
case HIO_DELETE:
hio->hio_offset = nv_get_uint64(nv, "offset");
if (nv_error(nv) != 0) {
@@ -563,7 +582,7 @@ requnpack(struct hast_resource *res, struct hio *hio, struct nv *nv)
hio->hio_error = EINVAL;
goto end;
}
- if (hio->hio_length > MAXPHYS) {
+ if (hio->hio_cmd != HIO_DELETE && hio->hio_length > MAXPHYS) {
pjdlog_error("Data length is too large (%ju > %ju).",
(uintmax_t)hio->hio_length, (uintmax_t)MAXPHYS);
hio->hio_error = EINVAL;
@@ -621,7 +640,7 @@ static void *
recv_thread(void *arg)
{
struct hast_resource *res = arg;
- struct hio *hio;
+ struct hio *hio, *mshio;
struct nv *nv;
for (;;) {
@@ -675,6 +694,27 @@ recv_thread(void *arg)
secondary_exit(EX_TEMPFAIL,
"Unable to receive request data");
}
+ if (hio->hio_memsync) {
+ /*
+ * For memsync requests we expect two replies.
+ * Clone the hio so we can handle both of them.
+ */
+ pjdlog_debug(2, "recv: Taking free request.");
+ QUEUE_TAKE(free, mshio);
+ pjdlog_debug(2, "recv: (%p) Got request.",
+ mshio);
+ hio_copy(hio, mshio);
+ mshio->hio_error = 0;
+ /*
+ * We want to keep 'memsync' tag only on the
+ * request going onto send queue (mshio).
+ */
+ hio->hio_memsync = false;
+ pjdlog_debug(2,
+ "recv: (%p) Moving memsync request to the send queue.",
+ mshio);
+ QUEUE_INSERT(send, mshio);
+ }
}
nv_free(nv);
pjdlog_debug(2, "recv: (%p) Moving request to the disk queue.",
@@ -725,6 +765,7 @@ disk_thread(void *arg)
pjdlog_errno(LOG_WARNING,
"Unable to store cleared activemap");
free(map);
+ res->hr_stat_activemap_write_error++;
break;
}
free(map);
@@ -818,6 +859,10 @@ send_thread(void *arg)
nvout = nv_alloc();
/* Copy sequence number. */
nv_add_uint64(nvout, hio->hio_seq, "seq");
+ if (hio->hio_memsync) {
+ PJDLOG_ASSERT(hio->hio_cmd == HIO_WRITE);
+ nv_add_int8(nvout, 1, "received");
+ }
switch (hio->hio_cmd) {
case HIO_READ:
if (hio->hio_error == 0) {
@@ -839,8 +884,23 @@ send_thread(void *arg)
PJDLOG_ABORT("Unexpected command (cmd=%hhu).",
hio->hio_cmd);
}
- if (hio->hio_error != 0)
+ if (hio->hio_error != 0) {
+ switch (hio->hio_cmd) {
+ case HIO_READ:
+ res->hr_stat_read_error++;
+ break;
+ case HIO_WRITE:
+ res->hr_stat_write_error++;
+ break;
+ case HIO_DELETE:
+ res->hr_stat_delete_error++;
+ break;
+ case HIO_FLUSH:
+ res->hr_stat_flush_error++;
+ break;
+ }
nv_add_int16(nvout, hio->hio_error, "error");
+ }
if (hast_proto_send(res, res->hr_remoteout, nvout, data,
length) == -1) {
secondary_exit(EX_TEMPFAIL, "Unable to send reply");
diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c
index ae6f984013c6..440061e8c364 100644
--- a/sbin/hastd/subr.c
+++ b/sbin/hastd/subr.c
@@ -31,14 +31,15 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#ifdef HAVE_CAPSICUM
-#include <sys/capability.h>
-#endif
#include <sys/param.h>
#include <sys/disk.h>
#include <sys/ioctl.h>
#include <sys/jail.h>
#include <sys/stat.h>
+#ifdef HAVE_CAPSICUM
+#include <sys/capability.h>
+#include <geom/gate/g_gate.h>
+#endif
#include <errno.h>
#include <fcntl.h>
@@ -224,22 +225,53 @@ drop_privs(const struct hast_resource *res)
return (-1);
}
- /*
- * Until capsicum doesn't allow ioctl(2) we cannot use it to sandbox
- * primary and secondary worker processes, as primary uses GGATE
- * ioctls and secondary uses ioctls to handle BIO_DELETE and BIO_FLUSH.
- * For now capsicum is only used to sandbox hastctl.
- */
#ifdef HAVE_CAPSICUM
- if (res == NULL) {
- capsicum = (cap_enter() == 0);
- if (!capsicum) {
- pjdlog_common(LOG_DEBUG, 1, errno,
- "Unable to sandbox using capsicum");
+ capsicum = (cap_enter() == 0);
+ if (!capsicum) {
+ pjdlog_common(LOG_DEBUG, 1, errno,
+ "Unable to sandbox using capsicum");
+ } else if (res != NULL) {
+ static const unsigned long geomcmds[] = {
+ DIOCGDELETE,
+ DIOCGFLUSH
+ };
+
+ PJDLOG_ASSERT(res->hr_role == HAST_ROLE_PRIMARY ||
+ res->hr_role == HAST_ROLE_SECONDARY);
+
+ if (cap_rights_limit(res->hr_localfd,
+ CAP_FLOCK | CAP_IOCTL | CAP_PREAD | CAP_PWRITE) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to limit capability rights on local descriptor");
+ }
+ if (cap_ioctls_limit(res->hr_localfd, geomcmds,
+ sizeof(geomcmds) / sizeof(geomcmds[0])) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to limit allowed GEOM ioctls");
}
- } else
+
+ if (res->hr_role == HAST_ROLE_PRIMARY) {
+ static const unsigned long ggatecmds[] = {
+ G_GATE_CMD_MODIFY,
+ G_GATE_CMD_START,
+ G_GATE_CMD_DONE,
+ G_GATE_CMD_DESTROY
+ };
+
+ if (cap_rights_limit(res->hr_ggatefd, CAP_IOCTL) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to limit capability rights to CAP_IOCTL on ggate descriptor");
+ }
+ if (cap_ioctls_limit(res->hr_ggatefd, ggatecmds,
+ sizeof(ggatecmds) / sizeof(ggatecmds[0])) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to limit allowed ggate ioctls");
+ }
+ }
+ }
+#else
+ capsicum = false;
#endif
- capsicum = false;
/*
* Better be sure that everything succeeded.
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index db0dfc0a505e..2047385d5317 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -854,7 +854,7 @@ So, to prevent endless loops in case of mistakes, both
and
.Cm return
actions don't do any jumps and simply go to the next rule if memory
-can't be allocated or stack overflowed/undeflowed.
+cannot be allocated or stack overflowed/underflowed.
.Pp
Internally stack for rule numbers is implemented using
.Xr mbuf_tags 9
@@ -960,6 +960,61 @@ It is possible to use the
keyword with setfib.
If the tablearg value is not within the compiled range of fibs,
the packet's fib is set to 0.
+.It Cm setdscp Ar DSCP | number | tablearg
+Set specified DiffServ codepoint for an IPv4/IPv6 packet.
+Processing continues at the next rule.
+Supported values are:
+.Pp
+.Cm CS0
+.Pq Dv 000000 ,
+.Cm CS1
+.Pq Dv 001000 ,
+.Cm CS2
+.Pq Dv 010000 ,
+.Cm CS3
+.Pq Dv 011000 ,
+.Cm CS4
+.Pq Dv 100000 ,
+.Cm CS5
+.Pq Dv 101000 ,
+.Cm CS6
+.Pq Dv 110000 ,
+.Cm CS7
+.Pq Dv 111000 ,
+.Cm AF11
+.Pq Dv 001010 ,
+.Cm AF12
+.Pq Dv 001100 ,
+.Cm AF13
+.Pq Dv 001110 ,
+.Cm AF21
+.Pq Dv 010010 ,
+.Cm AF22
+.Pq Dv 010100 ,
+.Cm AF23
+.Pq Dv 010110 ,
+.Cm AF31
+.Pq Dv 011010 ,
+.Cm AF32
+.Pq Dv 011100 ,
+.Cm AF33
+.Pq Dv 011110 ,
+.Cm AF41
+.Pq Dv 100010 ,
+.Cm AF42
+.Pq Dv 100100 ,
+.Cm AF43
+.Pq Dv 100110 ,
+.Cm EF
+.Pq Dv 101110 ,
+.Cm BE
+.Pq Dv 000000 .
+Additionally, DSCP value can be specified by number (0..64).
+It is also possible to use the
+.Cm tablearg
+keyword with setdscp.
+If the tablearg value is not within the 0..64 range, lower 6 bits of supplied
+value are used.
.It Cm reass
Queue and reassemble IP fragments.
If the packet is not fragmented, counters are updated and
@@ -1454,6 +1509,17 @@ The supported IP types of service are:
The absence of a particular type may be denoted
with a
.Ql \&! .
+.It Cm dscp spec Ns Op , Ns Ar spec
+Matches IPv4/IPv6 packets whose
+.Cm DS
+field value is contained in
+.Ar spec
+mask.
+Multiple values can be specified via
+the comma separated list.
+Value can be one of keywords used in
+.Cm setdscp
+action or exact number.
.It Cm ipttl Ar ttl-list
Matches IPv4 packets whose time to live is included in
.Ar ttl-list ,
@@ -2976,6 +3042,23 @@ configured on
but coming in on
.Li fxp1
would be dropped.
+.Pp
+The
+.Cm setdscp
+option could be used to (re)mark user traffic,
+by adding the following to the appropriate place in ruleset:
+.Pp
+.Dl "ipfw add setdscp be ip from any to any dscp af11,af21"
+.Pp
+This rule drops all incoming packets that appear to be coming from another
+directly connected system but on the wrong interface.
+For example, a packet with a source address of
+.Li 192.168.0.0/24 ,
+configured on
+.Li fxp0 ,
+but coming in on
+.Li fxp1
+would be dropped.
.Ss DYNAMIC RULES
In order to protect a site from flood attacks involving fake
TCP packets, it is safer to use dynamic rules:
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 530f3195a1f2..5b37995886ba 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -64,6 +64,22 @@ int ipfw_socket = -1;
#define s6_addr32 __u6_addr.__u6_addr32
#endif
+#define CHECK_LENGTH(v, len) do { \
+ if ((v) < (len)) \
+ errx(EX_DATAERR, "Rule too long"); \
+ } while (0)
+/*
+ * Check if we have enough space in cmd buffer. Note that since
+ * first 8? u32 words are reserved by reserved header, full cmd
+ * buffer can't be used, so we need to protect from buffer overrun
+ * only. At the beginnig, cblen is less than actual buffer size by
+ * size of ipfw_insn_u32 instruction + 1 u32 work. This eliminates need
+ * for checking small instructions fitting in given range.
+ * We also (ab)use the fact that ipfw_insn is always the first field
+ * for any custom instruction.
+ */
+#define CHECK_CMDLEN CHECK_LENGTH(cblen, F_LEN((ipfw_insn *)cmd))
+
#define GET_UINT_ARG(arg, min, max, tok, s_x) do { \
if (!av[0]) \
errx(EX_USAGE, "%s: missing argument", match_value(s_x, tok)); \
@@ -151,6 +167,32 @@ static struct _s_x f_iptos[] = {
{ NULL, 0 }
};
+static struct _s_x f_ipdscp[] = {
+ { "af11", IPTOS_DSCP_AF11 >> 2 }, /* 001010 */
+ { "af12", IPTOS_DSCP_AF12 >> 2 }, /* 001100 */
+ { "af13", IPTOS_DSCP_AF13 >> 2 }, /* 001110 */
+ { "af21", IPTOS_DSCP_AF21 >> 2 }, /* 010010 */
+ { "af22", IPTOS_DSCP_AF22 >> 2 }, /* 010100 */
+ { "af23", IPTOS_DSCP_AF23 >> 2 }, /* 010110 */
+ { "af31", IPTOS_DSCP_AF31 >> 2 }, /* 011010 */
+ { "af32", IPTOS_DSCP_AF32 >> 2 }, /* 011100 */
+ { "af33", IPTOS_DSCP_AF33 >> 2 }, /* 011110 */
+ { "af41", IPTOS_DSCP_AF41 >> 2 }, /* 100010 */
+ { "af42", IPTOS_DSCP_AF42 >> 2 }, /* 100100 */
+ { "af43", IPTOS_DSCP_AF43 >> 2 }, /* 100110 */
+ { "be", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */
+ { "ef", IPTOS_DSCP_EF >> 2 }, /* 101110 */
+ { "cs0", IPTOS_DSCP_CS0 >> 2 }, /* 000000 */
+ { "cs1", IPTOS_DSCP_CS1 >> 2 }, /* 001000 */
+ { "cs2", IPTOS_DSCP_CS2 >> 2 }, /* 010000 */
+ { "cs3", IPTOS_DSCP_CS3 >> 2 }, /* 011000 */
+ { "cs4", IPTOS_DSCP_CS4 >> 2 }, /* 100000 */
+ { "cs5", IPTOS_DSCP_CS5 >> 2 }, /* 101000 */
+ { "cs6", IPTOS_DSCP_CS6 >> 2 }, /* 110000 */
+ { "cs7", IPTOS_DSCP_CS7 >> 2 }, /* 100000 */
+ { NULL, 0 }
+};
+
static struct _s_x limit_masks[] = {
{"all", DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
{"src-addr", DYN_SRC_ADDR},
@@ -221,6 +263,7 @@ static struct _s_x rule_actions[] = {
{ "nat", TOK_NAT },
{ "reass", TOK_REASS },
{ "setfib", TOK_SETFIB },
+ { "setdscp", TOK_SETDSCP },
{ "call", TOK_CALL },
{ "return", TOK_RETURN },
{ NULL, 0 } /* terminator */
@@ -653,7 +696,7 @@ strtoport(char *s, char **end, int base, int proto)
* Fill the body of the command with the list of port ranges.
*/
static int
-fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
+fill_newports(ipfw_insn_u16 *cmd, char *av, int proto, int cblen)
{
uint16_t a, b, *p = cmd->ports;
int i = 0;
@@ -664,6 +707,8 @@ fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
if (s == av) /* empty or invalid argument */
return (0);
+ CHECK_LENGTH(cblen, i + 2);
+
switch (*s) {
case '-': /* a range */
av = s + 1;
@@ -696,6 +741,51 @@ fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
return (i);
}
+/*
+ * Fill the body of the command with the list of DiffServ codepoints.
+ */
+static void
+fill_dscp(ipfw_insn *cmd, char *av, int cblen)
+{
+ uint32_t *low, *high;
+ char *s = av, *a;
+ int code;
+
+ cmd->opcode = O_DSCP;
+ cmd->len |= F_INSN_SIZE(ipfw_insn_u32) + 1;
+
+ CHECK_CMDLEN;
+
+ low = (uint32_t *)(cmd + 1);
+ high = low + 1;
+
+ *low = 0;
+ *high = 0;
+
+ while (s != NULL) {
+ a = strchr(s, ',');
+
+ if (a != NULL)
+ *a++ = '\0';
+
+ if (isalpha(*s)) {
+ if ((code = match_token(f_ipdscp, s)) == -1)
+ errx(EX_DATAERR, "Unknown DSCP code");
+ } else {
+ code = strtoul(s, NULL, 10);
+ if (code < 0 || code > 63)
+ errx(EX_DATAERR, "Invalid DSCP value");
+ }
+
+ if (code > 32)
+ *high |= 1 << (code - 32);
+ else
+ *low |= 1 << code;
+
+ s = a;
+ }
+}
+
static struct _s_x icmpcodes[] = {
{ "net", ICMP_UNREACH_NET },
{ "host", ICMP_UNREACH_HOST },
@@ -954,6 +1044,32 @@ print_icmptypes(ipfw_insn_u32 *cmd)
}
}
+static void
+print_dscp(ipfw_insn_u32 *cmd)
+{
+ int i, c;
+ uint32_t *v;
+ char sep= ' ';
+ const char *code;
+
+ printf(" dscp");
+ i = 0;
+ c = 0;
+ v = cmd->d;
+ while (i < 64) {
+ if (*v & (1 << i)) {
+ if ((code = match_value(f_ipdscp, i)) != NULL)
+ printf("%c%s", sep, code);
+ else
+ printf("%c%d", sep, i);
+ sep = ',';
+ }
+
+ if ((++i % 32) == 0)
+ v++;
+ }
+}
+
/*
* show_ipfw() prints the body of an ipfw rule.
* Because the standard rule has at least proto src_ip dst_ip, we use
@@ -1187,6 +1303,17 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
PRINT_UINT_ARG("setfib ", cmd->arg1);
break;
+ case O_SETDSCP:
+ {
+ const char *code;
+
+ if ((code = match_value(f_ipdscp, cmd->arg1)) != NULL)
+ printf("setdscp %s", code);
+ else
+ PRINT_UINT_ARG("setdscp ", cmd->arg1);
+ }
+ break;
+
case O_REASS:
printf("reass");
break;
@@ -1482,6 +1609,10 @@ show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
printf(" ipprecedence %u", (cmd->arg1) >> 5 );
break;
+ case O_DSCP:
+ print_dscp((ipfw_insn_u32 *)cmd);
+ break;
+
case O_IPLEN:
if (F_LEN(cmd) == 1)
printf(" iplen %u", cmd->arg1 );
@@ -2068,7 +2199,7 @@ lookup_host (char *host, struct in_addr *ipaddr)
* We can have multiple comma-separated address/mask entries.
*/
static void
-fill_ip(ipfw_insn_ip *cmd, char *av)
+fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
{
int len = 0;
uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
@@ -2108,6 +2239,8 @@ fill_ip(ipfw_insn_ip *cmd, char *av)
int masklen;
char md, nd = '\0';
+ CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn) + 2 + len);
+
if (p) {
md = *p;
*p++ = '\0';
@@ -2366,11 +2499,13 @@ ipfw_delete(char *av[])
* patterns which match interfaces.
*/
static void
-fill_iface(ipfw_insn_if *cmd, char *arg)
+fill_iface(ipfw_insn_if *cmd, char *arg, int cblen)
{
cmd->name[0] = '\0';
cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
+ CHECK_CMDLEN;
+
/* Parse the interface or address */
if (strcmp(arg, "any") == 0)
cmd->o.len = 0; /* effectively ignore this command */
@@ -2441,8 +2576,10 @@ get_mac_addr_mask(const char *p, uint8_t *addr, uint8_t *mask)
* the new command in case it has been clobbered before.
*/
static ipfw_insn *
-next_cmd(ipfw_insn *cmd)
+next_cmd(ipfw_insn *cmd, int *len)
{
+ *len -= F_LEN(cmd);
+ CHECK_LENGTH(*len, 0);
cmd += F_LEN(cmd);
bzero(cmd, sizeof(*cmd));
return cmd;
@@ -2452,7 +2589,7 @@ next_cmd(ipfw_insn *cmd)
* Takes arguments and copies them into a comment
*/
static void
-fill_comment(ipfw_insn *cmd, char **av)
+fill_comment(ipfw_insn *cmd, char **av, int cblen)
{
int i, l;
char *p = (char *)(cmd + 1);
@@ -2470,6 +2607,8 @@ fill_comment(ipfw_insn *cmd, char **av)
"comment too long (max 80 chars)");
l = 1 + (l+3)/4;
cmd->len = (cmd->len & (F_NOT | F_OR)) | l;
+ CHECK_CMDLEN;
+
for (i = 0; av[i] != NULL; i++) {
strcpy(p, av[i]);
p += strlen(av[i]);
@@ -2495,7 +2634,7 @@ fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg)
* two microinstructions, and returns the pointer to the last one.
*/
static ipfw_insn *
-add_mac(ipfw_insn *cmd, char *av[])
+add_mac(ipfw_insn *cmd, char *av[], int cblen)
{
ipfw_insn_mac *mac;
@@ -2504,6 +2643,7 @@ add_mac(ipfw_insn *cmd, char *av[])
cmd->opcode = O_MACADDR2;
cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
+ CHECK_CMDLEN;
mac = (ipfw_insn_mac *)cmd;
get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */
@@ -2513,12 +2653,13 @@ add_mac(ipfw_insn *cmd, char *av[])
}
static ipfw_insn *
-add_mactype(ipfw_insn *cmd, char *av)
+add_mactype(ipfw_insn *cmd, char *av, int cblen)
{
if (!av)
errx(EX_DATAERR, "missing MAC type");
if (strcmp(av, "any") != 0) { /* we have a non-null type */
- fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
+ fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE,
+ cblen);
cmd->opcode = O_MAC_TYPE;
return cmd;
} else
@@ -2587,9 +2728,9 @@ add_proto_compat(ipfw_insn *cmd, char *av, u_char *protop)
}
static ipfw_insn *
-add_srcip(ipfw_insn *cmd, char *av)
+add_srcip(ipfw_insn *cmd, char *av, int cblen)
{
- fill_ip((ipfw_insn_ip *)cmd, av);
+ fill_ip((ipfw_insn_ip *)cmd, av, cblen);
if (cmd->opcode == O_IP_DST_SET) /* set */
cmd->opcode = O_IP_SRC_SET;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -2604,9 +2745,9 @@ add_srcip(ipfw_insn *cmd, char *av)
}
static ipfw_insn *
-add_dstip(ipfw_insn *cmd, char *av)
+add_dstip(ipfw_insn *cmd, char *av, int cblen)
{
- fill_ip((ipfw_insn_ip *)cmd, av);
+ fill_ip((ipfw_insn_ip *)cmd, av, cblen);
if (cmd->opcode == O_IP_DST_SET) /* set */
;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -2621,12 +2762,12 @@ add_dstip(ipfw_insn *cmd, char *av)
}
static ipfw_insn *
-add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
+add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode, int cblen)
{
/* XXX "any" is trapped before. Perhaps "to" */
if (_substrcmp(av, "any") == 0) {
return NULL;
- } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
+ } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto, cblen)) {
/* XXX todo: check that we have a protocol with ports */
cmd->opcode = opcode;
return cmd;
@@ -2635,7 +2776,7 @@ add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
}
static ipfw_insn *
-add_src(ipfw_insn *cmd, char *av, u_char proto)
+add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
{
struct in6_addr a;
char *host, *ch;
@@ -2648,11 +2789,11 @@ add_src(ipfw_insn *cmd, char *av, u_char proto)
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
inet_pton(AF_INET6, host, &a) == 1)
- ret = add_srcip6(cmd, av);
+ ret = add_srcip6(cmd, av, cblen);
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
inet_pton(AF_INET6, host, &a) != 1))
- ret = add_srcip(cmd, av);
+ ret = add_srcip(cmd, av, cblen);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2661,7 +2802,7 @@ add_src(ipfw_insn *cmd, char *av, u_char proto)
}
static ipfw_insn *
-add_dst(ipfw_insn *cmd, char *av, u_char proto)
+add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
{
struct in6_addr a;
char *host, *ch;
@@ -2674,11 +2815,11 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto)
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
inet_pton(AF_INET6, host, &a) == 1)
- ret = add_dstip6(cmd, av);
+ ret = add_dstip6(cmd, av, cblen);
/* XXX: should check for IPv4, not !IPv6 */
if (ret == NULL && (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
inet_pton(AF_INET6, host, &a) != 1))
- ret = add_dstip(cmd, av);
+ ret = add_dstip(cmd, av, cblen);
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
@@ -2708,6 +2849,7 @@ ipfw_add(char *av[])
* go into actbuf[].
*/
static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
+ int rblen, ablen, cblen;
ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
ipfw_insn *first_cmd; /* first match pattern */
@@ -2738,6 +2880,15 @@ ipfw_add(char *av[])
cmd = (ipfw_insn *)cmdbuf;
action = (ipfw_insn *)actbuf;
+ rblen = sizeof(rulebuf) / sizeof(rulebuf[0]);
+ rblen -= offsetof(struct ip_fw, cmd) / sizeof(rulebuf[0]);
+ ablen = sizeof(actbuf) / sizeof(actbuf[0]);
+ cblen = sizeof(cmdbuf) / sizeof(cmdbuf[0]);
+ cblen -= F_INSN_SIZE(ipfw_insn_u32) + 1;
+
+#define CHECK_RBUFLEN(len) { CHECK_LENGTH(rblen, len); rblen -= len; }
+#define CHECK_ACTLEN CHECK_LENGTH(ablen, action->len)
+
av++;
/* [rule N] -- Rule number optional */
@@ -2769,6 +2920,7 @@ ipfw_add(char *av[])
i = match_token(rule_actions, *av);
av++;
action->len = 1; /* default */
+ CHECK_ACTLEN;
switch(i) {
case TOK_CHECKSTATE:
have_state = action;
@@ -2820,6 +2972,7 @@ ipfw_add(char *av[])
case TOK_NAT:
action->opcode = O_NAT;
action->len = F_INSN_SIZE(ipfw_insn_nat);
+ CHECK_ACTLEN;
if (_substrcmp(*av, "global") == 0) {
action->arg1 = 0;
av++;
@@ -2936,6 +3089,7 @@ chkarg:
action->opcode = O_FORWARD_IP;
action->len = F_INSN_SIZE(ipfw_insn_sa);
+ CHECK_ACTLEN;
/*
* In the kernel we assume AF_INET and use only
@@ -2952,6 +3106,7 @@ chkarg:
action->opcode = O_FORWARD_IP6;
action->len = F_INSN_SIZE(ipfw_insn_sa6);
+ CHECK_ACTLEN;
p->sa.sin6_len = sizeof(struct sockaddr_in6);
p->sa.sin6_family = AF_INET6;
@@ -2994,6 +3149,24 @@ chkarg:
break;
}
+ case TOK_SETDSCP:
+ {
+ int code;
+
+ action->opcode = O_SETDSCP;
+ NEED1("missing DSCP code");
+ if (_substrcmp(*av, "tablearg") == 0) {
+ action->arg1 = IP_FW_TABLEARG;
+ } else if (isalpha(*av[0])) {
+ if ((code = match_token(f_ipdscp, *av)) == -1)
+ errx(EX_DATAERR, "Unknown DSCP code");
+ action->arg1 = code;
+ } else
+ action->arg1 = strtoul(*av, NULL, 10);
+ av++;
+ break;
+ }
+
case TOK_REASS:
action->opcode = O_REASS;
break;
@@ -3005,7 +3178,7 @@ chkarg:
default:
errx(EX_DATAERR, "invalid action %s\n", av[-1]);
}
- action = next_cmd(action);
+ action = next_cmd(action, &ablen);
/*
* [altq queuename] -- altq tag, optional
@@ -3027,6 +3200,7 @@ chkarg:
"log cannot be specified more than once");
have_log = (ipfw_insn *)c;
cmd->len = F_INSN_SIZE(ipfw_insn_log);
+ CHECK_CMDLEN;
cmd->opcode = O_LOG;
if (av[0] && _substrcmp(*av, "logamount") == 0) {
av++;
@@ -3040,9 +3214,14 @@ chkarg:
} else {
len = sizeof(c->max_log);
if (sysctlbyname("net.inet.ip.fw.verbose_limit",
- &c->max_log, &len, NULL, 0) == -1)
+ &c->max_log, &len, NULL, 0) == -1) {
+ if (co.test_only) {
+ c->max_log = 0;
+ break;
+ }
errx(1, "sysctlbyname(\"%s\")",
"net.inet.ip.fw.verbose_limit");
+ }
}
}
break;
@@ -3058,6 +3237,7 @@ chkarg:
"altq cannot be specified more than once");
have_altq = (ipfw_insn *)a;
cmd->len = F_INSN_SIZE(ipfw_insn_altq);
+ CHECK_CMDLEN;
cmd->opcode = O_ALTQ;
a->qid = altq_name_to_qid(*av);
av++;
@@ -3083,7 +3263,7 @@ chkarg:
default:
abort();
}
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
if (have_state) /* must be a check-state, we are done */
@@ -3168,7 +3348,7 @@ chkarg:
av++;
if (F_LEN(cmd) != 0) {
prev = cmd;
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
} else if (first_cmd != cmd) {
errx(EX_DATAERR, "invalid protocol ``%s''", *av);
@@ -3189,11 +3369,11 @@ chkarg:
OR_START(source_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing source address");
- if (add_src(cmd, *av, proto)) {
+ if (add_src(cmd, *av, proto, cblen)) {
av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
} else
errx(EX_USAGE, "bad source address %s", *av);
@@ -3205,10 +3385,10 @@ chkarg:
NOT_BLOCK; /* optional "not" */
if ( av[0] != NULL ) {
if (_substrcmp(*av, "any") == 0 ||
- add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
+ add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) {
av++;
if (F_LEN(cmd) != 0)
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
}
@@ -3225,11 +3405,11 @@ chkarg:
OR_START(dest_ip);
NOT_BLOCK; /* optional "not" */
NEED1("missing dst address");
- if (add_dst(cmd, *av, proto)) {
+ if (add_dst(cmd, *av, proto, cblen)) {
av++;
if (F_LEN(cmd) != 0) { /* ! any */
prev = cmd;
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
} else
errx( EX_USAGE, "bad destination address %s", *av);
@@ -3241,10 +3421,10 @@ chkarg:
NOT_BLOCK; /* optional "not" */
if (av[0]) {
if (_substrcmp(*av, "any") == 0 ||
- add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
+ add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) {
av++;
if (F_LEN(cmd) != 0)
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
}
@@ -3332,7 +3512,7 @@ read_options:
case TOK_VIA:
NEED1("recv, xmit, via require interface name"
" or address");
- fill_iface((ipfw_insn_if *)cmd, av[0]);
+ fill_iface((ipfw_insn_if *)cmd, av[0], cblen);
av++;
if (F_LEN(cmd) == 0) /* not a valid address */
break;
@@ -3352,14 +3532,14 @@ read_options:
case TOK_ICMP6TYPES:
NEED1("icmptypes requires list of types");
- fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
+ fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av, cblen);
av++;
break;
case TOK_IPTTL:
NEED1("ipttl requires TTL");
if (strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_IPTTL))
+ if (!add_ports(cmd, *av, 0, O_IPTTL, cblen))
errx(EX_DATAERR, "invalid ipttl %s", *av);
} else
fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
@@ -3369,7 +3549,7 @@ read_options:
case TOK_IPID:
NEED1("ipid requires id");
if (strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_IPID))
+ if (!add_ports(cmd, *av, 0, O_IPID, cblen))
errx(EX_DATAERR, "invalid ipid %s", *av);
} else
fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
@@ -3379,7 +3559,7 @@ read_options:
case TOK_IPLEN:
NEED1("iplen requires length");
if (strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_IPLEN))
+ if (!add_ports(cmd, *av, 0, O_IPLEN, cblen))
errx(EX_DATAERR, "invalid ip len %s", *av);
} else
fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
@@ -3399,6 +3579,12 @@ read_options:
av++;
break;
+ case TOK_DSCP:
+ NEED1("missing DSCP code");
+ fill_dscp(cmd, *av, cblen);
+ av++;
+ break;
+
case TOK_IPOPTS:
NEED1("missing argument for ipoptions");
fill_flags(cmd, O_IPOPT, f_ipopts, *av);
@@ -3475,7 +3661,7 @@ read_options:
case TOK_TCPDATALEN:
NEED1("tcpdatalen requires length");
if (strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_TCPDATALEN))
+ if (!add_ports(cmd, *av, 0, O_TCPDATALEN, cblen))
errx(EX_DATAERR, "invalid tcpdata len %s", *av);
} else
fill_cmd(cmd, O_TCPDATALEN, 0,
@@ -3501,7 +3687,7 @@ read_options:
case TOK_TCPWIN:
NEED1("tcpwin requires length");
if (strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_TCPWIN))
+ if (!add_ports(cmd, *av, 0, O_TCPWIN, cblen))
errx(EX_DATAERR, "invalid tcpwin len %s", *av);
} else
fill_cmd(cmd, O_TCPWIN, 0,
@@ -3540,6 +3726,7 @@ read_options:
have_state = cmd;
cmd->len = F_INSN_SIZE(ipfw_insn_limit);
+ CHECK_CMDLEN;
cmd->opcode = O_LIMIT;
c->limit_mask = c->conn_limit = 0;
@@ -3571,28 +3758,28 @@ read_options:
case TOK_SRCIP:
NEED1("missing source IP");
- if (add_srcip(cmd, *av)) {
+ if (add_srcip(cmd, *av, cblen)) {
av++;
}
break;
case TOK_DSTIP:
NEED1("missing destination IP");
- if (add_dstip(cmd, *av)) {
+ if (add_dstip(cmd, *av, cblen)) {
av++;
}
break;
case TOK_SRCIP6:
NEED1("missing source IP6");
- if (add_srcip6(cmd, *av)) {
+ if (add_srcip6(cmd, *av, cblen)) {
av++;
}
break;
case TOK_DSTIP6:
NEED1("missing destination IP6");
- if (add_dstip6(cmd, *av)) {
+ if (add_dstip6(cmd, *av, cblen)) {
av++;
}
break;
@@ -3600,7 +3787,7 @@ read_options:
case TOK_SRCPORT:
NEED1("missing source port");
if (_substrcmp(*av, "any") == 0 ||
- add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
+ add_ports(cmd, *av, proto, O_IP_SRCPORT, cblen)) {
av++;
} else
errx(EX_DATAERR, "invalid source port %s", *av);
@@ -3609,7 +3796,7 @@ read_options:
case TOK_DSTPORT:
NEED1("missing destination port");
if (_substrcmp(*av, "any") == 0 ||
- add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
+ add_ports(cmd, *av, proto, O_IP_DSTPORT, cblen)) {
av++;
} else
errx(EX_DATAERR, "invalid destination port %s",
@@ -3617,13 +3804,13 @@ read_options:
break;
case TOK_MAC:
- if (add_mac(cmd, av))
+ if (add_mac(cmd, av, cblen))
av += 2;
break;
case TOK_MACTYPE:
NEED1("missing mac type");
- if (!add_mactype(cmd, *av))
+ if (!add_mactype(cmd, *av, cblen))
errx(EX_DATAERR, "invalid mac type %s", *av);
av++;
break;
@@ -3661,18 +3848,18 @@ read_options:
if (proto != IPPROTO_IPV6 )
errx( EX_USAGE, "flow-id filter is active "
"only for ipv6 protocol\n");
- fill_flow6( (ipfw_insn_u32 *) cmd, *av );
+ fill_flow6( (ipfw_insn_u32 *) cmd, *av, cblen);
av++;
break;
case TOK_COMMENT:
- fill_comment(cmd, av);
+ fill_comment(cmd, av, cblen);
av[0]=NULL;
break;
case TOK_TAGGED:
if (av[0] && strpbrk(*av, "-,")) {
- if (!add_ports(cmd, *av, 0, O_TAGGED))
+ if (!add_ports(cmd, *av, 0, O_TAGGED, cblen))
errx(EX_DATAERR, "tagged: invalid tag"
" list: %s", *av);
}
@@ -3725,7 +3912,7 @@ read_options:
}
if (F_LEN(cmd) > 0) { /* prepare to advance */
prev = cmd;
- cmd = next_cmd(cmd);
+ cmd = next_cmd(cmd, &cblen);
}
}
@@ -3754,12 +3941,13 @@ done:
*/
if (have_state && have_state->opcode != O_CHECK_STATE) {
fill_cmd(dst, O_PROBE_STATE, 0, 0);
- dst = next_cmd(dst);
+ dst = next_cmd(dst, &rblen);
}
/* copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ, O_TAG */
for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
i = F_LEN(src);
+ CHECK_RBUFLEN(i);
switch (src->opcode) {
case O_LOG:
@@ -3779,6 +3967,7 @@ done:
*/
if (have_state && have_state->opcode != O_CHECK_STATE) {
i = F_LEN(have_state);
+ CHECK_RBUFLEN(i);
bcopy(have_state, dst, i * sizeof(uint32_t));
dst += i;
}
@@ -3790,24 +3979,29 @@ done:
/* put back O_LOG, O_ALTQ, O_TAG if necessary */
if (have_log) {
i = F_LEN(have_log);
+ CHECK_RBUFLEN(i);
bcopy(have_log, dst, i * sizeof(uint32_t));
dst += i;
}
if (have_altq) {
i = F_LEN(have_altq);
+ CHECK_RBUFLEN(i);
bcopy(have_altq, dst, i * sizeof(uint32_t));
dst += i;
}
if (have_tag) {
i = F_LEN(have_tag);
+ CHECK_RBUFLEN(i);
bcopy(have_tag, dst, i * sizeof(uint32_t));
dst += i;
}
+
/*
* copy all other actions
*/
for (src = (ipfw_insn *)actbuf; src != action; src += i) {
i = F_LEN(src);
+ CHECK_RBUFLEN(i);
bcopy(src, dst, i * sizeof(uint32_t));
dst += i;
}
@@ -3912,6 +4106,7 @@ ipfw_flush(int force)
static void table_list(uint16_t num, int need_header);
+static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
/*
* This one handles all table-related commands
@@ -3927,16 +4122,18 @@ ipfw_table_handler(int ac, char *av[])
int do_add;
int is_all;
size_t len;
- char *p;
- uint32_t a, type, mask, addrlen;
+ uint32_t a;
uint32_t tables_max;
- mask = 0; // XXX uninitialized ?
len = sizeof(tables_max);
if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
- NULL, 0) == -1)
- errx(1, "Can't determine maximum number of ipfw tables. "
- "Perhaps you forgot to load ipfw module?");
+ NULL, 0) == -1) {
+ if (co.test_only)
+ tables_max = 128; /* Old conservative default */
+ else
+ errx(1, "Can't determine maximum number of ipfw tables."
+ " Perhaps you forgot to load ipfw module?");
+ }
memset(&xent, 0, sizeof(xent));
@@ -3965,57 +4162,8 @@ ipfw_table_handler(int ac, char *av[])
ac--; av++;
if (!ac)
errx(EX_USAGE, "address required");
- /*
- * Let's try to guess type by agrument.
- * Possible types:
- * 1) IPv4[/mask]
- * 2) IPv6[/mask]
- * 3) interface name
- * 4) port ?
- */
- type = 0;
- if (ishexnumber(*av[0])) {
- /* Remove / if exists */
- if ((p = strchr(*av, '/')) != NULL) {
- *p = '\0';
- mask = atoi(p + 1);
- }
-
- if (inet_pton(AF_INET, *av, &xent.k.addr6) == 1) {
- type = IPFW_TABLE_CIDR;
- if ((p != NULL) && (mask > 32))
- errx(EX_DATAERR, "bad IPv4 mask width: %s", p + 1);
- xent.masklen = p ? mask : 32;
- addrlen = sizeof(struct in_addr);
- } else if (inet_pton(AF_INET6, *av, &xent.k.addr6) == 1) {
- type = IPFW_TABLE_CIDR;
- if ((p != NULL) && (mask > 128))
- errx(EX_DATAERR, "bad IPv6 mask width: %s", p + 1);
- xent.masklen = p ? mask : 128;
- addrlen = sizeof(struct in6_addr);
- }
- }
-
- if ((type == 0) && (strchr(*av, '.') == NULL)) {
- /* Assume interface name. Copy significant data only */
- mask = MIN(strlen(*av), IF_NAMESIZE - 1);
- memcpy(xent.k.iface, *av, mask);
- /* Set mask to exact match */
- xent.masklen = 8 * IF_NAMESIZE;
- type = IPFW_TABLE_INTERFACE;
- addrlen = IF_NAMESIZE;
- }
- if (type == 0) {
- if (lookup_host(*av, (struct in_addr *)&xent.k.addr6) != 0)
- errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
- xent.masklen = 32;
- type = IPFW_TABLE_CIDR;
- addrlen = sizeof(struct in_addr);
- }
-
- xent.type = type;
- xent.len = offsetof(ipfw_table_xentry, k) + addrlen;
+ table_fill_xentry(*av, &xent);
ac--; av++;
if (do_add && ac) {
@@ -4065,6 +4213,93 @@ ipfw_table_handler(int ac, char *av[])
}
static void
+table_fill_xentry(char *arg, ipfw_table_xentry *xent)
+{
+ int addrlen, mask, masklen, type;
+ struct in6_addr *paddr;
+ uint32_t *pkey;
+ char *p;
+ uint32_t key;
+
+ mask = 0;
+ type = 0;
+ addrlen = 0;
+ masklen = 0;
+
+ /*
+ * Let's try to guess type by agrument.
+ * Possible types:
+ * 1) IPv4[/mask]
+ * 2) IPv6[/mask]
+ * 3) interface name
+ * 4) port, uid/gid or other u32 key (base 10 format)
+ * 5) hostname
+ */
+ paddr = &xent->k.addr6;
+ if (ishexnumber(*arg) != 0 || *arg == ':') {
+ /* Remove / if exists */
+ if ((p = strchr(arg, '/')) != NULL) {
+ *p = '\0';
+ mask = atoi(p + 1);
+ }
+
+ if (inet_pton(AF_INET, arg, paddr) == 1) {
+ if (p != NULL && mask > 32)
+ errx(EX_DATAERR, "bad IPv4 mask width: %s",
+ p + 1);
+
+ type = IPFW_TABLE_CIDR;
+ masklen = p ? mask : 32;
+ addrlen = sizeof(struct in_addr);
+ } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
+ if (IN6_IS_ADDR_V4COMPAT(paddr))
+ errx(EX_DATAERR,
+ "Use IPv4 instead of v4-compatible");
+ if (p != NULL && mask > 128)
+ errx(EX_DATAERR, "bad IPv6 mask width: %s",
+ p + 1);
+
+ type = IPFW_TABLE_CIDR;
+ masklen = p ? mask : 128;
+ addrlen = sizeof(struct in6_addr);
+ } else {
+ /* Port or any other key */
+ key = strtol(arg, &p, 10);
+ /* Skip non-base 10 entries like 'fa1' */
+ if (p != arg) {
+ pkey = (uint32_t *)paddr;
+ *pkey = htonl(key);
+ type = IPFW_TABLE_CIDR;
+ addrlen = sizeof(uint32_t);
+ }
+ }
+ }
+
+ if (type == 0 && strchr(arg, '.') == NULL) {
+ /* Assume interface name. Copy significant data only */
+ mask = MIN(strlen(arg), IF_NAMESIZE - 1);
+ memcpy(xent->k.iface, arg, mask);
+ /* Set mask to exact match */
+ masklen = 8 * IF_NAMESIZE;
+ type = IPFW_TABLE_INTERFACE;
+ addrlen = IF_NAMESIZE;
+ }
+
+ if (type == 0) {
+ if (lookup_host(arg, (struct in_addr *)paddr) != 0)
+ errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
+
+ masklen = 32;
+ type = IPFW_TABLE_CIDR;
+ addrlen = sizeof(struct in_addr);
+ }
+
+ xent->type = type;
+ xent->masklen = masklen;
+ xent->len = offsetof(ipfw_table_xentry, k) + addrlen;
+}
+
+static void
table_list(uint16_t num, int need_header)
{
ipfw_xtable *tbl;
@@ -4107,8 +4342,8 @@ table_list(uint16_t num, int need_header)
tval = xent->value;
addr6 = &xent->k.addr6;
- if ((addr6->s6_addr32[0] == 0) && (addr6->s6_addr32[1] == 0) &&
- (addr6->s6_addr32[2] == 0)) {
+
+ if (IN6_IS_ADDR_V4COMPAT(addr6)) {
/* IPv4 address */
inet_ntop(AF_INET, &addr6->s6_addr32[3], tbuf, sizeof(tbuf));
} else {
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index bade0dda6529..d592930338f2 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -203,6 +203,7 @@ enum tokens {
TOK_SETFIB,
TOK_LOOKUP,
TOK_SOCKARG,
+ TOK_SETDSCP,
};
/*
* the following macro returns an error message if we run out of
@@ -283,10 +284,10 @@ void print_flow6id(struct _ipfw_insn_u32 *cmd);
void print_icmp6types(struct _ipfw_insn_u32 *cmd);
void print_ext6hdr(struct _ipfw_insn *cmd );
-struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av);
-struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av);
+struct _ipfw_insn *add_srcip6(struct _ipfw_insn *cmd, char *av, int cblen);
+struct _ipfw_insn *add_dstip6(struct _ipfw_insn *cmd, char *av, int cblen);
-void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av );
+void fill_flow6(struct _ipfw_insn_u32 *cmd, char *av, int cblen);
void fill_unreach6_code(u_short *codep, char *str);
-void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av);
+void fill_icmp6types(struct _ipfw_insn_icmp6 *cmd, char *av, int cblen);
int fill_ext6hdr(struct _ipfw_insn *cmd, char *av);
diff --git a/sbin/ipfw/ipv6.c b/sbin/ipfw/ipv6.c
index 6326590a46af..ee9bb623f3ae 100644
--- a/sbin/ipfw/ipv6.c
+++ b/sbin/ipfw/ipv6.c
@@ -42,6 +42,11 @@
#include <netinet/ip_fw.h>
#include <arpa/inet.h>
+#define CHECK_LENGTH(v, len) do { \
+ if ((v) < (len)) \
+ errx(EX_DATAERR, "Rule too long"); \
+ } while (0)
+
static struct _s_x icmp6codes[] = {
{ "no-route", ICMP6_DST_UNREACH_NOROUTE },
{ "admin-prohib", ICMP6_DST_UNREACH_ADMIN },
@@ -131,10 +136,12 @@ print_ip6(ipfw_insn_ip6 *cmd, char const *s)
}
void
-fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
+fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
{
uint8_t type;
+ CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6));
+
bzero(cmd, sizeof(*cmd));
while (*av) {
if (*av == ',')
@@ -327,7 +334,7 @@ lookup_host6 (char *host, struct in6_addr *ip6addr)
* Return 1 on success, 0 on failure.
*/
static int
-fill_ip6(ipfw_insn_ip6 *cmd, char *av)
+fill_ip6(ipfw_insn_ip6 *cmd, char *av, int cblen)
{
int len = 0;
struct in6_addr *d = &(cmd->addr6);
@@ -379,6 +386,8 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
int masklen;
char md = '\0';
+ CHECK_LENGTH(cblen, 1 + len + 2 * F_INSN_SIZE(struct in6_addr));
+
if ((p = strpbrk(av, "/,")) ) {
md = *p; /* save the separator */
*p = '\0'; /* terminate address string */
@@ -453,7 +462,7 @@ fill_ip6(ipfw_insn_ip6 *cmd, char *av)
* additional flow-id we want to filter, the basic is 1
*/
void
-fill_flow6( ipfw_insn_u32 *cmd, char *av )
+fill_flow6( ipfw_insn_u32 *cmd, char *av, int cblen)
{
u_int32_t type; /* Current flow number */
u_int16_t nflow = 0; /* Current flow index */
@@ -461,6 +470,8 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av )
cmd->d[0] = 0; /* Initializing the base number*/
while (s) {
+ CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_u32) + nflow + 1);
+
av = strsep( &s, ",") ;
type = strtoul(av, &av, 0);
if (*av != ',' && *av != '\0')
@@ -481,10 +492,10 @@ fill_flow6( ipfw_insn_u32 *cmd, char *av )
}
ipfw_insn *
-add_srcip6(ipfw_insn *cmd, char *av)
+add_srcip6(ipfw_insn *cmd, char *av, int cblen)
{
- fill_ip6((ipfw_insn_ip6 *)cmd, av);
+ fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
if (cmd->opcode == O_IP_DST_SET) /* set */
cmd->opcode = O_IP_SRC_SET;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
@@ -503,10 +514,10 @@ add_srcip6(ipfw_insn *cmd, char *av)
}
ipfw_insn *
-add_dstip6(ipfw_insn *cmd, char *av)
+add_dstip6(ipfw_insn *cmd, char *av, int cblen)
{
- fill_ip6((ipfw_insn_ip6 *)cmd, av);
+ fill_ip6((ipfw_insn_ip6 *)cmd, av, cblen);
if (cmd->opcode == O_IP_DST_SET) /* set */
;
else if (cmd->opcode == O_IP_DST_LOOKUP) /* table */
diff --git a/sbin/kldload/kldload.8 b/sbin/kldload/kldload.8
index b039edf9ad98..ee913ed638a1 100644
--- a/sbin/kldload/kldload.8
+++ b/sbin/kldload/kldload.8
@@ -63,7 +63,7 @@ in the current directory.
The following options are available:
.Bl -tag -width indent
.It Fl n
-Don't try to load module if already loaded.
+Do not try to load module if already loaded.
.It Fl v
Be more verbose.
.It Fl q
diff --git a/sbin/ldconfig/ldconfig.8 b/sbin/ldconfig/ldconfig.8
index 882459010b30..f2fc324b8cfc 100644
--- a/sbin/ldconfig/ldconfig.8
+++ b/sbin/ldconfig/ldconfig.8
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 11, 2005
+.Dd March 19, 2013
.Dt LDCONFIG 8
.Os
.Sh NAME
@@ -162,21 +162,6 @@ In
addition to building a set of hints for quick lookup, it also serves to
specify the trusted collection of directories from which shared objects can
be safely loaded.
-.Sh ENVIRONMENT
-.Bl -tag -width OBJFORMATxxx -compact
-.It Ev OBJFORMAT
-Overrides
-.Pa /etc/objformat
-(see below) to determine whether
-.Fl aout
-or
-.Fl elf
-is the default.
-If set, its value should be either
-.Ql aout
-or
-.Ql elf .
-.El
.Sh FILES
.Bl -tag -width /var/run/ld-elf.so.hintsxxx -compact
.It Pa /var/run/ld.so.hints
@@ -196,17 +181,6 @@ invocations with
Conventional configuration files containing directory names for
invocations with
.Fl 32 .
-.It Pa /etc/objformat
-Determines whether
-.Fl aout
-or
-.Fl elf
-is the default.
-If present, it must consist of a single line
-containing either
-.Ql OBJFORMAT=aout
-or
-.Ql OBJFORMAT=elf .
.El
.Sh SEE ALSO
.Xr ld 1 ,
diff --git a/sbin/ldconfig/ldconfig.c b/sbin/ldconfig/ldconfig.c
index 7fc64818d286..31d8083df7a8 100644
--- a/sbin/ldconfig/ldconfig.c
+++ b/sbin/ldconfig/ldconfig.c
@@ -97,6 +97,13 @@ static void listhints(void);
static int readhints(void);
static void usage(void);
+/*
+ * Note on aout/a.out support.
+ * To properly support shared libraries for compat2x, which are a.out, we need
+ * to support a.out here. As of 2013, bug reports are still coming in for this
+ * feature (on amd64 no less), so we know it is still in use.
+ */
+
int
main(int argc, char **argv)
{
diff --git a/sbin/mount_cd9660/mount_cd9660.8 b/sbin/mount_cd9660/mount_cd9660.8
index 909af4019cdf..b4716862bfd3 100644
--- a/sbin/mount_cd9660/mount_cd9660.8
+++ b/sbin/mount_cd9660/mount_cd9660.8
@@ -32,7 +32,7 @@
.\" @(#)mount_cd9660.8 8.3 (Berkeley) 3/27/94
.\" $FreeBSD$
.\"
-.Dd October 3, 2005
+.Dd March 5, 2013
.Dt MOUNT_CD9660 8
.Os
.Sh NAME
@@ -80,7 +80,7 @@ See the
man page for possible options and their meanings.
The following cd9660 specific options are available:
.Pp
-.Bl -tag -width "nostrictjoliet" -compact
+.Bl -tag -width "brokenjoliet" -compact
.It Cm extatt
Same as
.Fl e .
@@ -93,7 +93,7 @@ Same as
.It Cm norrip
Same as
.Fl r .
-.It Cm nostrictjoliet
+.It Cm brokenjoliet
Same as
.Fl b .
.El
diff --git a/sbin/mount_cd9660/mount_cd9660.c b/sbin/mount_cd9660/mount_cd9660.c
index 22159661db7a..7ea606439ef2 100644
--- a/sbin/mount_cd9660/mount_cd9660.c
+++ b/sbin/mount_cd9660/mount_cd9660.c
@@ -83,7 +83,7 @@ main(int argc, char **argv)
{
struct iovec *iov;
int iovlen;
- int ch, mntflags, opts;
+ int ch, mntflags;
char *dev, *dir, *p, *val, mntpath[MAXPATHLEN];
int verbose;
int ssector; /* starting sector, 0 for 1st session */
@@ -91,7 +91,7 @@ main(int argc, char **argv)
iov = NULL;
iovlen = 0;
- mntflags = opts = verbose = 0;
+ mntflags = verbose = 0;
ssector = -1;
while ((ch = getopt(argc, argv, "begjo:rs:vC:")) != -1)
@@ -109,7 +109,7 @@ main(int argc, char **argv)
build_iovec(&iov, &iovlen, "nojoliet", NULL, (size_t)-1);
break;
case 'o':
- getmntopts(optarg, mopts, &mntflags, &opts);
+ getmntopts(optarg, mopts, &mntflags, NULL);
p = strchr(optarg, '=');
val = NULL;
if (p != NULL) {
diff --git a/sbin/mount_ext2fs/Makefile b/sbin/mount_ext2fs/Makefile
deleted file mode 100644
index 08a0c3c7e5a5..000000000000
--- a/sbin/mount_ext2fs/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-# @(#)Makefile 8.3 (Berkeley) 3/27/94
-# $FreeBSD$
-
-PROG= mount_ext2fs
-SRCS= mount_ext2fs.c getmntopts.c
-MAN= mount_ext2fs.8
-
-WARNS?= 2
-MOUNT= ${.CURDIR}/../mount
-CFLAGS+= -I${MOUNT}
-
-.PATH: ${MOUNT}
-
-.include <bsd.prog.mk>
diff --git a/sbin/mount_ext2fs/Makefile.depend b/sbin/mount_ext2fs/Makefile.depend
deleted file mode 100644
index a83954553d0e..000000000000
--- a/sbin/mount_ext2fs/Makefile.depend
+++ /dev/null
@@ -1,19 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,}
-
-DEP_MACHINE := ${.PARSEFILE:E}
-
-DIRDEPS = \
- gnu/lib/libgcc \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/sbin/mount_ext2fs/mount_ext2fs.8 b/sbin/mount_ext2fs/mount_ext2fs.8
deleted file mode 100644
index 91a315e8bd39..000000000000
--- a/sbin/mount_ext2fs/mount_ext2fs.8
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" Copyright (c) 1993, 1994
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd January 31, 1996
-.Dt MOUNT_EXT2FS 8
-.Os
-.Sh NAME
-.Nm mount_ext2fs
-.Nd mount an ext2fs file system
-.Sh SYNOPSIS
-.Nm
-.Op Fl o Ar options
-.Ar special
-.Ar node
-.Sh DESCRIPTION
-The
-.Nm
-utility attaches an ext2fs file system
-.Ar special
-device on to the file system tree at the point
-.Ar node .
-.Pp
-This command is normally executed by
-.Xr mount 8
-at boot time.
-.Pp
-The options are as follows:
-.Bl -tag -width indent
-.It Fl o
-Options are specified with a
-.Fl o
-flag followed by a comma separated string of options.
-See the
-.Xr mount 8
-man page for possible options and their meanings.
-.El
-.Sh SEE ALSO
-.Xr mount 2 ,
-.Xr unmount 2 ,
-.Xr fstab 5 ,
-.Xr mount 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 2.2 .
diff --git a/sbin/mount_ext2fs/mount_ext2fs.c b/sbin/mount_ext2fs/mount_ext2fs.c
deleted file mode 100644
index 87539976e6e9..000000000000
--- a/sbin/mount_ext2fs/mount_ext2fs.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*-
- * Copyright (c) 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 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 const char copyright[] =
-"@(#) Copyright (c) 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-/*
-static char sccsid[] = "@(#)mount_lfs.c 8.3 (Berkeley) 3/27/94";
-*/
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/uio.h>
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include "mntopts.h"
-
-static void usage(void);
-
-int
-main(int argc, char *argv[])
-{
- struct iovec *iov;
- int ch, iovlen;
- char *fs_name, *fspec, mntpath[MAXPATHLEN];
- char *fstype;
-
- fstype = strrchr(argv[0], '_');
- if (fstype == NULL)
- errx(EX_USAGE, "argv[0] must end in _fstype");
- else
- ++fstype;
-
- iov = NULL;
- iovlen = 0;
- while ((ch = getopt(argc, argv, "o:")) != -1)
- switch (ch) {
- case 'o': {
- char *p = NULL;
- char *val = strdup("");
- p = strchr(optarg, '=');
- if (p != NULL) {
- free(val);
- *p = '\0';
- val = p + 1;
- }
- build_iovec(&iov, &iovlen, optarg, val, strlen(val)+1);
- }
- break;
- case '?':
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 2)
- usage();
-
- fspec = argv[0]; /* the name of the device file */
- fs_name = argv[1]; /* the mount point */
-
- /*
- * Resolve the mountpoint with realpath(3) and remove unnecessary
- * slashes from the devicename if there are any.
- */
- if (checkpath(fs_name, mntpath) != 0)
- err(EX_USAGE, "%s", mntpath);
- (void)rmslashes(fspec, fspec);
-
- build_iovec(&iov, &iovlen, "fstype", fstype, strlen(fstype) + 1);
- build_iovec(&iov, &iovlen, "fspath", mntpath, strlen(mntpath) + 1);
- build_iovec(&iov, &iovlen, "from", fspec, strlen(fspec) + 1);
-
- if (nmount(iov, iovlen, 0) < 0)
- err(EX_OSERR, "%s", fspec);
- return (0);
-}
-
-static void
-usage()
-{
- (void)fprintf(stderr,
- "usage: mount_ext2fs [-o options] special node\n");
- exit(EX_USAGE);
-}
diff --git a/sbin/mount_hpfs/Makefile b/sbin/mount_hpfs/Makefile
deleted file mode 100644
index 9e65b8e1833d..000000000000
--- a/sbin/mount_hpfs/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# $FreeBSD$
-#
-
-PROG= mount_hpfs
-SRCS= mount_hpfs.c getmntopts.c
-MAN= mount_hpfs.8
-
-MOUNT= ${.CURDIR}/../mount
-CFLAGS+= -I${MOUNT} -DHPFS
-
-.PATH: ${MOUNT}
-
-.include <bsd.prog.mk>
diff --git a/sbin/mount_hpfs/mount_hpfs.8 b/sbin/mount_hpfs/mount_hpfs.8
deleted file mode 100644
index 81e3ea3932fa..000000000000
--- a/sbin/mount_hpfs/mount_hpfs.8
+++ /dev/null
@@ -1,100 +0,0 @@
-.\"
-.\" Copyright (c) 1993,1994 Christopher G. Demetriou
-.\" Copyright (c) 1999 Semen Ustimenko <semenu@FreeBSD.org>
-.\" 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 acknowledgment:
-.\" This product includes software developed by Christopher G. Demetriou.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd May 20, 1999
-.Dt MOUNT_HPFS 8
-.Os
-.Sh NAME
-.Nm mount_hpfs
-.Nd mount an HPFS file system
-.Sh SYNOPSIS
-.Nm
-.Op Fl o Ar options
-.Op Fl u Ar uid
-.Op Fl g Ar gid
-.Op Fl m Ar mask
-.Pa special
-.Pa node
-.Sh DESCRIPTION
-The
-.Nm
-utility attaches the HPFS file system residing on the device
-.Pa special
-to the global file system namespace at the location
-indicated by
-.Pa node .
-This command is normally executed by
-.Xr mount 8
-at boot time, but can be used by any user to mount an
-HPFS file system on any directory that they own (provided,
-of course, that they have appropriate access to the device that
-contains the file system).
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl u Ar uid
-Set the owner of the files in the file system to
-.Ar uid .
-The default owner is the owner of the directory
-on which the file system is being mounted.
-.It Fl g Ar gid
-Set the group of the files in the file system to
-.Ar gid .
-The default group is the group of the directory
-on which the file system is being mounted.
-.It Fl m Ar mask
-Specify the maximum file permissions for files
-in the file system.
-.El
-.Sh EXAMPLES
-To mount an hpfs volume located in /dev/wd1s1:
-.Bd -literal -offset indent
-# mount_hpfs /dev/wd1s1 /mnt
-.Ed
-.Sh WRITING
-There is limited writing ability and it is not well-tested.
-It is strongly recommended to mount readonly!
-.Sh SEE ALSO
-.Xr mount 2 ,
-.Xr unmount 2 ,
-.Xr fstab 5 ,
-.Xr mount 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 3.0 .
-.Sh AUTHORS
-HPFS kernel implementation,
-.Nm
-and manual were written by
-.An Semen Ustimenko Aq semenu@FreeBSD.org .
diff --git a/sbin/mount_hpfs/mount_hpfs.c b/sbin/mount_hpfs/mount_hpfs.c
deleted file mode 100644
index 0106377c7454..000000000000
--- a/sbin/mount_hpfs/mount_hpfs.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (c) 1994 Christopher G. Demetriou
- * Copyright (c) 1999 Semen Ustimenko (semenu@FreeBSD.org)
- * 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 Christopher G. Demetriou.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <fs/hpfs/hpfsmount.h>
-#include <ctype.h>
-#include <err.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include "mntopts.h"
-
-static struct mntopt mopts[] = {
- MOPT_STDOPTS,
- MOPT_END
-};
-
-static gid_t a_gid(char *);
-static uid_t a_uid(char *);
-static mode_t a_mask(char *);
-static void usage(void) __dead2;
-static void load_u2wtable(struct hpfs_args *, char *);
-
-int
-main(int argc, char *argv[])
-{
- struct hpfs_args args;
- struct stat sb;
- int c, mntflags, set_gid, set_uid, set_mask;
- int forcerw = 0;
- char *dev, *dir, ndir[MAXPATHLEN];
-
- mntflags = set_gid = set_uid = set_mask = 0;
- (void)memset(&args, '\0', sizeof(args));
-
- while ((c = getopt(argc, argv, "u:g:m:o:c:W:F")) != -1) {
- switch (c) {
- case 'F':
- forcerw=1;
- break;
- case 'u':
- args.uid = a_uid(optarg);
- set_uid = 1;
- break;
- case 'g':
- args.gid = a_gid(optarg);
- set_gid = 1;
- break;
- case 'm':
- args.mode = a_mask(optarg);
- set_mask = 1;
- break;
- case 'o':
- getmntopts(optarg, mopts, &mntflags, 0);
- break;
- case 'W':
- load_u2wtable(&args, optarg);
- args.flags |= HPFSMNT_TABLES;
- break;
- case '?':
- default:
- usage();
- break;
- }
- }
-
- if (optind + 2 != argc)
- usage();
-
- if (!(mntflags & MNT_RDONLY) && !forcerw) {
- warnx("Write support is BETA, you need -F flag to enable RW mount!");
- exit (111);
- }
-
- dev = argv[optind];
- dir = argv[optind + 1];
- if (dir[0] != '/') {
- warnx("\"%s\" is a relative path", dir);
- if (getcwd(ndir, sizeof(ndir)) == NULL)
- err(EX_OSERR, "getcwd");
- strncat(ndir, "/", sizeof(ndir) - strlen(ndir) - 1);
- strncat(ndir, dir, sizeof(ndir) - strlen(ndir) - 1);
- dir = ndir;
- warnx("using \"%s\" instead", dir);
- }
-
- args.fspec = dev;
- args.export.ex_root = 65534; /* unchecked anyway on DOS fs */
- if (mntflags & MNT_RDONLY)
- args.export.ex_flags = MNT_EXRDONLY;
- else
- args.export.ex_flags = 0;
-
- if (!set_gid || !set_uid || !set_mask) {
- if (stat(dir, &sb) == -1)
- err(EX_OSERR, "stat %s", dir);
-
- if (!set_uid)
- args.uid = sb.st_uid;
- if (!set_gid)
- args.gid = sb.st_gid;
- if (!set_mask)
- args.mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- }
-
- if (mount("hpfs", dir, mntflags, &args) < 0)
- err(EX_OSERR, "%s", dev);
-
- exit (0);
-}
-
-gid_t
-a_gid(char *s)
-{
- struct group *gr;
- char *gname;
- gid_t gid;
-
- if ((gr = getgrnam(s)) != NULL)
- gid = gr->gr_gid;
- else {
- for (gname = s; *s && isdigit(*s); ++s);
- if (!*s)
- gid = atoi(gname);
- else
- errx(EX_NOUSER, "unknown group id: %s", gname);
- }
- return (gid);
-}
-
-uid_t
-a_uid(char *s)
-{
- struct passwd *pw;
- char *uname;
- uid_t uid;
-
- if ((pw = getpwnam(s)) != NULL)
- uid = pw->pw_uid;
- else {
- for (uname = s; *s && isdigit(*s); ++s);
- if (!*s)
- uid = atoi(uname);
- else
- errx(EX_NOUSER, "unknown user id: %s", uname);
- }
- return (uid);
-}
-
-mode_t
-a_mask(char *s)
-{
- int done, rv=0;
- char *ep;
-
- done = 0;
- if (*s >= '0' && *s <= '7') {
- done = 1;
- rv = strtol(optarg, &ep, 8);
- }
- if (!done || rv < 0 || *ep)
- errx(EX_USAGE, "invalid file mode: %s", s);
- return (rv);
-}
-
-void
-usage(void)
-{
- fprintf(stderr, "usage: mount_hpfs [-u user] [-g group] [-m mask] bdev dir\n");
- exit(EX_USAGE);
-}
-
-void
-load_u2wtable (struct hpfs_args *pargs, char *name)
-{
- FILE *f;
- int i, code;
- char buf[128];
- char *fn;
-
- if (*name == '/')
- fn = name;
- else {
- snprintf(buf, sizeof(buf), "/usr/libdata/msdosfs/%s", name);
- buf[127] = '\0';
- fn = buf;
- }
- if ((f = fopen(fn, "r")) == NULL)
- err(EX_NOINPUT, "%s", fn);
- for (i = 0; i < 128; i++) {
- if (fscanf(f, "%i", &code) != 1)
- errx(EX_DATAERR, "u2w: missing item number %d", i);
- /* pargs->u2w[i] = code; */
- }
- for (i = 0; i < 128; i++) {
- if (fscanf(f, "%i", &code) != 1)
- errx(EX_DATAERR, "d2u: missing item number %d", i);
- pargs->d2u[i] = code;
- }
- for (i = 0; i < 128; i++) {
- if (fscanf(f, "%i", &code) != 1)
- errx(EX_DATAERR, "u2d: missing item number %d", i);
- pargs->u2d[i] = code;
- }
- fclose(f);
-}
diff --git a/sbin/mount_msdosfs/mount_msdosfs.c b/sbin/mount_msdosfs/mount_msdosfs.c
index 3da673dd6fe4..8814fdd1692a 100644
--- a/sbin/mount_msdosfs/mount_msdosfs.c
+++ b/sbin/mount_msdosfs/mount_msdosfs.c
@@ -69,7 +69,7 @@ main(int argc, char **argv)
struct iovec *iov = NULL;
int iovlen = 0;
struct stat sb;
- int c, mntflags, set_gid, set_uid, set_mask, set_dirmask;
+ int c, set_gid, set_uid, set_mask, set_dirmask;
char *dev, *dir, mntpath[MAXPATHLEN], *csp;
char fstype[] = "msdosfs";
char errmsg[255] = {0};
@@ -78,9 +78,8 @@ main(int argc, char **argv)
mode_t mask = 0, dirmask = 0;
uid_t uid = 0;
gid_t gid = 0;
- getmnt_silent = 1;
- mntflags = set_gid = set_uid = set_mask = set_dirmask = 0;
+ set_gid = set_uid = set_mask = set_dirmask = 0;
while ((c = getopt(argc, argv, "sl9u:g:m:M:o:L:D:W:")) != -1) {
switch (c) {
@@ -219,7 +218,7 @@ main(int argc, char **argv)
build_iovec_argf(&iov, &iovlen, "mask", "%u", mask);
build_iovec_argf(&iov, &iovlen, "dirmask", "%u", dirmask);
- if (nmount(iov, iovlen, mntflags) < 0) {
+ if (nmount(iov, iovlen, 0) < 0) {
if (errmsg[0])
err(1, "%s: %s", dev, errmsg);
else
diff --git a/sbin/mount_nfs/mount_nfs.c b/sbin/mount_nfs/mount_nfs.c
index d71e952ab60f..bd016f3cb3bc 100644
--- a/sbin/mount_nfs/mount_nfs.c
+++ b/sbin/mount_nfs/mount_nfs.c
@@ -130,7 +130,7 @@ enum tryret {
TRYRET_LOCALERR /* Local failure. */
};
-static int fallback_mount(struct iovec *iov, int iovlen, int mntflags);
+static int fallback_mount(struct iovec *iov, int iovlen);
static int sec_name_to_num(char *sec);
static char *sec_num_to_name(int num);
static int getnfsargs(char *, struct iovec **iov, int *iovlen);
@@ -149,13 +149,12 @@ main(int argc, char *argv[])
{
int c;
struct iovec *iov;
- int mntflags, num, iovlen;
+ int num, iovlen;
int osversion;
char *name, *p, *spec, *fstype;
char mntpath[MAXPATHLEN], errmsg[255];
char hostname[MAXHOSTNAMELEN + 1], *gssname, gssn[MAXHOSTNAMELEN + 50];
- mntflags = 0;
iov = NULL;
iovlen = 0;
memset(errmsg, 0, sizeof(errmsg));
@@ -427,10 +426,10 @@ main(int argc, char *argv[])
*/
osversion = getosreldate();
if (osversion >= 702100) {
- if (nmount(iov, iovlen, mntflags))
+ if (nmount(iov, iovlen, 0))
err(1, "%s, %s", mntpath, errmsg);
} else {
- if (fallback_mount(iov, iovlen, mntflags))
+ if (fallback_mount(iov, iovlen))
err(1, "%s, %s", mntpath, errmsg);
}
@@ -473,7 +472,7 @@ copyopt(struct iovec **newiov, int *newiovlen,
* parameters. It should be eventually be removed.
*/
static int
-fallback_mount(struct iovec *iov, int iovlen, int mntflags)
+fallback_mount(struct iovec *iov, int iovlen)
{
struct nfs_args args = {
.version = NFS_ARGSVERSION,
@@ -663,7 +662,7 @@ fallback_mount(struct iovec *iov, int iovlen, int mntflags)
copyopt(&newiov, &newiovlen, iov, iovlen, "fspath");
copyopt(&newiov, &newiovlen, iov, iovlen, "errmsg");
- return nmount(newiov, newiovlen, mntflags);
+ return nmount(newiov, newiovlen, 0);
}
static int
diff --git a/sbin/mount_ntfs/Makefile b/sbin/mount_ntfs/Makefile
deleted file mode 100644
index 416f1ac8ab24..000000000000
--- a/sbin/mount_ntfs/Makefile
+++ /dev/null
@@ -1,20 +0,0 @@
-#
-# $FreeBSD$
-#
-
-PROG= mount_ntfs
-SRCS= mount_ntfs.c getmntopts.c
-MAN= mount_ntfs.8
-DPADD= ${LIBKICONV}
-LDADD= -lkiconv
-
-MOUNT= ${.CURDIR}/../mount
-CFLAGS+= -I${MOUNT}
-
-# Needs to be dynamically linked for optional dlopen() access to
-# userland libiconv
-NO_SHARED?= NO
-
-.PATH: ${MOUNT}
-
-.include <bsd.prog.mk>
diff --git a/sbin/mount_ntfs/Makefile.depend b/sbin/mount_ntfs/Makefile.depend
deleted file mode 100644
index 0dbc784cc478..000000000000
--- a/sbin/mount_ntfs/Makefile.depend
+++ /dev/null
@@ -1,21 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,}
-
-DEP_MACHINE := ${.PARSEFILE:E}
-
-DIRDEPS = \
- gnu/lib/libgcc \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
- lib/libkiconv \
- lib/libutil \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/sbin/mount_ntfs/mount_ntfs.8 b/sbin/mount_ntfs/mount_ntfs.8
deleted file mode 100644
index eb8ba690cb5b..000000000000
--- a/sbin/mount_ntfs/mount_ntfs.8
+++ /dev/null
@@ -1,173 +0,0 @@
-.\"
-.\" Copyright (c) 1993,1994 Christopher G. Demetriou
-.\" Copyright (c) 1999 Semen Ustimenko
-.\" 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 acknowledgment:
-.\" This product includes software developed by Christopher G. Demetriou.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd November 17, 2007
-.Dt MOUNT_NTFS 8
-.Os
-.Sh NAME
-.Nm mount_ntfs
-.Nd mount an NTFS file system
-.Sh SYNOPSIS
-.Nm
-.Op Fl a
-.Op Fl i
-.Op Fl u Ar user
-.Op Fl g Ar group
-.Op Fl m Ar mask
-.Op Fl C Ar charset
-.Op Fl W Ar u2wtable
-.Pa special
-.Pa node
-.Sh DESCRIPTION
-The
-.Nm
-utility attaches the NTFS file system residing on the device
-.Pa special
-to the global file system namespace at the location
-indicated by
-.Pa node .
-This command is normally executed by
-.Xr mount 8
-at boot time, but can be used by any user to mount an
-NTFS file system on any directory that they own (provided,
-of course, that they have appropriate access to the device that
-contains the file system).
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl a
-Force behaviour to return MS-DOS 8.3 names also on
-.Fn readdir .
-.It Fl i
-Make name lookup case insensitive for all names except POSIX names.
-.It Fl u Ar user
-Set the owner of the files in the file system to
-.Ar user .
-The default owner is the owner of the directory
-on which the file system is being mounted.
-.It Fl g Ar group
-Set the group of the files in the file system to
-.Ar group .
-The default group is the group of the directory
-on which the file system is being mounted.
-.It Fl m Ar mask
-Specify the maximum file permissions for files
-in the file system.
-Only the nine low-order bits of
-.Ar mask
-are used.
-.It Fl C Ar charset
-Specify local
-.Ar charset
-to convert Unicode file names.
-Currently only reading is supported, thus the file system is to be
-mounted read-only.
-.It Fl W Ar u2wtable
-Specify
-.Ux
-to
-.Tn Unicode
-translation table.
-See
-.Xr mount_msdosfs 8
-for the description of this option.
-.Bf Em
-This option is preserved for backward compatibility purpose only,
-and will be removed in the future.
-Please do not use this option.
-.Ef
-.El
-.Sh FEATURES
-NTFS file attributes are accessed in following way:
-.Bd -literal -offset indent
-foo[[:ATTRTYPE]:ATTRNAME]
-.Ed
-.Pp
-.Sq ATTRTYPE
-is one of the identifiers listed in $AttrDef file of
-volume.
-Default is $DATA.
-.Sq ATTRNAME
-is an attribute name.
-Default is none.
-.Sh EXAMPLES
-To mount an NTFS volume located in
-.Pa /dev/ad1s1 :
-.Pp
-.Dl "mount_ntfs /dev/ad1s1 /mnt"
-.Pp
-To get the volume name (in Unicode):
-.Pp
-.Dl "cat /mnt/\e$Volume:\e$VOLUME_NAME"
-.Pp
-To read directory raw data:
-.Pp
-.Dl "cat /mnt/foodir:\e$INDEX_ROOT:\e$I30"
-.Pp
-To mount a Japanese NTFS volume located in
-.Pa /dev/ad0s1 :
-.Pp
-.Dl "mount_ntfs -C eucJP /dev/ad0s1 /mnt"
-.Sh WRITING
-There is limited writing ability.
-Limitations: file must be nonresident
-and must not contain any sparces (uninitialized areas); compressed
-files are also not supported.
-The file name must not contain multibyte characters.
-.Sh SEE ALSO
-.Xr mount 2 ,
-.Xr unmount 2 ,
-.Xr fstab 5 ,
-.Xr mount 8 ,
-.Xr mount_msdosfs 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 3.0 .
-.Pp
-The Unicode conversion routine was added by
-.An Ryuichiro Imura Aq imura@ryu16.org
-in 2003.
-.Sh AUTHORS
-The NTFS kernel implementation,
-.Nm
-utility, and manual were written by
-.An Semen Ustimenko Aq semenu@FreeBSD.org .
-.Sh CAVEATS
-This utility is primarily used for read access to an NTFS volume.
-See the
-.Sx WRITING
-section for details about writing to an NTFS volume.
-.Pp
-For a full read-write NTFS support consider sysutils/fusefs-ntfs
-port/package.
diff --git a/sbin/mount_ntfs/mount_ntfs.c b/sbin/mount_ntfs/mount_ntfs.c
deleted file mode 100644
index e46ac21d5d5a..000000000000
--- a/sbin/mount_ntfs/mount_ntfs.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 1994 Christopher G. Demetriou
- * Copyright (c) 1999 Semen Ustimenko
- * 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 Christopher G. Demetriou.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- *
- */
-
-#include <sys/cdefs.h>
-#include <sys/param.h>
-#define NTFS
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <sys/module.h>
-#include <sys/iconv.h>
-#include <sys/linker.h>
-#include <fs/ntfs/ntfsmount.h>
-#include <ctype.h>
-#include <err.h>
-#include <grp.h>
-#include <pwd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-#include <libutil.h>
-
-#include "mntopts.h"
-
-#define TRANSITION_PERIOD_HACK
-
-static struct mntopt mopts[] = {
- MOPT_STDOPTS,
- MOPT_END
-};
-
-static gid_t a_gid(char *);
-static uid_t a_uid(char *);
-static mode_t a_mask(char *);
-static void usage(void) __dead2;
-
-static int set_charset(struct ntfs_args *);
-
-int
-main(int argc, char *argv[])
-{
- struct ntfs_args args;
- struct stat sb;
- int c, mntflags, set_gid, set_uid, set_mask;
- char *dev, *dir, mntpath[MAXPATHLEN];
-
- mntflags = set_gid = set_uid = set_mask = 0;
- (void)memset(&args, '\0', sizeof(args));
- args.cs_ntfs = NULL;
- args.cs_local = NULL;
-
-#ifdef TRANSITION_PERIOD_HACK
- while ((c = getopt(argc, argv, "aiu:g:m:o:C:W:")) != -1) {
-#else
- while ((c = getopt(argc, argv, "aiu:g:m:o:C:")) != -1) {
-#endif
- switch (c) {
- case 'u':
- args.uid = a_uid(optarg);
- set_uid = 1;
- break;
- case 'g':
- args.gid = a_gid(optarg);
- set_gid = 1;
- break;
- case 'm':
- args.mode = a_mask(optarg);
- set_mask = 1;
- break;
- case 'i':
- args.flag |= NTFS_MFLAG_CASEINS;
- break;
- case 'a':
- args.flag |= NTFS_MFLAG_ALLNAMES;
- break;
- case 'o':
- getmntopts(optarg, mopts, &mntflags, 0);
- break;
- case 'C':
- args.cs_local = malloc(ICONV_CSNMAXLEN);
- if (args.cs_local == NULL)
- err(EX_OSERR, "malloc()");
- strncpy(args.cs_local,
- kiconv_quirkcs(optarg, KICONV_VENDOR_MICSFT),
- ICONV_CSNMAXLEN);
- break;
-#ifdef TRANSITION_PERIOD_HACK
- case 'W':
- args.cs_local = malloc(ICONV_CSNMAXLEN);
- if (args.cs_local == NULL)
- err(EX_OSERR, "malloc()");
- if (strcmp(optarg, "iso22dos") == 0) {
- strcpy(args.cs_local, "ISO8859-2");
- } else if (strcmp(optarg, "iso72dos") == 0) {
- strcpy(args.cs_local, "ISO8859-7");
- } else if (strcmp(optarg, "koi2dos") == 0) {
- strcpy(args.cs_local, "KOI8-R");
- } else if (strcmp(optarg, "koi8u2dos") == 0) {
- strcpy(args.cs_local, "KOI8-U");
- } else {
- err(EX_NOINPUT, "%s", optarg);
- }
- break;
-#endif /* TRANSITION_PERIOD_HACK */
- case '?':
- default:
- usage();
- break;
- }
- }
-
- if (optind + 2 != argc)
- usage();
-
- dev = argv[optind];
- dir = argv[optind + 1];
-
- if (args.cs_local) {
- if (set_charset(&args) == -1)
- err(EX_OSERR, "ntfs_iconv");
- args.flag |= NTFS_MFLAG_KICONV;
- /*
- * XXX
- * Force to be MNT_RDONLY,
- * since only reading is supported right now,
- */
- mntflags |= MNT_RDONLY;
- }
-
- /*
- * Resolve the mountpoint with realpath(3) and remove unnecessary
- * slashes from the devicename if there are any.
- */
- if (checkpath(dir, mntpath) != 0)
- err(EX_USAGE, "%s", mntpath);
- (void)rmslashes(dev, dev);
-
- args.fspec = dev;
- args.export.ex_root = 65534; /* unchecked anyway on DOS fs */
- if (mntflags & MNT_RDONLY)
- args.export.ex_flags = MNT_EXRDONLY;
- else
- args.export.ex_flags = 0;
- if (!set_gid || !set_uid || !set_mask) {
- if (stat(mntpath, &sb) == -1)
- err(EX_OSERR, "stat %s", mntpath);
-
- if (!set_uid)
- args.uid = sb.st_uid;
- if (!set_gid)
- args.gid = sb.st_gid;
- if (!set_mask)
- args.mode = sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
- }
-
- if (mount("ntfs", mntpath, mntflags, &args) < 0)
- err(EX_OSERR, "%s", dev);
-
- exit (0);
-}
-
-gid_t
-a_gid(char *s)
-{
- struct group *gr;
- char *gname;
- gid_t gid;
-
- if ((gr = getgrnam(s)) != NULL)
- gid = gr->gr_gid;
- else {
- for (gname = s; *s && isdigit(*s); ++s);
- if (!*s)
- gid = atoi(gname);
- else
- errx(EX_NOUSER, "unknown group id: %s", gname);
- }
- return (gid);
-}
-
-uid_t
-a_uid(char *s)
-{
- struct passwd *pw;
- char *uname;
- uid_t uid;
-
- if ((pw = getpwnam(s)) != NULL)
- uid = pw->pw_uid;
- else {
- for (uname = s; *s && isdigit(*s); ++s);
- if (!*s)
- uid = atoi(uname);
- else
- errx(EX_NOUSER, "unknown user id: %s", uname);
- }
- return (uid);
-}
-
-mode_t
-a_mask(char *s)
-{
- int done, rv=0;
- char *ep;
-
- done = 0;
- if (*s >= '0' && *s <= '7') {
- done = 1;
- rv = strtol(optarg, &ep, 8);
- }
- if (!done || rv < 0 || *ep)
- errx(EX_USAGE, "invalid file mode: %s", s);
- return (rv);
-}
-
-void
-usage(void)
-{
-#ifdef TRANSITION_PERIOD_HACK
- fprintf(stderr, "%s\n%s\n",
- "usage: mount_ntfs [-a] [-i] [-u user] [-g group] [-m mask]",
- " [-C charset] [-W u2wtable] special node");
-#else
- fprintf(stderr, "usage: mount_ntfs [-a] [-i] [-u user] [-g group] [-m mask] [-C charset] special node\n");
-#endif
- exit(EX_USAGE);
-}
-
-int
-set_charset(struct ntfs_args *pargs)
-{
- int error;
-
- if (modfind("ntfs_iconv") < 0)
- if (kldload("ntfs_iconv") < 0 || modfind("ntfs_iconv") < 0) {
- warnx( "cannot find or load \"ntfs_iconv\" kernel module");
- return (-1);
- }
-
- if ((pargs->cs_ntfs = malloc(ICONV_CSNMAXLEN)) == NULL)
- return (-1);
- strncpy(pargs->cs_ntfs, ENCODING_UNICODE, ICONV_CSNMAXLEN);
- error = kiconv_add_xlat16_cspairs(pargs->cs_ntfs, pargs->cs_local);
- if (error)
- return (-1);
-
- return (0);
-}
diff --git a/sbin/mount_nullfs/mount_nullfs.c b/sbin/mount_nullfs/mount_nullfs.c
index aaf66e527ea3..e08599fca549 100644
--- a/sbin/mount_nullfs/mount_nullfs.c
+++ b/sbin/mount_nullfs/mount_nullfs.c
@@ -68,12 +68,11 @@ main(int argc, char *argv[])
char source[MAXPATHLEN];
char target[MAXPATHLEN];
char errmsg[255];
- int ch, mntflags, iovlen;
+ int ch, iovlen;
char nullfs[] = "nullfs";
iov = NULL;
iovlen = 0;
- mntflags = 0;
errmsg[0] = '\0';
while ((ch = getopt(argc, argv, "o:")) != -1)
switch(ch) {
@@ -111,7 +110,7 @@ main(int argc, char *argv[])
build_iovec(&iov, &iovlen, "fspath", source, (size_t)-1);
build_iovec(&iov, &iovlen, "target", target, (size_t)-1);
build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
- if (nmount(iov, iovlen, mntflags) < 0) {
+ if (nmount(iov, iovlen, 0) < 0) {
if (errmsg[0] != 0)
err(1, "%s: %s", source, errmsg);
else
diff --git a/sbin/mount_reiserfs/Makefile b/sbin/mount_reiserfs/Makefile
deleted file mode 100644
index 686629fe1843..000000000000
--- a/sbin/mount_reiserfs/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# $FreeBSD$
-
-PROG = mount_reiserfs
-SRCS = mount_reiserfs.c getmntopts.c
-MAN = mount_reiserfs.8
-
-# mount_reiserfs needs mntopts.h and getmntopts.c from src/sbin/mount/
-MOUNT ?= ${.CURDIR}/../mount
-CFLAGS += -I${MOUNT}
-
-.PATH: ${MOUNT}
-
-.include <bsd.prog.mk>
diff --git a/sbin/mount_reiserfs/Makefile.depend b/sbin/mount_reiserfs/Makefile.depend
deleted file mode 100644
index a83954553d0e..000000000000
--- a/sbin/mount_reiserfs/Makefile.depend
+++ /dev/null
@@ -1,19 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,}
-
-DEP_MACHINE := ${.PARSEFILE:E}
-
-DIRDEPS = \
- gnu/lib/libgcc \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/sbin/mount_reiserfs/mount_reiserfs.8 b/sbin/mount_reiserfs/mount_reiserfs.8
deleted file mode 100644
index f2464754cb62..000000000000
--- a/sbin/mount_reiserfs/mount_reiserfs.8
+++ /dev/null
@@ -1,90 +0,0 @@
-.\"
-.\" Copyright (c) 1993,1994 Christopher G. Demetriou
-.\" Copyright (c) 1999 Semen Ustimenko
-.\" Copyright (c) 2005 Jean-Sébastien Pédron
-.\" 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 acknowledgment:
-.\" This product includes software developed by Christopher G. Demetriou.
-.\" 3. The name of the author may not be used to endorse or promote products
-.\" derived from this software without specific prior written permission
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
-.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
-.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd February 3, 2005
-.Dt MOUNT_REISERFS 8
-.Os
-.Sh NAME
-.Nm mount_reiserfs
-.Nd "mount a ReiserFS file system"
-.Sh SYNOPSIS
-.Nm
-.Ar special
-.Ar node
-.Sh DESCRIPTION
-The
-.Nm
-utility attaches the ReiserFS file system residing on the device
-.Ar special
-to the global file system namespace at the location
-indicated by
-.Ar node .
-.Pp
-This command is normally executed by
-.Xr mount 8
-at boot time, but can be used by any user to mount a
-ReiserFS file system on any directory that they own (provided,
-of course, that they have appropriate access to the device that
-contains the file system).
-.Sh EXAMPLES
-To mount a ReiserFS volume located in
-.Pa /dev/ad1s1 :
-.Pp
-.Dl "mount_reiserfs /dev/ad1s1 /mnt"
-.Sh SEE ALSO
-.Xr mount 2 ,
-.Xr unmount 2 ,
-.Xr fstab 5 ,
-.Xr mount 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 6.0 .
-.Sh AUTHORS
-.An -nosplit
-The ReiserFS kernel implementation was written by
-.An Hans Reiser
-.Pq Pa http://www.namesys.com/ ,
-and ported to
-.Fx
-by
-.An Jean-S\['e]bastien P\['e]dron Aq dumbbell@FreeBSD.org .
-.Pp
-The
-.Nm
-utility and manual were written by
-.An Jean-S\['e]bastien P\['e]dron Aq dumbbell@FreeBSD.org .
-.Sh CAVEATS
-This utility is primarily used for read access to a ReiserFS volume.
-Writing to a volume is currently unsupported.
diff --git a/sbin/mount_reiserfs/mount_reiserfs.c b/sbin/mount_reiserfs/mount_reiserfs.c
deleted file mode 100644
index bf625267b9ba..000000000000
--- a/sbin/mount_reiserfs/mount_reiserfs.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*-
- * Copyright (c) 2005 Jean-Sébastien Pédron
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
- *
- * $FreeBSD$
- */
-
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/uio.h>
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include "mntopts.h"
-
-struct mntopt mopts[] = {
- MOPT_STDOPTS,
- MOPT_END
-};
-
-void usage(void);
-
-int
-main(int argc, char *argv[])
-{
- struct iovec *iov;
- int ch, mntflags, iovlen;
- char *dev, *dir, mntpath[MAXPATHLEN];
- char fstype[] = "reiserfs";
-
- mntflags = 0;
- while ((ch = getopt(argc, argv, "o:")) != -1) {
- switch(ch) {
- case 'o':
- getmntopts(optarg, mopts, &mntflags, 0);
- break;
- case '?':
- default:
- usage();
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 2)
- usage();
-
- dev = argv[0];
- dir = argv[1];
-
- /*
- * Resolve the mountpoint with realpath(3) and remove unnecessary
- * slashes from the devicename if there are any.
- */
- if (checkpath(dir, mntpath) != 0)
- err(EX_USAGE, "%s", mntpath);
- (void)rmslashes(dev, dev);
-
- /* Read-only support for now */
- mntflags |= MNT_RDONLY;
-
- /* Prepare the options vector for nmount(). build_iovec() is declared
- * in mntopts.h. */
- iov = NULL;
- iovlen = 0;
- build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
- build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1);
- build_iovec(&iov, &iovlen, "from", dev, (size_t)-1);
-
- if (nmount(iov, iovlen, mntflags) < 0)
- err(EX_OSERR, "%s", dev);
-
- exit(0);
-}
-
-void
-usage(void)
-{
- fprintf(stderr,
- "usage: mount_reiserfs [-o options] special node\n");
- exit(EX_USAGE);
-}
diff --git a/sbin/mount_std/Makefile b/sbin/mount_std/Makefile
deleted file mode 100644
index 44ff9ef6eb64..000000000000
--- a/sbin/mount_std/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-# @(#)Makefile 8.2 (Berkeley) 3/27/94
-# $FreeBSD$
-
-PROG= mount_std
-SRCS= mount_std.c getmntopts.c
-MAN= mount_std.8
-MLINKS= mount_std.8 mount_devfs.8 \
- mount_std.8 mount_fdescfs.8 \
- mount_std.8 mount_linprocfs.8 \
- mount_std.8 mount_procfs.8
-
-MOUNT= ${.CURDIR}/../mount
-CFLAGS+= -I${MOUNT}
-WARNS?= 3
-
-.PATH: ${MOUNT}
-
-LINKS= ${BINDIR}/mount_std ${BINDIR}/mount_devfs \
- ${BINDIR}/mount_std ${BINDIR}/mount_fdescfs \
- ${BINDIR}/mount_std ${BINDIR}/mount_linprocfs \
- ${BINDIR}/mount_std ${BINDIR}/mount_procfs
-
-.include <bsd.prog.mk>
diff --git a/sbin/mount_std/Makefile.depend b/sbin/mount_std/Makefile.depend
deleted file mode 100644
index a83954553d0e..000000000000
--- a/sbin/mount_std/Makefile.depend
+++ /dev/null
@@ -1,19 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DEP_RELDIR := ${_PARSEDIR:S,${SRCTOP}/,,}
-
-DEP_MACHINE := ${.PARSEFILE:E}
-
-DIRDEPS = \
- gnu/lib/libgcc \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/sbin/mount_std/mount_std.8 b/sbin/mount_std/mount_std.8
deleted file mode 100644
index 0aeeba8e8194..000000000000
--- a/sbin/mount_std/mount_std.8
+++ /dev/null
@@ -1,167 +0,0 @@
-.\"
-.\" Copyright (c) 1992, 1993, 1994
-.\" The Regents of the University of California. All rights reserved.
-.\" All rights reserved.
-.\"
-.\" This code is derived from software donated to Berkeley by
-.\" Jan-Simon Pendry.
-.\"
-.\" 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.
-.\" 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.
-.\"
-.\" $FreeBSD$
-.\"
-.Dd November 26, 2004
-.Dt MOUNT_STD 8
-.Os
-.Sh NAME
-.Nm mount_std ,
-.Nm mount_devfs ,
-.Nm mount_fdescfs ,
-.Nm mount_linprocfs ,
-.Nm mount_procfs
-.Nd mount
-.Dq standard
-file systems
-.Sh SYNOPSIS
-.Nm mount_ Ns Ar fsname
-.Op Fl o Ar options
-.Ar "fs"
-.Ar mount_point
-.Sh DESCRIPTION
-The
-.Nm
-utility is a generic mechanism for attaching ``standard'' file systems to
-the file system.
-The
-.Nm
-utility currently supports the following file systems:
-.Nm devfs ,
-.Nm fdescfs ,
-.Nm linprocfs
-and
-.Nm procfs .
-A ``standard'' file system is one which:
-.Bl -enum -offset indent
-.It
-accepts only the standard
-.Fl o
-options
-.Dq ro ,
-.Dq rw ,
-.Dq noexec ,
-.Dq nosuid ,
-and
-.Dq union .
-.It
-has a kernel file system module name the same as its user-visible name.
-.It
-requires no other special processing on the part of the
-.Nm
-utility.
-.El
-.Pp
-The options are as follows:
-.Bl -tag -width indent
-.It Fl o
-Options are specified with a
-.Fl o
-flag followed by a comma separated string of options.
-See the
-.Xr mount 8
-man page for possible options and their meanings.
-.El
-.Pp
-The
-.Nm
-utility examines its zeroth command-line argument (the name by which
-it was called) to determine the type of file system to be mounted.
-If
-it is called by a name which does not end in
-.Dq Li _ Ns Ar fsname ,
-.Nm
-will assume (for compatibility
-with
-.Xr mount 8 )
-that the zeroth argument contains only the name of the file system type.
-The
-.Nm
-utility is normally installed with appropriate links to commands for
-the distributed file systems which can be mounted in this way;
-for information on the function of each file system, see the manual page
-for that specific
-.Nm mount_ Ns Ar fsname
-utility.
-.Pp
-Refer to the following manual pages for detailed information
-on these file systems:
-.Xr devfs 5 ,
-.Xr fdescfs 5 ,
-.Xr linprocfs 5
-and
-.Xr procfs 5 .
-.Sh DIAGNOSTICS
-.Bl -diag
-.It argv[0] must end in _fsname
-The
-.Nm
-utility was called with a zeroth argument of
-.Dq Li mount_std .
-.It %s file system not available
-The specified file system type was not present in the kernel and no
-loadable module for it was found.
-.El
-.Sh SEE ALSO
-.Xr mount 2 ,
-.Xr unmount 2 ,
-.Xr getvfsbyname 3 ,
-.Xr devfs 5 ,
-.Xr fdescfs 5 ,
-.Xr fstab 5 ,
-.Xr linprocfs 5 ,
-.Xr procfs 5 ,
-.Xr mount 8
-.Sh HISTORY
-The
-.Nm
-utility first appeared in
-.Fx 2.2 .
-Loadable file system modules first appeared in
-.Fx 2.0 .
-The
-.Dq fdescfs
-and
-.Dq procfs
-file system types first appeared in
-.Fx 2.0 ;
-the
-.Dq devfs
-file system type first appeared in
-.Fx 2.2 ;
-the
-.Dq linprocfs
-file system type first appeared in
-.Fx 4.0 .
-.Sh CAVEATS
-None of the ``standard'' file systems may be NFS-exported.
diff --git a/sbin/mount_std/mount_std.c b/sbin/mount_std/mount_std.c
deleted file mode 100644
index c7f1643ebfeb..000000000000
--- a/sbin/mount_std/mount_std.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 1990, 1992 Jan-Simon Pendry
- * Copyright (c) 1992, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Jan-Simon Pendry.
- *
- * 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.
- * 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 const char copyright[] =
-"@(#) Copyright (c) 1992, 1993, 1994\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/mount.h>
-#include <sys/uio.h>
-
-#include <err.h>
-#include <errno.h>
-#include <stdio.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sysexits.h>
-#include <unistd.h>
-
-#include "mntopts.h"
-
-static struct mntopt mopts[] = {
- MOPT_STDOPTS,
- MOPT_END
-};
-
-static char *fsname;
-static volatile sig_atomic_t caughtsig;
-
-static void usage(void) __dead2;
-
-static void
-catchsig(int s __unused)
-{
- caughtsig = 1;
-}
-
-int
-main(int argc, char *argv[])
-{
- int ch, mntflags;
- char mntpath[MAXPATHLEN];
- struct iovec iov[4];
- int error;
-
- /*
- * XXX
- * mount(8) calls the mount programs with an argv[0] which is
- * /just/ the file system name. So, if there is no underscore
- * in argv[0], we assume that we are being called from mount(8)
- * and that argv[0] is thus the name of the file system type.
- */
- fsname = strrchr(argv[0], '_');
- if (fsname) {
- if (strcmp(fsname, "_std") == 0)
- errx(EX_USAGE, "argv[0] must end in _fsname");
- fsname++;
- } else {
- fsname = argv[0];
- }
-
- mntflags = 0;
- while ((ch = getopt(argc, argv, "o:")) != -1)
- switch (ch) {
- case 'o':
- getmntopts(optarg, mopts, &mntflags, 0);
- break;
- case '?':
- default:
- usage();
- }
- argc -= optind;
- argv += optind;
-
- if (argc != 2)
- usage();
-
- /* resolve the mountpoint with realpath(3) */
- if (checkpath(argv[1], mntpath) != 0)
- err(EX_USAGE, "%s", mntpath);
-
- iov[0].iov_base = "fstype";
- iov[0].iov_len = sizeof("fstype");
- iov[1].iov_base = fsname;
- iov[1].iov_len = strlen(iov[1].iov_base) + 1;
- iov[2].iov_base = "fspath";
- iov[2].iov_len = sizeof("fspath");
- iov[3].iov_base = mntpath;
- iov[3].iov_len = strlen(mntpath) + 1;
-
- /*
- * nmount(2) would kill us with SIGSYS if the kernel doesn't have it.
- * This design bug is inconvenient. We must catch the signal and not
- * just ignore it because of a plain bug: nmount(2) would return
- * EINVAL instead of the correct ENOSYS if the kernel doesn't have it
- * and we don't let the signal kill us. EINVAL is too ambiguous.
- * This bug in 4.4BSD-Lite1 was fixed in 4.4BSD-Lite2 but is still in
- * FreeBSD-5.0.
- */
- signal(SIGSYS, catchsig);
- error = nmount(iov, 4, mntflags);
- signal(SIGSYS, SIG_DFL);
-
- /*
- * Try with the old mount syscall in the case
- * this file system has not been converted yet,
- * or the user didn't recompile his kernel.
- */
- if (error && (errno == EOPNOTSUPP || errno == ENOSYS || caughtsig))
- error = mount(fsname, mntpath, mntflags, NULL);
-
- if (error)
- err(EX_OSERR, NULL);
- exit(0);
-}
-
-void
-usage(void)
-{
- (void)fprintf(stderr,
- "usage: mount_%s [-o options] what_to_mount mount_point\n",
- fsname);
- exit(EX_USAGE);
-}
diff --git a/sbin/mount_udf/Makefile b/sbin/mount_udf/Makefile
index c5351fdc8782..06ad9a768e4c 100644
--- a/sbin/mount_udf/Makefile
+++ b/sbin/mount_udf/Makefile
@@ -9,7 +9,6 @@ LDADD= -lkiconv
MOUNT= ${.CURDIR}/../mount
CFLAGS+= -I${MOUNT} -I${.CURDIR}/../../sys
.PATH: ${MOUNT}
-WARNS?= 1
# Needs to be dynamically linked for optional dlopen() access to
# userland libiconv
diff --git a/sbin/mount_udf/mount_udf.c b/sbin/mount_udf/mount_udf.c
index 8ee1286eea33..01fa44f50e44 100644
--- a/sbin/mount_udf/mount_udf.c
+++ b/sbin/mount_udf/mount_udf.c
@@ -73,18 +73,19 @@ void usage(void);
int
main(int argc, char **argv)
{
- struct iovec iov[12];
- int ch, i, mntflags, opts, udf_flags;
- char *dev, *dir, mntpath[MAXPATHLEN];
- char *cs_disk, *cs_local;
- int verbose;
+ char mntpath[MAXPATHLEN];
+ char fstype[] = "udf";
+ struct iovec *iov;
+ char *cs_disk, *cs_local, *dev, *dir;
+ int ch, i, iovlen, mntflags, udf_flags, verbose;
- i = mntflags = opts = udf_flags = verbose = 0;
+ i = iovlen = mntflags = udf_flags = verbose = 0;
cs_disk = cs_local = NULL;
+ iov = NULL;
while ((ch = getopt(argc, argv, "o:vC:")) != -1)
switch (ch) {
case 'o':
- getmntopts(optarg, mopts, &mntflags, &opts);
+ getmntopts(optarg, mopts, &mntflags, NULL);
break;
case 'v':
verbose++;
@@ -120,32 +121,13 @@ main(int argc, char **argv)
*/
mntflags |= MNT_RDONLY;
- iov[i].iov_base = "fstype";
- iov[i++].iov_len = sizeof("fstype");
- iov[i].iov_base = "udf";
- iov[i].iov_len = strlen(iov[i].iov_base) + 1;
- i++;
- iov[i].iov_base = "fspath";
- iov[i++].iov_len = sizeof("fspath");
- iov[i].iov_base = mntpath;
- iov[i++].iov_len = strlen(mntpath) + 1;
- iov[i].iov_base = "from";
- iov[i++].iov_len = sizeof("from");
- iov[i].iov_base = dev;
- iov[i++].iov_len = strlen(dev) + 1;
- iov[i].iov_base = "flags";
- iov[i++].iov_len = sizeof("flags");
- iov[i].iov_base = &udf_flags;
- iov[i++].iov_len = sizeof(udf_flags);
+ build_iovec(&iov, &iovlen, "fstype", fstype, (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath", mntpath, (size_t)-1);
+ build_iovec(&iov, &iovlen, "from", dev, (size_t)-1);
+ build_iovec(&iov, &iovlen, "flags", &udf_flags, sizeof(udf_flags));
if (udf_flags & UDFMNT_KICONV) {
- iov[i].iov_base = "cs_disk";
- iov[i++].iov_len = sizeof("cs_disk");
- iov[i].iov_base = cs_disk;
- iov[i++].iov_len = strlen(cs_disk) + 1;
- iov[i].iov_base = "cs_local";
- iov[i++].iov_len = sizeof("cs_local");
- iov[i].iov_base = cs_local;
- iov[i++].iov_len = strlen(cs_local) + 1;
+ build_iovec(&iov, &iovlen, "cs_disk", cs_disk, (size_t)-1);
+ build_iovec(&iov, &iovlen, "cs_local", cs_local, (size_t)-1);
}
if (nmount(iov, i, mntflags) < 0)
err(1, "%s", dev);
diff --git a/sbin/mount_unionfs/mount_unionfs.c b/sbin/mount_unionfs/mount_unionfs.c
index c42bf04dbed4..1026ecf2d9ee 100644
--- a/sbin/mount_unionfs/mount_unionfs.c
+++ b/sbin/mount_unionfs/mount_unionfs.c
@@ -129,7 +129,7 @@ int
main(int argc, char *argv[])
{
struct iovec *iov;
- int ch, mntflags, iovlen;
+ int ch, iovlen;
char source [MAXPATHLEN], target[MAXPATHLEN], errmsg[255];
char uid_str[20], gid_str[20];
char fstype[] = "unionfs";
@@ -137,7 +137,6 @@ main(int argc, char *argv[])
iov = NULL;
iovlen = 0;
- mntflags = 0;
memset(errmsg, 0, sizeof(errmsg));
while ((ch = getopt(argc, argv, "bo:")) != -1) {
@@ -190,7 +189,7 @@ main(int argc, char *argv[])
build_iovec(&iov, &iovlen, "from", target, (size_t)-1);
build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
- if (nmount(iov, iovlen, mntflags))
+ if (nmount(iov, iovlen, 0))
err(EX_OSERR, "%s: %s", source, errmsg);
exit(0);
}
diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c
index 0a547f90e3bc..a4cfa8dd7591 100644
--- a/sbin/newfs/mkfs.c
+++ b/sbin/newfs/mkfs.c
@@ -444,6 +444,12 @@ restart:
if (sblock.fs_sbsize > SBLOCKSIZE)
sblock.fs_sbsize = SBLOCKSIZE;
sblock.fs_minfree = minfree;
+ if (metaspace > 0 && metaspace < sblock.fs_fpg / 2)
+ sblock.fs_metaspace = blknum(&sblock, metaspace);
+ else if (metaspace != -1)
+ /* reserve half of minfree for metadata blocks */
+ sblock.fs_metaspace = blknum(&sblock,
+ (sblock.fs_fpg * minfree) / 200);
if (maxbpg == 0)
sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize);
else
diff --git a/sbin/newfs/newfs.8 b/sbin/newfs/newfs.8
index 7cfdfd1575f7..51cc8336bea2 100644
--- a/sbin/newfs/newfs.8
+++ b/sbin/newfs/newfs.8
@@ -50,6 +50,7 @@
.Op Fl g Ar avgfilesize
.Op Fl h Ar avgfpdir
.Op Fl i Ar bytes
+.Op Fl k Ar held-for-metadata-blocks
.Op Fl m Ar free-space
.Op Fl o Ar optimization
.Op Fl p Ar partition
@@ -163,6 +164,17 @@ This flag is implemented by running the
.Xr tunefs 8
utility found in the user's
.Dv $PATH .
+.It Fl k Ar held-for-metadata-blocks
+Set the amount of space to be held for metadata blocks in each cylinder group.
+When set, the file system preference routines will try to save
+the specified amount of space immediately following the inode blocks
+in each cylinder group for use by metadata blocks.
+Clustering the metadata blocks speeds up random file access
+and decreases the running time of
+.Xr fsck 8 .
+By default
+.Xr newfs 8
+sets it to half of the space reserved to minfree.
.It Fl l
Enable multilabel MAC on the new file system.
.It Fl m Ar free-space
@@ -214,7 +226,7 @@ See
for more details on how to set this option.
.It Fl p Ar partition
The partition name (a..h) you want to use in case the underlying image
-is a file, so you don't have access to individual partitions through the
+is a file, so you do not have access to individual partitions through the
filesystem.
Can also be used with a device, e.g.
.Nm
diff --git a/sbin/newfs/newfs.c b/sbin/newfs/newfs.c
index 3ce0be75f687..59b7e61246bb 100644
--- a/sbin/newfs/newfs.c
+++ b/sbin/newfs/newfs.c
@@ -102,6 +102,7 @@ int bsize = 0; /* block size */
int maxbsize = 0; /* maximum clustering */
int maxblkspercg = MAXBLKSPERCG; /* maximum blocks per cylinder group */
int minfree = MINFREE; /* free space threshold */
+int metaspace; /* space held for metadata blocks */
int opt = DEFAULTOPT; /* optimization preference (space or time) */
int density; /* number of bytes per inode */
int maxcontig = 0; /* max contiguous blocks to allocate */
@@ -141,7 +142,7 @@ main(int argc, char *argv[])
part_name = 'c';
reserved = 0;
while ((ch = getopt(argc, argv,
- "EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:jlm:no:p:r:s:t")) != -1)
+ "EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:jk:lm:no:p:r:s:t")) != -1)
switch (ch) {
case 'E':
Eflag = 1;
@@ -248,6 +249,13 @@ main(int argc, char *argv[])
case 'l':
lflag = 1;
break;
+ case 'k':
+ if ((metaspace = atoi(optarg)) < 0)
+ errx(1, "%s: bad metadata space %%", optarg);
+ if (metaspace == 0)
+ /* force to stay zero in mkfs */
+ metaspace = -1;
+ break;
case 'm':
if ((minfree = atoi(optarg)) < 0 || minfree > 99)
errx(1, "%s: bad free space %%", optarg);
@@ -501,6 +509,7 @@ usage()
fprintf(stderr, "\t-h average files per directory\n");
fprintf(stderr, "\t-i number of bytes per inode\n");
fprintf(stderr, "\t-j enable soft updates journaling\n");
+ fprintf(stderr, "\t-k space to hold for metadata blocks\n");
fprintf(stderr, "\t-l enable multilabel MAC\n");
fprintf(stderr, "\t-n do not create .snap directory\n");
fprintf(stderr, "\t-m minimum free space %%\n");
diff --git a/sbin/newfs/newfs.h b/sbin/newfs/newfs.h
index 9e1da0db8924..72f431404515 100644
--- a/sbin/newfs/newfs.h
+++ b/sbin/newfs/newfs.h
@@ -96,6 +96,7 @@ extern int bsize; /* block size */
extern int maxbsize; /* maximum clustering */
extern int maxblkspercg; /* maximum blocks per cylinder group */
extern int minfree; /* free space threshold */
+extern int metaspace; /* space held for metadata blocks */
extern int opt; /* optimization preference (space or time) */
extern int density; /* number of bytes per inode */
extern int maxcontig; /* max contiguous blocks to allocate */
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
index e726cbc08927..7e26240a95ba 100644
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -33,7 +33,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 17, 2012
+.Dd March 26, 2013
.Dt NVMECONTROL 8
.Os
.Sh NAME
@@ -54,7 +54,10 @@
.Op Fl p
.Aq Fl s Ar size_in_bytes
.Aq Fl t Ar time_in_sec
-.Aq device id
+.Aq namespace id
+.Nm
+.Ic reset
+.Aq controller id
.Sh DESCRIPTION
NVM Express (NVMe) is a storage protocol standard, for SSDs and other
high-speed storage devices over PCI Express.
@@ -62,6 +65,7 @@ high-speed storage devices over PCI Express.
.Dl nvmecontrol devlist
.Pp
Display a list of NVMe controllers and namespaces along with their device nodes.
+.Pp
.Dl nvmecontrol identify nvme0
.Pp
Display a human-readable summary of the nvme0 IDENTIFY_CONTROLLER data.
@@ -76,6 +80,10 @@ Display a hexadecimal dump of the nvme0 IDENTIFY_NAMESPACE data for namespace
Run a performance test on nvme0ns1 using 32 kernel threads for 30 seconds. Each
thread will issue a single 512 byte read command. Results are printed to
stdout when 30 seconds expires.
+.Pp
+.Dl nvmecontrol reset nvme0
+.Pp
+Perform a controller-level reset of the nvme0 controller.
.Sh AUTHORS
.An -nosplit
.Nm
diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c
index 6abd3f5d1d7a..cbb365b32d4a 100644
--- a/sbin/nvmecontrol/nvmecontrol.c
+++ b/sbin/nvmecontrol/nvmecontrol.c
@@ -56,6 +56,9 @@ __FBSDID("$FreeBSD$");
" <-i intr|wait> [-f refthread] [-p]\n" \
" <namespace id>\n"
+#define RESET_USAGE \
+" nvmecontrol reset <controller id>\n"
+
static void perftest_usage(void);
static void
@@ -64,6 +67,7 @@ usage(void)
fprintf(stderr, "usage:\n");
fprintf(stderr, DEVLIST_USAGE);
fprintf(stderr, IDENTIFY_USAGE);
+ fprintf(stderr, RESET_USAGE);
fprintf(stderr, PERFTEST_USAGE);
exit(EX_USAGE);
}
@@ -241,13 +245,15 @@ devlist(int argc, char *argv[])
fd = open(path, O_RDWR);
if (fd < 0) {
- printf("Could not open %s.\n", path);
+ printf("Could not open %s. errno=%d (%s)\n", path,
+ errno, strerror(errno));
exit_code = EX_NOPERM;
continue;
}
- if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) {
- printf("ioctl to %s failed.\n", path);
+ if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) < 0) {
+ printf("Identify request to %s failed. errno=%d (%s)\n",
+ path, errno, strerror(errno));
exit_code = EX_IOERR;
continue;
}
@@ -260,12 +266,15 @@ devlist(int argc, char *argv[])
fd = open(path, O_RDWR);
if (fd < 0) {
- printf("Could not open %s.\n", path);
+ printf("Could not open %s. errno=%d (%s)\n",
+ path, errno, strerror(errno));
exit_code = EX_NOPERM;
continue;
}
- if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) {
- printf("ioctl to %s failed.\n", path);
+ if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) < 0) {
+ printf("Identify request to %s failed. "
+ "errno=%d (%s)\n", path, errno,
+ strerror(errno));
exit_code = EX_IOERR;
continue;
}
@@ -307,19 +316,22 @@ identify_ctrlr(int argc, char *argv[])
sprintf(path, "/dev/%s", argv[optind]);
- if (stat(path, &devstat) != 0) {
- printf("Invalid device node '%s'.\n", path);
+ if (stat(path, &devstat) < 0) {
+ printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
+ strerror(errno));
exit(EX_IOERR);
}
fd = open(path, O_RDWR);
if (fd < 0) {
- printf("Could not open %s.\n", path);
+ printf("Could not open %s. errno=%d (%s)\n", path, errno,
+ strerror(errno));
exit(EX_NOPERM);
}
- if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) == -1) {
- printf("ioctl to %s failed.\n", path);
+ if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) < 0) {
+ printf("Identify request to %s failed. errno=%d (%s)\n", path,
+ errno, strerror(errno));
exit(EX_IOERR);
}
@@ -366,19 +378,22 @@ identify_ns(int argc, char *argv[])
sprintf(path, "/dev/%s", argv[optind]);
- if (stat(path, &devstat) != 0) {
- printf("Invalid device node '%s'.\n", path);
+ if (stat(path, &devstat) < 0) {
+ printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
+ strerror(errno));
exit(EX_IOERR);
}
fd = open(path, O_RDWR);
if (fd < 0) {
- printf("Could not open %s.\n", path);
+ printf("Could not open %s. errno=%d (%s)\n", path, errno,
+ strerror(errno));
exit(EX_NOPERM);
}
- if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) == -1) {
- printf("ioctl to %s failed.\n", path);
+ if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) < 0) {
+ printf("Identify request to %s failed. errno=%d (%s)\n", path,
+ errno, strerror(errno));
exit(EX_IOERR);
}
@@ -423,7 +438,7 @@ identify(int argc, char *argv[])
optind = 1;
/*
- * If devicde node contains "ns", we consider it a namespace,
+ * If device node contains "ns", we consider it a namespace,
* otherwise, consider it a controller.
*/
if (strstr(target, "ns") == NULL)
@@ -475,7 +490,7 @@ perftest(int argc, char *argv[])
char path[64];
u_long ioctl_cmd = NVME_IO_TEST;
bool nflag, oflag, sflag, tflag;
- int err, perthread = 0;
+ int perthread = 0;
nflag = oflag = sflag = tflag = false;
name = NULL;
@@ -565,14 +580,14 @@ perftest(int argc, char *argv[])
fd = open(path, O_RDWR);
if (fd < 0) {
- fprintf(stderr, "%s not valid device.\n", path);
+ fprintf(stderr, "%s not valid device. errno=%d (%s)\n", path,
+ errno, strerror(errno));
perftest_usage();
}
- err = ioctl(fd, ioctl_cmd, &io_test);
-
- if (err) {
- fprintf(stderr, "NVME_IO_TEST returned %d\n", errno);
+ if (ioctl(fd, ioctl_cmd, &io_test) < 0) {
+ fprintf(stderr, "NVME_IO_TEST failed. errno=%d (%s)\n", errno,
+ strerror(errno));
exit(EX_IOERR);
}
@@ -580,6 +595,44 @@ perftest(int argc, char *argv[])
exit(EX_OK);
}
+static void
+reset_ctrlr(int argc, char *argv[])
+{
+ struct stat devstat;
+ char path[64];
+ int ch, fd;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch ((char)ch) {
+ default:
+ usage();
+ }
+ }
+
+ sprintf(path, "/dev/%s", argv[optind]);
+
+ if (stat(path, &devstat) < 0) {
+ printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
+ strerror(errno));
+ exit(EX_IOERR);
+ }
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ printf("Could not open %s. errno=%d (%s)\n", path, errno,
+ strerror(errno));
+ exit(EX_NOPERM);
+ }
+
+ if (ioctl(fd, NVME_RESET_CONTROLLER) < 0) {
+ printf("Reset request to %s failed. errno=%d (%s)\n", path,
+ errno, strerror(errno));
+ exit(EX_IOERR);
+ }
+
+ exit(EX_OK);
+}
+
int
main(int argc, char *argv[])
{
@@ -593,6 +646,8 @@ main(int argc, char *argv[])
identify(argc-1, &argv[1]);
else if (strcmp(argv[1], "perftest") == 0)
perftest(argc-1, &argv[1]);
+ else if (strcmp(argv[1], "reset") == 0)
+ reset_ctrlr(argc-1, &argv[1]);
usage();
diff --git a/sbin/reboot/boot_i386.8 b/sbin/reboot/boot_i386.8
index 3b58cc5dfc68..33ad8febe4a1 100644
--- a/sbin/reboot/boot_i386.8
+++ b/sbin/reboot/boot_i386.8
@@ -220,15 +220,14 @@ you can use the
option to force the kernel to use the serial port as its
console device.
The serial port driver
-.Xr uart 4
+.Xr sio 4
+(but not
+.Xr uart 4 )
has a flag (0x20) to override this option.
If that flag is set, the serial port will always be used as the console,
regardless of the
.Fl h
option described here.
-See the man page for
-.Xr uart 4
-for more details.
.It Fl m
mute the console to suppress all console input and output during the
boot.
diff --git a/sbin/recoverdisk/recoverdisk.c b/sbin/recoverdisk/recoverdisk.c
index caa8ebdeccbe..af0d88e0bcc8 100644
--- a/sbin/recoverdisk/recoverdisk.c
+++ b/sbin/recoverdisk/recoverdisk.c
@@ -156,7 +156,7 @@ main(int argc, char * const argv[])
int error, state;
u_char *buf;
u_int sectorsize;
- u_int stripesize;
+ off_t stripesize;
time_t t1, t2;
struct stat sb;
u_int n, snapshot = 60;
diff --git a/sbin/shutdown/shutdown.8 b/sbin/shutdown/shutdown.8
index b7067e12fff7..871efbed8b06 100644
--- a/sbin/shutdown/shutdown.8
+++ b/sbin/shutdown/shutdown.8
@@ -28,7 +28,7 @@
.\" @(#)shutdown.8 8.2 (Berkeley) 4/27/95
.\" $FreeBSD$
.\"
-.Dd July 13, 2011
+.Dd March 19, 2013
.Dt SHUTDOWN 8
.Os
.Sh NAME
@@ -189,6 +189,11 @@ tells
.Xr login 1
not to let anyone log in
.El
+.Sh EXAMPLES
+Reboot the system in 30 minutes and display a warning message on the terminals
+of all users currently logged in:
+.Pp
+.Dl # shutdown -r +30 \&"System will reboot\&"
.Sh COMPATIBILITY
The hours and minutes in the second time format may be separated by
a colon (``:'') for backward compatibility.
diff --git a/sbin/tunefs/tunefs.8 b/sbin/tunefs/tunefs.8
index 5b522e585060..a58c17479d7a 100644
--- a/sbin/tunefs/tunefs.8
+++ b/sbin/tunefs/tunefs.8
@@ -42,6 +42,7 @@
.Op Fl f Ar avgfilesize
.Op Fl j Cm enable | disable
.Op Fl J Cm enable | disable
+.Op Fl k Ar held-for-metadata-blocks
.Op Fl L Ar volname
.Op Fl l Cm enable | disable
.Op Fl m Ar minfree
@@ -96,6 +97,19 @@ Specify the expected average file size.
Turn on/off soft updates journaling.
.It Fl J Cm enable | disable
Turn on/off gjournal flag.
+.It Fl k Ar held-for-metadata-blocks
+Set the amount of space to be held for metadata blocks.
+When set, the file system preference routines will try to save
+the specified amount of space immediately following the inode blocks
+in each cylinder group for use by metadata blocks.
+Clustering the metadata blocks speeds up random file access
+and decreases the running time of
+.Xr fsck 8 .
+While this option can be set at any time,
+it is most effective if set before any data is loaded into the file system.
+By default
+.Xr newfs 8
+sets it to half of the space reserved to minfree.
.It Fl L Ar volname
Add/modify an optional file system volume label.
.It Fl l Cm enable | disable
diff --git a/sbin/tunefs/tunefs.c b/sbin/tunefs/tunefs.c
index 688952fc790a..0671d1de5896 100644
--- a/sbin/tunefs/tunefs.c
+++ b/sbin/tunefs/tunefs.c
@@ -89,10 +89,9 @@ main(int argc, char *argv[])
const char *special, *on;
const char *name;
int active;
- int Aflag, aflag, eflag, evalue, fflag, fvalue, jflag, Jflag, Lflag;
- int lflag, mflag, mvalue, Nflag, nflag, oflag, ovalue, pflag, sflag;
- int tflag;
- int svalue, Svalue;
+ int Aflag, aflag, eflag, evalue, fflag, fvalue, jflag, Jflag, kflag;
+ int kvalue, Lflag, lflag, mflag, mvalue, Nflag, nflag, oflag, ovalue;
+ int pflag, sflag, svalue, Svalue, tflag;
int ch, found_arg, i;
const char *chg[2];
struct ufs_args args;
@@ -100,13 +99,13 @@ main(int argc, char *argv[])
if (argc < 3)
usage();
- Aflag = aflag = eflag = fflag = jflag = Jflag = Lflag = lflag = 0;
- mflag = Nflag = nflag = oflag = pflag = sflag = tflag = 0;
+ Aflag = aflag = eflag = fflag = jflag = Jflag = kflag = Lflag = 0;
+ lflag = mflag = Nflag = nflag = oflag = pflag = sflag = tflag = 0;
avalue = jvalue = Jvalue = Lvalue = lvalue = Nvalue = nvalue = NULL;
evalue = fvalue = mvalue = ovalue = svalue = Svalue = 0;
active = 0;
found_arg = 0; /* At least one arg is required. */
- while ((ch = getopt(argc, argv, "Aa:e:f:j:J:L:l:m:N:n:o:ps:S:t:"))
+ while ((ch = getopt(argc, argv, "Aa:e:f:j:J:k:L:l:m:N:n:o:ps:S:t:"))
!= -1)
switch (ch) {
@@ -171,6 +170,14 @@ main(int argc, char *argv[])
Jflag = 1;
break;
+ case 'k':
+ found_arg = 1;
+ name = "space to hold for metadata blocks";
+ kvalue = atoi(optarg);
+ if (mvalue < 0)
+ errx(10, "bad %s (%s)", name, optarg);
+ kflag = 1;
+ break;
case 'L':
found_arg = 1;
@@ -404,6 +411,22 @@ main(int argc, char *argv[])
}
}
}
+ if (kflag) {
+ name = "space to hold for metadata blocks";
+ if (sblock.fs_metaspace == kvalue)
+ warnx("%s remains unchanged as %d", name, kvalue);
+ else {
+ kvalue = blknum(&sblock, kvalue);
+ if (kvalue > sblock.fs_fpg / 2) {
+ kvalue = blknum(&sblock, sblock.fs_fpg / 2);
+ warnx("%s cannot exceed half the file system "
+ "space", name);
+ }
+ warnx("%s changes from %jd to %d",
+ name, sblock.fs_metaspace, kvalue);
+ sblock.fs_metaspace = kvalue;
+ }
+ }
if (lflag) {
name = "multilabel";
if (strcmp(lvalue, "enable") == 0) {
@@ -671,7 +694,7 @@ journal_findfile(void)
return (ino);
}
} else {
- if ((off_t)dp1->di_size >= lblktosize(&sblock, NDADDR)) {
+ if ((off_t)dp2->di_size >= lblktosize(&sblock, NDADDR)) {
warnx("ROOTINO extends beyond direct blocks.");
return (-1);
}
@@ -1064,7 +1087,7 @@ usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n",
"usage: tunefs [-A] [-a enable | disable] [-e maxbpg] [-f avgfilesize]",
-" [-J enable | disable] [-j enable | disable]",
+" [-J enable | disable] [-j enable | disable] [-k metaspace]",
" [-L volname] [-l enable | disable] [-m minfree]",
" [-N enable | disable] [-n enable | disable]",
" [-o space | time] [-p] [-s avgfpdir] [-t enable | disable]",
@@ -1097,6 +1120,8 @@ printfs(void)
sblock.fs_avgfpdir);
warnx("minimum percentage of free space: (-m) %d%%",
sblock.fs_minfree);
+ warnx("space to hold for metadata blocks: (-k) %jd",
+ sblock.fs_metaspace);
warnx("optimization preference: (-o) %s",
sblock.fs_optim == FS_OPTSPACE ? "space" : "time");
if (sblock.fs_minfree >= MINFREE &&