[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Wed Jul 25 14:36:04 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/4936d08172d1
changeset: 489:4936d08172d1
user:      Aleksandr Rybalko <ray at ddteam.net>
date:      Wed Jul 25 16:24:55 2012 +0300
description:
Lazy update

diffstat:

 head/sbin/Makefile                        |     8 +-
 head/sbin/atacontrol/atacontrol.8         |     6 +-
 head/sbin/camcontrol/Makefile             |     4 +-
 head/sbin/camcontrol/camcontrol.8         |    13 +-
 head/sbin/camcontrol/camcontrol.c         |   265 +++++-
 head/sbin/camcontrol/camcontrol.h         |     5 +-
 head/sbin/camcontrol/fwdownload.c         |   207 +++-
 head/sbin/camcontrol/progress.c           |   186 ++++
 head/sbin/camcontrol/progress.h           |    60 +
 head/sbin/devd/devd.cc                    |     4 +-
 head/sbin/devd/parse.y                    |     3 +-
 head/sbin/devfs/devfs.8                   |    14 +-
 head/sbin/dump/dump.8                     |    20 +-
 head/sbin/etherswitchcfg/Makefile         |     9 +
 head/sbin/etherswitchcfg/etherswitchcfg.8 |   115 ++
 head/sbin/etherswitchcfg/etherswitchcfg.c |   511 ++++++++++++
 head/sbin/etherswitchcfg/ifmedia.c        |   812 ++++++++++++++++++++
 head/sbin/fsck_ffs/suj.c                  |    17 +-
 head/sbin/fsck_msdosfs/main.c             |     3 +-
 head/sbin/geom/class/eli/geli.8           |   234 +++-
 head/sbin/geom/class/part/geom_part.c     |     7 +-
 head/sbin/geom/class/part/gpart.8         |     6 +-
 head/sbin/geom/class/raid/geom_raid.c     |     5 +-
 head/sbin/geom/class/raid/graid.8         |    61 +-
 head/sbin/geom/class/virstor/gvirstor.8   |     7 +-
 head/sbin/growfs/Makefile                 |    10 +-
 head/sbin/growfs/growfs.8                 |   105 +--
 head/sbin/growfs/growfs.c                 |   348 +++++--
 head/sbin/gvinum/gvinum.8                 |    17 +-
 head/sbin/hastctl/hastctl.8               |     4 +-
 head/sbin/hastd/hast.conf.5               |    14 +-
 head/sbin/hastd/hast.h                    |     3 +-
 head/sbin/hastd/hastd.8                   |     4 +-
 head/sbin/hastd/parse.y                   |   588 +++++++-------
 head/sbin/hastd/primary.c                 |    85 +-
 head/sbin/hastd/proto_common.c            |     4 +-
 head/sbin/hastd/synch.h                   |     4 +-
 head/sbin/ifconfig/af_inet6.c             |     4 +-
 head/sbin/ifconfig/af_nd6.c               |     8 +-
 head/sbin/ifconfig/ifconfig.8             |    54 +-
 head/sbin/ifconfig/ifconfig.c             |    15 +-
 head/sbin/ifconfig/ifieee80211.c          |    18 +-
 head/sbin/ifconfig/iflagg.c               |     5 +-
 head/sbin/init/init.c                     |     4 +-
 head/sbin/ipfw/ipfw.8                     |    42 +-
 head/sbin/iscontrol/iscsi.conf.5          |     6 +-
 head/sbin/mca/Makefile                    |     3 +-
 head/sbin/mca/mca.c                       |    18 +-
 head/sbin/md5/md5.1                       |     4 +-
 head/sbin/md5/md5.c                       |     4 +-
 head/sbin/mdconfig/Makefile               |     3 +-
 head/sbin/mdconfig/mdconfig.8             |    25 +-
 head/sbin/mdconfig/mdconfig.c             |    57 +-
 head/sbin/mount/mount.8                   |    11 +-
 head/sbin/nandfs/Makefile                 |    10 +
 head/sbin/nandfs/lssnap.c                 |   112 ++
 head/sbin/nandfs/mksnap.c                 |    80 +
 head/sbin/nandfs/nandfs.8                 |    74 +
 head/sbin/nandfs/nandfs.c                 |    74 +
 head/sbin/nandfs/nandfs.h                 |    40 +
 head/sbin/nandfs/rmsnap.c                 |    87 ++
 head/sbin/natd/natd.8                     |    16 +-
 head/sbin/newfs_nandfs/Makefile           |     9 +
 head/sbin/newfs_nandfs/newfs_nandfs.8     |    76 +
 head/sbin/newfs_nandfs/newfs_nandfs.c     |  1176 +++++++++++++++++++++++++++++
 head/sbin/ping/ping.c                     |     4 +-
 head/sbin/restore/restore.8               |    20 +-
 head/sbin/restore/utilities.c             |     3 +-
 head/sbin/setkey/setkey.8                 |    26 +-
 head/sbin/shutdown/shutdown.c             |     3 +-
 70 files changed, 4954 insertions(+), 905 deletions(-)

diffs (8191 lines):

diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/Makefile
--- a/head/sbin/Makefile	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -1,5 +1,5 @@
 #	@(#)Makefile	8.5 (Berkeley) 3/31/94
-# $FreeBSD$
+# $FreeBSD: head/sbin/Makefile 235537 2012-05-17 10:11:18Z gber $
 
 .include <bsd.own.mk>
 
@@ -20,6 +20,7 @@
 	dump \
 	dumpfs \
 	dumpon \
+	etherswitchcfg \
 	ffsinfo \
 	fsck \
 	fsck_ffs \
@@ -91,6 +92,11 @@
 SUBDIR+=	natd
 .endif
 
+.if ${MK_NAND} != "no"
+SUBDIR+=	nandfs
+SUBDIR+=	newfs_nandfs
+.endif
+
 .if ${MK_PF} != "no"
 SUBDIR+=	pfctl
 SUBDIR+=	pflogd
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/atacontrol/atacontrol.8
--- a/head/sbin/atacontrol/atacontrol.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/atacontrol/atacontrol.8	Wed Jul 25 16:24:55 2012 +0300
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/atacontrol/atacontrol.8 226179 2011-10-09 21:42:02Z rodrigc $
+.\" $FreeBSD: head/sbin/atacontrol/atacontrol.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd October 9, 2011
 .Dt ATACONTROL 8
@@ -367,8 +367,8 @@
 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 ata 4 ,
+.Xr cam 4 ,
 .Xr camcontrol 8
 .Sh HISTORY
 The
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/Makefile
--- a/head/sbin/camcontrol/Makefile	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/camcontrol/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -1,9 +1,9 @@
-# $FreeBSD: head/sbin/camcontrol/Makefile 230727 2012-01-29 09:12:34Z nyan $
+# $FreeBSD: head/sbin/camcontrol/Makefile 237281 2012-06-20 00:17:29Z scottl $
 
 PROG=	camcontrol
 SRCS=	camcontrol.c util.c
 .if !defined(RELEASE_CRUNCH)
-SRCS+=	fwdownload.c modeedit.c
+SRCS+=	fwdownload.c modeedit.c progress.c
 .else
 CFLAGS+= -DMINIMALISTIC
 .endif
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/camcontrol.8
--- a/head/sbin/camcontrol/camcontrol.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/camcontrol/camcontrol.8	Wed Jul 25 16:24:55 2012 +0300
@@ -25,9 +25,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/camcontrol/camcontrol.8 233648 2012-03-29 05:02:12Z eadler $
+.\" $FreeBSD: head/sbin/camcontrol/camcontrol.8 237452 2012-06-22 18:57:06Z ken $
 .\"
-.Dd November 24, 2011
+.Dd June 4, 2012
 .Dt CAMCONTROL 8
 .Os
 .Sh NAME
@@ -175,6 +175,7 @@
 .Op Fl S
 .Op Fl X
 .Op Fl c
+.Op Fl p
 .Aq all|off|bus Ns Op :target Ns Op :lun
 .Nm
 .Ic tags
@@ -496,6 +497,8 @@
 .Nm
 will print out the number of defects given in the READ DEFECT DATA header
 returned from the drive.
+Some drives will report 0 defects if neither the primary or grown defect
+lists are requested.
 .It Ic modepage
 Allows the user to display and optionally edit a SCSI mode page.
 The mode
@@ -737,7 +740,7 @@
 See the
 .Tn ANSI
 .Tn SAS
-Protcol Layer (SPL)
+Protocol Layer (SPL)
 specification for more information on this field.
 .It Fl a Ar enable|disable
 Enable or disable SATA slumber phy power conditions.
@@ -796,6 +799,8 @@
 Enable CAM_DEBUG_CDB printfs.
 This will cause the kernel to print out the
 SCSI CDBs sent to the specified device(s).
+.It Fl p
+Enable CAM_DEBUG_PROBE printfs.
 .It all
 Enable debugging for all devices.
 .It off
@@ -1106,7 +1111,7 @@
 Run in simulation mode.
 Packet sizes that will be sent are shown, but no actual packet is sent to the
 device.
-No confimation is asked in simulation mode.
+No confirmation is asked in simulation mode.
 .It Fl v
 Besides showing sense information in case of a failure, the verbose option
 causes
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/camcontrol.c
--- a/head/sbin/camcontrol/camcontrol.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/camcontrol/camcontrol.c	Wed Jul 25 16:24:55 2012 +0300
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/camcontrol/camcontrol.c 230590 2012-01-26 18:09:28Z ken $");
+__FBSDID("$FreeBSD: head/sbin/camcontrol/camcontrol.c 237452 2012-06-22 18:57:06Z ken $");
 
 #include <sys/ioctl.h>
 #include <sys/stdint.h>
@@ -123,6 +123,7 @@
 	CAM_ARG_DEBUG_CDB	= 0x08000000,
 	CAM_ARG_DEBUG_XPT	= 0x10000000,
 	CAM_ARG_DEBUG_PERIPH	= 0x20000000,
+	CAM_ARG_DEBUG_PROBE	= 0x40000000,
 } cam_argmask;
 
 struct camcontrol_opts {
@@ -176,7 +177,7 @@
 	{"tags", CAM_CMD_TAG, CAM_ARG_NONE, "N:q"},
 	{"negotiate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
 	{"rate", CAM_CMD_RATE, CAM_ARG_NONE, negotiate_opts},
-	{"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXc"},
+	{"debug", CAM_CMD_DEBUG, CAM_ARG_NONE, "IPTSXcp"},
 	{"format", CAM_CMD_FORMAT, CAM_ARG_NONE, "qrwy"},
 	{"idle", CAM_CMD_IDLE, CAM_ARG_NONE, "t:"},
 	{"standby", CAM_CMD_STANDBY, CAM_ARG_NONE, "t:"},
@@ -456,7 +457,7 @@
 			case DEV_MATCH_DEVICE: {
 				struct device_match_result *dev_result;
 				char vendor[16], product[48], revision[16];
-				char tmpstr[256];
+				char fw[5], tmpstr[256];
 
 				dev_result =
 				     &ccb.cdm.matches[i].result.device_result;
@@ -495,6 +496,25 @@
 					   sizeof(revision));
 				    sprintf(tmpstr, "<%s %s>", product,
 					revision);
+				} else if (dev_result->protocol == PROTO_SEMB) {
+					struct sep_identify_data *sid;
+
+					sid = (struct sep_identify_data *)
+					    &dev_result->ident_data;
+					cam_strvis(vendor, sid->vendor_id,
+					    sizeof(sid->vendor_id),
+					    sizeof(vendor));
+					cam_strvis(product, sid->product_id,
+					    sizeof(sid->product_id),
+					    sizeof(product));
+					cam_strvis(revision, sid->product_rev,
+					    sizeof(sid->product_rev),
+					    sizeof(revision));
+					cam_strvis(fw, sid->firmware_rev,
+					    sizeof(sid->firmware_rev),
+					    sizeof(fw));
+					sprintf(tmpstr, "<%s %s %s %s>",
+					    vendor, product, revision, fw);
 				} else {
 				    sprintf(tmpstr, "<>");
 				}
@@ -1006,11 +1026,11 @@
 		if (sas->valid & CTS_SAS_VALID_SPEED)
 			speed = sas->bitrate;
 	} else if (ccb->cts.transport == XPORT_ATA) {
-		struct ccb_trans_settings_ata *ata =
+		struct ccb_trans_settings_pata *pata =
 		    &ccb->cts.xport_specific.ata;
 
-		if (ata->valid & CTS_ATA_VALID_MODE)
-			speed = ata_mode2speed(ata->mode);
+		if (pata->valid & CTS_ATA_VALID_MODE)
+			speed = ata_mode2speed(pata->mode);
 	} else if (ccb->cts.transport == XPORT_SATA) {
 		struct	ccb_trans_settings_sata *sata =
 		    &ccb->cts.xport_specific.sata;
@@ -1053,16 +1073,16 @@
 			fprintf(stdout, ")");
 		}
 	} else if (ccb->cts.transport == XPORT_ATA) {
-		struct ccb_trans_settings_ata *ata =
+		struct ccb_trans_settings_pata *pata =
 		    &ccb->cts.xport_specific.ata;
 
 		printf(" (");
-		if (ata->valid & CTS_ATA_VALID_MODE)
-			printf("%s, ", ata_mode2string(ata->mode));
-		if ((ata->valid & CTS_ATA_VALID_ATAPI) && ata->atapi != 0)
-			printf("ATAPI %dbytes, ", ata->atapi);
-		if (ata->valid & CTS_ATA_VALID_BYTECOUNT)
-			printf("PIO %dbytes", ata->bytecount);
+		if (pata->valid & CTS_ATA_VALID_MODE)
+			printf("%s, ", ata_mode2string(pata->mode));
+		if ((pata->valid & CTS_ATA_VALID_ATAPI) && pata->atapi != 0)
+			printf("ATAPI %dbytes, ", pata->atapi);
+		if (pata->valid & CTS_ATA_VALID_BYTECOUNT)
+			printf("PIO %dbytes", pata->bytecount);
 		printf(")");
 	} else if (ccb->cts.transport == XPORT_SATA) {
 		struct ccb_trans_settings_sata *sata =
@@ -1779,13 +1799,14 @@
 	union ccb *ccb = NULL;
 	struct scsi_read_defect_data_10 *rdd_cdb;
 	u_int8_t *defect_list = NULL;
-	u_int32_t dlist_length = 65000;
+	u_int32_t max_dlist_length = SRDD10_MAX_LENGTH, dlist_length = 0;
 	u_int32_t returned_length = 0;
 	u_int32_t num_returned = 0;
 	u_int8_t returned_format;
 	unsigned int i;
 	int c, error = 0;
-	int lists_specified = 0;
+	int lists_specified;
+	int get_length = 1;
 
 	while ((c = getopt(argc, argv, combinedopt)) != -1) {
 		switch(c){
@@ -1822,20 +1843,33 @@
 	ccb = cam_getccb(device);
 
 	/*
-	 * Hopefully 65000 bytes is enough to hold the defect list.  If it
-	 * isn't, the disk is probably dead already.  We'd have to go with
-	 * 12 byte command (i.e. alloc_length is 32 bits instead of 16)
-	 * to hold them all.
+	 * Eventually we should probably support the 12 byte READ DEFECT
+	 * DATA command.  It supports a longer parameter list, which may be
+	 * necessary on newer drives with lots of defects.  According to
+	 * the SBC-3 spec, drives are supposed to return an illegal request
+	 * if they have more defect data than will fit in 64K.
 	 */
-	defect_list = malloc(dlist_length);
+	defect_list = malloc(max_dlist_length);
 	if (defect_list == NULL) {
 		warnx("can't malloc memory for defect list");
 		error = 1;
 		goto defect_bailout;
 	}
 
+	/*
+	 * We start off asking for just the header to determine how much
+	 * defect data is available.  Some Hitachi drives return an error
+	 * if you ask for more data than the drive has.  Once we know the
+	 * length, we retry the command with the returned length.
+	 */
+	dlist_length = sizeof(struct scsi_read_defect_data_hdr_10);
+
 	rdd_cdb =(struct scsi_read_defect_data_10 *)&ccb->csio.cdb_io.cdb_bytes;
 
+retry:
+
+	lists_specified = 0;
+
 	/*
 	 * cam_getccb() zeros the CCB header only.  So we need to zero the
 	 * payload portion of the ccb.
@@ -1897,6 +1931,51 @@
 	returned_length = scsi_2btoul(((struct
 		scsi_read_defect_data_hdr_10 *)defect_list)->length);
 
+	if (get_length != 0) {
+		get_length = 0;
+
+		if ((ccb->ccb_h.status & CAM_STATUS_MASK) ==
+		     CAM_SCSI_STATUS_ERROR) {
+			struct scsi_sense_data *sense;
+			int error_code, sense_key, asc, ascq;
+
+			sense = &ccb->csio.sense_data;
+			scsi_extract_sense_len(sense, ccb->csio.sense_len -
+			    ccb->csio.sense_resid, &error_code, &sense_key,
+			    &asc, &ascq, /*show_errors*/ 1);
+
+			/*
+			 * If the drive is reporting that it just doesn't
+			 * support the defect list format, go ahead and use
+			 * the length it reported.  Otherwise, the length
+			 * may not be valid, so use the maximum.
+			 */
+			if ((sense_key == SSD_KEY_RECOVERED_ERROR)
+			 && (asc == 0x1c) && (ascq == 0x00)
+			 && (returned_length > 0)) {
+				dlist_length = returned_length +
+				    sizeof(struct scsi_read_defect_data_hdr_10);
+				dlist_length = min(dlist_length,
+						   SRDD10_MAX_LENGTH);
+			} else
+				dlist_length = max_dlist_length;
+		} else if ((ccb->ccb_h.status & CAM_STATUS_MASK) !=
+			    CAM_REQ_CMP){
+			error = 1;
+			warnx("Error reading defect header");
+			if (arglist & CAM_ARG_VERBOSE)
+				cam_error_print(device, ccb, CAM_ESF_ALL,
+						CAM_EPF_ALL, stderr);
+			goto defect_bailout;
+		} else {
+			dlist_length = returned_length +
+			    sizeof(struct scsi_read_defect_data_hdr_10);
+			dlist_length = min(dlist_length, SRDD10_MAX_LENGTH);
+		}
+
+		goto retry;
+	}
+
 	returned_format = ((struct scsi_read_defect_data_hdr_10 *)
 			defect_list)->format;
 
@@ -2621,6 +2700,10 @@
 			arglist |= CAM_ARG_DEBUG_CDB;
 			ccb.cdbg.flags |= CAM_DEBUG_CDB;
 			break;
+		case 'p':
+			arglist |= CAM_ARG_DEBUG_PROBE;
+			ccb.cdbg.flags |= CAM_DEBUG_PROBE;
+			break;
 		default:
 			break;
 		}
@@ -2650,7 +2733,7 @@
 		ccb.cdbg.flags = CAM_DEBUG_NONE;
 		arglist &= ~(CAM_ARG_DEBUG_INFO|CAM_ARG_DEBUG_PERIPH|
 			     CAM_ARG_DEBUG_TRACE|CAM_ARG_DEBUG_SUBTRACE|
-			     CAM_ARG_DEBUG_XPT);
+			     CAM_ARG_DEBUG_XPT|CAM_ARG_DEBUG_PROBE);
 	} else if (strncmp(tstr, "all", 3) != 0) {
 		tmpstr = (char *)strtok(tstr, ":");
 		if ((tmpstr != NULL) && (*tmpstr != '\0')){
@@ -2872,21 +2955,45 @@
 				"enabled" : "disabled");
 		}
 	}
+	if (cts->transport == XPORT_FC) {
+		struct ccb_trans_settings_fc *fc =
+		    &cts->xport_specific.fc;
+
+		if (fc->valid & CTS_FC_VALID_WWNN)
+			fprintf(stdout, "%sWWNN: 0x%llx", pathstr,
+			    (long long) fc->wwnn);
+		if (fc->valid & CTS_FC_VALID_WWPN)
+			fprintf(stdout, "%sWWPN: 0x%llx", pathstr,
+			    (long long) fc->wwpn);
+		if (fc->valid & CTS_FC_VALID_PORT)
+			fprintf(stdout, "%sPortID: 0x%x", pathstr, fc->port);
+		if (fc->valid & CTS_FC_VALID_SPEED)
+			fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
+			    pathstr, fc->bitrate / 1000, fc->bitrate % 1000);
+	}
+	if (cts->transport == XPORT_SAS) {
+		struct ccb_trans_settings_sas *sas =
+		    &cts->xport_specific.sas;
+
+		if (sas->valid & CTS_SAS_VALID_SPEED)
+			fprintf(stdout, "%stransfer speed: %d.%03dMB/s\n",
+			    pathstr, sas->bitrate / 1000, sas->bitrate % 1000);
+	}
 	if (cts->transport == XPORT_ATA) {
-		struct ccb_trans_settings_ata *ata =
+		struct ccb_trans_settings_pata *pata =
 		    &cts->xport_specific.ata;
 
-		if ((ata->valid & CTS_ATA_VALID_MODE) != 0) {
+		if ((pata->valid & CTS_ATA_VALID_MODE) != 0) {
 			fprintf(stdout, "%sATA mode: %s\n", pathstr,
-				ata_mode2string(ata->mode));
+				ata_mode2string(pata->mode));
 		}
-		if ((ata->valid & CTS_ATA_VALID_ATAPI) != 0) {
+		if ((pata->valid & CTS_ATA_VALID_ATAPI) != 0) {
 			fprintf(stdout, "%sATAPI packet length: %d\n", pathstr,
-				ata->atapi);
+				pata->atapi);
 		}
-		if ((ata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
+		if ((pata->valid & CTS_ATA_VALID_BYTECOUNT) != 0) {
 			fprintf(stdout, "%sPIO transaction length: %d\n",
-				pathstr, ata->bytecount);
+				pathstr, pata->bytecount);
 		}
 	}
 	if (cts->transport == XPORT_SATA) {
@@ -2922,12 +3029,22 @@
 				sata->caps);
 		}
 	}
+	if (cts->protocol == PROTO_ATA) {
+		struct ccb_trans_settings_ata *ata=
+		    &cts->proto_specific.ata;
+
+		if (ata->valid & CTS_ATA_VALID_TQ) {
+			fprintf(stdout, "%stagged queueing: %s\n", pathstr,
+				(ata->flags & CTS_ATA_FLAGS_TAG_ENB) ?
+				"enabled" : "disabled");
+		}
+	}
 	if (cts->protocol == PROTO_SCSI) {
 		struct ccb_trans_settings_scsi *scsi=
 		    &cts->proto_specific.scsi;
 
 		if (scsi->valid & CTS_SCSI_VALID_TQ) {
-			fprintf(stdout, "%stagged queueing is %s\n", pathstr,
+			fprintf(stdout, "%stagged queueing: %s\n", pathstr,
 				(scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) ?
 				"enabled" : "disabled");
 		}
@@ -3013,6 +3130,26 @@
 	return(retval);
 }
 
+/* return the type of disk (really the command type) */
+static const char *
+get_disk_type(struct cam_device *device)
+{
+	struct ccb_getdev	cgd;
+
+	(void) memset(&cgd, 0x0, sizeof(cgd));
+	get_cgd(device, &cgd);
+	switch(cgd.protocol) {
+	case PROTO_SCSI:
+		return "scsi";
+	case PROTO_ATA:
+	case PROTO_ATAPI:
+	case PROTO_SATAPM:
+		return "ata";
+	default:
+		return "unknown";
+	}
+}
+
 static void
 cpi_print(struct ccb_pathinq *cpi)
 {
@@ -3365,16 +3502,19 @@
 	if (change_settings) {
 		int didsettings = 0;
 		struct ccb_trans_settings_spi *spi = NULL;
+		struct ccb_trans_settings_pata *pata = NULL;
+		struct ccb_trans_settings_sata *sata = NULL;
 		struct ccb_trans_settings_ata *ata = NULL;
-		struct ccb_trans_settings_sata *sata = NULL;
 		struct ccb_trans_settings_scsi *scsi = NULL;
 
 		if (ccb->cts.transport == XPORT_SPI)
 			spi = &ccb->cts.xport_specific.spi;
 		if (ccb->cts.transport == XPORT_ATA)
-			ata = &ccb->cts.xport_specific.ata;
+			pata = &ccb->cts.xport_specific.ata;
 		if (ccb->cts.transport == XPORT_SATA)
 			sata = &ccb->cts.xport_specific.sata;
+		if (ccb->cts.protocol == PROTO_ATA)
+			ata = &ccb->cts.proto_specific.ata;
 		if (ccb->cts.protocol == PROTO_SCSI)
 			scsi = &ccb->cts.proto_specific.scsi;
 		ccb->cts.xport_specific.valid = 0;
@@ -3385,20 +3525,30 @@
 				spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
 			else
 				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
+			didsettings++;
 		}
-		if (scsi && tag_enable != -1) {
+		if (tag_enable != -1) {
 			if ((cpi.hba_inquiry & PI_TAG_ABLE) == 0) {
 				warnx("HBA does not support tagged queueing, "
 				      "so you cannot modify tag settings");
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
-			scsi->valid |= CTS_SCSI_VALID_TQ;
-			if (tag_enable == 0)
-				scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
-			else
-				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
-			didsettings++;
+			if (ata) {
+				ata->valid |= CTS_SCSI_VALID_TQ;
+				if (tag_enable == 0)
+					ata->flags &= ~CTS_ATA_FLAGS_TAG_ENB;
+				else
+					ata->flags |= CTS_ATA_FLAGS_TAG_ENB;
+				didsettings++;
+			} else if (scsi) {
+				scsi->valid |= CTS_SCSI_VALID_TQ;
+				if (tag_enable == 0)
+					scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
+				else
+					scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
+				didsettings++;
+			}
 		}
 		if (spi && offset != -1) {
 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
@@ -3445,6 +3595,12 @@
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
+			if  (!user_settings) {
+				warnx("You can modify only user rate "
+				    "settings for SATA");
+				retval = 1;
+				goto ratecontrol_bailout;
+			}
 			sata->revision = ata_speed2revision(syncrate * 100);
 			if (sata->revision < 0) {
 				warnx("Invalid rate %f", syncrate);
@@ -3454,16 +3610,22 @@
 			sata->valid |= CTS_SATA_VALID_REVISION;
 			didsettings++;
 		}
-		if ((ata || sata) && mode != -1) {
+		if ((pata || sata) && mode != -1) {
 			if ((cpi.hba_inquiry & PI_SDTR_ABLE) == 0) {
 				warnx("HBA is not capable of changing "
 				      "transfer rates");
 				retval = 1;
 				goto ratecontrol_bailout;
 			}
-			if (ata) {
-				ata->mode = mode;
-				ata->valid |= CTS_ATA_VALID_MODE;
+			if  (!user_settings) {
+				warnx("You can modify only user mode "
+				    "settings for ATA/SATA");
+				retval = 1;
+				goto ratecontrol_bailout;
+			}
+			if (pata) {
+				pata->mode = mode;
+				pata->valid |= CTS_ATA_VALID_MODE;
 			} else {
 				sata->mode = mode;
 				sata->valid |= CTS_SATA_VALID_MODE;
@@ -3510,11 +3672,6 @@
 		if  (didsettings == 0) {
 			goto ratecontrol_bailout;
 		}
-		if  (!user_settings && (ata || sata)) {
-			warnx("You can modify only user settings for ATA/SATA");
-			retval = 1;
-			goto ratecontrol_bailout;
-		}
 		ccb->ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
 		if (cam_send_ccb(device, ccb) < 0) {
 			perror("error sending XPT_SET_TRAN_SETTINGS CCB");
@@ -3546,13 +3703,10 @@
 				fprintf(stderr, "Test Unit Ready failed\n");
 			goto ratecontrol_bailout;
 		}
-		/*
-		 * If the user wants things quiet, there's no sense in
-		 * getting the transfer settings, if we're not going
-		 * to print them.
-		 */
-		if (quiet != 0)
-			goto ratecontrol_bailout;
+	}
+	if ((change_settings || send_tur) && !quiet &&
+	    (ccb->cts.transport == XPORT_ATA ||
+	     ccb->cts.transport == XPORT_SATA || send_tur)) {
 		fprintf(stdout, "New parameters:\n");
 		retval = get_print_cts(device, user_settings, 0, NULL);
 	}
@@ -6122,7 +6276,8 @@
 			break;
 		case CAM_CMD_DOWNLOAD_FW:
 			error = fwdownload(cam_dev, argc, argv, combinedopt,
-			    arglist & CAM_ARG_VERBOSE, retry_count, timeout);
+			    arglist & CAM_ARG_VERBOSE, retry_count, timeout,
+			    get_disk_type(cam_dev));
 			break;
 #endif /* MINIMALISTIC */
 		case CAM_CMD_USAGE:
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/camcontrol.h
--- a/head/sbin/camcontrol/camcontrol.h	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/camcontrol/camcontrol.h	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/camcontrol/camcontrol.h 227961 2011-11-25 04:03:37Z emaste $
+ * $FreeBSD: head/sbin/camcontrol/camcontrol.h 237281 2012-06-20 00:17:29Z scottl $
  */
 
 #ifndef _CAMCONTROL_H
@@ -41,7 +41,8 @@
 };
 
 int fwdownload(struct cam_device *device, int argc, char **argv,
-	       char *combinedopt, int verbose, int retry_count, int timeout);
+	       char *combinedopt, int verbose, int retry_count, int timeout,
+	       const char */*type*/);
 void mode_sense(struct cam_device *device, int mode_page, int page_control,
 		int dbd, int retry_count, int timeout, u_int8_t *data,
 		int datalen);
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/fwdownload.c
--- a/head/sbin/camcontrol/fwdownload.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/camcontrol/fwdownload.c	Wed Jul 25 16:24:55 2012 +0300
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/camcontrol/fwdownload.c 228407 2011-12-11 11:38:50Z ed $");
+__FBSDID("$FreeBSD: head/sbin/camcontrol/fwdownload.c 237281 2012-06-20 00:17:29Z scottl $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -64,6 +64,8 @@
 #include <cam/scsi/scsi_message.h>
 #include <camlib.h>
 
+#include "progress.h"
+
 #include "camcontrol.h"
 
 #define	CMD_TIMEOUT 50000	/* 50 seconds */
@@ -73,6 +75,7 @@
 	VENDOR_HP,
 	VENDOR_IBM,
 	VENDOR_PLEXTOR,
+	VENDOR_QUALSTAR,
 	VENDOR_QUANTUM,
 	VENDOR_SEAGATE,
 	VENDOR_UNKNOWN
@@ -93,17 +96,43 @@
 	{VENDOR_HP,		"HP",		0x8000, 0x07, 0x07, 0, 1},
 	{VENDOR_IBM,		"IBM",		0x8000, 0x05, 0x05, 1, 0},
 	{VENDOR_PLEXTOR,	"PLEXTOR",	0x2000, 0x04, 0x05, 0, 1},
+	{VENDOR_QUALSTAR,	"QUALSTAR",	0x2030, 0x05, 0x05, 0, 0},
 	{VENDOR_QUANTUM,	"QUANTUM",	0x2000, 0x04, 0x05, 0, 1},
 	{VENDOR_SEAGATE,	"SEAGATE",	0x8000, 0x07, 0x07, 0, 1},
+	/* the next 2 are SATA disks going through SAS HBA */
+	{VENDOR_SEAGATE,	"ATA ST",	0x8000, 0x07, 0x07, 0, 1},
+	{VENDOR_HITACHI,	"ATA HDS",	0x8000, 0x05, 0x05, 1, 0},
 	{VENDOR_UNKNOWN,	NULL,		0x0000, 0x00, 0x00, 0, 0}
 };
 
+#ifndef ATA_DOWNLOAD_MICROCODE
+#define ATA_DOWNLOAD_MICROCODE	0x92
+#endif
+
+#define USE_OFFSETS_FEATURE	0x3
+
+#ifndef LOW_SECTOR_SIZE
+#define LOW_SECTOR_SIZE		512
+#endif
+
+#define ATA_MAKE_LBA(o, p)	\
+	((((((o) / LOW_SECTOR_SIZE) >> 8) & 0xff) << 16) | \
+	  ((((o) / LOW_SECTOR_SIZE) & 0xff) << 8) | \
+	  ((((p) / LOW_SECTOR_SIZE) >> 8) & 0xff))
+
+#define ATA_MAKE_SECTORS(p)	(((p) / 512) & 0xff)
+
+#ifndef UNKNOWN_MAX_PKT_SIZE
+#define UNKNOWN_MAX_PKT_SIZE	0x8000
+#endif
+
 static const struct fw_vendor *fw_get_vendor(struct cam_device *cam_dev);
 static char	*fw_read_img(const char *fw_img_path,
 		    const struct fw_vendor *vp, int *num_bytes);
 static int	 fw_download_img(struct cam_device *cam_dev,
 		    const struct fw_vendor *vp, char *buf, int img_size,
-		    int sim_mode, int verbose, int retry_count, int timeout);
+		    int sim_mode, int verbose, int retry_count, int timeout,
+		    const char */*name*/, const char */*type*/);
 
 /*
  * Find entry in vendors list that belongs to
@@ -173,6 +202,9 @@
 		    (img_size % 512 == 80))
 			skip_bytes = 80;
 		break;
+	case VENDOR_QUALSTAR:
+		skip_bytes = img_size % 1030;
+		break;
 	default:
 		break;
 	}
@@ -207,26 +239,57 @@
 static int
 fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp,
     char *buf, int img_size, int sim_mode, int verbose, int retry_count,
-    int timeout)
+    int timeout, const char *imgname, const char *type)
 {
 	struct scsi_write_buffer cdb;
+	progress_t progress;
+	int size;
 	union ccb *ccb;
 	int pkt_count = 0;
+	int max_pkt_size;
 	u_int32_t pkt_size = 0;
 	char *pkt_ptr = buf;
 	u_int32_t offset;
 	int last_pkt = 0;
+	int16_t *ptr;
 
 	if ((ccb = cam_getccb(cam_dev)) == NULL) {
 		warnx("Could not allocate CCB");
 		return (1);
 	}
-	scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
-	    SSD_FULL_SIZE, 5000);
+	if (strcmp(type, "scsi") == 0) {
+		scsi_test_unit_ready(&ccb->csio, 0, NULL, MSG_SIMPLE_Q_TAG,
+		    SSD_FULL_SIZE, 5000);
+	} else if (strcmp(type, "ata") == 0) {
+		/* 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));
+
+		ptr = (uint16_t *)malloc(sizeof(struct ata_params));
+
+		if (ptr == NULL) {
+			cam_freeccb(ccb);
+			warnx("can't malloc memory for identify\n");
+			return(1);
+		}
+		bzero(ptr, sizeof(struct ata_params));
+		cam_fill_ataio(&ccb->ataio,
+                      1,
+                      NULL,
+                      /*flags*/CAM_DIR_IN,
+                      MSG_SIMPLE_Q_TAG,
+                      /*data_ptr*/(uint8_t *)ptr,
+                      /*dxfer_len*/sizeof(struct ata_params),
+                      timeout ? timeout : 30 * 1000);
+		ata_28bit_cmd(&ccb->ataio, ATA_ATA_IDENTIFY, 0, 0, 0);
+	} else {
+		warnx("weird disk type '%s'", type);
+		return 1;
+	}
 	/* Disable freezing the device queue. */
 	ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
 	if (cam_send_ccb(cam_dev, ccb) < 0) {
-		warnx("Error sending test unit ready");
+		warnx("Error sending identify/test unit ready");
 		if (verbose)
 			cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
 			    CAM_EPF_ALL, stderr);
@@ -241,83 +304,102 @@
 		cam_freeccb(ccb);
 		return (1);
 	}
+	max_pkt_size = vp->max_pkt_size;
+	if (vp->max_pkt_size == 0 && strcmp(type, "ata") == 0) {
+		max_pkt_size = UNKNOWN_MAX_PKT_SIZE;
+	}
 	pkt_size = vp->max_pkt_size;
-	if (verbose || sim_mode) {
-		fprintf(stdout,
-		    "--------------------------------------------------\n");
-		fprintf(stdout,
-		    "PktNo.	PktSize	       BytesRemaining	LastPkt\n");
-		fprintf(stdout,
-		    "--------------------------------------------------\n");
-	}
+	progress_init(&progress, imgname, size = img_size);
 	/* Download single fw packets. */
 	do {
-		if (img_size <= vp->max_pkt_size) {
+		if (img_size <= max_pkt_size) {
 			last_pkt = 1;
 			pkt_size = img_size;
 		}
-		if (verbose || sim_mode)
-			fprintf(stdout, "%3u   %5u (0x%05X)   %7u (0x%06X)   "
-			    "%d\n", pkt_count, pkt_size, pkt_size,
-			    img_size - pkt_size, img_size - pkt_size,
-			    last_pkt);
+		progress_update(&progress, size - img_size);
+		progress_draw(&progress);
 		bzero(&cdb, sizeof(cdb));
-		cdb.opcode  = WRITE_BUFFER;
-		cdb.control = 0;
-		/* Parameter list length. */
-		scsi_ulto3b(pkt_size, &cdb.length[0]);
-		offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0;
-		scsi_ulto3b(offset, &cdb.offset[0]);
-		cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2;
-		cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0;
-		/* Zero out payload of ccb union after ccb header. */
-		bzero((u_char *)ccb + sizeof(struct ccb_hdr),
-		    sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
-		/* Copy previously constructed cdb into ccb_scsiio struct. */
-		bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0],
-		    sizeof(struct scsi_write_buffer));
-		/* Fill rest of ccb_scsiio struct. */
+		if (strcmp(type, "scsi") == 0) {
+			cdb.opcode  = WRITE_BUFFER;
+			cdb.control = 0;
+			/* Parameter list length. */
+			scsi_ulto3b(pkt_size, &cdb.length[0]);
+			offset = vp->inc_cdb_offset ? (pkt_ptr - buf) : 0;
+			scsi_ulto3b(offset, &cdb.offset[0]);
+			cdb.byte2 = last_pkt ? vp->cdb_byte2_last : vp->cdb_byte2;
+			cdb.buffer_id = vp->inc_cdb_buffer_id ? pkt_count : 0;
+			/* Zero out payload of ccb union after ccb header. */
+			bzero((u_char *)ccb + sizeof(struct ccb_hdr),
+			    sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+			/* Copy previously constructed cdb into ccb_scsiio struct. */
+			bcopy(&cdb, &ccb->csio.cdb_io.cdb_bytes[0],
+			    sizeof(struct scsi_write_buffer));
+			/* Fill rest of ccb_scsiio struct. */
+			if (!sim_mode) {
+				cam_fill_csio(&ccb->csio,		/* ccb_scsiio	*/
+				    retry_count,			/* retries	*/
+				    NULL,				/* cbfcnp	*/
+				    CAM_DIR_OUT | CAM_DEV_QFRZDIS,	/* flags	*/
+				    CAM_TAG_ACTION_NONE,		/* tag_action	*/
+				    (u_char *)pkt_ptr,			/* data_ptr	*/
+				    pkt_size,				/* dxfer_len	*/
+				    SSD_FULL_SIZE,			/* sense_len	*/
+				    sizeof(struct scsi_write_buffer),	/* cdb_len	*/
+				    timeout ? timeout : CMD_TIMEOUT);	/* timeout	*/
+			}
+		} else if (strcmp(type, "ata") == 0) {
+			bzero(&(&ccb->ccb_h)[1],
+			      sizeof(struct ccb_ataio) - sizeof(struct ccb_hdr));
+			if (!sim_mode) {
+				uint32_t	off;
+
+				cam_fill_ataio(&ccb->ataio,
+					(last_pkt) ? 256 : retry_count,
+					NULL,
+					/*flags*/CAM_DIR_OUT | CAM_DEV_QFRZDIS,
+					CAM_TAG_ACTION_NONE,
+					/*data_ptr*/(uint8_t *)pkt_ptr,
+					/*dxfer_len*/pkt_size,
+					timeout ? timeout : 30 * 1000);
+				off = (uint32_t)(pkt_ptr - buf);
+				ata_28bit_cmd(&ccb->ataio, ATA_DOWNLOAD_MICROCODE,
+					USE_OFFSETS_FEATURE,
+					ATA_MAKE_LBA(off, pkt_size),
+					ATA_MAKE_SECTORS(pkt_size));
+			}
+		}
 		if (!sim_mode) {
-			cam_fill_csio(&ccb->csio,		/* ccb_scsiio	*/
-			    retry_count,			/* retries	*/
-			    NULL,				/* cbfcnp	*/
-			    CAM_DIR_OUT | CAM_DEV_QFRZDIS,	/* flags	*/
-			    CAM_TAG_ACTION_NONE,		/* tag_action	*/
-			    (u_char *)pkt_ptr,			/* data_ptr	*/
-			    pkt_size,				/* dxfer_len	*/
-			    SSD_FULL_SIZE,			/* sense_len	*/
-			    sizeof(struct scsi_write_buffer),	/* cdb_len	*/
-			    timeout ? timeout : CMD_TIMEOUT);	/* timeout	*/
 			/* Execute the command. */
 			if (cam_send_ccb(cam_dev, ccb) < 0) {
 				warnx("Error writing image to device");
 				if (verbose)
 					cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
-					    CAM_EPF_ALL, stderr);
+						   CAM_EPF_ALL, stderr);
 				goto bailout;
 			}
+			if (ccb->ataio.res.status != 0 /*&& !last_pkt*/) {
+				cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
+					   CAM_EPF_ALL, stderr);
+			}
 		}
 		/* Prepare next round. */
 		pkt_count++;
 		pkt_ptr += pkt_size;
 		img_size -= pkt_size;
 	} while(!last_pkt);
