summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2013-09-05 20:18:59 +0000
committersjg <sjg@FreeBSD.org>2013-09-05 20:18:59 +0000
commit62bb1062226d3ce6a2350808256a25508978352d (patch)
tree22b131dceb13c3df96da594fbaadb693504797c7 /sbin
parent72ab90509b3a51ab361bf710338f2ef44a4e360d (diff)
parent04932445481c2cb89ff69a83b961bdef3d64757e (diff)
downloadFreeBSD-src-62bb1062226d3ce6a2350808256a25508978352d.zip
FreeBSD-src-62bb1062226d3ce6a2350808256a25508978352d.tar.gz
Merge from head
Diffstat (limited to 'sbin')
-rw-r--r--sbin/camcontrol/camcontrol.8103
-rw-r--r--sbin/camcontrol/camcontrol.c704
-rw-r--r--sbin/camcontrol/fwdownload.c8
-rw-r--r--sbin/devd/devd.86
-rw-r--r--sbin/devd/devd.cc160
-rw-r--r--sbin/devd/devd.h2
-rw-r--r--sbin/devd/token.l5
-rw-r--r--sbin/devfs/devfs.872
-rw-r--r--sbin/dhclient/bpf.c222
-rw-r--r--sbin/dhclient/clparse.c4
-rw-r--r--sbin/dhclient/dhclient.c152
-rw-r--r--sbin/dhclient/dhcpd.h20
-rw-r--r--sbin/dhclient/packet.c14
-rw-r--r--sbin/dhclient/privsep.c5
-rw-r--r--sbin/dhclient/privsep.h5
-rw-r--r--sbin/dmesg/dmesg.86
-rw-r--r--sbin/dmesg/dmesg.c19
-rw-r--r--sbin/dumpfs/dumpfs.823
-rw-r--r--sbin/dumpfs/dumpfs.c13
-rw-r--r--sbin/dumpon/dumpon.815
-rw-r--r--sbin/etherswitchcfg/etherswitchcfg.859
-rw-r--r--sbin/etherswitchcfg/etherswitchcfg.c231
-rw-r--r--sbin/fdisk_pc98/fdisk.c16
-rw-r--r--sbin/fsck_ffs/fsck.h6
-rw-r--r--sbin/fsck_ffs/fsck_ffs.818
-rw-r--r--sbin/fsck_ffs/fsutil.c42
-rw-r--r--sbin/fsck_ffs/main.c10
-rw-r--r--sbin/fsck_ffs/pass5.c15
-rw-r--r--sbin/gbde/Makefile1
-rw-r--r--sbin/geom/class/Makefile.inc2
-rw-r--r--sbin/geom/class/eli/geli.89
-rw-r--r--sbin/geom/class/label/glabel.84
-rw-r--r--sbin/geom/class/nop/gnop.89
-rw-r--r--sbin/geom/class/part/geom_part.c8
-rw-r--r--sbin/geom/class/part/gpart.890
-rw-r--r--sbin/growfs/growfs.c9
-rw-r--r--sbin/hastctl/Makefile5
-rw-r--r--sbin/hastctl/hastctl.c16
-rw-r--r--sbin/hastd/Makefile3
-rw-r--r--sbin/hastd/control.c1
-rw-r--r--sbin/hastd/hast.h3
-rw-r--r--sbin/hastd/hastd.836
-rw-r--r--sbin/hastd/parse.y2
-rw-r--r--sbin/hastd/primary.c13
-rw-r--r--sbin/hastd/refcnt.h13
-rw-r--r--sbin/hastd/subr.c9
-rw-r--r--sbin/hastd/token.l4
-rw-r--r--sbin/ifconfig/af_nd6.c2
-rw-r--r--sbin/ifconfig/ifconfig.812
-rw-r--r--sbin/ifconfig/iflagg.c4
-rw-r--r--sbin/init/init.c3
-rw-r--r--sbin/ipfw/ipfw.810
-rw-r--r--sbin/ipfw/ipfw2.c38
-rw-r--r--sbin/iscontrol/auth_subr.c5
-rw-r--r--sbin/iscontrol/config.c2
-rw-r--r--sbin/iscontrol/fsm.c5
-rw-r--r--sbin/iscontrol/iscontrol.c2
-rw-r--r--sbin/iscontrol/iscsi.conf.54
-rw-r--r--sbin/iscontrol/login.c5
-rw-r--r--sbin/iscontrol/misc.c5
-rw-r--r--sbin/iscontrol/pdu.c2
-rw-r--r--sbin/md5/Makefile1
-rw-r--r--sbin/mdconfig/mdconfig.816
-rw-r--r--sbin/mdconfig/mdconfig.c79
-rw-r--r--sbin/mount/Makefile2
-rw-r--r--sbin/mount/mount.819
-rw-r--r--sbin/mount/mount.c16
-rw-r--r--sbin/mount/mount.conf.8252
-rw-r--r--sbin/mount_nfs/mount_nfs.826
-rw-r--r--sbin/newfs_nandfs/newfs_nandfs.c35
-rw-r--r--sbin/nvmecontrol/Makefile4
-rw-r--r--sbin/nvmecontrol/devlist.c116
-rw-r--r--sbin/nvmecontrol/firmware.c309
-rw-r--r--sbin/nvmecontrol/identify.c284
-rw-r--r--sbin/nvmecontrol/logpage.c357
-rw-r--r--sbin/nvmecontrol/nvmecontrol.836
-rw-r--r--sbin/nvmecontrol/nvmecontrol.c649
-rw-r--r--sbin/nvmecontrol/nvmecontrol.h74
-rw-r--r--sbin/nvmecontrol/perftest.c176
-rw-r--r--sbin/nvmecontrol/reset.c71
-rw-r--r--sbin/ping6/ping6.815
-rw-r--r--sbin/ping6/ping6.c29
-rw-r--r--sbin/reboot/boot_i386.83
-rw-r--r--sbin/recoverdisk/recoverdisk.16
-rw-r--r--sbin/route/Makefile19
-rw-r--r--sbin/route/route.c784
-rw-r--r--sbin/routed/routed.82
-rw-r--r--sbin/swapon/swapon.828
-rw-r--r--sbin/swapon/swapon.c575
-rw-r--r--sbin/tunefs/tunefs.c8
90 files changed, 4729 insertions, 1553 deletions
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 7a13aa4..df0b3e7 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 4, 2012
+.Dd April 24, 2013
.Dt CAMCONTROL 8
.Os
.Sh NAME
@@ -243,6 +243,18 @@
.Op Fl U Ar user|master
.Op Fl y
.Nm
+.Ic hpa
+.Op device id
+.Op generic args
+.Op Fl f
+.Op Fl l
+.Op Fl P
+.Op Fl p Ar pwd
+.Op Fl q
+.Op Fl s Ar max_sectors
+.Op Fl U Ar pwd
+.Op Fl y
+.Nm
.Ic help
.Sh DESCRIPTION
The
@@ -1205,6 +1217,73 @@ password for the specified user the command will fail.
.Pp
The password in all cases is limited to 32 characters, longer passwords will
fail.
+.It Ic hpa
+Update or report Host Protected Area details.
+By default
+.Nm
+will print out the HPA support and associated settings of the device.
+The
+.Ic hpa
+command takes several optional arguments:
+.Bl -tag -width 0n
+.It Fl f
+.Pp
+Freeze the HPA configuration of the specified device.
+.Pp
+After command completion any other commands that update the HPA configuration
+shall be command aborted.
+Frozen mode is disabled by power-off or hardware reset.
+.It Fl l
+.Pp
+Lock the HPA configuration of the device until a successful call to unlock or
+the next power-on reset occurs.
+.It Fl P
+.Pp
+Make the HPA max sectors persist across power-on reset or a hardware reset.
+This must be used in combination with
+.Fl s Ar max_sectors
+.
+.It Fl p Ar pwd
+.Pp
+Set the HPA configuration password required for unlock calls.
+.It Fl q
+.Pp
+Be quiet, do not print any status messages.
+This option will not disable the questions.
+To disable questions, use the
+.Fl y
+argument, below.
+.It Fl s Ar max_sectors
+.Pp
+Configures the maximum user accessible sectors of the device.
+This will change the number of sectors the device reports.
+.Pp
+.Em WARNING! WARNING! WARNING!
+.Pp
+Changing the max sectors of a device using this option will make the data on
+the device beyond the specified value inaccessible.
+.Pp
+Only one successful
+.Fl s Ar max_sectors
+call can be made without a power-on reset or a hardware reset of the device.
+.It Fl U Ar pwd
+.Pp
+Unlock the HPA configuration of the specified device using the given password.
+If the password specified doesn't match the password configured via
+.Fl p Ar pwd
+the command will fail.
+.Pp
+After 5 failed unlock calls, due to password miss-match, the device will refuse
+additional unlock calls until after a power-on reset.
+.It Fl y
+.Pp
+Confirm yes to dangerous options such as
+.Fl e
+without prompting for confirmation
+.Pp
+.El
+The password for all HPA commands is limited to 32 characters, longer passwords
+will fail.
.It Ic fwdownload
Program firmware of the named SCSI device using the image file provided.
.Pp
@@ -1397,6 +1476,28 @@ data from the device, so backup your data before using!
.Pp
This command can be used used against an SSD drive to restoring it to
factory default write performance.
+.Bd -literal -offset indent
+camcontrol hpa ada0
+.Ed
+.Pp
+Report HPA support and settings for ada0 (also reported via
+identify).
+.Bd -literal -offset indent
+camcontrol hpa ada0 -s 10240
+.Ed
+.Pp
+Enables HPA on ada0 setting the maximum reported sectors to 10240.
+.Pp
+.Em WARNING! WARNING! WARNING!
+.Pp
+This will
+.Em PREVENT ACCESS
+to all data on the device beyond this limit until HPA is disabled by setting
+HPA to native max sectors of the device, which can only be done after a
+power-on or hardware reset!
+.Pp
+.Em DO NOT
+use this on a device which has an active filesystem!
.Sh SEE ALSO
.Xr cam 3 ,
.Xr cam_cdbparse 3 ,
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 90ceb9a..76b3939 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -45,6 +45,10 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <err.h>
#include <libutil.h>
+#ifndef MINIMALISTIC
+#include <limits.h>
+#include <inttypes.h>
+#endif
#include <cam/cam.h>
#include <cam/cam_debug.h>
@@ -88,7 +92,8 @@ typedef enum {
CAM_CMD_SMP_PHYLIST = 0x0000001a,
CAM_CMD_SMP_MANINFO = 0x0000001b,
CAM_CMD_DOWNLOAD_FW = 0x0000001c,
- CAM_CMD_SECURITY = 0x0000001d
+ CAM_CMD_SECURITY = 0x0000001d,
+ CAM_CMD_HPA = 0x0000001e
} cam_cmdmask;
typedef enum {
@@ -135,6 +140,29 @@ struct camcontrol_opts {
};
#ifndef MINIMALISTIC
+struct ata_res_pass16 {
+ u_int16_t reserved[5];
+ u_int8_t flags;
+ u_int8_t error;
+ u_int8_t sector_count_exp;
+ u_int8_t sector_count;
+ u_int8_t lba_low_exp;
+ u_int8_t lba_low;
+ u_int8_t lba_mid_exp;
+ u_int8_t lba_mid;
+ u_int8_t lba_high_exp;
+ u_int8_t lba_high;
+ u_int8_t device;
+ u_int8_t status;
+};
+
+struct ata_set_max_pwd
+{
+ u_int16_t reserved1;
+ u_int8_t password[32];
+ u_int16_t reserved2[239];
+};
+
static const char scsicmd_opts[] = "a:c:dfi:o:r";
static const char readdefect_opts[] = "f:GP";
static const char negotiate_opts[] = "acD:M:O:qR:T:UW:";
@@ -186,6 +214,7 @@ static struct camcontrol_opts option_table[] = {
{"sleep", CAM_CMD_SLEEP, CAM_ARG_NONE, ""},
{"fwdownload", CAM_CMD_DOWNLOAD_FW, CAM_ARG_NONE, "f:ys"},
{"security", CAM_CMD_SECURITY, CAM_ARG_NONE, "d:e:fh:k:l:qs:T:U:y"},
+ {"hpa", CAM_CMD_HPA, CAM_ARG_NONE, "Pflp:qs:U:y"},
#endif /* MINIMALISTIC */
{"help", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
{"-?", CAM_CMD_USAGE, CAM_ARG_NONE, NULL},
@@ -280,6 +309,8 @@ static int atapm(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
static int atasecurity(struct cam_device *device, int retry_count, int timeout,
int argc, char **argv, char *combinedopt);
+static int atahpa(struct cam_device *device, int retry_count, int timeout,
+ int argc, char **argv, char *combinedopt);
#endif /* MINIMALISTIC */
#ifndef min
@@ -1128,6 +1159,38 @@ xferrate_bailout:
}
static void
+atahpa_print(struct ata_params *parm, u_int64_t hpasize, int header)
+{
+ u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
+ ((u_int32_t)parm->lba_size_2 << 16);
+
+ u_int64_t lbasize48 = ((u_int64_t)parm->lba_size48_1) |
+ ((u_int64_t)parm->lba_size48_2 << 16) |
+ ((u_int64_t)parm->lba_size48_3 << 32) |
+ ((u_int64_t)parm->lba_size48_4 << 48);
+
+ if (header) {
+ printf("\nFeature "
+ "Support Enabled Value\n");
+ }
+
+ printf("Host Protected Area (HPA) ");
+ if (parm->support.command1 & ATA_SUPPORT_PROTECTED) {
+ u_int64_t lba = lbasize48 ? lbasize48 : lbasize;
+ printf("yes %s %ju/%ju\n", (hpasize > lba) ? "yes" : "no ",
+ lba, hpasize);
+
+ printf("HPA - Security ");
+ if (parm->support.command1 & ATA_SUPPORT_MAXSECURITY)
+ printf("yes\n");
+ else
+ printf("no\n");
+ } else {
+ printf("no\n");
+ }
+}
+
+static void
atacapprint(struct ata_params *parm)
{
u_int32_t lbasize = (u_int32_t)parm->lba_size_1 |
@@ -1554,6 +1617,83 @@ ata_do_28bit_cmd(struct cam_device *device, union ccb *ccb, int retries,
return ata_cam_send(device, ccb, quiet);
}
+static int
+ata_do_cmd(struct cam_device *device, union ccb *ccb, int retries,
+ u_int32_t flags, u_int8_t protocol, u_int8_t ata_flags,
+ u_int8_t tag_action, u_int8_t command, u_int8_t features,
+ u_int64_t lba, u_int8_t sector_count, u_int8_t *data_ptr,
+ u_int16_t dxfer_len, int timeout, int force48bit)
+{
+ int retval;
+
+ retval = ata_try_pass_16(device);
+ if (retval == -1)
+ return (1);
+
+ if (retval == 1) {
+ int error;
+
+ /* Try using SCSI Passthrough */
+ error = ata_do_pass_16(device, ccb, retries, flags, protocol,
+ ata_flags, tag_action, command, features,
+ lba, sector_count, data_ptr, dxfer_len,
+ timeout, 0);
+
+ if (ata_flags & AP_FLAG_CHK_COND) {
+ /* Decode ata_res from sense data */
+ struct ata_res_pass16 *res_pass16;
+ struct ata_res *res;
+ u_int i;
+ u_int16_t *ptr;
+
+ /* sense_data is 4 byte aligned */
+ ptr = (uint16_t*)(uintptr_t)&ccb->csio.sense_data;
+ for (i = 0; i < sizeof(*res_pass16) / 2; i++)
+ ptr[i] = le16toh(ptr[i]);
+
+ /* sense_data is 4 byte aligned */
+ res_pass16 = (struct ata_res_pass16 *)(uintptr_t)
+ &ccb->csio.sense_data;
+ res = &ccb->ataio.res;
+ res->flags = res_pass16->flags;
+ res->status = res_pass16->status;
+ res->error = res_pass16->error;
+ res->lba_low = res_pass16->lba_low;
+ res->lba_mid = res_pass16->lba_mid;
+ res->lba_high = res_pass16->lba_high;
+ res->device = res_pass16->device;
+ res->lba_low_exp = res_pass16->lba_low_exp;
+ res->lba_mid_exp = res_pass16->lba_mid_exp;
+ res->lba_high_exp = res_pass16->lba_high_exp;
+ res->sector_count = res_pass16->sector_count;
+ res->sector_count_exp = res_pass16->sector_count_exp;
+ }
+
+ return (error);
+ }
+
+ bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_ataio) -
+ sizeof(struct ccb_hdr));
+ cam_fill_ataio(&ccb->ataio,
+ retries,
+ NULL,
+ flags,
+ tag_action,
+ data_ptr,
+ dxfer_len,
+ timeout);
+
+ if (force48bit || lba > ATA_MAX_28BIT_LBA)
+ ata_48bit_cmd(&ccb->ataio, command, features, lba, sector_count);
+ else
+ ata_28bit_cmd(&ccb->ataio, command, features, lba, sector_count);
+
+ if (ata_flags & AP_FLAG_CHK_COND)
+ ccb->ataio.cmd.flags |= CAM_ATAIO_NEEDRESULT;
+
+ return ata_cam_send(device, ccb, 0);
+}
+
static void
dump_data(uint16_t *ptr, uint32_t len)
{
@@ -1571,6 +1711,278 @@ dump_data(uint16_t *ptr, uint32_t len)
}
static int
+atahpa_proc_resp(struct cam_device *device, union ccb *ccb,
+ int is48bit, u_int64_t *hpasize)
+{
+ struct ata_res *res;
+
+ res = &ccb->ataio.res;
+ if (res->status & ATA_STATUS_ERROR) {
+ if (arglist & CAM_ARG_VERBOSE) {
+ cam_error_print(device, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ printf("error = 0x%02x, sector_count = 0x%04x, "
+ "device = 0x%02x, status = 0x%02x\n",
+ res->error, res->sector_count,
+ res->device, res->status);
+ }
+
+ if (res->error & ATA_ERROR_ID_NOT_FOUND) {
+ warnx("Max address has already been set since "
+ "last power-on or hardware reset");
+ }
+
+ return (1);
+ }
+
+ if (arglist & CAM_ARG_VERBOSE) {
+ fprintf(stdout, "%s%d: Raw native max data:\n",
+ device->device_name, device->dev_unit_num);
+ /* res is 4 byte aligned */
+ dump_data((uint16_t*)(uintptr_t)res, sizeof(struct ata_res));
+
+ printf("error = 0x%02x, sector_count = 0x%04x, device = 0x%02x, "
+ "status = 0x%02x\n", res->error, res->sector_count,
+ res->device, res->status);
+ }
+
+ if (hpasize != NULL) {
+ if (is48bit) {
+ *hpasize = (((u_int64_t)((res->lba_high_exp << 16) |
+ (res->lba_mid_exp << 8) | res->lba_low_exp) << 24) |
+ ((res->lba_high << 16) | (res->lba_mid << 8) |
+ res->lba_low)) + 1;
+ } else {
+ *hpasize = (((res->device & 0x0f) << 24) |
+ (res->lba_high << 16) | (res->lba_mid << 8) |
+ res->lba_low) + 1;
+ }
+ }
+
+ return (0);
+}
+
+static int
+ata_read_native_max(struct cam_device *device, int retry_count,
+ u_int32_t timeout, union ccb *ccb,
+ struct ata_params *parm, u_int64_t *hpasize)
+{
+ int error;
+ u_int cmd, is48bit;
+ u_int8_t protocol;
+
+ is48bit = parm->support.command2 & ATA_SUPPORT_ADDRESS48;
+ protocol = AP_PROTO_NON_DATA;
+
+ if (is48bit) {
+ cmd = ATA_READ_NATIVE_MAX_ADDRESS48;
+ protocol |= AP_EXTEND;
+ } else {
+ cmd = ATA_READ_NATIVE_MAX_ADDRESS;
+ }
+
+ error = ata_do_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/protocol,
+ /*ata_flags*/AP_FLAG_CHK_COND,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/0,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ timeout ? timeout : 1000,
+ is48bit);
+
+ if (error)
+ return (error);
+
+ return atahpa_proc_resp(device, ccb, is48bit, hpasize);
+}
+
+static int
+atahpa_set_max(struct cam_device *device, int retry_count,
+ u_int32_t timeout, union ccb *ccb,
+ int is48bit, u_int64_t maxsize, int persist)
+{
+ int error;
+ u_int cmd;
+ u_int8_t protocol;
+
+ protocol = AP_PROTO_NON_DATA;
+
+ if (is48bit) {
+ cmd = ATA_SET_MAX_ADDRESS48;
+ protocol |= AP_EXTEND;
+ } else {
+ cmd = ATA_SET_MAX_ADDRESS;
+ }
+
+ /* lba's are zero indexed so the max lba is requested max - 1 */
+ if (maxsize)
+ maxsize--;
+
+ error = ata_do_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/protocol,
+ /*ata_flags*/AP_FLAG_CHK_COND,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/ATA_HPA_FEAT_MAX_ADDR,
+ /*lba*/maxsize,
+ /*sector_count*/persist,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ timeout ? timeout : 1000,
+ is48bit);
+
+ if (error)
+ return (error);
+
+ return atahpa_proc_resp(device, ccb, is48bit, NULL);
+}
+
+static int
+atahpa_password(struct cam_device *device, int retry_count,
+ u_int32_t timeout, union ccb *ccb,
+ int is48bit, struct ata_set_max_pwd *pwd)
+{
+ int error;
+ u_int cmd;
+ u_int8_t protocol;
+
+ protocol = AP_PROTO_PIO_OUT;
+ cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
+
+ error = ata_do_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_OUT,
+ /*protocol*/protocol,
+ /*ata_flags*/AP_FLAG_CHK_COND,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/ATA_HPA_FEAT_SET_PWD,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/(u_int8_t*)pwd,
+ /*dxfer_len*/sizeof(struct ata_set_max_pwd),
+ timeout ? timeout : 1000,
+ is48bit);
+
+ if (error)
+ return (error);
+
+ return atahpa_proc_resp(device, ccb, is48bit, NULL);
+}
+
+static int
+atahpa_lock(struct cam_device *device, int retry_count,
+ u_int32_t timeout, union ccb *ccb, int is48bit)
+{
+ int error;
+ u_int cmd;
+ u_int8_t protocol;
+
+ protocol = AP_PROTO_NON_DATA;
+ cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
+
+ error = ata_do_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/protocol,
+ /*ata_flags*/AP_FLAG_CHK_COND,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/ATA_HPA_FEAT_LOCK,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ timeout ? timeout : 1000,
+ is48bit);
+
+ if (error)
+ return (error);
+
+ return atahpa_proc_resp(device, ccb, is48bit, NULL);
+}
+
+static int
+atahpa_unlock(struct cam_device *device, int retry_count,
+ u_int32_t timeout, union ccb *ccb,
+ int is48bit, struct ata_set_max_pwd *pwd)
+{
+ int error;
+ u_int cmd;
+ u_int8_t protocol;
+
+ protocol = AP_PROTO_PIO_OUT;
+ cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
+
+ error = ata_do_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_OUT,
+ /*protocol*/protocol,
+ /*ata_flags*/AP_FLAG_CHK_COND,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/ATA_HPA_FEAT_UNLOCK,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/(u_int8_t*)pwd,
+ /*dxfer_len*/sizeof(struct ata_set_max_pwd),
+ timeout ? timeout : 1000,
+ is48bit);
+
+ if (error)
+ return (error);
+
+ return atahpa_proc_resp(device, ccb, is48bit, NULL);
+}
+
+static int
+atahpa_freeze_lock(struct cam_device *device, int retry_count,
+ u_int32_t timeout, union ccb *ccb, int is48bit)
+{
+ int error;
+ u_int cmd;
+ u_int8_t protocol;
+
+ protocol = AP_PROTO_NON_DATA;
+ cmd = (is48bit) ? ATA_SET_MAX_ADDRESS48 : ATA_SET_MAX_ADDRESS;
+
+ error = ata_do_cmd(device,
+ ccb,
+ retry_count,
+ /*flags*/CAM_DIR_NONE,
+ /*protocol*/protocol,
+ /*ata_flags*/AP_FLAG_CHK_COND,
+ /*tag_action*/MSG_SIMPLE_Q_TAG,
+ /*command*/cmd,
+ /*features*/ATA_HPA_FEAT_FREEZE,
+ /*lba*/0,
+ /*sector_count*/0,
+ /*data_ptr*/NULL,
+ /*dxfer_len*/0,
+ timeout ? timeout : 1000,
+ is48bit);
+
+ if (error)
+ return (error);
+
+ return atahpa_proc_resp(device, ccb, is48bit, NULL);
+}
+
+
+static int
ata_do_identify(struct cam_device *device, int retry_count, int timeout,
union ccb *ccb, struct ata_params** ident_bufp)
{
@@ -1701,6 +2113,7 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
{
union ccb *ccb;
struct ata_params *ident_buf;
+ u_int64_t hpasize;
if ((ccb = cam_getccb(device)) == NULL) {
warnx("couldn't allocate CCB");
@@ -1712,10 +2125,21 @@ ataidentify(struct cam_device *device, int retry_count, int timeout)
return (1);
}
+ if (ident_buf->support.command1 & ATA_SUPPORT_PROTECTED) {
+ if (ata_read_native_max(device, retry_count, timeout, ccb,
+ ident_buf, &hpasize) != 0) {
+ cam_freeccb(ccb);
+ return (1);
+ }
+ } else {
+ hpasize = 0;
+ }
+
printf("%s%d: ", device->device_name, device->dev_unit_num);
ata_print_ident(ident_buf);
camxferrate(device);
atacapprint(ident_buf);
+ atahpa_print(ident_buf, hpasize, 0);
free(ident_buf);
cam_freeccb(ccb);
@@ -2044,6 +2468,245 @@ ata_getpwd(u_int8_t *passwd, int max, char opt)
return (0);
}
+enum {
+ ATA_HPA_ACTION_PRINT,
+ ATA_HPA_ACTION_SET_MAX,
+ ATA_HPA_ACTION_SET_PWD,
+ ATA_HPA_ACTION_LOCK,
+ ATA_HPA_ACTION_UNLOCK,
+ ATA_HPA_ACTION_FREEZE_LOCK
+};
+
+static int
+atahpa_set_confirm(struct cam_device *device, struct ata_params* ident_buf,
+ u_int64_t maxsize, int persist)
+{
+ printf("\nYou are about to configure HPA to limit the user accessible\n"
+ "sectors to %ju %s on the device:\n%s%d,%s%d: ", maxsize,
+ persist ? "persistently" : "temporarily",
+ device->device_name, device->dev_unit_num,
+ device->given_dev_name, device->given_unit_number);
+ ata_print_ident(ident_buf);
+
+ for(;;) {
+ char str[50];
+ printf("\nAre you SURE you want to configure HPA? (yes/no) ");
+
+ if (NULL != fgets(str, sizeof(str), stdin)) {
+ if (0 == strncasecmp(str, "yes", 3)) {
+ return (1);
+ } else if (0 == strncasecmp(str, "no", 2)) {
+ return (0);
+ } else {
+ printf("Please answer \"yes\" or "
+ "\"no\"\n");
+ }
+ }
+ }
+
+ /* NOTREACHED */
+ return (0);
+}
+
+static int
+atahpa(struct cam_device *device, int retry_count, int timeout,
+ int argc, char **argv, char *combinedopt)
+{
+ union ccb *ccb;
+ struct ata_params *ident_buf;
+ struct ccb_getdev cgd;
+ struct ata_set_max_pwd pwd;
+ int error, confirm, quiet, c, action, actions, setpwd, persist;
+ int security, is48bit, pwdsize;
+ u_int64_t hpasize, maxsize;
+
+ actions = 0;
+ setpwd = 0;
+ confirm = 0;
+ quiet = 0;
+ maxsize = 0;
+ persist = 0;
+ security = 0;
+
+ memset(&pwd, 0, sizeof(pwd));
+
+ /* default action is to print hpa information */
+ action = ATA_HPA_ACTION_PRINT;
+ pwdsize = sizeof(pwd.password);
+
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch(c){
+ case 's':
+ action = ATA_HPA_ACTION_SET_MAX;
+ maxsize = strtoumax(optarg, NULL, 0);
+ actions++;
+ break;
+
+ case 'p':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ action = ATA_HPA_ACTION_SET_PWD;
+ security = 1;
+ actions++;
+ break;
+
+ case 'l':
+ action = ATA_HPA_ACTION_LOCK;
+ security = 1;
+ actions++;
+ break;
+
+ case 'U':
+ if (ata_getpwd(pwd.password, pwdsize, c) != 0)
+ return (1);
+ action = ATA_HPA_ACTION_UNLOCK;
+ security = 1;
+ actions++;
+ break;
+
+ case 'f':
+ action = ATA_HPA_ACTION_FREEZE_LOCK;
+ security = 1;
+ actions++;
+ break;
+
+ case 'P':
+ persist = 1;
+ break;
+
+ case 'y':
+ confirm++;
+ break;
+
+ case 'q':
+ quiet++;
+ break;
+ }
+ }
+
+ if (actions > 1) {
+ warnx("too many hpa actions specified");
+ return (1);
+ }
+
+ if (get_cgd(device, &cgd) != 0) {
+ warnx("couldn't get CGD");
+ return (1);
+ }
+
+ ccb = cam_getccb(device);
+ if (ccb == NULL) {
+ warnx("couldn't allocate CCB");
+ return (1);
+ }
+
+ error = ata_do_identify(device, retry_count, timeout, ccb, &ident_buf);
+ if (error != 0) {
+ cam_freeccb(ccb);
+ return (1);
+ }
+
+ if (quiet == 0) {
+ printf("%s%d: ", device->device_name, device->dev_unit_num);
+ ata_print_ident(ident_buf);
+ camxferrate(device);
+ }
+
+ if (action == ATA_HPA_ACTION_PRINT) {
+ error = ata_read_native_max(device, retry_count, timeout, ccb,
+ ident_buf, &hpasize);
+ if (error == 0)
+ atahpa_print(ident_buf, hpasize, 1);
+
+ cam_freeccb(ccb);
+ free(ident_buf);
+ return (error);
+ }
+
+ if (!(ident_buf->support.command1 & ATA_SUPPORT_PROTECTED)) {
+ warnx("HPA is not supported by this device");
+ cam_freeccb(ccb);
+ free(ident_buf);
+ return (1);
+ }
+
+ if (security && !(ident_buf->support.command1 & ATA_SUPPORT_MAXSECURITY)) {
+ warnx("HPA Security is not supported by this device");
+ cam_freeccb(ccb);
+ free(ident_buf);
+ return (1);
+ }
+
+ is48bit = ident_buf->support.command2 & ATA_SUPPORT_ADDRESS48;
+
+ /*
+ * The ATA spec requires:
+ * 1. Read native max addr is called directly before set max addr
+ * 2. Read native max addr is NOT called before any other set max call
+ */
+ switch(action) {
+ case ATA_HPA_ACTION_SET_MAX:
+ if (confirm == 0 &&
+ atahpa_set_confirm(device, ident_buf, maxsize,
+ persist) == 0) {
+ cam_freeccb(ccb);
+ free(ident_buf);
+ return (1);
+ }
+
+ error = ata_read_native_max(device, retry_count, timeout,
+ ccb, ident_buf, &hpasize);
+ if (error == 0) {
+ error = atahpa_set_max(device, retry_count, timeout,
+ ccb, is48bit, maxsize, persist);
+ if (error == 0) {
+ /* redo identify to get new lba values */
+ error = ata_do_identify(device, retry_count,
+ timeout, ccb,
+ &ident_buf);
+ atahpa_print(ident_buf, hpasize, 1);
+ }
+ }
+ break;
+
+ case ATA_HPA_ACTION_SET_PWD:
+ error = atahpa_password(device, retry_count, timeout,
+ ccb, is48bit, &pwd);
+ if (error == 0)
+ printf("HPA password has been set\n");
+ break;
+
+ case ATA_HPA_ACTION_LOCK:
+ error = atahpa_lock(device, retry_count, timeout,
+ ccb, is48bit);
+ if (error == 0)
+ printf("HPA has been locked\n");
+ break;
+
+ case ATA_HPA_ACTION_UNLOCK:
+ error = atahpa_unlock(device, retry_count, timeout,
+ ccb, is48bit, &pwd);
+ if (error == 0)
+ printf("HPA has been unlocked\n");
+ break;
+
+ case ATA_HPA_ACTION_FREEZE_LOCK:
+ error = atahpa_freeze_lock(device, retry_count, timeout,
+ ccb, is48bit);
+ if (error == 0)
+ printf("HPA has been frozen\n");
+ break;
+
+ default:
+ errx(1, "Option currently not supported");
+ }
+
+ cam_freeccb(ccb);
+ free(ident_buf);
+
+ return (error);
+}
+
static int
atasecurity(struct cam_device *device, int retry_count, int timeout,
int argc, char **argv, char *combinedopt)
@@ -3825,13 +4488,13 @@ cts_print(struct cam_device *device, struct ccb_trans_settings *cts)
&cts->xport_specific.fc;
if (fc->valid & CTS_FC_VALID_WWNN)
- fprintf(stdout, "%sWWNN: 0x%llx", pathstr,
+ fprintf(stdout, "%sWWNN: 0x%llx\n", pathstr,
(long long) fc->wwnn);
if (fc->valid & CTS_FC_VALID_WWPN)
- fprintf(stdout, "%sWWPN: 0x%llx", pathstr,
+ fprintf(stdout, "%sWWPN: 0x%llx\n", pathstr,
(long long) fc->wwpn);
if (fc->valid & CTS_FC_VALID_PORT)
- fprintf(stdout, "%sPortID: 0x%x", pathstr, fc->port);
+ fprintf(stdout, "%sPortID: 0x%x\n", 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);
@@ -6284,18 +6947,18 @@ findsasdevice(struct cam_devlist *devlist, uint64_t sasaddr)
struct cam_devitem *item;
STAILQ_FOREACH(item, &devlist->dev_queue, links) {
- uint8_t *item_addr;
+ struct scsi_vpd_id_descriptor *idd;
/*
* XXX KDM look for LUN IDs as well?
*/
- item_addr = scsi_get_devid(item->device_id,
+ idd = scsi_get_devid(item->device_id,
item->device_id_len,
scsi_devid_is_sas_target);
- if (item_addr == NULL)
+ if (idd == NULL)
continue;
- if (scsi_8btou64(item_addr) == sasaddr)
+ if (scsi_8btou64(idd->identifier) == sasaddr)
return (item);
}
@@ -6475,8 +7138,12 @@ smpphylist(struct cam_device *device, int argc, char **argv,
continue;
}
- item = findsasdevice(&devlist,
- scsi_8btou64(disresponse->attached_sas_address));
+ if (disresponse->attached_device == SMP_DIS_AD_TYPE_NONE) {
+ item = NULL;
+ } else {
+ item = findsasdevice(&devlist,
+ scsi_8btou64(disresponse->attached_sas_address));
+ }
if ((quiet == 0)
|| (item != NULL)) {
@@ -6702,6 +7369,8 @@ usage(int printlong)
" <-d pwd | -e pwd | -f | -h pwd | -k pwd>\n"
" [-l <high|maximum>] [-q] [-s pwd] [-T timeout]\n"
" [-U <user|master>] [-y]\n"
+" camcontrol hpa [dev_id][generic args] [-f] [-l] [-P] [-p pwd]\n"
+" [-q] [-s max_sectors] [-U pwd] [-y]\n"
#endif /* MINIMALISTIC */
" camcontrol help\n");
if (!printlong)
@@ -6852,6 +7521,17 @@ usage(int printlong)
"-T timeout overrides the timeout (seconds) used for erase operation\n"
"-U <user|master> specifies which user to set: user or master\n"
"-y don't ask any questions\n"
+"hpa arguments:\n"
+"-f freeze the HPA configuration of the device\n"
+"-l lock the HPA configuration of the device\n"
+"-P make the HPA max sectors persist\n"
+"-p pwd Set the HPA configuration password required for unlock\n"
+" calls\n"
+"-q be quiet, do not print any status messages\n"
+"-s sectors configures the maximum user accessible sectors of the\n"
+" device\n"
+"-U pwd unlock the HPA configuration of the device\n"
+"-y don't ask any questions\n"
);
#endif /* MINIMALISTIC */
}
@@ -7076,6 +7756,10 @@ main(int argc, char **argv)
case CAM_CMD_DEVLIST:
error = getdevlist(cam_dev);
break;
+ case CAM_CMD_HPA:
+ error = atahpa(cam_dev, retry_count, timeout,
+ argc, argv, combinedopt);
+ break;
#endif /* MINIMALISTIC */
case CAM_CMD_DEVTREE:
error = getdevtree();
diff --git a/sbin/camcontrol/fwdownload.c b/sbin/camcontrol/fwdownload.c
index daa1520..2fa9ba4 100644
--- a/sbin/camcontrol/fwdownload.c
+++ b/sbin/camcontrol/fwdownload.c
@@ -370,17 +370,15 @@ fw_download_img(struct cam_device *cam_dev, const struct fw_vendor *vp,
}
if (!sim_mode) {
/* Execute the command. */
- if (cam_send_ccb(cam_dev, ccb) < 0) {
+ if (cam_send_ccb(cam_dev, ccb) < 0 ||
+ (ccb->ccb_h.status & CAM_STATUS_MASK) !=
+ CAM_REQ_CMP) {
warnx("Error writing image to device");
if (printerrors)
cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
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++;
diff --git a/sbin/devd/devd.8 b/sbin/devd/devd.8
index 8e33236..1869de6 100644
--- a/sbin/devd/devd.8
+++ b/sbin/devd/devd.8
@@ -33,7 +33,7 @@
.Nd "device state change daemon"
.Sh SYNOPSIS
.Nm
-.Op Fl Ddn
+.Op Fl dn
.Op Fl f Ar file
.Op Fl l Ar num
.Sh DESCRIPTION
@@ -44,10 +44,8 @@ kernel events happen.
.Pp
The following options are accepted.
.Bl -tag -width ".Fl f Ar file"
-.It Fl D
-Enable debugging messages.
.It Fl d
-Run in the foreground instead of becoming a daemon.
+Run in the foreground instead of becoming a daemon and log additional information for debugging.
.It Fl f Ar file
Use configuration file
.Ar file
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index 9448775..447ab87 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -73,19 +73,22 @@ __FBSDID("$FreeBSD$");
#include <sys/wait.h>
#include <sys/un.h>
-#include <ctype.h>
+#include <cctype>
+#include <cerrno>
+#include <cstdlib>
+#include <cstdio>
+#include <csignal>
+#include <cstring>
+#include <cstdarg>
+
#include <dirent.h>
-#include <errno.h>
#include <err.h>
#include <fcntl.h>
#include <libutil.h>
#include <paths.h>
#include <poll.h>
#include <regex.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include <syslog.h>
#include <unistd.h>
#include <algorithm>
@@ -113,13 +116,16 @@ static const char detach = '-';
static struct pidfh *pfh;
-int Dflag;
int dflag;
int nflag;
+static unsigned total_events = 0;
+static volatile sig_atomic_t got_siginfo = 0;
static volatile sig_atomic_t romeo_must_die = 0;
static const char *configfile = CF;
+static void devdlog(int priority, const char* message, ...)
+ __printflike(2, 3);
static void event_loop(void);
static void usage(void);
@@ -166,7 +172,7 @@ bool
event_proc::run(config &c) const
{
vector<eps *>::const_iterator i;
-
+
for (i = _epsvec.begin(); i != _epsvec.end(); ++i)
if (!(*i)->do_action(c))
return (false);
@@ -174,7 +180,7 @@ event_proc::run(config &c) const
}
action::action(const char *cmd)
- : _cmd(cmd)
+ : _cmd(cmd)
{
// nothing
}
@@ -193,7 +199,7 @@ my_system(const char *command)
sigset_t newsigblock, oldsigblock;
if (!command) /* just checking... */
- return(1);
+ return (1);
/*
* Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
@@ -242,8 +248,7 @@ bool
action::do_action(config &c)
{
string s = c.expand_string(_cmd.c_str());
- if (Dflag)
- fprintf(stderr, "Executing '%s'\n", s.c_str());
+ devdlog(LOG_NOTICE, "Executing '%s'\n", s.c_str());
my_system(s.c_str());
return (true);
}
@@ -267,15 +272,22 @@ match::do_match(config &c)
const string &value = c.get_variable(_var);
bool retval;
- if (Dflag)
- fprintf(stderr, "Testing %s=%s against %s, invert=%d\n",
+ /*
+ * This function gets called WAY too often to justify calling syslog()
+ * each time, even at LOG_DEBUG. Because if syslogd isn't running, it
+ * can consume excessive amounts of systime inside of connect(). Only
+ * log when we're in -d mode.
+ */
+ if (dflag) {
+ devdlog(LOG_DEBUG, "Testing %s=%s against %s, invert=%d\n",
_var.c_str(), value.c_str(), _re.c_str(), _inv);
+ }
retval = (regexec(&_regex, value.c_str(), 0, NULL, 0) == 0);
if (_inv == 1)
retval = (retval == 0) ? 1 : 0;
- return retval;
+ return (retval);
}
#include <sys/sockio.h>
@@ -321,8 +333,7 @@ media::do_match(config &c)
value = c.get_variable("device-name");
if (value.empty())
value = c.get_variable("subsystem");
- if (Dflag)
- fprintf(stderr, "Testing media type of %s against 0x%x\n",
+ devdlog(LOG_DEBUG, "Testing media type of %s against 0x%x\n",
value.c_str(), _type);
retval = false;
@@ -334,20 +345,18 @@ media::do_match(config &c)
if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) >= 0 &&
ifmr.ifm_status & IFM_AVALID) {
- if (Dflag)
- fprintf(stderr, "%s has media type 0x%x\n",
+ devdlog(LOG_DEBUG, "%s has media type 0x%x\n",
value.c_str(), IFM_TYPE(ifmr.ifm_active));
retval = (IFM_TYPE(ifmr.ifm_active) == _type);
} else if (_type == -1) {
- if (Dflag)
- fprintf(stderr, "%s has unknown media type\n",
+ devdlog(LOG_DEBUG, "%s has unknown media type\n",
value.c_str());
retval = true;
}
close(s);
}
- return retval;
+ return (retval);
}
const string var_list::bogus = "_$_$_$_$_B_O_G_U_S_$_$_$_$_";
@@ -373,8 +382,14 @@ var_list::is_set(const string &var) const
void
var_list::set_variable(const string &var, const string &val)
{
- if (Dflag)
- fprintf(stderr, "setting %s=%s\n", var.c_str(), val.c_str());
+ /*
+ * This function gets called WAY too often to justify calling syslog()
+ * each time, even at LOG_DEBUG. Because if syslogd isn't running, it
+ * can consume excessive amounts of systime inside of connect(). Only
+ * log when we're in -d mode.
+ */
+ if (dflag)
+ devdlog(LOG_DEBUG, "setting %s=%s\n", var.c_str(), val.c_str());
_vars[var] = val;
}
@@ -392,8 +407,7 @@ config::reset(void)
void
config::parse_one_file(const char *fn)
{
- if (Dflag)
- fprintf(stderr, "Parsing %s\n", fn);
+ devdlog(LOG_DEBUG, "Parsing %s\n", fn);
yyin = fopen(fn, "r");
if (yyin == NULL)
err(1, "Cannot open config file %s", fn);
@@ -410,8 +424,7 @@ config::parse_files_in_dir(const char *dirname)
struct dirent *dp;
char path[PATH_MAX];
- if (Dflag)
- fprintf(stderr, "Parsing files in %s\n", dirname);
+ devdlog(LOG_DEBUG, "Parsing files in %s\n", dirname);
dirp = opendir(dirname);
if (dirp == NULL)
return;
@@ -459,7 +472,7 @@ void
config::open_pidfile()
{
pid_t otherpid;
-
+
if (_pidfile.empty())
return;
pfh = pidfile_open(_pidfile.c_str(), 0600, &otherpid);
@@ -473,21 +486,21 @@ config::open_pidfile()
void
config::write_pidfile()
{
-
+
pidfile_write(pfh);
}
void
config::close_pidfile()
{
-
+
pidfile_close(pfh);
}
void
config::remove_pidfile()
{
-
+
pidfile_remove(pfh);
}
@@ -535,11 +548,10 @@ void
config::push_var_table()
{
var_list *vl;
-
+
vl = new var_list();
_var_list_table.push_back(vl);
- if (Dflag)
- fprintf(stderr, "Pushing table\n");
+ devdlog(LOG_DEBUG, "Pushing table\n");
}
void
@@ -547,8 +559,7 @@ config::pop_var_table()
{
delete _var_list_table.back();
_var_list_table.pop_back();
- if (Dflag)
- fprintf(stderr, "Popping table\n");
+ devdlog(LOG_DEBUG, "Popping table\n");
}
void
@@ -572,7 +583,7 @@ config::get_variable(const string &var)
bool
config::is_id_char(char ch) const
{
- return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
+ return (ch != '\0' && (isalpha(ch) || isdigit(ch) || ch == '_' ||
ch == '-'));
}
@@ -588,7 +599,7 @@ config::expand_one(const char *&src, string &dst)
dst += *src++;
return;
}
-
+
// $(foo) -> $(foo)
// Not sure if I want to support this or not, so for now we just pass
// it through.
@@ -605,7 +616,7 @@ config::expand_one(const char *&src, string &dst)
}
return;
}
-
+
// $[^A-Za-z] -> $\1
if (!isalpha(*src)) {
dst += '$';
@@ -656,7 +667,7 @@ bool
config::chop_var(char *&buffer, char *&lhs, char *&rhs) const
{
char *walker;
-
+
if (*buffer == '\0')
return (false);
walker = lhs = buffer;
@@ -730,8 +741,7 @@ config::find_and_execute(char type)
s = "detach";
break;
}
- if (Dflag)
- fprintf(stderr, "Processing %s event\n", s);
+ devdlog(LOG_DEBUG, "Processing %s event\n", s);
for (i = l->begin(); i != l->end(); ++i) {
if ((*i)->matches(*this)) {
(*i)->run(*this);
@@ -741,7 +751,7 @@ config::find_and_execute(char type)
}
-
+
static void
process_event(char *buffer)
{
@@ -749,8 +759,7 @@ process_event(char *buffer)
char *sp;
sp = buffer + 1;
- if (Dflag)
- fprintf(stderr, "Processing event '%s'\n", buffer);
+ devdlog(LOG_DEBUG, "Processing event '%s'\n", buffer);
type = *buffer++;
cfg.push_var_table();
// No match doesn't have a device, and the format is a little
@@ -793,7 +802,7 @@ process_event(char *buffer)
cfg.set_variable("bus", sp + 3);
break;
}
-
+
cfg.find_and_execute(type);
cfg.pop_var_table();
}
@@ -842,6 +851,8 @@ notify_clients(const char *data, int len)
--num_clients;
close(*i);
i = clients.erase(i);
+ devdlog(LOG_WARNING, "notify_clients: write() failed; "
+ "dropping unresponsive client\n");
} else
++i;
}
@@ -870,6 +881,8 @@ check_clients(void)
--num_clients;
close(*i);
i = clients.erase(i);
+ devdlog(LOG_NOTICE, "check_clients: "
+ "dropping disconnected client\n");
} else
++i;
}
@@ -922,8 +935,7 @@ event_loop(void)
rv = select(fd + 1, &fds, &fds, &fds, &tv);
// No events -> we've processed all pending events
if (rv == 0) {
- if (Dflag)
- fprintf(stderr, "Calling daemon\n");
+ devdlog(LOG_DEBUG, "Calling daemon\n");
cfg.remove_pidfile();
cfg.open_pidfile();
daemon(0, 0);
@@ -957,6 +969,11 @@ event_loop(void)
tv.tv_usec = 0;
}
rv = select(max_fd, &fds, NULL, NULL, &tv);
+ if (got_siginfo) {
+ devdlog(LOG_INFO, "Events received so far=%u\n",
+ total_events);
+ got_siginfo = 0;
+ }
if (rv == -1) {
if (errno == EINTR)
continue;
@@ -966,6 +983,12 @@ event_loop(void)
if (FD_ISSET(fd, &fds)) {
rv = read(fd, buffer, sizeof(buffer) - 1);
if (rv > 0) {
+ total_events++;
+ if (rv == sizeof(buffer) - 1) {
+ devdlog(LOG_WARNING, "Warning: "
+ "available event data exceeded "
+ "buffer space\n");
+ }
notify_clients(buffer, rv);
buffer[rv] = '\0';
while (buffer[--rv] == '\n')
@@ -984,7 +1007,7 @@ event_loop(void)
}
close(fd);
}
-
+
/*
* functions that the parser uses.
*/
@@ -1069,7 +1092,7 @@ set_variable(const char *var, const char *val)
free(const_cast<char *>(val));
}
-
+
static void
gensighand(int)
@@ -1077,10 +1100,37 @@ gensighand(int)
romeo_must_die = 1;
}
+/*
+ * SIGINFO handler. Will print useful statistics to the syslog or stderr
+ * as appropriate
+ */
+static void
+siginfohand(int)
+{
+ got_siginfo = 1;
+}
+
+/*
+ * Local logging function. Prints to syslog if we're daemonized; syslog
+ * otherwise.
+ */
+static void
+devdlog(int priority, const char* fmt, ...)
+{
+ va_list argp;
+
+ va_start(argp, fmt);
+ if (dflag)
+ vfprintf(stderr, fmt, argp);
+ else
+ vsyslog(priority, fmt, argp);
+ va_end(argp);
+}
+
static void
usage()
{
- fprintf(stderr, "usage: %s [-Ddn] [-l connlimit] [-f file]\n",
+ fprintf(stderr, "usage: %s [-dn] [-l connlimit] [-f file]\n",
getprogname());
exit(1);
}
@@ -1110,11 +1160,8 @@ main(int argc, char **argv)
int ch;
check_devd_enabled();
- while ((ch = getopt(argc, argv, "Ddf:l:n")) != -1) {
+ while ((ch = getopt(argc, argv, "df:l:n")) != -1) {
switch (ch) {
- case 'D':
- Dflag++;
- break;
case 'd':
dflag++;
break;
@@ -1142,6 +1189,7 @@ main(int argc, char **argv)
signal(SIGHUP, gensighand);
signal(SIGINT, gensighand);
signal(SIGTERM, gensighand);
+ signal(SIGINFO, siginfohand);
event_loop();
return (0);
}
diff --git a/sbin/devd/devd.h b/sbin/devd/devd.h
index a8d113b..becfe82 100644
--- a/sbin/devd/devd.h
+++ b/sbin/devd/devd.h
@@ -53,6 +53,6 @@ int yyparse(void);
__END_DECLS
#define PATH_DEVCTL "/dev/devctl"
-#define DEVCTL_MAXBUF 1025
+#define DEVCTL_MAXBUF 8192
#endif /* DEVD_H */
diff --git a/sbin/devd/token.l b/sbin/devd/token.l
index 7a63bec..b3441c3 100644
--- a/sbin/devd/token.l
+++ b/sbin/devd/token.l
@@ -37,8 +37,6 @@
#include "y.tab.h"
int lineno = 1;
-#define YY_NO_UNPUT
-#define YY_NO_INPUT
static void
update_lineno(const char *cp)
@@ -50,6 +48,9 @@ update_lineno(const char *cp)
%}
+%option nounput
+%option noinput
+
%%
[ \t]+ ;
diff --git a/sbin/devfs/devfs.8 b/sbin/devfs/devfs.8
index 8c41b13..8bbdfcc 100644
--- a/sbin/devfs/devfs.8
+++ b/sbin/devfs/devfs.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 21, 2010
+.Dd July 12, 2013
.Dt DEVFS 8
.Os
.Sh NAME
@@ -190,6 +190,7 @@ Nodes may later be revived manually with
or with the
.Cm unhide
action.
+Hiding a directory node effectively hides all of its child nodes.
.It Cm include Ar ruleset
Apply all the rules in ruleset number
.Ar ruleset
@@ -213,6 +214,8 @@ which may be a user name
or number.
.It Cm unhide
Unhide the node.
+If the node resides in a subdirectory,
+all parent directory nodes must be visible to be able to access the node.
.El
.Sh IMPLEMENTATION NOTES
Rulesets are created by the kernel at the first reference
@@ -269,13 +272,11 @@ the operations are performed on
.Pa /dev
(this only matters for things that might change the properties of nodes).
.Pp
-.Dl "devfs ruleset 10"
-.Pp
Specify that ruleset 10 should be the current ruleset for
.Pa /dev
-(if it does not already exist, it is created).
+(if it does not already exist, it is created):
.Pp
-.Dl "devfs rule add path speaker mode 666"
+.Dl "devfs ruleset 10"
.Pp
Add a rule that causes all nodes that have a path that matches
.Dq Li speaker
@@ -291,22 +292,19 @@ be changed if the node is created
the rule is added
(e.g., the
.Pa atspeaker
-module is loaded after the above rule is added).
+module is loaded after the above rule is added):
.Pp
-.Dl "devfs rule applyset"
+.Dl "devfs rule add path speaker mode 666"
.Pp
Apply all the rules in the current ruleset to all the existing nodes.
-E.g., if the above rule was added after
+E.g., if the below rule was added after
.Pa /dev/speaker
was created,
this command will cause its file mode to be changed to 666
-as prescribed by the rule.
+as prescribed by the rule:
.Pp
-.Dl devfs rule add path "snp*" mode 660 group snoopers
+.Dl "devfs rule applyset"
.Pp
-(Quoting the argument to
-.Cm path
-is often necessary to disable the shell's globbing features.)
For all devices with a path that matches
.Dq Li snp* ,
set the file mode to 660 and the GID to
@@ -315,53 +313,57 @@ This permits users in the
.Dq Li snoopers
group to use the
.Xr snp 4
-devices.
+devices
+(quoting the argument to
+.Cm path
+is often necessary to disable the shell's globbing features):
.Pp
-.Dl "devfs rule -s 20 add type disk group wheel"
+.Dl devfs rule add path "snp*" mode 660 group snoopers
.Pp
Add a rule to ruleset number 20.
Since this ruleset is not the current ruleset for any mount-points,
this rule is never applied automatically (unless ruleset 20 becomes
-a current ruleset for some mount-point at a later time).
-However, it can be applied explicitly, as such:
+a current ruleset for some mount-point at a later time):
.Pp
-.Dl "devfs -m /my/jail/dev rule -s 20 applyset"
+.Dl "devfs rule -s 20 add type disk group wheel"
.Pp
-This will apply all rules in ruleset number 20 to the DEVFS mount on
+Explicitly apply all rules in ruleset number 20 to the DEVFS mount on
.Pa /my/jail/dev .
It does not matter that ruleset 20 is not the current ruleset for that
-mount-point; the rules are still applied.
+mount-point; the rules are still applied:
.Pp
-.Dl "devfs rule apply hide"
+.Dl "devfs -m /my/jail/dev rule -s 20 applyset"
.Pp
-Since this rule has no conditions, the action
+Since the following rule has no conditions, the action
.Pq Cm hide
-will be applied to all nodes.
-Since hiding all nodes is not very useful, we can undo it:
+will be applied to all nodes:
.Pp
-.Dl "devfs rule apply unhide"
+.Dl "devfs rule apply hide"
.Pp
-which applies
+Since hiding all nodes is not very useful, we can undo it.
+The following applies
.Cm unhide
to all the nodes,
-causing them to reappear.
+causing them to reappear:
.Pp
-.Dl "devfs rule -s 10 add - < my_rules"
+.Dl "devfs rule apply unhide"
.Pp
Add all the rules from the file
.Pa my_rules
-to ruleset 10.
+to ruleset 10:
.Pp
-.Dl "devfs rule -s 20 show | devfs rule -s 10 add -"
+.Dl "devfs rule -s 10 add - < my_rules"
.Pp
-Since
-.Cm show
-outputs valid rules,
-this feature can be used to copy rulesets.
-The above copies all the rules from ruleset 20 into ruleset 10.
+The below copies all the rules from ruleset 20 into ruleset 10.
The rule numbers are preserved,
but ruleset 10 may already have rules with non-conflicting numbers
(these will be preserved).
+Since
+.Cm show
+outputs valid rules,
+this feature can be used to copy rulesets:
+.Pp
+.Dl "devfs rule -s 20 show | devfs rule -s 10 add -"
.Sh SEE ALSO
.Xr chmod 1 ,
.Xr jail 2 ,
diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c
index 9f8e45f..c0a1720 100644
--- a/sbin/dhclient/bpf.c
+++ b/sbin/dhclient/bpf.c
@@ -43,7 +43,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/capability.h>
+
#include "dhcpd.h"
+#include "privsep.h"
+#include <sys/capability.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
@@ -61,15 +65,15 @@ __FBSDID("$FreeBSD$");
* mask.
*/
int
-if_register_bpf(struct interface_info *info)
+if_register_bpf(struct interface_info *info, int flags)
{
char filename[50];
int sock, b;
/* Open a BPF device */
- for (b = 0; 1; b++) {
+ for (b = 0;; b++) {
snprintf(filename, sizeof(filename), BPF_FORMAT, b);
- sock = open(filename, O_RDWR, 0);
+ sock = open(filename, flags);
if (sock < 0) {
if (errno == EBUSY)
continue;
@@ -87,16 +91,81 @@ if_register_bpf(struct interface_info *info)
return (sock);
}
+/*
+ * Packet write filter program:
+ * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
+ */
+struct bpf_insn dhcp_bpf_wfilter[] = {
+ BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
+
+ /* Make sure this is an IP packet... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
+
+ /* Make sure it's a UDP packet... */
+ BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
+
+ /* Make sure this isn't a fragment... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
+ BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
+
+ /* Get the IP header length... */
+ BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
+
+ /* Make sure it's from the right port... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
+
+ /* Make sure it is to the right ports ... */
+ BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
+ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
+
+ /* If we passed all the tests, ask for the whole packet. */
+ BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
+
+ /* Otherwise, drop it. */
+ BPF_STMT(BPF_RET+BPF_K, 0),
+};
+
+int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
+
void
if_register_send(struct interface_info *info)
{
+ cap_rights_t rights;
+ struct bpf_version v;
+ struct bpf_program p;
int sock, on = 1;
- /*
- * If we're using the bpf API for sending and receiving, we
- * don't need to register this interface twice.
- */
- info->wfdesc = info->rfdesc;
+ /* Open a BPF device and hang it on this interface... */
+ info->wfdesc = if_register_bpf(info, O_WRONLY);
+
+ /* Make sure the BPF version is in range... */
+ if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0)
+ error("Can't get BPF version: %m");
+
+ if (v.bv_major != BPF_MAJOR_VERSION ||
+ v.bv_minor < BPF_MINOR_VERSION)
+ error("Kernel BPF version out of range - recompile dhcpd!");
+
+ /* Set up the bpf write filter program structure. */
+ p.bf_len = dhcp_bpf_wfilter_len;
+ p.bf_insns = dhcp_bpf_wfilter;
+
+ if (dhcp_bpf_wfilter[7].k == 0x1fff)
+ dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
+
+ if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0)
+ error("Can't install write filter program: %m");
+
+ if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0)
+ error("Cannot lock bpf");
+
+ cap_rights_init(&rights, CAP_WRITE);
+ if (cap_rights_limit(info->wfdesc, &rights) < 0 && errno != ENOSYS)
+ error("Can't limit bpf descriptor: %m");
/*
* Use raw socket for unicast send.
@@ -144,55 +213,17 @@ struct bpf_insn dhcp_bpf_filter[] = {
int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
-/*
- * Packet write filter program:
- * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
- */
-struct bpf_insn dhcp_bpf_wfilter[] = {
- BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
-
- /* Make sure this is an IP packet... */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
-
- /* Make sure it's a UDP packet... */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
-
- /* Make sure this isn't a fragment... */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
-
- /* Get the IP header length... */
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
-
- /* Make sure it's from the right port... */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
-
- /* Make sure it is to the right ports ... */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
-
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
-
- /* Otherwise, drop it. */
- BPF_STMT(BPF_RET+BPF_K, 0),
-};
-
-int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
-
void
if_register_receive(struct interface_info *info)
{
+ static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA };
+ cap_rights_t rights;
struct bpf_version v;
struct bpf_program p;
int flag = 1, sz;
/* Open a BPF device and hang it on this interface... */
- info->rfdesc = if_register_bpf(info);
+ info->rfdesc = if_register_bpf(info, O_RDONLY);
/* Make sure the BPF version is in range... */
if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0)
@@ -235,48 +266,94 @@ if_register_receive(struct interface_info *info)
if (ioctl(info->rfdesc, BIOCSETF, &p) < 0)
error("Can't install packet filter program: %m");
- /* Set up the bpf write filter program structure. */
- p.bf_len = dhcp_bpf_wfilter_len;
- p.bf_insns = dhcp_bpf_wfilter;
-
- if (dhcp_bpf_wfilter[7].k == 0x1fff)
- dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
-
- if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0)
- error("Can't install write filter program: %m");
-
if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0)
error("Cannot lock bpf");
+
+ cap_rights_init(&rights, CAP_IOCTL, CAP_POLL_EVENT, CAP_READ);
+ if (cap_rights_limit(info->rfdesc, &rights) < 0 && errno != ENOSYS)
+ error("Can't limit bpf descriptor: %m");
+ if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS)
+ error("Can't limit ioctls for bpf descriptor: %m");
}
-ssize_t
-send_packet(struct interface_info *interface, struct dhcp_packet *raw,
- size_t len, struct in_addr from, struct sockaddr_in *to,
- struct hardware *hto)
+void
+send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len,
+ struct in_addr from, struct in_addr to)
+{
+ struct imsg_hdr hdr;
+ struct buf *buf;
+ int errs;
+
+ hdr.code = IMSG_SEND_PACKET;
+ hdr.len = sizeof(hdr) +
+ sizeof(size_t) + len +
+ sizeof(from) + sizeof(to);
+
+ if ((buf = buf_open(hdr.len)) == NULL)
+ error("buf_open: %m");
+
+ errs = 0;
+ errs += buf_add(buf, &hdr, sizeof(hdr));
+ errs += buf_add(buf, &len, sizeof(len));
+ errs += buf_add(buf, raw, len);
+ errs += buf_add(buf, &from, sizeof(from));
+ errs += buf_add(buf, &to, sizeof(to));
+ if (errs)
+ error("buf_add: %m");
+
+ if (buf_close(privfd, buf) == -1)
+ error("buf_close: %m");
+}
+
+void
+send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd)
{
unsigned char buf[256];
struct iovec iov[2];
struct msghdr msg;
+ struct dhcp_packet raw;
+ size_t len;
+ struct in_addr from, to;
int result, bufp = 0;
+ if (hdr->len < sizeof(*hdr) + sizeof(size_t))
+ error("corrupted message received");
+ buf_read(fd, &len, sizeof(len));
+ if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len +
+ sizeof(from) + sizeof(to)) {
+ error("corrupted message received");
+ }
+ if (len > sizeof(raw))
+ error("corrupted message received");
+ buf_read(fd, &raw, len);
+ buf_read(fd, &from, sizeof(from));
+ buf_read(fd, &to, sizeof(to));
+
/* Assemble the headers... */
- if (to->sin_addr.s_addr == INADDR_BROADCAST)
- assemble_hw_header(interface, buf, &bufp, hto);
- assemble_udp_ip_header(buf, &bufp, from.s_addr,
- to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len);
+ if (to.s_addr == INADDR_BROADCAST)
+ assemble_hw_header(interface, buf, &bufp);
+ assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr,
+ htons(REMOTE_PORT), (unsigned char *)&raw, len);
- iov[0].iov_base = (char *)buf;
+ iov[0].iov_base = buf;
iov[0].iov_len = bufp;
- iov[1].iov_base = (char *)raw;
+ iov[1].iov_base = &raw;
iov[1].iov_len = len;
/* Fire it off */
- if (to->sin_addr.s_addr == INADDR_BROADCAST)
+ if (to.s_addr == INADDR_BROADCAST)
result = writev(interface->wfdesc, iov, 2);
else {
+ struct sockaddr_in sato;
+
+ sato.sin_addr = to;
+ sato.sin_port = htons(REMOTE_PORT);
+ sato.sin_family = AF_INET;
+ sato.sin_len = sizeof(sato);
+
memset(&msg, 0, sizeof(msg));
- msg.msg_name = (struct sockaddr *)to;
- msg.msg_namelen = sizeof(*to);
+ msg.msg_name = (struct sockaddr *)&sato;
+ msg.msg_namelen = sizeof(sato);
msg.msg_iov = iov;
msg.msg_iovlen = 2;
result = sendmsg(interface->ufdesc, &msg, 0);
@@ -284,7 +361,6 @@ send_packet(struct interface_info *interface, struct dhcp_packet *raw,
if (result < 0)
warning("send_packet: %m");
- return (result);
}
ssize_t
diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c
index 58de8cc..4f234c7 100644
--- a/sbin/dhclient/clparse.c
+++ b/sbin/dhclient/clparse.c
@@ -642,6 +642,10 @@ parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
case FILENAME:
lease->filename = parse_string(cfile);
return;
+ case NEXT_SERVER:
+ if (!parse_ip_addr(cfile, &lease->nextserver))
+ return;
+ break;
case SERVER_NAME:
lease->server_name = parse_string(cfile);
return;
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index f71c8c8..e16e464 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -56,9 +56,13 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/capability.h>
+
#include "dhcpd.h"
#include "privsep.h"
+#include <sys/capability.h>
+
#include <net80211/ieee80211_freebsd.h>
#ifndef _PATH_VAREMPTY
@@ -91,9 +95,10 @@ int log_perror = 1;
int privfd;
int nullfd = -1;
+char hostname[_POSIX_HOST_NAME_MAX + 1];
+
struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } };
-struct in_addr inaddr_any;
-struct sockaddr_in sockaddr_broadcast;
+struct in_addr inaddr_any, inaddr_broadcast;
char *path_dhclient_pidfile;
struct pidfh *pidfile;
@@ -343,6 +348,7 @@ main(int argc, char *argv[])
int immediate_daemon = 0;
struct passwd *pw;
pid_t otherpid;
+ cap_rights_t rights;
/* Initially, log errors to stderr as well as to syslogd. */
openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY);
@@ -410,11 +416,7 @@ main(int argc, char *argv[])
tzset();
time(&cur_time);
- memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast));
- sockaddr_broadcast.sin_family = AF_INET;
- sockaddr_broadcast.sin_port = htons(REMOTE_PORT);
- sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST;
- sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast);
+ inaddr_broadcast.s_addr = INADDR_BROADCAST;
inaddr_any.s_addr = INADDR_ANY;
read_client_conf();
@@ -451,13 +453,36 @@ main(int argc, char *argv[])
error("no such user: nobody");
}
+ /*
+ * Obtain hostname before entering capability mode - it won't be
+ * possible then, as reading kern.hostname is not permitted.
+ */
+ if (gethostname(hostname, sizeof(hostname)) < 0)
+ hostname[0] = '\0';
+
+ priv_script_init("PREINIT", NULL);
+ if (ifi->client->alias)
+ priv_script_write_params("alias_", ifi->client->alias);
+ priv_script_go();
+
+ /* set up the interface */
+ discover_interfaces(ifi);
+
if (pipe(pipe_fd) == -1)
error("pipe");
fork_privchld(pipe_fd[0], pipe_fd[1]);
+ close(ifi->ufdesc);
+ ifi->ufdesc = -1;
+ close(ifi->wfdesc);
+ ifi->wfdesc = -1;
+
close(pipe_fd[0]);
privfd = pipe_fd[1];
+ cap_rights_init(&rights, CAP_READ, CAP_WRITE);
+ if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS)
+ error("can't limit private descriptor: %m");
if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1)
error("can't open and lock %s: %m", path_dhclient_db);
@@ -465,16 +490,13 @@ main(int argc, char *argv[])
rewrite_client_leases();
close(fd);
- priv_script_init("PREINIT", NULL);
- if (ifi->client->alias)
- priv_script_write_params("alias_", ifi->client->alias);
- priv_script_go();
-
if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1)
add_protocol("AF_ROUTE", routefd, routehandler, ifi);
-
- /* set up the interface */
- discover_interfaces(ifi);
+ if (shutdown(routefd, SHUT_WR) < 0)
+ error("can't shutdown route socket: %m");
+ cap_rights_init(&rights, CAP_POLL_EVENT, CAP_READ);
+ if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
+ error("can't limit route socket: %m");
if (chroot(_PATH_VAREMPTY) == -1)
error("chroot");
@@ -490,6 +512,9 @@ main(int argc, char *argv[])
setproctitle("%s", ifi->name);
+ if (cap_enter() < 0 && errno != ENOSYS)
+ error("can't enter capability mode: %m");
+
if (immediate_daemon)
go_daemon();
@@ -1063,6 +1088,9 @@ packet_to_lease(struct packet *packet)
lease->address.len = sizeof(packet->raw->yiaddr);
memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len);
+ lease->nextserver.len = sizeof(packet->raw->siaddr);
+ memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len);
+
/* If the server name was filled out, copy it.
Do not attempt to validate the server name as a host name.
RFC 2131 merely states that sname is NUL-terminated (which do
@@ -1223,13 +1251,12 @@ again:
ip->client->secs = ip->client->packet.secs;
note("DHCPDISCOVER on %s to %s port %d interval %d",
- ip->name, inet_ntoa(sockaddr_broadcast.sin_addr),
- ntohs(sockaddr_broadcast.sin_port),
+ ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT,
(int)ip->client->interval);
/* Send out a packet. */
- (void)send_packet(ip, &ip->client->packet, ip->client->packet_length,
- inaddr_any, &sockaddr_broadcast, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, inaddr_any, inaddr_broadcast);
add_timeout(cur_time + ip->client->interval, send_discover, ip);
}
@@ -1337,8 +1364,7 @@ void
send_request(void *ipp)
{
struct interface_info *ip = ipp;
- struct sockaddr_in destination;
- struct in_addr from;
+ struct in_addr from, to;
int interval;
/* Figure out how long it's been since we started transmitting. */
@@ -1426,18 +1452,13 @@ cancel:
/* If the lease T2 time has elapsed, or if we're not yet bound,
broadcast the DHCPREQUEST rather than unicasting. */
- memset(&destination, 0, sizeof(destination));
if (ip->client->state == S_REQUESTING ||
ip->client->state == S_REBOOTING ||
cur_time > ip->client->active->rebind)
- destination.sin_addr.s_addr = INADDR_BROADCAST;
+ to.s_addr = INADDR_BROADCAST;
else
- memcpy(&destination.sin_addr.s_addr,
- ip->client->destination.iabuf,
- sizeof(destination.sin_addr.s_addr));
- destination.sin_port = htons(REMOTE_PORT);
- destination.sin_family = AF_INET;
- destination.sin_len = sizeof(destination);
+ memcpy(&to.s_addr, ip->client->destination.iabuf,
+ sizeof(to.s_addr));
if (ip->client->state != S_REQUESTING)
memcpy(&from, ip->client->active->address.iabuf,
@@ -1455,12 +1476,12 @@ cancel:
ip->client->packet.secs = htons(65535);
}
- note("DHCPREQUEST on %s to %s port %d", ip->name,
- inet_ntoa(destination.sin_addr), ntohs(destination.sin_port));
+ note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to),
+ REMOTE_PORT);
/* Send out a packet. */
- (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
- from, &destination, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, from, to);
add_timeout(cur_time + ip->client->interval, send_request, ip);
}
@@ -1471,12 +1492,11 @@ send_decline(void *ipp)
struct interface_info *ip = ipp;
note("DHCPDECLINE on %s to %s port %d", ip->name,
- inet_ntoa(sockaddr_broadcast.sin_addr),
- ntohs(sockaddr_broadcast.sin_port));
+ inet_ntoa(inaddr_broadcast), REMOTE_PORT);
/* Send out a packet. */
- (void) send_packet(ip, &ip->client->packet, ip->client->packet_length,
- inaddr_any, &sockaddr_broadcast, NULL);
+ send_packet_unpriv(privfd, &ip->client->packet,
+ ip->client->packet_length, inaddr_any, inaddr_broadcast);
}
void
@@ -1533,11 +1553,10 @@ make_discover(struct interface_info *ip, struct client_lease *lease)
ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
-
+
/* send host name if not set via config file. */
- char hostname[_POSIX_HOST_NAME_MAX+1];
if (!options[DHO_HOST_NAME]) {
- if (gethostname(hostname, sizeof(hostname)) == 0) {
+ if (hostname[0] != '\0') {
size_t len;
char* posDot = strchr(hostname, '.');
if (posDot != NULL)
@@ -1558,7 +1577,7 @@ make_discover(struct interface_info *ip, struct client_lease *lease)
int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
ip->hw_address.hlen : sizeof(client_ident)-1;
client_ident[0] = ip->hw_address.htype;
- memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
+ memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
@@ -1657,11 +1676,10 @@ make_request(struct interface_info *ip, struct client_lease * lease)
ip->client->config->send_options[i].len;
options[i]->timeout = 0xFFFFFFFF;
}
-
+
/* send host name if not set via config file. */
- char hostname[_POSIX_HOST_NAME_MAX+1];
if (!options[DHO_HOST_NAME]) {
- if (gethostname(hostname, sizeof(hostname)) == 0) {
+ if (hostname[0] != '\0') {
size_t len;
char* posDot = strchr(hostname, '.');
if (posDot != NULL)
@@ -1682,7 +1700,7 @@ make_request(struct interface_info *ip, struct client_lease * lease)
int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ?
ip->hw_address.hlen : sizeof(client_ident)-1;
client_ident[0] = ip->hw_address.htype;
- memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
+ memcpy(&client_ident[1], ip->hw_address.haddr, hwlen);
options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER];
options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident;
options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1;
@@ -1823,11 +1841,18 @@ void
rewrite_client_leases(void)
{
struct client_lease *lp;
+ cap_rights_t rights;
if (!leaseFile) {
leaseFile = fopen(path_dhclient_db, "w");
if (!leaseFile)
error("can't create %s: %m", path_dhclient_db);
+ cap_rights_init(&rights, CAP_FSTAT, CAP_FSYNC, CAP_FTRUNCATE,
+ CAP_SEEK, CAP_WRITE);
+ if (cap_rights_limit(fileno(leaseFile), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit lease descriptor: %m");
+ }
} else {
fflush(leaseFile);
rewind(leaseFile);
@@ -1874,6 +1899,11 @@ write_client_lease(struct interface_info *ip, struct client_lease *lease,
fprintf(leaseFile, " bootp;\n");
fprintf(leaseFile, " interface \"%s\";\n", ip->name);
fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address));
+ if (lease->nextserver.len == sizeof(inaddr_any) &&
+ 0 != memcmp(lease->nextserver.iabuf, &inaddr_any,
+ sizeof(inaddr_any)))
+ fprintf(leaseFile, " next-server %s;\n",
+ piaddr(lease->nextserver));
if (lease->filename)
fprintf(leaseFile, " filename \"%s\";\n", lease->filename);
if (lease->server_name)
@@ -2327,6 +2357,7 @@ void
go_daemon(void)
{
static int state = 0;
+ cap_rights_t rights;
if (no_daemon || state)
return;
@@ -2339,8 +2370,15 @@ go_daemon(void)
if (daemon(1, 0) == -1)
error("daemon");
- if (pidfile != NULL)
+ cap_rights_init(&rights);
+
+ if (pidfile != NULL) {
pidfile_write(pidfile);
+ if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 &&
+ errno != ENOSYS) {
+ error("can't limit pidfile descriptor: %m");
+ }
+ }
/* we are chrooted, daemon(3) fails to open /dev/null */
if (nullfd != -1) {
@@ -2350,6 +2388,14 @@ go_daemon(void)
close(nullfd);
nullfd = -1;
}
+
+ if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stdin: %m");
+ cap_rights_init(&rights, CAP_WRITE);
+ if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stdout: %m");
+ if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
+ error("can't limit stderr: %m");
}
int
@@ -2494,19 +2540,19 @@ check_classless_option(unsigned char *data, int len)
i += 4;
continue;
} else if (width < 9) {
- addr = (in_addr_t)(data[i] << 24);
+ addr = (in_addr_t)(data[i] << 24);
i += 1;
} else if (width < 17) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16);
i += 2;
} else if (width < 25) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16) +
(in_addr_t)(data[i + 2] << 8);
i += 3;
} else if (width < 33) {
- addr = (in_addr_t)(data[i] << 24) +
+ addr = (in_addr_t)(data[i] << 24) +
(in_addr_t)(data[i + 1] << 16) +
(in_addr_t)(data[i + 2] << 8) +
data[i + 3];
@@ -2530,7 +2576,7 @@ check_classless_option(unsigned char *data, int len)
addr &= mask;
data[i - 1] = (unsigned char)(
(addr >> (((32 - width)/8)*8)) & 0xFF);
- }
+ }
i += 4;
}
if (i > len) {
@@ -2694,6 +2740,8 @@ fork_privchld(int fd, int fd2)
dup2(nullfd, STDERR_FILENO);
close(nullfd);
close(fd2);
+ close(ifi->rfdesc);
+ ifi->rfdesc = -1;
for (;;) {
pfd[0].fd = fd;
@@ -2705,6 +2753,6 @@ fork_privchld(int fd, int fd2)
if (nfds == 0 || !(pfd[0].revents & POLLIN))
continue;
- dispatch_imsg(fd);
+ dispatch_imsg(ifi, fd);
}
}
diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h
index 4762cbd..479753e 100644
--- a/sbin/dhclient/dhcpd.h
+++ b/sbin/dhclient/dhcpd.h
@@ -121,6 +121,7 @@ struct client_lease {
struct client_lease *next;
time_t expiry, renewal, rebind;
struct iaddr address;
+ struct iaddr nextserver;
char *server_name;
char *filename;
struct string_list *medium;
@@ -296,11 +297,13 @@ struct hash_table *new_hash_table(int);
struct hash_bucket *new_hash_bucket(void);
/* bpf.c */
-int if_register_bpf(struct interface_info *);
+int if_register_bpf(struct interface_info *, int);
void if_register_send(struct interface_info *);
void if_register_receive(struct interface_info *);
-ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t,
- struct in_addr, struct sockaddr_in *, struct hardware *);
+void send_packet_unpriv(int, struct dhcp_packet *, size_t, struct in_addr,
+ struct in_addr);
+struct imsg_hdr;
+void send_packet_priv(struct interface_info *, struct imsg_hdr *, int);
ssize_t receive_packet(struct interface_info *, unsigned char *, size_t,
struct sockaddr_in *, struct hardware *);
@@ -404,20 +407,13 @@ void bootp(struct packet *);
void dhcp(struct packet *);
/* packet.c */
-void assemble_hw_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
+void assemble_hw_header(struct interface_info *, unsigned char *, int *);
void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t,
unsigned int, unsigned char *, int);
ssize_t decode_hw_header(unsigned char *, int, struct hardware *);
ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *,
unsigned char *, int);
-/* ethernet.c */
-void assemble_ethernet_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
-ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
- int, struct hardware *);
-
/* clparse.c */
int read_client_conf(void);
void read_client_leases(void);
@@ -441,4 +437,4 @@ struct buf *buf_open(size_t);
int buf_add(struct buf *, void *, size_t);
int buf_close(int, struct buf *);
ssize_t buf_read(int, void *, size_t);
-void dispatch_imsg(int);
+void dispatch_imsg(struct interface_info *, int);
diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c
index 2e90cc8..f79ca2f 100644
--- a/sbin/dhclient/packet.c
+++ b/sbin/dhclient/packet.c
@@ -55,11 +55,6 @@ __FBSDID("$FreeBSD$");
u_int32_t checksum(unsigned char *, unsigned, u_int32_t);
u_int32_t wrapsum(u_int32_t);
-void assemble_ethernet_header(struct interface_info *, unsigned char *,
- int *, struct hardware *);
-ssize_t decode_ethernet_header(struct interface_info *, unsigned char *,
- int bufix, struct hardware *);
-
u_int32_t
checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum)
{
@@ -95,14 +90,11 @@ wrapsum(u_int32_t sum)
void
assemble_hw_header(struct interface_info *interface, unsigned char *buf,
- int *bufix, struct hardware *to)
+ int *bufix)
{
struct ether_header eh;
- if (to != NULL && to->hlen == 6) /* XXX */
- memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost));
- else
- memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
+ memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost));
if (interface->hw_address.hlen == sizeof(eh.ether_shost))
memcpy(eh.ether_shost, interface->hw_address.haddr,
sizeof(eh.ether_shost));
@@ -128,7 +120,7 @@ assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from,
ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
ip.ip_id = 0;
ip.ip_off = 0;
- ip.ip_ttl = 16;
+ ip.ip_ttl = 128;
ip.ip_p = IPPROTO_UDP;
ip.ip_sum = 0;
ip.ip_src.s_addr = from;
diff --git a/sbin/dhclient/privsep.c b/sbin/dhclient/privsep.c
index b42572f..a0521a6 100644
--- a/sbin/dhclient/privsep.c
+++ b/sbin/dhclient/privsep.c
@@ -101,7 +101,7 @@ buf_read(int sock, void *buf, size_t nbytes)
}
void
-dispatch_imsg(int fd)
+dispatch_imsg(struct interface_info *ifi, int fd)
{
struct imsg_hdr hdr;
char *medium, *reason, *filename,
@@ -232,6 +232,9 @@ dispatch_imsg(int fd)
if (buf_close(fd, buf) == -1)
error("buf_close: %m");
break;
+ case IMSG_SEND_PACKET:
+ send_packet_priv(ifi, &hdr, fd);
+ break;
default:
error("received unknown message, code %d", hdr.code);
}
diff --git a/sbin/dhclient/privsep.h b/sbin/dhclient/privsep.h
index f30284e..d464da4 100644
--- a/sbin/dhclient/privsep.h
+++ b/sbin/dhclient/privsep.h
@@ -14,6 +14,8 @@
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
*/
#include <sys/types.h>
@@ -33,7 +35,8 @@ enum imsg_code {
IMSG_SCRIPT_INIT,
IMSG_SCRIPT_WRITE_PARAMS,
IMSG_SCRIPT_GO,
- IMSG_SCRIPT_GO_RET
+ IMSG_SCRIPT_GO_RET,
+ IMSG_SEND_PACKET
};
struct imsg_hdr {
diff --git a/sbin/dmesg/dmesg.8 b/sbin/dmesg/dmesg.8
index 9d05e6c..35446fb 100644
--- a/sbin/dmesg/dmesg.8
+++ b/sbin/dmesg/dmesg.8
@@ -28,7 +28,7 @@
.\" @(#)dmesg.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd June 5, 1993
+.Dd May 9, 2013
.Dt DMESG 8
.Os
.Sh NAME
@@ -36,7 +36,7 @@
.Nd "display the system message buffer"
.Sh SYNOPSIS
.Nm
-.Op Fl a
+.Op Fl ac
.Op Fl M Ar core Op Fl N Ar system
.Sh DESCRIPTION
The
@@ -59,6 +59,8 @@ Show all data in the message buffer.
This includes any syslog records and
.Pa /dev/console
output.
+.It Fl c
+Clear the kernel buffer after printing.
.It Fl M
Extract values associated with the name list from the specified core.
.It Fl N
diff --git a/sbin/dmesg/dmesg.c b/sbin/dmesg/dmesg.c
index 002732c..f0fcb81 100644
--- a/sbin/dmesg/dmesg.c
+++ b/sbin/dmesg/dmesg.c
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$");
#include <locale.h>
#include <nlist.h>
#include <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -79,15 +80,20 @@ main(int argc, char *argv[])
kvm_t *kd;
size_t buflen, bufpos;
long pri;
- int all, ch;
+ int ch, clear;
+ bool all;
- all = 0;
+ all = false;
+ clear = false;
(void) setlocale(LC_CTYPE, "");
memf = nlistf = NULL;
- while ((ch = getopt(argc, argv, "aM:N:")) != -1)
+ while ((ch = getopt(argc, argv, "acM:N:")) != -1)
switch(ch) {
case 'a':
- all++;
+ all = true;
+ break;
+ case 'c':
+ clear = true;
break;
case 'M':
memf = optarg;
@@ -114,6 +120,9 @@ main(int argc, char *argv[])
errx(1, "malloc failed");
if (sysctlbyname("kern.msgbuf", bp, &buflen, NULL, 0) == -1)
err(1, "sysctl kern.msgbuf");
+ if (clear)
+ if (sysctlbyname("kern.msgbuf_clear", NULL, NULL, &clear, sizeof(int)))
+ err(1, "sysctl kern.msgbuf_clear");
} else {
/* Read in kernel message buffer and do sanity checks. */
kd = kvm_open(nlistf, memf, NULL, O_RDONLY, "dmesg");
@@ -196,6 +205,6 @@ main(int argc, char *argv[])
void
usage(void)
{
- (void)fprintf(stderr, "usage: dmesg [-a] [-M core [-N system]]\n");
+ fprintf(stderr, "usage: dmesg [-ac] [-M core [-N system]]\n");
exit(1);
}
diff --git a/sbin/dumpfs/dumpfs.8 b/sbin/dumpfs/dumpfs.8
index 858881a..feb8758 100644
--- a/sbin/dumpfs/dumpfs.8
+++ b/sbin/dumpfs/dumpfs.8
@@ -28,7 +28,7 @@
.\" @(#)dumpfs.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd Jul 14, 2011
+.Dd May 16, 2013
.Dt DUMPFS 8
.Os
.Sh NAME
@@ -76,6 +76,27 @@ is specified, a
.Xr newfs 8
command is printed that can be used to generate a new file system
with equivalent settings.
+Please note that
+.Xr newfs 8
+options
+.Fl E ,
+.Fl R ,
+.Fl S ,
+and
+.Fl T
+are not handled and
+.Fl p
+is not useful in this case so is omitted.
+.Xr Newfs 8
+options
+.Fl n
+and
+.Fl r
+are neither checked for nor output but should be.
+The
+.Fl r
+flag is needed if the filesystem uses
+.Xr gjournal 8 .
.Sh SEE ALSO
.Xr disktab 5 ,
.Xr fs 5 ,
diff --git a/sbin/dumpfs/dumpfs.c b/sbin/dumpfs/dumpfs.c
index 6669d53..baf3d99 100644
--- a/sbin/dumpfs/dumpfs.c
+++ b/sbin/dumpfs/dumpfs.c
@@ -197,15 +197,15 @@ dumpfs(const char *name)
"maxbsize", afs.fs_maxbsize, afs.fs_maxbpg,
afs.fs_maxcontig, afs.fs_contigsumsize);
printf("nbfree\t%jd\tndir\t%jd\tnifree\t%jd\tnffree\t%jd\n",
- (intmax_t)afs.fs_cstotal.cs_nbfree,
+ (intmax_t)afs.fs_cstotal.cs_nbfree,
(intmax_t)afs.fs_cstotal.cs_ndir,
- (intmax_t)afs.fs_cstotal.cs_nifree,
+ (intmax_t)afs.fs_cstotal.cs_nifree,
(intmax_t)afs.fs_cstotal.cs_nffree);
printf("bpg\t%d\tfpg\t%d\tipg\t%d\tunrefs\t%jd\n",
afs.fs_fpg / afs.fs_frag, afs.fs_fpg, afs.fs_ipg,
(intmax_t)afs.fs_unrefs);
printf("nindir\t%d\tinopb\t%d\tmaxfilesize\t%ju\n",
- afs.fs_nindir, afs.fs_inopb,
+ afs.fs_nindir, afs.fs_inopb,
(uintmax_t)afs.fs_maxfilesize);
printf("sbsize\t%d\tcgsize\t%d\tcsaddr\t%jd\tcssize\t%d\n",
afs.fs_sbsize, afs.fs_cgsize, (intmax_t)afs.fs_csaddr,
@@ -417,12 +417,15 @@ marshal(const char *name)
printf("-f %d ", fs->fs_fsize);
printf("-g %d ", fs->fs_avgfilesize);
printf("-h %d ", fs->fs_avgfpdir);
- /* -i is dumb */
+ printf("-i %jd ", fragroundup(fs, lblktosize(fs, fragstoblks(fs,
+ fs->fs_fpg)) / fs->fs_ipg));
if (fs->fs_flags & FS_SUJ)
printf("-j ");
if (fs->fs_flags & FS_GJOURNAL)
printf("-J ");
- /* -k..l unimplemented */
+ printf("-k %jd ", fs->fs_metaspace);
+ if (fs->fs_flags & FS_MULTILABEL)
+ printf("-l ");
printf("-m %d ", fs->fs_minfree);
/* -n unimplemented */
printf("-o ");
diff --git a/sbin/dumpon/dumpon.8 b/sbin/dumpon/dumpon.8
index 2c09e85..6be8090 100644
--- a/sbin/dumpon/dumpon.8
+++ b/sbin/dumpon/dumpon.8
@@ -28,7 +28,7 @@
.\" From: @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd May 12, 1995
+.Dd April 29, 2013
.Dt DUMPON 8
.Os
.Sh NAME
@@ -59,14 +59,21 @@ controlled by the
variable in the boot time configuration file
.Pa /etc/rc.conf .
.Pp
-For most systems the size of the specified dump device must be at
+The default type of kernel crash dump is the mini crash dump.
+Mini crash dumps hold only memory pages in use by the kernel.
+Alternatively, full memory dumps can be enabled by setting the
+.Va debug.minidump
+.Xr sysctl 8
+variable to 0.
+.Pp
+For systems using full memory dumps, the size of the specified dump
+device must be at
least the size of physical memory.
Even though an additional 64 kB header is added to the dump, the BIOS for a
platform typically holds back some memory, so it is not usually
necessary to size the dump device larger than the actual amount of RAM
available in the machine.
-.Pp
-The
+Also, when using full memory dumps, the
.Nm
utility will refuse to enable a dump device which is smaller than the
total amount of physical memory as reported by the
diff --git a/sbin/etherswitchcfg/etherswitchcfg.8 b/sbin/etherswitchcfg/etherswitchcfg.8
index 4f3bc92..a8b8d1a 100644
--- a/sbin/etherswitchcfg/etherswitchcfg.8
+++ b/sbin/etherswitchcfg/etherswitchcfg.8
@@ -11,12 +11,16 @@
.Ar info
.Nm
.Op Fl "f control file"
+.Ar config
+.Ar command parameter
+.Nm
+.Op Fl "f control file"
.Ar phy
.Ar phy.register[=value]
.Nm
.Op Fl "f control file"
.Ar port%d
-.Ar command parameter
+.Ar [flags] command parameter
.Nm
.Op Fl "f control file"
.Ar reg
@@ -46,6 +50,14 @@ Produce more verbose output.
Without this flag, lines that represent inactive or empty configuration
options are omitted.
.El
+.Ss config
+The config command provides access to global switch configuration
+parameters.
+It support the following commands:
+.Bl -tag -width ".Ar vlan_mode mode" -compact
+.It Ar vlan_mode mode
+Sets the switch VLAN mode (depends on the hardware).
+.El
.Ss phy
The phy command provides access to the registers of the PHYs attached
to or integrated into the switch controller.
@@ -57,24 +69,57 @@ is usually the port number, and
is the register number.
Both can be provided as decimal, octal or hexadecimal numbers in any of the formats
understood by
-.Xr strtol 4 .
+.Xr strtol 3 .
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.
+.Bl -tag -width ".Ar pvid number" -compact
+.It Ar pvid number
+Sets the default port VID 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
+Specifies a list of media options for a port.
+See
.Xr ifconfig 8
for details on
.Ar media
and
.Ar mediaopt .
.El
+And the following flags (please note that not all flags
+are supporterd by all switch drivers):
+.Bl -tag -width ".Ar addtag" -compact
+.It Ar addtag
+Add VLAN tag to each packet sent by the port.
+.It Ar -addtag
+Disable the add VLAN tag option.
+.It Ar striptag
+Strip the VLAN tags from the packets sent by the port.
+.It Ar -striptag
+Disable the strip VLAN tag option.
+.It Ar firstlock
+This options makes the switch port lock on the first MAC address it seems.
+After that, usually you need to reset the switch to learn different
+MAC addresses.
+.It Ar -firstlock
+Disable the first lock option.
+Note that sometimes you need to reset the
+switch to really disable this option.
+.It Ar dropuntagged
+Drop packets without a VLAN tag.
+.It Ar -dropuntagged
+Disable the drop untagged packets option.
+.It Ar doubletag
+Enable QinQ for the port.
+.It Ar -doubletag
+Disable QinQ for the port.
+.It Ar ingress
+Enable the ingress filter on the port.
+.It Ar -ingress
+Disable the ingress filter.
+.El
.Ss reg
The reg command provides access to the registers of the switch controller.
.Ss vlangroup
@@ -104,7 +149,7 @@ 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
+.Dl # etherswitchcfg vlangroup1 vlan 2 members 0,5t port0 pvid 2
.Sh SEE ALSO
.Xr etherswitch 4
.Sh HISTORY
diff --git a/sbin/etherswitchcfg/etherswitchcfg.c b/sbin/etherswitchcfg/etherswitchcfg.c
index ea2cec8..1eef832 100644
--- a/sbin/etherswitchcfg/etherswitchcfg.c
+++ b/sbin/etherswitchcfg/etherswitchcfg.c
@@ -58,6 +58,7 @@ void print_media_word_ifconfig(int);
enum cmdmode {
MODE_NONE = 0,
MODE_PORT,
+ MODE_CONFIG,
MODE_VLANGROUP,
MODE_REGISTER,
MODE_PHYREG
@@ -68,6 +69,7 @@ struct cfg {
int verbose;
int mediatypes;
const char *controlfile;
+ etherswitch_conf_t conf;
etherswitch_info_t info;
enum cmdmode mode;
int unit;
@@ -82,7 +84,37 @@ struct cmds {
static struct cmds cmds[];
-static void usage(void);
+/*
+ * Print a value a la the %b format of the kernel's printf.
+ * Stolen from ifconfig.c.
+ */
+static void
+printb(const char *s, unsigned v, const char *bits)
+{
+ int i, any = 0;
+ char c;
+
+ if (bits && *bits == 8)
+ printf("%s=%o", s, v);
+ else
+ printf("%s=%x", s, v);
+ bits++;
+ if (bits) {
+ putchar('<');
+ while ((i = *bits++) != '\0') {
+ if (v & (1 << (i-1))) {
+ if (any)
+ putchar(',');
+ any = 1;
+ for (; (c = *bits) > 32; bits++)
+ putchar(c);
+ } else
+ for (; *bits > 32; bits++)
+ ;
+ }
+ putchar('>');
+ }
+}
static int
read_register(struct cfg *cfg, int r)
@@ -131,18 +163,61 @@ write_phyregister(struct cfg *cfg, int phy, int reg, int val)
}
static void
-set_port_vlangroup(struct cfg *cfg, char *argv[])
+set_port_vid(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);
+ if (v < 0 || v > IEEE802DOT1Q_VID_MAX)
+ errx(EX_USAGE, "pvid must be between 0 and %d",
+ IEEE802DOT1Q_VID_MAX);
+ bzero(&p, sizeof(p));
+ p.es_port = cfg->unit;
+ if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
+ err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
+ p.es_pvid = v;
+ if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
+ err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
+}
+
+static void
+set_port_flag(struct cfg *cfg, char *argv[])
+{
+ char *flag;
+ int n;
+ uint32_t f;
+ etherswitch_port_t p;
+
+ n = 0;
+ f = 0;
+ flag = argv[0];
+ if (strcmp(flag, "none") != 0) {
+ if (*flag == '-') {
+ n++;
+ flag++;
+ }
+ if (strcasecmp(flag, "striptag") == 0)
+ f = ETHERSWITCH_PORT_STRIPTAG;
+ else if (strcasecmp(flag, "addtag") == 0)
+ f = ETHERSWITCH_PORT_ADDTAG;
+ else if (strcasecmp(flag, "firstlock") == 0)
+ f = ETHERSWITCH_PORT_FIRSTLOCK;
+ else if (strcasecmp(flag, "dropuntagged") == 0)
+ f = ETHERSWITCH_PORT_DROPUNTAGGED;
+ else if (strcasecmp(flag, "doubletag") == 0)
+ f = ETHERSWITCH_PORT_DOUBLE_TAG;
+ else if (strcasecmp(flag, "ingress") == 0)
+ f = ETHERSWITCH_PORT_INGRESS;
+ }
+ bzero(&p, sizeof(p));
p.es_port = cfg->unit;
if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
- p.es_vlangroup = v;
+ if (n)
+ p.es_flags &= ~f;
+ else
+ p.es_flags |= f;
if (ioctl(cfg->fd, IOETHERSWITCHSETPORT, &p) != 0)
err(EX_OSERR, "ioctl(IOETHERSWITCHSETPORT)");
}
@@ -288,6 +363,66 @@ set_phyregister(struct cfg *cfg, char *arg)
}
static void
+set_vlan_mode(struct cfg *cfg, char *argv[])
+{
+ etherswitch_conf_t conf;
+
+ bzero(&conf, sizeof(conf));
+ conf.cmd = ETHERSWITCH_CONF_VLAN_MODE;
+ if (strcasecmp(argv[1], "isl") == 0)
+ conf.vlan_mode = ETHERSWITCH_VLAN_ISL;
+ else if (strcasecmp(argv[1], "port") == 0)
+ conf.vlan_mode = ETHERSWITCH_VLAN_PORT;
+ else if (strcasecmp(argv[1], "dot1q") == 0)
+ conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q;
+ else if (strcasecmp(argv[1], "dot1q4k") == 0)
+ conf.vlan_mode = ETHERSWITCH_VLAN_DOT1Q_4K;
+ else if (strcasecmp(argv[1], "qinq") == 0)
+ conf.vlan_mode = ETHERSWITCH_VLAN_DOUBLE_TAG;
+ else
+ conf.vlan_mode = 0;
+ if (ioctl(cfg->fd, IOETHERSWITCHSETCONF, &conf) != 0)
+ err(EX_OSERR, "ioctl(IOETHERSWITCHSETCONF)");
+}
+
+static void
+print_config(struct cfg *cfg)
+{
+ const char *c;
+
+ /* Get the device name. */
+ c = strrchr(cfg->controlfile, '/');
+ if (c != NULL)
+ c = c + 1;
+ else
+ c = cfg->controlfile;
+
+ /* Print VLAN mode. */
+ if (cfg->conf.cmd & ETHERSWITCH_CONF_VLAN_MODE) {
+ printf("%s: VLAN mode: ", c);
+ switch (cfg->conf.vlan_mode) {
+ case ETHERSWITCH_VLAN_ISL:
+ printf("ISL\n");
+ break;
+ case ETHERSWITCH_VLAN_PORT:
+ printf("PORT\n");
+ break;
+ case ETHERSWITCH_VLAN_DOT1Q:
+ printf("DOT1Q\n");
+ break;
+ case ETHERSWITCH_VLAN_DOT1Q_4K:
+ printf("DOT1Q4K\n");
+ break;
+ case ETHERSWITCH_VLAN_DOUBLE_TAG:
+ printf("QinQ\n");
+ break;
+ default:
+ printf("none\n");
+ }
+ }
+}
+
+static void
print_port(struct cfg *cfg, int port)
{
etherswitch_port_t p;
@@ -301,7 +436,10 @@ print_port(struct cfg *cfg, int port)
if (ioctl(cfg->fd, IOETHERSWITCHGETPORT, &p) != 0)
err(EX_OSERR, "ioctl(IOETHERSWITCHGETPORT)");
printf("port%d:\n", port);
- printf("\tvlangroup: %d\n", p.es_vlangroup);
+ if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_DOT1Q)
+ printf("\tpvid: %d\n", p.es_pvid);
+ printb("\tflags", p.es_flags, ETHERSWITCH_PORT_FLAGS_BITS);
+ printf("\n");
printf("\tmedia: ");
print_media_word(p.es_ifmr.ifm_current, 1);
if (p.es_ifmr.ifm_active != p.es_ifmr.ifm_current) {
@@ -333,10 +471,14 @@ print_vlangroup(struct cfg *cfg, int vlangroup)
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)
+ if ((vg.es_vid & ETHERSWITCH_VID_VALID) == 0)
return;
+ vg.es_vid &= ETHERSWITCH_VID_MASK;
printf("vlangroup%d:\n", vlangroup);
- printf("\tvlan: %d\n", vg.es_vid);
+ if (cfg->conf.vlan_mode == ETHERSWITCH_VLAN_PORT)
+ printf("\tport: %d\n", vg.es_vid);
+ else
+ printf("\tvlan: %d\n", vg.es_vid);
printf("\tmembers ");
comma = 0;
if (vg.es_member_ports != 0)
@@ -366,9 +508,16 @@ print_info(struct cfg *cfg)
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);
+ 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);
+ printf("%s: ", c);
+ printb("VLAN capabilities", cfg->info.es_vlan_caps,
+ ETHERSWITCH_VLAN_CAPS_BITS);
+ printf("\n");
+ }
+ print_config(cfg);
for (i=0; i<cfg->info.es_nports; i++) {
print_port(cfg, i);
}
@@ -378,9 +527,23 @@ print_info(struct cfg *cfg)
}
static void
-usage(void)
+usage(struct cfg *cfg __unused, char *argv[] __unused)
{
fprintf(stderr, "usage: etherswitchctl\n");
+ fprintf(stderr, "\tetherswitchcfg [-f control file] info\n");
+ fprintf(stderr, "\tetherswitchcfg [-f control file] config "
+ "command parameter\n");
+ fprintf(stderr, "\t\tconfig commands: vlan_mode\n");
+ fprintf(stderr, "\tetherswitchcfg [-f control file] phy "
+ "phy.register[=value]\n");
+ fprintf(stderr, "\tetherswitchcfg [-f control file] portX "
+ "[flags] command parameter\n");
+ fprintf(stderr, "\t\tport commands: pvid, media, mediaopt\n");
+ fprintf(stderr, "\tetherswitchcfg [-f control file] reg "
+ "register[=value]\n");
+ fprintf(stderr, "\tetherswitchcfg [-f control file] vlangroupX "
+ "command parameter\n");
+ fprintf(stderr, "\t\tvlangroup commands: vlan, members\n");
exit(EX_USAGE);
}
@@ -392,6 +555,15 @@ newmode(struct cfg *cfg, enum cmdmode mode)
switch (cfg->mode) {
case MODE_NONE:
break;
+ case MODE_CONFIG:
+ /*
+ * Read the updated the configuration (it can be different
+ * from the last time we read it).
+ */
+ if (ioctl(cfg->fd, IOETHERSWITCHGETCONF, &cfg->conf) != 0)
+ err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)");
+ print_config(cfg);
+ break;
case MODE_PORT:
print_port(cfg, cfg->unit);
break;
@@ -428,7 +600,7 @@ main(int argc, char *argv[])
case '?':
/* FALLTHROUGH */
default:
- usage();
+ usage(&cfg, argv);
}
argc -= optind;
argv += optind;
@@ -437,6 +609,8 @@ main(int argc, char *argv[])
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 (ioctl(cfg.fd, IOETHERSWITCHGETCONF, &cfg.conf) != 0)
+ err(EX_OSERR, "ioctl(IOETHERSWITCHGETCONF)");
if (argc == 0) {
print_info(&cfg);
return (0);
@@ -453,21 +627,31 @@ main(int argc, char *argv[])
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);
+ errx(EX_USAGE,
+ "vlangroup unit must be between 0 and %d",
+ cfg.info.es_nvlangroups - 1);
newmode(&cfg, MODE_VLANGROUP);
+ } else if (strcmp(argv[0], "config") == 0) {
+ newmode(&cfg, MODE_CONFIG);
} else if (strcmp(argv[0], "phy") == 0) {
newmode(&cfg, MODE_PHYREG);
} else if (strcmp(argv[0], "reg") == 0) {
newmode(&cfg, MODE_REGISTER);
+ } else if (strcmp(argv[0], "help") == 0) {
+ usage(&cfg, argv);
} else {
errx(EX_USAGE, "Unknown command \"%s\"", argv[0]);
}
break;
case MODE_PORT:
+ case MODE_CONFIG:
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) {
+ if (cfg.mode == cmds[i].mode && strcmp(argv[0], cmds[i].name) == 0) {
+ if (argc < (cmds[i].args + 1)) {
+ printf("%s needs an argument\n", cmds[i].name);
+ break;
+ }
(cmds[i].f)(&cfg, argv);
argc -= cmds[i].args;
argv += cmds[i].args;
@@ -502,9 +686,22 @@ main(int argc, char *argv[])
}
static struct cmds cmds[] = {
- { MODE_PORT, "vlangroup", 1, set_port_vlangroup },
+ { MODE_PORT, "pvid", 1, set_port_vid },
{ MODE_PORT, "media", 1, set_port_media },
{ MODE_PORT, "mediaopt", 1, set_port_mediaopt },
+ { MODE_PORT, "addtag", 0, set_port_flag },
+ { MODE_PORT, "-addtag", 0, set_port_flag },
+ { MODE_PORT, "ingress", 0, set_port_flag },
+ { MODE_PORT, "-ingress", 0, set_port_flag },
+ { MODE_PORT, "striptag", 0, set_port_flag },
+ { MODE_PORT, "-striptag", 0, set_port_flag },
+ { MODE_PORT, "doubletag", 0, set_port_flag },
+ { MODE_PORT, "-doubletag", 0, set_port_flag },
+ { MODE_PORT, "firstlock", 0, set_port_flag },
+ { MODE_PORT, "-firstlock", 0, set_port_flag },
+ { MODE_PORT, "dropuntagged", 0, set_port_flag },
+ { MODE_PORT, "-dropuntagged", 0, set_port_flag },
+ { MODE_CONFIG, "vlan_mode", 1, set_vlan_mode },
{ MODE_VLANGROUP, "vlan", 1, set_vlangroup_vid },
{ MODE_VLANGROUP, "members", 1, set_vlangroup_members },
{ 0, NULL, 0, NULL }
diff --git a/sbin/fdisk_pc98/fdisk.c b/sbin/fdisk_pc98/fdisk.c
index b66bad4..479e1e4 100644
--- a/sbin/fdisk_pc98/fdisk.c
+++ b/sbin/fdisk_pc98/fdisk.c
@@ -254,7 +254,7 @@ main(int argc, char *argv[])
dos_sectors);
printf("Part %11s %11s %4s %4s %-16s\n", "Start", "Size", "MID",
"SID", "Name");
- for (i = 0; i < NDOSPART; i++) {
+ for (i = 0; i < PC98_NPARTS; i++) {
partp = ((struct pc98_partition *) &mboot.parts) + i;
if (partp->dp_sid == 0)
continue;
@@ -310,7 +310,7 @@ main(int argc, char *argv[])
printf("Warning: BIOS sector numbering starts with sector 1\n");
printf("Information from DOS bootblock is:\n");
if (partition == -1)
- for (i = 1; i <= NDOSPART; i++)
+ for (i = 1; i <= PC98_NPARTS; i++)
change_part(i, v_flag);
else
change_part(partition, 1);
@@ -367,7 +367,7 @@ print_s0(int which)
print_params();
printf("Information from DOS bootblock is:\n");
if (which == -1) {
- for (i = 1; i <= NDOSPART; i++)
+ for (i = 1; i <= PC98_NPARTS; i++)
if (v_flag || !part_unused(i)) {
printf("%d: ", i);
print_part(i);
@@ -414,7 +414,7 @@ static void
init_boot(void)
{
- mboot.signature = DOSMAGIC;
+ mboot.signature = PC98_MAGIC;
}
@@ -517,7 +517,7 @@ change_active(int which)
int active, i, new, tmp;
active = -1;
- for (i = 0; i < NDOSPART; i++) {
+ for (i = 0; i < PC98_NPARTS; i++) {
if ((partp[i].dp_sid & PC98_SID_ACTIVE) == 0)
continue;
printf("Partition %d is marked active\n", i + 1);
@@ -672,7 +672,7 @@ write_disk(off_t sector, void *buf)
if (error == sz)
return (0);
- for (i = 0; i < NDOSPART; i++) {
+ for (i = 0; i < PC98_NPARTS; i++) {
sprintf(fbuf, "%ss%d", disk, i + 1);
fdw = open(fbuf, O_RDWR, 0);
if (fdw < 0)
@@ -731,7 +731,7 @@ read_s0()
warnx("can't read fdisk partition table");
return -1;
}
- if (mboot.signature != DOSMAGIC) {
+ if (mboot.signature != PC98_MAGIC) {
warnx("invalid fdisk partition table found");
/* So should we initialize things */
return -1;
@@ -911,7 +911,7 @@ reset_boot(void)
struct pc98_partition *partp;
init_boot();
- for (i = 1; i <= NDOSPART; i++) {
+ for (i = 1; i <= PC98_NPARTS; i++) {
partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
bzero((char *)partp, sizeof (struct pc98_partition));
}
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 7b45d48..632d454 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -74,6 +74,7 @@
#define MINBUFS 10 /* minimum number of buffers required */
#define MAXBUFS 40 /* maximum space to allocate to buffers */
#define INOBUFSIZE 64*1024 /* size of buffer to read inodes in pass1 */
+#define ZEROBUFSIZE (dev_bsize * 128) /* size of zero buffer used by -Z */
union dinode {
struct ufs1_dinode dp1;
@@ -306,7 +307,8 @@ char yflag; /* assume a yes response */
int bkgrdflag; /* use a snapshot to run on an active system */
int bflag; /* location of alternate super block */
int debug; /* output debugging info */
-int Eflag; /* zero out empty data blocks */
+int Eflag; /* delete empty data blocks */
+int Zflag; /* zero empty data blocks */
int inoopt; /* trim out unused inodes */
char ckclean; /* only do work if not cleanly unmounted */
int cvtlevel; /* convert to newer file system format */
@@ -322,6 +324,7 @@ char skipclean; /* skip clean file systems if preening */
int fsmodified; /* 1 => write done to file system */
int fsreadfd; /* file descriptor for reading file system */
int fswritefd; /* file descriptor for writing file system */
+int surrender; /* Give up if reads fail */
ufs2_daddr_t maxfsblock; /* number of blocks in the file system */
char *blockmap; /* ptr to primary blk allocation map */
@@ -402,6 +405,7 @@ int blread(int fd, char *buf, ufs2_daddr_t blk, long size);
void bufinit(void);
void blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size);
void blerase(int fd, ufs2_daddr_t blk, long size);
+void blzero(int fd, ufs2_daddr_t blk, long size);
void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8
index 0513017..adf08d7 100644
--- a/sbin/fsck_ffs/fsck_ffs.8
+++ b/sbin/fsck_ffs/fsck_ffs.8
@@ -29,7 +29,7 @@
.\" @(#)fsck.8 8.4 (Berkeley) 5/9/95
.\" $FreeBSD$
.\"
-.Dd February 10, 2012
+.Dd July 30, 2013
.Dt FSCK_FFS 8
.Os
.Sh NAME
@@ -38,7 +38,7 @@
.Nd file system consistency check and interactive repair
.Sh SYNOPSIS
.Nm
-.Op Fl BEFfnpry
+.Op Fl BEFfnpryZ
.Op Fl b Ar block
.Op Fl c Ar level
.Op Fl m Ar mode
@@ -275,11 +275,25 @@ and frees up space that can allocated to files.
The
.Fl r
option is ignored when running in preen mode.
+.It Fl S
+Surrender on error.
+With this flag enabled, a hard error returned on disk i/o will cause
+.Nm
+to abort instead of continuing on and possibly tripping over more i/o errors.
.It Fl y
Assume a yes response to all questions asked by
.Nm ;
this should be used with great caution as this is a free license
to continue after essentially unlimited trouble has been encountered.
+.It Fl Z
+Similar to
+.Fl E ,
+but overwrites unused blocks with zeroes.
+If both
+.Fl E
+and
+.Fl Z
+are specified, blocks are first zeroed and then erased.
.El
.Pp
Inconsistencies checked are as follows:
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 9ebc342..16ef819 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -549,7 +549,18 @@ blread(int fd, char *buf, ufs2_daddr_t blk, long size)
slowio_end();
return (0);
}
- rwerror("READ BLK", blk);
+
+ /*
+ * This is handled specially here instead of in rwerror because
+ * rwerror is used for all sorts of errors, not just true read/write
+ * errors. It should be refactored and fixed.
+ */
+ if (surrender) {
+ pfatal("CANNOT READ_BLK: %ld", (long)blk);
+ errx(EEXIT, "ABORTING DUE TO READ ERRORS");
+ } else
+ rwerror("READ BLK", blk);
+
if (lseek(fd, offset, 0) < 0)
rwerror("SEEK BLK", blk);
errs = 0;
@@ -619,6 +630,35 @@ blerase(int fd, ufs2_daddr_t blk, long size)
}
/*
+ * Fill a contiguous region with all-zeroes. Note ZEROBUFSIZE is by
+ * definition a multiple of dev_bsize.
+ */
+void
+blzero(int fd, ufs2_daddr_t blk, long size)
+{
+ static char *zero;
+ off_t offset, len;
+
+ if (fd < 0)
+ return;
+ if (zero == NULL) {
+ zero = calloc(ZEROBUFSIZE, 1);
+ if (zero == NULL)
+ errx(EEXIT, "cannot allocate buffer pool");
+ }
+ offset = blk * dev_bsize;
+ if (lseek(fd, offset, 0) < 0)
+ rwerror("SEEK BLK", blk);
+ while (size > 0) {
+ len = size > ZEROBUFSIZE ? ZEROBUFSIZE : size;
+ if (write(fd, zero, len) != len)
+ rwerror("WRITE BLK", blk);
+ blk += len / dev_bsize;
+ size -= len;
+ }
+}
+
+/*
* Verify cylinder group's magic number and other parameters. If the
* test fails, offer an option to rebuild the whole cylinder group.
*/
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 27f17db..1a1c03b 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -82,7 +82,7 @@ main(int argc, char *argv[])
sync();
skipclean = 1;
inoopt = 0;
- while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npry")) != -1) {
+ while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:nprSyZ")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
@@ -142,11 +142,19 @@ main(int argc, char *argv[])
inoopt++;
break;
+ case 'S':
+ surrender = 1;
+ break;
+
case 'y':
yflag++;
nflag = 0;
break;
+ case 'Z':
+ Zflag++;
+ break;
+
default:
usage();
}
diff --git a/sbin/fsck_ffs/pass5.c b/sbin/fsck_ffs/pass5.c
index 146acec..13ef86d 100644
--- a/sbin/fsck_ffs/pass5.c
+++ b/sbin/fsck_ffs/pass5.c
@@ -252,7 +252,7 @@ pass5(void)
frags = 0;
for (j = 0; j < fs->fs_frag; j++) {
if (testbmap(d + j)) {
- if (Eflag && start != -1) {
+ if ((Eflag || Zflag) && start != -1) {
clear_blocks(start, d + j - 1);
start = -1;
}
@@ -274,7 +274,7 @@ pass5(void)
ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
}
}
- if (Eflag && start != -1)
+ if ((Eflag || Zflag) && start != -1)
clear_blocks(start, d - 1);
if (fs->fs_contigsumsize > 0) {
int32_t *sump = cg_clustersum(newcg);
@@ -581,11 +581,16 @@ check_maps(
}
}
-static void clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end)
+static void
+clear_blocks(ufs2_daddr_t start, ufs2_daddr_t end)
{
if (debug)
printf("Zero frags %jd to %jd\n", start, end);
- blerase(fswritefd, fsbtodb(&sblock, start),
- lfragtosize(&sblock, end - start + 1));
+ if (Zflag)
+ blzero(fswritefd, fsbtodb(&sblock, start),
+ lfragtosize(&sblock, end - start + 1));
+ if (Eflag)
+ blerase(fswritefd, fsbtodb(&sblock, start),
+ lfragtosize(&sblock, end - start + 1));
}
diff --git a/sbin/gbde/Makefile b/sbin/gbde/Makefile
index 3975eb6..019ee18 100644
--- a/sbin/gbde/Makefile
+++ b/sbin/gbde/Makefile
@@ -10,6 +10,7 @@ SRCS+= g_bde_lock.c
# rijndael-fst.c does evil casting things which can results in warnings,
# the test-vectors check out however, so it works right.
NO_WCAST_ALIGN=
+NO_WMISSING_VARIABLE_DECLARATIONS=
CFLAGS+= -I${.CURDIR}/../../sys
.PATH: ${.CURDIR}/../../sys/geom/bde \
diff --git a/sbin/geom/class/Makefile.inc b/sbin/geom/class/Makefile.inc
index 6f0141e..06b733f 100644
--- a/sbin/geom/class/Makefile.inc
+++ b/sbin/geom/class/Makefile.inc
@@ -6,6 +6,8 @@ LINKS= ${BINDIR}/geom ${BINDIR}/g${GEOM_CLASS}
MAN= g${GEOM_CLASS}.8
SRCS+= geom_${GEOM_CLASS}.c subr.c
+NO_WMISSING_VARIABLE_DECLARATIONS=
+
CFLAGS+= -I${.CURDIR}/../..
.include "../Makefile.inc"
diff --git a/sbin/geom/class/eli/geli.8 b/sbin/geom/class/eli/geli.8
index 263b8b2..ad70798 100644
--- a/sbin/geom/class/eli/geli.8
+++ b/sbin/geom/class/eli/geli.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 18, 2012
+.Dd July 5, 2013
.Dt GELI 8
.Os
.Sh NAME
@@ -285,11 +285,14 @@ Currently supported algorithms are:
.Nm AES-XTS ,
.Nm AES-CBC ,
.Nm Blowfish-CBC ,
-.Nm Camellia-CBC
+.Nm Camellia-CBC ,
+.Nm 3DES-CBC ,
and
-.Nm 3DES-CBC .
+.Nm NULL .
The default and recommended algorithm is
.Nm AES-XTS .
+.Nm NULL
+is unencrypted.
.It Fl i Ar iterations
Number of iterations to use with PKCS#5v2 when processing User Key
passphrase component.
diff --git a/sbin/geom/class/label/glabel.8 b/sbin/geom/class/label/glabel.8
index fff9205..c1c7bc4 100644
--- a/sbin/geom/class/label/glabel.8
+++ b/sbin/geom/class/label/glabel.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 13, 2009
+.Dd April 22, 2013
.Dt GLABEL 8
.Os
.Sh NAME
@@ -81,7 +81,7 @@ The
method uses on-disk metadata to store the label and detect it automatically in
the future.
.Pp
-This class also provides volume label detection for file systems.
+This GEOM class also provides volume label detection for file systems.
Those labels cannot be set with
.Nm ,
but must be set with the appropriate file system utility, e.g.\& for UFS
diff --git a/sbin/geom/class/nop/gnop.8 b/sbin/geom/class/nop/gnop.8
index 892212c..2bcbef3 100644
--- a/sbin/geom/class/nop/gnop.8
+++ b/sbin/geom/class/nop/gnop.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 17, 2009
+.Dd April 14, 2013
.Dt GNOP 8
.Os
.Sh NAME
@@ -139,8 +139,11 @@ Debug level of the
.Nm NOP
GEOM class.
This can be set to a number between 0 and 2 inclusive.
-If set to 0 minimal debug information is printed, and if set to 2 the
-maximum amount of debug information is printed.
+If set to 0, minimal debug information is printed.
+If set to 1, basic debug information is logged along with the I/O requests
+that were returned as errors.
+If set to 2, the maximum amount of debug information is printed including
+all I/O requests.
.El
.Sh EXIT STATUS
Exit status is 0 on success, and 1 if the command fails.
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index 8a57ca4..9b3e0e5 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -147,10 +147,10 @@ struct g_command PUBSYM(class_commands)[] = {
},
{ "set", 0, gpart_issue, {
{ 'a', "attrib", NULL, G_TYPE_STRING },
- { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER },
+ { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER },
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
G_OPT_SENTINEL },
- "-a attrib -i index [-f flags] geom"
+ "-a attrib [-i index] [-f flags] geom"
},
{ "show", 0, gpart_show, {
{ 'l', "show_label", NULL, G_TYPE_BOOL },
@@ -164,10 +164,10 @@ struct g_command PUBSYM(class_commands)[] = {
},
{ "unset", 0, gpart_issue, {
{ 'a', "attrib", NULL, G_TYPE_STRING },
- { 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER },
+ { 'i', GPART_PARAM_INDEX, G_VAL_OPTIONAL, G_TYPE_NUMBER },
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
G_OPT_SENTINEL },
- "-a attrib -i index [-f flags] geom"
+ "-a attrib [-i index] [-f flags] geom"
},
{ "resize", 0, gpart_issue, {
{ 'a', "alignment", GPART_AUTOFILL, G_TYPE_STRING },
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index 7386900..3ce79a8 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 25, 2013
+.Dd July 1, 2013
.Dt GPART 8
.Os
.Sh NAME
@@ -645,14 +645,12 @@ The scheme-specific attributes for GPT:
When set, the
.Nm gptboot
stage 1 boot loader will try to boot the system from this partition.
-Multiple partitions might be marked with the
+Multiple partitions can be marked with the
.Cm bootme
attribute.
-In such scenario the
-.Nm gptboot
-will try all
-.Cm bootme
-partitions one by one, until the next boot stage is successfully entered.
+See
+.Xr gptboot 8
+for more details.
.It Cm bootonce
Setting this attribute automatically sets the
.Cm bootme
@@ -660,49 +658,14 @@ attribute.
When set, the
.Nm gptboot
stage 1 boot loader will try to boot the system from this partition only once.
-Partitions with both
-.Cm bootonce
-and
-.Cm bootme
-attributes are tried before partitions with only the
-.Cm bootme
-attribute.
-Before
-.Cm bootonce
-partition is tried, the
-.Nm gptboot
-removes the
-.Cm bootme
-attribute and tries to execute the next boot stage.
-If it fails, the
-.Cm bootonce
-attribute that is now alone is replaced with the
-.Cm bootfailed
-attribute.
-If the execution of the next boot stage succeeds, but the system is not fully
-booted, the
-.Nm gptboot
-will look for
-.Cm bootonce
-attributes alone (without the
-.Cm bootme
-attribute) on the next system boot and will replace those with the
-.Cm bootfailed
-attribute.
-If the system is fully booted, the
-.Pa /etc/rc.d/gptboot
-start-up script will look for partition with the
-.Cm bootonce
-attribute alone, will remove the attribute and log that the system was
-successfully booted from this partition.
-There should be at most one
-.Cm bootonce
-partition when system is successfully booted.
-Multiple partitions might be marked with the
+Multiple partitions can be marked with the
.Cm bootonce
and
.Cm bootme
attribute pairs.
+See
+.Xr gptboot 8
+for more details.
.It Cm bootfailed
This attribute should not be manually managed.
It is managed by the
@@ -710,14 +673,9 @@ It is managed by the
stage 1 boot loader and the
.Pa /etc/rc.d/gptboot
start-up script.
-This attribute is used to mark partitions that had the
-.Cm bootonce
-attribute set, but we failed to boot from them.
-Once we successfully boot, the
-.Pa /etc/rc.d/gptboot
-script will log all the partitions we failed to boot from and will remove the
-.Cm bootfailed
-attributes.
+See
+.Xr gptboot 8
+for more details.
.El
.Pp
The scheme-specific attributes for MBR:
@@ -795,20 +753,17 @@ There are two variants of bootstrap code to write to this partition:
.Pa /boot/gptboot
and
.Pa /boot/gptzfsboot .
+.Pp
.Pa /boot/gptboot
-is used to boot from UFS.
-It searches through
+is used to boot from UFS partitions.
+.Cm gptboot
+searches through
.Cm freebsd-ufs
-partitions in the GPT and boots from the first one with the
+partitions in the GPT and selects one to boot based on the
.Cm bootonce
-attribute set.
-If that attribute is not found,
-.Pa /boot/gptboot
-boots from the first
-.Cm freebsd-ufs
-partition with the
+and
.Cm bootme
-attribute set.
+attributes.
If neither attribute is found,
.Pa /boot/gptboot
boots from the first
@@ -817,6 +772,10 @@ partition.
.Pa /boot/loader
.Pq the third bootstrap stage
is loaded from the first partition that matches these conditions.
+See
+.Xr gptboot 8
+for more information.
+.Pp
.Pa /boot/gptzfsboot
is used to boot from ZFS.
It searches through the GPT for
@@ -1105,7 +1064,8 @@ and
.Xr dd 1 ,
.Xr geom 4 ,
.Xr boot0cfg 8 ,
-.Xr geom 8
+.Xr geom 8 ,
+.Xr gptboot 8
.Sh HISTORY
The
.Nm
diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c
index 745e9e9..b8a81c2 100644
--- a/sbin/growfs/growfs.c
+++ b/sbin/growfs/growfs.c
@@ -141,14 +141,9 @@ growfs(int fsi, int fso, unsigned int Nflag)
uint cylno;
int i, j, width;
char tmpbuf[100];
- static int randinit = 0;
DBG_ENTER;
- if (!randinit) {
- randinit = 1;
- srandomdev();
- }
time(&modtime);
/*
@@ -407,7 +402,7 @@ initcg(int cylno, time_t modtime, int fso, unsigned int Nflag)
i += sblock.fs_frag) {
dp1 = (struct ufs1_dinode *)(void *)iobuf;
for (j = 0; j < INOPB(&sblock); j++) {
- dp1->di_gen = random();
+ dp1->di_gen = arc4random();
dp1++;
}
wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
@@ -1549,7 +1544,7 @@ main(int argc, char **argv)
printf(" from %s to %s? [Yes/No] ", oldsizebuf, newsizebuf);
fflush(stdout);
fgets(reply, (int)sizeof(reply), stdin);
- if (strcmp(reply, "Yes\n")){
+ if (strcasecmp(reply, "Yes\n")){
printf("\nNothing done\n");
exit (0);
}
diff --git a/sbin/hastctl/Makefile b/sbin/hastctl/Makefile
index e7cd9cb..02531e6 100644
--- a/sbin/hastctl/Makefile
+++ b/sbin/hastctl/Makefile
@@ -21,6 +21,7 @@ MAN= hastctl.8
NO_WFORMAT=
NO_WCAST_ALIGN=
+NO_WMISSING_VARIABLE_DECLARATIONS=
CFLAGS+=-I${.CURDIR}/../hastd
CFLAGS+=-DHAVE_CAPSICUM
CFLAGS+=-DINET
@@ -31,8 +32,8 @@ CFLAGS+=-DINET6
CFLAGS+=-DYY_NO_UNPUT
CFLAGS+=-DYY_NO_INPUT
-DPADD= ${LIBL} ${LIBUTIL}
-LDADD= -ll -lutil
+DPADD= ${LIBUTIL}
+LDADD= -lutil
.if ${MK_OPENSSL} != "no"
DPADD+= ${LIBCRYPTO}
LDADD+= -lcrypto
diff --git a/sbin/hastctl/hastctl.c b/sbin/hastctl/hastctl.c
index 883a298..11b5b8d 100644
--- a/sbin/hastctl/hastctl.c
+++ b/sbin/hastctl/hastctl.c
@@ -293,6 +293,7 @@ control_set_role(struct nv *nv, const char *newrole)
static int
control_list(struct nv *nv)
{
+ pid_t pid;
unsigned int ii;
const char *str;
int error, ret;
@@ -331,6 +332,9 @@ control_list(struct nv *nv)
str = nv_get_string(nv, "status%u", ii);
if (str != NULL)
printf(" status: %s\n", str);
+ pid = nv_get_int32(nv, "workerpid%u", ii);
+ if (pid != 0)
+ printf(" workerpid: %d\n", pid);
printf(" dirty: %ju (%NB)\n",
(uintmax_t)nv_get_uint64(nv, "dirty%u", ii),
(intmax_t)nv_get_uint64(nv, "dirty%u", ii));
@@ -504,18 +508,8 @@ main(int argc, char *argv[])
nv_add_string(nv, argv[ii + 1], "resource%d", ii);
break;
case CMD_LIST:
- /* Obtain verbose status of the given resources. */
- nv = nv_alloc();
- nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd");
- if (argc == 0)
- nv_add_string(nv, "all", "resource%d", 0);
- else {
- for (ii = 0; ii < argc; ii++)
- nv_add_string(nv, argv[ii], "resource%d", ii);
- }
- break;
case CMD_STATUS:
- /* Obtain brief status of the given resources. */
+ /* Obtain status of the given resources. */
nv = nv_alloc();
nv_add_uint8(nv, HASTCTL_CMD_STATUS, "cmd");
if (argc == 0)
diff --git a/sbin/hastd/Makefile b/sbin/hastd/Makefile
index 2a4a9ce..7ff6ee8 100644
--- a/sbin/hastd/Makefile
+++ b/sbin/hastd/Makefile
@@ -21,6 +21,7 @@ MAN= hastd.8 hast.conf.5
NO_WFORMAT=
NO_WCAST_ALIGN=
+NO_WMISSING_VARIABLE_DECLARATIONS=
CFLAGS+=-I${.CURDIR}
CFLAGS+=-DHAVE_CAPSICUM
CFLAGS+=-DPROTO_TCP_DEFAULT_PORT=8457
@@ -30,7 +31,7 @@ CFLAGS+=-DINET6
.endif
DPADD= ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} ${LIBL} ${LIBPTHREAD} ${LIBUTIL}
-LDADD= -lgeom -lbsdxml -lsbuf -ll -lpthread -lutil
+LDADD= -lgeom -lbsdxml -lsbuf -lpthread -lutil
.if ${MK_OPENSSL} != "no"
DPADD+= ${LIBCRYPTO}
LDADD+= -lcrypto
diff --git a/sbin/hastd/control.c b/sbin/hastd/control.c
index 3619fc6..922f507 100644
--- a/sbin/hastd/control.c
+++ b/sbin/hastd/control.c
@@ -271,6 +271,7 @@ control_status(struct hastd_config *cfg, struct nv *nvout,
nv_add_string(nvout, compression_name(res->hr_compression),
"compression%u", no);
nv_add_string(nvout, role2str(res->hr_role), "role%u", no);
+ nv_add_int32(nvout, res->hr_workerpid, "workerpid%u", no);
switch (res->hr_role) {
case HAST_ROLE_PRIMARY:
diff --git a/sbin/hastd/hast.h b/sbin/hastd/hast.h
index b757994..381e195 100644
--- a/sbin/hastd/hast.h
+++ b/sbin/hastd/hast.h
@@ -259,7 +259,4 @@ struct hast_resource {
struct hastd_config *yy_config_parse(const char *config, bool exitonerror);
void yy_config_free(struct hastd_config *config);
-void yyerror(const char *);
-int yylex(void);
-
#endif /* !_HAST_H_ */
diff --git a/sbin/hastd/hastd.8 b/sbin/hastd/hastd.8
index b614f36..017e895 100644
--- a/sbin/hastd/hastd.8
+++ b/sbin/hastd/hastd.8
@@ -70,18 +70,18 @@ hastd: <resource name> (<role>)
.Pp
If (and only if)
.Nm
-operates in primary role for the given resource, corresponding
+operates in primary role for the given resource, a corresponding
.Pa /dev/hast/<name>
disk-like device (GEOM provider) is created.
File systems and applications can use this provider to send I/O
requests to.
Every write, delete and flush operation
.Dv ( BIO_WRITE , BIO_DELETE , BIO_FLUSH )
-is send to local component and replicated to the remote (secondary) node if it
-is available.
+is sent to the local component and replicated on the remote (secondary) node
+if it is available.
Read operations
.Dv ( BIO_READ )
-are handled locally unless I/O error occurs or local version of the data
+are handled locally unless an I/O error occurs or the local version of the data
is not up-to-date yet (synchronization is in progress).
.Pp
The
@@ -100,38 +100,38 @@ The connection between two
.Nm
daemons is always initiated from the one running as primary to the one
running as secondary.
-When primary
+When the primary
.Nm
-is unable to connect or connection fails, it will try to re-establish
-connection every few seconds.
-Once connection is established, primary
+is unable to connect or the connection fails, it will try to re-establish
+the connection every few seconds.
+Once the connection is established, the primary
.Nm
will synchronize every extent that was modified during connection outage
to the secondary
.Nm .
.Pp
-It is possible that in case of connection outage between the nodes
+It is possible that in the case of a connection outage between the nodes the
.Nm
primary role for the given resource will be configured on both nodes.
This in turn leads to incompatible data modifications.
-Such condition is called split-brain and cannot be automatically
+Such a condition is called a split-brain and cannot be automatically
resolved by the
.Nm
-daemon as this will lead most likely to data corruption or lost of
+daemon as this will lead most likely to data corruption or loss of
important changes.
Even though it cannot be fixed by
.Nm
-itself, it will be detected and further connection between independently
+itself, it will be detected and a further connection between independently
modified nodes will not be possible.
-Once this situation is manually resolved by an administrator, resource
+Once this situation is manually resolved by an administrator, the resource
on one of the nodes can be initialized (erasing local data), which makes
-connection to the remote node possible again.
-Connection of freshly initialized component will trigger full resource
+a connection to the remote node possible again.
+Connection of the freshly initialized component will trigger full resource
synchronization.
.Pp
-The
+A
.Nm
-daemon itself never picks his role up automatically.
+daemon never picks its role automatically.
The role has to be configured with the
.Xr hastctl 8
control utility by additional software like
@@ -139,7 +139,7 @@ control utility by additional software like
or
.Nm heartbeat
that can reliably manage role separation and switch secondary node to
-primary role in case of original primary failure.
+primary role in case of the primary's failure.
.Pp
The
.Nm
diff --git a/sbin/hastd/parse.y b/sbin/hastd/parse.y
index bd0690a..6bfb537 100644
--- a/sbin/hastd/parse.y
+++ b/sbin/hastd/parse.y
@@ -75,6 +75,8 @@ static char depth1_provname[PATH_MAX];
static char depth1_localpath[PATH_MAX];
static int depth1_metaflush;
+extern void yyerror(const char *);
+extern int yylex(void);
extern void yyrestart(FILE *);
static int isitme(const char *name);
diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c
index a9dfa2b..92d1d9e 100644
--- a/sbin/hastd/primary.c
+++ b/sbin/hastd/primary.c
@@ -78,7 +78,7 @@ struct hio {
* kernel. Each component has to decrease this counter by one
* even on failure.
*/
- unsigned int hio_countdown;
+ refcnt_t hio_countdown;
/*
* Each component has a place to store its own error.
* Once the request is handled by all components we can decide if the
@@ -415,7 +415,7 @@ init_environment(struct hast_resource *res __unused)
"Unable to allocate %zu bytes of memory for hio request.",
sizeof(*hio));
}
- hio->hio_countdown = 0;
+ refcnt_init(&hio->hio_countdown, 0);
hio->hio_errors = malloc(sizeof(hio->hio_errors[0]) * ncomps);
if (hio->hio_errors == NULL) {
primary_exitx(EX_TEMPFAIL,
@@ -1300,11 +1300,12 @@ ggate_recv_thread(void *arg)
}
pjdlog_debug(2,
"ggate_recv: (%p) Moving request to the send queues.", hio);
- hio->hio_countdown = ncomps;
if (hio->hio_replication == HAST_REPLICATION_MEMSYNC &&
ggio->gctl_cmd == BIO_WRITE) {
/* Each remote request needs two responses in memsync. */
- hio->hio_countdown++;
+ refcnt_init(&hio->hio_countdown, ncomps + 1);
+ } else {
+ refcnt_init(&hio->hio_countdown, ncomps);
}
for (ii = ncomp; ii < ncomps; ii++)
QUEUE_INSERT1(hio, send, ii);
@@ -2139,7 +2140,7 @@ sync_thread(void *arg __unused)
ncomp = 1;
}
mtx_unlock(&metadata_lock);
- hio->hio_countdown = 1;
+ refcnt_init(&hio->hio_countdown, 1);
QUEUE_INSERT1(hio, send, ncomp);
/*
@@ -2189,7 +2190,7 @@ sync_thread(void *arg __unused)
pjdlog_debug(2, "sync: (%p) Moving request to the send queue.",
hio);
- hio->hio_countdown = 1;
+ refcnt_init(&hio->hio_countdown, 1);
QUEUE_INSERT1(hio, send, ncomp);
/*
diff --git a/sbin/hastd/refcnt.h b/sbin/hastd/refcnt.h
index a989df0..1246043 100644
--- a/sbin/hastd/refcnt.h
+++ b/sbin/hastd/refcnt.h
@@ -36,15 +36,24 @@
#include "pjdlog.h"
+typedef unsigned int refcnt_t;
+
+static __inline void
+refcnt_init(refcnt_t *count, unsigned int v)
+{
+
+ *count = v;
+}
+
static __inline void
-refcnt_acquire(volatile unsigned int *count)
+refcnt_acquire(refcnt_t *count)
{
atomic_add_acq_int(count, 1);
}
static __inline unsigned int
-refcnt_release(volatile unsigned int *count)
+refcnt_release(refcnt_t *count)
{
unsigned int old;
diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c
index 440061e..0e9930b 100644
--- a/sbin/hastd/subr.c
+++ b/sbin/hastd/subr.c
@@ -231,6 +231,7 @@ drop_privs(const struct hast_resource *res)
pjdlog_common(LOG_DEBUG, 1, errno,
"Unable to sandbox using capsicum");
} else if (res != NULL) {
+ cap_rights_t rights;
static const unsigned long geomcmds[] = {
DIOCGDELETE,
DIOCGFLUSH
@@ -239,8 +240,9 @@ drop_privs(const struct hast_resource *res)
PJDLOG_ASSERT(res->hr_role == HAST_ROLE_PRIMARY ||
res->hr_role == HAST_ROLE_SECONDARY);
- if (cap_rights_limit(res->hr_localfd,
- CAP_FLOCK | CAP_IOCTL | CAP_PREAD | CAP_PWRITE) == -1) {
+ cap_rights_init(&rights, CAP_FLOCK, CAP_IOCTL, CAP_PREAD,
+ CAP_PWRITE);
+ if (cap_rights_limit(res->hr_localfd, &rights) == -1) {
pjdlog_errno(LOG_ERR,
"Unable to limit capability rights on local descriptor");
}
@@ -258,7 +260,8 @@ drop_privs(const struct hast_resource *res)
G_GATE_CMD_DESTROY
};
- if (cap_rights_limit(res->hr_ggatefd, CAP_IOCTL) == -1) {
+ cap_rights_init(&rights, CAP_IOCTL);
+ if (cap_rights_limit(res->hr_ggatefd, &rights) == -1) {
pjdlog_errno(LOG_ERR,
"Unable to limit capability rights to CAP_IOCTL on ggate descriptor");
}
diff --git a/sbin/hastd/token.l b/sbin/hastd/token.l
index 38bf8d6..e8f6760 100644
--- a/sbin/hastd/token.l
+++ b/sbin/hastd/token.l
@@ -42,10 +42,14 @@ int depth;
int lineno;
#define DP do { } while (0)
+#define YY_DECL int yylex(void)
+
+extern int yylex(void);
%}
%option noinput
%option nounput
+%option noyywrap
%%
control { DP; return CONTROL; }
diff --git a/sbin/ifconfig/af_nd6.c b/sbin/ifconfig/af_nd6.c
index 5c46452..b3db0a8 100644
--- a/sbin/ifconfig/af_nd6.c
+++ b/sbin/ifconfig/af_nd6.c
@@ -148,7 +148,7 @@ nd6_status(int s)
memset(&nd, 0, sizeof(nd));
strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
- if (errno != EAFNOSUPPORT)
+ if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
warn("socket(AF_INET6, SOCK_DGRAM)");
return;
}
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 9c74980..d0d8671 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -1054,7 +1054,9 @@ can be used on a channel are defined by this setting.
Country/Region codes are specified as a 2-character abbreviation
defined by ISO 3166 or using a longer, but possibly ambiguous, spelling;
e.g., "ES" and "Spain".
-The set of country codes are taken from /etc/regdomain.xml and can also
+The set of country codes are taken from
+.Pa /etc/regdomain.xml
+and can also
be viewed with the ``list countries'' request.
Note that not all devices support changing the country code from a default
setting; typically stored in EEPROM.
@@ -1072,7 +1074,9 @@ according to a least-congested criteria.
DFS support is mandatory for some 5GHz frequencies in certain
locales (e.g., ETSI).
By default DFS is enabled according to the regulatory definitions
-specified in /etc/regdomain.xml and the current country code, regdomain,
+specified in
+.Pa /etc/regdomain.xml
+and the current country code, regdomain,
and channel.
Note the underlying device (and driver) must support radar detection
for full DFS support to work.
@@ -1578,7 +1582,9 @@ for operation.
In particular the set of available channels, how the wireless device
will operation on the channels, and the maximum transmit power that
can be used on a channel are defined by this setting.
-Regdomain codes (SKU's) are taken from /etc/regdomain.xml and can also
+Regdomain codes (SKU's) are taken from
+.Pa /etc/regdomain.xml
+and can also
be viewed with the ``list countries'' request.
Note that not all devices support changing the regdomain from a default
setting; typically stored in EEPROM.
diff --git a/sbin/ifconfig/iflagg.c b/sbin/ifconfig/iflagg.c
index a474729..29b8574 100644
--- a/sbin/ifconfig/iflagg.c
+++ b/sbin/ifconfig/iflagg.c
@@ -98,10 +98,8 @@ setlagghash(const char *val, int d, int s, const struct afswtch *afp)
rf.rf_flags |= LAGG_F_HASHL3;
else if (strcmp(tok, "l4") == 0)
rf.rf_flags |= LAGG_F_HASHL4;
- else {
- free(str);
+ else
errx(1, "Invalid lagghash option: %s", tok);
- }
}
free(str);
if (rf.rf_flags == 0)
diff --git a/sbin/init/init.c b/sbin/init/init.c
index c19b070..99041c9 100644
--- a/sbin/init/init.c
+++ b/sbin/init/init.c
@@ -1729,7 +1729,8 @@ setprocresources(const char *cname)
login_cap_t *lc;
if ((lc = login_getclassbyname(cname, NULL)) != NULL) {
setusercontext(lc, (struct passwd*)NULL, 0,
- LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
+ LOGIN_SETPRIORITY | LOGIN_SETRESOURCES |
+ LOGIN_SETLOGINCLASS | LOGIN_SETCPUMASK);
login_close(lc);
}
}
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 2047385..65fa334 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -3049,16 +3049,6 @@ option could be used to (re)mark user traffic,
by adding the following to the appropriate place in ruleset:
.Pp
.Dl "ipfw add setdscp be ip from any to any dscp af11,af21"
-.Pp
-This rule drops all incoming packets that appear to be coming from another
-directly connected system but on the wrong interface.
-For example, a packet with a source address of
-.Li 192.168.0.0/24 ,
-configured on
-.Li fxp0 ,
-but coming in on
-.Li fxp1
-would be dropped.
.Ss DYNAMIC RULES
In order to protect a site from flood attacks involving fake
TCP packets, it is safer to use dynamic rules:
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 5b37995..577d644 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -2779,13 +2779,19 @@ static ipfw_insn *
add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
{
struct in6_addr a;
- char *host, *ch;
+ char *host, *ch, buf[INET6_ADDRSTRLEN];
ipfw_insn *ret = NULL;
-
- if ((host = strdup(av)) == NULL)
- return NULL;
- if ((ch = strrchr(host, '/')) != NULL)
- *ch = '\0';
+ int len;
+
+ /* Copy first address in set if needed */
+ if ((ch = strpbrk(av, "/,")) != NULL) {
+ len = ch - av;
+ strlcpy(buf, av, sizeof(buf));
+ if (len < sizeof(buf))
+ buf[len] = '\0';
+ host = buf;
+ } else
+ host = av;
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
inet_pton(AF_INET6, host, &a) == 1)
@@ -2797,7 +2803,6 @@ add_src(ipfw_insn *cmd, char *av, u_char proto, int cblen)
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
- free(host);
return ret;
}
@@ -2805,13 +2810,19 @@ static ipfw_insn *
add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
{
struct in6_addr a;
- char *host, *ch;
+ char *host, *ch, buf[INET6_ADDRSTRLEN];
ipfw_insn *ret = NULL;
-
- if ((host = strdup(av)) == NULL)
- return NULL;
- if ((ch = strrchr(host, '/')) != NULL)
- *ch = '\0';
+ int len;
+
+ /* Copy first address in set if needed */
+ if ((ch = strpbrk(av, "/,")) != NULL) {
+ len = ch - av;
+ strlcpy(buf, av, sizeof(buf));
+ if (len < sizeof(buf))
+ buf[len] = '\0';
+ host = buf;
+ } else
+ host = av;
if (proto == IPPROTO_IPV6 || strcmp(av, "me6") == 0 ||
inet_pton(AF_INET6, host, &a) == 1)
@@ -2823,7 +2834,6 @@ add_dst(ipfw_insn *cmd, char *av, u_char proto, int cblen)
if (ret == NULL && strcmp(av, "any") != 0)
ret = cmd;
- free(host);
return ret;
}
diff --git a/sbin/iscontrol/auth_subr.c b/sbin/iscontrol/auth_subr.c
index 375d06d..5f82929 100644
--- a/sbin/iscontrol/auth_subr.c
+++ b/sbin/iscontrol/auth_subr.c
@@ -40,9 +40,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-#if __FreeBSD_version < 500000
-#include <sys/time.h>
-#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
@@ -52,7 +49,7 @@ __FBSDID("$FreeBSD$");
#include <md5.h>
#include <sha.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static int
diff --git a/sbin/iscontrol/config.c b/sbin/iscontrol/config.c
index 6307f66..e8fd309 100644
--- a/sbin/iscontrol/config.c
+++ b/sbin/iscontrol/config.c
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD$");
#include <ctype.h>
#include <camlib.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
/*
diff --git a/sbin/iscontrol/fsm.c b/sbin/iscontrol/fsm.c
index b74daa0..a4660bb 100644
--- a/sbin/iscontrol/fsm.c
+++ b/sbin/iscontrol/fsm.c
@@ -40,9 +40,6 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-#if __FreeBSD_version < 500000
-#include <sys/time.h>
-#endif
#include <sys/ioctl.h>
#include <netdb.h>
#include <stdlib.h>
@@ -56,7 +53,7 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <camlib.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
typedef enum {
diff --git a/sbin/iscontrol/iscontrol.c b/sbin/iscontrol/iscontrol.c
index c6ce21c..2e8f2ea 100644
--- a/sbin/iscontrol/iscontrol.c
+++ b/sbin/iscontrol/iscontrol.c
@@ -55,7 +55,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <camlib.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static char version[] = "2.3.1"; // keep in sync with iscsi_initiator
diff --git a/sbin/iscontrol/iscsi.conf.5 b/sbin/iscontrol/iscsi.conf.5
index 1e2c7f0..e6a776d 100644
--- a/sbin/iscontrol/iscsi.conf.5
+++ b/sbin/iscontrol/iscsi.conf.5
@@ -173,7 +173,9 @@ same as the none
counterpart, but to authenticate the target.
.El
.Sh FILES
-.Pa /etc/iscsi.conf
+.Bl -tag -width indent
+.It Pa /etc/iscsi.conf
+.El
.Sh EXAMPLES
.Bd -literal
#
diff --git a/sbin/iscontrol/login.c b/sbin/iscontrol/login.c
index e2a9e5f..92bbc64b 100644
--- a/sbin/iscontrol/login.c
+++ b/sbin/iscontrol/login.c
@@ -39,15 +39,12 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-#if __FreeBSD_version < 500000
-#include <sys/time.h>
-#endif
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static char *status_class1[] = {
diff --git a/sbin/iscontrol/misc.c b/sbin/iscontrol/misc.c
index 1c7a1ad..b6fe6df 100644
--- a/sbin/iscontrol/misc.c
+++ b/sbin/iscontrol/misc.c
@@ -40,14 +40,11 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
-#if __FreeBSD_version < 500000
-#include <sys/time.h>
-#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static inline char
diff --git a/sbin/iscontrol/pdu.c b/sbin/iscontrol/pdu.c
index c4d3a2a..7ce90ea 100644
--- a/sbin/iscontrol/pdu.c
+++ b/sbin/iscontrol/pdu.c
@@ -43,7 +43,7 @@ __FBSDID("$FreeBSD$");
#include <stdarg.h>
#include <camlib.h>
-#include <dev/iscsi/initiator/iscsi.h>
+#include <dev/iscsi_initiator/iscsi.h>
#include "iscontrol.h"
static void pukeText(char *it, pdu_t *pp);
diff --git a/sbin/md5/Makefile b/sbin/md5/Makefile
index c3c5a9f..eabf129 100644
--- a/sbin/md5/Makefile
+++ b/sbin/md5/Makefile
@@ -13,6 +13,7 @@ MLINKS= md5.1 rmd160.1 \
md5.1 sha256.1 \
md5.1 sha512.1
+NO_WMISSING_VARIABLE_DECLARATIONS=
WFORMAT?= 1
DPADD= ${LIBMD}
diff --git a/sbin/mdconfig/mdconfig.8 b/sbin/mdconfig/mdconfig.8
index c18027c..9e30896 100644
--- a/sbin/mdconfig/mdconfig.8
+++ b/sbin/mdconfig/mdconfig.8
@@ -41,7 +41,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 3, 2012
+.Dd June 20, 2013
.Dt MDCONFIG 8
.Os
.Sh NAME
@@ -72,6 +72,7 @@
.Fl l
.Op Fl n
.Op Fl v
+.Op Fl f Ar file
.Op Fl u Ar unit
.Nm
.Ar file
@@ -131,6 +132,19 @@ List configured devices.
If given with
.Fl u ,
display details about that particular device.
+If given with
+.Fl f Ar file ,
+display
+.Xr md 4
+device names of which
+.Ar file
+is used as the backing store.
+If both of
+.Fl u
+and
+.Fl f
+options are specified,
+display devices which match the two conditions.
If the
.Fl v
option is specified, show all details.
diff --git a/sbin/mdconfig/mdconfig.c b/sbin/mdconfig/mdconfig.c
index 70cefe9..233058d 100644
--- a/sbin/mdconfig/mdconfig.c
+++ b/sbin/mdconfig/mdconfig.c
@@ -47,6 +47,7 @@
#include <inttypes.h>
#include <libgeom.h>
#include <libutil.h>
+#include <paths.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
@@ -59,9 +60,9 @@ static int nflag;
static void usage(void);
static void md_set_file(const char *);
-static int md_find(char *, const char *);
-static int md_query(char *name);
-static int md_list(char *units, int opt);
+static int md_find(const char *, const char *);
+static int md_query(const char *, const int, const char *);
+static int md_list(const char *, int, const char *);
static char *geom_config_get(struct gconf *g, const char *name);
static void md_prthumanval(char *length);
@@ -82,7 +83,7 @@ usage(void)
" [-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 -l [-v] [-n] [-f file] [-u unit]\n"
" mdconfig file\n");
fprintf(stderr, "\t\ttype = {malloc, vnode, swap}\n");
fprintf(stderr, "\t\toption = {cluster, compress, reserve}\n");
@@ -160,7 +161,9 @@ main(int argc, char **argv)
case 'f':
if (fflag != NULL)
errx(1, "-f can be passed only once");
- fflag = optarg;
+ fflag = realpath(optarg, NULL);
+ if (fflag == NULL)
+ err(1, "realpath");
break;
case 'o':
if (!strcmp(optarg, "async"))
@@ -215,8 +218,8 @@ main(int argc, char **argv)
errx(1, "unknown suffix on -s argument");
break;
case 'u':
- if (!strncmp(optarg, "/dev/", 5))
- optarg += 5;
+ if (!strncmp(optarg, _PATH_DEV, sizeof(_PATH_DEV) - 1))
+ optarg += sizeof(_PATH_DEV) - 1;
if (!strncmp(optarg, MD_NAME, sizeof(MD_NAME) - 1))
optarg += sizeof(MD_NAME) - 1;
uflag = optarg;
@@ -298,8 +301,8 @@ main(int argc, char **argv)
errx(1, "-x can only be used with -a");
if (mdio.md_fwheads != 0)
errx(1, "-y can only be used with -a");
- if (fflag != NULL)
- errx(1, "-f can only be used with -a");
+ if (fflag != NULL && action != LIST)
+ errx(1, "-f can only be used with -a and -l");
if (tflag != NULL)
errx(1, "-t can only be used with -a");
if (argc > 0)
@@ -333,14 +336,14 @@ main(int argc, char **argv)
if (!kld_isloaded("g_md") && kld_load("geom_md") == -1)
err(1, "failed to load geom_md module");
- fd = open("/dev/" MDCTL_NAME, O_RDWR, 0);
+ fd = open(_PATH_DEV MDCTL_NAME, O_RDWR, 0);
if (fd < 0)
- err(1, "open(/dev/%s)", MDCTL_NAME);
+ err(1, "open(%s%s)", _PATH_DEV, MDCTL_NAME);
if (action == ATTACH) {
i = ioctl(fd, MDIOCATTACH, &mdio);
if (i < 0)
- err(1, "ioctl(/dev/%s)", MDCTL_NAME);
+ err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
if (mdio.md_options & MD_AUTOUNIT)
printf("%s%d\n", nflag ? "" : MD_NAME, mdio.md_unit);
} else if (action == DETACH) {
@@ -348,22 +351,22 @@ main(int argc, char **argv)
errx(1, "-d requires -u");
i = ioctl(fd, MDIOCDETACH, &mdio);
if (i < 0)
- err(1, "ioctl(/dev/%s)", MDCTL_NAME);
+ err(1, "ioctl(%s%s)", _PATH_DEV, 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);
+ err(1, "ioctl(%s%s)", _PATH_DEV, MDCTL_NAME);
} else if (action == LIST) {
if (mdio.md_options & MD_AUTOUNIT) {
/*
* Listing all devices. This is why we pass NULL
* together with OPT_LIST.
*/
- md_list(NULL, OPT_LIST | vflag);
+ return (md_list(NULL, OPT_LIST | vflag, fflag));
} else
- return (md_query(uflag));
+ return (md_query(uflag, vflag, fflag));
} else
usage();
close(fd);
@@ -397,7 +400,7 @@ md_set_file(const char *fn)
* between list and query mode.
*/
static int
-md_list(char *units, int opt)
+md_list(const char *units, int opt, const char *fflag)
{
struct gmesh gm;
struct gprovider *pp;
@@ -407,7 +410,7 @@ md_list(char *units, int opt)
struct ggeom *gg;
struct gclass *gcl;
void *sq;
- int retcode, found;
+ int retcode, ffound, ufound;
char *type, *file, *length;
type = file = length = NULL;
@@ -422,7 +425,7 @@ md_list(char *units, int opt)
if (sq == NULL)
return (-1);
- found = 0;
+ ffound = ufound = 0;
while ((gsp = geom_stats_snapshot_next(sq)) != NULL) {
gid = geom_lookupid(&gm, gsp->id);
if (gid == NULL)
@@ -438,18 +441,26 @@ md_list(char *units, int opt)
if (retcode != 1)
continue;
else
- found = 1;
+ ufound = 1;
}
gc = &pp->lg_config;
- if (nflag && strncmp(pp->lg_name, "md", 2) == 0)
+ type = geom_config_get(gc, "type");
+ if (strcmp(type, "vnode") == 0) {
+ file = geom_config_get(gc, "file");
+ if (fflag != NULL &&
+ strcmp(fflag, file) != 0)
+ continue;
+ else
+ ffound = 1;
+ } else if (fflag != NULL)
+ continue;
+ if (nflag && strncmp(pp->lg_name, MD_NAME, 2) == 0)
printf("%s", pp->lg_name + 2);
else
printf("%s", pp->lg_name);
- if (opt & OPT_VERBOSE || opt & OPT_UNIT) {
- type = geom_config_get(gc, "type");
- if (strcmp(type, "vnode") == 0)
- file = geom_config_get(gc, "file");
+ if (opt & OPT_VERBOSE ||
+ ((opt & OPT_UNIT) && fflag == NULL)) {
length = geom_config_get(gc, "length");
printf("\t%s\t", type);
if (length != NULL)
@@ -470,7 +481,9 @@ md_list(char *units, int opt)
printf("\n");
/* XXX: Check if it's enough to clean everything. */
geom_stats_snapshot_free(sq);
- if ((opt & OPT_UNIT) && found)
+ if (((opt & OPT_UNIT) && (fflag == NULL) && ufound) ||
+ ((opt & OPT_UNIT) == 0 && (fflag != NULL) && ffound) ||
+ ((opt & OPT_UNIT) && (fflag != NULL) && ufound && ffound))
return (0);
else
return (-1);
@@ -497,10 +510,10 @@ geom_config_get(struct gconf *g, const char *name)
* otherwise.
*/
static int
-md_find(char *list, const char *name)
+md_find(const char *list, const char *name)
{
int ret;
- char num[16];
+ char num[PATH_MAX];
char *ptr, *p, *u;
ret = 0;
@@ -508,10 +521,10 @@ md_find(char *list, const char *name)
if (ptr == NULL)
return (-1);
for (p = ptr; (u = strsep(&p, ",")) != NULL;) {
- if (strncmp(u, "/dev/", 5) == 0)
- u += 5;
+ if (strncmp(u, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
+ u += sizeof(_PATH_DEV) - 1;
/* Just in case user specified number instead of full name */
- snprintf(num, sizeof(num), "md%s", u);
+ snprintf(num, sizeof(num), "%s%s", MD_NAME, u);
if (strcmp(u, name) == 0 || strcmp(num, name) == 0) {
ret = 1;
break;
@@ -538,8 +551,8 @@ md_prthumanval(char *length)
}
static int
-md_query(char *name)
+md_query(const char *name, const int opt, const char *fflag)
{
- return (md_list(name, OPT_UNIT));
+ return (md_list(name, opt | OPT_UNIT, fflag));
}
diff --git a/sbin/mount/Makefile b/sbin/mount/Makefile
index 8f6299a..c4d98f0 100644
--- a/sbin/mount/Makefile
+++ b/sbin/mount/Makefile
@@ -3,7 +3,7 @@
PROG= mount
SRCS= mount.c mount_fs.c getmntopts.c vfslist.c
-MAN= mount.8
+MAN= mount.8 mount.conf.8
# We do NOT install the getmntopts.3 man page.
DPADD= ${LIBUTIL}
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index 6bc4b5c..50c5a8b 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" @(#)mount.8 8.8 (Berkeley) 6/16/94
.\" $FreeBSD$
.\"
-.Dd July 12, 2012
+.Dd June 6, 2011
.Dt MOUNT 8
.Os
.Sh NAME
@@ -106,11 +106,21 @@ a file system mount status from read-write to read-only.
Also
forces the R/W mount of an unclean file system (dangerous; use with
caution).
+.It Fl L
+When used in conjunction with the
+.Fl a
+option, mount
+.Em only
+those file systems which are marked as
+.Dq Li late .
.It Fl l
When used in conjunction with the
.Fl a
option, also mount those file systems which are marked as
.Dq Li late .
+.It Fl n
+For compatibility with some other implementations, this flag is
+currently a no-op.
.It Fl o
Options are specified with a
.Fl o
@@ -145,11 +155,6 @@ When used with the
.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,6 +453,7 @@ However, for the following file system types:
.Cm nfs ,
.Cm nullfs ,
.Cm oldnfs ,
+.Cm smbfs ,
.Cm udf ,
and
.Cm unionfs .
@@ -542,6 +548,7 @@ support for a particular file system might be provided either on a static
.Xr mount_msdosfs 8 ,
.Xr mount_nfs 8 ,
.Xr mount_nullfs 8 ,
+.Xr mount_smbfs 8 ,
.Xr mount_udf 8 ,
.Xr mount_unionfs 8 ,
.Xr umount 8 ,
diff --git a/sbin/mount/mount.c b/sbin/mount/mount.c
index 1984eac..91c7d7c 100644
--- a/sbin/mount/mount.c
+++ b/sbin/mount/mount.c
@@ -143,7 +143,7 @@ use_mountprog(const char *vfstype)
unsigned int i;
const char *fs[] = {
"cd9660", "mfs", "msdosfs", "nfs",
- "nullfs", "oldnfs", "udf", "unionfs",
+ "nullfs", "oldnfs", "smbfs", "udf", "unionfs",
NULL
};
@@ -245,14 +245,15 @@ main(int argc, char *argv[])
struct fstab *fs;
struct statfs *mntbuf;
int all, ch, i, init_flags, late, failok, mntsize, rval, have_fstab, ro;
+ int onlylate;
char *cp, *ep, *options;
- all = init_flags = late = 0;
+ all = init_flags = late = onlylate = 0;
ro = 0;
options = NULL;
vfslist = NULL;
vfstype = "ufs";
- while ((ch = getopt(argc, argv, "adF:flo:prt:uvw")) != -1)
+ while ((ch = getopt(argc, argv, "adF:fLlno:prt:uvw")) != -1)
switch (ch) {
case 'a':
all = 1;
@@ -266,9 +267,16 @@ main(int argc, char *argv[])
case 'f':
init_flags |= MNT_FORCE;
break;
+ case 'L':
+ onlylate = 1;
+ late = 1;
+ break;
case 'l':
late = 1;
break;
+ case 'n':
+ /* For compatibility with the Linux version of mount. */
+ break;
case 'o':
if (*optarg) {
options = catopt(options, optarg);
@@ -327,6 +335,8 @@ main(int argc, char *argv[])
continue;
if (hasopt(fs->fs_mntops, "noauto"))
continue;
+ if (!hasopt(fs->fs_mntops, "late") && onlylate)
+ continue;
if (hasopt(fs->fs_mntops, "late") && !late)
continue;
if (hasopt(fs->fs_mntops, "failok"))
diff --git a/sbin/mount/mount.conf.8 b/sbin/mount/mount.conf.8
new file mode 100644
index 0000000..c3296c3
--- /dev/null
+++ b/sbin/mount/mount.conf.8
@@ -0,0 +1,252 @@
+.\" Copyright (c) 2013 Marcel Moolenaar
+.\" Copyright (c) 2013 Craig Rodrigues
+.\" 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 AUTHORS 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 AUTHORS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.\"
+.Dd July 7, 2013
+.Dt MOUNT.CONF 8
+.Os
+.Sh NAME
+.Nm mount.conf
+.Nd root file system mount configuration file
+.Sh SYNOPSIS
+.Pa /.mount.conf
+.Sh DESCRIPTION
+During the bootup process, the
+.Fx
+kernel will try to mount the root file system
+using the logic in the
+.Fn vfs_mountroot
+function in
+.Pa src/sys/kern/vfs_mountroot.c .
+The root mount logic can be described as follows:
+.Bl -enum
+.It
+The kernel will synthesize in memory a config file
+with default directives for mounting
+the root file system.
+The logic for this is in
+.Fn vfs_mountroot_conf0 .
+.It
+The kernel will first mount
+.Xr devfs 8
+as the root file system.
+.It
+Next, the kernel will parse the in-memory config file created in step 1
+and try to mount the actual root file system.
+See
+.Sx FILE FORMAT
+for the format of the config file.
+.It
+When the actual root file system is mounted,
+.Xr devfs
+will be re-mounted on the
+.Pa /dev
+directory.
+.It
+If a
+.Pa /.mount.conf
+file does not exist in the root file system which was
+just mounted, the root mount logic stops here.
+.It
+If a
+.Pa /.mount.conf
+file exists in the root file system which was just mounted,
+this file will be parsed, and the kernel will use this new config
+file to try to re-mount the root file system.
+See
+.Sx FILE FORMAT
+for the format of the config file.
+.It
+If the new root file system has a
+.Pa /.mount
+directory, the old root file system will be re-mounted
+on
+.Pa /.mount .
+.It
+The root mount logic will go back to step 4.
+.El
+.Pp
+The root mount logic is recursive, and step 8 will
+be repeated as long as each new root file system
+which is mounted has a
+.Pa /.mount.conf
+file.
+.Sh FILE FORMAT
+The kernel parses each line in
+.Pa .mount.conf
+and then tries to perform the action specified on that line as soon as it is parsed.
+.Bl -tag -width "XXXXXXXXXX"
+.It Ic #
+A line beginning with a # is a comment and is ignored.
+.It Ic {FS}:{MOUNTPOINT} {OPTIONS}
+The kernel will try to mount this in an
+operation equivalent to:
+.Bd -literal -offset indent
+mount -t {FS} -o {OPTIONS} {MOUNTPOINT} /
+.Ed
+.Pp
+If this is successfully mounted,
+further lines in
+.Pa .mount.conf
+are ignored.
+If all lines in
+.Pa .mount.conf
+have been processed and no root file system has been successfully
+mounted, then the action specified by
+.Ic .onfail
+is performed.
+.It Ic .ask
+When the kernel processes this line, a
+.Li mountroot>
+command-line prompt is displayed.
+At this prompt, the operator can enter the
+the root mount.
+.It Ic .md Ar file
+Create a memory backed
+.Xr md 4
+virtual disk, using
+.Ar file
+as the backing store.
+.It Ic .onfail Ar [panic|reboot|retry|continue]
+If after parsing all the lines in
+.Pa .mount.conf
+the kernel is unable to mount a root file system,
+the
+.Ic .onfail
+directive tells the kernel what action to perform.
+.It Ic .timeout Ar N
+Before trying to mount a root file system,
+if the root mount device does not exist, wait at most
+.Ar N
+seconds for the device to appear before trying to mount it.
+If
+.Ic .timeout
+is not specified, the default timeout is 3 seconds.
+.El
+.Sh EXAMPLES
+The following example
+.Pa .mount.conf
+will direct the kernel to try mounting the root file system
+first as an ISO CD9660 file system on
+.Pa /dev/cd0 ,
+then if that does not work, as an ISO CD9660 file system on
+.Pa /dev/acd0 ,
+and then if that does not work, as a UFS file system on
+.Pa /dev/ada0s1a .
+If that does not work, a
+.Li mountroot>
+command-line prompt will be displayed where the operator
+can manually enter the root file system to mount.
+Finally if that does not work, the kernel will panic.
+.Bd -literal -offset indent
+.Li .onfail panic
+.Li .timeout 3
+cd9660:/dev/cd0 ro
+.Li .timeout 0
+cd9660:/dev/acd0 ro
+.Li .timeout 3
+ufs:/dev/ada0s1a
+.Li .ask
+.Ed
+.Pp
+The following example
+.Pa .mount.conf
+will direct the kernel to create a
+.Xr md 4
+memory disk attached to the file
+.Pa /data/OS-1.0.iso
+and then mount the ISO CD9660 file system
+on the md device which was just created.
+The last line is a comment which is ignored.
+.Bd -literal -offset indent
+.Li .timeout 3
+.Li .md /data/OS-1.0.iso
+.Li cd9600:/dev/md# ro
+.Li # Can also use cd9660:/dev/md0 ro
+.Ed
+.Pp
+The following example
+.Pa .mount.conf
+will direct the kernel to create a
+.Xr md 4
+memory disk attached to the file
+.Pa /data/base.ufs.uzip
+and then mount the UFS file system
+on the md uzip device which was just created
+by the
+.Xr geom_uzip 4
+driver.
+.Bd -literal -offset indent
+.Li .md /data/base.ufs.uzip
+.Li ufs:/dev/md#.uzip ro
+.Li # Can also use ufs:/dev/md0.uzip ro
+.Ed
+.Pp
+The following example
+.Pa .mount.conf
+will direct the kernel to do a unionfs
+mount on a directory
+.Pa /jail/freebsd-8-stable
+which has a
+.Xr chroot 2
+environment.
+.Bd -literal -offset indent
+.Li .timeout 3
+.Li unionfs:/jail/freebsd-8-stable
+.Ed
+.Sh NOTES
+For each root file system which is mounted, a
+.Pa /dev
+directory
+.Em must
+exist so that the root mount logic can properly re-mount
+.Xr devfs 8 .
+If this directory does not exist, the system
+may hang during the bootup process.
+.Sh SEE ALSO
+.Xr nmount 2 ,
+.Xr md 4 ,
+.Xr boot.config 5 ,
+.Xr fstab 5 ,
+.Xr boot 8 ,
+.Xr loader 8 ,
+.Xr mount 8
+.Sh HISTORY
+The
+.Nm
+file first appeared in
+.Fx 9.0 .
+.Sh AUTHORS
+.An -nosplit
+The root mount logic in the
+.Fx
+kernel which parses
+.Pa /.mount.conf
+was written by
+.An Marcel Moolenaar Aq marcel@FreeBSD.org .
+This man page was written by
+.An Craig Rodrigues Aq rodrigc@FreeBSD.org .
diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index 26ed091..216b248 100644
--- a/sbin/mount_nfs/mount_nfs.8
+++ b/sbin/mount_nfs/mount_nfs.8
@@ -28,7 +28,7 @@
.\" @(#)mount_nfs.8 8.3 (Berkeley) 3/29/95
.\" $FreeBSD$
.\"
-.Dd December 9, 2012
+.Dd July 8, 2013
.Dt MOUNT_NFS 8
.Os
.Sh NAME
@@ -118,6 +118,13 @@ for regular files, and 30 -> 60 seconds for directories.
The algorithm to calculate the timeout is based on the age of the file.
The older the file,
the longer the cache is considered valid, subject to the limits above.
+.It Cm allgssname
+This option can be used along with
+.Fl o Cm gssname
+to specify that all operations should use the host-based initiator
+credential.
+This may be used for clients that run system daemons that need to
+access files on the NFSv4 mounted volume.
.It Cm bg
If an initial attempt to contact the server fails, fork off a child to keep
trying the mount in the background.
@@ -138,6 +145,23 @@ short.
.It Cm fg
Same as not specifying
.Cm bg .
+.It Cm gssname Ns = Ns Aq Ar service-principal-name
+This option can be used with the KerberosV security flavors for NFSv4 mounts
+to specify the
+.Dq "service-principal-name"
+of a host-based entry in the default
+keytab file that is used for system operations.
+It allows the mount to be performed by
+.Dq "root"
+and avoids problems with
+cached credentials for the system operations expiring.
+The
+.Dq "service-prinicpal-name"
+should be specified without instance or domain and is typically
+.Dq "host" ,
+.Dq "nfs"
+or
+.Dq "root" .
.It Cm hard
Same as not specifying
.Cm soft .
diff --git a/sbin/newfs_nandfs/newfs_nandfs.c b/sbin/newfs_nandfs/newfs_nandfs.c
index c996674..5242318 100644
--- a/sbin/newfs_nandfs/newfs_nandfs.c
+++ b/sbin/newfs_nandfs/newfs_nandfs.c
@@ -80,15 +80,18 @@ struct file_info {
struct nandfs_inode *inode;
};
-struct file_info user_files[] =
-{
- {NANDFS_ROOT_INO, NULL, S_IFDIR | 0755, 0, 1, NULL, NULL},
+static 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};
+static struct file_info ifile =
+ { NANDFS_IFILE_INO, NULL, 0, 0, -1, NULL, NULL };
+static struct file_info sufile =
+ { NANDFS_SUFILE_INO, NULL, 0, 0, -1, NULL, NULL };
+static struct file_info cpfile =
+ { NANDFS_CPFILE_INO, NULL, 0, 0, -1, NULL, NULL };
+static struct file_info datfile =
+ { NANDFS_DAT_INO, NULL, 0, 0, -1, NULL, NULL };
struct nandfs_block {
LIST_ENTRY(nandfs_block) block_link;
@@ -97,7 +100,8 @@ struct nandfs_block {
void *data;
};
-static LIST_HEAD(, nandfs_block) block_head = LIST_HEAD_INITIALIZER(&block_head);
+static LIST_HEAD(, nandfs_block) block_head =
+ LIST_HEAD_INITIALIZER(&block_head);
/* Storage geometry */
static off_t mediasize;
@@ -106,8 +110,8 @@ static uint64_t nsegments;
static uint64_t erasesize;
static uint64_t segsize;
-struct nandfs_fsdata fsdata;
-struct nandfs_super_block super_block;
+static struct nandfs_fsdata fsdata;
+static struct nandfs_super_block super_block;
static int is_nand;
@@ -120,14 +124,13 @@ 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;
+static u_char *volumelabel = NULL;
-struct nandfs_super_root *sr;
+static struct nandfs_super_root *sr;
-uint32_t nuserfiles;
-uint32_t seg_segsum_size;
-uint32_t seg_nblocks;
-uint32_t seg_endblock;
+static uint32_t nuserfiles;
+static uint32_t seg_nblocks;
+static uint32_t seg_endblock;
#define SIZE_TO_BLOCK(size) (((size) + (blocksize - 1)) / blocksize)
diff --git a/sbin/nvmecontrol/Makefile b/sbin/nvmecontrol/Makefile
index 04cefaa..ea60da3 100644
--- a/sbin/nvmecontrol/Makefile
+++ b/sbin/nvmecontrol/Makefile
@@ -1,6 +1,10 @@
# $FreeBSD$
PROG= nvmecontrol
+SRCS= nvmecontrol.c devlist.c firmware.c identify.c logpage.c \
+ perftest.c reset.c nvme_util.c
MAN= nvmecontrol.8
+.PATH: ${.CURDIR}/../../sys/dev/nvme
+
.include <bsd.prog.mk>
diff --git a/sbin/nvmecontrol/devlist.c b/sbin/nvmecontrol/devlist.c
new file mode 100644
index 0000000..f73d643
--- /dev/null
+++ b/sbin/nvmecontrol/devlist.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$");
+
+#include <sys/param.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+devlist_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, DEVLIST_USAGE);
+ exit(1);
+}
+
+static inline uint32_t
+ns_get_sector_size(struct nvme_namespace_data *nsdata)
+{
+
+ return (1 << nsdata->lbaf[nsdata->flbas.format].lbads);
+}
+
+void
+devlist(int argc, char *argv[])
+{
+ struct nvme_controller_data cdata;
+ struct nvme_namespace_data nsdata;
+ char name[64];
+ uint8_t mn[64];
+ uint32_t i;
+ int ch, ctrlr, fd, found, ret;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch ((char)ch) {
+ default:
+ devlist_usage();
+ }
+ }
+
+ ctrlr = -1;
+ found = 0;
+
+ while (1) {
+ ctrlr++;
+ sprintf(name, "%s%d", NVME_CTRLR_PREFIX, ctrlr);
+
+ ret = open_dev(name, &fd, 0, 0);
+
+ if (ret != 0) {
+ if (ret == EACCES) {
+ warnx("could not open "_PATH_DEV"%s\n", name);
+ continue;
+ } else
+ break;
+ }
+
+ found++;
+ read_controller_data(fd, &cdata);
+ nvme_strvis(mn, cdata.mn, sizeof(mn), NVME_MODEL_NUMBER_LENGTH);
+ printf("%6s: %s\n", name, mn);
+
+ for (i = 0; i < cdata.nn; i++) {
+ sprintf(name, "%s%d%s%d", NVME_CTRLR_PREFIX, ctrlr,
+ NVME_NS_PREFIX, i+1);
+ read_namespace_data(fd, i+1, &nsdata);
+ printf(" %10s (%lldGB)\n",
+ name,
+ nsdata.nsze *
+ (long long)ns_get_sector_size(&nsdata) /
+ 1024 / 1024 / 1024);
+ }
+
+ close(fd);
+ }
+
+ if (found == 0)
+ printf("No NVMe controllers found.\n");
+
+ exit(1);
+}
diff --git a/sbin/nvmecontrol/firmware.c b/sbin/nvmecontrol/firmware.c
new file mode 100644
index 0000000..cb7fb0f
--- /dev/null
+++ b/sbin/nvmecontrol/firmware.c
@@ -0,0 +1,309 @@
+/*-
+ * Copyright (c) 2013 EMC Corp.
+ * All rights reserved.
+ *
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static int
+slot_has_valid_firmware(int fd, int slot)
+{
+ struct nvme_firmware_page fw;
+ int has_fw = false;
+
+ read_logpage(fd, NVME_LOG_FIRMWARE_SLOT,
+ NVME_GLOBAL_NAMESPACE_TAG, &fw, sizeof(fw));
+
+ if (fw.revision[slot-1] != 0LLU)
+ has_fw = true;
+
+ return (has_fw);
+}
+
+static void
+read_image_file(char *path, void **buf, int32_t *size)
+{
+ struct stat sb;
+ int32_t filesize;
+ int fd;
+
+ *size = 0;
+ *buf = NULL;
+
+ if ((fd = open(path, O_RDONLY)) < 0)
+ err(1, "unable to open '%s'", path);
+ if (fstat(fd, &sb) < 0)
+ err(1, "unable to stat '%s'", path);
+
+ /*
+ * The NVMe spec does not explicitly state a maximum firmware image
+ * size, although one can be inferred from the dword size limitation
+ * for the size and offset fields in the Firmware Image Download
+ * command.
+ *
+ * Technically, the max is UINT32_MAX * sizeof(uint32_t), since the
+ * size and offsets are specified in terms of dwords (not bytes), but
+ * realistically INT32_MAX is sufficient here and simplifies matters
+ * a bit.
+ */
+ if (sb.st_size > INT32_MAX)
+ errx(1, "size of file '%s' is too large (%jd bytes)",
+ path, (intmax_t)sb.st_size);
+ filesize = (int32_t)sb.st_size;
+ if ((*buf = malloc(filesize)) == NULL)
+ errx(1, "unable to malloc %d bytes", filesize);
+ if ((*size = read(fd, *buf, filesize)) < 0)
+ err(1, "error reading '%s'", path);
+ /* XXX assuming no short reads */
+ if (*size != filesize)
+ errx(1,
+ "error reading '%s' (read %d bytes, requested %d bytes)",
+ path, *size, filesize);
+}
+
+static void
+update_firmware(int fd, uint8_t *payload, int32_t payload_size)
+{
+ struct nvme_pt_command pt;
+ int32_t off, resid, size;
+ void *chunk;
+
+ off = 0;
+ resid = payload_size;
+
+ if ((chunk = malloc(NVME_MAX_XFER_SIZE)) == NULL)
+ errx(1, "unable to malloc %d bytes", NVME_MAX_XFER_SIZE);
+
+ while (resid > 0) {
+ size = (resid >= NVME_MAX_XFER_SIZE) ?
+ NVME_MAX_XFER_SIZE : resid;
+ memcpy(chunk, payload + off, size);
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD;
+ pt.cmd.cdw10 = (size / sizeof(uint32_t)) - 1;
+ pt.cmd.cdw11 = (off / sizeof(uint32_t));
+ pt.buf = chunk;
+ pt.len = size;
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "firmware download request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "firmware download request returned error");
+
+ resid -= size;
+ off += size;
+ }
+}
+
+static void
+activate_firmware(int fd, int slot, int activate_action)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_FIRMWARE_ACTIVATE;
+ pt.cmd.cdw10 = (activate_action << 3) | slot;
+ pt.is_read = 0;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "firmware activate request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "firmware activate request returned error");
+}
+
+static void
+firmware_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, FIRMWARE_USAGE);
+ exit(1);
+}
+
+void
+firmware(int argc, char *argv[])
+{
+ int fd = -1, slot = 0;
+ int a_flag, s_flag, f_flag;
+ char ch, *p, *image = NULL;
+ char *controller = NULL, prompt[64];
+ void *buf = NULL;
+ int32_t size = 0;
+ struct nvme_controller_data cdata;
+
+ a_flag = s_flag = f_flag = false;
+
+ while ((ch = getopt(argc, argv, "af:s:")) != -1) {
+ switch (ch) {
+ case 'a':
+ a_flag = true;
+ break;
+ case 's':
+ slot = strtol(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid slot.\n",
+ optarg);
+ firmware_usage();
+ } else if (slot == 0) {
+ fprintf(stderr,
+ "0 is not a valid slot number. "
+ "Slot numbers start at 1.\n");
+ firmware_usage();
+ } else if (slot > 7) {
+ fprintf(stderr,
+ "Slot number %s specified which is "
+ "greater than max allowed slot number of "
+ "7.\n", optarg);
+ firmware_usage();
+ }
+ s_flag = true;
+ break;
+ case 'f':
+ image = optarg;
+ f_flag = true;
+ break;
+ }
+ }
+
+ /* Check that a controller (and not a namespace) was specified. */
+ if (optind >= argc || strstr(argv[optind], NVME_NS_PREFIX) != NULL)
+ firmware_usage();
+
+ if (!f_flag && !a_flag) {
+ fprintf(stderr,
+ "Neither a replace ([-f path_to_firmware]) nor "
+ "activate ([-a]) firmware image action\n"
+ "was specified.\n");
+ firmware_usage();
+ }
+
+ if (!f_flag && a_flag && slot == 0) {
+ fprintf(stderr,
+ "Slot number to activate not specified.\n");
+ firmware_usage();
+ }
+
+ controller = argv[optind];
+ open_dev(controller, &fd, 1, 1);
+ read_controller_data(fd, &cdata);
+
+ if (cdata.oacs.firmware == 0)
+ errx(1,
+ "controller does not support firmware activate/download");
+
+ if (f_flag && slot == 1 && cdata.frmw.slot1_ro)
+ errx(1, "slot %d is marked as read only", slot);
+
+ if (slot > cdata.frmw.num_slots)
+ errx(1,
+ "slot %d specified but controller only supports %d slots",
+ slot, cdata.frmw.num_slots);
+
+ if (a_flag && !f_flag && !slot_has_valid_firmware(fd, slot))
+ errx(1,
+ "slot %d does not contain valid firmware,\n"
+ "try 'nvmecontrol logpage -p 3 %s' to get a list "
+ "of available images\n",
+ slot, controller);
+
+ if (f_flag)
+ read_image_file(image, &buf, &size);
+
+ if (f_flag && a_flag)
+ printf("You are about to download and activate "
+ "firmware image (%s) to controller %s.\n"
+ "This may damage your controller and/or "
+ "overwrite an existing firmware image.\n",
+ image, controller);
+ else if (a_flag)
+ printf("You are about to activate a new firmware "
+ "image on controller %s.\n"
+ "This may damage your controller.\n",
+ controller);
+ else if (f_flag)
+ printf("You are about to download firmware image "
+ "(%s) to controller %s.\n"
+ "This may damage your controller and/or "
+ "overwrite an existing firmware image.\n",
+ image, controller);
+
+ printf("Are you sure you want to continue? (yes/no) ");
+ while (1) {
+ fgets(prompt, sizeof(prompt), stdin);
+ if (strncasecmp(prompt, "yes", 3) == 0)
+ break;
+ if (strncasecmp(prompt, "no", 2) == 0)
+ exit(1);
+ printf("Please answer \"yes\" or \"no\". ");
+ }
+
+ if (f_flag) {
+ update_firmware(fd, buf, size);
+ if (a_flag)
+ activate_firmware(fd, slot,
+ NVME_AA_REPLACE_ACTIVATE);
+ else
+ activate_firmware(fd, slot,
+ NVME_AA_REPLACE_NO_ACTIVATE);
+ } else {
+ activate_firmware(fd, slot, NVME_AA_ACTIVATE);
+ }
+
+ if (a_flag) {
+ printf("New firmware image activated and will take "
+ "effect after next controller reset.\n"
+ "Controller reset can be initiated via "
+ "'nvmecontrol reset %s'\n",
+ controller);
+ }
+
+ close(fd);
+ exit(0);
+}
diff --git a/sbin/nvmecontrol/identify.c b/sbin/nvmecontrol/identify.c
new file mode 100644
index 0000000..58492e2
--- /dev/null
+++ b/sbin/nvmecontrol/identify.c
@@ -0,0 +1,284 @@
+/*-
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$");
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+print_controller(struct nvme_controller_data *cdata)
+{
+ uint8_t str[128];
+
+ printf("Controller Capabilities/Features\n");
+ printf("================================\n");
+ printf("Vendor ID: %04x\n", cdata->vid);
+ printf("Subsystem Vendor ID: %04x\n", cdata->ssvid);
+ nvme_strvis(str, cdata->sn, sizeof(str), NVME_SERIAL_NUMBER_LENGTH);
+ printf("Serial Number: %s\n", str);
+ nvme_strvis(str, cdata->mn, sizeof(str), NVME_MODEL_NUMBER_LENGTH);
+ printf("Model Number: %s\n", str);
+ nvme_strvis(str, cdata->fr, sizeof(str), NVME_FIRMWARE_REVISION_LENGTH);
+ printf("Firmware Version: %s\n", str);
+ printf("Recommended Arb Burst: %d\n", cdata->rab);
+ printf("IEEE OUI Identifier: %02x %02x %02x\n",
+ cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
+ printf("Multi-Interface Cap: %02x\n", cdata->mic);
+ /* TODO: Use CAP.MPSMIN to determine true memory page size. */
+ printf("Max Data Transfer Size: ");
+ if (cdata->mdts == 0)
+ printf("Unlimited\n");
+ else
+ printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
+ printf("\n");
+
+ printf("Admin Command Set Attributes\n");
+ printf("============================\n");
+ printf("Security Send/Receive: %s\n",
+ cdata->oacs.security ? "Supported" : "Not Supported");
+ printf("Format NVM: %s\n",
+ cdata->oacs.format ? "Supported" : "Not Supported");
+ printf("Firmware Activate/Download: %s\n",
+ cdata->oacs.firmware ? "Supported" : "Not Supported");
+ printf("Abort Command Limit: %d\n", cdata->acl+1);
+ printf("Async Event Request Limit: %d\n", cdata->aerl+1);
+ printf("Number of Firmware Slots: ");
+ if (cdata->oacs.firmware != 0)
+ printf("%d\n", cdata->frmw.num_slots);
+ else
+ printf("N/A\n");
+ printf("Firmware Slot 1 Read-Only: ");
+ if (cdata->oacs.firmware != 0)
+ printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
+ else
+ printf("N/A\n");
+ printf("Per-Namespace SMART Log: %s\n",
+ cdata->lpa.ns_smart ? "Yes" : "No");
+ printf("Error Log Page Entries: %d\n", cdata->elpe+1);
+ printf("Number of Power States: %d\n", cdata->npss+1);
+ printf("\n");
+
+ printf("NVM Command Set Attributes\n");
+ printf("==========================\n");
+ printf("Submission Queue Entry Size\n");
+ printf(" Max: %d\n", 1 << cdata->sqes.max);
+ printf(" Min: %d\n", 1 << cdata->sqes.min);
+ printf("Completion Queue Entry Size\n");
+ printf(" Max: %d\n", 1 << cdata->cqes.max);
+ printf(" Min: %d\n", 1 << cdata->cqes.min);
+ printf("Number of Namespaces: %d\n", cdata->nn);
+ printf("Compare Command: %s\n",
+ cdata->oncs.compare ? "Supported" : "Not Supported");
+ printf("Write Uncorrectable Command: %s\n",
+ cdata->oncs.write_unc ? "Supported" : "Not Supported");
+ printf("Dataset Management Command: %s\n",
+ cdata->oncs.dsm ? "Supported" : "Not Supported");
+ printf("Volatile Write Cache: %s\n",
+ cdata->vwc.present ? "Present" : "Not Present");
+}
+
+static void
+print_namespace(struct nvme_namespace_data *nsdata)
+{
+ uint32_t i;
+
+ printf("Size (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->nsze,
+ (long long)nsdata->nsze / 1024 / 1024);
+ printf("Capacity (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->ncap,
+ (long long)nsdata->ncap / 1024 / 1024);
+ printf("Utilization (in LBAs): %lld (%lldM)\n",
+ (long long)nsdata->nuse,
+ (long long)nsdata->nuse / 1024 / 1024);
+ printf("Thin Provisioning: %s\n",
+ nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
+ printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1);
+ printf("Current LBA Format: LBA Format #%02d\n",
+ nsdata->flbas.format);
+ for (i = 0; i <= nsdata->nlbaf; i++)
+ printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n",
+ i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
+}
+
+static void
+identify_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, IDENTIFY_USAGE);
+ exit(1);
+}
+
+static void
+identify_ctrlr(int argc, char *argv[])
+{
+ struct nvme_controller_data cdata;
+ int ch, fd, hexflag = 0, hexlength;
+ int verboseflag = 0;
+
+ while ((ch = getopt(argc, argv, "vx")) != -1) {
+ switch ((char)ch) {
+ case 'v':
+ verboseflag = 1;
+ break;
+ case 'x':
+ hexflag = 1;
+ break;
+ default:
+ identify_usage();
+ }
+ }
+
+ /* Check that a controller was specified. */
+ if (optind >= argc)
+ identify_usage();
+
+ open_dev(argv[optind], &fd, 1, 1);
+ read_controller_data(fd, &cdata);
+ close(fd);
+
+ if (hexflag == 1) {
+ if (verboseflag == 1)
+ hexlength = sizeof(struct nvme_controller_data);
+ else
+ hexlength = offsetof(struct nvme_controller_data,
+ reserved5);
+ print_hex(&cdata, hexlength);
+ exit(0);
+ }
+
+ if (verboseflag == 1) {
+ fprintf(stderr, "-v not currently supported without -x\n");
+ identify_usage();
+ }
+
+ print_controller(&cdata);
+ exit(0);
+}
+
+static void
+identify_ns(int argc, char *argv[])
+{
+ struct nvme_namespace_data nsdata;
+ char path[64];
+ int ch, fd, hexflag = 0, hexlength, nsid;
+ int verboseflag = 0;
+
+ while ((ch = getopt(argc, argv, "vx")) != -1) {
+ switch ((char)ch) {
+ case 'v':
+ verboseflag = 1;
+ break;
+ case 'x':
+ hexflag = 1;
+ break;
+ default:
+ identify_usage();
+ }
+ }
+
+ /* Check that a namespace was specified. */
+ if (optind >= argc)
+ identify_usage();
+
+ /*
+ * Check if the specified device node exists before continuing.
+ * This is a cleaner check for cases where the correct controller
+ * is specified, but an invalid namespace on that controller.
+ */
+ open_dev(argv[optind], &fd, 1, 1);
+ close(fd);
+
+ /*
+ * We send IDENTIFY commands to the controller, not the namespace,
+ * since it is an admin cmd. The namespace ID will be specified in
+ * the IDENTIFY command itself. So parse the namespace's device node
+ * string to get the controller substring and namespace ID.
+ */
+ parse_ns_str(argv[optind], path, &nsid);
+ open_dev(path, &fd, 1, 1);
+ read_namespace_data(fd, nsid, &nsdata);
+ close(fd);
+
+ if (hexflag == 1) {
+ if (verboseflag == 1)
+ hexlength = sizeof(struct nvme_namespace_data);
+ else
+ hexlength = offsetof(struct nvme_namespace_data,
+ reserved6);
+ print_hex(&nsdata, hexlength);
+ exit(0);
+ }
+
+ if (verboseflag == 1) {
+ fprintf(stderr, "-v not currently supported without -x\n");
+ identify_usage();
+ }
+
+ print_namespace(&nsdata);
+ exit(0);
+}
+
+void
+identify(int argc, char *argv[])
+{
+ char *target;
+
+ if (argc < 2)
+ identify_usage();
+
+ while (getopt(argc, argv, "vx") != -1) ;
+
+ /* Check that a controller or namespace was specified. */
+ if (optind >= argc)
+ identify_usage();
+
+ target = argv[optind];
+
+ optreset = 1;
+ optind = 1;
+
+ /*
+ * If device node contains "ns", we consider it a namespace,
+ * otherwise, consider it a controller.
+ */
+ if (strstr(target, NVME_NS_PREFIX) == NULL)
+ identify_ctrlr(argc, argv);
+ else
+ identify_ns(argc, argv);
+}
diff --git a/sbin/nvmecontrol/logpage.c b/sbin/nvmecontrol/logpage.c
new file mode 100644
index 0000000..e330988
--- /dev/null
+++ b/sbin/nvmecontrol/logpage.c
@@ -0,0 +1,357 @@
+/*-
+ * Copyright (c) 2013 EMC Corp.
+ * All rights reserved.
+ *
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+#define DEFAULT_SIZE (4096)
+#define MAX_FW_SLOTS (7)
+
+typedef void (*print_fn_t)(void *buf, uint32_t size);
+
+static void *
+get_log_buffer(uint32_t size)
+{
+ void *buf;
+
+ if ((buf = malloc(size)) == NULL)
+ errx(1, "unable to malloc %u bytes", size);
+
+ memset(buf, 0, size);
+ return (buf);
+}
+
+void
+read_logpage(int fd, uint8_t log_page, int nsid, void *payload,
+ uint32_t payload_size)
+{
+ struct nvme_pt_command pt;
+
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_GET_LOG_PAGE;
+ pt.cmd.nsid = nsid;
+ pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16;
+ pt.cmd.cdw10 |= log_page;
+ pt.buf = payload;
+ pt.len = payload_size;
+ pt.is_read = 1;
+
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "get log page request failed");
+
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "get log page request returned error");
+}
+
+static void
+print_log_error(void *buf, uint32_t size)
+{
+ int i, nentries;
+ struct nvme_error_information_entry *entry = buf;
+ struct nvme_status *status;
+
+ printf("Error Information Log\n");
+ printf("=====================\n");
+
+ if (entry->error_count == 0) {
+ printf("No error entries found\n");
+ return;
+ }
+
+ nentries = size/sizeof(struct nvme_error_information_entry);
+ for (i = 0; i < nentries; i++, entry++) {
+ if (entry->error_count == 0)
+ break;
+
+ status = &entry->status;
+ printf("Entry %02d\n", i + 1);
+ printf("=========\n");
+ printf(" Error count: %ju\n", entry->error_count);
+ printf(" Submission queue ID: %u\n", entry->sqid);
+ printf(" Command ID: %u\n", entry->cid);
+ /* TODO: Export nvme_status_string structures from kernel? */
+ printf(" Status:\n");
+ printf(" Phase tag: %d\n", status->p);
+ printf(" Status code: %d\n", status->sc);
+ printf(" Status code type: %d\n", status->sct);
+ printf(" More: %d\n", status->m);
+ printf(" DNR: %d\n", status->dnr);
+ printf(" Error location: %u\n", entry->error_location);
+ printf(" LBA: %ju\n", entry->lba);
+ printf(" Namespace ID: %u\n", entry->nsid);
+ printf(" Vendor specific info: %u\n", entry->vendor_specific);
+ }
+}
+
+static void
+print_log_health(void *buf, uint32_t size __unused)
+{
+ struct nvme_health_information_page *health = buf;
+
+ printf("SMART/Health Information Log\n");
+ printf("============================\n");
+
+ printf("Critical Warning State: 0x%02x\n",
+ health->critical_warning.raw);
+ printf(" Available spare: %d\n",
+ health->critical_warning.bits.available_spare);
+ printf(" Temperature: %d\n",
+ health->critical_warning.bits.temperature);
+ printf(" Device reliability: %d\n",
+ health->critical_warning.bits.device_reliability);
+ printf(" Read only: %d\n",
+ health->critical_warning.bits.read_only);
+ printf(" Volatile memory backup: %d\n",
+ health->critical_warning.bits.volatile_memory_backup);
+ printf("Temperature: %u K, %2.2f C, %3.2f F\n",
+ health->temperature,
+ (float)health->temperature - (float)273.15,
+ ((float)health->temperature * (float)9/5) - (float)459.67);
+ printf("Available spare: %u\n",
+ health->available_spare);
+ printf("Available spare threshold: %u\n",
+ health->available_spare_threshold);
+ printf("Percentage used: %u\n",
+ health->percentage_used);
+
+ /*
+ * TODO: These are pretty ugly in hex. Is there a library that
+ * will convert 128-bit unsigned values to decimal?
+ */
+ printf("Data units (512 byte) read: 0x%016jx%016jx\n",
+ health->data_units_read[1],
+ health->data_units_read[0]);
+ printf("Data units (512 byte) written: 0x%016jx%016jx\n",
+ health->data_units_written[1],
+ health->data_units_written[0]);
+ printf("Host read commands: 0x%016jx%016jx\n",
+ health->host_read_commands[1],
+ health->host_read_commands[0]);
+ printf("Host write commands: 0x%016jx%016jx\n",
+ health->host_write_commands[1],
+ health->host_write_commands[0]);
+ printf("Controller busy time (minutes): 0x%016jx%016jx\n",
+ health->controller_busy_time[1],
+ health->controller_busy_time[0]);
+ printf("Power cycles: 0x%016jx%016jx\n",
+ health->power_cycles[1],
+ health->power_cycles[0]);
+ printf("Power on hours: 0x%016jx%016jx\n",
+ health->power_on_hours[1],
+ health->power_on_hours[0]);
+ printf("Unsafe shutdowns: 0x%016jx%016jx\n",
+ health->unsafe_shutdowns[1],
+ health->unsafe_shutdowns[0]);
+ printf("Media errors: 0x%016jx%016jx\n",
+ health->media_errors[1],
+ health->media_errors[0]);
+ printf("No. error info log entries: 0x%016jx%016jx\n",
+ health->num_error_info_log_entries[1],
+ health->num_error_info_log_entries[0]);
+}
+
+static void
+print_log_firmware(void *buf, uint32_t size __unused)
+{
+ int i;
+ const char *status;
+ struct nvme_firmware_page *fw = buf;
+
+ printf("Firmware Slot Log\n");
+ printf("=================\n");
+
+ for (i = 0; i < MAX_FW_SLOTS; i++) {
+ printf("Slot %d: ", i + 1);
+ if (fw->afi.slot == i + 1)
+ status = " Active";
+ else
+ status = "Inactive";
+
+ if (fw->revision[i] == 0LLU)
+ printf("Empty\n");
+ else
+ if (isprint(*(char *)&fw->revision[i]))
+ printf("[%s] %.8s\n", status,
+ (char *)&fw->revision[i]);
+ else
+ printf("[%s] %016jx\n", status,
+ fw->revision[i]);
+ }
+}
+
+static struct logpage_function {
+ uint8_t log_page;
+ print_fn_t fn;
+} logfuncs[] = {
+ {NVME_LOG_ERROR, print_log_error },
+ {NVME_LOG_HEALTH_INFORMATION, print_log_health },
+ {NVME_LOG_FIRMWARE_SLOT, print_log_firmware },
+ {0, NULL },
+};
+
+static void
+logpage_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, LOGPAGE_USAGE);
+ exit(1);
+}
+
+void
+logpage(int argc, char *argv[])
+{
+ int fd, nsid;
+ int log_page = 0, pageflag = false;
+ int hexflag = false, ns_specified;
+ char ch, *p;
+ char cname[64];
+ uint32_t size;
+ void *buf;
+ struct logpage_function *f;
+ struct nvme_controller_data cdata;
+ print_fn_t print_fn;
+
+ while ((ch = getopt(argc, argv, "p:x")) != -1) {
+ switch (ch) {
+ case 'p':
+ /* TODO: Add human-readable ASCII page IDs */
+ log_page = strtol(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid log page id.\n",
+ optarg);
+ logpage_usage();
+ /* TODO: Define valid log page id ranges in nvme.h? */
+ } else if (log_page == 0 ||
+ (log_page >= 0x04 && log_page <= 0x7F) ||
+ (log_page >= 0x80 && log_page <= 0xBF)) {
+ fprintf(stderr,
+ "\"%s\" not valid log page id.\n",
+ optarg);
+ logpage_usage();
+ }
+ pageflag = true;
+ break;
+ case 'x':
+ hexflag = true;
+ break;
+ }
+ }
+
+ if (!pageflag) {
+ printf("Missing page_id (-p).\n");
+ logpage_usage();
+ }
+
+ /* Check that a controller and/or namespace was specified. */
+ if (optind >= argc)
+ logpage_usage();
+
+ if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) {
+ ns_specified = true;
+ parse_ns_str(argv[optind], cname, &nsid);
+ open_dev(cname, &fd, 1, 1);
+ } else {
+ ns_specified = false;
+ nsid = NVME_GLOBAL_NAMESPACE_TAG;
+ open_dev(argv[optind], &fd, 1, 1);
+ }
+
+ /*
+ * The log page attribtues indicate whether or not the controller
+ * supports the SMART/Health information log page on a per
+ * namespace basis.
+ */
+ if (ns_specified) {
+ if (log_page != NVME_LOG_HEALTH_INFORMATION)
+ errx(1, "log page %d valid only at controller level",
+ log_page);
+ read_controller_data(fd, &cdata);
+ if (cdata.lpa.ns_smart == 0)
+ errx(1,
+ "controller does not support per namespace "
+ "smart/health information");
+ }
+
+ print_fn = print_hex;
+ if (!hexflag) {
+ /*
+ * See if there is a pretty print function for the
+ * specified log page. If one isn't found, we
+ * just revert to the default (print_hex).
+ */
+ f = logfuncs;
+ while (f->log_page > 0) {
+ if (log_page == f->log_page) {
+ print_fn = f->fn;
+ break;
+ }
+ f++;
+ }
+ }
+
+ /* Read the log page */
+ switch (log_page) {
+ case NVME_LOG_ERROR:
+ size = sizeof(struct nvme_error_information_entry);
+ size *= (cdata.elpe + 1);
+ break;
+ case NVME_LOG_HEALTH_INFORMATION:
+ size = sizeof(struct nvme_health_information_page);
+ break;
+ case NVME_LOG_FIRMWARE_SLOT:
+ size = sizeof(struct nvme_firmware_page);
+ break;
+ default:
+ size = DEFAULT_SIZE;
+ break;
+ }
+
+ buf = get_log_buffer(size);
+ read_logpage(fd, log_page, nsid, buf, size);
+ print_fn(buf, size);
+
+ close(fd);
+ exit(0);
+}
diff --git a/sbin/nvmecontrol/nvmecontrol.8 b/sbin/nvmecontrol/nvmecontrol.8
index 7e26240..010f106 100644
--- a/sbin/nvmecontrol/nvmecontrol.8
+++ b/sbin/nvmecontrol/nvmecontrol.8
@@ -58,6 +58,18 @@
.Nm
.Ic reset
.Aq controller id
+.Nm
+.Ic logpage
+.Aq Fl p Ar page_id
+.Op Fl x
+.Aq device id
+.Aq namespace id
+.Nm
+.Ic firmware
+.Op Fl s Ar slot
+.Op Fl f Ar path_to_firmware
+.Op Fl a
+.Aq device id
.Sh DESCRIPTION
NVM Express (NVMe) is a storage protocol standard, for SSDs and other
high-speed storage devices over PCI Express.
@@ -84,6 +96,30 @@ stdout when 30 seconds expires.
.Dl nvmecontrol reset nvme0
.Pp
Perform a controller-level reset of the nvme0 controller.
+.Pp
+.Dl nvmecontrol logpage -p 1 nvme0
+.Pp
+Display a human-readable summary of the nvme0 controller's Error Information Log.
+Log pages defined by the NVMe specification include Error Information Log (ID=1),
+SMART/Health Information Log (ID=2), and Firmware Slot Log (ID=3).
+.Pp
+.Dl nvmecontrol logpage -p 1 -x nvme0
+.Pp
+Display a hexidecimal dump of the nvme0 controller's Error Information Log.
+.Pp
+.Dl nvmecontrol firmware -s 2 -f /tmp/nvme_firmware nvme0
+.Pp
+Download the firmware image contained in "/tmp/nvme_firmware" to slot 2 of the
+nvme0 controller, but do not activate the image.
+.Pp
+.Dl nvmecontrol firmware -s 4 -a nvme0
+.Pp
+Activate the firmware in slot 4 of the nvme0 controller on the next reset.
+.Pp
+.Dl nvmecontrol firmware -s 7 -f /tmp/nvme_firmware -a nvme0
+.Pp
+Download the firmware image contained in "/tmp/nvme_firmware" to slot 7 of the
+nvme0 controller and activate it on the next reset.
.Sh AUTHORS
.An -nosplit
.Nm
diff --git a/sbin/nvmecontrol/nvmecontrol.c b/sbin/nvmecontrol/nvmecontrol.c
index cbb365b..4dee190 100644
--- a/sbin/nvmecontrol/nvmecontrol.c
+++ b/sbin/nvmecontrol/nvmecontrol.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012-2013 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,140 +31,77 @@ __FBSDID("$FreeBSD$");
#include <sys/ioccom.h>
#include <sys/stat.h>
-#include <dev/nvme/nvme.h>
-
#include <ctype.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <paths.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <unistd.h>
-#define DEVLIST_USAGE \
-" nvmecontrol devlist\n"
-
-#define IDENTIFY_USAGE \
-" nvmecontrol identify <controller id|namespace id>\n"
-
-#define PERFTEST_USAGE \
-" nvmecontrol perftest <-n num_threads> <-o read|write>\n" \
-" <-s size_in_bytes> <-t time_in_seconds>\n" \
-" <-i intr|wait> [-f refthread] [-p]\n" \
-" <namespace id>\n"
+#include "nvmecontrol.h"
-#define RESET_USAGE \
-" nvmecontrol reset <controller id>\n"
+typedef void (*nvme_fn_t)(int argc, char *argv[]);
-static void perftest_usage(void);
+static struct nvme_function {
+ const char *name;
+ nvme_fn_t fn;
+ const char *usage;
+} funcs[] = {
+ {"devlist", devlist, DEVLIST_USAGE},
+ {"identify", identify, IDENTIFY_USAGE},
+ {"perftest", perftest, PERFTEST_USAGE},
+ {"reset", reset, RESET_USAGE},
+ {"logpage", logpage, LOGPAGE_USAGE},
+ {"firmware", firmware, FIRMWARE_USAGE},
+ {NULL, NULL, NULL},
+};
static void
usage(void)
{
+ struct nvme_function *f;
+
+ f = funcs;
fprintf(stderr, "usage:\n");
- fprintf(stderr, DEVLIST_USAGE);
- fprintf(stderr, IDENTIFY_USAGE);
- fprintf(stderr, RESET_USAGE);
- fprintf(stderr, PERFTEST_USAGE);
- exit(EX_USAGE);
+ while (f->name != NULL) {
+ fprintf(stderr, "%s", f->usage);
+ f++;
+ }
+ exit(1);
}
static void
-print_controller_hex(struct nvme_controller_data *cdata, uint32_t length)
+print_bytes(void *data, uint32_t length)
{
- uint32_t *p;
uint32_t i, j;
+ uint8_t *p, *end;
- p = (uint32_t *)cdata;
- length /= sizeof(uint32_t);
+ end = (uint8_t *)data + length;
- for (i = 0; i < length; i+=8) {
- printf("%03x: ", i*4);
- for (j = 0; j < 8; j++)
- printf("%08x ", p[i+j]);
+ for (i = 0; i < length; i++) {
+ p = (uint8_t *)data + (i*16);
+ printf("%03x: ", i*16);
+ for (j = 0; j < 16 && p < end; j++)
+ printf("%02x ", *p++);
+ if (p >= end)
+ break;
printf("\n");
}
-
printf("\n");
}
static void
-print_controller(struct nvme_controller_data *cdata)
-{
- printf("Controller Capabilities/Features\n");
- printf("================================\n");
- printf("Vendor ID: %04x\n", cdata->vid);
- printf("Subsystem Vendor ID: %04x\n", cdata->ssvid);
- printf("Serial Number: %s\n", cdata->sn);
- printf("Model Number: %s\n", cdata->mn);
- printf("Firmware Version: %s\n", cdata->fr);
- printf("Recommended Arb Burst: %d\n", cdata->rab);
- printf("IEEE OUI Identifier: %02x %02x %02x\n",
- cdata->ieee[0], cdata->ieee[1], cdata->ieee[2]);
- printf("Multi-Interface Cap: %02x\n", cdata->mic);
- /* TODO: Use CAP.MPSMIN to determine true memory page size. */
- printf("Max Data Transfer Size: ");
- if (cdata->mdts == 0)
- printf("Unlimited\n");
- else
- printf("%d\n", PAGE_SIZE * (1 << cdata->mdts));
- printf("\n");
-
- printf("Admin Command Set Attributes\n");
- printf("============================\n");
- printf("Security Send/Receive: %s\n",
- cdata->oacs.security ? "Supported" : "Not Supported");
- printf("Format NVM: %s\n",
- cdata->oacs.format ? "Supported" : "Not Supported");
- printf("Firmware Activate/Download: %s\n",
- cdata->oacs.firmware ? "Supported" : "Not Supported");
- printf("Abort Command Limit: %d\n", cdata->acl+1);
- printf("Async Event Request Limit: %d\n", cdata->aerl+1);
- printf("Number of Firmware Slots: ");
- if (cdata->oacs.firmware != 0)
- printf("%d\n", cdata->frmw.num_slots);
- else
- printf("N/A\n");
- printf("Firmware Slot 1 Read-Only: ");
- if (cdata->oacs.firmware != 0)
- printf("%s\n", cdata->frmw.slot1_ro ? "Yes" : "No");
- else
- printf("N/A\n");
- printf("Per-Namespace SMART Log: %s\n",
- cdata->lpa.ns_smart ? "Yes" : "No");
- printf("Error Log Page Entries: %d\n", cdata->elpe+1);
- printf("Number of Power States: %d\n", cdata->npss+1);
- printf("\n");
-
- printf("NVM Command Set Attributes\n");
- printf("==========================\n");
- printf("Submission Queue Entry Size\n");
- printf(" Max: %d\n", 1 << cdata->sqes.max);
- printf(" Min: %d\n", 1 << cdata->sqes.min);
- printf("Completion Queue Entry Size\n");
- printf(" Max: %d\n", 1 << cdata->cqes.max);
- printf(" Min: %d\n", 1 << cdata->cqes.min);
- printf("Number of Namespaces: %d\n", cdata->nn);
- printf("Compare Command: %s\n",
- cdata->oncs.compare ? "Supported" : "Not Supported");
- printf("Write Uncorrectable Command: %s\n",
- cdata->oncs.write_unc ? "Supported" : "Not Supported");
- printf("Dataset Management Command: %s\n",
- cdata->oncs.dsm ? "Supported" : "Not Supported");
- printf("Volatile Write Cache: %s\n",
- cdata->vwc.present ? "Present" : "Not Present");
-}
-
-static void
-print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length)
+print_dwords(void *data, uint32_t length)
{
uint32_t *p;
uint32_t i, j;
- p = (uint32_t *)nsdata;
+ p = (uint32_t *)data;
length /= sizeof(uint32_t);
for (i = 0; i < length; i+=8) {
@@ -177,477 +114,119 @@ print_namespace_hex(struct nvme_namespace_data *nsdata, uint32_t length)
printf("\n");
}
-static void
-print_namespace(struct nvme_namespace_data *nsdata)
-{
- uint32_t i;
-
- printf("Size (in LBAs): %lld (%lldM)\n",
- (long long)nsdata->nsze,
- (long long)nsdata->nsze / 1024 / 1024);
- printf("Capacity (in LBAs): %lld (%lldM)\n",
- (long long)nsdata->ncap,
- (long long)nsdata->ncap / 1024 / 1024);
- printf("Utilization (in LBAs): %lld (%lldM)\n",
- (long long)nsdata->nuse,
- (long long)nsdata->nuse / 1024 / 1024);
- printf("Thin Provisioning: %s\n",
- nsdata->nsfeat.thin_prov ? "Supported" : "Not Supported");
- printf("Number of LBA Formats: %d\n", nsdata->nlbaf+1);
- printf("Current LBA Format: LBA Format #%d\n",
- nsdata->flbas.format);
- for (i = 0; i <= nsdata->nlbaf; i++) {
- printf("LBA Format #%d:\n", i);
- printf(" LBA Data Size: %d\n",
- 1 << nsdata->lbaf[i].lbads);
- }
-}
-
-static uint32_t
-ns_get_sector_size(struct nvme_namespace_data *nsdata)
+void
+print_hex(void *data, uint32_t length)
{
-
- return (1 << nsdata->lbaf[0].lbads);
+ if (length >= sizeof(uint32_t) || length % sizeof(uint32_t) == 0)
+ print_dwords(data, length);
+ else
+ print_bytes(data, length);
}
-
-static void
-devlist(int argc, char *argv[])
+void
+read_controller_data(int fd, struct nvme_controller_data *cdata)
{
- struct nvme_controller_data cdata;
- struct nvme_namespace_data nsdata;
- struct stat devstat;
- char name[64], path[64];
- uint32_t i;
- int ch, ctrlr, exit_code, fd, found;
-
- exit_code = EX_OK;
-
- while ((ch = getopt(argc, argv, "")) != -1) {
- switch ((char)ch) {
- default:
- usage();
- }
- }
+ struct nvme_pt_command pt;
- ctrlr = -1;
- found = 0;
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_IDENTIFY;
+ pt.cmd.cdw10 = 1;
+ pt.buf = cdata;
+ pt.len = sizeof(*cdata);
+ pt.is_read = 1;
- while (1) {
- ctrlr++;
- sprintf(name, "nvme%d", ctrlr);
- sprintf(path, "/dev/%s", name);
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "identify request failed");
- if (stat(path, &devstat) != 0)
- break;
-
- found++;
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- printf("Could not open %s. errno=%d (%s)\n", path,
- errno, strerror(errno));
- exit_code = EX_NOPERM;
- continue;
- }
-
- if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) < 0) {
- printf("Identify request to %s failed. errno=%d (%s)\n",
- path, errno, strerror(errno));
- exit_code = EX_IOERR;
- continue;
- }
-
- printf("%6s: %s\n", name, cdata.mn);
-
- for (i = 0; i < cdata.nn; i++) {
- sprintf(name, "nvme%dns%d", ctrlr, i+1);
- sprintf(path, "/dev/%s", name);
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- printf("Could not open %s. errno=%d (%s)\n",
- path, errno, strerror(errno));
- exit_code = EX_NOPERM;
- continue;
- }
- if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) < 0) {
- printf("Identify request to %s failed. "
- "errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit_code = EX_IOERR;
- continue;
- }
- printf(" %10s (%lldGB)\n",
- name,
- nsdata.nsze *
- (long long)ns_get_sector_size(&nsdata) /
- 1024 / 1024 / 1024);
- }
- }
-
- if (found == 0)
- printf("No NVMe controllers found.\n");
-
- exit(exit_code);
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "identify request returned error");
}
-static void
-identify_ctrlr(int argc, char *argv[])
+void
+read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata)
{
- struct nvme_controller_data cdata;
- struct stat devstat;
- char path[64];
- int ch, fd, hexflag = 0, hexlength;
- int verboseflag = 0;
-
- while ((ch = getopt(argc, argv, "vx")) != -1) {
- switch ((char)ch) {
- case 'v':
- verboseflag = 1;
- break;
- case 'x':
- hexflag = 1;
- break;
- default:
- usage();
- }
- }
-
- sprintf(path, "/dev/%s", argv[optind]);
-
- if (stat(path, &devstat) < 0) {
- printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit(EX_IOERR);
- }
+ struct nvme_pt_command pt;
- fd = open(path, O_RDWR);
- if (fd < 0) {
- printf("Could not open %s. errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit(EX_NOPERM);
- }
+ memset(&pt, 0, sizeof(pt));
+ pt.cmd.opc = NVME_OPC_IDENTIFY;
+ pt.cmd.nsid = nsid;
+ pt.buf = nsdata;
+ pt.len = sizeof(*nsdata);
+ pt.is_read = 1;
- if (ioctl(fd, NVME_IDENTIFY_CONTROLLER, &cdata) < 0) {
- printf("Identify request to %s failed. errno=%d (%s)\n", path,
- errno, strerror(errno));
- exit(EX_IOERR);
- }
+ if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
+ err(1, "identify request failed");
- if (hexflag == 1) {
- if (verboseflag == 1)
- hexlength = sizeof(struct nvme_controller_data);
- else
- hexlength = offsetof(struct nvme_controller_data,
- reserved5);
- print_controller_hex(&cdata, hexlength);
- exit(EX_OK);
- }
-
- if (verboseflag == 1) {
- printf("-v not currently supported without -x.\n");
- usage();
- }
-
- print_controller(&cdata);
- exit(EX_OK);
+ if (nvme_completion_is_error(&pt.cpl))
+ errx(1, "identify request returned error");
}
-static void
-identify_ns(int argc, char *argv[])
+int
+open_dev(const char *str, int *fd, int show_error, int exit_on_error)
{
- struct nvme_namespace_data nsdata;
- struct stat devstat;
- char path[64];
- int ch, fd, hexflag = 0, hexlength;
- int verboseflag = 0;
-
- while ((ch = getopt(argc, argv, "vx")) != -1) {
- switch ((char)ch) {
- case 'v':
- verboseflag = 1;
- break;
- case 'x':
- hexflag = 1;
- break;
- default:
- usage();
- }
- }
-
- sprintf(path, "/dev/%s", argv[optind]);
-
- if (stat(path, &devstat) < 0) {
- printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit(EX_IOERR);
- }
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- printf("Could not open %s. errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit(EX_NOPERM);
- }
-
- if (ioctl(fd, NVME_IDENTIFY_NAMESPACE, &nsdata) < 0) {
- printf("Identify request to %s failed. errno=%d (%s)\n", path,
- errno, strerror(errno));
- exit(EX_IOERR);
- }
-
- if (hexflag == 1) {
- if (verboseflag == 1)
- hexlength = sizeof(struct nvme_namespace_data);
+ char full_path[64];
+
+ if (!strnstr(str, NVME_CTRLR_PREFIX, strlen(NVME_CTRLR_PREFIX))) {
+ if (show_error)
+ warnx("controller/namespace ids must begin with '%s'",
+ NVME_CTRLR_PREFIX);
+ if (exit_on_error)
+ exit(1);
else
- hexlength = offsetof(struct nvme_namespace_data,
- reserved6);
- print_namespace_hex(&nsdata, hexlength);
- exit(EX_OK);
+ return (EINVAL);
}
- if (verboseflag == 1) {
- printf("-v not currently supported without -x.\n");
- usage();
+ snprintf(full_path, sizeof(full_path), _PATH_DEV"%s", str);
+ *fd = open(full_path, O_RDWR);
+ if (*fd < 0) {
+ if (show_error)
+ warn("could not open %s", full_path);
+ if (exit_on_error)
+ exit(1);
+ else
+ return (errno);
}
- print_namespace(&nsdata);
- exit(EX_OK);
+ return (0);
}
-static void
-identify(int argc, char *argv[])
+void
+parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid)
{
- char *target;
-
- if (argc < 2)
- usage();
-
- while (getopt(argc, argv, "vx") != -1) ;
-
- target = argv[optind];
-
- /* Specified device node must have "nvme" in it. */
- if (strstr(argv[optind], "nvme") == NULL) {
- printf("Invalid device node '%s'.\n", argv[optind]);
- exit(EX_IOERR);
- }
-
- optreset = 1;
- optind = 1;
+ char *nsloc;
/*
- * If device node contains "ns", we consider it a namespace,
- * otherwise, consider it a controller.
+ * Pull the namespace id from the string. +2 skips past the "ns" part
+ * of the string. Don't search past 10 characters into the string,
+ * otherwise we know it is malformed.
*/
- if (strstr(target, "ns") == NULL)
- identify_ctrlr(argc, argv);
- else
- identify_ns(argc, argv);
-}
+ nsloc = strnstr(ns_str, NVME_NS_PREFIX, 10);
+ if (nsloc != NULL)
+ *nsid = strtol(nsloc + 2, NULL, 10);
+ if (nsloc == NULL || (*nsid == 0 && errno != 0))
+ errx(1, "invalid namespace ID '%s'", ns_str);
-static void
-print_perftest(struct nvme_io_test *io_test, bool perthread)
-{
- uint32_t i, io_completed = 0, iops, mbps;
-
- for (i = 0; i < io_test->num_threads; i++)
- io_completed += io_test->io_completed[i];
-
- iops = io_completed/io_test->time;
- mbps = iops * io_test->size / (1024*1024);
-
- printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
- io_test->num_threads, io_test->size,
- io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
- io_test->time, iops, mbps);
-
- if (perthread)
- for (i = 0; i < io_test->num_threads; i++)
- printf("\t%3d: %8d IO/s\n", i,
- io_test->io_completed[i]/io_test->time);
-
- exit(1);
-}
-
-static void
-perftest_usage(void)
-{
- fprintf(stderr, "usage:\n");
- fprintf(stderr, PERFTEST_USAGE);
- exit(EX_USAGE);
-}
-
-static void
-perftest(int argc, char *argv[])
-{
- struct nvme_io_test io_test;
- int fd;
- char ch;
- char *p;
- const char *name;
- char path[64];
- u_long ioctl_cmd = NVME_IO_TEST;
- bool nflag, oflag, sflag, tflag;
- int perthread = 0;
-
- nflag = oflag = sflag = tflag = false;
- name = NULL;
-
- memset(&io_test, 0, sizeof(io_test));
-
- while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
- switch (ch) {
- case 'f':
- if (!strcmp(optarg, "refthread"))
- io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
- break;
- case 'i':
- if (!strcmp(optarg, "bio") ||
- !strcmp(optarg, "wait"))
- ioctl_cmd = NVME_BIO_TEST;
- else if (!strcmp(optarg, "io") ||
- !strcmp(optarg, "intr"))
- ioctl_cmd = NVME_IO_TEST;
- break;
- case 'n':
- nflag = true;
- io_test.num_threads = strtoul(optarg, &p, 0);
- if (p != NULL && *p != '\0') {
- fprintf(stderr,
- "\"%s\" not valid number of threads.\n",
- optarg);
- perftest_usage();
- } else if (io_test.num_threads == 0 ||
- io_test.num_threads > 128) {
- fprintf(stderr,
- "\"%s\" not valid number of threads.\n",
- optarg);
- perftest_usage();
- }
- break;
- case 'o':
- oflag = true;
- if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
- io_test.opc = NVME_OPC_READ;
- else if (!strcmp(optarg, "write") ||
- !strcmp(optarg, "WRITE"))
- io_test.opc = NVME_OPC_WRITE;
- else {
- fprintf(stderr, "\"%s\" not valid opcode.\n",
- optarg);
- perftest_usage();
- }
- break;
- case 'p':
- perthread = 1;
- break;
- case 's':
- sflag = true;
- io_test.size = strtoul(optarg, &p, 0);
- if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
- // do nothing
- } else if (toupper(*p) == 'K') {
- io_test.size *= 1024;
- } else if (toupper(*p) == 'M') {
- io_test.size *= 1024 * 1024;
- } else {
- fprintf(stderr, "\"%s\" not valid size.\n",
- optarg);
- perftest_usage();
- }
- break;
- case 't':
- tflag = true;
- io_test.time = strtoul(optarg, &p, 0);
- if (p != NULL && *p != '\0') {
- fprintf(stderr,
- "\"%s\" not valid time duration.\n",
- optarg);
- perftest_usage();
- }
- break;
- }
- }
-
- name = argv[optind];
-
- if (!nflag || !oflag || !sflag || !tflag || name == NULL)
- perftest_usage();
-
- sprintf(path, "/dev/%s", name);
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- fprintf(stderr, "%s not valid device. errno=%d (%s)\n", path,
- errno, strerror(errno));
- perftest_usage();
- }
-
- if (ioctl(fd, ioctl_cmd, &io_test) < 0) {
- fprintf(stderr, "NVME_IO_TEST failed. errno=%d (%s)\n", errno,
- strerror(errno));
- exit(EX_IOERR);
- }
-
- print_perftest(&io_test, perthread);
- exit(EX_OK);
-}
-
-static void
-reset_ctrlr(int argc, char *argv[])
-{
- struct stat devstat;
- char path[64];
- int ch, fd;
-
- while ((ch = getopt(argc, argv, "")) != -1) {
- switch ((char)ch) {
- default:
- usage();
- }
- }
-
- sprintf(path, "/dev/%s", argv[optind]);
-
- if (stat(path, &devstat) < 0) {
- printf("Invalid device node %s. errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit(EX_IOERR);
- }
-
- fd = open(path, O_RDWR);
- if (fd < 0) {
- printf("Could not open %s. errno=%d (%s)\n", path, errno,
- strerror(errno));
- exit(EX_NOPERM);
- }
-
- if (ioctl(fd, NVME_RESET_CONTROLLER) < 0) {
- printf("Reset request to %s failed. errno=%d (%s)\n", path,
- errno, strerror(errno));
- exit(EX_IOERR);
- }
-
- exit(EX_OK);
+ /*
+ * The controller string will include only the nvmX part of the
+ * nvmeXnsY string.
+ */
+ snprintf(ctrlr_str, nsloc - ns_str + 1, "%s", ns_str);
}
int
main(int argc, char *argv[])
{
+ struct nvme_function *f;
if (argc < 2)
usage();
- if (strcmp(argv[1], "devlist") == 0)
- devlist(argc-1, &argv[1]);
- else if (strcmp(argv[1], "identify") == 0)
- identify(argc-1, &argv[1]);
- else if (strcmp(argv[1], "perftest") == 0)
- perftest(argc-1, &argv[1]);
- else if (strcmp(argv[1], "reset") == 0)
- reset_ctrlr(argc-1, &argv[1]);
+ f = funcs;
+ while (f->name != NULL) {
+ if (strcmp(argv[1], f->name) == 0)
+ f->fn(argc-1, &argv[1]);
+ f++;
+ }
usage();
diff --git a/sbin/nvmecontrol/nvmecontrol.h b/sbin/nvmecontrol/nvmecontrol.h
new file mode 100644
index 0000000..8401dd7
--- /dev/null
+++ b/sbin/nvmecontrol/nvmecontrol.h
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$
+ */
+
+#ifndef __NVMECONTROL_H__
+#define __NVMECONTROL_H__
+
+#include <dev/nvme/nvme.h>
+
+#define NVME_CTRLR_PREFIX "nvme"
+#define NVME_NS_PREFIX "ns"
+
+#define DEVLIST_USAGE \
+" nvmecontrol devlist\n"
+
+#define IDENTIFY_USAGE \
+" nvmecontrol identify [-x [-v]] <controller id|namespace id>\n"
+
+#define PERFTEST_USAGE \
+" nvmecontrol perftest <-n num_threads> <-o read|write>\n" \
+" <-s size_in_bytes> <-t time_in_seconds>\n" \
+" <-i intr|wait> [-f refthread] [-p]\n" \
+" <namespace id>\n"
+
+#define RESET_USAGE \
+" nvmecontrol reset <controller id>\n"
+
+#define LOGPAGE_USAGE \
+" nvmecontrol logpage <-p page_id> [-x] <controller id|namespace id>\n" \
+
+#define FIRMWARE_USAGE \
+" nvmecontrol firmware [-s slot] [-f path_to_firmware] [-a] <controller id>\n"
+
+void devlist(int argc, char *argv[]);
+void identify(int argc, char *argv[]);
+void perftest(int argc, char *argv[]);
+void reset(int argc, char *argv[]);
+void logpage(int argc, char *argv[]);
+void firmware(int argc, char *argv[]);
+
+int open_dev(const char *str, int *fd, int show_error, int exit_on_error);
+void parse_ns_str(const char *ns_str, char *ctrlr_str, int *nsid);
+void read_controller_data(int fd, struct nvme_controller_data *cdata);
+void read_namespace_data(int fd, int nsid, struct nvme_namespace_data *nsdata);
+void print_hex(void *data, uint32_t length);
+void read_logpage(int fd, uint8_t log_page, int nsid, void *payload,
+ uint32_t payload_size);
+
+#endif
+
diff --git a/sbin/nvmecontrol/perftest.c b/sbin/nvmecontrol/perftest.c
new file mode 100644
index 0000000..a7339bf
--- /dev/null
+++ b/sbin/nvmecontrol/perftest.c
@@ -0,0 +1,176 @@
+/*-
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+print_perftest(struct nvme_io_test *io_test, bool perthread)
+{
+ uint32_t i, io_completed = 0, iops, mbps;
+
+ for (i = 0; i < io_test->num_threads; i++)
+ io_completed += io_test->io_completed[i];
+
+ iops = io_completed/io_test->time;
+ mbps = iops * io_test->size / (1024*1024);
+
+ printf("Threads: %2d Size: %6d %5s Time: %3d IO/s: %7d MB/s: %4d\n",
+ io_test->num_threads, io_test->size,
+ io_test->opc == NVME_OPC_READ ? "READ" : "WRITE",
+ io_test->time, iops, mbps);
+
+ if (perthread)
+ for (i = 0; i < io_test->num_threads; i++)
+ printf("\t%3d: %8d IO/s\n", i,
+ io_test->io_completed[i]/io_test->time);
+
+ exit(1);
+}
+
+static void
+perftest_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, PERFTEST_USAGE);
+ exit(1);
+}
+
+void
+perftest(int argc, char *argv[])
+{
+ struct nvme_io_test io_test;
+ int fd;
+ char ch;
+ char *p;
+ u_long ioctl_cmd = NVME_IO_TEST;
+ bool nflag, oflag, sflag, tflag;
+ int perthread = 0;
+
+ nflag = oflag = sflag = tflag = false;
+
+ memset(&io_test, 0, sizeof(io_test));
+
+ while ((ch = getopt(argc, argv, "f:i:n:o:ps:t:")) != -1) {
+ switch (ch) {
+ case 'f':
+ if (!strcmp(optarg, "refthread"))
+ io_test.flags |= NVME_TEST_FLAG_REFTHREAD;
+ break;
+ case 'i':
+ if (!strcmp(optarg, "bio") ||
+ !strcmp(optarg, "wait"))
+ ioctl_cmd = NVME_BIO_TEST;
+ else if (!strcmp(optarg, "io") ||
+ !strcmp(optarg, "intr"))
+ ioctl_cmd = NVME_IO_TEST;
+ break;
+ case 'n':
+ nflag = true;
+ io_test.num_threads = strtoul(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid number of threads.\n",
+ optarg);
+ perftest_usage();
+ } else if (io_test.num_threads == 0 ||
+ io_test.num_threads > 128) {
+ fprintf(stderr,
+ "\"%s\" not valid number of threads.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 'o':
+ oflag = true;
+ if (!strcmp(optarg, "read") || !strcmp(optarg, "READ"))
+ io_test.opc = NVME_OPC_READ;
+ else if (!strcmp(optarg, "write") ||
+ !strcmp(optarg, "WRITE"))
+ io_test.opc = NVME_OPC_WRITE;
+ else {
+ fprintf(stderr, "\"%s\" not valid opcode.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 'p':
+ perthread = 1;
+ break;
+ case 's':
+ sflag = true;
+ io_test.size = strtoul(optarg, &p, 0);
+ if (p == NULL || *p == '\0' || toupper(*p) == 'B') {
+ // do nothing
+ } else if (toupper(*p) == 'K') {
+ io_test.size *= 1024;
+ } else if (toupper(*p) == 'M') {
+ io_test.size *= 1024 * 1024;
+ } else {
+ fprintf(stderr, "\"%s\" not valid size.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ case 't':
+ tflag = true;
+ io_test.time = strtoul(optarg, &p, 0);
+ if (p != NULL && *p != '\0') {
+ fprintf(stderr,
+ "\"%s\" not valid time duration.\n",
+ optarg);
+ perftest_usage();
+ }
+ break;
+ }
+ }
+
+ if (!nflag || !oflag || !sflag || !tflag || optind >= argc)
+ perftest_usage();
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if (ioctl(fd, ioctl_cmd, &io_test) < 0)
+ err(1, "ioctl NVME_IO_TEST failed");
+
+ close(fd);
+ print_perftest(&io_test, perthread);
+ exit(0);
+}
diff --git a/sbin/nvmecontrol/reset.c b/sbin/nvmecontrol/reset.c
new file mode 100644
index 0000000..8ce597e
--- /dev/null
+++ b/sbin/nvmecontrol/reset.c
@@ -0,0 +1,71 @@
+/*-
+ * Copyright (C) 2012-2013 Intel Corporation
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/ioccom.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nvmecontrol.h"
+
+static void
+reset_usage(void)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, RESET_USAGE);
+ exit(1);
+}
+
+void
+reset(int argc, char *argv[])
+{
+ int ch, fd;
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch ((char)ch) {
+ default:
+ reset_usage();
+ }
+ }
+
+ /* Check that a controller was specified. */
+ if (optind >= argc)
+ reset_usage();
+
+ open_dev(argv[optind], &fd, 1, 1);
+ if (ioctl(fd, NVME_RESET_CONTROLLER) < 0)
+ err(1, "reset request to %s failed", argv[optind]);
+
+ exit(0);
+}
diff --git a/sbin/ping6/ping6.8 b/sbin/ping6/ping6.8
index b720aef..60a6980 100644
--- a/sbin/ping6/ping6.8
+++ b/sbin/ping6/ping6.8
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 20, 2010
+.Dd May 5, 2013
.Dt PING6 8
.Os
.Sh NAME
@@ -215,8 +215,8 @@ unicast and multicast packets.
Numeric output only.
No attempt will be made to lookup symbolic names from addresses in the reply.
.It Fl N
-Probe node information multicast group
-.Pq Li ff02::2:xxxx:xxxx .
+Probe node information multicast group address
+.Pq Li ff02::2:ffxx:xxxx .
.Ar host
must be string hostname of the target
(must not be a numeric IPv6 address).
@@ -227,6 +227,15 @@ Since node information multicast group is a link-local multicast group,
outgoing interface needs to be specified by
.Fl I
option.
+.Pp
+When specified twice, the address
+.Pq Li ff02::2:xxxx:xxxx
+is used instead.
+The former is in RFC 4620, the latter is in an old Internet Draft
+draft-ietf-ipngwg-icmp-name-lookup.
+Note that KAME-derived implementations including
+.Fx
+use the latter.
.It Fl o
Exit successfully after receiving one reply packet.
.It Fl p Ar pattern
diff --git a/sbin/ping6/ping6.c b/sbin/ping6/ping6.c
index 8c3e16b..01e29a1 100644
--- a/sbin/ping6/ping6.c
+++ b/sbin/ping6/ping6.c
@@ -287,7 +287,7 @@ void pr_retip(struct ip6_hdr *, u_char *);
void summary(void);
void tvsub(struct timeval *, struct timeval *);
int setpolicy(int, char *);
-char *nigroup(char *);
+char *nigroup(char *, int);
void usage(void);
int
@@ -306,6 +306,7 @@ main(int argc, char *argv[])
struct addrinfo hints;
int cc, i;
int ch, hold, packlen, preload, optval, ret_ga;
+ int nig_oldmcprefix = -1;
u_char *datap;
char *e, *target, *ifname = NULL, *gateway = NULL;
int ip6optlen = 0;
@@ -490,6 +491,7 @@ main(int argc, char *argv[])
break;
case 'N':
options |= F_NIGROUP;
+ nig_oldmcprefix++;
break;
case 'o':
options |= F_ONCE;
@@ -605,7 +607,7 @@ main(int argc, char *argv[])
}
if (options & F_NIGROUP) {
- target = nigroup(argv[argc - 1]);
+ target = nigroup(argv[argc - 1], nig_oldmcprefix);
if (target == NULL) {
usage();
/*NOTREACHED*/
@@ -2723,7 +2725,7 @@ setpolicy(int so __unused, char *policy)
#endif
char *
-nigroup(char *name)
+nigroup(char *name, int nig_oldmcprefix)
{
char *p;
char *q;
@@ -2733,6 +2735,7 @@ nigroup(char *name)
size_t l;
char hbuf[NI_MAXHOST];
struct in6_addr in6;
+ int valid;
p = strchr(name, '.');
if (!p)
@@ -2748,7 +2751,7 @@ nigroup(char *name)
*q = tolower(*(unsigned char *)q);
}
- /* generate 8 bytes of pseudo-random value. */
+ /* generate 16 bytes of pseudo-random value. */
memset(&ctxt, 0, sizeof(ctxt));
MD5Init(&ctxt);
c = l & 0xff;
@@ -2756,9 +2759,23 @@ nigroup(char *name)
MD5Update(&ctxt, (unsigned char *)name, l);
MD5Final(digest, &ctxt);
- if (inet_pton(AF_INET6, "ff02::2:0000:0000", &in6) != 1)
+ if (nig_oldmcprefix) {
+ /* draft-ietf-ipngwg-icmp-name-lookup */
+ valid = inet_pton(AF_INET6, "ff02::2:0000:0000", &in6);
+ } else {
+ /* RFC 4620 */
+ valid = inet_pton(AF_INET6, "ff02::2:ff00:0000", &in6);
+ }
+ if (valid != 1)
return NULL; /*XXX*/
- bcopy(digest, &in6.s6_addr[12], 4);
+
+ if (nig_oldmcprefix) {
+ /* draft-ietf-ipngwg-icmp-name-lookup */
+ bcopy(digest, &in6.s6_addr[12], 4);
+ } else {
+ /* RFC 4620 */
+ bcopy(digest, &in6.s6_addr[13], 3);
+ }
if (inet_ntop(AF_INET6, &in6, hbuf, sizeof(hbuf)) == NULL)
return NULL;
diff --git a/sbin/reboot/boot_i386.8 b/sbin/reboot/boot_i386.8
index 33ad8fe..e21e53f 100644
--- a/sbin/reboot/boot_i386.8
+++ b/sbin/reboot/boot_i386.8
@@ -36,7 +36,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 4, 2010
+.Dd July 1, 2013
.Dt BOOT 8 i386
.Os
.Sh NAME
@@ -351,6 +351,7 @@ requirement has not been adhered to.
.Xr bsdlabel 8 ,
.Xr btxld 8 ,
.Xr config 8 ,
+.Xr gptboot 8 ,
.Xr halt 8 ,
.Xr loader 8 ,
.Xr nextboot 8 ,
diff --git a/sbin/recoverdisk/recoverdisk.1 b/sbin/recoverdisk/recoverdisk.1
index ef1241b..1661ab8 100644
--- a/sbin/recoverdisk/recoverdisk.1
+++ b/sbin/recoverdisk/recoverdisk.1
@@ -125,9 +125,9 @@ recoverdisk -b 0 /dev/ad3 /somewhere
.Ed
.Sh SEE ALSO
.Xr dd 1 ,
-.Xr ada 4,
-.Xr cam 4,
-.Xr cd 4,
+.Xr ada 4 ,
+.Xr cam 4 ,
+.Xr cd 4 ,
.Xr da 4
.Sh HISTORY
The
diff --git a/sbin/route/Makefile b/sbin/route/Makefile
index 0f4cd67..569d21a 100644
--- a/sbin/route/Makefile
+++ b/sbin/route/Makefile
@@ -7,24 +7,21 @@ PROG= route
MAN= route.8
SRCS= route.c keywords.h
WARNS?= 3
-CLEANFILES+=keywords.h _keywords.tmp
+CLEANFILES+=keywords.h
CFLAGS+= -DNS
-
+.if ${MK_INET_SUPPORT} != "no"
+CFLAGS+= -DINET
+.endif
.if ${MK_INET6_SUPPORT} != "no"
CFLAGS+= -DINET6
.endif
-
CFLAGS+= -I.
keywords.h: keywords
- sed -e '/^#/d' -e '/^$$/d' ${.CURDIR}/keywords > _keywords.tmp
- LC_ALL=C tr 'a-z' 'A-Z' < _keywords.tmp | paste _keywords.tmp - | \
- awk '{ \
- if (NF > 1) \
- printf "#define\tK_%s\t%d\n\t{\"%s\", K_%s},\n", \
- $$2, NR, $$1, $$2 }' \
- > ${.TARGET}
- rm -f _keywords.tmp
+ LC_ALL=C awk '!/^#|^$$/ { \
+ printf "#define\tK_%s\t%d\n\t{\"%s\", K_%s},\n", \
+ toupper($$1), ++L, $$1, toupper($$1); \
+ }' < ${.CURDIR}/keywords > ${.TARGET} || (rm -f ${.TARGET}; false)
.include <bsd.prog.mk>
diff --git a/sbin/route/route.c b/sbin/route/route.c
index 48f90a7..e575c71 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -70,7 +70,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <ifaddrs.h>
-struct keytab {
+static struct keytab {
const char *kt_cp;
int kt_i;
} keywords[] = {
@@ -78,42 +78,33 @@ struct keytab {
{0, 0}
};
-union sockunion {
- struct sockaddr sa;
- struct sockaddr_in sin;
-#ifdef INET6
- struct sockaddr_in6 sin6;
-#endif
- struct sockaddr_at sat;
- struct sockaddr_dl sdl;
- struct sockaddr_storage ss; /* added to avoid memory overrun */
-} so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp;
-
-typedef union sockunion *sup;
-int pid, rtm_addrs;
-int s;
-int forcehost, forcenet, doflush, nflag, af, qflag, tflag;
-int verbose, aflen = sizeof (struct sockaddr_in);
-int locking, lockrest, debugonly;
-struct rt_metrics rt_metrics;
-u_long rtm_inits;
-uid_t uid;
+static struct sockaddr_storage so[RTAX_MAX];
+static int pid, rtm_addrs;
+static int s;
+static int forcehost, forcenet, nflag, af, qflag, tflag;
+static int verbose, aflen;
+static int locking, lockrest, debugonly;
+static struct rt_metrics rt_metrics;
+static u_long rtm_inits;
+static uid_t uid;
static int defaultfib;
static int numfibs;
static int atalk_aton(const char *, struct at_addr *);
static char *atalk_ntoa(struct at_addr);
-static void bprintf(FILE *, int, u_char *);
+static void printb(int, const char *);
static void flushroutes(int argc, char *argv[]);
static int flushroutes_fib(int);
static int getaddr(int, char *, struct hostent **, int);
static int keyword(const char *);
-static void inet_makenetandmask(u_long, struct sockaddr_in *, u_long);
+#ifdef INET
+static void inet_makenetandmask(u_long, struct sockaddr_in *,
+ struct sockaddr_in *, u_long);
+#endif
#ifdef INET6
-static int inet6_makenetandmask(struct sockaddr_in6 *, const char *);
+static int inet6_makenetandmask(struct sockaddr_in6 *, const char *);
#endif
static void interfaces(void);
-static void mask_addr(void);
static void monitor(int, char*[]);
static const char *netname(struct sockaddr *);
static void newroute(int, char **);
@@ -127,10 +118,8 @@ static const char *routename(struct sockaddr *);
static int rtmsg(int, int, int);
static void set_metric(char *, int);
static int set_sofib(int);
-static int set_procfib(int);
-static void sockaddr(char *, struct sockaddr *);
-static void sodump(sup, const char *);
-extern char *iso_ntoa(void);
+static void sockaddr(char *, struct sockaddr *, size_t);
+static void sodump(struct sockaddr *, const char *);
struct fibl {
TAILQ_ENTRY(fibl) fl_next;
@@ -139,21 +128,19 @@ struct fibl {
int fl_error;
int fl_errno;
};
-TAILQ_HEAD(fibl_head_t, fibl) fibl_head;
+static TAILQ_HEAD(fibl_head_t, fibl) fibl_head;
static int fiboptlist_csv(const char *, struct fibl_head_t *);
static int fiboptlist_range(const char *, struct fibl_head_t *);
static void usage(const char *) __dead2;
-void
+static void
usage(const char *cp)
{
if (cp != NULL)
warnx("bad keyword: %s", cp);
- (void) fprintf(stderr,
- "usage: route [-dnqtv] command [[modifiers] args]\n");
- exit(EX_USAGE);
+ errx(EX_USAGE, "usage: route [-dnqtv] command [[modifiers] args]");
/* NOTREACHED */
}
@@ -247,15 +234,6 @@ set_sofib(int fib)
}
static int
-set_procfib(int fib)
-{
-
- if (fib < 0)
- return (0);
- return (setfib(fib));
-}
-
-static int
fiboptlist_range(const char *arg, struct fibl_head_t *flh)
{
struct fibl *fl;
@@ -313,6 +291,7 @@ fiboptlist_csv(const char *arg, struct fibl_head_t *flh)
char *str0, *str, *token, *endptr;
int fib, error;
+ str0 = str = NULL;
if (strcmp("all", arg) == 0) {
str = calloc(1, ALLSTRLEN);
if (str == NULL) {
@@ -362,7 +341,8 @@ fiboptlist_csv(const char *arg, struct fibl_head_t *flh)
}
}
fiboptlist_csv_ret:
- free(str0);
+ if (str0 != NULL)
+ free(str0);
return (error);
}
@@ -376,9 +356,8 @@ flushroutes(int argc, char *argv[])
struct fibl *fl;
int error;
- if (uid != 0 && !debugonly && !tflag) {
+ if (uid != 0 && !debugonly && !tflag)
errx(EX_NOPERM, "must be root to alter routing table");
- }
shutdown(s, SHUT_RD); /* Don't want to read back our messages */
TAILQ_INIT(&fibl_head);
@@ -388,9 +367,11 @@ flushroutes(int argc, char *argv[])
if (**argv != '-')
usage(*argv);
switch (keyword(*argv + 1)) {
+#ifdef INET
case K_INET:
af = AF_INET;
break;
+#endif
#ifdef INET6
case K_INET6:
af = AF_INET6;
@@ -428,11 +409,10 @@ flushroutes_fib(int fib)
struct rt_msghdr *rtm;
size_t needed;
char *buf, *next, *lim;
- int mib[6], rlen, seqno, count = 0;
+ int mib[7], rlen, seqno, count = 0;
int error;
error = set_sofib(fib);
- error += set_procfib(fib);
if (error) {
warn("fib number %d is ignored", fib);
return (error);
@@ -442,14 +422,15 @@ retry:
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
- mib[3] = 0; /* wildcard address family */
+ mib[3] = AF_UNSPEC;
mib[4] = NET_RT_DUMP;
mib[5] = 0; /* no flags */
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ mib[6] = fib;
+ if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
err(EX_OSERR, "route-sysctl-estimate");
if ((buf = malloc(needed)) == NULL)
errx(EX_OSERR, "malloc failed");
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) {
if (errno == ENOMEM && count++ < 10) {
warnx("Routing table grew, retrying");
sleep(1);
@@ -460,10 +441,10 @@ retry:
}
lim = buf + needed;
if (verbose)
- (void) printf("Examining routing table from sysctl\n");
+ (void)printf("Examining routing table from sysctl\n");
seqno = 0; /* ??? */
for (next = buf; next < lim; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
+ rtm = (struct rt_msghdr *)(void *)next;
if (verbose)
print_rtmsg(rtm, rtm->rtm_msglen);
if ((rtm->rtm_flags & RTF_GATEWAY) == 0)
@@ -483,7 +464,7 @@ retry:
err(1, "write to routing socket");
if (rlen < (int)rtm->rtm_msglen) {
warn("write to routing socket");
- (void) printf("got only %d for rlen\n", rlen);
+ (void)printf("got only %d for rlen\n", rlen);
free(buf);
goto retry;
break;
@@ -508,12 +489,12 @@ retry:
return (error);
}
-const char *
+static const char *
routename(struct sockaddr *sa)
{
+ struct sockaddr_dl *sdl;
const char *cp;
- static char line[MAXHOSTNAMELEN + 1];
- struct hostent *hp;
+ static char line[NI_MAXHOST];
static char domain[MAXHOSTNAMELEN + 1];
static int first = 1, n;
@@ -522,73 +503,99 @@ routename(struct sockaddr *sa)
if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
(cp = strchr(domain, '.'))) {
domain[MAXHOSTNAMELEN] = '\0';
- (void) strcpy(domain, cp + 1);
+ (void)strcpy(domain, cp + 1);
} else
- domain[0] = 0;
+ domain[0] = '\0';
}
- if (sa->sa_len == 0)
- strcpy(line, "default");
- else switch (sa->sa_family) {
-
+ /* If the address is zero-filled, use "default". */
+ if (sa->sa_len == 0 && nflag == 0)
+ return ("default");
+#if defined(INET) || defined(INET6)
+ switch (sa->sa_family) {
+#ifdef INET
case AF_INET:
- { struct in_addr in;
- in = ((struct sockaddr_in *)sa)->sin_addr;
-
- cp = NULL;
- if (in.s_addr == INADDR_ANY || sa->sa_len < 4)
- cp = "default";
- if (cp == NULL && !nflag) {
- hp = gethostbyaddr((char *)&in, sizeof (struct in_addr),
- AF_INET);
- if (hp != NULL) {
- char *cptr;
- cptr = strchr(hp->h_name, '.');
- if (cptr != NULL &&
- strcmp(cptr + 1, domain) == 0)
- *cptr = '\0';
- cp = hp->h_name;
- }
- }
- if (cp != NULL) {
- strncpy(line, cp, sizeof(line) - 1);
- line[sizeof(line) - 1] = '\0';
- } else
- (void) sprintf(line, "%s", inet_ntoa(in));
+ /* If the address is zero-filled, use "default". */
+ if (nflag == 0 &&
+ ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr ==
+ INADDR_ANY)
+ return("default");
break;
- }
+#endif
+#ifdef INET6
+ case AF_INET6:
+ /* If the address is zero-filled, use "default". */
+ if (nflag == 0 &&
+ IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr))
+ return("default");
+ break;
+#endif
+ }
+#endif
+ switch (sa->sa_family) {
+#if defined(INET) || defined(INET6)
+#ifdef INET
+ case AF_INET:
+#endif
#ifdef INET6
case AF_INET6:
+#endif
{
- struct sockaddr_in6 sin6; /* use static var for safety */
- int niflags = 0;
+ struct sockaddr_storage ss;
+ int error;
+ char *p;
- memset(&sin6, 0, sizeof(sin6));
- memcpy(&sin6, sa, sa->sa_len);
- sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_family = AF_INET6;
- if (nflag)
- niflags |= NI_NUMERICHOST;
- if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
- line, sizeof(line), NULL, 0, niflags) != 0)
+ memset(&ss, 0, sizeof(ss));
+ if (sa->sa_len == 0)
+ ss.ss_family = sa->sa_family;
+ else
+ memcpy(&ss, sa, sa->sa_len);
+ /* Expand sa->sa_len because it could be shortened. */
+ if (sa->sa_family == AF_INET)
+ ss.ss_len = sizeof(struct sockaddr_in);
+ else if (sa->sa_family == AF_INET6)
+ ss.ss_len = sizeof(struct sockaddr_in6);
+ error = getnameinfo((struct sockaddr *)&ss, ss.ss_len,
+ line, sizeof(line), NULL, 0,
+ (nflag == 0) ? 0 : NI_NUMERICHOST);
+ if (error) {
+ warnx("getnameinfo(): %s", gai_strerror(error));
strncpy(line, "invalid", sizeof(line));
+ }
- return(line);
+ /* Remove the domain part if any. */
+ p = strchr(line, '.');
+ if (p != NULL && strcmp(p + 1, domain) == 0)
+ *p = '\0';
+
+ return (line);
+ break;
}
#endif
-
case AF_APPLETALK:
- (void) snprintf(line, sizeof(line), "atalk %s",
- atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
+ (void)snprintf(line, sizeof(line), "atalk %s",
+ atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr));
break;
case AF_LINK:
- return (link_ntoa((struct sockaddr_dl *)sa));
+ sdl = (struct sockaddr_dl *)(void *)sa;
+
+ if (sdl->sdl_nlen == 0 &&
+ sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ n = snprintf(line, sizeof(line), "link#%d",
+ sdl->sdl_index);
+ if (n > (int)sizeof(line))
+ line[0] = '\0';
+ return (line);
+ } else
+ return (link_ntoa(sdl));
+ break;
default:
{
- u_short *sp = (u_short *)sa;
+ u_short *sp = (u_short *)(void *)sa;
u_short *splim = sp + ((sa->sa_len + 1) >> 1);
char *cps = line + sprintf(line, "(%d)", sa->sa_family);
char *cpe = line + sizeof(line);
@@ -608,21 +615,25 @@ routename(struct sockaddr *sa)
* Return the name of the network whose address is given.
* The address is assumed to be that of a net, not a host.
*/
-const char *
+static const char *
netname(struct sockaddr *sa)
{
- const char *cp = NULL;
+ struct sockaddr_dl *sdl;
static char line[MAXHOSTNAMELEN + 1];
+ int n;
+#ifdef INET
struct netent *np = NULL;
+ const char *cp = NULL;
u_long i;
- int n;
+#endif
switch (sa->sa_family) {
-
+#ifdef INET
case AF_INET:
- { struct in_addr in;
- in = ((struct sockaddr_in *)sa)->sin_addr;
+ {
+ struct in_addr in;
+ in = ((struct sockaddr_in *)(void *)sa)->sin_addr;
i = in.s_addr = ntohl(in.s_addr);
if (in.s_addr == 0)
cp = "default";
@@ -635,30 +646,30 @@ netname(struct sockaddr *sa)
if (cp != NULL)
strncpy(line, cp, sizeof(line));
else if ((in.s_addr & 0xffffff) == 0)
- (void) sprintf(line, "%u", C(in.s_addr >> 24));
+ (void)sprintf(line, "%u", C(in.s_addr >> 24));
else if ((in.s_addr & 0xffff) == 0)
- (void) sprintf(line, "%u.%u", C(in.s_addr >> 24),
+ (void)sprintf(line, "%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16));
else if ((in.s_addr & 0xff) == 0)
- (void) sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
+ (void)sprintf(line, "%u.%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16), C(in.s_addr >> 8));
else
- (void) sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
+ (void)sprintf(line, "%u.%u.%u.%u", C(in.s_addr >> 24),
C(in.s_addr >> 16), C(in.s_addr >> 8),
C(in.s_addr));
#undef C
break;
- }
-
+ }
+#endif
#ifdef INET6
case AF_INET6:
{
- struct sockaddr_in6 sin6; /* use static var for safety */
+ struct sockaddr_in6 sin6;
int niflags = 0;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6, sa, sa->sa_len);
- sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_len = sizeof(sin6);
sin6.sin6_family = AF_INET6;
if (nflag)
niflags |= NI_NUMERICHOST;
@@ -671,17 +682,28 @@ netname(struct sockaddr *sa)
#endif
case AF_APPLETALK:
- (void) snprintf(line, sizeof(line), "atalk %s",
- atalk_ntoa(((struct sockaddr_at *)sa)->sat_addr));
+ (void)snprintf(line, sizeof(line), "atalk %s",
+ atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr));
break;
case AF_LINK:
- return (link_ntoa((struct sockaddr_dl *)sa));
-
+ sdl = (struct sockaddr_dl *)(void *)sa;
+
+ if (sdl->sdl_nlen == 0 &&
+ sdl->sdl_alen == 0 &&
+ sdl->sdl_slen == 0) {
+ n = snprintf(line, sizeof(line), "link#%d",
+ sdl->sdl_index);
+ if (n > (int)sizeof(line))
+ line[0] = '\0';
+ return (line);
+ } else
+ return (link_ntoa(sdl));
+ break;
default:
{
- u_short *sp = (u_short *)sa->sa_data;
+ u_short *sp = (u_short *)(void *)sa->sa_data;
u_short *splim = sp + ((sa->sa_len + 1)>>1);
char *cps = line + sprintf(line, "af %d:", sa->sa_family);
char *cpe = line + sizeof(line);
@@ -738,10 +760,8 @@ newroute(int argc, char **argv)
const char *dest, *gateway, *errmsg;
int key, error, flags, nrflags, fibnum;
- if (uid != 0 && !debugonly && !tflag) {
+ if (uid != 0 && !debugonly && !tflag)
errx(EX_NOPERM, "must be root to alter routing table");
- }
-
dest = NULL;
gateway = NULL;
flags = RTF_STATIC;
@@ -752,7 +772,6 @@ newroute(int argc, char **argv)
cmd = argv[0];
if (*cmd != 'g' && *cmd != 's')
shutdown(s, SHUT_RD); /* Don't want to read back our messages */
-
while (--argc > 0) {
if (**(++argv)== '-') {
switch (key = keyword(1 + *argv)) {
@@ -760,10 +779,12 @@ newroute(int argc, char **argv)
af = AF_LINK;
aflen = sizeof(struct sockaddr_dl);
break;
+#ifdef INET
case K_INET:
af = AF_INET;
aflen = sizeof(struct sockaddr_in);
break;
+#endif
#ifdef INET6
case K_INET6:
af = AF_INET6;
@@ -776,7 +797,7 @@ newroute(int argc, char **argv)
break;
case K_SA:
af = PF_ROUTE;
- aflen = sizeof(union sockunion);
+ aflen = sizeof(struct sockaddr_storage);
break;
case K_IFACE:
case K_INTERFACE:
@@ -832,34 +853,35 @@ newroute(int argc, char **argv)
case K_IFA:
if (!--argc)
usage(NULL);
- getaddr(RTA_IFA, *++argv, 0, nrflags);
+ getaddr(RTAX_IFA, *++argv, 0, nrflags);
break;
case K_IFP:
if (!--argc)
usage(NULL);
- getaddr(RTA_IFP, *++argv, 0, nrflags);
+ getaddr(RTAX_IFP, *++argv, 0, nrflags);
break;
case K_GENMASK:
if (!--argc)
usage(NULL);
- getaddr(RTA_GENMASK, *++argv, 0, nrflags);
+ getaddr(RTAX_GENMASK, *++argv, 0, nrflags);
break;
case K_GATEWAY:
if (!--argc)
usage(NULL);
- getaddr(RTA_GATEWAY, *++argv, 0, nrflags);
+ getaddr(RTAX_GATEWAY, *++argv, 0, nrflags);
+ gateway = *argv;
break;
case K_DST:
if (!--argc)
usage(NULL);
- if (getaddr(RTA_DST, *++argv, &hp, nrflags))
+ if (getaddr(RTAX_DST, *++argv, &hp, nrflags))
nrflags |= F_ISHOST;
dest = *argv;
break;
case K_NETMASK:
if (!--argc)
usage(NULL);
- getaddr(RTA_NETMASK, *++argv, 0, nrflags);
+ getaddr(RTAX_NETMASK, *++argv, 0, nrflags);
/* FALLTHROUGH */
case K_NET:
nrflags |= F_FORCENET;
@@ -894,13 +916,13 @@ newroute(int argc, char **argv)
} else {
if ((rtm_addrs & RTA_DST) == 0) {
dest = *argv;
- if (getaddr(RTA_DST, *argv, &hp, nrflags))
+ if (getaddr(RTAX_DST, *argv, &hp, nrflags))
nrflags |= F_ISHOST;
} else if ((rtm_addrs & RTA_GATEWAY) == 0) {
gateway = *argv;
- getaddr(RTA_GATEWAY, *argv, &hp, nrflags);
+ getaddr(RTAX_GATEWAY, *argv, &hp, nrflags);
} else {
- getaddr(RTA_NETMASK, *argv, 0, nrflags);
+ getaddr(RTAX_NETMASK, *argv, 0, nrflags);
nrflags |= F_FORCENET;
}
}
@@ -911,7 +933,7 @@ newroute(int argc, char **argv)
#ifdef INET6
if (af == AF_INET6) {
rtm_addrs &= ~RTA_NETMASK;
- memset((void *)&so_mask, 0, sizeof(so_mask));
+ memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK]));
}
#endif
}
@@ -1034,11 +1056,12 @@ newroute_fib(int fib, char *cmd, int flags)
return (error);
}
+#ifdef INET
static void
-inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits)
+inet_makenetandmask(u_long net, struct sockaddr_in *sin,
+ struct sockaddr_in *sin_mask, u_long bits)
{
u_long mask = 0;
- char *cp;
rtm_addrs |= RTA_NETMASK;
@@ -1055,7 +1078,8 @@ inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits)
*/
if ((bits == 0) && (net != 0)) {
u_long i, j;
- for(i=0,j=0xff; i<4; i++) {
+
+ for(i = 0, j = 0xff; i < 4; i++) {
if (net & j) {
break;
}
@@ -1068,15 +1092,11 @@ inet_makenetandmask(u_long net, struct sockaddr_in *sin, u_long bits)
mask = 0xffffffff << (32 - bits);
sin->sin_addr.s_addr = htonl(net);
- sin = &so_mask.sin;
- sin->sin_addr.s_addr = htonl(mask);
- sin->sin_len = 0;
- sin->sin_family = 0;
- cp = (char *)(&sin->sin_addr + 1);
- while (*--cp == 0 && cp > (char *)sin)
- ;
- sin->sin_len = 1 + cp - (char *)sin;
+ sin_mask->sin_addr.s_addr = htonl(mask);
+ sin_mask->sin_len = sizeof(struct sockaddr_in);
+ sin_mask->sin_family = AF_INET;
}
+#endif
#ifdef INET6
/*
@@ -1113,33 +1133,50 @@ inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen)
* returning 1 if a host address, 0 if a network address.
*/
static int
-getaddr(int which, char *str, struct hostent **hpp, int nrflags)
+getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
{
- sup su;
+ struct sockaddr *sa;
+#if defined(INET)
+ struct sockaddr_in *sin;
struct hostent *hp;
struct netent *np;
u_long val;
char *q;
- int afamily; /* local copy of af so we can change it */
+#elif defined(INET6)
+ char *q;
+#endif
+ if (idx < 0 || idx >= RTAX_MAX)
+ usage("internal error");
if (af == 0) {
+#if defined(INET)
af = AF_INET;
aflen = sizeof(struct sockaddr_in);
+#elif defined(INET6)
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
+#else
+ af = AF_LINK;
+ aflen = sizeof(struct sockaddr_dl);
+#endif
}
- afamily = af;
- rtm_addrs |= which;
- switch (which) {
- case RTA_DST:
- su = &so_dst;
- break;
- case RTA_GATEWAY:
- su = &so_gate;
+#ifndef INET
+ hpp = NULL;
+#endif
+ rtm_addrs |= (1 << idx);
+ sa = (struct sockaddr *)&so[idx];
+ sa->sa_family = af;
+ sa->sa_len = aflen;
+
+ switch (idx) {
+ case RTAX_GATEWAY:
if (nrflags & F_INTERFACE) {
struct ifaddrs *ifap, *ifa;
+ struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa;
struct sockaddr_dl *sdl = NULL;
if (getifaddrs(&ifap))
- err(1, "getifaddrs");
+ err(EX_OSERR, "getifaddrs");
for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family != AF_LINK)
@@ -1148,63 +1185,38 @@ getaddr(int which, char *str, struct hostent **hpp, int nrflags)
if (strcmp(str, ifa->ifa_name) != 0)
continue;
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr;
}
/* If we found it, then use it */
if (sdl != NULL) {
/*
- * Copy is safe since we have a
- * sockaddr_storage member in sockunion{}.
* Note that we need to copy before calling
* freeifaddrs().
*/
- memcpy(&su->sdl, sdl, sdl->sdl_len);
+ memcpy(sdl0, sdl, sdl->sdl_len);
}
freeifaddrs(ifap);
if (sdl != NULL)
return(1);
}
break;
- case RTA_NETMASK:
- su = &so_mask;
+ case RTAX_IFP:
+ sa->sa_family = AF_LINK;
break;
- case RTA_GENMASK:
- su = &so_genmask;
- break;
- case RTA_IFP:
- su = &so_ifp;
- afamily = AF_LINK;
- break;
- case RTA_IFA:
- su = &so_ifa;
- break;
- default:
- usage("internal error");
- /*NOTREACHED*/
}
- su->sa.sa_len = aflen;
- su->sa.sa_family = afamily; /* cases that don't want it have left already */
if (strcmp(str, "default") == 0) {
/*
* Default is net 0.0.0.0/0
*/
- switch (which) {
- case RTA_DST:
+ switch (idx) {
+ case RTAX_DST:
forcenet++;
-#if 0
- bzero(su, sizeof(*su)); /* for readability */
-#endif
- getaddr(RTA_NETMASK, str, 0, nrflags);
+ getaddr(RTAX_NETMASK, str, 0, nrflags);
break;
-#if 0
- case RTA_NETMASK:
- case RTA_GENMASK:
- bzero(su, sizeof(*su)); /* for readability */
-#endif
}
return (0);
}
- switch (afamily) {
+ switch (sa->sa_family) {
#ifdef INET6
case AF_INET6:
{
@@ -1212,89 +1224,93 @@ getaddr(int which, char *str, struct hostent **hpp, int nrflags)
int ecode;
q = NULL;
- if (which == RTA_DST && (q = strchr(str, '/')) != NULL)
+ if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL)
*q = '\0';
memset(&hints, 0, sizeof(hints));
- hints.ai_family = afamily; /*AF_INET6*/
- hints.ai_socktype = SOCK_DGRAM; /*dummy*/
+ hints.ai_family = sa->sa_family;
+ hints.ai_socktype = SOCK_DGRAM;
ecode = getaddrinfo(str, NULL, &hints, &res);
if (ecode != 0 || res->ai_family != AF_INET6 ||
- res->ai_addrlen != sizeof(su->sin6)) {
- (void) fprintf(stderr, "%s: %s\n", str,
- gai_strerror(ecode));
- exit(1);
- }
- memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6));
+ res->ai_addrlen != sizeof(struct sockaddr_in6))
+ errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode));
+ memcpy(sa, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
if (q != NULL)
*q++ = '/';
- if (which == RTA_DST)
- return (inet6_makenetandmask(&su->sin6, q));
+ if (idx == RTAX_DST)
+ return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q));
return (0);
}
#endif /* INET6 */
case AF_APPLETALK:
- if (!atalk_aton(str, &su->sat.sat_addr))
+ {
+ struct sockaddr_at *sat = (struct sockaddr_at *)(void *)sa;
+
+ if (!atalk_aton(str, &sat->sat_addr))
errx(EX_NOHOST, "bad address: %s", str);
rtm_addrs |= RTA_NETMASK;
- return(forcehost || su->sat.sat_addr.s_node != 0);
-
+ return(forcehost || sat->sat_addr.s_node != 0);
+ }
case AF_LINK:
- link_addr(str, &su->sdl);
+ link_addr(str, (struct sockaddr_dl *)(void *)sa);
return (1);
-
case PF_ROUTE:
- su->sa.sa_len = sizeof(*su);
- sockaddr(str, &su->sa);
+ sockaddr(str, sa, sizeof(struct sockaddr_storage));
return (1);
-
+#ifdef INET
case AF_INET:
+#endif
default:
break;
}
+#ifdef INET
+ sin = (struct sockaddr_in *)(void *)sa;
if (hpp == NULL)
hpp = &hp;
*hpp = NULL;
q = strchr(str,'/');
- if (q != NULL && which == RTA_DST) {
+ if (q != NULL && idx == RTAX_DST) {
*q = '\0';
if ((val = inet_network(str)) != INADDR_NONE) {
- inet_makenetandmask(
- val, &su->sin, strtoul(q+1, 0, 0));
+ inet_makenetandmask(val, sin,
+ (struct sockaddr_in *)&so[RTAX_NETMASK],
+ strtoul(q+1, 0, 0));
return (0);
}
*q = '/';
}
- if ((which != RTA_DST || forcenet == 0) &&
- inet_aton(str, &su->sin.sin_addr)) {
- val = su->sin.sin_addr.s_addr;
- if (which != RTA_DST || forcehost ||
- inet_lnaof(su->sin.sin_addr) != INADDR_ANY)
+ if ((idx != RTAX_DST || forcenet == 0) &&
+ inet_aton(str, &sin->sin_addr)) {
+ val = sin->sin_addr.s_addr;
+ if (idx != RTAX_DST || forcehost ||
+ inet_lnaof(sin->sin_addr) != INADDR_ANY)
return (1);
else {
val = ntohl(val);
goto netdone;
}
}
- if (which == RTA_DST && forcehost == 0 &&
+ if (idx == RTAX_DST && forcehost == 0 &&
((val = inet_network(str)) != INADDR_NONE ||
((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) {
netdone:
- inet_makenetandmask(val, &su->sin, 0);
+ inet_makenetandmask(val, sin,
+ (struct sockaddr_in *)&so[RTAX_NETMASK], 0);
return (0);
}
hp = gethostbyname(str);
if (hp != NULL) {
*hpp = hp;
- su->sin.sin_family = hp->h_addrtype;
- memmove((char *)&su->sin.sin_addr, hp->h_addr,
- MIN((size_t)hp->h_length, sizeof(su->sin.sin_addr)));
+ sin->sin_family = hp->h_addrtype;
+ memmove((char *)&sin->sin_addr, hp->h_addr,
+ MIN((size_t)hp->h_length, sizeof(sin->sin_addr)));
return (1);
}
+#endif
errx(EX_NOHOST, "bad address: %s", str);
}
@@ -1309,28 +1325,39 @@ prefixlen(const char *str)
switch (af) {
#ifdef INET6
case AF_INET6:
+ {
+ struct sockaddr_in6 *sin6 =
+ (struct sockaddr_in6 *)&so[RTAX_NETMASK];
+
max = 128;
- p = (char *)&so_mask.sin6.sin6_addr;
+ p = (char *)&sin6->sin6_addr;
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
break;
+ }
#endif
+#ifdef INET
case AF_INET:
+ {
+ struct sockaddr_in *sin =
+ (struct sockaddr_in *)&so[RTAX_NETMASK];
+
max = 32;
- p = (char *)&so_mask.sin.sin_addr;
+ p = (char *)&sin->sin_addr;
+ sin->sin_family = AF_INET;
+ sin->sin_len = sizeof(*sin);
break;
+ }
+#endif
default:
- fprintf(stderr, "prefixlen not supported in this af\n");
- exit(1);
+ errx(EX_OSERR, "prefixlen not supported in this af");
}
- if (len < 0 || max < len) {
- fprintf(stderr, "%s: bad value\n", str);
- exit(1);
- }
+ if (len < 0 || max < len)
+ errx(EX_USAGE, "%s: invalid prefixlen", str);
q = len >> 3;
r = len & 7;
- so_mask.sa.sa_family = af;
- so_mask.sa.sa_len = aflen;
memset((void *)p, 0, max / 8);
if (q > 0)
memset((void *)p, 0xff, q);
@@ -1354,14 +1381,14 @@ retry2:
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
- mib[3] = 0; /* wildcard address family */
+ mib[3] = AF_UNSPEC;
mib[4] = NET_RT_IFLIST;
mib[5] = 0; /* no flags */
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0)
err(EX_OSERR, "route-sysctl-estimate");
if ((buf = malloc(needed)) == NULL)
errx(EX_OSERR, "malloc failed");
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) {
if (errno == ENOMEM && count++ < 10) {
warnx("Routing table grew, retrying");
sleep(1);
@@ -1372,7 +1399,7 @@ retry2:
}
lim = buf + needed;
for (next = buf; next < lim; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
+ rtm = (struct rt_msghdr *)(void *)next;
print_rtmsg(rtm, rtm->rtm_msglen);
}
}
@@ -1421,12 +1448,12 @@ monitor(int argc, char *argv[])
time_t now;
n = read(s, msg, 2048);
now = time(NULL);
- (void) printf("\ngot message of size %d on %s", n, ctime(&now));
- print_rtmsg((struct rt_msghdr *)msg, n);
+ (void)printf("\ngot message of size %d on %s", n, ctime(&now));
+ print_rtmsg((struct rt_msghdr *)(void *)msg, n);
}
}
-struct {
+static struct {
struct rt_msghdr m_rtm;
char m_space[512];
} m_rtmsg;
@@ -1439,10 +1466,16 @@ rtmsg(int cmd, int flags, int fib)
char *cp = m_rtmsg.m_space;
int l;
-#define NEXTADDR(w, u) \
- if (rtm_addrs & (w)) {\
- l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\
- if (verbose) sodump(&(u),#u);\
+#define NEXTADDR(w, u) \
+ if (rtm_addrs & (w)) { \
+ l = (((struct sockaddr *)&(u))->sa_len == 0) ? \
+ sizeof(long) : \
+ 1 + ((((struct sockaddr *)&(u))->sa_len - 1) \
+ | (sizeof(long) - 1)); \
+ memmove(cp, (char *)&(u), l); \
+ cp += l; \
+ if (verbose) \
+ sodump((struct sockaddr *)&(u), #w); \
}
errno = 0;
@@ -1453,9 +1486,9 @@ rtmsg(int cmd, int flags, int fib)
cmd = RTM_CHANGE;
else if (cmd == 'g' || cmd == 's') {
cmd = RTM_GET;
- if (so_ifp.sa.sa_family == 0) {
- so_ifp.sa.sa_family = AF_LINK;
- so_ifp.sa.sa_len = sizeof(struct sockaddr_dl);
+ if (so[RTAX_IFP].ss_family == 0) {
+ so[RTAX_IFP].ss_family = AF_LINK;
+ so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl);
rtm_addrs |= RTA_IFP;
}
} else
@@ -1469,14 +1502,12 @@ rtmsg(int cmd, int flags, int fib)
rtm.rtm_rmx = rt_metrics;
rtm.rtm_inits = rtm_inits;
- if (rtm_addrs & RTA_NETMASK)
- mask_addr();
- NEXTADDR(RTA_DST, so_dst);
- NEXTADDR(RTA_GATEWAY, so_gate);
- NEXTADDR(RTA_NETMASK, so_mask);
- NEXTADDR(RTA_GENMASK, so_genmask);
- NEXTADDR(RTA_IFP, so_ifp);
- NEXTADDR(RTA_IFA, so_ifa);
+ NEXTADDR(RTA_DST, so[RTAX_DST]);
+ NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]);
+ NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]);
+ NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]);
+ NEXTADDR(RTA_IFP, so[RTAX_IFP]);
+ NEXTADDR(RTA_IFA, so[RTAX_IFA]);
rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
if (verbose)
print_rtmsg(&rtm, l);
@@ -1501,38 +1532,7 @@ rtmsg(int cmd, int flags, int fib)
return (0);
}
-static void
-mask_addr(void)
-{
- int olen = so_mask.sa.sa_len;
- char *cp1 = olen + (char *)&so_mask, *cp2;
-
- for (so_mask.sa.sa_len = 0; cp1 > (char *)&so_mask; )
- if (*--cp1 != 0) {
- so_mask.sa.sa_len = 1 + cp1 - (char *)&so_mask;
- break;
- }
- if ((rtm_addrs & RTA_DST) == 0)
- return;
- switch (so_dst.sa.sa_family) {
- case AF_INET:
-#ifdef INET6
- case AF_INET6:
-#endif
- case AF_APPLETALK:
- case 0:
- return;
- }
- cp1 = so_mask.sa.sa_len + 1 + (char *)&so_dst;
- cp2 = so_dst.sa.sa_len + 1 + (char *)&so_dst;
- while (cp2 > cp1)
- *--cp2 = 0;
- cp2 = so_mask.sa.sa_len + 1 + (char *)&so_mask;
- while (cp1 > so_dst.sa.sa_data)
- *--cp1 &= *--cp2;
-}
-
-const char *msgtypes[] = {
+static const char *msgtypes[] = {
"",
"RTM_ADD: Add Route",
"RTM_DELETE: Delete Route",
@@ -1554,23 +1554,23 @@ const char *msgtypes[] = {
"RTM_IEEE80211: IEEE 802.11 wireless event",
};
-char metricnames[] =
-"\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
-"\1mtu";
-char routeflags[] =
-"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
-"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
-"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
-"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
-char ifnetflags[] =
-"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
-"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
-"\017LINK2\020MULTICAST";
-char addrnames[] =
-"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
+static const char metricnames[] =
+ "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"
+ "\1mtu";
+static const char routeflags[] =
+ "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
+ "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
+ "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
+ "\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
+static const char ifnetflags[] =
+ "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
+ "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
+ "\017LINK2\020MULTICAST";
+static const char addrnames[] =
+ "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD";
static const char errfmt[] =
-"\n%s: truncated route message, only %zu bytes left\n";
+ "\n%s: truncated route message, only %zu bytes left\n";
static void
print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
@@ -1586,11 +1586,11 @@ print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
if (verbose == 0)
return;
if (rtm->rtm_version != RTM_VERSION) {
- (void) printf("routing message version %d not understood\n",
+ (void)printf("routing message version %d not understood\n",
rtm->rtm_version);
return;
}
- if (rtm->rtm_type < sizeof(msgtypes) / sizeof(msgtypes[0]))
+ if (rtm->rtm_type < nitems(msgtypes))
(void)printf("%s: ", msgtypes[rtm->rtm_type]);
else
(void)printf("unknown type %d: ", rtm->rtm_type);
@@ -1607,7 +1607,7 @@ print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
case RTM_IFINFO:
REQUIRE(struct if_msghdr);
ifm = (struct if_msghdr *)rtm;
- (void) printf("if# %d, ", ifm->ifm_index);
+ (void)printf("if# %d, ", ifm->ifm_index);
switch (ifm->ifm_data.ifi_link_state) {
case LINK_STATE_DOWN:
state = "down";
@@ -1619,16 +1619,16 @@ print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
state = "unknown";
break;
}
- (void) printf("link: %s, flags:", state);
- bprintf(stdout, ifm->ifm_flags, ifnetflags);
+ (void)printf("link: %s, flags:", state);
+ printb(ifm->ifm_flags, ifnetflags);
pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen);
break;
case RTM_NEWADDR:
case RTM_DELADDR:
REQUIRE(struct ifa_msghdr);
ifam = (struct ifa_msghdr *)rtm;
- (void) printf("metric %d, flags:", ifam->ifam_metric);
- bprintf(stdout, ifam->ifam_flags, routeflags);
+ (void)printf("metric %d, flags:", ifam->ifam_metric);
+ printb(ifam->ifam_flags, routeflags);
pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen);
break;
#ifdef RTM_NEWMADDR
@@ -1642,10 +1642,10 @@ print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
case RTM_IFANNOUNCE:
REQUIRE(struct if_announcemsghdr);
ifan = (struct if_announcemsghdr *)rtm;
- (void) printf("if# %d, what: ", ifan->ifan_index);
+ (void)printf("if# %d, what: ", ifan->ifan_index);
switch (ifan->ifan_what) {
case IFAN_ARRIVAL:
- printf("arrival");
+ (void)printf("arrival");
break;
case IFAN_DEPARTURE:
printf("departure");
@@ -1659,9 +1659,9 @@ print_rtmsg(struct rt_msghdr *rtm, size_t msglen)
break;
default:
- (void) printf("pid: %ld, seq %d, errno %d, flags:",
+ printf("pid: %ld, seq %d, errno %d, flags:",
(long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno);
- bprintf(stdout, rtm->rtm_flags, routeflags);
+ printb(rtm->rtm_flags, routeflags);
pmsg_common(rtm, msglen);
}
@@ -1675,14 +1675,13 @@ badlen:
static void
print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
{
- struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL;
- struct sockaddr_dl *ifp = NULL;
- struct sockaddr *sa;
+ struct sockaddr *sp[RTAX_MAX];
char *cp;
int i;
- (void) printf(" route to: %s\n",
- routename((struct sockaddr *)&so_dst));
+ memset(sp, 0, sizeof(sp));
+ (void)printf(" route to: %s\n",
+ routename((struct sockaddr *)&so[RTAX_DST]));
if (rtm->rtm_version != RTM_VERSION) {
warnx("routing message version %d not understood",
rtm->rtm_version);
@@ -1691,6 +1690,7 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
if (rtm->rtm_msglen > msglen) {
warnx("message length mismatch, in packet %d, returned %d",
rtm->rtm_msglen, msglen);
+ return;
}
if (rtm->rtm_errno) {
errno = rtm->rtm_errno;
@@ -1698,54 +1698,36 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
return;
}
cp = ((char *)(rtm + 1));
- if (rtm->rtm_addrs)
- for (i = 1; i; i <<= 1)
- if (i & rtm->rtm_addrs) {
- sa = (struct sockaddr *)cp;
- switch (i) {
- case RTA_DST:
- dst = sa;
- break;
- case RTA_GATEWAY:
- gate = sa;
- break;
- case RTA_NETMASK:
- mask = sa;
- break;
- case RTA_IFP:
- if (sa->sa_family == AF_LINK &&
- ((struct sockaddr_dl *)sa)->sdl_nlen)
- ifp = (struct sockaddr_dl *)sa;
- break;
- }
- cp += SA_SIZE(sa);
- }
- if (dst && mask)
- mask->sa_family = dst->sa_family; /* XXX */
- if (dst)
- (void)printf("destination: %s\n", routename(dst));
- if (mask) {
- int savenflag = nflag;
-
- nflag = 1;
- (void)printf(" mask: %s\n", routename(mask));
- nflag = savenflag;
- }
- if (gate && rtm->rtm_flags & RTF_GATEWAY)
- (void)printf(" gateway: %s\n", routename(gate));
+ for (i = 0; i < RTAX_MAX; i++)
+ if (rtm->rtm_addrs & (1 << i)) {
+ sp[i] = (struct sockaddr *)cp;
+ cp += SA_SIZE((struct sockaddr *)cp);
+ }
+ if ((rtm->rtm_addrs & RTA_IFP) &&
+ (sp[RTAX_IFP]->sa_family != AF_LINK ||
+ ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0))
+ sp[RTAX_IFP] = NULL;
+ if (sp[RTAX_DST] && sp[RTAX_NETMASK])
+ sp[RTAX_NETMASK]->sa_family = sp[RTAX_DST]->sa_family; /* XXX */
+ if (sp[RTAX_DST])
+ (void)printf("destination: %s\n", routename(sp[RTAX_DST]));
+ if (sp[RTAX_NETMASK])
+ (void)printf(" mask: %s\n", routename(sp[RTAX_NETMASK]));
+ if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY))
+ (void)printf(" gateway: %s\n", routename(sp[RTAX_GATEWAY]));
if (fib >= 0)
(void)printf(" fib: %u\n", (unsigned int)fib);
- if (ifp)
+ if (sp[RTAX_IFP])
(void)printf(" interface: %.*s\n",
- ifp->sdl_nlen, ifp->sdl_data);
+ ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen,
+ ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data);
(void)printf(" flags: ");
- bprintf(stdout, rtm->rtm_flags, routeflags);
+ printb(rtm->rtm_flags, routeflags);
#define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ')
#define msec(u) (((u) + 500) / 1000) /* usec to msec */
-
- (void) printf("\n%s\n", "\
- recvpipe sendpipe ssthresh rtt,msec mtu weight expire");
+ printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe",
+ "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire");
printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
@@ -1761,8 +1743,8 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
if (verbose)
pmsg_common(rtm, msglen);
else if (rtm->rtm_addrs &~ RTA_IGN) {
- (void) printf("sockaddrs: ");
- bprintf(stdout, rtm->rtm_addrs, addrnames);
+ (void)printf("sockaddrs: ");
+ printb(rtm->rtm_addrs, addrnames);
putchar('\n');
}
#undef RTA_IGN
@@ -1771,15 +1753,16 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
static void
pmsg_common(struct rt_msghdr *rtm, size_t msglen)
{
- (void) printf("\nlocks: ");
- bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames);
- (void) printf(" inits: ");
- bprintf(stdout, rtm->rtm_inits, metricnames);
+
+ (void)printf("\nlocks: ");
+ printb(rtm->rtm_rmx.rmx_locks, metricnames);
+ (void)printf(" inits: ");
+ printb(rtm->rtm_inits, metricnames);
if (msglen > sizeof(struct rt_msghdr))
pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs,
msglen - sizeof(struct rt_msghdr));
else
- (void) fflush(stdout);
+ (void)fflush(stdout);
}
static void
@@ -1789,29 +1772,29 @@ pmsg_addrs(char *cp, int addrs, size_t len)
int i;
if (addrs == 0) {
- (void) putchar('\n');
+ (void)putchar('\n');
return;
}
- (void) printf("\nsockaddrs: ");
- bprintf(stdout, addrs, addrnames);
- (void) putchar('\n');
- for (i = 1; i != 0; i <<= 1)
- if (i & addrs) {
+ (void)printf("\nsockaddrs: ");
+ printb(addrs, addrnames);
+ putchar('\n');
+ for (i = 0; i < RTAX_MAX; i++)
+ if (addrs & (1 << i)) {
sa = (struct sockaddr *)cp;
if (len == 0 || len < SA_SIZE(sa)) {
- (void) printf(errfmt, __func__, len);
+ (void)printf(errfmt, __func__, len);
break;
}
- (void) printf(" %s", routename(sa));
+ (void)printf(" %s", routename(sa));
len -= SA_SIZE(sa);
cp += SA_SIZE(sa);
}
- (void) putchar('\n');
- (void) fflush(stdout);
+ (void)putchar('\n');
+ (void)fflush(stdout);
}
static void
-bprintf(FILE *fp, int b, u_char *str)
+printb(int b, const char *str)
{
int i;
int gotsome = 0;
@@ -1824,16 +1807,16 @@ bprintf(FILE *fp, int b, u_char *str)
i = '<';
else
i = ',';
- (void) putc(i, fp);
+ putchar(i);
gotsome = 1;
for (; (i = *str) > 32; str++)
- (void) putc(i, fp);
+ putchar(i);
} else
while (*str > 32)
str++;
}
if (gotsome)
- (void) putc('>', fp);
+ putchar('>');
}
int
@@ -1847,23 +1830,36 @@ keyword(const char *cp)
}
static void
-sodump(sup su, const char *which)
+sodump(struct sockaddr *sa, const char *which)
{
- switch (su->sa.sa_family) {
+#ifdef INET6
+ char nbuf[INET6_ADDRSTRLEN];
+#endif
+
+ switch (sa->sa_family) {
case AF_LINK:
- (void) printf("%s: link %s; ",
- which, link_ntoa(&su->sdl));
+ (void)printf("%s: link %s; ", which,
+ link_ntoa((struct sockaddr_dl *)(void *)sa));
break;
+#ifdef INET
case AF_INET:
- (void) printf("%s: inet %s; ",
- which, inet_ntoa(su->sin.sin_addr));
+ (void)printf("%s: inet %s; ", which,
+ inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr));
break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ (void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family,
+ &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf,
+ sizeof(nbuf)));
+ break;
+#endif
case AF_APPLETALK:
- (void) printf("%s: atalk %s; ",
- which, atalk_ntoa(su->sat.sat_addr));
+ (void)printf("%s: atalk %s; ", which,
+ atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr));
break;
}
- (void) fflush(stdout);
+ (void)fflush(stdout);
}
/* States*/
@@ -1876,10 +1872,9 @@ sodump(sup su, const char *which)
#define DELIM (4*2)
static void
-sockaddr(char *addr, struct sockaddr *sa)
+sockaddr(char *addr, struct sockaddr *sa, size_t size)
{
char *cp = (char *)sa;
- int size = sa->sa_len;
char *cplim = cp + size;
int byte = 0, state = VIRGIN, new = 0 /* foil gcc */;
@@ -1935,6 +1930,7 @@ atalk_ntoa(struct at_addr at)
{
static char buf[20];
- (void) snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
+ (void)snprintf(buf, sizeof(buf), "%u.%u", ntohs(at.s_net), at.s_node);
+ buf[sizeof(buf) - 1] = '\0';
return(buf);
}
diff --git a/sbin/routed/routed.8 b/sbin/routed/routed.8
index 570e20b..2f8a021 100644
--- a/sbin/routed/routed.8
+++ b/sbin/routed/routed.8
@@ -576,7 +576,7 @@ Incoming packets can carry any password that is valid, will
be valid within the next 24 hours, or that was valid within the preceding
24 hours.
To protect the secrets, the passwd settings are valid only in the
-.Em /etc/gateways
+.Pa /etc/gateways
file and only when that file is readable only by UID 0.
.It Cm md5_passwd Ns \&= Ns Ar XXX|KeyID[start|stop]
specifies a RIPv2 MD5 password.
diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8
index 5602a9a..ec2ad72 100644
--- a/sbin/swapon/swapon.8
+++ b/sbin/swapon/swapon.8
@@ -28,7 +28,7 @@
.\" @(#)swapon.8 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd June 23, 2008
+.Dd June 21, 2013
.Dt SWAPON 8
.Os
.Sh NAME
@@ -38,11 +38,11 @@
.Nm swapon
.Oo Fl F Ar fstab
.Oc
-.Fl aq | Ar
+.Fl aLq | Ar
.Nm swapoff
.Oo Fl F Ar fstab
.Oc
-.Fl aq | Ar
+.Fl aLq | Ar
.Nm swapctl
.Op Fl AghklmsU
.Oo
@@ -74,10 +74,19 @@ option is used, all swap devices in
.Pa /etc/fstab
will be added, unless their
.Dq noauto
+or
+.Dq late
option is also set.
If the
+.Fl L
+option is specified,
+swap devices with the
+.Dq late
+option will be added as well as ones with no option.
+If the
.Fl q
-option is used informational messages will not be
+option is used,
+informational messages will not be
written to standard output when a swap device is added.
.Pp
The
@@ -89,10 +98,19 @@ option is used, all swap devices in
.Pa /etc/fstab
will be removed, unless their
.Dq noauto
+or
+.Dq late
option is also set.
If the
+.Fl L
+option is specified,
+swap devices with the
+.Dq late
+option will be removed as well as ones with no option.
+If the
.Fl q
-option is used informational messages will not be
+option is used,
+informational messages will not be
written to standard output when a swap device is removed.
Note that
.Nm swapoff
diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c
index 5b9a0ed..d93277c 100644
--- a/sbin/swapon/swapon.c
+++ b/sbin/swapon/swapon.c
@@ -41,35 +41,51 @@ static char sccsid[] = "@(#)swapon.c 8.1 (Berkeley) 6/5/93";
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/stat.h>
#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/mdioctl.h>
+#include <sys/stat.h>
#include <sys/sysctl.h>
+#include <sys/wait.h>
#include <vm/vm_param.h>
#include <err.h>
#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
#include <fstab.h>
+#include <libgen.h>
+#include <libutil.h>
+#include <limits.h>
+#include <paths.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <fcntl.h>
-#include <libutil.h>
static void usage(void);
-static int swap_on_off(char *name, int ignoreebusy);
+static const char *swap_on_off(const char *, int, char *);
+static const char *swap_on_off_gbde(const char *, int);
+static const char *swap_on_off_geli(const char *, char *, int);
+static const char *swap_on_off_md(const char *, char *, int);
+static const char *swap_on_off_sfile(const char *, int);
static void swaplist(int, int, int);
+static int run_cmd(int *, const char *, ...) __printflike(2, 3);
static enum { SWAPON, SWAPOFF, SWAPCTL } orig_prog, which_prog = SWAPCTL;
+static int qflag;
+
int
main(int argc, char **argv)
{
struct fstab *fsp;
+ const char *swfile;
char *ptr;
int ret;
int ch, doall;
- int sflag = 0, lflag = 0, hflag = 0, qflag = 0;
+ int sflag = 0, lflag = 0, late = 0, hflag = 0;
const char *etc_fstab;
if ((ptr = strrchr(argv[0], '/')) == NULL)
@@ -82,7 +98,7 @@ main(int argc, char **argv)
doall = 0;
etc_fstab = NULL;
- while ((ch = getopt(argc, argv, "AadghklmqsUF:")) != -1) {
+ while ((ch = getopt(argc, argv, "AadghklLmqsUF:")) != -1) {
switch(ch) {
case 'A':
if (which_prog == SWAPCTL) {
@@ -116,6 +132,9 @@ main(int argc, char **argv)
case 'l':
lflag = 1;
break;
+ case 'L':
+ late = 1;
+ break;
case 'm':
hflag = 'M';
break;
@@ -145,6 +164,7 @@ main(int argc, char **argv)
argv += optind;
ret = 0;
+ swfile = NULL;
if (etc_fstab != NULL)
setfstab(etc_fstab);
if (which_prog == SWAPON || which_prog == SWAPOFF) {
@@ -154,27 +174,37 @@ main(int argc, char **argv)
continue;
if (strstr(fsp->fs_mntops, "noauto"))
continue;
- if (swap_on_off(fsp->fs_spec, 1)) {
+ if (which_prog != SWAPOFF &&
+ strstr(fsp->fs_mntops, "late") &&
+ !late)
+ continue;
+ swfile = swap_on_off(fsp->fs_spec, 1,
+ fsp->fs_mntops);
+ if (swfile == NULL) {
ret = 1;
- } else {
- if (!qflag) {
- printf("%s: %sing %s as swap device\n",
- getprogname(),
- which_prog == SWAPOFF ? "remov" : "add",
- fsp->fs_spec);
- }
+ continue;
+ }
+ if (!qflag) {
+ printf("%s: %sing %s as swap device\n",
+ getprogname(),
+ (which_prog == SWAPOFF) ?
+ "remov" : "add", swfile);
}
}
}
else if (!*argv)
usage();
for (; *argv; ++argv) {
- if (swap_on_off(*argv, 0)) {
+ swfile = swap_on_off(*argv, 0, NULL);
+ if (swfile == NULL) {
ret = 1;
- } else if (orig_prog == SWAPCTL) {
+ continue;
+ }
+ if (orig_prog == SWAPCTL) {
printf("%s: %sing %s as swap device\n",
- getprogname(), which_prog == SWAPOFF ? "remov" : "add",
- *argv);
+ getprogname(),
+ (which_prog == SWAPOFF) ? "remov" : "add",
+ swfile);
}
}
} else {
@@ -186,14 +216,511 @@ main(int argc, char **argv)
exit(ret);
}
+static const char *
+swap_on_off(const char *name, int doingall, char *mntops)
+{
+ char base[PATH_MAX];
+
+ /* Swap on vnode-backed md(4) device. */
+ if (mntops != NULL &&
+ (fnmatch(_PATH_DEV MD_NAME "[0-9]*", name, 0) == 0 ||
+ fnmatch(MD_NAME "[0-9]*", name, 0) == 0 ||
+ strncmp(_PATH_DEV MD_NAME, name,
+ sizeof(_PATH_DEV) + sizeof(MD_NAME)) == 0 ||
+ strncmp(MD_NAME, name, sizeof(MD_NAME)) == 0))
+ return (swap_on_off_md(name, mntops, doingall));
+
+ basename_r(name, base);
+
+ /* Swap on encrypted device by GEOM_BDE. */
+ if (fnmatch("*.bde", base, 0) == 0)
+ return (swap_on_off_gbde(name, doingall));
+
+ /* Swap on encrypted device by GEOM_ELI. */
+ if (fnmatch("*.eli", base, 0) == 0)
+ return (swap_on_off_geli(name, mntops, doingall));
+
+ /* Swap on special file. */
+ return (swap_on_off_sfile(name, doingall));
+}
+
+/* Strip off .bde or .eli suffix from swap device name */
+static char *
+swap_basename(const char *name)
+{
+ char *dname, *p;
+
+ dname = strdup(name);
+ p = strrchr(dname, '.');
+ /* assert(p != NULL); */
+ *p = '\0';
+
+ return (dname);
+}
+
+static const char *
+swap_on_off_gbde(const char *name, int doingall)
+{
+ const char *ret;
+ char pass[64 * 2 + 1], bpass[64];
+ char *dname;
+ int i, error;
+
+ dname = swap_basename(name);
+ if (dname == NULL)
+ return (NULL);
+
+ if (which_prog == SWAPON) {
+ arc4random_buf(bpass, sizeof(bpass));
+ for (i = 0; i < (int)sizeof(bpass); i++)
+ sprintf(&pass[2 * i], "%02x", bpass[i]);
+ pass[sizeof(pass) - 1] = '\0';
+
+ error = run_cmd(NULL, "%s init %s -P %s", _PATH_GBDE,
+ dname, pass);
+ if (error) {
+ /* bde device found. Ignore it. */
+ free(dname);
+ if (!qflag)
+ warnx("%s: Device already in use", name);
+ return (NULL);
+ }
+ error = run_cmd(NULL, "%s attach %s -p %s", _PATH_GBDE,
+ dname, pass);
+ free(dname);
+ if (error) {
+ warnx("gbde (attach) error: %s", name);
+ return (NULL);
+ }
+ }
+
+ ret = swap_on_off_sfile(name, doingall);
+
+ if (which_prog == SWAPOFF) {
+ error = run_cmd(NULL, "%s detach %s", _PATH_GBDE, dname);
+ free(dname);
+ if (error) {
+ /* bde device not found. Ignore it. */
+ if (!qflag)
+ warnx("%s: Device not found", name);
+ return (NULL);
+ }
+ }
+
+ return (ret);
+}
+
+/* Build geli(8) arguments from mntops */
+static char *
+swap_on_geli_args(const char *mntops)
+{
+ const char *aalgo, *ealgo, *keylen_str, *sectorsize_str;
+ const char *aflag, *eflag, *lflag, *sflag;
+ char *p;
+ char *args;
+ char *token, *string, *ops;
+ int argsize, pagesize;
+ size_t pagesize_len;
+ u_long ul;
+
+ /* Use built-in defaults for geli(8) */
+ aalgo = ealgo = keylen_str = "";
+ aflag = eflag = lflag = "";
+
+ /* We will always specify sectorsize */
+ sflag = " -s ";
+ sectorsize_str = NULL;
+
+ if (mntops != NULL) {
+ string = ops = strdup(mntops);
+
+ while ((token = strsep(&string, ",")) != NULL) {
+ if ((p = strstr(token, "aalgo=")) == token) {
+ aalgo = p + sizeof("aalgo=") - 1;
+ aflag = " -a ";
+ } else if ((p = strstr(token, "ealgo=")) == token) {
+ ealgo = p + sizeof("ealgo=") - 1;
+ eflag = " -e ";
+ } else if ((p = strstr(token, "keylen=")) == token) {
+ keylen_str = p + sizeof("keylen=") - 1;
+ errno = 0;
+ ul = strtoul(keylen_str, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("Invalid keylen: %s", keylen_str);
+ free(ops);
+ return (NULL);
+ }
+ lflag = " -l ";
+ } else if ((p = strstr(token, "sectorsize=")) == token) {
+ sectorsize_str = p + sizeof("sectorsize=") - 1;
+ errno = 0;
+ ul = strtoul(sectorsize_str, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("Invalid sectorsize: %s", sectorsize_str);
+ free(ops);
+ return (NULL);
+ }
+ } else if (strcmp(token, "sw") != 0) {
+ warnx("Invalid option: %s", token);
+ free(ops);
+ return (NULL);
+ }
+ }
+ } else
+ ops = NULL;
+
+ /*
+ * If we do not have a sector size at this point, fill in
+ * pagesize as sector size.
+ */
+ if (sectorsize_str == NULL) {
+ /* Use pagesize as default sectorsize */
+ pagesize = getpagesize();
+ pagesize_len = snprintf(NULL, 0, "%d", pagesize) + 1;
+ p = alloca(pagesize_len);
+ snprintf(p, pagesize_len, "%d", pagesize);
+ sectorsize_str = p;
+ }
+
+ argsize = asprintf(&args, "%s%s%s%s%s%s%s%s -d",
+ aflag, aalgo, eflag, ealgo, lflag, keylen_str,
+ sflag, sectorsize_str);
+
+ free(ops);
+ return (args);
+}
+
+static const char *
+swap_on_off_geli(const char *name, char *mntops, int doingall)
+{
+ char *dname;
+ char *args;
+ struct stat sb;
+ int error;
+
+ error = stat(name, &sb);
+
+ if (which_prog == SWAPON) do {
+ /* Skip if the .eli device already exists */
+ if (error == 0)
+ break;
+
+ args = swap_on_geli_args(mntops);
+ if (args == NULL)
+ return (NULL);
+
+ dname = swap_basename(name);
+ if (dname == NULL) {
+ free(args);
+ return (NULL);
+ }
+
+ error = run_cmd(NULL, "%s onetime%s %s", _PATH_GELI, args,
+ dname);
+
+ free(dname);
+ free(args);
+
+ if (error) {
+ /* error occured during creation */
+ if (!qflag)
+ warnx("%s: Invalid parameters", name);
+ return (NULL);
+ }
+ } while (0);
+
+ return (swap_on_off_sfile(name, doingall));
+}
+
+static const char *
+swap_on_off_md(const char *name, char *mntops, int doingall)
+{
+ FILE *sfd;
+ int fd, mdunit, error;
+ const char *ret;
+ static char mdpath[PATH_MAX], linebuf[PATH_MAX];
+ char *p, *vnodefile;
+ size_t linelen;
+ u_long ul;
+
+ fd = -1;
+ sfd = NULL;
+ if (strlen(name) == (sizeof(MD_NAME) - 1))
+ mdunit = -1;
+ else {
+ errno = 0;
+ ul = strtoul(name + 2, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("Bad device unit: %s", name);
+ return (NULL);
+ }
+ mdunit = (int)ul;
+ }
+
+ vnodefile = NULL;
+ if ((p = strstr(mntops, "file=")) != NULL) {
+ vnodefile = strdup(p + sizeof("file=") - 1);
+ p = strchr(vnodefile, ',');
+ if (p != NULL)
+ *p = '\0';
+ }
+ if (vnodefile == NULL) {
+ warnx("file option not found for %s", name);
+ return (NULL);
+ }
+
+ if (which_prog == SWAPON) {
+ if (mdunit == -1) {
+ error = run_cmd(&fd, "%s -l -n -f %s",
+ _PATH_MDCONFIG, vnodefile);
+ if (error == 0) {
+ /* md device found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("%s: Device already in use",
+ vnodefile);
+ free(vnodefile);
+ return (NULL);
+ }
+ error = run_cmd(&fd, "%s -a -t vnode -n -f %s",
+ _PATH_MDCONFIG, vnodefile);
+ if (error) {
+ warnx("mdconfig (attach) error: file=%s",
+ vnodefile);
+ free(vnodefile);
+ return (NULL);
+ }
+ sfd = fdopen(fd, "r");
+ if (sfd == NULL) {
+ warn("mdconfig (attach) fdopen error");
+ ret = NULL;
+ goto err;
+ }
+ p = fgetln(sfd, &linelen);
+ if (p == NULL &&
+ (linelen < 2 || linelen > sizeof(linebuf))) {
+ warn("mdconfig (attach) unexpected output");
+ ret = NULL;
+ goto err;
+ }
+ strncpy(linebuf, p, linelen);
+ linebuf[linelen - 1] = '\0';
+ errno = 0;
+ ul = strtoul(linebuf, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("mdconfig (attach) unexpected output: %s",
+ linebuf);
+ ret = NULL;
+ goto err;
+ }
+ mdunit = (int)ul;
+ } else {
+ error = run_cmd(&fd, "%s -l -n -f %s -u %d",
+ _PATH_MDCONFIG, vnodefile, mdunit);
+ if (error == 0) {
+ /* md device found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("md%d on %s: Device already "
+ "in use", mdunit, vnodefile);
+ free(vnodefile);
+ return (NULL);
+ }
+ error = run_cmd(NULL, "%s -a -t vnode -u %d -f %s",
+ _PATH_MDCONFIG, mdunit, vnodefile);
+ if (error) {
+ warnx("mdconfig (attach) error: "
+ "md%d on file=%s", mdunit, vnodefile);
+ free(vnodefile);
+ return (NULL);
+ }
+ }
+ } else /* SWAPOFF */ {
+ if (mdunit == -1) {
+ error = run_cmd(&fd, "%s -l -n -f %s",
+ _PATH_MDCONFIG, vnodefile);
+ if (error) {
+ /* md device not found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("md on %s: Device not found",
+ vnodefile);
+ free(vnodefile);
+ return (NULL);
+ }
+ sfd = fdopen(fd, "r");
+ if (sfd == NULL) {
+ warn("mdconfig (list) fdopen error");
+ ret = NULL;
+ goto err;
+ }
+ p = fgetln(sfd, &linelen);
+ if (p == NULL &&
+ (linelen < 2 || linelen > sizeof(linebuf) - 1)) {
+ warn("mdconfig (list) unexpected output");
+ ret = NULL;
+ goto err;
+ }
+ strncpy(linebuf, p, linelen);
+ linebuf[linelen - 1] = '\0';
+ p = strchr(linebuf, ' ');
+ if (p != NULL)
+ *p = '\0';
+ errno = 0;
+ ul = strtoul(linebuf, &p, 10);
+ if (errno == 0) {
+ if (*p != '\0' || ul > INT_MAX)
+ errno = EINVAL;
+ }
+ if (errno) {
+ warn("mdconfig (list) unexpected output: %s",
+ linebuf);
+ ret = NULL;
+ goto err;
+ }
+ mdunit = (int)ul;
+ } else {
+ error = run_cmd(&fd, "%s -l -n -f %s -u %d",
+ _PATH_MDCONFIG, vnodefile, mdunit);
+ if (error) {
+ /* md device not found. Ignore it. */
+ close(fd);
+ if (!qflag)
+ warnx("md%d on %s: Device not found",
+ mdunit, vnodefile);
+ free(vnodefile);
+ return (NULL);
+ }
+ }
+ }
+ snprintf(mdpath, sizeof(mdpath), "%s%s%d", _PATH_DEV,
+ MD_NAME, mdunit);
+ mdpath[sizeof(mdpath) - 1] = '\0';
+ ret = swap_on_off_sfile(mdpath, doingall);
+
+ if (which_prog == SWAPOFF) {
+ if (ret != NULL) {
+ error = run_cmd(NULL, "%s -d -u %d",
+ _PATH_MDCONFIG, mdunit);
+ if (error)
+ warn("mdconfig (detach) detach failed: %s%s%d",
+ _PATH_DEV, MD_NAME, mdunit);
+ }
+ }
+err:
+ if (sfd != NULL)
+ fclose(sfd);
+ if (fd != -1)
+ close(fd);
+ free(vnodefile);
+ return (ret);
+}
+
static int
-swap_on_off(char *name, int doingall)
+run_cmd(int *ofd, const char *cmdline, ...)
{
- if ((which_prog == SWAPOFF ? swapoff(name) : swapon(name)) == -1) {
+ va_list ap;
+ char **argv, **argvp, *cmd, *p;
+ int argc, pid, status, rv;
+ int pfd[2], nfd, dup2dn;
+
+ va_start(ap, cmdline);
+ rv = vasprintf(&cmd, cmdline, ap);
+ if (rv == -1) {
+ warn("%s", __func__);
+ return (rv);
+ }
+ va_end(ap);
+
+ for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++)
+ argc++;
+ argv = (char **)malloc(sizeof(*argv) * (argc + 1));
+ for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;)
+ if (**argvp != '\0' && (++argvp > &argv[argc])) {
+ *argvp = NULL;
+ break;
+ }
+ /* The argv array ends up NULL-terminated here. */
+#if 0
+ {
+ int i;
+
+ fprintf(stderr, "DEBUG: running:");
+ /* Should be equivalent to 'cmd' (before strsep, of course). */
+ for (i = 0; argv[i] != NULL; i++)
+ fprintf(stderr, " %s", argv[i]);
+ fprintf(stderr, "\n");
+ }
+#endif
+ dup2dn = 1;
+ if (ofd != NULL) {
+ if (pipe(&pfd[0]) == -1) {
+ warn("%s: pipe", __func__);
+ return (-1);
+ }
+ *ofd = pfd[0];
+ dup2dn = 0;
+ }
+ pid = fork();
+ switch (pid) {
+ case 0:
+ /* Child process. */
+ if (ofd != NULL)
+ if (dup2(pfd[1], STDOUT_FILENO) < 0)
+ err(1, "dup2 in %s", __func__);
+ nfd = open(_PATH_DEVNULL, O_RDWR);
+ if (nfd == -1)
+ err(1, "%s: open %s", __func__, _PATH_DEVNULL);
+ if (dup2(nfd, STDIN_FILENO) < 0)
+ err(1, "%s: dup2", __func__);
+ if (dup2dn && dup2(nfd, STDOUT_FILENO) < 0)
+ err(1, "%s: dup2", __func__);
+ if (dup2(nfd, STDERR_FILENO) < 0)
+ err(1, "%s: dup2", __func__);
+ execv(argv[0], argv);
+ warn("exec: %s", argv[0]);
+ _exit(-1);
+ case -1:
+ err(1, "%s: fork", __func__);
+ }
+ free(cmd);
+ free(argv);
+ while (waitpid(pid, &status, 0) != pid)
+ ;
+ return (WEXITSTATUS(status));
+}
+
+static const char *
+swap_on_off_sfile(const char *name, int doingall)
+{
+ int error;
+
+ if (which_prog == SWAPON)
+ error = swapon(name);
+ else /* SWAPOFF */
+ error = swapoff(name);
+
+ if (error == -1) {
switch (errno) {
case EBUSY:
if (!doingall)
- warnx("%s: device already in use", name);
+ warnx("%s: Device already in use", name);
break;
case EINVAL:
if (which_prog == SWAPON)
@@ -205,9 +732,9 @@ swap_on_off(char *name, int doingall)
warn("%s", name);
break;
}
- return(1);
+ return (NULL);
}
- return(0);
+ return (name);
}
static void
@@ -217,7 +744,7 @@ usage(void)
switch(orig_prog) {
case SWAPON:
case SWAPOFF:
- fprintf(stderr, "[-F fstab] -aq | file ...\n");
+ fprintf(stderr, "[-F fstab] -aLq | file ...\n");
break;
case SWAPCTL:
fprintf(stderr, "[-AghklmsU] [-a file ... | -d file ...]\n");
diff --git a/sbin/tunefs/tunefs.c b/sbin/tunefs/tunefs.c
index 0671d1d..15c6cf0 100644
--- a/sbin/tunefs/tunefs.c
+++ b/sbin/tunefs/tunefs.c
@@ -84,8 +84,8 @@ static void sbdirty(void);
int
main(int argc, char *argv[])
{
- char *avalue, *jvalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue;
- char *tvalue;
+ const char *avalue, *jvalue, *Jvalue, *Lvalue, *lvalue, *Nvalue, *nvalue;
+ const char *tvalue;
const char *special, *on;
const char *name;
int active;
@@ -174,7 +174,7 @@ main(int argc, char *argv[])
found_arg = 1;
name = "space to hold for metadata blocks";
kvalue = atoi(optarg);
- if (mvalue < 0)
+ if (kvalue < 0)
errx(10, "bad %s (%s)", name, optarg);
kflag = 1;
break;
@@ -711,7 +711,7 @@ journal_findfile(void)
}
static void
-dir_clear_block(char *block, off_t off)
+dir_clear_block(const char *block, off_t off)
{
struct direct *dp;
OpenPOWER on IntegriCloud