-	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
-		if (verbose)
-			cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
-			    CAM_EPF_ALL, stderr);
-		goto bailout;
-	}
+	progress_complete(&progress, size - img_size);
 	cam_freeccb(ccb);
 	return (0);
 bailout:
+	progress_complete(&progress, size - img_size);
 	cam_freeccb(ccb);
 	return (1);
 }
 
 int
 fwdownload(struct cam_device *device, int argc, char **argv,
-    char *combinedopt, int verbose, int retry_count, int timeout)
+    char *combinedopt, int verbose, int retry_count, int timeout,
+    const char *type)
 {
 	const struct fw_vendor *vp;
 	char *fw_img_path = NULL;
@@ -345,12 +427,13 @@
 	}
 
 	if (fw_img_path == NULL)
-		errx(1,
-		    "you must specify a firmware image file using -f option");
+		errx(1, "you must specify a firmware image file using -f option");
 
 	vp = fw_get_vendor(device);
-	if (vp == NULL || vp->type == VENDOR_UNKNOWN)
-		errx(1, "Unsupported device");
+	if (vp == NULL)
+		errx(1, "NULL vendor");
+	if (vp->type == VENDOR_UNKNOWN)
+		warnx("Unsupported device - flashing through an HBA?");
 
 	buf = fw_read_img(fw_img_path, vp, &img_size);
 	if (buf == NULL)
@@ -360,11 +443,6 @@
 		fprintf(stdout, "You are about to download firmware image (%s)"
 		    " into the following device:\n",
 		    fw_img_path);
-		if (scsidoinquiry(device, argc, argv, combinedopt, 0,
-		    5000) != 0) {
-			warnx("Error sending inquiry");
-			goto fail;
-		}
 		fprintf(stdout, "\nIt may damage your drive. ");
 		if (!get_confirmation())
 			goto fail;
@@ -373,10 +451,11 @@
 		fprintf(stdout, "Running in simulation mode\n");
 
 	if (fw_download_img(device, vp, buf, img_size, sim_mode, verbose,
-	    retry_count, timeout) != 0) {
+	    retry_count, timeout, fw_img_path, type) != 0) {
 		fprintf(stderr, "Firmware download failed\n");
 		goto fail;
-	} else 
+	}
+	else 
 		fprintf(stdout, "Firmware download successful\n");
 
 	free(buf);
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/progress.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/camcontrol/progress.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,186 @@
+/*	$NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997-2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/camcontrol/progress.c 237285 2012-06-20 04:11:34Z scottl $");
+
+#include "progress.h"
+
+static const char * const suffixes[] = {
+	"",	/* 2^0  (byte) */
+	"KiB",	/* 2^10 Kibibyte */
+	"MiB",	/* 2^20 Mebibyte */
+	"GiB",	/* 2^30 Gibibyte */
+	"TiB",	/* 2^40 Tebibyte */
+	"PiB",	/* 2^50 Pebibyte */
+	"EiB",	/* 2^60 Exbibyte */
+};
+
+#define NSUFFIXES	(sizeof(suffixes) / sizeof(suffixes[0]))
+#define SECSPERHOUR	(60 * 60)
+#define DEFAULT_TTYWIDTH	80
+
+/* initialise progress meter structure */
+int
+progress_init(progress_t *prog, const char *prefix, uint64_t total)
+{
+        struct winsize	winsize;
+        int		oerrno = errno;
+
+	(void) memset(prog, 0x0, sizeof(*prog));
+	prog->size = total;
+	prog->prefix = strdup(prefix);
+	prog->start = time(NULL);
+        if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) != -1 &&
+            winsize.ws_col != 0) {
+                prog->ttywidth = winsize.ws_col;
+        } else {
+                prog->ttywidth = DEFAULT_TTYWIDTH;
+	}
+        errno = oerrno;
+	return 1;
+}
+
+/* update the values in the progress meter */
+int
+progress_update(progress_t *prog, uint64_t done)
+{
+	prog->done = done;
+	prog->percent = (prog->done * 100) / prog->size;
+	prog->now = time(NULL);
+	prog->elapsed = prog->now - prog->start;
+	if (done == 0 || prog->elapsed == 0 || prog->done / prog->elapsed == 0) {
+		prog->eta = 0;
+	} else {
+		prog->eta = prog->size / (prog->done / prog->elapsed) - prog->elapsed;
+	}
+	return 1;
+}
+
+/* update the values in the progress meter */
+int
+progress_reset_size(progress_t *prog, uint64_t size)
+{
+	prog->size = size;
+	return 1;
+}
+
+/* make it look pretty at the end - display done bytes (usually total) */
+int
+progress_complete(progress_t *prog, uint64_t done)
+{
+	progress_update(prog, done);
+	progress_draw(prog);
+	printf("\n");
+	return 1;
+}
+
+/* draw the progress meter */
+int
+progress_draw(progress_t *prog)
+{
+#define	BAROVERHEAD	45		/* non `*' portion of progress bar */
+					/*
+					 * stars should contain at least
+					 * sizeof(buf) - BAROVERHEAD entries
+					 */
+	static const char	stars[] =
+"*****************************************************************************"
+"*****************************************************************************"
+"*****************************************************************************";
+	unsigned		bytesabbrev;
+	unsigned		bpsabbrev;
+	int64_t			secs;
+	uint64_t		bytespersec;
+	uint64_t		abbrevsize;
+	int64_t			secsleft;
+	size_t			barlength;
+	size_t			starc;
+	char			hours[12];
+	char			buf[256];
+	int			len;
+
+	barlength = MIN(sizeof(buf) - 1, (unsigned)prog->ttywidth) - BAROVERHEAD - strlen(prog->prefix);
+	starc = (barlength * prog->percent) / 100;
+	abbrevsize = prog->done;
+	for (bytesabbrev = 0; abbrevsize >= 100000 && bytesabbrev < NSUFFIXES; bytesabbrev++) {
+		abbrevsize >>= 10;
+	}
+	if (bytesabbrev == NSUFFIXES) {
+		bytesabbrev--;
+	}
+	bytespersec = 0;
+	if (prog->done > 0) {
+		bytespersec = prog->done;
+		if (prog->elapsed > 0) {
+			bytespersec /= prog->elapsed;
+		}
+	}
+	for (bpsabbrev = 1; bytespersec >= 1024000 && bpsabbrev < NSUFFIXES; bpsabbrev++) {
+		bytespersec >>= 10;
+	}
+	if (prog->done == 0 || prog->elapsed <= 0 || prog->done > prog->size) {
+		secsleft = 0;
+	} else {
+		secsleft = prog->eta;
+	}
+	if ((secs = secsleft / SECSPERHOUR) > 0) {
+		(void) snprintf(hours, sizeof(hours), "%2lld:", (long long)secs);
+	} else {
+		(void) snprintf(hours, sizeof(hours), "   ");
+	}
+	secs = secsleft % SECSPERHOUR;
+	len = snprintf(buf, sizeof(buf),
+		"\r%s %3lld%% |%.*s%*s| %5lld %-3s %3lld.%02d %.2sB/s %s%02d:%02d ETA",
+		(prog->prefix) ? prog->prefix : "",
+		(long long)prog->percent,
+		(int)starc, stars, (int)(barlength - starc), "",
+		(long long)abbrevsize,
+		suffixes[bytesabbrev],
+		(long long)(bytespersec / 1024),
+		(int)((bytespersec % 1024) * 100 / 1024),
+		suffixes[bpsabbrev],
+		hours,
+		(int)secs / 60, (int)secs % 60);
+	return (int)write(STDOUT_FILENO, buf, len);
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/camcontrol/progress.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/camcontrol/progress.h	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,60 @@
+/*	$NetBSD: progressbar.c,v 1.21 2009/04/12 10:18:52 lukem Exp $	*/
+
+/*-
+ * Copyright (c) 1997-2012 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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: head/sbin/camcontrol/progress.h 237285 2012-06-20 04:11:34Z scottl $
+ */
+
+#ifndef PROGRESS_H_
+#define PROGRESS_H_	20100228
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+
+/* structure used to display a progress meter */
+typedef struct progress_t {
+	char		*prefix;	/* any prefix explanation */
+	uint64_t	 size;		/* total of bytes/units to be counted */
+	uint64_t	 done;		/* number of units counted to date */
+	uint64_t	 percent;	/* cache the percentage complete */
+	time_t		 start;		/* time we started this */
+	time_t		 now;		/* time now */
+	time_t		 eta;		/* estimated # of secs until completion */
+	int64_t		 elapsed;	/* cached # of elapsed seconds */
+	int32_t		 ttywidth;	/* width of tty in columns */
+} progress_t;
+
+int progress_init(progress_t */*meter*/, const char */*prefix*/, uint64_t /*size*/);
+int progress_update(progress_t */*meter*/, uint64_t /*done*/);
+int progress_draw(progress_t */*meter*/);
+int progress_reset_size(progress_t */*meter*/, uint64_t /*size*/);
+int progress_complete(progress_t */*meter*/, uint64_t /*done*/);
+
+#endif
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/devd/devd.cc
--- a/head/sbin/devd/devd.cc	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/devd/devd.cc	Wed Jul 25 16:24:55 2012 +0300
@@ -63,7 +63,7 @@
 //	  - devd.conf needs more details on the supported statements.
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 229702 2012-01-06 15:01:05Z glebius $");
+__FBSDID("$FreeBSD: head/sbin/devd/devd.cc 236388 2012-06-01 06:56:35Z dim $");
 
 #include <sys/param.h>
 #include <sys/socket.h>
@@ -807,7 +807,7 @@
 	unlink(name);
 	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
 	    	err(1, "fcntl");
-	if (bind(fd, (struct sockaddr *) & sun, slen) < 0)
+	if (::bind(fd, (struct sockaddr *) & sun, slen) < 0)
 		err(1, "bind");
 	listen(fd, 4);
 	chown(name, 0, 0);	/* XXX - root.wheel */
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/devd/parse.y
--- a/head/sbin/devd/parse.y	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/devd/parse.y	Wed Jul 25 16:24:55 2012 +0300
@@ -26,9 +26,10 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD$
+ * $FreeBSD: head/sbin/devd/parse.y 235789 2012-05-22 16:33:10Z bapt $
  */
 
+#include <sys/cdefs.h>
 #include "devd.h"
 #include <stdio.h>
 #include <string.h>
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/devfs/devfs.8
--- a/head/sbin/devfs/devfs.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/devfs/devfs.8	Wed Jul 25 16:24:55 2012 +0300
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/devfs/devfs.8 233648 2012-03-29 05:02:12Z eadler $
+.\" $FreeBSD: head/sbin/devfs/devfs.8 236780 2012-06-09 07:18:53Z joel $
 .\"
 .Dd February 21, 2010
 .Dt DEVFS 8
@@ -52,7 +52,7 @@
 .Cm rule
 keyword.
 The following flags are common to all keywords:
-.Bl -tag -offset indent
+.Bl -tag -width 15n
 .It Fl m Ar mount-point
 Operate on
 .Ar mount-point ,
@@ -88,7 +88,7 @@
 .Cm rule
 keyword.
 The following flags are common to all of the rule manipulation commands:
-.Bl -tag -offset indent
+.Bl -tag -width 15n
 .It Fl s Ar ruleset
 Operate on the ruleset with the number
 .Ar ruleset .
@@ -98,7 +98,7 @@
 .El
 .Pp
 The following commands are recognized:
-.Bl -tag -offset indent
+.Bl -tag -width 15n
 .It Cm rule add Oo Ar rulenum Oc Ar rulespec
 Add the rule described by
 .Ar rulespec
@@ -156,7 +156,7 @@
 The following conditions are recognized.
 Conditions are ANDed together when matching a device;
 if OR is desired, multiple rules can be written.
-.Bl -tag -offset indent
+.Bl -tag -width 15n
 .It Cm path Ar pattern
 Matches any node with a path that matches
 .Ar pattern ,
@@ -175,7 +175,7 @@
 The following actions are recognized.
 Although there is no explicit delimiter between conditions and actions,
 they may not be intermixed.
-.Bl -tag -offset indent
+.Bl -tag -width 15n
 .It Cm group Ar gid
 Set the GID of the node to
 .Ar gid ,
@@ -238,7 +238,7 @@
 The mount-point is only relevant when changing what its current ruleset is
 or when using one of the apply commands.
 .Sh FILES
-.Bl -tag -compact
+.Bl -tag -width "Pa /usr/share/examples/etc/devfs.conf" -compact
 .It Pa /etc/defaults/devfs.rules
 Default
 .Nm
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/dump/dump.8
--- a/head/sbin/dump/dump.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/dump/dump.8	Wed Jul 25 16:24:55 2012 +0300
@@ -27,7 +27,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)dump.8	8.3 (Berkeley) 5/1/95
-.\" $FreeBSD$
+.\" $FreeBSD: head/sbin/dump/dump.8 235837 2012-05-23 15:06:13Z joel $
 .\"
 .Dd February 24, 2006
 .Dt DUMP 8
@@ -51,16 +51,6 @@
 .Ar filesystem
 .Nm
 .Fl W | Fl w
-.Pp
-.Nm rdump
-is an alternate name for
-.Nm .
-.Pp
-.in \" XXX
-(The
-.Bx 4.3
-option syntax is implemented for backward compatibility, but
-is not documented here.)
 .Sh DESCRIPTION
 The
 .Nm
@@ -97,6 +87,14 @@
 (if that is in a standard entry in
 .Pa /etc/fstab ) .
 .Pp
+.Nm
+may also be invoked as
+.Nm rdump .
+The
+.Bx 4.3
+option syntax is implemented for backward compatibility, but
+is not documented here.
+.Pp
 The following options are supported by
 .Nm :
 .Bl -tag -width Ds
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/etherswitchcfg/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/etherswitchcfg/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,9 @@
+#	@(#)Makefile	5.4 (Berkeley) 6/5/91
+# $FreeBSD: head/sbin/etherswitchcfg/Makefile 235289 2012-05-11 20:56:04Z adrian $
+
+PROG=	etherswitchcfg
+MAN=	etherswitchcfg.8
+SRCS=	etherswitchcfg.c ifmedia.c
+CFLAGS+= -I${.CURDIR}/../../sys
+
+.include <bsd.prog.mk>
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/etherswitchcfg/etherswitchcfg.8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/etherswitchcfg/etherswitchcfg.8	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,115 @@
+.\" $FreeBSD: head/sbin/etherswitchcfg/etherswitchcfg.8 235873 2012-05-24 02:24:03Z wblock $
+.Dd December 15, 2011
+.Dt ETHERSWITCHCFG 8
+.Os
+.Sh NAME
+.Nm etherswitchcfg
+.Nd configure a built-in Ethernet switch
+.Sh SYNOPSIS
+.Nm
+.Op Fl "f control file"
+.Ar info
+.Nm
+.Op Fl "f control file"
+.Ar phy
+.Ar phy.register[=value]
+.Nm
+.Op Fl "f control file"
+.Ar port%d
+.Ar command parameter
+.Nm
+.Op Fl "f control file"
+.Ar reg
+.Ar register[=value]
+.Nm
+.Op Fl "f control file"
+.Ar vlangroup%d
+.Ar command parameter
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to configure an Ethernet switch built into the system.
+.Nm
+accepts a number of options:
+.Bl -tag -width ".Fl f" -compact
+.It Fl "f control file"
+Specifies the
+.Xr etherswitch 4
+control file that represents the switch to be configured.
+It defaults to
+.Li /dev/etherswitch0 .
+.It Fl m
+When reporting port information, also list available media options for
+that port.
+.It Fl v
+Produce more verbose output.
+Without this flag, lines that represent inactive or empty configuration
+options are omitted.
+.El
+.Ss phy
+The phy command provides access to the registers of the PHYs attached
+to or integrated into the switch controller.
+PHY registers are specified as phy.register,
+where
+.Ar phy
+is usually the port number, and
+.Ar register
+is the register number.
+Both can be provided as decimal, octal or hexadecimal numbers in any of the formats
+understood by
+.Xr strtol 4 .
+To set the register value, use the form instance.register=value.
+.Ss port
+The port command selects one of the ports of the switch.
+It supports the following commands:
+.Bl -tag -width ".Ar vlangroup number" -compact
+.It Ar vlangroup number
+Sets the VLAN group number that is used to process incoming frames that are not tagged.
+.It Ar media mediaspec
+Specifies the physical media configuration to be configured for a port.
+.It Ar mediaopt mediaoption
+Specifies a list of media options for a port. See
+.Xr ifconfig 8
+for details on
+.Ar media
+and
+.Ar mediaopt .
+.El
+.Ss reg
+The reg command provides access to the registers of the switch controller.
+.Ss vlangroup
+The vlangroup command selects one of the VLAN groups for configuration.
+It supports the following commands:
+.Bl -tag -width ".Ar vlangroup" -compact
+.It Ar vlan VID
+Sets the VLAN ID (802.1q VID) for this VLAN group.
+Frames transmitted on tagged member ports of this group will be tagged
+with this VID.
+Incoming frames carrying this tag will be forwarded according to the
+configuration of this VLAN group.
+.It Ar members port,...
+Configures which ports are to be a member of this VLAN group.
+The port numbers are given as a comma-separated list.
+Each port can optionally be followed by
+.Dq t
+to indicate that frames on this port are tagged.
+.El
+.Sh FILES
+.Bl -tag -width /dev/etherswitch? -compact
+.It Pa /dev/etherswitch?
+Control file for the ethernet switch driver.
+.El
+.Sh EXAMPLES
+Configure VLAN group 1 with a VID of 2 and makes ports 0 and 5 members,
+while excluding all other ports.
+Port 5 will send and receive tagged frames, while port 0 will be untagged.
+Incoming untagged frames on port 0 are assigned to vlangroup1.
+.Dl # etherswitchcfg vlangroup1 vlan 2 members 0,5t port0 vlangroup 1
+.Sh SEE ALSO
+.Xr etherswitch 4
+.Sh HISTORY
+.Nm
+first appeared in
+.Fx 10.0 .
+.Sh AUTHORS
+.An Stefan Bethke
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/etherswitchcfg/etherswitchcfg.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/etherswitchcfg/etherswitchcfg.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,511 @@
+/*-
+ * Copyright (c) 2011-2012 Stefan Bethke.
+ * 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: head/sbin/etherswitchcfg/etherswitchcfg.c 235289 2012-05-11 20:56:04Z adrian $
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/etherswitchcfg/etherswitchcfg.c 235289 2012-05-11 20:56:04Z adrian $");
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <net/if_media.h>
+#include <dev/etherswitch/etherswitch.h>
+
+int	get_media_subtype(int, const char *);
+int	get_media_mode(int, const char *);
+int	get_media_options(int, const char *);
+int	lookup_media_word(struct ifmedia_description *, const char *);
+void    print_media_word(int, int);
+void    print_media_word_ifconfig(int);
+
+/* some constants */
+#define IEEE802DOT1Q_VID_MAX	4094
+#define IFMEDIAREQ_NULISTENTRIES	256
+
+enum cmdmode {
+	MODE_NONE = 0,
+	MODE_PORT,
+	MODE_VLANGROUP,
+	MODE_REGISTER,
+	MODE_PHYREG
+};
+
+struct cfg {
+	int					fd;
+	int					verbose;
+	int					mediatypes;
+	const char			*controlfile;
+	etherswitch_info_t	info;
+	enum cmdmode		mode;
+	int					unit;
+};
+
+struct cmds {
+	enum cmdmode	mode;
+	const char		*name;
+	int				args;
+	void 			(*f)(struct cfg *, char *argv[]);
+};
+struct cmds cmds[];
+
+
+static void usage(void);
+
+static int
+read_register(struct cfg *cfg, int r)
+{
+	struct etherswitch_reg er;
+	
+	er.reg = r;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETREG, &er) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETREG)");
+	return (er.val);
+}
+
+static void
+write_register(struct cfg *cfg, int r, int v)
+{
+	struct etherswitch_reg er;
+	
+	er.reg = r;
+	er.val = v;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETREG, &er) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETREG)");
+}
+
+static int
+read_phyregister(struct cfg *cfg, int phy, int reg)
+{
+	struct etherswitch_phyreg er;
+	
+	er.phy = phy;
+	er.reg = reg;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETPHYREG, &er) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETPHYREG)");
+	return (er.val);
+}
+
+static void
+write_phyregister(struct cfg *cfg, int phy, int reg, int val)
+{
+	struct etherswitch_phyreg er;
+	
+	er.phy = phy;
+	er.reg = reg;
+	er.val = val;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETPHYREG, &er) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETPHYREG)");
+}
+
+static void
+set_port_vlangroup(struct cfg *cfg, char *argv[])
+{
+	int v;
+	etherswitch_port_t p;
+	
+	v = strtol(argv[1], NULL, 0);
+	if (v < 0 || v >= cfg->info.es_nvlangroups)
+		errx(EX_USAGE, "vlangroup must be between 0 and %d", cfg->info.es_nvlangroups-1);
+	p.es_port = cfg->unit;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
+	p.es_vlangroup = v;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
+}
+
+static void
+set_port_media(struct cfg *cfg, char *argv[])
+{
+	etherswitch_port_t p;
+	int ifm_ulist[IFMEDIAREQ_NULISTENTRIES];
+	int subtype;
+	
+	bzero(&p, sizeof(p));
+	p.es_port = cfg->unit;
+	p.es_ifmr.ifm_ulist = ifm_ulist;
+	p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
+	subtype = get_media_subtype(IFM_TYPE(ifm_ulist[0]), argv[1]);
+	p.es_ifr.ifr_media = (p.es_ifmr.ifm_current & IFM_IMASK) |
+	        IFM_TYPE(ifm_ulist[0]) | subtype;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
+}
+
+static void
+set_port_mediaopt(struct cfg *cfg, char *argv[])
+{
+	etherswitch_port_t p;
+	int ifm_ulist[IFMEDIAREQ_NULISTENTRIES];
+	int options;
+	
+	bzero(&p, sizeof(p));
+	p.es_port = cfg->unit;
+	p.es_ifmr.ifm_ulist = ifm_ulist;
+	p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
+	options = get_media_options(IFM_TYPE(ifm_ulist[0]), argv[1]);
+	if (options == -1)
+		errx(EX_USAGE, "invalid media options \"%s\"", argv[1]);
+	if (options & IFM_HDX) {
+		p.es_ifr.ifr_media &= ~IFM_FDX;
+		options &= ~IFM_HDX;
+	}
+	p.es_ifr.ifr_media |= options;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
+}
+
+static void
+set_vlangroup_vid(struct cfg *cfg, char *argv[])
+{
+	int v;
+	etherswitch_vlangroup_t vg;
+	
+	v = strtol(argv[1], NULL, 0);
+	if (v < 0 || v >= IEEE802DOT1Q_VID_MAX)
+		errx(EX_USAGE, "vlan must be between 0 and %d", IEEE802DOT1Q_VID_MAX);
+	vg.es_vlangroup = cfg->unit;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)");
+	vg.es_vid = v;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)");
+}
+
+static void
+set_vlangroup_members(struct cfg *cfg, char *argv[])
+{
+	etherswitch_vlangroup_t vg;
+	int member, untagged;
+	char *c, *d;
+	int v;
+	
+	member = untagged = 0;
+	if (strcmp(argv[1], "none") != 0) {
+		for (c=argv[1]; *c; c=d) {
+			v = strtol(c, &d, 0);
+			if (d == c)
+				break;
+			if (v < 0 || v >= cfg->info.es_nports)
+				errx(EX_USAGE, "Member port must be between 0 and %d", cfg->info.es_nports-1);
+			if (d[0] == ',' || d[0] == '\0' ||
+				((d[0] == 't' || d[0] == 'T') && (d[1] == ',' || d[1] == '\0'))) {
+				if (d[0] == 't' || d[0] == 'T') {
+					untagged &= ~ETHERSWITCH_PORTMASK(v);
+					d++;
+				} else
+					untagged |= ETHERSWITCH_PORTMASK(v);
+				member |= ETHERSWITCH_PORTMASK(v);
+				d++;
+			} else
+				errx(EX_USAGE, "Invalid members specification \"%s\"", d);
+		}
+	}
+	vg.es_vlangroup = cfg->unit;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)");
+	vg.es_member_ports = member;
+	vg.es_untagged_ports = untagged;
+	if (ioctl(cfg->fd, IOETHERSWITCHSETVLANGROUP, &vg) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHSETVLANGROUP)");
+}
+
+static int
+set_register(struct cfg *cfg, char *arg)
+{
+	int a, v;
+	char *c;
+	
+	a = strtol(arg, &c, 0);
+	if (c==arg)
+		return (1);
+	if (*c == '=') {
+		v = strtol(c+1, NULL, 0);
+		write_register(cfg, a, v);
+	}
+	printf("\treg 0x%04x=0x%04x\n", a, read_register(cfg, a));
+	return (0);
+}
+
+static int
+set_phyregister(struct cfg *cfg, char *arg)
+{
+	int phy, reg, val;
+	char *c, *d;
+	
+	phy = strtol(arg, &c, 0);
+	if (c==arg)
+		return (1);
+	if (*c != '.')
+		return (1);
+	d = c+1;
+	reg = strtol(d, &c, 0);
+	if (d == c)
+		return (1);
+	if (*c == '=') {
+		val = strtol(c+1, NULL, 0);
+		write_phyregister(cfg, phy, reg, val);
+	}
+	printf("\treg %d.0x%02x=0x%04x\n", phy, reg, read_phyregister(cfg, phy, reg));
+	return (0);
+}
+
+static void
+print_port(struct cfg *cfg, int port)
+{
+	etherswitch_port_t p;
+	int ifm_ulist[IFMEDIAREQ_NULISTENTRIES];
+	int i;
+
+	bzero(&p, sizeof(p));
+	p.es_port = port;
+	p.es_ifmr.ifm_ulist = ifm_ulist;
+	p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
+	printf("port%d:\n", port);
+	printf("\tvlangroup: %d\n", p.es_vlangroup);
+	printf("\tmedia: ");
+	print_media_word(p.es_ifmr.ifm_current, 1);
+	if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) {
+		putchar(' ');
+		putchar('(');
+		print_media_word(p.es_ifmr.ifm_active, 0);
+		putchar(')');
+	}
+	putchar('\n');
+	printf("\tstatus: %s\n", (p.es_ifmr.ifm_status & IFM_ACTIVE) != 0 ? "active" : "no carrier");
+	if (cfg->mediatypes) {
+		printf("\tsupported media:\n");
+		if (p.es_ifmr.ifm_count > IFMEDIAREQ_NULISTENTRIES)
+			p.es_ifmr.ifm_count = IFMEDIAREQ_NULISTENTRIES;
+		for (i=0; i<p.es_ifmr.ifm_count; i++) {
+			printf("\t\tmedia ");
+			print_media_word(ifm_ulist[i], 0);
+			putchar('\n');
+		}
+	}
+}
+
+static void
+print_vlangroup(struct cfg *cfg, int vlangroup)
+{
+	etherswitch_vlangroup_t vg;
+	int i, comma;
+	
+	vg.es_vlangroup = vlangroup;
+	if (ioctl(cfg->fd, IOETHERSWITCHGETVLANGROUP, &vg) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETVLANGROUP)");
+	if (cfg->verbose == 0 && vg.es_member_ports == 0)
+		return;
+	printf("vlangroup%d:\n", vlangroup);
+	printf("\tvlan: %d\n", vg.es_vid);
+	printf("\tmembers ");
+	comma = 0;
+	if (vg.es_member_ports != 0)
+		for (i=0; i<cfg->info.es_nports; i++) {
+			if ((vg.es_member_ports & ETHERSWITCH_PORTMASK(i)) != 0) {
+				if (comma)
+					printf(",");
+				printf("%d", i);
+				if ((vg.es_untagged_ports & ETHERSWITCH_PORTMASK(i)) == 0)
+					printf("t");
+				comma = 1;
+			}
+		}
+	else
+		printf("none");
+	printf("\n");
+}
+
+static void
+print_info(struct cfg *cfg)
+{
+	const char *c;
+	int i;
+	
+	c = strrchr(cfg->controlfile, '/');
+	if (c != NULL)
+		c = c + 1;
+	else
+		c = cfg->controlfile;
+	if (cfg->verbose)
+		printf("%s: %s with %d ports and %d VLAN groups\n",
+			c, cfg->info.es_name, cfg->info.es_nports, cfg->info.es_nvlangroups);
+	for (i=0; i<cfg->info.es_nports; i++) {
+		print_port(cfg, i);
+	}
+	for (i=0; i<cfg->info.es_nvlangroups; i++) {
+		print_vlangroup(cfg, i);
+	}
+}
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: etherswitchctl\n");
+	exit(EX_USAGE);
+}
+
+static void
+newmode(struct cfg *cfg, enum cmdmode mode)
+{
+	if (mode == cfg->mode)
+		return;
+	switch (cfg->mode) {
+	case MODE_NONE:
+		break;
+	case MODE_PORT:
+		print_port(cfg, cfg->unit);
+		break;
+	case MODE_VLANGROUP:
+		print_vlangroup(cfg, cfg->unit);
+		break;
+	case MODE_REGISTER:
+	case MODE_PHYREG:
+		break;
+	}
+	cfg->mode = mode;
+}
+
+int
+main(int argc, char *argv[])
+{
+	int ch;
+	struct cfg cfg;
+	int i;
+	
+	bzero(&cfg, sizeof(cfg));
+	cfg.controlfile = "/dev/etherswitch0";
+	while ((ch = getopt(argc, argv, "f:mv?")) != -1)
+		switch(ch) {
+		case 'f':
+			cfg.controlfile = optarg;
+			break;
+		case 'm':
+			cfg.mediatypes++;
+			break;
+		case 'v':
+			cfg.verbose++;
+			break;
+		case '?':
+			/* FALLTHROUGH */
+		default:
+			usage();
+		}
+	argc -= optind;
+	argv += optind;
+	cfg.fd = open(cfg.controlfile, O_RDONLY);
+	if (cfg.fd < 0)
+		err(EX_UNAVAILABLE, "Can't open control file: %s", cfg.controlfile);
+	if (ioctl(cfg.fd, IOETHERSWITCHGETINFO, &cfg.info) != 0)
+		err(EX_OSERR, "ioctl(IOETHERSWITCHGETINFO)");
+	if (argc == 0) {
+		print_info(&cfg);
+		return (0);
+	}
+	cfg.mode = MODE_NONE;
+	while (argc > 0) {
+		switch(cfg.mode) {
+		case MODE_NONE:
+			if (strcmp(argv[0], "info") == 0) {
+				print_info(&cfg);
+			} else if (sscanf(argv[0], "port%d", &cfg.unit) == 1) {
+				if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nports)
+					errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nports);
+				newmode(&cfg, MODE_PORT);
+			} else if (sscanf(argv[0], "vlangroup%d", &cfg.unit) == 1) {
+				if (cfg.unit < 0 || cfg.unit >= cfg.info.es_nvlangroups)
+					errx(EX_USAGE, "port unit must be between 0 and %d", cfg.info.es_nvlangroups);
+				newmode(&cfg, MODE_VLANGROUP);
+			} else if (strcmp(argv[0], "phy") == 0) {
+				newmode(&cfg, MODE_PHYREG);
+			} else if (strcmp(argv[0], "reg") == 0) {
+				newmode(&cfg, MODE_REGISTER);
+			} else {
+				errx(EX_USAGE, "Unknown command \"%s\"", argv[0]);
+			}
+			break;
+		case MODE_PORT:
+		case MODE_VLANGROUP:
+			for(i=0; cmds[i].name != NULL; i++) {
+				if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0
+					&& argc >= cmds[i].args) {
+					(cmds[i].f)(&cfg, argv);
+					argc -= cmds[i].args;
+					argv += cmds[i].args;
+					break;
+				}
+			}
+			if (cmds[i].name == NULL) {
+				newmode(&cfg, MODE_NONE);
+				continue;
+			}
+			break;
+		case MODE_REGISTER:
+			if (set_register(&cfg, argv[0]) != 0) {
+				newmode(&cfg, MODE_NONE);
+				continue;
+			}
+			break;
+		case MODE_PHYREG:
+			if (set_phyregister(&cfg, argv[0]) != 0) {
+				newmode(&cfg, MODE_NONE);
+				continue;
+			}
+			break;
+		}
+		argc--;
+		argv++;
+	}
+	/* switch back to command mode to print configuration for last command */
+	newmode(&cfg, MODE_NONE);
+	close(cfg.fd);
+	return (0);
+}
+
+struct cmds cmds[] = {
+	{ MODE_PORT, "vlangroup", 1, set_port_vlangroup },
+	{ MODE_PORT, "media", 1, set_port_media },
+	{ MODE_PORT, "mediaopt", 1, set_port_mediaopt },
+	{ MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid },
+	{ MODE_VLANGROUP, "members", 1, set_vlangroup_members },
+	{ 0, NULL, 0, NULL }
+};
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/etherswitchcfg/ifmedia.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/etherswitchcfg/ifmedia.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,812 @@
+/*	$NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $	*/
+/* $FreeBSD: head/sbin/etherswitchcfg/ifmedia.c 235289 2012-05-11 20:56:04Z adrian $ */
+
+/*
+ * Copyright (c) 1997 Jason R. Thorpe.
+ * 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 for the NetBSD Project
+ *	by Jason R. Thorpe.
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ */
+/*
+ * based on sbin/ifconfig/ifmedia.c r221954
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/time.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/if_media.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+void	domediaopt(const char *, int, int);
+int	get_media_subtype(int, const char *);
+int	get_media_mode(int, const char *);
+int	get_media_options(int, const char *);
+int	lookup_media_word(struct ifmedia_description *, const char *);
+void	print_media_word(int, int);
+void	print_media_word_ifconfig(int);
+
+#if 0
+static struct ifmedia_description *get_toptype_desc(int);
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int);
+static struct ifmedia_description *get_subtype_desc(int,
+    struct ifmedia_type_to_subtype *ttos);
+
+#define	IFM_OPMODE(x) \
+	((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \
+	 IFM_IEEE80211_IBSS | IFM_IEEE80211_WDS | IFM_IEEE80211_MONITOR | \
+	 IFM_IEEE80211_MBSS))
+#define	IFM_IEEE80211_STA	0
+
+static void
+media_status(int s)
+{
+	struct ifmediareq ifmr;
+	int *media_list, i;
+
+	(void) memset(&ifmr, 0, sizeof(ifmr));
+	(void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name));
+
+	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) {
+		/*
+		 * Interface doesn't support SIOC{G,S}IFMEDIA.
+		 */
+		return;
+	}
+
+	if (ifmr.ifm_count == 0) {
+		warnx("%s: no media types?", name);
+		return;
+	}
+
+	media_list = (int *)malloc(ifmr.ifm_count * sizeof(int));
+	if (media_list == NULL)
+		err(1, "malloc");
+	ifmr.ifm_ulist = media_list;
+
+	if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
+		err(1, "SIOCGIFMEDIA");
+
+	printf("\tmedia: ");
+	print_media_word(ifmr.ifm_current, 1);
+	if (ifmr.ifm_active != ifmr.ifm_current) {
+		putchar(' ');
+		putchar('(');
+		print_media_word(ifmr.ifm_active, 0);
+		putchar(')');
+	}
+
+	putchar('\n');
+
+	if (ifmr.ifm_status & IFM_AVALID) {
+		printf("\tstatus: ");
+		switch (IFM_TYPE(ifmr.ifm_active)) {
+		case IFM_ETHER:
+		case IFM_ATM:
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				printf("active");
+			else
+				printf("no carrier");
+			break;
+
+		case IFM_FDDI:
+		case IFM_TOKEN:
+			if (ifmr.ifm_status & IFM_ACTIVE)
+				printf("inserted");
+			else
+				printf("no ring");
+			break;
+
+		case IFM_IEEE80211:
+			if (ifmr.ifm_status & IFM_ACTIVE) {
+				/* NB: only sta mode associates */
+				if (IFM_OPMODE(ifmr.ifm_active) == IFM_IEEE80211_STA)
+					printf("associated");
+				else
+					printf("running");
+			} else
+				printf("no carrier");
+			break;
+		}
+		putchar('\n');
+	}
+
+	if (ifmr.ifm_count > 0 && supmedia) {
+		printf("\tsupported media:\n");
+		for (i = 0; i < ifmr.ifm_count; i++) {
+			printf("\t\t");
+			print_media_word_ifconfig(media_list[i]);
+			putchar('\n');
+		}
+	}
+
+	free(media_list);
+}
+
+struct ifmediareq *
+ifmedia_getstate(int s)
+{
+	static struct ifmediareq *ifmr = NULL;
+	int *mwords;
+
+	if (ifmr == NULL) {
+		ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq));
+		if (ifmr == NULL)
+			err(1, "malloc");
+
+		(void) memset(ifmr, 0, sizeof(struct ifmediareq));
+		(void) strncpy(ifmr->ifm_name, name,
+		    sizeof(ifmr->ifm_name));
+
+		ifmr->ifm_count = 0;
+		ifmr->ifm_ulist = NULL;
+
+		/*
+		 * We must go through the motions of reading all
+		 * supported media because we need to know both
+		 * the current media type and the top-level type.
+		 */
+
+		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) {
+			err(1, "SIOCGIFMEDIA");
+		}
+
+		if (ifmr->ifm_count == 0)
+			errx(1, "%s: no media types?", name);
+
+		mwords = (int *)malloc(ifmr->ifm_count * sizeof(int));
+		if (mwords == NULL)
+			err(1, "malloc");
+  
+		ifmr->ifm_ulist = mwords;
+		if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0)
+			err(1, "SIOCGIFMEDIA");
+	}
+
+	return ifmr;
+}
+
+static void
+setifmediacallback(int s, void *arg)
+{
+	struct ifmediareq *ifmr = (struct ifmediareq *)arg;
+	static int did_it = 0;
+
+	if (!did_it) {
+		ifr.ifr_media = ifmr->ifm_current;
+		if (ioctl(s, SIOCSIFMEDIA, (caddr_t)&ifr) < 0)
+			err(1, "SIOCSIFMEDIA (media)");
+		free(ifmr->ifm_ulist);
+		free(ifmr);
+		did_it = 1;
+	}
+}
+
+static void
+setmedia(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int subtype;
+
+	ifmr = ifmedia_getstate(s);
+
+	/*
+	 * We are primarily concerned with the top-level type.
+	 * However, "current" may be only IFM_NONE, so we just look
+	 * for the top-level type in the first "supported type"
+	 * entry.
+	 *
+	 * (I'm assuming that all supported media types for a given
+	 * interface will be the same top-level type..)
+	 */
+	subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) |
+	    IFM_TYPE(ifmr->ifm_ulist[0]) | subtype;
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	domediaopt(val, 0, s);
+}
+
+static void
+unsetmediaopt(const char *val, int d, int s, const struct afswtch *afp)
+{
+
+	domediaopt(val, 1, s);
+}
+
+static void
+domediaopt(const char *val, int clear, int s)
+{
+	struct ifmediareq *ifmr;
+	int options;
+
+	ifmr = ifmedia_getstate(s);
+
+	options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = ifmr->ifm_current;
+	if (clear)
+		ifr.ifr_media &= ~options;
+	else {
+		if (options & IFM_HDX) {
+			ifr.ifr_media &= ~IFM_FDX;
+			options &= ~IFM_HDX;
+		}
+		ifr.ifr_media |= options;
+	}
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediainst(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int inst;
+
+	ifmr = ifmedia_getstate(s);
+
+	inst = atoi(val);
+	if (inst < 0 || inst > (int)IFM_INST_MAX)
+		errx(1, "invalid media instance: %s", val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT;
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+
+static void
+setmediamode(const char *val, int d, int s, const struct afswtch *afp)
+{
+	struct ifmediareq *ifmr;
+	int mode;
+
+	ifmr = ifmedia_getstate(s);
+
+	mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val);
+
+	strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+	ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode;
+
+	ifmr->ifm_current = ifr.ifr_media;
+	callback_register(setifmediacallback, (void *)ifmr);
+}
+#endif
+
+/**********************************************************************
+ * A good chunk of this is duplicated from sys/net/ifmedia.c
+ **********************************************************************/
+
+static struct ifmedia_description ifm_type_descriptions[] =
+    IFM_TYPE_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_descriptions[] =
+    IFM_SUBTYPE_ETHERNET_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ethernet_aliases[] =
+    IFM_SUBTYPE_ETHERNET_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] =
+    IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_descriptions[] =
+    IFM_SUBTYPE_TOKENRING_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_tokenring_aliases[] =
+    IFM_SUBTYPE_TOKENRING_ALIASES;
+
+static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] =
+    IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_descriptions[] =
+    IFM_SUBTYPE_FDDI_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_fddi_aliases[] =
+    IFM_SUBTYPE_FDDI_ALIASES;
+
+static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] =
+    IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_ieee80211_aliases[] =
+    IFM_SUBTYPE_IEEE80211_ALIASES;
+
+static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] =
+    IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS;
+
+struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] =
+    IFM_SUBTYPE_IEEE80211_MODE_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_descriptions[] =
+    IFM_SUBTYPE_ATM_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_atm_aliases[] =
+    IFM_SUBTYPE_ATM_ALIASES;
+
+static struct ifmedia_description ifm_subtype_atm_option_descriptions[] =
+    IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_shared_descriptions[] =
+    IFM_SUBTYPE_SHARED_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_subtype_shared_aliases[] =
+    IFM_SUBTYPE_SHARED_ALIASES;
+
+static struct ifmedia_description ifm_shared_option_descriptions[] =
+    IFM_SHARED_OPTION_DESCRIPTIONS;
+
+static struct ifmedia_description ifm_shared_option_aliases[] =
+    IFM_SHARED_OPTION_ALIASES;
+
+struct ifmedia_type_to_subtype {
+	struct {
+		struct ifmedia_description *desc;
+		int alias;
+	} subtypes[5];
+	struct {
+		struct ifmedia_description *desc;
+		int alias;
+	} options[4];
+	struct {
+		struct ifmedia_description *desc;
+		int alias;
+	} modes[3];
+};
+
+/* must be in the same order as IFM_TYPE_DESCRIPTIONS */
+static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = {
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_ethernet_descriptions[0], 0 },
+			{ &ifm_subtype_ethernet_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_shared_option_aliases[0], 1 },
+			{ &ifm_subtype_ethernet_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_tokenring_descriptions[0], 0 },
+			{ &ifm_subtype_tokenring_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_shared_option_aliases[0], 1 },
+			{ &ifm_subtype_tokenring_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_fddi_descriptions[0], 0 },
+			{ &ifm_subtype_fddi_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_shared_option_aliases[0], 1 },
+			{ &ifm_subtype_fddi_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_ieee80211_descriptions[0], 0 },
+			{ &ifm_subtype_ieee80211_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_shared_option_aliases[0], 1 },
+			{ &ifm_subtype_ieee80211_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_subtype_ieee80211_mode_descriptions[0], 0 },
+			{ &ifm_subtype_ieee80211_mode_aliases[0], 0 },
+			{ NULL, 0 },
+		},
+	},
+	{
+		{
+			{ &ifm_subtype_shared_descriptions[0], 0 },
+			{ &ifm_subtype_shared_aliases[0], 1 },
+			{ &ifm_subtype_atm_descriptions[0], 0 },
+			{ &ifm_subtype_atm_aliases[0], 1 },
+			{ NULL, 0 },
+		},
+		{
+			{ &ifm_shared_option_descriptions[0], 0 },
+			{ &ifm_shared_option_aliases[0], 1 },
+			{ &ifm_subtype_atm_option_descriptions[0], 0 },
+			{ NULL, 0 },
+		},
+		{
+			{ NULL, 0 },
+		},
+	},
+};
+
+int
+get_media_subtype(int type, const char *val)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int rval, i;
+
+	/* Find the top-level interface type. */
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (type == desc->ifmt_word)
+			break;
+	if (desc->ifmt_string == NULL)
+		errx(1, "unknown media type 0x%x", type);
+
+	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+		rval = lookup_media_word(ttos->subtypes[i].desc, val);
+		if (rval != -1)
+			return (rval);
+	}
+	errx(1, "unknown media subtype: %s", val);
+	/*NOTREACHED*/
+}
+
+int
+get_media_mode(int type, const char *val)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int rval, i;
+
+	/* Find the top-level interface type. */
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (type == desc->ifmt_word)
+			break;
+	if (desc->ifmt_string == NULL)
+		errx(1, "unknown media mode 0x%x", type);
+
+	for (i = 0; ttos->modes[i].desc != NULL; i++) {
+		rval = lookup_media_word(ttos->modes[i].desc, val);
+		if (rval != -1)
+			return (rval);
+	}
+	return -1;
+}
+
+int
+get_media_options(int type, const char *val)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	char *optlist, *optptr;
+	int option = 0, i, rval = 0;
+
+	/* We muck with the string, so copy it. */
+	optlist = strdup(val);
+	if (optlist == NULL)
+		err(1, "strdup");
+
+	/* Find the top-level interface type. */
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (type == desc->ifmt_word)
+			break;
+	if (desc->ifmt_string == NULL)
+		errx(1, "unknown media type 0x%x", type);
+
+	/*
+	 * Look up the options in the user-provided comma-separated
+	 * list.
+	 */
+	optptr = optlist;
+	for (; (optptr = strtok(optptr, ",")) != NULL; optptr = NULL) {
+		for (i = 0; ttos->options[i].desc != NULL; i++) {
+			option = lookup_media_word(ttos->options[i].desc, optptr);
+			if (option != -1)
+				break;
+		}
+		if (option == 0)
+			errx(1, "unknown option: %s", optptr);
+		rval |= option;
+	}
+
+	free(optlist);
+	return (rval);
+}
+
+int
+lookup_media_word(struct ifmedia_description *desc, const char *val)
+{
+
+	for (; desc->ifmt_string != NULL; desc++)
+		if (strcasecmp(desc->ifmt_string, val) == 0)
+			return (desc->ifmt_word);
+
+	return (-1);
+}
+
+static struct ifmedia_description *get_toptype_desc(int ifmw)
+{
+	struct ifmedia_description *desc;
+
+	for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++)
+		if (IFM_TYPE(ifmw) == desc->ifmt_word)
+			break;
+
+	return desc;
+}
+
+static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+
+	for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes;
+	    desc->ifmt_string != NULL; desc++, ttos++)
+		if (IFM_TYPE(ifmw) == desc->ifmt_word)
+			break;
+
+	return ttos;
+}
+
+static struct ifmedia_description *get_subtype_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
+{
+	int i;
+	struct ifmedia_description *desc;
+
+	for (i = 0; ttos->subtypes[i].desc != NULL; i++) {
+		if (ttos->subtypes[i].alias)
+			continue;
+		for (desc = ttos->subtypes[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (IFM_SUBTYPE(ifmw) == desc->ifmt_word)
+				return desc;
+		}
+	}
+
+	return NULL;
+}
+
+static struct ifmedia_description *get_mode_desc(int ifmw, 
+    struct ifmedia_type_to_subtype *ttos)
+{
+	int i;
+	struct ifmedia_description *desc;
+
+	for (i = 0; ttos->modes[i].desc != NULL; i++) {
+		if (ttos->modes[i].alias)
+			continue;
+		for (desc = ttos->modes[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (IFM_MODE(ifmw) == desc->ifmt_word)
+				return desc;
+		}
+	}
+
+	return NULL;
+}
+
+void
+print_media_word(int ifmw, int print_toptype)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int seen_option = 0, i;
+
+	/* Find the top-level interface type. */
+	desc = get_toptype_desc(ifmw);
+	ttos = get_toptype_ttos(ifmw);
+	if (desc->ifmt_string == NULL) {
+		printf("<unknown type>");
+		return;
+	} else if (print_toptype) {
+		printf("%s", desc->ifmt_string);
+	}
+
+	/*
+	 * Don't print the top-level type; it's not like we can
+	 * change it, or anything.
+	 */
+
+	/* Find subtype. */
+	desc = get_subtype_desc(ifmw, ttos);
+	if (desc == NULL) {
+		printf("<unknown subtype>");
+		return;
+	}
+
+	if (print_toptype)
+		putchar(' ');
+
+	printf("%s", desc->ifmt_string);
+
+	if (print_toptype) {
+		desc = get_mode_desc(ifmw, ttos);
+		if (desc != NULL && strcasecmp("autoselect", desc->ifmt_string))
+			printf(" mode %s", desc->ifmt_string);
+	}
+
+	/* Find options. */
+	for (i = 0; ttos->options[i].desc != NULL; i++) {
+		if (ttos->options[i].alias)
+			continue;
+		for (desc = ttos->options[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (ifmw & desc->ifmt_word) {
+				if (seen_option == 0)
+					printf(" <");
+				printf("%s%s", seen_option++ ? "," : "",
+				    desc->ifmt_string);
+			}
+		}
+	}
+	printf("%s", seen_option ? ">" : "");
+
+	if (print_toptype && IFM_INST(ifmw) != 0)
+		printf(" instance %d", IFM_INST(ifmw));
+}
+
+void
+print_media_word_ifconfig(int ifmw)
+{
+	struct ifmedia_description *desc;
+	struct ifmedia_type_to_subtype *ttos;
+	int seen_option = 0, i;
+
+	/* Find the top-level interface type. */
+	desc = get_toptype_desc(ifmw);
+	ttos = get_toptype_ttos(ifmw);
+	if (desc->ifmt_string == NULL) {
+		printf("<unknown type>");
+		return;
+	}
+
+	/*
+	 * Don't print the top-level type; it's not like we can
+	 * change it, or anything.
+	 */
+
+	/* Find subtype. */
+	desc = get_subtype_desc(ifmw, ttos);
+	if (desc == NULL) {
+		printf("<unknown subtype>");
+		return;
+	}
+
+	printf("media %s", desc->ifmt_string);
+
+	desc = get_mode_desc(ifmw, ttos);
+	if (desc != NULL)
+		printf(" mode %s", desc->ifmt_string);
+
+	/* Find options. */
+	for (i = 0; ttos->options[i].desc != NULL; i++) {
+		if (ttos->options[i].alias)
+			continue;
+		for (desc = ttos->options[i].desc;
+		    desc->ifmt_string != NULL; desc++) {
+			if (ifmw & desc->ifmt_word) {
+				if (seen_option == 0)
+					printf(" mediaopt ");
+				printf("%s%s", seen_option++ ? "," : "",
+				    desc->ifmt_string);
+			}
+		}
+	}
+
+	if (IFM_INST(ifmw) != 0)
+		printf(" instance %d", IFM_INST(ifmw));
+}
+
+/**********************************************************************
+ * ...until here.
+ **********************************************************************/
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/fsck_ffs/suj.c
--- a/head/sbin/fsck_ffs/suj.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/fsck_ffs/suj.c	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/fsck_ffs/suj.c 228751 2011-12-20 20:39:00Z kib $");
+__FBSDID("$FreeBSD: head/sbin/fsck_ffs/suj.c 236976 2012-06-12 21:37:27Z kib $");
 
 #include <sys/param.h>
 #include <sys/disk.h>
@@ -1789,6 +1789,20 @@
 	}
 }
 
+static void
+cg_adj_blk(struct suj_cg *sc)
+{
+	struct suj_ino *sino;
+	int i;
+
+	for (i = 0; i < SUJ_HASHSIZE; i++) {
+		LIST_FOREACH(sino, &sc->sc_inohash[i], si_next) {
+			if (sino->si_blkadj)
+				ino_adjblks(sino);
+		}
+	}
+}
+
 /*
  * Free any partially allocated blocks and then resolve inode block
  * counts.
@@ -2720,6 +2734,7 @@
 		printf("** Processing journal entries.\n");
 		cg_apply(cg_trunc);
 		cg_apply(cg_check_blk);
+		cg_apply(cg_adj_blk);
 		cg_apply(cg_check_ino);
 	}
 	if (preen == 0 && (jrecs > 0 || jbytes > 0) && reply("WRITE CHANGES") == 0)
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/fsck_msdosfs/main.c
--- a/head/sbin/fsck_msdosfs/main.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/fsck_msdosfs/main.c	Wed Jul 25 16:24:55 2012 +0300
@@ -28,7 +28,7 @@
 #ifndef lint
 __RCSID("$NetBSD: main.c,v 1.10 1997/10/01 02:18:14 enami Exp $");
 static const char rcsid[] =
-  "$FreeBSD$";
+  "$FreeBSD: head/sbin/fsck_msdosfs/main.c 236213 2012-05-29 01:48:06Z kevlo $";
 #endif /* not lint */
 
 #include <stdlib.h>
@@ -138,6 +138,7 @@
 
 	va_start(ap, fmt);
 	vsnprintf(prompt, sizeof(prompt), fmt, ap);
+	va_end(ap);
 	if (alwaysyes || rdonly) {
 		printf("%s? %s\n", prompt, rdonly ? "no" : "yes");
 		return !rdonly;
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/geom/class/eli/geli.8
--- a/head/sbin/geom/class/eli/geli.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/geom/class/eli/geli.8	Wed Jul 25 16:24:55 2012 +0300
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/geom/class/eli/geli.8 233458 2012-03-25 09:21:09Z joel $
+.\" $FreeBSD: head/sbin/geom/class/eli/geli.8 238117 2012-07-04 17:59:26Z pjd $
 .\"
-.Dd March 4, 2012
+.Dd June 18, 2012
 .Dt GELI 8
 .Os
 .Sh NAME
@@ -186,14 +186,15 @@
 or
 .Nm HMAC/SHA512 .
 .It
-Can create a key from a couple of components (user entered passphrase, random
-bits from a file, etc.).
+Can create a User Key from up to two, piecewise components: a passphrase
+entered via prompt or read from one or more passfiles; a keyfile read from
+one or more files.
 .It
 Allows encryption of the root partition.
 The user will be asked for the
 passphrase before the root file system is mounted.
 .It
-The passphrase of the user is strengthened with:
+Strengthens the passphrase component of the User Key with:
 .Rs
 .%A B. Kaliski
 .%T "PKCS #5: Password-Based Cryptography Specification, Version 2.0."
@@ -201,7 +202,7 @@
 .%N 2898
 .Re
 .It
-Allows the use of two independent keys (e.g., a
+Allows the use of two independent User Keys (e.g., a
 .Qq "user key"
 and a
 .Qq "company key" ) .
@@ -210,8 +211,8 @@
 .Nm
 performs simple sector-to-sector encryption.
 .It
-Allows Master Keys to be backed up and restored,
-so that if a user has to quickly destroy his keys,
+Allows the encrypted Master Key to be backed up and restored,
+so that if a user has to quickly destroy key material,
 it is possible to get the data back by restoring keys from
 backup.
 .It
@@ -219,8 +220,8 @@
 (so users do not have to remember to detach providers after unmounting
 the file systems).
 .It
-Allows attaching a provider with a random, one-time key - useful for swap
-partitions and temporary file systems.
+Allows attaching a provider with a random, one-time Master Key -
+useful for swap partitions and temporary file systems.
 .It
 Allows verification of data integrity (data authentication).
 .It
@@ -233,7 +234,8 @@
 .Bl -tag -width ".Cm configure"
 .It Cm init
 Initialize the provider which needs to be encrypted.
-Here you can set up the cryptographic algorithm to use, key length, etc.
+Here you can set up the cryptographic algorithm to use, Data Key length,
+etc.
 The last sector of the provider is used to store metadata.
 The
 .Cm init
@@ -289,37 +291,58 @@
 The default and recommended algorithm is
 .Nm AES-XTS .
 .It Fl i Ar iterations
-Number of iterations to use with PKCS#5v2.
+Number of iterations to use with PKCS#5v2 when processing User Key
+passphrase component.
 If this option is not specified,
 .Nm
 will find the number of iterations which is equal to 2 seconds of crypto work.
 If 0 is given, PKCS#5v2 will not be used.
+PKCS#5v2 processing is performed once, after all parts of the passphrase
+component have been read.
 .It Fl J Ar newpassfile
-Specifies a file which contains the passphrase or its part.
+Specifies a file which contains the passphrase component of the User Key
+(or part of it).
 If
 .Ar newpassfile
 is given as -, standard input will be used.
 Only the first line (excluding new-line character) is taken from the given file.
-This argument can be specified multiple times.
+This argument can be specified multiple times, which has the effect of
+reassembling a single passphrase split across multiple files.
+Cannot be combined with the
+.Fl P
+option.
 .It Fl K Ar newkeyfile
-Specifies a file which contains part of the key.
+Specifies a file which contains the keyfile component of the User Key
+(or part of it).
 If
 .Ar newkeyfile
 is given as -, standard input will be used.
-This argument can be specified multiple times.
+This argument can be specified multiple times, which has the effect of
+reassembling a single keyfile split across multiple keyfile parts.
 .It Fl l Ar keylen
-Key length to use with the given cryptographic algorithm.
-If not given, the default key length for the given algorithm is used, which is:
-128 for
-.Nm AES-XTS ,
-.Nm AES-CBC ,
-.Nm Blowfish-CBC
-and
-.Nm Camellia-CBC
-and 192 for
-.Nm 3DES-CBC .
+Data Key length to use with the given cryptographic algorithm.
+If the length is not specified, the selected algorithm uses its
+.Em default
+key length.
+.Bl -ohang -offset indent
+.It Nm AES-XTS
+.Em 128 ,
+256
+.It Nm AES-CBC , Nm Camilla-CBC
+.Em 128 ,
+192,
+256
+.It Nm Blowfish-CBC
+.Em 128
++ n * 32, for n=[0..10]
+.It Nm 3DES-CBC
+.Em 192
+.El
 .It Fl P
-Do not use passphrase as the key component.
+Do not use a passphrase as a component of the User Key.
+Cannot be combined with the
+.Fl J
+option.
 .It Fl s Ar sectorsize
 Change decrypted provider's sector size.
 Increasing the sector size allows increased performance,
@@ -337,9 +360,9 @@
 .El
 .It Cm attach
 Attach the given provider.
-The master key will be decrypted using the given
-passphrase/keyfile and a new GEOM provider will be created using the given
-provider's name with an
+The encrypted Master Key will be loaded from the metadata and decrypted
+using the given passphrase/keyfile and a new GEOM provider will be created
+using the given provider's name with an
 .Qq .eli
 suffix.
 .Pp
@@ -357,28 +380,33 @@
 .Cm detach
 subcommand.
 .It Fl j Ar passfile
-Specifies a file which contains the passphrase or its part.
+Specifies a file which contains the passphrase component of the User Key
+(or part of it).
 For more information see the description of the
 .Fl J
 option for the
 .Cm init
 subcommand.
 .It Fl k Ar keyfile
-Specifies a file which contains part of the key.
+Specifies a file which contains the keyfile component of the User Key
+(or part of it).
 For more information see the description of the
 .Fl K
 option for the
 .Cm init
 subcommand.
 .It Fl p
-Do not use passphrase as the key component.
+Do not use a passphrase as a component of the User Key.
+Cannot be combined with the
+.Fl j
+option.
 .It Fl r
 Attach read-only provider.
 It will not be opened for writing.
 .El
 .It Cm detach
 Detach the given providers, which means remove the devfs entry
-and clear the keys from memory.
+and clear the Master Key and Data Keys from memory.
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl f"
@@ -391,7 +419,7 @@
 last time even if it was only opened for reading.
 .El
 .It Cm onetime
-Attach the given providers with random, one-time keys.
+Attach the given providers with a random, one-time (ephemeral) Master Key.
 The command can be used to encrypt swap partitions or temporary file systems.
 .Pp
 Additional options include:
@@ -415,7 +443,7 @@
 .Cm attach
 subcommand.
 .It Fl l Ar keylen
-Key length to use with the given cryptographic algorithm.
+Data Key length to use with the given cryptographic algorithm.
 For more information, see the description of the
 .Cm init
 subcommand.
@@ -439,15 +467,18 @@
 Remove the BOOT flag from the given providers.
 .El
 .It Cm setkey
-Change or setup (if not yet initialized) selected key.
-There is one master key, which can be encrypted with two independent user keys.
+Install a copy of the Master Key into the selected slot, encrypted with
+a new User Key.
+If the selected slot is populated, replace the existing copy.
+A provider has one Master Key, which can be stored in one or both slots,
+each encrypted with an independent User Key.
 With the
 .Cm init
 subcommand, only key number 0 is initialized.
-The key can always be changed: for an attached provider,
+The User Key can be changed at any time: for an attached provider,
 for a detached provider, or on the backup file.
 When a provider is attached, the user does not have to provide
-an old passphrase/keyfile.
+an existing passphrase/keyfile.
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl J Ar newpassfile"
@@ -458,44 +489,54 @@
 .Cm setkey
 subcommand, only one key has to be defined and this key must be changed.
 .It Fl j Ar passfile
-Specifies a file which contains the old passphrase or its part.
+Specifies a file which contains the passphrase component of a current User Key
+(or part of it).
 .It Fl J Ar newpassfile
-Specifies a file which contains the new passphrase or its part.
+Specifies a file which contains the passphrase component of the new User Key
+(or part of it).
 .It Fl k Ar keyfile
-Specifies a file which contains part of the old key.
+Specifies a file which contains the keyfile component of a current User Key
+(or part of it).
 .It Fl K Ar newkeyfile
-Specifies a file which contains part of the new key.
+Specifies a file which contains the keyfile component of the new User Key
+(or part of it).
 .It Fl n Ar keyno
-Specifies the number of the key to change (could be 0 or 1).
+Specifies the index number of the Master Key copy to change (could be 0 or 1).
 If the provider is attached and no key number is given, the key
 used for attaching the provider will be changed.
 If the provider is detached (or we are operating on a backup file)
-and no key number is given, the key decrypted with the passphrase/keyfile
-will be changed.
+and no key number is given, the first Master Key copy to be successfully
+decrypted with the provided User Key passphrase/keyfile will be changed.
 .It Fl p
-Do not use passphrase as the old key component.
+Do not use a passphrase as a component of the current User Key.
+Cannot be combined with the
+.Fl j
+option.
 .It Fl P
-Do not use passphrase as the new key component.
+Do not use a passphrase as a component of the new User Key.
+Cannot be combined with the
+.Fl J
+option.
 .El
 .It Cm delkey
-Destroy (overwrite with random data) the selected key.
+Destroy (overwrite with random data) the selected Master Key copy.
 If one is destroying keys for an attached provider, the provider
-will not be detached even if all keys are destroyed.
+will not be detached even if all copies of the Master Key are destroyed.
 It can even be rescued with the
 .Cm setkey
-subcommand.
+subcommand because the Master Key is still in memory.
 .Pp
 Additional options include:
 .Bl -tag -width ".Fl a Ar keyno"
 .It Fl a
-Destroy all keys (does not need
+Destroy all copies of the Master Key (does not need
 .Fl f
 option).
 .It Fl f
 Force key destruction.
-This option is needed to destroy the last key.
+This option is needed to destroy the last copy of the Master Key.
 .It Fl n Ar keyno
-Specifies the key number.
+Specifies the index number of the Master Key copy.
 If the provider is attached and no key number is given, the key
 used for attaching the provider will be destroyed.
 If provider is detached (or we are operating on a backup file) the key number
@@ -503,8 +544,8 @@
 .El
 .It Cm kill
 This command should be used only in emergency situations.
-It will destroy all the keys on a given provider and will detach it forcibly
-(if it is attached).
+It will destroy all copies of the Master Key on a given provider and will
+detach it forcibly (if it is attached).
 This is absolutely a one-way command - if you do not have a metadata
 backup, your data is gone for good.
 In case the provider was attached with the
@@ -542,8 +583,8 @@
 .El
 .It Cm suspend
 Suspend device by waiting for all inflight requests to finish, clearing all
-sensitive information (like keys) from kernel memory, and blocking all
-further I/O requests until the
+sensitive information (like the Master Key and Data Keys) from kernel memory,
+and blocking all further I/O requests until the
 .Cm resume
 subcommand is executed.
 This functionality is useful for laptops: when one wants to suspend a
@@ -553,8 +594,8 @@
 the
 .Cm suspend
 subcommand can be used.
-Any access to the encrypted device will be blocked until the keys are
-recovered through the
+Any access to the encrypted device will be blocked until the Master Key is
+reloaded through the
 .Cm resume
 subcommand.
 Thus there is no need to close nor unmount anything.
@@ -584,21 +625,26 @@
 Additional options include:
 .Bl -tag -width ".Fl j Ar passfile"
 .It Fl j Ar passfile
-Specifies a file which contains the passphrase or its part.
+Specifies a file which contains the passphrase component of the User Key
+(or part of it).
 For more information see the description of the
 .Fl J
 option for the
 .Cm init
 subcommand.
 .It Fl k Ar keyfile
-Specifies a file which contains part of the key.
+Specifies a file which contains the keyfile component of the User Key
+(or part of it).
 For more information see the description of the
 .Fl K
 option for the
 .Cm init
 subcommand.
 .It Fl p
-Do not use passphrase as the key component.
+Do not use a passphrase as a component of the User Key.
+Cannot be combined with the
+.Fl j
+option.
 .El
 .It Cm resize
 Inform
@@ -626,6 +672,9 @@
 subcommand will print metadata version used by each of them.
 .It Cm clear
 Clear metadata from the given providers.
+.Em WARNING :
+This will erase with zeros the encrypted Master Key copies stored in the
+metadata.
 .It Cm dump
 Dump metadata stored on the given providers.
 .It Cm list
@@ -647,6 +696,36 @@
 .It Fl v
 Be more verbose.
 .El
+.Sh KEY SUMMARY
+.Ss Master Key
+Upon
+.Cm init ,
+the
+.Nm
+utility generates a random Master Key for the provider.
+The Master Key never changes during the lifetime of the provider.
+Each copy of the provider metadata, active or backed up to a file, can store
+up to two, independently-encrypted copies of the Master Key.
+.Ss User Key
+Each stored copy of the Master Key is encrypted with a User Key, which
+is generated by the
+.Nm
+utility from a passphrase and/or a keyfile.
+The
+.Nm
+utility first reads all parts of the keyfile in the order specified on the
+command line, then reads all parts of the stored passphrase in the order
+specified on the command line.
+If no passphrase parts are specified, the system prompts the user to enter
+the passphrase.
+The passphrase is optionally strengthened by PKCS#5v2.
+The User Key is a digest computed over the concatenated keyfile and passphrase.
+.Ss Data Key
+During operation, one or more Data Keys are deterministically derived by
+the kernel from the Master Key and cached in memory.
+The number of Data Keys used by a given provider, and the way they are
+derived, depend on the GELI version and whether the provider is configured to
+use data authentication.
 .Sh SYSCTL VARIABLES
 The following
 .Xr sysctl 8
@@ -677,7 +756,7 @@
 This variable should be set in
 .Pa /boot/loader.conf .
 .It Va kern.geom.eli.overwrites : No 5
-Specifies how many times the Master-Key will be overwritten
+Specifies how many times the Master Key will be overwritten
 with random values when it is destroyed.
 After this operation it is filled with zeros.
 .It Va kern.geom.eli.visible_passphrase : No 0
@@ -692,7 +771,6 @@
 Specifies how many kernel threads should be used for doing software
 cryptography.
 Its purpose is to increase performance on SMP systems.
-If hardware acceleration is available, only one thread will be started.
 If set to 0, a CPU-pinned thread will be started for every active CPU.
 .It Va kern.geom.eli.batch : No 0
 When set to 1, can speed-up crypto operations by using batching.
@@ -700,18 +778,19 @@
 crypto requests with one interrupt.
 The crypto card and the driver has to support this feature.
 .It Va kern.geom.eli.key_cache_limit : No 8192
-Specifies how many encryption keys to cache.
+Specifies how many Data Keys to cache.
 The default limit
 (8192 keys) will allow caching of all keys for a 4TB provider with 512 byte
 sectors and will take around 1MB of memory.
 .It Va kern.geom.eli.key_cache_hits
-Reports how many times we were looking up a key and it was already in cache.
-This sysctl is not updated for providers that need less keys than the limit
-specified in
+Reports how many times we were looking up a Data Key and it was already in
+cache.
+This sysctl is not updated for providers that need fewer Data Keys than
+the limit specified in
 .Va kern.geom.eli.key_cache_limit .
 .It Va kern.geom.eli.key_cache_misses
-Reports how many times we were looking up a key and it was not in cache.
-This sysctl is not updated for providers that need fewer keys than the limit
+Reports how many times we were looking up a Data Key and it was not in cache.
+This sysctl is not updated for providers that need fewer Data Keys than the limit
 specified in
 .Va kern.geom.eli.key_cache_limit .
 .El
@@ -739,7 +818,7 @@
 # geli detach da2.eli
 .Ed
 .Pp
-Create an encrypted provider, but use two keys:
+Create an encrypted provider, but use two User Keys:
 one for your employee and one for you as the company's security officer
 (so it's not a tragedy if the employee
 .Qq accidentally
@@ -761,7 +840,7 @@
 # dd if=/dev/random of=/mnt/pendrive/keys/`hostname` bs=64 count=1
 # geli init -P -K /mnt/pendrive/keys/`hostname` /dev/ad0s1e
 # geli backup /dev/ad0s1e /mnt/pendrive/backups/`hostname`
-(use key number 0, so the encrypted Master Key will be overwritten by this)
+(use key number 0, so the encrypted Master Key will be re-encrypted by this)
 # geli setkey -n 0 -k /mnt/pendrive/keys/`hostname` /dev/ad0s1e
 (allow the user to enter his passphrase)
 Enter new passphrase:
@@ -777,8 +856,8 @@
 .Pp
 The example below shows how to configure two providers which will be attached
 on boot (before the root file system is mounted).
-One of them is using passphrase and three keyfiles and the other is using only a
-keyfile:
+One of them is using passphrase and three keyfile parts and the other is
+using only a keyfile in one part:
 .Bd -literal -offset indent
 # dd if=/dev/random of=/dev/da0 bs=1m
 # dd if=/dev/random of=/boot/keys/da0.key0 bs=32k count=1
@@ -925,6 +1004,9 @@
 It is recommended to write to the whole provider before first use,
 in order to make sure that all sectors and their corresponding
 checksums are properly initialized into a consistent state.
+One can safely ignore data authentication errors that occur immediately
+after the first time a provider is attached and before it is
+initialized in this way.
 .Sh SEE ALSO
 .Xr crypto 4 ,
 .Xr gbde 4 ,
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/geom/class/part/geom_part.c
--- a/head/sbin/geom/class/part/geom_part.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/geom/class/part/geom_part.c	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 229916 2012-01-10 02:59:35Z eadler $");
+__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 235033 2012-05-04 19:49:24Z ae $");
 
 #include <sys/stat.h>
 #include <sys/vtoc.h>
@@ -507,6 +507,8 @@
 	grade = ~0ULL;
 	a_first = ALIGNUP(first + offset, alignment);
 	last = ALIGNDOWN(last + offset, alignment);
+	if (a_first < start)
+		a_first = start;
 	while ((pp = find_provider(gp, first)) != NULL) {
 		s = find_provcfg(pp, "start");
 		lba = (off_t)strtoimax(s, NULL, 0);
@@ -536,7 +538,8 @@
 
 		s = find_provcfg(pp, "end");
 		first = (off_t)strtoimax(s, NULL, 0) + 1;
-		a_first = ALIGNUP(first + offset, alignment);
+		if (first > a_first)
+			a_first = ALIGNUP(first + offset, alignment);
 	}
 	if (a_first <= last) {
 		/* Free space [first-last] */
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/geom/class/part/gpart.8
--- a/head/sbin/geom/class/part/gpart.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/geom/class/part/gpart.8	Wed Jul 25 16:24:55 2012 +0300
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/geom/class/part/gpart.8 233179 2012-03-19 13:17:47Z ae $
+.\" $FreeBSD: head/sbin/geom/class/part/gpart.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd March 19, 2012
 .Dt GPART 8
@@ -650,7 +650,7 @@
 for GPT.
 .It Cm ms-ldm-metadata
 A partition that contains Logical Disk Manager (LDM) database.
-The scheme-specifig type is
+The scheme-specific type is
 .Qq Li "!5808c8aa-7e8f-42e0-85d2-e1e90434cfb3"
 for GPT.
 .El
@@ -971,7 +971,7 @@
 .Sx "PARTITION TYPES"
 section).
 If this variable set to 1 each component of the mirrored volume will be
-present as independet partition.
+present as independent partition.
 .Em NOTE :
 This may break a mirrored volume and lead to data damage.
 .El
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/geom/class/raid/geom_raid.c
--- a/head/sbin/geom/class/raid/geom_raid.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/geom/class/raid/geom_raid.c	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sbin/geom/class/raid/geom_raid.c 234940 2012-05-03 05:32:56Z mav $");
 
 #include <sys/param.h>
 #include <errno.h>
@@ -48,11 +48,12 @@
 	{ "label", G_FLAG_VERBOSE, NULL,
 	    {
 		{ 'f', "force", NULL, G_TYPE_BOOL },
+		{ 'o', "fmtopt", G_VAL_OPTIONAL, G_TYPE_STRING },
 		{ 'S', "size", G_VAL_OPTIONAL, G_TYPE_NUMBER },
 		{ 's', "strip", G_VAL_OPTIONAL, G_TYPE_NUMBER },
 		G_OPT_SENTINEL
 	    },
-	    "[-fv] [-S size] [-s stripsize] format label level prov ..."
+	    "[-fv] [-o fmtopt] [-S size] [-s stripsize] format label level prov ..."
 	},
 	{ "add", G_FLAG_VERBOSE, NULL,
 	    {
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/geom/class/raid/graid.8
--- a/head/sbin/geom/class/raid/graid.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/geom/class/raid/graid.8	Wed Jul 25 16:24:55 2012 +0300
@@ -22,9 +22,9 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/geom/class/raid/graid.8 234458 2012-04-19 12:30:12Z mav $
+.\" $FreeBSD: head/sbin/geom/class/raid/graid.8 237620 2012-06-27 01:44:48Z wblock $
 .\"
-.Dd April 19, 2012
+.Dd May 6, 2012
 .Dt GRAID 8
 .Os
 .Sh NAME
@@ -34,6 +34,7 @@
 .Nm
 .Cm label
 .Op Fl f
+.Op Fl o Ar fmtopt
 .Op Fl S Ar size
 .Op Fl s Ar strip
 .Ar format
@@ -84,7 +85,7 @@
 GEOM RAID class.
 GEOM RAID class uses on-disk metadata to provide access to software-RAID
 volumes defined by different RAID BIOSes.
-Depending on RAID BIOS type and it's metadata format, different subsets of
+Depending on RAID BIOS type and its metadata format, different subsets of
 configurations and features are supported.
 To allow booting from RAID volume, the metadata format should match the
 RAID BIOS type and its capabilities.
@@ -119,6 +120,8 @@
 .It Fl f
 Enforce specified configuration creation if it is officially unsupported,
 but technically can be created.
+.It Fl o Ar fmtopt
+Specifies metadata format options.
 .It Fl S Ar size
 Use
 .Ar size
@@ -200,6 +203,23 @@
 formats to be used.
 Support is currently implemented for the following formats:
 .Bl -tag -width "Intel"
+.It DDF
+The format defined by the SNIA Common RAID Disk Data Format v2.0 specification.
+Used by some Adaptec RAID BIOSes and some hardware RAID controllers.
+Because of high format flexibility different implementations support
+different set of features and have different on-disk metadata layouts.
+To provide compatibility, the GEOM RAID class mimics capabilities
+of the first detected DDF array.
+Respecting that, it may support different number of disks per volume,
+volumes per array, partitions per disk, etc.
+The following configurations are supported: RAID0 (2+ disks), RAID1 (2+ disks),
+RAID1E (3+ disks), RAID3 (3+ disks), RAID4 (3+ disks), RAID5 (3+ disks),
+RAID5E (4+ disks), RAID5EE (4+ disks), RAID5R (3+ disks), RAID6 (4+ disks),
+RAIDMDF (4+ disks), RAID10 (4+ disks), SINGLE (1 disk), CONCAT (2+ disks).
+.Pp
+Format supports two options "BE" and "LE", that mean big-endian byte order
+defined by specification (default) and little-endian used by some Adaptec
+controllers.
 .It Intel
 The format used by Intel RAID BIOS.
 Supports up to two volumes per array.
@@ -241,9 +261,11 @@
 .Sh SUPPORTED RAID LEVELS
 The GEOM RAID class follows a modular design, allowing different RAID levels
 to be used.
-Support for the following RAID levels is currently implemented: RAID0, RAID1,
-RAID1E, RAID5, RAID10, SINGLE, CONCAT.
-RAID5 support is read-only and only for volumes in optimal state.
+Full support for the following RAID levels is currently implemented:
+RAID0, RAID1, RAID1E, RAID10, SINGLE, CONCAT.
+The following RAID levels supported as read-only for volumes in optimal
+state (without using redundancy): RAID4, RAID5, RAID5E, RAID5EE, RAID5R,
+RAID6, RAIDMDF.
 .Sh RAID LEVEL MIGRATION
 The GEOM RAID class has no support for RAID level migration, allowed by some
 metadata formats.
@@ -254,6 +276,33 @@
 .Sh 2TiB BARRIERS
 Promise metadata format does not support disks above 2TiB.
 NVIDIA metadata format does not support volumes above 2TiB.
+.Sh SYSCTL VARIABLES
+The following
+.Xr sysctl 8
+variable can be used to control the behavior of the
+.Nm RAID
+GEOM class.
+.Bl -tag -width indent
+.It Va kern.geom.raid.aggressive_spare : No 0
+Use any disks without metadata connected to controllers of the vendor
+matching to volume metadata format as spare.
+Use it with much care to not lose data if connecting unrelated disk!
+.It Va kern.geom.raid.clean_time : No 5
+Mark volume as clean when idle for the specified number of seconds.
+.It Va kern.geom.raid.debug : No 0
+Debug level of the
+.Nm RAID
+GEOM class.
+.It Va kern.geom.raid.idle_threshold : No 1000000
+Time in microseconds to consider a volume idle for rebuild purposes.
+.It Va kern.geom.raid.name_format : No 0
+Providers name format: 0 -- raid/r{num}, 1 -- raid/{label}.
+.It Va kern.geom.raid.read_err_thresh : No 10
+Number of read errors equated to disk failure.
+Write errors are always considered as disk failures.
+.It Va kern.geom.raid.start_timeout : No 30
+Time to wait for missing array components on startup.
+.El
 .Sh EXIT STATUS
 Exit status is 0 on success, and non-zero if the command fails.
 .Sh SEE ALSO
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/geom/class/virstor/gvirstor.8
--- a/head/sbin/geom/class/virstor/gvirstor.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/geom/class/virstor/gvirstor.8	Wed Jul 25 16:24:55 2012 +0300
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
+.\" $FreeBSD: head/sbin/geom/class/virstor/gvirstor.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd January 24, 2011
 .Dt GVIRSTOR 8
@@ -113,7 +113,7 @@
 The specified virstor device must exist and be active
 .Pq i.e. module loaded, device present in Pa /dev .
 This action can be safely performed while the virstor device is in use
-.Pq Qo hot Qc operation
+.Pq Qo hot Qc operation .
 .It Cm remove
 Removes components from existing virtual device with the given
 .Ar name .
@@ -268,7 +268,8 @@
 components will always remain constant during their existence.
 For alternative ways to implement virtual or resizable file systems see
 .Xr zfs 1M ,
-.Xr gconcat 8 and
+.Xr gconcat 8
+and
 .Xr growfs 8 .
 .Pp
 Note that
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/growfs/Makefile
--- a/head/sbin/growfs/Makefile	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/growfs/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -1,17 +1,23 @@
 #	@(#)Makefile	8.8 (Berkeley) 6/21/2000
 #
 # $TSHeader: src/sbin/growfs/Makefile,v 1.4 2000/12/05 19:45:24 tomsoft Exp $
-# $FreeBSD$
+# $FreeBSD: head/sbin/growfs/Makefile 234846 2012-04-30 16:08:02Z trasz $
 #
 
 #GFSDBG=
 
+.PATH:	${.CURDIR}/../mount
+
 PROG=   growfs
-SRCS=   growfs.c
+SRCS=   growfs.c getmntopts.c
 MAN=	growfs.8
+CFLAGS+=-I${.CURDIR}/../mount
 
 .if defined(GFSDBG)
 SRCS+=  debug.c
 .endif  
 
+DPADD=	${LIBUTIL}
+LDADD=	-lutil
+
 .include <bsd.prog.mk>      
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/growfs/growfs.8
--- a/head/sbin/growfs/growfs.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/growfs/growfs.8	Wed Jul 25 16:24:55 2012 +0300
@@ -35,9 +35,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\" $TSHeader: src/sbin/growfs/growfs.8,v 1.3 2000/12/12 19:31:00 tomsoft Exp $
-.\" $FreeBSD: head/sbin/growfs/growfs.8 223652 2011-06-28 19:59:46Z trasz $
+.\" $FreeBSD: head/sbin/growfs/growfs.8 235336 2012-05-12 14:46:49Z joel $
 .\"
-.Dd June 29, 2011
+.Dd April 30, 2012
 .Dt GROWFS 8
 .Os
 .Sh NAME
@@ -47,41 +47,20 @@
 .Nm
 .Op Fl Ny
 .Op Fl s Ar size
-.Ar special
+.Ar special | filesystem
 .Sh DESCRIPTION
 The
 .Nm
-utility extends the
-.Xr newfs 8
-program.
-Before starting
+utility makes it possible to expand an UFS file system.
+Before running
 .Nm
-the disk must be labeled to a bigger size using
-.Xr bsdlabel 8 .
-If you wish to grow a file system beyond the boundary of
-the slice it resides in, you must re-size the slice using
-.Xr gpart 8
-before running
-.Nm .
+the partition or slice containing the file system must be extended using
+.Xr gpart 8 .
 If you are using volumes you must enlarge them by using
 .Xr gvinum 8 .
 The
 .Nm
 utility extends the size of the file system on the specified special file.
-Currently
-.Nm
-can only enlarge unmounted file systems.
-Do not try enlarging a mounted file system, your system may panic and you will
-not be able to use the file system any longer.
-Most of the
-.Xr newfs 8
-options cannot be changed by
-.Nm .
-In fact, you can only increase the size of the file system.
-Use
-.Xr tunefs 8
-for other changes.
-.Pp
 The following options are available:
 .Bl -tag -width indent
 .It Fl N
@@ -103,6 +82,13 @@
 Determines the
 .Ar size
 of the file system after enlarging in sectors.
+.Ar Size
+is the number of 512 byte sectors unless suffixed with a
+.Cm b , k , m , g ,
+or
+.Cm t
+which
+denotes byte, kilobyte, megabyte, gigabyte and terabyte respectively.
 This value defaults to the size of the raw partition specified in
 .Ar special
 (in other words,
@@ -110,19 +96,18 @@
 will enlarge the file system to the size of the entire partition).
 .El
 .Sh EXAMPLES
-.Dl growfs -s 4194304 /dev/vinum/testvol
+.Dl growfs -s 2G /dev/ada0p1
 .Pp
 will enlarge
-.Pa /dev/vinum/testvol
+.Pa /dev/ada0p1
 up to 2GB if there is enough space in
-.Pa /dev/vinum/testvol .
+.Pa /dev/ada0p1 .
 .Sh SEE ALSO
-.Xr bsdlabel 8 ,
 .Xr dumpfs 8 ,
 .Xr ffsinfo 8 ,
 .Xr fsck 8 ,
+.Xr fsdb 8 ,
 .Xr gpart 8 ,
-.Xr gvinum 8 ,
 .Xr newfs 8 ,
 .Xr tunefs 8
 .Sh HISTORY
@@ -134,61 +119,11 @@
 .An Christoph Herrmann Aq chm at FreeBSD.org
 .An Thomas-Henning von Kamptz Aq tomsoft at FreeBSD.org
 .An The GROWFS team Aq growfs at Tomsoft.COM
+.An Edward Tomasz Napierala Aq trasz at FreeBSD.org
 .Sh BUGS
-The
-.Nm
-utility works starting with
-.Fx
-3.x.
-There may be cases on
-.Fx
-3.x only, when
-.Nm
-does not recognize properly whether or not the file system is mounted and
-exits with an error message.
-Then please use
-.Nm
-.Fl y
-if you are sure that the file system is not mounted.
-It is also recommended to always use
-.Xr fsck 8
-after enlarging (just to be on the safe side).
-.Pp
-For enlarging beyond certain limits, it is essential to have some free blocks
-available in the first cylinder group.
-If that space is not available in the first cylinder group, a critical data
-structure has to be relocated into one of the new available cylinder groups.
-On
-.Fx
-3.x this will cause problems with
-.Xr fsck 8
-afterwards.
-So
-.Xr fsck 8
-needs to be patched if you want to use
-.Nm
-for
-.Fx
-3.x.
-This patch is already integrated in
-.Fx
-starting with
-.Fx 4.4 .
-To avoid an unexpected relocation of that structure it is possible to use
-.Nm ffsinfo
-.Fl g Ar 0
-.Fl l Ar 4
-on the first cylinder group to verify that
-.Em nbfree
-in the CYLINDER SUMMARY (internal cs) of the CYLINDER GROUP
-.Em cgr0
-has enough blocks.
-As a rule of thumb for default file system parameters one block is needed for
-every 2 GB of total file system size.
-.Pp
 Normally
 .Nm
-writes this critical structure to disk and reads it again later for doing more
+writes cylinder group summary to disk and reads it again later for doing more
 updates.
 This read operation will provide unexpected data when using
 .Fl N .
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/growfs/growfs.c
--- a/head/sbin/growfs/growfs.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/growfs/growfs.c	Wed Jul 25 16:24:55 2012 +0300
@@ -1,11 +1,15 @@
 /*
+ * Copyright (c) 1980, 1989, 1993 The Regents of the University of California.
  * Copyright (c) 2000 Christoph Herrmann, Thomas-Henning von Kamptz
- * Copyright (c) 1980, 1989, 1993 The Regents of the University of California.
+ * Copyright (c) 2012 The FreeBSD Foundation
  * All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Christoph Herrmann and Thomas-Henning von Kamptz, Munich and Frankfurt.
  *
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * under sponsorship from the FreeBSD Foundation.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -47,19 +51,24 @@
 #endif /* not lint */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/growfs/growfs.c 234420 2012-04-18 13:50:17Z trasz $");
+__FBSDID("$FreeBSD: head/sbin/growfs/growfs.c 238204 2012-07-07 17:25:36Z eadler $");
 
 #include <sys/param.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/disk.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
 
 #include <stdio.h>
 #include <paths.h>
 #include <ctype.h>
 #include <err.h>
 #include <fcntl.h>
+#include <fstab.h>
+#include <inttypes.h>
 #include <limits.h>
+#include <mntopts.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
@@ -67,6 +76,7 @@
 #include <unistd.h>
 #include <ufs/ufs/dinode.h>
 #include <ufs/ffs/fs.h>
+#include <libutil.h>
 
 #include "debug.h"
 
@@ -109,7 +119,7 @@
 static void	updcsloc(time_t, int, int, unsigned int);
 static void	frag_adjust(ufs2_daddr_t, int);
 static void	updclst(int);
-static void	get_dev_size(int, int *);
+static void	mount_reload(const struct statfs *stfs);
 
 /*
  * Here we actually start growing the file system. We basically read the
@@ -177,6 +187,7 @@
 	/*
 	 * Dump out summary information about file system.
 	 */
+#ifdef FS_DEBUG
 #define B2MBFACTOR (1 / (1024.0 * 1024.0))
 	printf("growfs: %.1fMB (%jd sectors) block size %d, fragment size %d\n",
 	    (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
@@ -188,6 +199,7 @@
 	if (sblock.fs_flags & FS_DOSOFTDEP)
 		printf("\twith soft updates\n");
 #undef B2MBFACTOR
+#endif /* FS_DEBUG */
 
 	/*
 	 * Now build the cylinders group blocks and
@@ -774,7 +786,7 @@
 
 /*
  * Here we update the location of the cylinder summary. We have two possible
- * ways of growing the cylinder summary.
+ * ways of growing the cylinder summary:
  * (1)	We can try to grow the summary in the current location, and relocate
  *	possibly used blocks within the current cylinder group.
  * (2)	Alternatively we can relocate the whole cylinder summary to the first
@@ -791,7 +803,6 @@
 	DBG_FUNC("updcsloc")
 	struct csum *cs;
 	int ocscg, ncscg;
-	int blocks;
 	ufs2_daddr_t d;
 	int lcs = 0;
 	int block;
@@ -808,8 +819,6 @@
 	}
 	ocscg = dtog(&osblock, osblock.fs_csaddr);
 	cs = fscs + ocscg;
-	blocks = 1 + howmany(sblock.fs_cssize, sblock.fs_bsize) -
-	    howmany(osblock.fs_cssize, osblock.fs_bsize);
 
 	/*
 	 * Read original cylinder group from disk, and make a copy.
@@ -1238,24 +1247,104 @@
 	return (columns);
 }
 
+static int
+is_dev(const char *name)
+{
+	struct stat devstat;
+
+	if (stat(name, &devstat) != 0)
+		return (0);
+	if (!S_ISCHR(devstat.st_mode))
+		return (0);
+	return (1);
+}
+
 /*
- * Get the size of the partition.
- */
-static void
-get_dev_size(int fd, int *size)
+ * Return mountpoint on which the device is currently mounted.
+ */ 
+static const struct statfs *
+dev_to_statfs(const char *dev)
 {
-	int sectorsize;
-	off_t mediasize;
+	struct stat devstat, mntdevstat;
+	struct statfs *mntbuf, *statfsp;
+	char device[MAXPATHLEN];
+	char *mntdevname;
+	int i, mntsize;
 
-	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) == -1)
-		err(1,"DIOCGSECTORSIZE");
-	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1)
-		err(1,"DIOCGMEDIASIZE");
+	/*
+	 * First check the mounted filesystems.
+	 */
+	if (stat(dev, &devstat) != 0)
+		return (NULL);
+	if (!S_ISCHR(devstat.st_mode) && !S_ISBLK(devstat.st_mode))
+		return (NULL);
 
-	if (sectorsize <= 0)
-		errx(1, "bogus sectorsize: %d", sectorsize);
+	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+	for (i = 0; i < mntsize; i++) {
+		statfsp = &mntbuf[i];
+		mntdevname = statfsp->f_mntfromname;
+		if (*mntdevname != '/') {
+			strcpy(device, _PATH_DEV);
+			strcat(device, mntdevname);
+			mntdevname = device;
+		}
+		if (stat(mntdevname, &mntdevstat) == 0 &&
+		    mntdevstat.st_rdev == devstat.st_rdev)
+			return (statfsp);
+	}
 
-	*size = mediasize / sectorsize;
+	return (NULL);
+}
+
+static const char *
+mountpoint_to_dev(const char *mountpoint)
+{
+	struct statfs *mntbuf, *statfsp;
+	struct fstab *fs;
+	int i, mntsize;
+
+	/*
+	 * First check the mounted filesystems.
+	 */
+	mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+	for (i = 0; i < mntsize; i++) {
+		statfsp = &mntbuf[i];
+
+		if (strcmp(statfsp->f_mntonname, mountpoint) == 0)
+			return (statfsp->f_mntfromname);
+	}
+
+	/*
+	 * Check the fstab.
+	 */
+	fs = getfsfile(mountpoint);
+	if (fs != NULL)
+		return (fs->fs_spec);
+
+	return (NULL);
+}
+
+static const char *
+getdev(const char *name)
+{
+	static char device[MAXPATHLEN];
+	const char *cp, *dev;
+
+	if (is_dev(name))
+		return (name);
+
+	cp = strrchr(name, '/');
+	if (cp == 0) {
+		snprintf(device, sizeof(device), "%s%s", _PATH_DEV, name);
+		if (is_dev(device))
+			return (device);
+	}
+
+	dev = mountpoint_to_dev(name);
+	if (dev != NULL && is_dev(dev))
+		return (dev);
+
+	return (NULL);
 }
 
 /*
@@ -1283,17 +1372,13 @@
 main(int argc, char **argv)
 {
 	DBG_FUNC("main")
-	char *device, *special;
-	int ch;
-	unsigned int size = 0;
-	size_t len;
-	unsigned int Nflag = 0;
-	int ExpertFlag = 0;
-	struct stat st;
-	int i, fsi, fso;
-	u_int32_t p_size;
-	char reply[5];
-	int j;
+	const char *device;
+	const struct statfs *statfsp;
+	uint64_t size = 0;
+	off_t mediasize;
+	int error, i, j, fsi, fso, ch, Nflag = 0, yflag = 0;
+	char *p, reply[5], oldsizebuf[6], newsizebuf[6];
+	void *testbuf;
 
 	DBG_ENTER;
 
@@ -1303,14 +1388,27 @@
 			Nflag = 1;
 			break;
 		case 's':
-			size = (size_t)atol(optarg);
-			if (size < 1)
-				usage();
+			size = (off_t)strtoumax(optarg, &p, 0);
+			if (p == NULL || *p == '\0')
+				size *= DEV_BSIZE;
+			else if (*p == 'b' || *p == 'B')
+				; /* do nothing */
+			else if (*p == 'k' || *p == 'K')
+				size <<= 10;
+			else if (*p == 'm' || *p == 'M')
+				size <<= 20;
+			else if (*p == 'g' || *p == 'G')
+				size <<= 30;
+			else if (*p == 't' || *p == 'T') {
+				size <<= 30;
+				size <<= 10;
+			} else
+				errx(1, "unknown suffix on -s argument");
 			break;
 		case 'v': /* for compatibility to newfs */
 			break;
 		case 'y':
-			ExpertFlag = 1;
+			yflag = 1;
 			break;
 		case '?':
 			/* FALLTHROUGH */
@@ -1324,71 +1422,29 @@
 	if (argc != 1)
 		usage();
 
-	device = *argv;
+	/*
+	 * Now try to guess the device name.
+	 */
+	device = getdev(*argv);
+	if (device == NULL)
+		errx(1, "cannot find special device for %s", *argv);
 
-	/*
-	 * Now try to guess the (raw)device name.
-	 */
-	if (0 == strrchr(device, '/')) {
-		/*
-		 * No path prefix was given, so try in that order:
-		 *     /dev/r%s
-		 *     /dev/%s
-		 *     /dev/vinum/r%s
-		 *     /dev/vinum/%s.
-		 *
-		 * FreeBSD now doesn't distinguish between raw and block
-		 * devices any longer, but it should still work this way.
-		 */
-		len = strlen(device) + strlen(_PATH_DEV) + 2 + strlen("vinum/");
-		special = (char *)malloc(len);
-		if (special == NULL)
-			errx(1, "malloc failed");
-		snprintf(special, len, "%sr%s", _PATH_DEV, device);
-		if (stat(special, &st) == -1) {
-			snprintf(special, len, "%s%s", _PATH_DEV, device);
-			if (stat(special, &st) == -1) {
-				snprintf(special, len, "%svinum/r%s",
-				    _PATH_DEV, device);
-				if (stat(special, &st) == -1) {
-					/* For now this is the 'last resort' */
-					snprintf(special, len, "%svinum/%s",
-					    _PATH_DEV, device);
-				}
-			}
-		}
-		device = special;
-	}
+	statfsp = dev_to_statfs(device);
 
-	/*
-	 * Try to access our devices for writing ...
-	 */
-	if (Nflag) {
-		fso = -1;
-	} else {
-		fso = open(device, O_WRONLY);
-		if (fso < 0)
-			err(1, "%s", device);
-	}
-
-	/*
-	 * ... and reading.
-	 */
 	fsi = open(device, O_RDONLY);
 	if (fsi < 0)
 		err(1, "%s", device);
 
 	/*
-	 * Try to guess the slice if not specified. This code should guess
-	 * the right thing and avoid to bother the user with the task
-	 * of specifying the option -v on vinum volumes.
+	 * Try to guess the slice size if not specified.
 	 */
-	get_dev_size(fsi, &p_size);
+	if (ioctl(fsi, DIOCGMEDIASIZE, &mediasize) == -1)
+		err(1,"DIOCGMEDIASIZE");
 
 	/*
 	 * Check if that partition is suitable for growing a file system.
 	 */
-	if (p_size < 1)
+	if (mediasize < 1)
 		errx(1, "partition is unavailable");
 
 	/*
@@ -1414,16 +1470,36 @@
 	/*
 	 * Determine size to grow to. Default to the device size.
 	 */
-	sblock.fs_size = dbtofsb(&osblock, p_size);
-	if (size != 0) {
-		if (size > p_size)
-			errx(1, "there is not enough space (%d < %d)",
-			    p_size, size);
-		sblock.fs_size = dbtofsb(&osblock, size);
+	if (size == 0)
+		size = mediasize;
+	else {
+		if (size > (uint64_t)mediasize) {
+			humanize_number(oldsizebuf, sizeof(oldsizebuf), size,
+			    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+			humanize_number(newsizebuf, sizeof(newsizebuf),
+			    mediasize,
+			    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+
+			errx(1, "requested size %s is larger "
+			    "than the available %s", oldsizebuf, newsizebuf);
+		}
 	}
 
+	if (size <= (uint64_t)(osblock.fs_size * osblock.fs_fsize)) {
+		humanize_number(oldsizebuf, sizeof(oldsizebuf),
+		    osblock.fs_size * osblock.fs_fsize,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+		humanize_number(newsizebuf, sizeof(newsizebuf), size,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+
+		errx(1, "requested size %s is not larger than the current "
+		   "filesystem size %s", newsizebuf, oldsizebuf);
+	}
+
+	sblock.fs_size = dbtofsb(&osblock, size / DEV_BSIZE);
+
 	/*
-	 * Are we really growing ?
+	 * Are we really growing?
 	 */
 	if (osblock.fs_size >= sblock.fs_size) {
 		errx(1, "we are not growing (%jd->%jd)",
@@ -1433,7 +1509,7 @@
 	/*
 	 * Check if we find an active snapshot.
 	 */
-	if (ExpertFlag == 0) {
+	if (yflag == 0) {
 		for (j = 0; j < FSMAXSNAP; j++) {
 			if (sblock.fs_snapinum[j]) {
 				errx(1, "active snapshot found in file system; "
@@ -1445,10 +1521,23 @@
 		}
 	}
 
-	if (ExpertFlag == 0 && Nflag == 0) {
-		printf("We strongly recommend you to make a backup "
+	if (yflag == 0 && Nflag == 0) {
+		if (statfsp != NULL && (statfsp->f_flags & MNT_RDONLY) == 0)
+			errx(1, "%s is mounted read-write on %s",
+			    statfsp->f_mntfromname, statfsp->f_mntonname);
+		printf("It's strongly recommended to make a backup "
 		    "before growing the file system.\n"
-		    "Did you backup your data (Yes/No)? ");
+		    "OK to grow filesystem on %s", device);
+		if (statfsp != NULL)
+			printf(", mounted on %s,", statfsp->f_mntonname);
+		humanize_number(oldsizebuf, sizeof(oldsizebuf),
+		    osblock.fs_size * osblock.fs_fsize,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+		humanize_number(newsizebuf, sizeof(newsizebuf),
+		    sblock.fs_size * sblock.fs_fsize,
+		    "B", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
+		printf(" from %s to %s? [Yes/No] ", oldsizebuf, newsizebuf);
+		fflush(stdout);
 		fgets(reply, (int)sizeof(reply), stdin);
 		if (strcmp(reply, "Yes\n")){
 			printf("\nNothing done\n");
@@ -1456,15 +1545,30 @@
 		}
 	}
 
-	printf("New file system size is %jd frags\n", (intmax_t)sblock.fs_size);
+	/*
+	 * Try to access our device for writing.  If it's not mounted,
+	 * or mounted read-only, simply open it; otherwise, use UFS
+	 * suspension mechanism.
+	 */
+	if (Nflag) {
+		fso = -1;
+	} else {
+		fso = open(device, O_WRONLY);
+		if (fso < 0)
+			err(1, "%s", device);
+	}
 
 	/*
-	 * Try to access our new last block in the file system. Even if we
-	 * later on realize we have to abort our operation, on that block
-	 * there should be no data, so we can't destroy something yet.
+	 * Try to access our new last block in the file system.
 	 */
-	wtfs((ufs2_daddr_t)p_size - 1, (size_t)DEV_BSIZE, (void *)&sblock,
-	    fso, Nflag);
+	testbuf = malloc(sblock.fs_fsize);
+	if (testbuf == NULL)
+		err(1, "malloc");
+	rdfs((ufs2_daddr_t)((size - sblock.fs_fsize) / DEV_BSIZE),
+	    sblock.fs_fsize, testbuf, fsi);
+	wtfs((ufs2_daddr_t)((size - sblock.fs_fsize) / DEV_BSIZE),
+	    sblock.fs_fsize, testbuf, fso, Nflag);
+	free(testbuf);
 
 	/*
 	 * Now calculate new superblock values and check for reasonable
@@ -1520,8 +1624,13 @@
 	growfs(fsi, fso, Nflag);
 
 	close(fsi);
-	if (fso > -1)
-		close(fso);
+	if (fso > -1) {
+		error = close(fso);
+		if (error != 0)
+			err(1, "close");
+	}
+	if (statfsp != NULL)
+		mount_reload(statfsp);
 
 	DBG_CLOSE;
 
@@ -1539,7 +1648,7 @@
 
 	DBG_ENTER;
 
-	fprintf(stderr, "usage: growfs [-Ny] [-s size] special\n");
+	fprintf(stderr, "usage: growfs [-Ny] [-s size] special | filesystem\n");
 
 	DBG_LEAVE;
 	exit(1);
@@ -1586,3 +1695,26 @@
 	DBG_LEAVE;
 	return;
 }
+
+static void
+mount_reload(const struct statfs *stfs)
+{
+	char errmsg[255];
+	struct iovec *iov;
+	int iovlen;
+
+	iov = NULL;
+	iovlen = 0;
+	*errmsg = '\0';
+	build_iovec(&iov, &iovlen, "fstype", __DECONST(char *, "ffs"), 4);
+	build_iovec(&iov, &iovlen, "fspath", __DECONST(char *, stfs->f_mntonname), (size_t)-1);
+	build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
+	build_iovec(&iov, &iovlen, "update", NULL, 0);
+	build_iovec(&iov, &iovlen, "reload", NULL, 0);
+
+	if (nmount(iov, iovlen, stfs->f_flags) < 0) {
+		errmsg[sizeof(errmsg) - 1] = '\0';
+		err(9, "%s: cannot reload filesystem%s%s", stfs->f_mntonname,
+		    *errmsg != '\0' ? ": " : "", errmsg);
+	}
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/gvinum/gvinum.8
--- a/head/sbin/gvinum/gvinum.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/gvinum/gvinum.8	Wed Jul 25 16:24:55 2012 +0300
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/gvinum/gvinum.8 233648 2012-03-29 05:02:12Z eadler $
+.\" $FreeBSD: head/sbin/gvinum/gvinum.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd April 10, 2009
 .Dt GVINUM 8
@@ -58,7 +58,8 @@
 plex must be up for a parity check.
 .It Ic concat Oo Fl fv Oc Oo Fl n Ar name Oc Ar drives
 Create a concatenated volume from the specified drives.
-If no name is specified, a unique name will be set by gvinum.
+If no name is specified, a unique name will be set by
+.Ic gvinum .
 .It Ic create Oo Fl f Oc Op Ar description-file
 Create a volume as described in
 .Ar description-file .
@@ -148,8 +149,8 @@
 EOF character.
 .It Ic raid5 Oo Fl fv Oc Oo Fl s Ar stripesize Oc Oo Fl n Ar name Oc Ar drives
 Create a RAID-5 volume from the specified drives.
-If no name is specified,a unique name will be set by
-.Ic gvinum.
+If no name is specified, a unique name will be set by
+.Ic gvinum .
 This organization requires at least three drives.
 .It Ic rename Oo Fl r Oc Ar drive | subdisk | plex | volume newname
 Change the name of the specified object.
@@ -202,8 +203,9 @@
 if no parameters are specified.
 .It Ic stripe Oo Fl fv Oc Oo Fl n Ar name Oc Ar drives
 Create a striped volume from the specified drives. If no name is specified,
-a unique name will be set by Ic gvinum. This organization requires at least two
-drives.
+a unique name will be set by
+.Ic gvinum .
+This organization requires at least two drives.
 .El
 .Sh DESCRIPTION
 The
@@ -278,7 +280,8 @@
 .El
 .Sh EXAMPLES
 To create a mirror on disks /dev/ad1 and /dev/ad2, create a filesystem, mount,
-unmount and then stop Ic gvinum:
+unmount and then stop
+.Ic gvinum :
 .Pp
 .Dl "gvinum mirror /dev/ad1 /dev/ad2"
 .Dl "newfs /dev/gvinum/gvinumvolume0"
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastctl/hastctl.8
--- a/head/sbin/hastctl/hastctl.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastctl/hastctl.8	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/hastctl/hastctl.8 229778 2012-01-07 16:09:33Z uqs $
+.\" $FreeBSD: head/sbin/hastctl/hastctl.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd April 10, 2011
 .Dt HASTCTL 8
@@ -211,7 +211,7 @@
 .Xr ggatel 8 ,
 .Xr hastd 8 ,
 .Xr mount 8 ,
-.Xr newfs 8 .
+.Xr newfs 8
 .Sh AUTHORS
 The
 .Nm
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/hast.conf.5
--- a/head/sbin/hastd/hast.conf.5	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/hast.conf.5	Wed Jul 25 16:24:55 2012 +0300
@@ -26,7 +26,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/hastd/hast.conf.5 230515 2012-01-24 23:43:13Z pjd $
+.\" $FreeBSD: head/sbin/hastd/hast.conf.5 238538 2012-07-16 20:43:28Z trociny $
 .\"
 .Dd January 25, 2012
 .Dt HAST.CONF 5
@@ -37,7 +37,7 @@
 .Xr hastd 8
 daemon and the
 .Xr hastctl 8
-utility.
+utility
 .Sh DESCRIPTION
 The
 .Nm
@@ -63,7 +63,7 @@
 compression <algorithm>
 timeout <seconds>
 exec <path>
-metaflush "on" | "off"
+metaflush on | off
 pidfile <path>
 
 on <node> {
@@ -89,14 +89,14 @@
 	local <path>
 	timeout <seconds>
 	exec <path>
-	metaflush "on" | "off"
+	metaflush on | off
 
 	on <node> {
 		# Resource-node section
 		name <name>
 		# Required
 		local <path>
-		metaflush "on" | "off"
+		metaflush on | off
 		# Required
 		remote <addr>
 		source <addr>
@@ -106,7 +106,7 @@
 		name <name>
 		# Required
 		local <path>
-		metaflush "on" | "off"
+		metaflush on | off
 		# Required
 		remote <addr>
 		source <addr>
@@ -439,7 +439,7 @@
 .Xr gethostname 3 ,
 .Xr geom 4 ,
 .Xr hastctl 8 ,
-.Xr hastd 8 .
+.Xr hastd 8
 .Sh AUTHORS
 The
 .Nm
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/hast.h
--- a/head/sbin/hastd/hast.h	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/hast.h	Wed Jul 25 16:24:55 2012 +0300
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/hastd/hast.h 226463 2011-10-17 12:22:09Z pjd $
+ * $FreeBSD: head/sbin/hastd/hast.h 235789 2012-05-22 16:33:10Z bapt $
  */
 
 #ifndef	_HAST_H_
@@ -244,6 +244,5 @@
 
 void yyerror(const char *);
 int yylex(void);
-int yyparse(void);
 
 #endif	/* !_HAST_H_ */
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/hastd.8
--- a/head/sbin/hastd/hastd.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/hastd.8	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD$
+.\" $FreeBSD: head/sbin/hastd/hastd.8 235873 2012-05-24 02:24:03Z wblock $
 .\"
 .Dd February 1, 2010
 .Dt HASTD 8
@@ -223,7 +223,7 @@
 .Xr hastctl 8 ,
 .Xr mount 8 ,
 .Xr newfs 8 ,
-.Xr g_bio 9 .
+.Xr g_bio 9
 .Sh AUTHORS
 The
 .Nm
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/parse.y
--- a/head/sbin/hastd/parse.y	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/parse.y	Wed Jul 25 16:24:55 2012 +0300
@@ -28,7 +28,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/hastd/parse.y 230976 2012-02-04 07:59:12Z pjd $
+ * $FreeBSD: head/sbin/hastd/parse.y 235789 2012-05-22 16:33:10Z bapt $
  */
 
 #include <sys/param.h>	/* MAXHOSTNAMELEN */
@@ -77,296 +77,9 @@
 
 extern void yyrestart(FILE *);
 
-static int
-isitme(const char *name)
-{
-	char buf[MAXHOSTNAMELEN];
-	char *pos;
-	size_t bufsize;
-
-	/*
-	 * First check if the given name matches our full hostname.
-	 */
-	if (gethostname(buf, sizeof(buf)) < 0) {
-		pjdlog_errno(LOG_ERR, "gethostname() failed");
-		return (-1);
-	}
-	if (strcmp(buf, name) == 0)
-		return (1);
-
-	/*
-	 * Now check if it matches first part of the host name.
-	 */
-	pos = strchr(buf, '.');
-	if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
-	    strncmp(buf, name, pos - buf) == 0) {
-		return (1);
-	}
-
-	/*
-	 * At the end check if name is equal to our host's UUID.
-	 */
-	bufsize = sizeof(buf);
-	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
-		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
-		return (-1);
-	}
-	if (strcasecmp(buf, name) == 0)
-		return (1);
-
-	/*
-	 * Looks like this isn't about us.
-	 */
-	return (0);
-}
-
-static bool
-family_supported(int family)
-{
-	int sock;
-
-	sock = socket(family, SOCK_STREAM, 0);
-	if (sock == -1 && errno == EPROTONOSUPPORT)
-		return (false);
-	if (sock >= 0)
-		(void)close(sock);
-	return (true);
-}
-
-static int
-node_names(char **namesp)
-{
-	static char names[MAXHOSTNAMELEN * 3];
-	char buf[MAXHOSTNAMELEN];
-	char *pos;
-	size_t bufsize;
-
-	if (gethostname(buf, sizeof(buf)) < 0) {
-		pjdlog_errno(LOG_ERR, "gethostname() failed");
-		return (-1);
-	}
-
-	/* First component of the host name. */
-	pos = strchr(buf, '.');
-	if (pos != NULL && pos != buf) {
-		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
-		    sizeof(names)));
-		(void)strlcat(names, ", ", sizeof(names));
-	}
-
-	/* Full host name. */
-	(void)strlcat(names, buf, sizeof(names));
-	(void)strlcat(names, ", ", sizeof(names));
-
-	/* Host UUID. */
-	bufsize = sizeof(buf);
-	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
-		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
-		return (-1);
-	}
-	(void)strlcat(names, buf, sizeof(names));
-
-	*namesp = names;
-
-	return (0);
-}
-
-void
-yyerror(const char *str)
-{
-
-	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
-	    lineno, yytext, str);
-}
-
-struct hastd_config *
-yy_config_parse(const char *config, bool exitonerror)
-{
-	int ret;
-
-	curres = NULL;
-	mynode = false;
-	depth = 0;
-	lineno = 0;
-
-	depth0_timeout = HAST_TIMEOUT;
-	depth0_replication = HAST_REPLICATION_FULLSYNC;
-	depth0_checksum = HAST_CHECKSUM_NONE;
-	depth0_compression = HAST_COMPRESSION_HOLE;
-	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
-	strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile));
-	TAILQ_INIT(&depth0_listen);
-	strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4,
-	    sizeof(depth0_listen_tcp4));
-	strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6,
-	    sizeof(depth0_listen_tcp6));
-	depth0_exec[0] = '\0';
-	depth0_metaflush = 1;
-
-	lconfig = calloc(1, sizeof(*lconfig));
-	if (lconfig == NULL) {
-		pjdlog_error("Unable to allocate memory for configuration.");
-		if (exitonerror)
-			exit(EX_TEMPFAIL);
-		return (NULL);
-	}
-
-	TAILQ_INIT(&lconfig->hc_listen);
-	TAILQ_INIT(&lconfig->hc_resources);
-
-	yyin = fopen(config, "r");
-	if (yyin == NULL) {
-		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
-		    config);
-		yy_config_free(lconfig);
-		if (exitonerror)
-			exit(EX_OSFILE);
-		return (NULL);
-	}
-	yyrestart(yyin);
-	ret = yyparse();
-	fclose(yyin);
-	if (ret != 0) {
-		yy_config_free(lconfig);
-		if (exitonerror)
-			exit(EX_CONFIG);
-		return (NULL);
-	}
-
-	/*
-	 * Let's see if everything is set up.
-	 */
-	if (lconfig->hc_controladdr[0] == '\0') {
-		strlcpy(lconfig->hc_controladdr, depth0_control,
-		    sizeof(lconfig->hc_controladdr));
-	}
-	if (lconfig->hc_pidfile[0] == '\0') {
-		strlcpy(lconfig->hc_pidfile, depth0_pidfile,
-		    sizeof(lconfig->hc_pidfile));
-	}
-	if (!TAILQ_EMPTY(&depth0_listen))
-		TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
-	if (TAILQ_EMPTY(&lconfig->hc_listen)) {
-		struct hastd_listen *lst;
-
-		if (family_supported(AF_INET)) {
-			lst = calloc(1, sizeof(*lst));
-			if (lst == NULL) {
-				pjdlog_error("Unable to allocate memory for listen address.");
-				yy_config_free(lconfig);
-				if (exitonerror)
-					exit(EX_TEMPFAIL);
-				return (NULL);
-			}
-			(void)strlcpy(lst->hl_addr, depth0_listen_tcp4,
-			    sizeof(lst->hl_addr));
-			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
-		} else {
-			pjdlog_debug(1,
-			    "No IPv4 support in the kernel, not listening on IPv4 address.");
-		}
-		if (family_supported(AF_INET6)) {
-			lst = calloc(1, sizeof(*lst));
-			if (lst == NULL) {
-				pjdlog_error("Unable to allocate memory for listen address.");
-				yy_config_free(lconfig);
-				if (exitonerror)
-					exit(EX_TEMPFAIL);
-				return (NULL);
-			}
-			(void)strlcpy(lst->hl_addr, depth0_listen_tcp6,
-			    sizeof(lst->hl_addr));
-			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
-		} else {
-			pjdlog_debug(1,
-			    "No IPv6 support in the kernel, not listening on IPv6 address.");
-		}
-		if (TAILQ_EMPTY(&lconfig->hc_listen)) {
-			pjdlog_error("No address to listen on.");
-			yy_config_free(lconfig);
-			if (exitonerror)
-				exit(EX_TEMPFAIL);
-			return (NULL);
-		}
-	}
-	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
-		PJDLOG_ASSERT(curres->hr_provname[0] != '\0');
-		PJDLOG_ASSERT(curres->hr_localpath[0] != '\0');
-		PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0');
-
-		if (curres->hr_replication == -1) {
-			/*
-			 * Replication is not set at resource-level.
-			 * 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;
-		}
-		if (curres->hr_checksum == -1) {
-			/*
-			 * Checksum is not set at resource-level.
-			 * Use global or default setting.
-			 */
-			curres->hr_checksum = depth0_checksum;
-		}
-		if (curres->hr_compression == -1) {
-			/*
-			 * Compression is not set at resource-level.
-			 * Use global or default setting.
-			 */
-			curres->hr_compression = depth0_compression;
-		}
-		if (curres->hr_timeout == -1) {
-			/*
-			 * Timeout is not set at resource-level.
-			 * Use global or default setting.
-			 */
-			curres->hr_timeout = depth0_timeout;
-		}
-		if (curres->hr_exec[0] == '\0') {
-			/*
-			 * Exec is not set at resource-level.
-			 * Use global or default setting.
-			 */
-			strlcpy(curres->hr_exec, depth0_exec,
-			    sizeof(curres->hr_exec));
-		}
-		if (curres->hr_metaflush == -1) {
-			/*
-			 * Metaflush is not set at resource-level.
-			 * Use global or default setting.
-			 */
-			curres->hr_metaflush = depth0_metaflush;
-		}
-	}
-
-	return (lconfig);
-}
-
-void
-yy_config_free(struct hastd_config *config)
-{
-	struct hastd_listen *lst;
-	struct hast_resource *res;
-
-	while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
-		TAILQ_REMOVE(&depth0_listen, lst, hl_next);
-		free(lst);
-	}
-	while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
-		TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
-		free(lst);
-	}
-	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
-		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
-		free(res);
-	}
-	free(config);
-}
+static int isitme(const char *name);
+static bool family_supported(int family);
+static int node_names(char **namesp);
 %}
 
 %token CONTROL PIDFILE LISTEN REPLICATION CHECKSUM COMPRESSION METAFLUSH
@@ -1004,3 +717,296 @@
 		free($2);
 	}
 	;
+
+%%
+
+static int
+isitme(const char *name)
+{
+	char buf[MAXHOSTNAMELEN];
+	char *pos;
+	size_t bufsize;
+
+	/*
+	 * First check if the given name matches our full hostname.
+	 */
+	if (gethostname(buf, sizeof(buf)) < 0) {
+		pjdlog_errno(LOG_ERR, "gethostname() failed");
+		return (-1);
+	}
+	if (strcmp(buf, name) == 0)
+		return (1);
+
+	/*
+	 * Now check if it matches first part of the host name.
+	 */
+	pos = strchr(buf, '.');
+	if (pos != NULL && (size_t)(pos - buf) == strlen(name) &&
+	    strncmp(buf, name, pos - buf) == 0) {
+		return (1);
+	}
+
+	/*
+	 * At the end check if name is equal to our host's UUID.
+	 */
+	bufsize = sizeof(buf);
+	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
+		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
+		return (-1);
+	}
+	if (strcasecmp(buf, name) == 0)
+		return (1);
+
+	/*
+	 * Looks like this isn't about us.
+	 */
+	return (0);
+}
+
+static bool
+family_supported(int family)
+{
+	int sock;
+
+	sock = socket(family, SOCK_STREAM, 0);
+	if (sock == -1 && errno == EPROTONOSUPPORT)
+		return (false);
+	if (sock >= 0)
+		(void)close(sock);
+	return (true);
+}
+
+static int
+node_names(char **namesp)
+{
+	static char names[MAXHOSTNAMELEN * 3];
+	char buf[MAXHOSTNAMELEN];
+	char *pos;
+	size_t bufsize;
+
+	if (gethostname(buf, sizeof(buf)) < 0) {
+		pjdlog_errno(LOG_ERR, "gethostname() failed");
+		return (-1);
+	}
+
+	/* First component of the host name. */
+	pos = strchr(buf, '.');
+	if (pos != NULL && pos != buf) {
+		(void)strlcpy(names, buf, MIN((size_t)(pos - buf + 1),
+		    sizeof(names)));
+		(void)strlcat(names, ", ", sizeof(names));
+	}
+
+	/* Full host name. */
+	(void)strlcat(names, buf, sizeof(names));
+	(void)strlcat(names, ", ", sizeof(names));
+
+	/* Host UUID. */
+	bufsize = sizeof(buf);
+	if (sysctlbyname("kern.hostuuid", buf, &bufsize, NULL, 0) < 0) {
+		pjdlog_errno(LOG_ERR, "sysctlbyname(kern.hostuuid) failed");
+		return (-1);
+	}
+	(void)strlcat(names, buf, sizeof(names));
+
+	*namesp = names;
+
+	return (0);
+}
+
+void
+yyerror(const char *str)
+{
+
+	pjdlog_error("Unable to parse configuration file at line %d near '%s': %s",
+	    lineno, yytext, str);
+}
+
+struct hastd_config *
+yy_config_parse(const char *config, bool exitonerror)
+{
+	int ret;
+
+	curres = NULL;
+	mynode = false;
+	depth = 0;
+	lineno = 0;
+
+	depth0_timeout = HAST_TIMEOUT;
+	depth0_replication = HAST_REPLICATION_FULLSYNC;
+	depth0_checksum = HAST_CHECKSUM_NONE;
+	depth0_compression = HAST_COMPRESSION_HOLE;
+	strlcpy(depth0_control, HAST_CONTROL, sizeof(depth0_control));
+	strlcpy(depth0_pidfile, HASTD_PIDFILE, sizeof(depth0_pidfile));
+	TAILQ_INIT(&depth0_listen);
+	strlcpy(depth0_listen_tcp4, HASTD_LISTEN_TCP4,
+	    sizeof(depth0_listen_tcp4));
+	strlcpy(depth0_listen_tcp6, HASTD_LISTEN_TCP6,
+	    sizeof(depth0_listen_tcp6));
+	depth0_exec[0] = '\0';
+	depth0_metaflush = 1;
+
+	lconfig = calloc(1, sizeof(*lconfig));
+	if (lconfig == NULL) {
+		pjdlog_error("Unable to allocate memory for configuration.");
+		if (exitonerror)
+			exit(EX_TEMPFAIL);
+		return (NULL);
+	}
+
+	TAILQ_INIT(&lconfig->hc_listen);
+	TAILQ_INIT(&lconfig->hc_resources);
+
+	yyin = fopen(config, "r");
+	if (yyin == NULL) {
+		pjdlog_errno(LOG_ERR, "Unable to open configuration file %s",
+		    config);
+		yy_config_free(lconfig);
+		if (exitonerror)
+			exit(EX_OSFILE);
+		return (NULL);
+	}
+	yyrestart(yyin);
+	ret = yyparse();
+	fclose(yyin);
+	if (ret != 0) {
+		yy_config_free(lconfig);
+		if (exitonerror)
+			exit(EX_CONFIG);
+		return (NULL);
+	}
+
+	/*
+	 * Let's see if everything is set up.
+	 */
+	if (lconfig->hc_controladdr[0] == '\0') {
+		strlcpy(lconfig->hc_controladdr, depth0_control,
+		    sizeof(lconfig->hc_controladdr));
+	}
+	if (lconfig->hc_pidfile[0] == '\0') {
+		strlcpy(lconfig->hc_pidfile, depth0_pidfile,
+		    sizeof(lconfig->hc_pidfile));
+	}
+	if (!TAILQ_EMPTY(&depth0_listen))
+		TAILQ_CONCAT(&lconfig->hc_listen, &depth0_listen, hl_next);
+	if (TAILQ_EMPTY(&lconfig->hc_listen)) {
+		struct hastd_listen *lst;
+
+		if (family_supported(AF_INET)) {
+			lst = calloc(1, sizeof(*lst));
+			if (lst == NULL) {
+				pjdlog_error("Unable to allocate memory for listen address.");
+				yy_config_free(lconfig);
+				if (exitonerror)
+					exit(EX_TEMPFAIL);
+				return (NULL);
+			}
+			(void)strlcpy(lst->hl_addr, depth0_listen_tcp4,
+			    sizeof(lst->hl_addr));
+			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
+		} else {
+			pjdlog_debug(1,
+			    "No IPv4 support in the kernel, not listening on IPv4 address.");
+		}
+		if (family_supported(AF_INET6)) {
+			lst = calloc(1, sizeof(*lst));
+			if (lst == NULL) {
+				pjdlog_error("Unable to allocate memory for listen address.");
+				yy_config_free(lconfig);
+				if (exitonerror)
+					exit(EX_TEMPFAIL);
+				return (NULL);
+			}
+			(void)strlcpy(lst->hl_addr, depth0_listen_tcp6,
+			    sizeof(lst->hl_addr));
+			TAILQ_INSERT_TAIL(&lconfig->hc_listen, lst, hl_next);
+		} else {
+			pjdlog_debug(1,
+			    "No IPv6 support in the kernel, not listening on IPv6 address.");
+		}
+		if (TAILQ_EMPTY(&lconfig->hc_listen)) {
+			pjdlog_error("No address to listen on.");
+			yy_config_free(lconfig);
+			if (exitonerror)
+				exit(EX_TEMPFAIL);
+			return (NULL);
+		}
+	}
+	TAILQ_FOREACH(curres, &lconfig->hc_resources, hr_next) {
+		PJDLOG_ASSERT(curres->hr_provname[0] != '\0');
+		PJDLOG_ASSERT(curres->hr_localpath[0] != '\0');
+		PJDLOG_ASSERT(curres->hr_remoteaddr[0] != '\0');
+
+		if (curres->hr_replication == -1) {
+			/*
+			 * Replication is not set at resource-level.
+			 * 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;
+		}
+		if (curres->hr_checksum == -1) {
+			/*
+			 * Checksum is not set at resource-level.
+			 * Use global or default setting.
+			 */
+			curres->hr_checksum = depth0_checksum;
+		}
+		if (curres->hr_compression == -1) {
+			/*
+			 * Compression is not set at resource-level.
+			 * Use global or default setting.
+			 */
+			curres->hr_compression = depth0_compression;
+		}
+		if (curres->hr_timeout == -1) {
+			/*
+			 * Timeout is not set at resource-level.
+			 * Use global or default setting.
+			 */
+			curres->hr_timeout = depth0_timeout;
+		}
+		if (curres->hr_exec[0] == '\0') {
+			/*
+			 * Exec is not set at resource-level.
+			 * Use global or default setting.
+			 */
+			strlcpy(curres->hr_exec, depth0_exec,
+			    sizeof(curres->hr_exec));
+		}
+		if (curres->hr_metaflush == -1) {
+			/*
+			 * Metaflush is not set at resource-level.
+			 * Use global or default setting.
+			 */
+			curres->hr_metaflush = depth0_metaflush;
+		}
+	}
+
+	return (lconfig);
+}
+
+void
+yy_config_free(struct hastd_config *config)
+{
+	struct hastd_listen *lst;
+	struct hast_resource *res;
+
+	while ((lst = TAILQ_FIRST(&depth0_listen)) != NULL) {
+		TAILQ_REMOVE(&depth0_listen, lst, hl_next);
+		free(lst);
+	}
+	while ((lst = TAILQ_FIRST(&config->hc_listen)) != NULL) {
+		TAILQ_REMOVE(&config->hc_listen, lst, hl_next);
+		free(lst);
+	}
+	while ((res = TAILQ_FIRST(&config->hc_resources)) != NULL) {
+		TAILQ_REMOVE(&config->hc_resources, res, hr_next);
+		free(res);
+	}
+	free(config);
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/primary.c
--- a/head/sbin/hastd/primary.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/primary.c	Wed Jul 25 16:24:55 2012 +0300
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/hastd/primary.c 231016 2012-02-05 15:23:32Z trociny $");
+__FBSDID("$FreeBSD: head/sbin/hastd/primary.c 238120 2012-07-04 20:20:48Z pjd $");
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -543,6 +543,27 @@
 
 	return (0);
 }
+ 
+/*
+ * Function instructs GEOM_GATE to handle reads directly from within the kernel.
+ */
+static void
+enable_direct_reads(struct hast_resource *res)
+{
+	struct g_gate_ctl_modify ggiomodify;
+
+	bzero(&ggiomodify, sizeof(ggiomodify));
+	ggiomodify.gctl_version = G_GATE_VERSION;
+	ggiomodify.gctl_unit = res->hr_ggateunit;
+	ggiomodify.gctl_modify = GG_MODIFY_READPROV | GG_MODIFY_READOFFSET;
+	strlcpy(ggiomodify.gctl_readprov, res->hr_localpath,
+	    sizeof(ggiomodify.gctl_readprov));
+	ggiomodify.gctl_readoffset = res->hr_localoff;
+	if (ioctl(res->hr_ggatefd, G_GATE_CMD_MODIFY, &ggiomodify) == 0)
+		pjdlog_debug(1, "Direct reads enabled.");
+	else
+		pjdlog_errno(LOG_WARNING, "Failed to enable direct reads");
+}
 
 static int
 init_remote(struct hast_resource *res, struct proto_conn **inp,
@@ -692,6 +713,8 @@
 	res->hr_secondary_localcnt = nv_get_uint64(nvin, "localcnt");
 	res->hr_secondary_remotecnt = nv_get_uint64(nvin, "remotecnt");
 	res->hr_syncsrc = nv_get_uint8(nvin, "syncsrc");
+	if (res->hr_syncsrc == HAST_SYNCSRC_PRIMARY)
+		enable_direct_reads(res);
 	if (nv_exists(nvin, "virgin")) {
 		/*
 		 * Secondary was reinitialized, bump localcnt if it is 0 as
@@ -990,36 +1013,33 @@
 {
 	char msg[1024];
 	va_list ap;
-	int len;
 
 	va_start(ap, fmt);
-	len = vsnprintf(msg, sizeof(msg), fmt, ap);
+	(void)vsnprintf(msg, sizeof(msg), fmt, ap);
 	va_end(ap);
-	if ((size_t)len < sizeof(msg)) {
-		switch (ggio->gctl_cmd) {
-		case BIO_READ:
-			(void)snprintf(msg + len, sizeof(msg) - len,
-			    "READ(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
-			    (uintmax_t)ggio->gctl_length);
-			break;
-		case BIO_DELETE:
-			(void)snprintf(msg + len, sizeof(msg) - len,
-			    "DELETE(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
-			    (uintmax_t)ggio->gctl_length);
-			break;
-		case BIO_FLUSH:
-			(void)snprintf(msg + len, sizeof(msg) - len, "FLUSH.");
-			break;
-		case BIO_WRITE:
-			(void)snprintf(msg + len, sizeof(msg) - len,
-			    "WRITE(%ju, %ju).", (uintmax_t)ggio->gctl_offset,
-			    (uintmax_t)ggio->gctl_length);
-			break;
-		default:
-			(void)snprintf(msg + len, sizeof(msg) - len,
-			    "UNKNOWN(%u).", (unsigned int)ggio->gctl_cmd);
-			break;
-		}
+	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);
+		break;
+	case BIO_DELETE:
+		(void)snprlcat(msg, sizeof(msg), "DELETE(%ju, %ju).",
+		    (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);
+		break;
+	default:
+		(void)snprlcat(msg, sizeof(msg), "UNKNOWN(%u).",
+		    (unsigned int)ggio->gctl_cmd);
+		break;
 	}
 	pjdlog_common(loglevel, debuglevel, -1, "%s", msg);
 }
@@ -1792,13 +1812,14 @@
 	struct timeval tstart, tend, tdiff;
 	unsigned int ii, ncomp, ncomps;
 	off_t offset, length, synced;
-	bool dorewind;
+	bool dorewind, directreads;
 	int syncext;
 
 	ncomps = HAST_NCOMPONENTS;
 	dorewind = true;
 	synced = 0;
 	offset = -1;
+	directreads = false;
 
 	for (;;) {
 		mtx_lock(&sync_lock);
@@ -1870,6 +1891,8 @@
 					event_send(res, EVENT_SYNCDONE);
 				}
 				mtx_lock(&metadata_lock);
+				if (res->hr_syncsrc == HAST_SYNCSRC_SECONDARY)
+					directreads = true;
 				res->hr_syncsrc = HAST_SYNCSRC_UNDEF;
 				res->hr_primary_localcnt =
 				    res->hr_secondary_remotecnt;
@@ -1883,6 +1906,10 @@
 				mtx_unlock(&metadata_lock);
 			}
 			rw_unlock(&hio_remote_lock[ncomp]);
+			if (directreads) {
+				directreads = false;
+				enable_direct_reads(res);
+			}
 			continue;
 		}
 		pjdlog_debug(2, "sync: Taking free request.");
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/proto_common.c
--- a/head/sbin/hastd/proto_common.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/proto_common.c	Wed Jul 25 16:24:55 2012 +0300
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/hastd/proto_common.c 229945 2012-01-10 22:39:07Z pjd $");
+__FBSDID("$FreeBSD: head/sbin/hastd/proto_common.c 237931 2012-07-01 16:26:07Z pjd $");
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -181,7 +181,7 @@
 		return (errno);
 
 	cmsg = CMSG_FIRSTHDR(&msg);
-	if (cmsg->cmsg_level != SOL_SOCKET ||
+	if (cmsg == NULL || cmsg->cmsg_level != SOL_SOCKET ||
 	    cmsg->cmsg_type != SCM_RIGHTS) {
 		return (EINVAL);
 	}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/hastd/synch.h
--- a/head/sbin/hastd/synch.h	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/hastd/synch.h	Wed Jul 25 16:24:55 2012 +0300
@@ -26,7 +26,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/hastd/synch.h 225787 2011-09-27 08:50:37Z pjd $
+ * $FreeBSD: head/sbin/hastd/synch.h 236919 2012-06-11 20:27:52Z hselasky $
  */
 
 #ifndef	_SYNCH_H_
@@ -168,7 +168,7 @@
 		return (false);
 	}
 
-        error = clock_gettime(CLOCK_MONOTONIC, &ts);
+	error = clock_gettime(CLOCK_MONOTONIC, &ts);
 	PJDLOG_ASSERT(error == 0);
 	ts.tv_sec += timeout;
 	error = pthread_cond_timedwait(cv, lock, &ts);
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ifconfig/af_inet6.c
--- a/head/sbin/ifconfig/af_inet6.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ifconfig/af_inet6.c	Wed Jul 25 16:24:55 2012 +0300
@@ -29,7 +29,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: head/sbin/ifconfig/af_inet6.c 228571 2011-12-16 12:16:56Z glebius $";
+  "$FreeBSD: head/sbin/ifconfig/af_inet6.c 238273 2012-07-09 06:21:46Z hrs $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -509,8 +509,6 @@
 	DEF_CMD("-ifdisabled",	-ND6_IFF_IFDISABLED,	setnd6flags),
 	DEF_CMD("nud",		ND6_IFF_PERFORMNUD,	setnd6flags),
 	DEF_CMD("-nud",		-ND6_IFF_PERFORMNUD,	setnd6flags),
-	DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE,	setnd6flags),
-	DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags),
 	DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
 	DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
 	DEF_CMD_ARG("pltime",        			setip6pltime),
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ifconfig/af_nd6.c
--- a/head/sbin/ifconfig/af_nd6.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ifconfig/af_nd6.c	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: head/sbin/ifconfig/af_nd6.c 222728 2011-06-06 02:14:23Z hrs $";
+  "$FreeBSD: head/sbin/ifconfig/af_nd6.c 235285 2012-05-11 20:01:45Z hrs $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -148,12 +148,14 @@
 	memset(&nd, 0, sizeof(nd));
 	strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
 	if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
-		warn("socket(AF_INET6, SOCK_DGRAM)");
+		if (errno != EPROTONOSUPPORT)
+			warn("socket(AF_INET6, SOCK_DGRAM)");
 		return;
 	}
 	error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
 	if (error) {
-		warn("ioctl(SIOCGIFINFO_IN6)");
+		if (errno != EPFNOSUPPORT)
+			warn("ioctl(SIOCGIFINFO_IN6)");
 		close(s6);
 		return;
 	}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ifconfig/ifconfig.8
--- a/head/sbin/ifconfig/ifconfig.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ifconfig/ifconfig.8	Wed Jul 25 16:24:55 2012 +0300
@@ -26,9 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     From: @(#)ifconfig.8	8.3 (Berkeley) 1/5/94
-.\" $FreeBSD: head/sbin/ifconfig/ifconfig.8 233993 2012-04-07 09:11:07Z joel $
+.\" $FreeBSD: head/sbin/ifconfig/ifconfig.8 238273 2012-07-09 06:21:46Z hrs $
 .\"
-.Dd April 3, 2012
+.Dd July 9, 2012
 .Dt IFCONFIG 8
 .Os
 .Sh NAME
@@ -372,16 +372,32 @@
 .It Cm name Ar name
 Set the interface name to
 .Ar name .
-.It Cm rxcsum , txcsum
+.It Cm rxcsum , txcsum , rxcsum6 , txcsum6
 If the driver supports user-configurable checksum offloading,
 enable receive (or transmit) checksum offloading on the interface.
+The feature can be turned on selectively per protocol family.
+Use
+.Cm rxcsum6 , txcsum6
+for
+.Xr ip6 4
+or
+.Cm rxcsum , txcsum
+otherwise.
 Some drivers may not be able to enable these flags independently
 of each other, so setting one may also set the other.
 The driver will offload as much checksum work as it can reliably
 support, the exact level of offloading varies between drivers.
-.It Fl rxcsum , txcsum
+.It Fl rxcsum , txcsum , rxcsum6 , txcsum6
 If the driver supports user-configurable checksum offloading,
 disable receive (or transmit) checksum offloading on the interface.
+The feature can be turned off selectively per protocol family.
+Use
+.Fl rxcsum6 , txcsum6
+for
+.Xr ip6 4
+or
+.Fl rxcsum , txcsum
+otherwise.
 These settings may not always be independent of each other.
 .It Cm tso
 If the driver supports
@@ -400,6 +416,22 @@
 .Xr ip 4
 and
 .Xr ip6 4 .
+.It Cm tso6 , tso4
+If the driver supports
+.Xr tcp 4
+segmentation offloading for
+.Xr ip6 4
+or
+.Xr ip 4
+use one of these to selectively enabled it only for one protocol family.
+.It Fl tso6 , tso4
+If the driver supports
+.Xr tcp 4
+segmentation offloading for
+.Xr ip6 4
+or
+.Xr ip 4
+use one of these to selectively disable it only for one protocol family.
 .It Cm lro
 If the driver supports
 .Xr tcp 4
@@ -684,12 +716,6 @@
 .It Cm -nud
 Clear a flag
 .Cm nud .
-.It Cm prefer_source
-Set a flag to prefer addresses on the interface as candidates of the
-source address for outgoing packets.
-.It Cm -prefer_source
-Clear a flag
-.Cm prefer_source .
 .El
 .Pp
 The following parameters are specific to cloning
@@ -1979,6 +2005,12 @@
 By default
 .Cm meshforward
 is enabled.
+.It Cm meshgate
+This attribute specifies whether or not the mesh STA activates mesh gate
+announcements.
+By default
+.Cm meshgate
+is disabled.
 .It Cm meshmetric Ar protocol
 Set the specified
 .Ar protocol
@@ -2013,7 +2045,7 @@
 Nodes on the mesh without a path to this root mesh station with try to
 discover a path to us.
 .It Cm PROACTIVE
-Send broadcast path requests every two seconds and every node must reply with
+Send broadcast path requests every two seconds and every node must reply
 with a path reply even if it already has a path to this root mesh station.
 .It Cm RANN
 Send broadcast root announcement (RANN) frames.
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ifconfig/ifconfig.c
--- a/head/sbin/ifconfig/ifconfig.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ifconfig/ifconfig.c	Wed Jul 25 16:24:55 2012 +0300
@@ -38,7 +38,7 @@
 static char sccsid[] = "@(#)ifconfig.c	8.2 (Berkeley) 2/16/94";
 #endif
 static const char rcsid[] =
-  "$FreeBSD: head/sbin/ifconfig/ifconfig.c 231642 2012-02-14 07:14:42Z rmh $";
+  "$FreeBSD: head/sbin/ifconfig/ifconfig.c 237263 2012-06-19 07:34:13Z np $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -916,7 +916,8 @@
 #define	IFCAPBITS \
 "\020\1RXCSUM\2TXCSUM\3NETCONS\4VLAN_MTU\5VLAN_HWTAGGING\6JUMBO_MTU\7POLLING" \
 "\10VLAN_HWCSUM\11TSO4\12TSO6\13LRO\14WOL_UCAST\15WOL_MCAST\16WOL_MAGIC" \
-"\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP"
+"\17TOE4\20TOE6\21VLAN_HWFILTER\23VLAN_HWTSO\24LINKSTATE\25NETMAP" \
+"\26RXCSUM_IPV6\27TXCSUM_IPV6"
 
 /*
  * Print the status of the interface.  If an address family was
@@ -1193,6 +1194,10 @@
 	DEF_CMD("-monitor",	-IFF_MONITOR,	setifflags),
 	DEF_CMD("staticarp",	IFF_STATICARP,	setifflags),
 	DEF_CMD("-staticarp",	-IFF_STATICARP,	setifflags),
+	DEF_CMD("rxcsum6",	IFCAP_RXCSUM_IPV6,	setifcap),
+	DEF_CMD("-rxcsum6",	-IFCAP_RXCSUM_IPV6,	setifcap),
+	DEF_CMD("txcsum6",	IFCAP_TXCSUM_IPV6,	setifcap),
+	DEF_CMD("-txcsum6",	-IFCAP_TXCSUM_IPV6,	setifcap),
 	DEF_CMD("rxcsum",	IFCAP_RXCSUM,	setifcap),
 	DEF_CMD("-rxcsum",	-IFCAP_RXCSUM,	setifcap),
 	DEF_CMD("txcsum",	IFCAP_TXCSUM,	setifcap),
@@ -1201,8 +1206,14 @@
 	DEF_CMD("-netcons",	-IFCAP_NETCONS,	setifcap),
 	DEF_CMD("polling",	IFCAP_POLLING,	setifcap),
 	DEF_CMD("-polling",	-IFCAP_POLLING,	setifcap),
+	DEF_CMD("tso6",		IFCAP_TSO6,	setifcap),
+	DEF_CMD("-tso6",	-IFCAP_TSO6,	setifcap),
+	DEF_CMD("tso4",		IFCAP_TSO4,	setifcap),
+	DEF_CMD("-tso4",	-IFCAP_TSO4,	setifcap),
 	DEF_CMD("tso",		IFCAP_TSO,	setifcap),
 	DEF_CMD("-tso",		-IFCAP_TSO,	setifcap),
+	DEF_CMD("toe",		IFCAP_TOE,	setifcap),
+	DEF_CMD("-toe",		-IFCAP_TOE,	setifcap),
 	DEF_CMD("lro",		IFCAP_LRO,	setifcap),
 	DEF_CMD("-lro",		-IFCAP_LRO,	setifcap),
 	DEF_CMD("wol",		IFCAP_WOL,	setifcap),
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ifconfig/ifieee80211.c
--- a/head/sbin/ifconfig/ifieee80211.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ifconfig/ifieee80211.c	Wed Jul 25 16:24:55 2012 +0300
@@ -24,7 +24,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 233382 2012-03-23 18:12:25Z bschmidt $
+ * $FreeBSD: head/sbin/ifconfig/ifieee80211.c 234895 2012-05-01 16:17:17Z monthadar $
  */
 
 /*-
@@ -1883,6 +1883,12 @@
 }
 
 static
+DECL_CMD_FUNC(set80211meshgate, val, d)
+{
+	set80211(s, IEEE80211_IOC_MESH_GATE, d, 0, NULL);
+}
+
+static
 DECL_CMD_FUNC(set80211meshpeering, val, d)
 {
 	set80211(s, IEEE80211_IOC_MESH_AP, d, 0, NULL);
@@ -4014,6 +4020,8 @@
 			ether_ntoa((const struct ether_addr *)rt->imr_nexthop),
 			rt->imr_nhops, rt->imr_metric, rt->imr_lifetime,
 			rt->imr_lastmseq,
+			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_DISCOVER) ?
+			    'D' :
 			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_VALID) ?
 			    'V' : '!',
 			(rt->imr_flags & IEEE80211_MESHRT_FLAGS_PROXY) ?
@@ -4832,6 +4840,12 @@
 			else
 				LINE_CHECK("-meshforward");
 		}
+		if (get80211val(s, IEEE80211_IOC_MESH_GATE, &val) != -1) {
+			if (val)
+				LINE_CHECK("meshgate");
+			else
+				LINE_CHECK("-meshgate");
+		}
 		if (get80211len(s, IEEE80211_IOC_MESH_PR_METRIC, data, 12,
 		    &len) != -1) {
 			data[len] = '\0';
@@ -5271,6 +5285,8 @@
 	DEF_CMD_ARG("meshttl",		set80211meshttl),
 	DEF_CMD("meshforward",	1,	set80211meshforward),
 	DEF_CMD("-meshforward",	0,	set80211meshforward),
+	DEF_CMD("meshgate",	1,	set80211meshgate),
+	DEF_CMD("-meshgate",	0,	set80211meshgate),
 	DEF_CMD("meshpeering",	1,	set80211meshpeering),
 	DEF_CMD("-meshpeering",	0,	set80211meshpeering),
 	DEF_CMD_ARG("meshmetric",	set80211meshmetric),
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ifconfig/iflagg.c
--- a/head/sbin/ifconfig/iflagg.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ifconfig/iflagg.c	Wed Jul 25 16:24:55 2012 +0300
@@ -3,7 +3,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-  "$FreeBSD: head/sbin/ifconfig/iflagg.c 232629 2012-03-06 22:58:13Z thompsa $";
+  "$FreeBSD: head/sbin/ifconfig/iflagg.c 236178 2012-05-28 12:13:04Z rea $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -40,7 +40,8 @@
 	strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname));
 	strlcpy(rp.rp_portname, val, sizeof(rp.rp_portname));
 
-	if (ioctl(s, SIOCSLAGGPORT, &rp))
+	/* Don't choke if the port is already in this lagg. */
+	if (ioctl(s, SIOCSLAGGPORT, &rp) && errno != EEXIST)
 		err(1, "SIOCSLAGGPORT");
 }
 
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/init/init.c
--- a/head/sbin/init/init.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/init/init.c	Wed Jul 25 16:24:55 2012 +0300
@@ -41,7 +41,7 @@
 static char sccsid[] = "@(#)init.c	8.1 (Berkeley) 7/15/93";
 #endif
 static const char rcsid[] =
-  "$FreeBSD: head/sbin/init/init.c 233945 2012-04-06 13:06:01Z ed $";
+  "$FreeBSD: head/sbin/init/init.c 236020 2012-05-25 19:45:01Z jilles $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -646,8 +646,6 @@
 	if (Reboot) {
 		/* Instead of going single user, let's reboot the machine */
 		sync();
-		alarm(2);
-		pause();
 		reboot(howto);
 		_exit(0);
 	}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ipfw/ipfw.8
--- a/head/sbin/ipfw/ipfw.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ipfw/ipfw.8	Wed Jul 25 16:24:55 2012 +0300
@@ -1,7 +1,7 @@
 .\"
-.\" $FreeBSD: head/sbin/ipfw/ipfw.8 233648 2012-03-29 05:02:12Z eadler $
+.\" $FreeBSD: head/sbin/ipfw/ipfw.8 238540 2012-07-16 22:15:30Z issyl0 $
 .\"
-.Dd March 9, 2012
+.Dd July 16, 2012
 .Dt IPFW 8
 .Os
 .Sh NAME
@@ -560,7 +560,22 @@
 .Xr bpf 4
 attached to the
 .Li ipfw0
-pseudo interface. There is no overhead if no
+pseudo interface.
+This pseudo interface can be created after a boot
+manually by using the following command:
+.Bd -literal -offset indent
+# ifconfig ipfw0 create
+.Ed
+.Pp
+Or, automatically at boot time by adding the following
+line to the
+.Xr rc.conf 5
+file:
+.Bd -literal -offset indent
+firewall_logif="YES"
+.Ed
+.Pp
+There is no overhead if no
 .Xr bpf 4
 is attached to the pseudo interface.
 .Pp
@@ -1535,9 +1550,9 @@
 .It Cm recv | xmit | via Brq Ar ifX | Ar if Ns Cm * | Ar table Ns Pq Ar number Ns Op , Ns Ar value | Ar ipno | Ar any
 Matches packets received, transmitted or going through,
 respectively, the interface specified by exact name
-.Ns No ( Ar ifX Ns No ),
+.Po Ar ifX Pc ,
 by device name
-.Ns No ( Ar if Ns Ar * Ns No ),
+.Po Ar if* Pc ,
 by IP address, or through some interface.
 .Pp
 The
@@ -1733,7 +1748,7 @@
 Lookup tables are useful to handle large sparse sets of
 addresses or other search keys (e.g. ports, jail IDs, interface names).
 In the rest of this section we will use the term ``address''.
-There may be up to 4096 different lookup tables, numbered 0 to 4095.
+There may be up to 65535 different lookup tables, numbered 0 to 65534.
 .Pp
 Each entry is represented by an
 .Ar addr Ns Op / Ns Ar masklen
@@ -2218,19 +2233,20 @@
 The weight must be in the range 1..100, and defaults to 1.
 .El
 .Pp
-The following parameters can be configured for a scheduler:
+The following case-insensitive parameters can be configured for a
+scheduler:
 .Pp
 .Bl -tag -width indent -compact
-.It Cm type Ar {fifo | wf2qp | rr | qfq}
+.It Cm type Ar {fifo | wf2q+ | rr | qfq}
 specifies the scheduling algorithm to use.
 .Bl -tag -width indent -compact
-.It cm fifo
+.It Cm fifo
 is just a FIFO scheduler (which means that all packets
 are stored in the same queue as they arrive to the scheduler).
 FIFO has O(1) per-packet time complexity, with very low
 constants (estimate 60-80ns on a 2GHz desktop machine)
 but gives no service guarantees.
-.It Cm wf2qp
+.It Cm wf2q+
 implements the WF2Q+ algorithm, which is a Weighted Fair Queueing
 algorithm which permits flows to share bandwidth according to
 their weights. Note that weights are not priorities; even a flow
@@ -2951,9 +2967,11 @@
 those connection which start with a regular SYN packet coming
 from the inside of our network.
 Dynamic rules are checked when encountering the first
-.Cm check-state
+occurrence of a
+.Cm check-state ,
+.Cm keep-state
 or
-.Cm keep-state
+.Cm limit
 rule.
 A
 .Cm check-state
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/iscontrol/iscsi.conf.5
--- a/head/sbin/iscontrol/iscsi.conf.5	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/iscontrol/iscsi.conf.5	Wed Jul 25 16:24:55 2012 +0300
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/iscontrol/iscsi.conf.5 234233 2012-04-13 18:21:56Z jpaetzel $
+.\" $FreeBSD: head/sbin/iscontrol/iscsi.conf.5 235337 2012-05-12 15:08:22Z gjb $
 .\"
 .Dd June 5, 2007
 .Dt ISCSI.CONF 5
@@ -76,7 +76,7 @@
 is the name by which the target is known, not to be confused with
 target address, either obtained via the target administrator, or
 from a
-.Em discovery session.
+.Em discovery session .
 .It Cm InitiatorName
 if not specified, defaults to
 .Sy iqn.2005-01.il.ac.huji.cs:
@@ -146,7 +146,7 @@
 This value can only be reduced.
 .It Cm sockbufsize
 sets the receiver and transmitter socket buffer size to
-.Em size,
+.Em size ,
 in kilobytes.
 The default is 128.
 .El
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/mca/Makefile
--- a/head/sbin/mca/Makefile	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/mca/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -1,6 +1,5 @@
-# $FreeBSD$
+# $FreeBSD: head/sbin/mca/Makefile 236355 2012-05-31 08:22:02Z eadler $
 PROG=	mca
-WARNS?=	4
 MAN=	mca.8
 
 .include <bsd.prog.mk>
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/mca/mca.c
--- a/head/sbin/mca/mca.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/mca/mca.c	Wed Jul 25 16:24:55 2012 +0300
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sbin/mca/mca.c 236355 2012-05-31 08:22:02Z eadler $");
 
 #include <sys/types.h>
 #include <sys/mman.h>
@@ -55,10 +55,10 @@
 
 #define	HW_MCA_MAX_CPUID	255
 
-static char hw_mca_count[] = "hw.mca.count";
-static char hw_mca_first[] = "hw.mca.first";
-static char hw_mca_last[] = "hw.mca.last";
-static char hw_mca_recid[] = "hw.mca.%lu.%u";
+static const char hw_mca_count[] = "hw.mca.count";
+static const char hw_mca_first[] = "hw.mca.first";
+static const char hw_mca_last[] = "hw.mca.last";
+static const char hw_mca_recid[] = "hw.mca.%d.%u";
 
 static char default_dumpfile[] = "/var/log/mca.log";
 
@@ -162,7 +162,9 @@
 	char var[16];
 	struct mca_cpu_mod *mod;
 	struct mca_cpu_cpuid *cpuid;
+#ifdef notyet
 	struct mca_cpu_psi *psi;
+#endif
 	int i, n;
 
 	printf("    <cpu>\n");
@@ -200,8 +202,10 @@
 		show_value(6, var, "0x%016llx", (long long)cpuid->cpuid[i]);
 	}
 
-	psi = (struct mca_cpu_psi*)(cpuid + 1);
-	/* TODO: Dump PSI */
+#ifdef notyet
+	 psi = (struct mca_cpu_psi*)(cpuid + 1);
+#endif
+	 /* TODO: Dump PSI */
 
 	printf("    </cpu>\n");
 }
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/md5/md5.1
--- a/head/sbin/md5/md5.1	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/md5/md5.1	Wed Jul 25 16:24:55 2012 +0300
@@ -1,9 +1,9 @@
-.\" $FreeBSD: head/sbin/md5/md5.1 227491 2011-11-13 17:07:43Z eadler $
+.\" $FreeBSD: head/sbin/md5/md5.1 235211 2012-05-10 02:07:00Z gjb $
 .Dd September 7, 2008
 .Dt MD5 1
 .Os
 .Sh NAME
-.Nm md5 , sha1 , sha256, rmd160
+.Nm md5 , sha1 , sha256 , rmd160
 .Nd calculate a message-digest fingerprint (checksum) for a file
 .Sh SYNOPSIS
 .Nm md5
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/md5/md5.c
--- a/head/sbin/md5/md5.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/md5/md5.c	Wed Jul 25 16:24:55 2012 +0300
@@ -18,7 +18,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/md5/md5.c 227488 2011-11-13 16:35:47Z eadler $");
+__FBSDID("$FreeBSD: head/sbin/md5/md5.c 235205 2012-05-09 17:32:10Z eadler $");
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -372,6 +372,6 @@
 usage(Algorithm_t *alg)
 {
 
-	fprintf(stderr, "usage: %s [-pqrtx] [-s string] [files ...]\n", alg->progname);
+	fprintf(stderr, "usage: %s [-pqrtx] [-c string] [-s string] [files ...]\n", alg->progname);
 	exit(1);
 }
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/mdconfig/Makefile
--- a/head/sbin/mdconfig/Makefile	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/mdconfig/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -1,8 +1,7 @@
-# $FreeBSD$
+# $FreeBSD: head/sbin/mdconfig/Makefile 238202 2012-07-07 17:20:27Z eadler $
 
 PROG=		mdconfig
 MAN=		mdconfig.8
-MLINKS=		mdconfig.8 vnconfig.8
 
 DPADD=	${LIBUTIL} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} 
 LDADD=	-lutil -lgeom -lbsdxml -lsbuf
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/mdconfig/mdconfig.8
--- a/head/sbin/mdconfig/mdconfig.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/mdconfig/mdconfig.8	Wed Jul 25 16:24:55 2012 +0300
@@ -39,9 +39,9 @@
 .\"     @(#)vnconfig.8	8.1 (Berkeley) 6/5/93
 .\" from: src/usr.sbin/vnconfig/vnconfig.8,v 1.19 2000/12/27 15:30:29
 .\"
-.\" $FreeBSD: head/sbin/mdconfig/mdconfig.8 234047 2012-04-09 01:20:50Z bjk $
+.\" $FreeBSD: head/sbin/mdconfig/mdconfig.8 238215 2012-07-07 20:32:21Z trasz $
 .\"
-.Dd March 21, 2012
+.Dd June 27, 2012
 .Dt MDCONFIG 8
 .Os
 .Sh NAME
@@ -64,6 +64,11 @@
 .Fl u Ar unit
 .Op Fl o Oo Cm no Oc Ns Ar force
 .Nm
+.Fl r
+.Fl u Ar unit
+.Fl s Ar size
+.Op Fl o Oo Cm no Oc Ns Ar force
+.Nm
 .Fl l
 .Op Fl n
 .Op Fl v
@@ -85,6 +90,8 @@
 parameters specified and attach it to the system.
 .It Fl d
 Detach a memory disk from the system and release all resources.
+.It Fl r
+Resize a memory disk.
 .It Fl t Ar type
 Select the type of the memory disk.
 .Bl -tag -width "malloc"
@@ -128,7 +135,7 @@
 .Fl v
 option is specified, show all details.
 .It Fl n
-When printing 
+When printing
 .Xr md 4
 device names, print only the unit number without the
 .Xr md 4
@@ -148,7 +155,7 @@
 .Fl t Ar swap
 options are implied if not specified.
 .It Fl S Ar sectorsize
-Sectorsize to use for malloc backed device.
+Sectorsize to use for the memory disk, in bytes.
 .It Fl x Ar sectors/track
 See the description of the
 .Fl y
@@ -235,10 +242,11 @@
 .Ed
 .Pp
 Create a 5MB file-backed disk
-.Ns ( Fl a
+.Po Fl a
 and
 .Fl t Ar vnode
-are implied):
+are implied
+.Pc :
 .Bd -literal -offset indent
 dd if=/dev/zero of=somebackingfile bs=1k count=5k
 mdconfig -f somebackingfile -u 0
@@ -250,10 +258,11 @@
 Create an
 .Xr md 4
 device out of an ISO 9660 CD image file
-.Ns ( Fl a
+.Po Fl a
 and
 .Fl t Ar vnode
-are implied), using the first available
+are implied
+.Pc , using the first available
 .Xr md 4
 device, and then mount the new memory disk:
 .Bd -literal -offset indent
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/mdconfig/mdconfig.c
--- a/head/sbin/mdconfig/mdconfig.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/mdconfig/mdconfig.c	Wed Jul 25 16:24:55 2012 +0300
@@ -27,7 +27,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * $FreeBSD: head/sbin/mdconfig/mdconfig.c 232964 2012-03-14 10:10:15Z trasz $
+ * $FreeBSD: head/sbin/mdconfig/mdconfig.c 238215 2012-07-07 20:32:21Z trasz $
  */
 
 #include <sys/param.h>
@@ -54,7 +54,7 @@
 #include <unistd.h>
 
 static struct md_ioctl mdio;
-static enum {UNSET, ATTACH, DETACH, LIST} action = UNSET;
+static enum {UNSET, ATTACH, DETACH, RESIZE, LIST} action = UNSET;
 static int nflag;
 
 static void usage(void);
@@ -81,6 +81,7 @@
 "                [-s size] [-S sectorsize] [-u unit]\n"
 "                [-x sectors/track] [-y heads/cylinder]\n"
 "       mdconfig -d -u unit [-o [no]force]\n"
+"       mdconfig -r -u unit -s size [-o [no]force]\n"
 "       mdconfig -l [-v] [-n] [-u unit]\n"
 "       mdconfig file\n");
 	fprintf(stderr, "\t\ttype = {malloc, preload, vnode, swap}\n");
@@ -96,7 +97,7 @@
 {
 	int ch, fd, i, vflag;
 	char *p;
-	char *fflag = NULL, *tflag = NULL, *uflag = NULL;
+	char *fflag = NULL, *sflag = NULL, *tflag = NULL, *uflag = NULL;
 
 	bzero(&mdio, sizeof(mdio));
 	mdio.md_file = malloc(PATH_MAX);
@@ -108,25 +109,32 @@
 	if (argc == 1)
 		usage();
 
-	while ((ch = getopt(argc, argv, "ab:df:lno:s:S:t:u:vx:y:")) != -1) {
+	while ((ch = getopt(argc, argv, "ab:df:lno:rs:S:t:u:vx:y:")) != -1) {
 		switch (ch) {
 		case 'a':
 			if (action != UNSET && action != ATTACH)
-				errx(1,
-				    "-a is mutually exclusive with -d and -l");
+				errx(1, "-a is mutually exclusive "
+				    "with -d, -r, and -l");
 			action = ATTACH;
 			break;
 		case 'd':
 			if (action != UNSET && action != DETACH)
-				errx(1,
-				    "-d is mutually exclusive with -a and -l");
+				errx(1, "-d is mutually exclusive "
+				    "with -a, -r, and -l");
 			action = DETACH;
 			mdio.md_options |= MD_AUTOUNIT;
 			break;
+		case 'r':
+			if (action != UNSET && action != RESIZE)
+				errx(1, "-r is mutually exclusive "
+				    "with -a, -d, and -l");
+			action = RESIZE;
+			mdio.md_options |= MD_AUTOUNIT;
+			break;
 		case 'l':
 			if (action != UNSET && action != LIST)
-				errx(1,
-				    "-l is mutually exclusive with -a and -d");
+				errx(1, "-l is mutually exclusive "
+				    "with -a, -r, and -d");
 			action = LIST;
 			mdio.md_options |= MD_AUTOUNIT;
 			break;
@@ -188,6 +196,9 @@
 			mdio.md_sectorsize = strtoul(optarg, &p, 0);
 			break;
 		case 's':
+			if (sflag != NULL)
+				errx(1, "-s can be passed only once");
+			sflag = optarg;
 			mdio.md_mediasize = (off_t)strtoumax(optarg, &p, 0);
 			if (p == NULL || *p == '\0')
 				mdio.md_mediasize *= DEV_BSIZE;
@@ -242,7 +253,7 @@
 				mdio.md_type = MD_VNODE;
 				mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
 				    MD_COMPRESS;
-			} else if (mdio.md_mediasize != 0) {
+			} else if (sflag != NULL) {
 				/* Imply ``-t swap'' */
 				mdio.md_type = MD_SWAP;
 				mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT |
@@ -276,15 +287,15 @@
 		}
 
 		if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP) &&
-		    mdio.md_mediasize == 0)
+		    sflag == NULL)
 			errx(1, "must specify -s for -t malloc or -t swap");
 		if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0')
 			errx(1, "must specify -f for -t vnode");
 	} else {
 		if (mdio.md_sectorsize != 0)
 			errx(1, "-S can only be used with -a");
-		if (mdio.md_mediasize != 0)
-			errx(1, "-s can only be used with -a");
+		if (action != RESIZE && sflag != NULL)
+			errx(1, "-s can only be used with -a and -r");
 		if (mdio.md_fwsectors != 0)
 			errx(1, "-x can only be used with -a");
 		if (mdio.md_fwheads != 0)
@@ -295,13 +306,20 @@
 			errx(1, "-t can only be used with -a");
 		if (argc > 0)
 			errx(1, "file can only be used with -a");
-		if (action != DETACH && (mdio.md_options & ~MD_AUTOUNIT) != 0)
-			errx(1, "-o can only be used with -a and -d");
+		if ((action != DETACH && action != RESIZE) &&
+		    (mdio.md_options & ~MD_AUTOUNIT) != 0)
+			errx(1, "-o can only be used with -a, -d, and -r");
 		if (action == DETACH &&
 		    (mdio.md_options & ~(MD_FORCE | MD_AUTOUNIT)) != 0)
 			errx(1, "only -o [no]force can be used with -d");
+		if (action == RESIZE &&
+		    (mdio.md_options & ~(MD_FORCE | MD_RESERVE | MD_AUTOUNIT)) != 0)
+			errx(1, "only -o [no]force and -o [no]reserve can be used with -r");
 	}
 
+	if (action == RESIZE && sflag == NULL)
+		errx(1, "must specify -s for -r");
+
 	if (action != LIST && vflag == OPT_VERBOSE)
 		errx(1, "-v can only be used with -l");
 
@@ -333,6 +351,12 @@
 		i = ioctl(fd, MDIOCDETACH, &mdio);
 		if (i < 0)
 			err(1, "ioctl(/dev/%s)", MDCTL_NAME);
+	} else if (action == RESIZE) {
+		if (mdio.md_options & MD_AUTOUNIT)
+			errx(1, "-r requires -u");
+		i = ioctl(fd, MDIOCRESIZE, &mdio);
+		if (i < 0)
+			err(1, "ioctl(/dev/%s)", MDCTL_NAME);
 	} else if (action == LIST) {
 		if (mdio.md_options & MD_AUTOUNIT) {
 			/*
@@ -342,7 +366,6 @@
 			md_list(NULL, OPT_LIST | vflag);
 		} else
 			return (md_query(uflag));
-
 	} else
 		usage();
 	close(fd);
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/mount/mount.8
--- a/head/sbin/mount/mount.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/mount/mount.8	Wed Jul 25 16:24:55 2012 +0300
@@ -26,9 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)mount.8	8.8 (Berkeley) 6/16/94
-.\" $FreeBSD: head/sbin/mount/mount.8 222754 2011-06-06 13:24:54Z gavin $
+.\" $FreeBSD: head/sbin/mount/mount.8 238399 2012-07-12 15:20:20Z eadler $
 .\"
-.Dd June 6, 2011
+.Dd July 12, 2012
 .Dt MOUNT 8
 .Os
 .Sh NAME
@@ -145,6 +145,11 @@
 .Fl u
 flag, this is the same as specifying the options currently in effect for
 the mounted file system.
+.It Cm failok
+If this option is specified,
+.Nm
+will return 0 even if an error occurs
+during the mount of the filesystem.
 .It Cm force
 The same as
 .Fl f ;
@@ -448,7 +453,7 @@
 .Cm smbfs ,
 .Cm udf ,
 and
-.Cm unionfs ,
+.Cm unionfs .
 .Nm
 will not call
 .Xr nmount 2
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,10 @@
+# $FreeBSD: head/sbin/nandfs/Makefile 235537 2012-05-17 10:11:18Z gber $
+
+PROG=	nandfs
+SRCS=	nandfs.c lssnap.c mksnap.c rmsnap.c
+MAN=	nandfs.8
+
+DPADD=	${LIBNANDFS}
+LDADD=	-lnandfs
+
+.include <bsd.prog.mk>
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/lssnap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/lssnap.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,112 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/nandfs/lssnap.c 235537 2012-05-17 10:11:18Z gber $");
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <time.h>
+
+#include <fs/nandfs/nandfs_fs.h>
+#include <libnandfs.h>
+
+#include "nandfs.h"
+
+#define NCPINFO	512
+
+static void
+lssnap_usage(void)
+{
+
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, "\tlssnap node\n");
+}
+
+static void
+print_cpinfo(struct nandfs_cpinfo *cpinfo)
+{
+	struct tm tm;
+	time_t t;
+	char timebuf[128];
+
+	t = (time_t)cpinfo->nci_create;
+	localtime_r(&t, &tm);
+	strftime(timebuf, sizeof(timebuf), "%F %T", &tm);
+
+	printf("%20llu  %s\n", (unsigned long long)cpinfo->nci_cno, timebuf);
+}
+
+int
+nandfs_lssnap(int argc, char **argv)
+{
+	struct nandfs_cpinfo *cpinfos;
+	struct nandfs fs;
+	uint64_t next;
+	int error, nsnap, i;
+
+	if (argc != 1) {
+		lssnap_usage();
+		return (EX_USAGE);
+	}
+
+	cpinfos = malloc(sizeof(*cpinfos) * NCPINFO);
+	if (cpinfos == NULL) {
+		fprintf(stderr, "cannot allocate memory\n");
+		return (-1);
+	}
+
+	nandfs_init(&fs, argv[0]);
+	error = nandfs_open(&fs);
+	if (error == -1) {
+		fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs));
+		goto out;
+	}
+
+	for (next = 1; next != 0; next = cpinfos[nsnap - 1].nci_next) {
+		nsnap = nandfs_get_snap(&fs, next, cpinfos, NCPINFO);
+		if (nsnap < 1)
+			break;
+
+		for (i = 0; i < nsnap; i++)
+			print_cpinfo(&cpinfos[i]);
+	}
+
+	if (nsnap == -1)
+		fprintf(stderr, "nandfs_get_snap: %s\n", nandfs_errmsg(&fs));
+
+out:
+	nandfs_close(&fs);
+	nandfs_destroy(&fs);
+	free(cpinfos);
+	return (error);
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/mksnap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/mksnap.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,80 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/nandfs/mksnap.c 235537 2012-05-17 10:11:18Z gber $");
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <sysexits.h>
+
+#include <fs/nandfs/nandfs_fs.h>
+#include <libnandfs.h>
+
+#include "nandfs.h"
+
+static void
+mksnap_usage(void)
+{
+
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, "\tmksnap node\n");
+}
+
+int
+nandfs_mksnap(int argc, char **argv)
+{
+	struct nandfs fs;
+	uint64_t cpno;
+	int error;
+
+	if (argc != 1) {
+		mksnap_usage();
+		return (EX_USAGE);
+	}
+
+	nandfs_init(&fs, argv[0]);
+	error = nandfs_open(&fs);
+	if (error == -1) {
+		fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs));
+		goto out;
+	}
+
+	error = nandfs_make_snap(&fs, &cpno);
+	if (error == -1)
+		fprintf(stderr, "nandfs_make_snap: %s\n", nandfs_errmsg(&fs));
+	else
+		printf("%jd\n", cpno);
+
+out:
+	nandfs_close(&fs);
+	nandfs_destroy(&fs);
+	return (error);
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/nandfs.8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/nandfs.8	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,74 @@
+.\"
+.\" Copyright (c) 2012 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Semihalf under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" 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: head/sbin/nandfs/nandfs.8 235542 2012-05-17 11:29:22Z joel $
+.\"
+.Dd February 28, 2012
+.Dt NANDFS 8
+.Os
+.Sh NAME
+.Nm nandfs
+.Nd manage mounted NAND FS
+.Sh SYNOPSIS
+.Nm
+.Cm lssnap
+.Ar node
+.Nm
+.Cm mksnap
+.Ar node
+.Nm
+.Cm rmsnap
+.Ar snapshot node
+.Sh DESCRIPTION
+The
+.Nm
+utility allows to manage snapshots of a mounted NAND FS.
+.Sh EXAMPLES
+Create a snapshot of filesystem mounted on
+.Em /nand .
+.Bd -literal -offset 2n
+.Li # Ic nandfs mksnap /nand
+1
+.Ed
+.Pp
+List snapshots of filesystem mounted on
+.Em /nand .
+.Bd -literal -offset 2n
+.Li # Ic nandfs lssnap /nand
+1  2012-02-28 18:49:45   ss           138          2
+.Ed
+.Pp
+Remove snapshot 1 of filesystem mounted on
+.Em /nand .
+.Bd -literal -offset 2n
+.Li # Ic nandfs rmsnap 1 /nand
+.Ed
+.Sh AUTHORS
+This utility and manual page were written by
+.An Mateusz Guzik .
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/nandfs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/nandfs.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/nandfs/nandfs.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "nandfs.h"
+
+static void
+usage(void)
+{
+
+	fprintf(stderr, "usage: nandfs [lssnap | mksnap | rmsnap <snap>] "
+	    "node\n");
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	int error = 0;
+	char *cmd;
+
+	if (argc < 2)
+		usage();
+
+	cmd = argv[1];
+	argc -= 2;
+	argv += 2;
+
+	if (strcmp(cmd, "lssnap") == 0)
+		error = nandfs_lssnap(argc, argv);
+	else if (strcmp(cmd, "mksnap") == 0)
+		error = nandfs_mksnap(argc, argv);
+	else if (strcmp(cmd, "rmsnap") == 0)
+		error = nandfs_rmsnap(argc, argv);
+	else
+		usage();
+
+	return (error);
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/nandfs.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/nandfs.h	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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: head/sbin/nandfs/nandfs.h 235537 2012-05-17 10:11:18Z gber $
+ */
+
+#ifndef NANDFS_H
+#define NANDFS_H
+
+int nandfs_lssnap(int, char **);
+int nandfs_mksnap(int, char **);
+int nandfs_rmsnap(int, char **);
+
+#endif /* !NANDFS_H */
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/nandfs/rmsnap.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/nandfs/rmsnap.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,87 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Semihalf under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/nandfs/rmsnap.c 235537 2012-05-17 10:11:18Z gber $");
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <sysexits.h>
+
+#include <fs/nandfs/nandfs_fs.h>
+#include <libnandfs.h>
+
+#include "nandfs.h"
+
+static void
+rmsnap_usage(void)
+{
+
+	fprintf(stderr, "usage:\n");
+	fprintf(stderr, "\trmsnap snap node\n");
+}
+
+int
+nandfs_rmsnap(int argc, char **argv)
+{
+	struct nandfs fs;
+	uint64_t cpno;
+	int error;
+
+	if (argc != 2) {
+		rmsnap_usage();
+		return (EX_USAGE);
+	}
+
+	cpno = strtoll(argv[0], (char **)NULL, 10);
+	if (cpno == 0) {
+		fprintf(stderr, "%s must be a number greater than 0\n",
+		    argv[0]);
+		return (EX_USAGE);
+	}
+
+	nandfs_init(&fs, argv[1]);
+	error = nandfs_open(&fs);
+	if (error == -1) {
+		fprintf(stderr, "nandfs_open: %s\n", nandfs_errmsg(&fs));
+		goto out;
+	}
+
+	error = nandfs_delete_snap(&fs, cpno);
+	if (error == -1)
+		fprintf(stderr, "nandfs_delete_snap: %s\n", nandfs_errmsg(&fs));
+
+out:
+	nandfs_close(&fs);
+	nandfs_destroy(&fs);
+	return (error);
+}
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/natd/natd.8
--- a/head/sbin/natd/natd.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/natd/natd.8	Wed Jul 25 16:24:55 2012 +0300
@@ -1,4 +1,4 @@
-.\" $FreeBSD: head/sbin/natd/natd.8 223713 2011-07-01 19:22:27Z sem $
+.\" $FreeBSD: head/sbin/natd/natd.8 236809 2012-06-09 10:43:33Z joel $
 .Dd June 23, 2008
 .Dt NATD 8
 .Os
@@ -130,9 +130,9 @@
 172.16.0.0/12 and 192.168.0.0/16.
 .It Fl redirect_port Ar proto Xo
 .Ar targetIP Ns : Ns Xo
-.Ar targetPORT Ns Op - Ns Ar targetPORT Xc
-.Op Ar aliasIP Ns : Ns Xo
-.Ar aliasPORT Ns Op - Ns Ar aliasPORT Xc
+.Ar targetPORT Ns Oo - Ns Ar targetPORT Oc Xc
+.Oo Ar aliasIP Ns : Oc Ns Xo
+.Ar aliasPORT Ns Oo - Ns Ar aliasPORT Oc Xc
 .Oo Ar remoteIP Ns Oo : Ns
 .Ar remotePORT Ns Op - Ns Ar remotePORT
 .Oc Oc
@@ -247,10 +247,8 @@
 .Ar targetIP Ns : Ns Xo
 .Ar targetPORT Ns Oo , Ns
 .Ar ...\&
-.Oc Oc
-.Xc
-.Xc
-.Op Ar aliasIP Ns : Ns Xo
+.Oc Xc Oc Xc
+.Oo Ar aliasIP Ns : Oc Ns Xo
 .Ar aliasPORT
 .Xc
 .Oo Ar remoteIP Ns
@@ -787,7 +785,7 @@
 .Pp
 Here the packet from internal network to Internet goes out via
 .Ql sis0
-(rule number 2000) and gets catched by the
+(rule number 2000) and gets caught by the
 .Ic globalport
 socket (3000).
 After that, either a match is found in a translation table
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/newfs_nandfs/Makefile
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/newfs_nandfs/Makefile	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,9 @@
+# $FreeBSD: head/sbin/newfs_nandfs/Makefile 235537 2012-05-17 10:11:18Z gber $
+
+PROG=	newfs_nandfs
+MAN=	newfs_nandfs.8
+
+LDADD+= -lgeom
+DPADD+= ${LIBGEOM}
+
+.include <bsd.prog.mk>
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/newfs_nandfs/newfs_nandfs.8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/newfs_nandfs/newfs_nandfs.8	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,76 @@
+.\"
+.\" Copyright (c) 2010 Semihalf
+.\" 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 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: head/sbin/newfs_nandfs/newfs_nandfs.8 235544 2012-05-17 11:50:12Z joel $
+.\"
+.Dd April 11, 2009
+.Dt NEWFS_NANDFS 8
+.Os
+.Sh NAME
+.Nm newfs_nandfs
+.Nd construct a new NAND FS file system
+.Sh SYNOPSIS
+.Nm
+.Op Fl b Ar blocsize
+.Op Fl B Ar blocks-per-segment
+.Op Fl L Ar label
+.Op Fl m Ar reserved-segment-percent
+.Ar device
+.Sh DESCRIPTION
+The
+.Nm
+utility creates a NAND FS file system on device.
+.Pp
+The options are as follow:
+.Bl -tag -width indent
+.It Fl b Ar blocksize
+Size of block (1024 if not specified).
+.It Fl B Ar blocks_per_segment
+Number of blocks per segment (2048 if not specified).
+.It Fl L Ar label
+Volume label (up to 16 characters).
+.It Fl m Ar reserved_block_percent
+Percentage of reserved blocks (5 if not specified).
+.El
+.Sh EXIT STATUS
+Exit status is 0 on success and 1 on error.
+.Sh EXAMPLES
+Create a file system, using default parameters, on
+.Pa /dev/ad0s1 :
+.Bd -literal -offset indent
+newfs_nandfs /dev/ad0s1
+.Ed
+.Sh SEE ALSO
+.Xr disktab 5 ,
+.Xr disklabel 8 ,
+.Xr fdisk 8 ,
+.Xr newfs 8
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 10.0 .
+.Sh AUTHOR
+.An Grzegorz Bernacki
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/newfs_nandfs/newfs_nandfs.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/head/sbin/newfs_nandfs/newfs_nandfs.c	Wed Jul 25 16:24:55 2012 +0300
@@ -0,0 +1,1176 @@
+/*-
+ * Copyright (c) 2010-2012 Semihalf.
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: head/sbin/newfs_nandfs/newfs_nandfs.c 235537 2012-05-17 10:11:18Z gber $");
+
+#include <sys/param.h>
+#include <sys/fdcio.h>
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/endian.h>
+#include <sys/stddef.h>
+#include <sys/uuid.h>
+#include <sys/dirent.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgeom.h>
+#include <paths.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <fs/nandfs/nandfs_fs.h>
+#include <dev/nand/nand_dev.h>
+
+#define DEBUG
+#undef DEBUG
+#ifdef DEBUG
+#define debug(fmt, args...) do { \
+	printf("nandfs:" fmt "\n", ##args); } while (0)
+#else
+#define debug(fmt, args...)
+#endif
+
+#define NANDFS_FIRST_BLOCK	nandfs_first_block()
+#define NANDFS_FIRST_CNO		1
+#define NANDFS_BLOCK_BAD	1
+#define NANDFS_BLOCK_GOOD	0
+
+struct file_info {
+	uint64_t	ino;
+	const char	*name;
+	uint32_t	mode;
+	uint64_t	size;
+	uint8_t		nblocks;
+	uint32_t	*blocks;
+	struct nandfs_inode *inode;
+};
+
+struct file_info user_files[] =
+{
+	{NANDFS_ROOT_INO, NULL, S_IFDIR | 0755, 0, 1, NULL, NULL},
+};
+
+struct file_info ifile = {NANDFS_IFILE_INO, NULL, 0, 0, -1, NULL, NULL};
+struct file_info sufile = {NANDFS_SUFILE_INO, NULL, 0, 0, -1, NULL, NULL};
+struct file_info cpfile = {NANDFS_CPFILE_INO, NULL, 0, 0, -1, NULL, NULL};
+struct file_info datfile = {NANDFS_DAT_INO, NULL, 0, 0, -1, NULL, NULL};
+
+struct nandfs_block {
+	LIST_ENTRY(nandfs_block) block_link;
+	uint32_t number;
+	uint64_t offset;
+	void	*data;
+};
+
+static LIST_HEAD(, nandfs_block) block_head = LIST_HEAD_INITIALIZER(&block_head);
+
+/* Storage geometry */
+static off_t mediasize;
+static ssize_t sectorsize;
+static uint64_t nsegments;
+static uint64_t erasesize;
+static uint64_t segsize;
+
+struct nandfs_fsdata fsdata;
+struct nandfs_super_block super_block;
+
+static int is_nand;
+
+/* Nandfs parameters */
+static size_t blocksize = NANDFS_DEF_BLOCKSIZE;
+static long blocks_per_segment;
+static long rsv_segment_percent = 5;
+static time_t nandfs_time;
+static uint32_t bad_segments_count = 0;
+static uint32_t *bad_segments = NULL;
+static uint8_t fsdata_blocks_state[NANDFS_NFSAREAS];
+
+u_char *volumelabel = NULL;
+
+struct nandfs_super_root *sr;
+
+uint32_t nuserfiles;
+uint32_t seg_segsum_size;
+uint32_t seg_nblocks;
+uint32_t seg_endblock;
+
+#define SIZE_TO_BLOCK(size) (((size) + (blocksize - 1)) / blocksize)
+
+static uint32_t
+nandfs_first_block(void)
+{
+	uint32_t i, first_free, start_bad_segments = 0;
+
+	for (i = 0; i < bad_segments_count; i++) {
+		if (i == bad_segments[i])
+			start_bad_segments++;
+		else
+			break;
+	}
+
+	first_free = SIZE_TO_BLOCK(NANDFS_DATA_OFFSET_BYTES(erasesize) +
+	    (start_bad_segments * segsize));
+
+	if (first_free < (uint32_t)blocks_per_segment)
+		return (blocks_per_segment);
+	else
+		return (first_free);
+}
+
+static void
+usage(void)
+{
+
+	fprintf(stderr,
+	    "usage: newfs_nandfs [ -options ] device\n"
+	    "where the options are:\n"
+	    "\t-b block-size\n"
+	    "\t-B blocks-per-segment\n"
+	    "\t-L volume label\n"
+	    "\t-m reserved-segments-percentage\n");
+	exit(1);
+}
+
+static int
+nandfs_log2(unsigned n)
+{
+	unsigned count;
+
+	/*
+	 * N.B. this function will return 0 if supplied 0.
+	 */
+	for (count = 0; n/2; count++)
+		n /= 2;
+	return count;
+}
+
+/* from NetBSD's src/sys/net/if_ethersubr.c */
+static uint32_t
+crc32_le(uint32_t crc, const uint8_t *buf, size_t len)
+{
+	static const uint32_t crctab[] = {
+		0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
+		0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+		0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
+		0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
+	};
+	size_t i;
+
+	crc = crc ^ ~0U;
+
+	for (i = 0; i < len; i++) {
+		crc ^= buf[i];
+		crc = (crc >> 4) ^ crctab[crc & 0xf];
+		crc = (crc >> 4) ^ crctab[crc & 0xf];
+	}
+
+	return (crc ^ ~0U);
+}
+
+static void *
+get_block(uint32_t block_nr, uint64_t offset)
+{
+	struct nandfs_block *block, *new_block;
+
+	LIST_FOREACH(block, &block_head, block_link) {
+		if (block->number == block_nr)
+			return block->data;
+	}
+
+	debug("allocating block %x\n", block_nr);
+
+	new_block = malloc(sizeof(*block));
+	if (!new_block)
+		err(1, "cannot allocate block");
+
+	new_block->number = block_nr;
+	new_block->offset = offset;
+	new_block->data = malloc(blocksize);
+	if (!new_block->data)
+		err(1, "cannot allocate block data");
+
+	memset(new_block->data, 0, blocksize);
+
+	LIST_INSERT_HEAD(&block_head, new_block, block_link);
+
+	return (new_block->data);
+}
+
+static int
+nandfs_seg_usage_blk_offset(uint64_t seg, uint64_t *blk, uint64_t *offset)
+{
+	uint64_t off;
+	uint16_t seg_size;
+
+	seg_size = sizeof(struct nandfs_segment_usage);
+
+	off = roundup(sizeof(struct nandfs_sufile_header), seg_size);
+	off += (seg * seg_size);
+
+	*blk = off / blocksize;
+	*offset = (off % blocksize) / seg_size;
+	return (0);
+}
+
+static uint32_t
+segment_size(void)
+{
+	u_int size;
+
+	size = sizeof(struct nandfs_segment_summary );
+	size +=	seg_nblocks * sizeof(struct nandfs_binfo_v);
+
+	if (size > blocksize)
+		err(1, "segsum info bigger that blocksize");
+
+	return (size);
+}
+
+
+static void
+prepare_blockgrouped_file(uint32_t block)
+{
+	struct nandfs_block_group_desc *desc;
+	uint32_t i, entries;
+
+	desc = (struct nandfs_block_group_desc *)get_block(block, 0);
+	entries = blocksize / sizeof(struct nandfs_block_group_desc);
+	for (i = 0; i < entries; i++)
+		desc[i].bg_nfrees = blocksize * 8;
+}
+
+static void
+alloc_blockgrouped_file(uint32_t block, uint32_t entry)
+{
+	struct nandfs_block_group_desc *desc;
+	uint32_t desc_nr;
+	uint32_t *bitmap;
+
+	desc = (struct nandfs_block_group_desc *)get_block(block, 0);
+	bitmap = (uint32_t *)get_block(block + 1, 1);
+
+	bitmap += (entry >> 5);
+	if (*bitmap & (1 << (entry % 32))) {
+		printf("nandfs: blockgrouped entry %d already allocated\n",
+		    entry);
+	}
+	*bitmap |= (1 << (entry % 32));
+
+	desc_nr = entry / (blocksize * 8);
+	desc[desc_nr].bg_nfrees--;
+}
+
+
+static uint64_t
+count_su_blocks(void)
+{
+	uint64_t maxblk, blk, offset, i;
+
+	maxblk = blk = 0;
+
+	for (i = 0; i < bad_segments_count; i++) {
+		nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &offset);
+		debug("bad segment at block:%jx off: %jx", blk, offset);
+		if (blk > maxblk)
+			maxblk = blk;
+	}
+
+	debug("bad segment needs %#jx", blk);
+	if (blk >= NDADDR) {
+		printf("nandfs: file too big (%jd > %d)\n", blk, NDADDR);
+		exit(2);
+	}
+
+	sufile.size = (blk + 1) * blocksize;
+	return (blk + 1);
+}
+
+static void
+count_seg_blocks(void)
+{
+	uint32_t i;
+
+	for (i = 0; i < nuserfiles; i++)
+		if (user_files[i].nblocks) {
+			seg_nblocks += user_files[i].nblocks;
+			user_files[i].blocks = malloc(user_files[i].nblocks * sizeof(uint32_t));
+		}
+
+	ifile.nblocks = 2 +
+	    SIZE_TO_BLOCK(sizeof(struct nandfs_inode) * (NANDFS_USER_INO + 1));
+	ifile.blocks = malloc(ifile.nblocks * sizeof(uint32_t));
+	seg_nblocks += ifile.nblocks;
+
+	cpfile.nblocks =
+	    SIZE_TO_BLOCK((NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1) *
+	    sizeof(struct nandfs_checkpoint));
+	cpfile.blocks = malloc(cpfile.nblocks * sizeof(uint32_t));
+	seg_nblocks += cpfile.nblocks;
+
+	if (!bad_segments) {
+		sufile.nblocks =
+		    SIZE_TO_BLOCK((NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET + 1) *
+		    sizeof(struct nandfs_segment_usage));
+	} else {
+		debug("bad blocks found: extra space for sufile");
+		sufile.nblocks = count_su_blocks();
+	}
+
+	sufile.blocks = malloc(sufile.nblocks * sizeof(uint32_t));
+	seg_nblocks += sufile.nblocks;
+
+	datfile.nblocks = 2 +
+	    SIZE_TO_BLOCK((seg_nblocks) * sizeof(struct nandfs_dat_entry));
+	datfile.blocks = malloc(datfile.nblocks * sizeof(uint32_t));
+	seg_nblocks += datfile.nblocks;
+}
+
+static void
+assign_file_blocks(uint64_t start_block)
+{
+	uint32_t i, j;
+
+	for (i = 0; i < nuserfiles; i++)
+		for (j = 0; j < user_files[i].nblocks; j++) {
+			debug("user file %d at block %d at %#jx",
+			    i, j, (uintmax_t)start_block);
+			user_files[i].blocks[j] = start_block++;
+		}
+
+	for (j = 0; j < ifile.nblocks; j++) {
+		debug("ifile block %d at %#jx", j, (uintmax_t)start_block);
+		ifile.blocks[j] = start_block++;
+	}
+
+	for (j = 0; j < cpfile.nblocks; j++) {
+		debug("cpfile block %d at %#jx", j, (uintmax_t)start_block);
+		cpfile.blocks[j] = start_block++;
+	}
+
+	for (j = 0; j < sufile.nblocks; j++) {
+		debug("sufile block %d at %#jx", j, (uintmax_t)start_block);
+		sufile.blocks[j] = start_block++;
+	}
+
+	for (j = 0; j < datfile.nblocks; j++) {
+		debug("datfile block %d at %#jx", j, (uintmax_t)start_block);
+		datfile.blocks[j] = start_block++;
+	}
+
+	/* add one for superroot */
+	debug("sr at block %#jx", (uintmax_t)start_block);
+	sr = (struct nandfs_super_root *)get_block(start_block++, 0);
+	seg_endblock = start_block;
+}
+
+static void
+save_datfile(void)
+{
+
+	prepare_blockgrouped_file(datfile.blocks[0]);
+}
+
+static uint64_t
+update_datfile(uint64_t block)
+{
+	struct nandfs_dat_entry *dat;
+	static uint64_t vblock = 0;
+	uint64_t allocated, i, off;
+
+	if (vblock == 0) {
+		alloc_blockgrouped_file(datfile.blocks[0], vblock);
+		vblock++;
+	}
+	allocated = vblock;
+	i = vblock / (blocksize / sizeof(*dat));
+	off = vblock % (blocksize / sizeof(*dat));
+	vblock++;
+
+	dat = (struct nandfs_dat_entry *)get_block(datfile.blocks[2 + i], 2 + i);
+
+	alloc_blockgrouped_file(datfile.blocks[0], allocated);
+	dat[off].de_blocknr = block;
+	dat[off].de_start = NANDFS_FIRST_CNO;
+	dat[off].de_end = UINTMAX_MAX;
+
+	return (allocated);
+}
+
+static union nandfs_binfo *
+update_block_info(union nandfs_binfo *binfo, struct file_info *file)
+{
+	nandfs_daddr_t vblock;
+	uint32_t i;
+
+	for (i = 0; i < file->nblocks; i++) {
+		debug("%s: blk %x", __func__, i);
+		if (file->ino != NANDFS_DAT_INO) {
+			vblock = update_datfile(file->blocks[i]);
+			binfo->bi_v.bi_vblocknr = vblock;
+			binfo->bi_v.bi_blkoff = i;
+			binfo->bi_v.bi_ino = file->ino;
+			file->inode->i_db[i] = vblock;
+		} else {
+			binfo->bi_dat.bi_blkoff = i;
+			binfo->bi_dat.bi_ino = file->ino;
+			file->inode->i_db[i] = datfile.blocks[i];
+		}
+		binfo++;
+	}
+
+	return (binfo);
+}
+
+static void
+save_segsum(struct nandfs_segment_summary *ss)
+{
+	union nandfs_binfo *binfo;
+	struct nandfs_block *block;
+	uint32_t sum_bytes, i;
+	uint8_t crc_data, crc_skip;
+
+	sum_bytes = segment_size();
+	ss->ss_magic = NANDFS_SEGSUM_MAGIC;
+	ss->ss_bytes = sizeof(struct nandfs_segment_summary);
+	ss->ss_flags = NANDFS_SS_LOGBGN | NANDFS_SS_LOGEND | NANDFS_SS_SR;
+	ss->ss_seq = 1;
+	ss->ss_create = nandfs_time;
+
+	ss->ss_next = nandfs_first_block() + blocks_per_segment;
+	/* nblocks = segment blocks + segsum block + superroot */
+	ss->ss_nblocks = seg_nblocks + 2;
+	ss->ss_nbinfos = seg_nblocks;
+	ss->ss_sumbytes = sum_bytes;
+
+	crc_skip = sizeof(ss->ss_datasum) + sizeof(ss->ss_sumsum);
+	ss->ss_sumsum = crc32_le(0, (uint8_t *)ss + crc_skip,
+	    sum_bytes - crc_skip);
+	crc_data = 0;
+
+	binfo = (union nandfs_binfo *)(ss + 1);
+	for (i = 0; i < nuserfiles; i++) {
+		if (user_files[i].nblocks)
+			binfo = update_block_info(binfo, &user_files[i]);
+	}
+
+	binfo = update_block_info(binfo, &ifile);
+	binfo = update_block_info(binfo, &cpfile);
+	binfo = update_block_info(binfo, &sufile);
+	update_block_info(binfo, &datfile);
+
+	/* save superroot crc */
+	crc_skip = sizeof(sr->sr_sum);
+	sr->sr_sum = crc32_le(0, (uint8_t *)sr + crc_skip,
+	    NANDFS_SR_BYTES - crc_skip);
+
+	/* segment checksup */
+	crc_skip = sizeof(ss->ss_datasum);
+	LIST_FOREACH(block, &block_head, block_link) {
+		if (block->number < NANDFS_FIRST_BLOCK)
+			continue;
+		if (block->number == NANDFS_FIRST_BLOCK)
+			crc_data = crc32_le(0,
+			    (uint8_t *)block->data + crc_skip,
+			    blocksize - crc_skip);
+		else
+			crc_data = crc32_le(crc_data, (uint8_t *)block->data,
+			    blocksize);
+	}
+	ss->ss_datasum = crc_data;
+}
+
+static void
+create_fsdata(void)
+{
+
+	memset(&fsdata, 0, sizeof(struct nandfs_fsdata));
+
+	fsdata.f_magic = NANDFS_FSDATA_MAGIC;
+	fsdata.f_nsegments = nsegments;
+	fsdata.f_erasesize = erasesize;
+	fsdata.f_first_data_block = NANDFS_FIRST_BLOCK;
+	fsdata.f_blocks_per_segment = blocks_per_segment;
+	fsdata.f_r_segments_percentage = rsv_segment_percent;
+	fsdata.f_rev_level = NANDFS_CURRENT_REV;
+	fsdata.f_sbbytes = NANDFS_SB_BYTES;
+	fsdata.f_bytes = NANDFS_FSDATA_CRC_BYTES;
+	fsdata.f_ctime = nandfs_time;
+	fsdata.f_log_block_size = nandfs_log2(blocksize) - 10;
+	fsdata.f_errors = 1;
+	fsdata.f_inode_size = sizeof(struct nandfs_inode);
+	fsdata.f_dat_entry_size = sizeof(struct nandfs_dat_entry);
+	fsdata.f_checkpoint_size = sizeof(struct nandfs_checkpoint);
+	fsdata.f_segment_usage_size = sizeof(struct nandfs_segment_usage);
+
+	uuidgen(&fsdata.f_uuid, 1);
+
+	if (volumelabel)
+		memcpy(fsdata.f_volume_name, volumelabel, 16);
+
+	fsdata.f_sum = crc32_le(0, (const uint8_t *)&fsdata,
+	    NANDFS_FSDATA_CRC_BYTES);
+}
+
+static void
+save_fsdata(void *data)
+{
+
+	memcpy(data, &fsdata, sizeof(fsdata));
+}
+
+static void
+create_super_block(void)
+{
+
+	memset(&super_block, 0, sizeof(struct nandfs_super_block));
+
+	super_block.s_magic = NANDFS_SUPER_MAGIC;
+	super_block.s_last_cno = NANDFS_FIRST_CNO;
+	super_block.s_last_pseg = NANDFS_FIRST_BLOCK;
+	super_block.s_last_seq = 1;
+	super_block.s_free_blocks_count =
+	    (nsegments - bad_segments_count) * blocks_per_segment;
+	super_block.s_mtime = 0;
+	super_block.s_wtime = nandfs_time;
+	super_block.s_state = NANDFS_VALID_FS;
+
+	super_block.s_sum = crc32_le(0, (const uint8_t *)&super_block,
+	    NANDFS_SB_BYTES);
+}
+
+static void
+save_super_block(void *data)
+{
+
+	memcpy(data, &super_block, sizeof(super_block));
+}
+
+static void
+save_super_root(void)
+{
+
+	sr->sr_bytes = NANDFS_SR_BYTES;
+	sr->sr_flags = 0;
+	sr->sr_nongc_ctime = nandfs_time;
+	datfile.inode = &sr->sr_dat;
+	cpfile.inode = &sr->sr_cpfile;
+	sufile.inode = &sr->sr_sufile;
+}
+
+static struct nandfs_dir_entry *
+add_de(void *block, struct nandfs_dir_entry *de, uint64_t ino,
+    const char *name, uint8_t type)
+{
+	uint16_t reclen;
+
+	/* modify last de */
+	de->rec_len = NANDFS_DIR_REC_LEN(de->name_len);
+	de = (void *)((uint8_t *)de + de->rec_len);
+
+	reclen = blocksize - ((uintptr_t)de - (uintptr_t)block);
+	if (reclen < NANDFS_DIR_REC_LEN(strlen(name))) {
+		printf("nandfs: too many dir entries for one block\n");
+		return (NULL);
+	}
+
+	de->inode = ino;
+	de->rec_len = reclen;
+	de->name_len = strlen(name);
+	de->file_type = type;
+	memset(de->name, 0,
+	    (strlen(name) + NANDFS_DIR_PAD - 1) & ~NANDFS_DIR_ROUND);
+	memcpy(de->name, name, strlen(name));
+
+	return (de);
+}
+
+static struct nandfs_dir_entry *
+make_dir(void *block, uint64_t ino, uint64_t parent_ino)
+{
+	struct nandfs_dir_entry *de = (struct nandfs_dir_entry *)block;
+
+	/* create '..' entry */
+	de->inode = parent_ino;
+	de->rec_len = NANDFS_DIR_REC_LEN(2);
+	de->name_len = 2;
+	de->file_type = DT_DIR;
+	memset(de->name, 0, NANDFS_DIR_NAME_LEN(2));
+	memcpy(de->name, "..", 2);
+
+	/* create '.' entry */
+	de = (void *)((uint8_t *)block + NANDFS_DIR_REC_LEN(2));
+	de->inode = ino;
+	de->rec_len = blocksize - NANDFS_DIR_REC_LEN(2);
+	de->name_len = 1;
+	de->file_type = DT_DIR;
+	memset(de->name, 0, NANDFS_DIR_NAME_LEN(1));
+	memcpy(de->name, ".", 1);
+
+	return (de);
+}
+
+static void
+save_root_dir(void)
+{
+	struct file_info *root = &user_files[0];
+	struct nandfs_dir_entry *de;
+	uint32_t i;
+	void *block;
+
+	block = get_block(root->blocks[0], 0);
+
+	de = make_dir(block, root->ino, root->ino);
+	for (i = 1; i < nuserfiles; i++)
+		de = add_de(block, de, user_files[i].ino, user_files[i].name,
+		    IFTODT(user_files[i].mode));
+
+	root->size = ((uintptr_t)de - (uintptr_t)block) +
+	    NANDFS_DIR_REC_LEN(de->name_len);
+}
+
+static void
+save_sufile(void)
+{
+	struct nandfs_sufile_header *header;
+	struct nandfs_segment_usage *su;
+	uint64_t blk, i, off;
+	void *block;
+	int start;
+
+	/*
+	 * At the beginning just zero-out everything
+	 */
+	for (i = 0; i < sufile.nblocks; i++)
+		get_block(sufile.blocks[i], 0);
+
+	start = 0;
+
+	block = get_block(sufile.blocks[start], 0);
+	header = (struct nandfs_sufile_header *)block;
+	header->sh_ncleansegs = nsegments - bad_segments_count - 1;
+	header->sh_ndirtysegs = 1;
+	header->sh_last_alloc = 1;
+
+	su = (struct nandfs_segment_usage *)header;
+	off = NANDFS_SUFILE_FIRST_SEGMENT_USAGE_OFFSET;
+	/* Allocate data segment */
+	su[off].su_lastmod = nandfs_time;
+	/* nblocks = segment blocks + segsum block + superroot */
+	su[off].su_nblocks = seg_nblocks + 2;
+	su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY;
+	off++;
+	/* Allocate next segment */
+	su[off].su_lastmod = nandfs_time;
+	su[off].su_nblocks = 0;
+	su[off].su_flags = NANDFS_SEGMENT_USAGE_DIRTY;
+	for (i = 0; i < bad_segments_count; i++) {
+		nandfs_seg_usage_blk_offset(bad_segments[i], &blk, &off);
+		debug("storing bad_segments[%jd]=%x at %jx off %jx\n", i,
+		    bad_segments[i], blk, off);
+		block = get_block(sufile.blocks[blk],
+		    off * sizeof(struct nandfs_segment_usage *));
+		su = (struct nandfs_segment_usage *)block;
+		su[off].su_lastmod = nandfs_time;
+		su[off].su_nblocks = 0;
+		su[off].su_flags = NANDFS_SEGMENT_USAGE_ERROR;
+	}
+}
+
+static void
+save_cpfile(void)
+{
+	struct nandfs_cpfile_header *header;
+	struct nandfs_checkpoint *cp, *initial_cp;
+	int i, entries = blocksize / sizeof(struct nandfs_checkpoint);
+	uint64_t cno;
+
+	header = (struct nandfs_cpfile_header *)get_block(cpfile.blocks[0], 0);
+	header->ch_ncheckpoints = 1;
+	header->ch_nsnapshots = 0;
+
+	cp = (struct nandfs_checkpoint *)header;
+
+	/* fill first checkpoint data*/
+	initial_cp = &cp[NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET];
+	initial_cp->cp_flags = 0;
+	initial_cp->cp_checkpoints_count = 0;
+	initial_cp->cp_cno = NANDFS_FIRST_CNO;
+	initial_cp->cp_create = nandfs_time;
+	initial_cp->cp_nblk_inc = seg_endblock - 1;
+	initial_cp->cp_blocks_count = seg_nblocks;
+	memset(&initial_cp->cp_snapshot_list, 0,
+	    sizeof(struct nandfs_snapshot_list));
+
+	ifile.inode = &initial_cp->cp_ifile_inode;
+
+	/* mark rest of cp as invalid */
+	cno = NANDFS_FIRST_CNO + 1;
+	i = NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET + 1;
+	for (; i < entries; i++) {
+		cp[i].cp_cno = cno++;
+		cp[i].cp_flags = NANDFS_CHECKPOINT_INVALID;
+	}
+}
+
+static void
+init_inode(struct nandfs_inode *inode, struct file_info *file)
+{
+
+	inode->i_blocks = file->nblocks;
+	inode->i_ctime = nandfs_time;
+	inode->i_mtime = nandfs_time;
+	inode->i_mode = file->mode & 0xffff;
+	inode->i_links_count = 1;
+
+	if (file->size > 0)
+		inode->i_size = file->size;
+	else
+		inode->i_size = 0;
+
+	if (file->ino == NANDFS_USER_INO)
+		inode->i_flags = SF_NOUNLINK|UF_NOUNLINK;
+	else
+		inode->i_flags = 0;
+}
+
+static void
+save_ifile(void)
+{
+	struct nandfs_inode *inode;
+	struct file_info *file;
+	uint64_t ino, blk, off;
+	uint32_t i;
+
+	prepare_blockgrouped_file(ifile.blocks[0]);
+	for (i = 0; i <= NANDFS_USER_INO; i++)
+		alloc_blockgrouped_file(ifile.blocks[0], i);
+
+	for (i = 0; i < nuserfiles; i++) {
+		file = &user_files[i];
+		ino = file->ino;
+		blk = ino / (blocksize / sizeof(*inode));
+		off = ino % (blocksize / sizeof(*inode));
+		inode =
+		    (struct nandfs_inode *)get_block(ifile.blocks[2 + blk], 2 + blk);
+		file->inode = &inode[off];
+		init_inode(file->inode, file);
+	}
+
+	init_inode(ifile.inode, &ifile);
+	init_inode(cpfile.inode, &cpfile);
+	init_inode(sufile.inode, &sufile);
+	init_inode(datfile.inode, &datfile);
+}
+
+static int
+create_fs(void)
+{
+	uint64_t start_block;
+	uint32_t segsum_size;
+	char *data;
+	int i;
+
+	nuserfiles = (sizeof(user_files) / sizeof(user_files[0]));
+
+	/* Count and assign blocks */
+	count_seg_blocks();
+	segsum_size = segment_size();
+	start_block = NANDFS_FIRST_BLOCK + SIZE_TO_BLOCK(segsum_size);
+	assign_file_blocks(start_block);
+
+	/* Create super root structure */
+	save_super_root();
+
+	/* Create root directory */
+	save_root_dir();
+
+	/* Fill in file contents */
+	save_sufile();
+	save_cpfile();
+	save_ifile();
+	save_datfile();
+
+	/* Save fsdata and superblocks */
+	create_fsdata();
+	create_super_block();
+
+	for (i = 0; i < NANDFS_NFSAREAS; i++) {
+		if (fsdata_blocks_state[i] != NANDFS_BLOCK_GOOD)
+			continue;
+
+		data = get_block((i * erasesize)/blocksize, 0);
+		save_fsdata(data);
+
+		data = get_block((i * erasesize + NANDFS_SBLOCK_OFFSET_BYTES) /
+		    blocksize, 0);
+		if (blocksize > NANDFS_SBLOCK_OFFSET_BYTES)
+			data += NANDFS_SBLOCK_OFFSET_BYTES;
+		save_super_block(data);
+		memset(data + sizeof(struct nandfs_super_block), 0xff,
+		    (blocksize - sizeof(struct nandfs_super_block) -
+		    NANDFS_SBLOCK_OFFSET_BYTES));
+	}
+
+	/* Save segment summary and CRCs */
+	save_segsum(get_block(NANDFS_FIRST_BLOCK, 0));
+
+	return (0);
+}
+
+static void
+write_fs(int fda)
+{
+	struct nandfs_block *block;
+	char *data;
+	u_int ret;
+
+	/* Overwrite next block with ff if not nand device */
+	if (!is_nand) {
+		data = get_block(seg_endblock, 0);
+		memset(data, 0xff, blocksize);
+	}
+
+	LIST_FOREACH(block, &block_head, block_link) {
+		lseek(fda, block->number * blocksize, SEEK_SET);
+		ret = write(fda, block->data, blocksize);
+		if (ret != blocksize)
+			err(1, "cannot write filesystem data");
+	}
+}
+
+static void
+check_parameters(void)
+{
+	int i;
+
+	/* check blocksize */
+	if ((blocksize < NANDFS_MIN_BLOCKSIZE) || (blocksize > MAXBSIZE) ||
+	    ((blocksize - 1) & blocksize)) {
+		errx(1, "Bad blocksize (%zu). Must be in range [%u-%u] "
+		    "and a power of two.", blocksize, NANDFS_MIN_BLOCKSIZE,
+		    MAXBSIZE);
+	}
+
+	/* check blocks per segments */
+	if ((blocks_per_segment < NANDFS_SEG_MIN_BLOCKS) ||
+	    ((blocksize - 1) & blocksize))
+		errx(1, "Bad blocks per segment (%lu). Must be greater than "
+		    "%u and a power of two.", blocks_per_segment,
+		    NANDFS_SEG_MIN_BLOCKS);
+
+	/* check reserved segment percentage */
+	if ((rsv_segment_percent < 1) && (rsv_segment_percent > 99))
+		errx(1, "Bad reserved segment percentage. "
+		    "Must in range 1..99.");
+
+	/* check volume label */
+	i = 0;
+	if (volumelabel) {
+		while (isalnum(volumelabel[++i]))
+			;
+
+		if (volumelabel[i] != '\0') {
+			errx(1, "bad volume label. "
+			    "Valid characters are alphanumerics.");
+		}
+
+		if (strlen(volumelabel) >= 16)
+			errx(1, "Bad volume label. Length is longer than %d.",
+			    16);
+	}
+
+	nandfs_time = time(NULL);
+}
+
+static void
+print_parameters(void)
+{
+
+	printf("filesystem parameters:\n");
+	printf("blocksize: %#zx sectorsize: %#zx\n", blocksize, sectorsize);
+	printf("erasesize: %#jx mediasize: %#jx\n", erasesize, mediasize);
+	printf("segment size: %#jx blocks per segment: %#x\n", segsize,
+	    (uint32_t)blocks_per_segment);
+}
+
+/*
+ * Exit with error if file system is mounted.
+ */
+static void
+check_mounted(const char *fname, mode_t mode)
+{
+	struct statfs *mp;
+	const char *s1, *s2;
+	size_t len;
+	int n, r;
+
+	if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
+		err(1, "getmntinfo");
+
+	len = strlen(_PATH_DEV);
+	s1 = fname;
+	if (!strncmp(s1, _PATH_DEV, len))
+		s1 += len;
+
+	r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
+
+	for (; n--; mp++) {
+		s2 = mp->f_mntfromname;
+
+		if (!strncmp(s2, _PATH_DEV, len))
+			s2 += len;
+		if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
+		    !strcmp(s1, s2))
+			errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
+	}
+}
+
+static void
+calculate_geometry(int fd)
+{
+	struct chip_param_io chip_params;
+	char ident[DISK_IDENT_SIZE];
+	char medianame[MAXPATHLEN];
+
+	/* Check storage type */
+	g_get_ident(fd, ident, DISK_IDENT_SIZE);
+	g_get_name(ident, medianame, MAXPATHLEN);
+	debug("device name: %s", medianame);
+
+	is_nand = (strstr(medianame, "gnand") != NULL);
+	debug("is_nand = %d", is_nand);
+
+	sectorsize = g_sectorsize(fd);
+	debug("sectorsize: %#zx", sectorsize);
+
+	/* Get storage size */
+	mediasize = g_mediasize(fd);
+	debug("mediasize: %#jx", mediasize);
+
+	/* Get storage erase unit size */
+	if (!is_nand)
+		erasesize = NANDFS_DEF_ERASESIZE;
+	else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1)
+		errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
+	else
+		erasesize = chip_params.page_size * chip_params.pages_per_block;
+
+	debug("erasesize: %#jx", (uintmax_t)erasesize);
+
+	if (blocks_per_segment == 0) {
+		if (erasesize >= NANDFS_MIN_SEGSIZE)
+			blocks_per_segment = erasesize / blocksize;
+		else
+			blocks_per_segment = NANDFS_MIN_SEGSIZE / blocksize;
+	}
+
+	/* Calculate number of segments */
+	segsize = blocksize * blocks_per_segment;
+	nsegments = ((mediasize - NANDFS_NFSAREAS * erasesize) / segsize) - 2;
+	debug("segsize: %#jx", segsize);
+	debug("nsegments: %#jx", nsegments);
+}
+
+static void
+erase_device(int fd)
+{
+	int rest, failed;
+	uint64_t i, nblocks;
+	off_t offset;
+
+	failed = 0;
+	for (i = 0; i < NANDFS_NFSAREAS; i++) {
+		debug("Deleting %jx\n", i * erasesize);
+		if (g_delete(fd, i * erasesize, erasesize)) {
+			printf("cannot delete %jx\n", i * erasesize);
+			fsdata_blocks_state[i] = NANDFS_BLOCK_BAD;
+			failed++;
+		} else
+			fsdata_blocks_state[i] = NANDFS_BLOCK_GOOD;
+	}
+
+	if (failed == NANDFS_NFSAREAS) {
+		printf("%d first blocks not usable. Unable to create "
+		    "filesystem.\n", failed);
+		exit(1);
+	}
+
+	for (i = 0; i < nsegments; i++) {
+		offset = NANDFS_NFSAREAS * erasesize + i * segsize;
+		if (g_delete(fd, offset, segsize)) {
+			printf("cannot delete segment %jx (offset %jd)\n",
+			    i, offset);
+			bad_segments_count++;
+			bad_segments = realloc(bad_segments,
+			    bad_segments_count * sizeof(uint32_t));
+			bad_segments[bad_segments_count - 1] = i;
+		}
+	}
+
+	if (bad_segments_count == nsegments) {
+		printf("no valid segments\n");
+		exit(1);
+	}
+
+	/* Delete remaining blocks at the end of device */
+	rest = mediasize % segsize;
+	nblocks = rest / erasesize;
+	for (i = 0; i < nblocks; i++) {
+		offset = (segsize * nsegments) + (i * erasesize);
+		if (g_delete(fd, offset, erasesize)) {
+			printf("cannot delete space after last segment "
+			    "- probably a bad block\n");
+		}
+	}
+}
+
+static void
+erase_initial(int fd)
+{
+	char buf[512];
+	u_int i;
+
+	memset(buf, 0xff, sizeof(buf));
+
+	lseek(fd, 0, SEEK_SET);
+	for (i = 0; i < NANDFS_NFSAREAS * erasesize; i += sizeof(buf))
+		write(fd, buf, sizeof(buf));
+}
+
+static void
+create_nandfs(int fd)
+{
+
+	create_fs();
+
+	write_fs(fd);
+}
+
+static void
+print_summary(void)
+{
+
+	printf("filesystem created succesfully\n");
+	printf("total segments: %#jx valid segments: %#jx\n", nsegments,
+	    nsegments - bad_segments_count);
+	printf("total space: %ju MB free: %ju MB\n",
+	    (nsegments *
+	    blocks_per_segment * blocksize) / (1024 * 1024),
+	    ((nsegments - bad_segments_count) *
+	    blocks_per_segment * blocksize) / (1024 * 1024));
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct stat sb;
+	char buf[MAXPATHLEN];
+	const char opts[] = "b:B:L:m:";
+	const char *fname;
+	int ch, fd;
+
+	while ((ch = getopt(argc, argv, opts)) != -1) {
+		switch (ch) {
+		case 'b':
+			blocksize = strtol(optarg, (char **)NULL, 10);
+			if (blocksize == 0)
+				usage();
+			break;
+		case 'B':
+			blocks_per_segment = strtol(optarg, (char **)NULL, 10);
+			if (blocks_per_segment == 0)
+				usage();
+			break;
+		case 'L':
+			volumelabel = optarg;
+			break;
+		case 'm':
+			rsv_segment_percent = strtol(optarg, (char **)NULL, 10);
+			if (rsv_segment_percent == 0)
+				usage();
+			break;
+		default:
+			usage();
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
+	if (argc < 1 || argc > 2)
+		usage();
+
+	/* construct proper device path */
+	fname = *argv++;
+	if (!strchr(fname, '/')) {
+		snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
+		if (!(fname = strdup(buf)))
+			err(1, NULL);
+	}
+
+	fd = g_open(fname, 1);
+	if (fd == -1)
+		err(1, "Cannot open %s", fname);
+
+	if (fstat(fd, &sb) == -1)
+		err(1, "Cannot stat %s", fname);
+	if (!S_ISCHR(sb.st_mode))
+		warnx("%s is not a character device", fname);
+
+	check_mounted(fname, sb.st_mode);
+
+	calculate_geometry(fd);
+
+	check_parameters();
+
+	print_parameters();
+
+	if (is_nand)
+		erase_device(fd);
+	else
+		erase_initial(fd);
+
+	create_nandfs(fd);
+
+	print_summary();
+
+	g_close(fd);
+
+	return (0);
+}
+
+
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/ping/ping.c
--- a/head/sbin/ping/ping.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/ping/ping.c	Wed Jul 25 16:24:55 2012 +0300
@@ -42,7 +42,7 @@
 #endif /* not lint */
 #endif
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
+__FBSDID("$FreeBSD: head/sbin/ping/ping.c 237942 2012-07-02 02:38:27Z delphij $");
 
 /*
  *			P I N G . C
@@ -832,7 +832,7 @@
 			timeout.tv_sec++;
 		}
 		if (timeout.tv_sec < 0)
-			timeout.tv_sec = timeout.tv_usec = 0;
+			timerclear(&timeout);
 		n = select(s + 1, &rfds, NULL, NULL, &timeout);
 		if (n < 0)
 			continue;	/* Must be EINTR. */
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/restore/restore.8
--- a/head/sbin/restore/restore.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/restore/restore.8	Wed Jul 25 16:24:55 2012 +0300
@@ -26,7 +26,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)restore.8	8.4 (Berkeley) 5/1/95
-.\" $FreeBSD$
+.\" $FreeBSD: head/sbin/restore/restore.8 235837 2012-05-23 15:06:13Z joel $
 .\"
 .Dd October 12, 2006
 .Dt RESTORE 8
@@ -68,16 +68,6 @@
 .Op Fl f Ar file | Fl P Ar pipecommand
 .Op Fl s Ar fileno
 .Op Ar
-.Pp
-.Nm rrestore
-is an alternate name for
-.Nm .
-.Pp
-.in \" XXX
-(The
-.Bx 4.3
-option syntax is implemented for backward compatibility, but
-is not documented here.)
 .Sh DESCRIPTION
 The
 .Nm
@@ -104,6 +94,14 @@
 the appearance of a directory name refers to
 the files and (recursively) subdirectories of that directory.
 .Pp
+.Nm
+may also be invoked as
+.Nm rrestore .
+The
+.Bx 4.3
+option syntax is implemented for backward compatibility, but
+is not documented here.
+.Pp
 Exactly one of the following flags is required:
 .Bl -tag -width Ds
 .It Fl i
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/restore/utilities.c
--- a/head/sbin/restore/utilities.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/restore/utilities.c	Wed Jul 25 16:24:55 2012 +0300
@@ -32,7 +32,7 @@
 static char sccsid[] = "@(#)utilities.c	8.5 (Berkeley) 4/28/95";
 #endif
 static const char rcsid[] =
-  "$FreeBSD$";
+  "$FreeBSD: head/sbin/restore/utilities.c 236213 2012-05-29 01:48:06Z kevlo $";
 #endif /* not lint */
 
 #include <sys/param.h>
@@ -411,6 +411,7 @@
 	va_list ap;
 	va_start(ap, fmt);
 	vfprintf(stderr, fmt, ap);
+	va_end(ap);
 	if (yflag)
 		return;
 	if (reply("abort") == GOOD) {
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/setkey/setkey.8
--- a/head/sbin/setkey/setkey.8	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/setkey/setkey.8	Wed Jul 25 16:24:55 2012 +0300
@@ -27,7 +27,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\" $FreeBSD: head/sbin/setkey/setkey.8 233522 2012-03-26 21:22:53Z joel $
+.\" $FreeBSD: head/sbin/setkey/setkey.8 236502 2012-06-03 07:45:42Z joel $
 .\"
 .Dd May 13, 2006
 .Dt SETKEY 8
@@ -130,7 +130,7 @@
 .Ar src Ar dst Ar protocol Ar spi
 .Op Ar extensions
 .Ar algorithm ...
-.Li ;
+.Li \&;
 .Xc
 Add an SAD entry.
 .Li add
@@ -141,7 +141,7 @@
 .Li get
 .Op Fl 46n
 .Ar src Ar dst Ar protocol Ar spi
-.Li ;
+.Li \&;
 .Xc
 Show an SAD entry.
 .\"
@@ -149,7 +149,7 @@
 .Li delete
 .Op Fl 46n
 .Ar src Ar dst Ar protocol Ar spi
-.Li ;
+.Li \&;
 .Xc
 Remove an SAD entry.
 .\"
@@ -157,14 +157,14 @@
 .Li deleteall
 .Op Fl 46n
 .Ar src Ar dst Ar protocol
-.Li ;
+.Li \&;
 .Xc
 Remove all SAD entries that match the specification.
 .\"
 .It Xo
 .Li flush
 .Op Ar protocol
-.Li ;
+.Li \&;
 .Xc
 Clear all SAD entries matched by the options.
 .Fl F
@@ -173,7 +173,7 @@
 .It Xo
 .Li dump
 .Op Ar protocol
-.Li ;
+.Li \&;
 .Xc
 Dumps all SAD entries matched by the options.
 .Fl D
@@ -183,7 +183,7 @@
 .Li spdadd
 .Op Fl 46n
 .Ar src_range Ar dst_range Ar upperspec Ar policy
-.Li ;
+.Li \&;
 .Xc
 Add an SPD entry.
 .\"
@@ -191,13 +191,13 @@
 .Li spddelete
 .Op Fl 46n
 .Ar src_range Ar dst_range Ar upperspec Fl P Ar direction
-.Li ;
+.Li \&;
 .Xc
 Delete an SPD entry.
 .\"
 .It Xo
 .Li spdflush
-.Li ;
+.Li \&;
 .Xc
 Clear all SPD entries.
 .Fl FP
@@ -205,7 +205,7 @@
 .\"
 .It Xo
 .Li spddump
-.Li ;
+.Li \&;
 .Xc
 Dumps all SPD entries.
 .Fl DP
@@ -442,7 +442,7 @@
 .Ar policy
 is expressed in one of the following three formats:
 .Pp
-.Bl -tag -compact
+.Bl -tag -width 2n -compact
 .It Fl P Ar direction Li discard
 .It Fl P Ar direction Li none
 .It Xo Fl P Ar direction Li ipsec
@@ -553,7 +553,9 @@
 example, if an IP header was followed by an AH header followed by an
 ESP header followed by an upper layer protocol header, the rule would
 be:
+.Pp
 .Dl esp/transport//require ah/transport//require ;
+.Pp
 The rule order is very important.
 .Pp
 Note that
diff -r 7449ca4973e7 -r 4936d08172d1 head/sbin/shutdown/shutdown.c
--- a/head/sbin/shutdown/shutdown.c	Wed Jul 25 16:23:00 2012 +0300
+++ b/head/sbin/shutdown/shutdown.c	Wed Jul 25 16:24:55 2012 +0300
@@ -39,7 +39,7 @@
 #endif /* not lint */
 #endif
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sbin/shutdown/shutdown.c 229403 2012-01-03 18:51:58Z ed $");
+__FBSDID("$FreeBSD: head/sbin/shutdown/shutdown.c 235855 2012-05-23 19:25:46Z jilles $");
 
 #include <sys/param.h>
 #include <sys/time.h>
@@ -356,7 +356,6 @@
 	syslog(LOG_NOTICE, "%s by %s: %s",
 	    doreboot ? "reboot" : dohalt ? "halt" : dopower ? "power-down" : 
 	    "shutdown", whom, mbuf);
-	(void)sleep(2);
 
 	(void)printf("\r\nSystem shutdown time has arrived\007\007\r\n");
 	if (killflg) {


More information about the Zrouter-src-freebsd mailing list