summaryrefslogtreecommitdiffstats
path: root/sbin
diff options
context:
space:
mode:
Diffstat (limited to 'sbin')
-rw-r--r--sbin/Makefile12
-rw-r--r--sbin/camcontrol/camcontrol.85
-rw-r--r--sbin/camcontrol/camcontrol.c116
-rw-r--r--sbin/camcontrol/modeedit.c4
-rw-r--r--sbin/casperd/Makefile18
-rw-r--r--sbin/casperd/casperd.8126
-rw-r--r--sbin/casperd/casperd.c715
-rw-r--r--sbin/casperd/zygote.c229
-rw-r--r--sbin/casperd/zygote.h40
-rw-r--r--sbin/devd/devd.84
-rw-r--r--sbin/devd/devd.cc65
-rw-r--r--sbin/dhclient/Makefile6
-rw-r--r--sbin/dhclient/bpf.c6
-rw-r--r--sbin/dhclient/dhclient.c8
-rw-r--r--sbin/dhclient/tests/Makefile15
-rw-r--r--sbin/dhclient/tests/fake.c64
-rw-r--r--sbin/dhclient/tests/option-domain-search.c328
-rw-r--r--sbin/etherswitchcfg/etherswitchcfg.840
-rw-r--r--sbin/fdisk/fdisk.c10
-rw-r--r--sbin/fsck_ffs/Makefile3
-rw-r--r--sbin/fsck_ffs/dir.c11
-rw-r--r--sbin/fsck_ffs/ea.c2
-rw-r--r--sbin/fsck_ffs/fsck.h140
-rw-r--r--sbin/fsck_ffs/fsck_ffs.87
-rw-r--r--sbin/fsck_ffs/fsutil.c37
-rw-r--r--sbin/fsck_ffs/globs.c165
-rw-r--r--sbin/fsck_ffs/main.c35
-rw-r--r--sbin/fsck_ffs/pass1.c5
-rw-r--r--sbin/fsck_ffs/pass1b.c8
-rw-r--r--sbin/fsck_ffs/suj.c56
-rw-r--r--sbin/fsck_ffs/utilities.c11
-rw-r--r--sbin/fsdb/Makefile2
-rw-r--r--sbin/gbde/gbde.c1
-rw-r--r--sbin/geom/Makefile2
-rw-r--r--sbin/geom/class/eli/geom_eli.c2
-rw-r--r--sbin/geom/class/mirror/geom_mirror.c109
-rw-r--r--sbin/geom/class/mirror/gmirror.833
-rw-r--r--sbin/geom/class/part/geom_part.c49
-rw-r--r--sbin/geom/class/part/gpart.827
-rw-r--r--sbin/growfs/Makefile6
-rw-r--r--sbin/growfs/debug.c2
-rw-r--r--sbin/growfs/growfs.82
-rw-r--r--sbin/growfs/growfs.c2
-rw-r--r--sbin/growfs/tests/Makefile7
-rwxr-xr-xsbin/growfs/tests/legacy_test.pl89
-rw-r--r--sbin/gvinum/gvinum.c17
-rw-r--r--sbin/hastctl/hastctl.c7
-rw-r--r--sbin/hastd/control.c11
-rw-r--r--sbin/hastd/hast.h5
-rw-r--r--sbin/hastd/hastd.82
-rw-r--r--sbin/hastd/hastd.c12
-rw-r--r--sbin/hastd/nv.c2
-rw-r--r--sbin/hastd/primary.c245
-rw-r--r--sbin/hastd/proto.c6
-rw-r--r--sbin/hastd/refcnt.h3
-rw-r--r--sbin/hastd/secondary.c24
-rw-r--r--sbin/hastd/subr.c2
-rw-r--r--sbin/ifconfig/Makefile12
-rw-r--r--sbin/ifconfig/af_atalk.c182
-rw-r--r--sbin/ifconfig/af_ipx.c118
-rw-r--r--sbin/ifconfig/ifconfig.855
-rw-r--r--sbin/ifconfig/ifconfig.c17
-rw-r--r--sbin/ifconfig/ifgroup.c4
-rw-r--r--sbin/ifconfig/tests/Makefile9
-rwxr-xr-xsbin/ifconfig/tests/fibs_test.sh126
-rw-r--r--sbin/init/init.c20
-rw-r--r--sbin/ipfw/Makefile10
-rw-r--r--sbin/ipfw/ipfw.88
-rw-r--r--sbin/ipfw/ipfw2.c60
-rw-r--r--sbin/ipfw/ipfw2.h7
-rw-r--r--sbin/iscontrol/fsm.c1
-rw-r--r--sbin/iscontrol/iscsi.conf.59
-rw-r--r--sbin/kldconfig/kldconfig.c27
-rw-r--r--sbin/kldload/kldload.c17
-rw-r--r--sbin/kldstat/kldstat.83
-rw-r--r--sbin/kldstat/kldstat.c11
-rw-r--r--sbin/mdconfig/Makefile6
-rw-r--r--sbin/mdconfig/mdconfig.828
-rw-r--r--sbin/mdconfig/mdconfig.c28
-rw-r--r--sbin/mdconfig/tests/Makefile13
-rw-r--r--sbin/mdconfig/tests/legacy_test.sh47
-rw-r--r--sbin/mdconfig/tests/mdconfig.test231
-rw-r--r--sbin/mdconfig/tests/run.pl329
-rw-r--r--sbin/mount_fusefs/Makefile1
-rw-r--r--sbin/mount_nfs/mount_nfs.815
-rw-r--r--sbin/mount_udf/mount_udf.c6
-rw-r--r--sbin/newfs/mkfs.c8
-rw-r--r--sbin/newfs_msdos/newfs_msdos.c10
-rw-r--r--sbin/newfs_nandfs/newfs_nandfs.c6
-rw-r--r--sbin/nos-tun/nos-tun.c2
-rw-r--r--sbin/nvmecontrol/devlist.c4
-rw-r--r--sbin/nvmecontrol/firmware.c35
-rw-r--r--sbin/nvmecontrol/perftest.c2
-rw-r--r--sbin/pfctl/Makefile10
-rw-r--r--sbin/pfctl/pf_print_state.c5
-rw-r--r--sbin/pfctl/pfctl.c34
-rw-r--r--sbin/pfctl/pfctl_altq.c4
-rw-r--r--sbin/pfctl/pfctl_parser.c24
-rw-r--r--sbin/pfctl/pfctl_parser.h1
-rw-r--r--sbin/ping/Makefile8
-rw-r--r--sbin/ping/ping.c212
-rw-r--r--sbin/route/keywords4
-rw-r--r--sbin/route/route.839
-rw-r--r--sbin/route/route.c247
-rw-r--r--sbin/rtsol/Makefile2
-rw-r--r--sbin/savecore/savecore.c4
-rw-r--r--sbin/swapon/swapon.810
-rw-r--r--sbin/swapon/swapon.c3
-rw-r--r--sbin/sysctl/sysctl.82
-rw-r--r--sbin/sysctl/sysctl.c4
-rw-r--r--sbin/tests/Makefile10
111 files changed, 3973 insertions, 1077 deletions
diff --git a/sbin/Makefile b/sbin/Makefile
index 4772844..1548155 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -72,12 +72,16 @@ SUBDIR=adjkerntz \
swapon \
sysctl \
tunefs \
- umount \
+ umount
.if ${MK_ATM} != "no"
SUBDIR+= atm
.endif
+.if ${MK_CASPER} != "no"
+SUBDIR+= casperd
+.endif
+
.if ${MK_CXX} != "no"
SUBDIR+= devd
.endif
@@ -114,8 +118,14 @@ SUBDIR+= quotacheck
SUBDIR+= routed
.endif
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.arch.inc.mk>
SUBDIR:= ${SUBDIR:O}
+SUBDIR_PARALLEL=
+
.include <bsd.subdir.mk>
diff --git a/sbin/camcontrol/camcontrol.8 b/sbin/camcontrol/camcontrol.8
index 3b5eafe..856edc4 100644
--- a/sbin/camcontrol/camcontrol.8
+++ b/sbin/camcontrol/camcontrol.8
@@ -41,6 +41,7 @@
.Op command args
.Nm
.Ic devlist
+.Op Fl b
.Op Fl v
.Nm
.Ic periphlist
@@ -361,6 +362,10 @@ With the
.Fl v
argument, SCSI bus number, adapter name and unit numbers are printed as
well.
+On the other hand, with the
+.Fl b
+argument, only the bus adapter, and unit information will be printed, and
+device information will be omitted.
.It Ic periphlist
List all peripheral drivers attached to a given physical device (logical
unit).
diff --git a/sbin/camcontrol/camcontrol.c b/sbin/camcontrol/camcontrol.c
index 68c6d79..6783bd3 100644
--- a/sbin/camcontrol/camcontrol.c
+++ b/sbin/camcontrol/camcontrol.c
@@ -202,7 +202,7 @@ static struct camcontrol_opts option_table[] = {
{"defects", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
{"defectlist", CAM_CMD_READ_DEFECTS, CAM_ARG_NONE, readdefect_opts},
#endif /* MINIMALISTIC */
- {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, NULL},
+ {"devlist", CAM_CMD_DEVTREE, CAM_ARG_NONE, "-b"},
#ifndef MINIMALISTIC
{"periphlist", CAM_CMD_DEVLIST, CAM_ARG_NONE, NULL},
{"modepage", CAM_CMD_MODE_PAGE, CAM_ARG_NONE, "bdelm:P:"},
@@ -254,7 +254,7 @@ camcontrol_optret getoption(struct camcontrol_opts *table, char *arg,
#ifndef MINIMALISTIC
static int getdevlist(struct cam_device *device);
#endif /* MINIMALISTIC */
-static int getdevtree(void);
+static int getdevtree(int argc, char **argv, char *combinedopt);
#ifndef MINIMALISTIC
static int testunitready(struct cam_device *device, int retry_count,
int timeout, int quiet);
@@ -264,11 +264,12 @@ static int scsiinquiry(struct cam_device *device, int retry_count, int timeout);
static int scsiserial(struct cam_device *device, int retry_count, int timeout);
static int camxferrate(struct cam_device *device);
#endif /* MINIMALISTIC */
-static int parse_btl(char *tstr, int *bus, int *target, int *lun,
- cam_argmask *arglst);
+static int parse_btl(char *tstr, path_id_t *bus, target_id_t *target,
+ lun_id_t *lun, cam_argmask *arglst);
static int dorescan_or_reset(int argc, char **argv, int rescan);
-static int rescan_or_reset_bus(int bus, int rescan);
-static int scanlun_or_reset_dev(int bus, int target, int lun, int scan);
+static int rescan_or_reset_bus(path_id_t bus, int rescan);
+static int scanlun_or_reset_dev(path_id_t bus, target_id_t target,
+ lun_id_t lun, int scan);
#ifndef MINIMALISTIC
static int readdefects(struct cam_device *device, int argc, char **argv,
char *combinedopt, int retry_count, int timeout);
@@ -411,7 +412,7 @@ getdevlist(struct cam_device *device)
#endif /* MINIMALISTIC */
static int
-getdevtree(void)
+getdevtree(int argc, char **argv, char *combinedopt)
{
union ccb ccb;
int bufsize, fd;
@@ -419,6 +420,19 @@ getdevtree(void)
int need_close = 0;
int error = 0;
int skip_device = 0;
+ int busonly = 0;
+ int c;
+
+ while ((c = getopt(argc, argv, combinedopt)) != -1) {
+ switch(c) {
+ case 'b':
+ if ((arglist & CAM_ARG_VERBOSE) == 0)
+ busonly = 1;
+ break;
+ default:
+ break;
+ }
+ }
if ((fd = open(XPT_DEVICE, O_RDWR)) == -1) {
warn("couldn't open %s", XPT_DEVICE);
@@ -478,7 +492,8 @@ getdevtree(void)
* Only print the bus information if the
* user turns on the verbose flag.
*/
- if ((arglist & CAM_ARG_VERBOSE) == 0)
+ if ((busonly == 0) &&
+ (arglist & CAM_ARG_VERBOSE) == 0)
break;
bus_result =
@@ -489,11 +504,12 @@ getdevtree(void)
need_close = 0;
}
- fprintf(stdout, "scbus%d on %s%d bus %d:\n",
+ fprintf(stdout, "scbus%d on %s%d bus %d%s\n",
bus_result->path_id,
bus_result->dev_name,
bus_result->unit_number,
- bus_result->bus_id);
+ bus_result->bus_id,
+ (busonly ? "" : ":"));
break;
}
case DEV_MATCH_DEVICE: {
@@ -501,6 +517,9 @@ getdevtree(void)
char vendor[16], product[48], revision[16];
char fw[5], tmpstr[256];
+ if (busonly == 1)
+ break;
+
dev_result =
&ccb.cdm.matches[i].result.device_result;
@@ -566,11 +585,11 @@ getdevtree(void)
}
fprintf(stdout, "%-33s at scbus%d "
- "target %d lun %d (",
+ "target %d lun %jx (",
tmpstr,
dev_result->path_id,
dev_result->target_id,
- dev_result->target_lun);
+ (uintmax_t)dev_result->target_lun);
need_close = 1;
@@ -582,7 +601,7 @@ getdevtree(void)
periph_result =
&ccb.cdm.matches[i].result.periph_result;
- if (skip_device != 0)
+ if (busonly || skip_device != 0)
break;
if (need_close > 1)
@@ -1195,6 +1214,18 @@ atahpa_print(struct ata_params *parm, u_int64_t hpasize, int header)
}
}
+static int
+atasata(struct ata_params *parm)
+{
+
+
+ if (parm->satacapabilities != 0xffff &&
+ parm->satacapabilities != 0x0000)
+ return 1;
+
+ return 0;
+}
+
static void
atacapprint(struct ata_params *parm)
{
@@ -1351,6 +1382,17 @@ atacapprint(struct ata_params *parm)
ATA_QUEUE_LEN(parm->queue) + 1);
} else
printf("no\n");
+
+ printf("NCQ Queue Management %s\n", atasata(parm) &&
+ parm->satacapabilities2 & ATA_SUPPORT_NCQ_QMANAGEMENT ?
+ "yes" : "no");
+ printf("NCQ Streaming %s\n", atasata(parm) &&
+ parm->satacapabilities2 & ATA_SUPPORT_NCQ_STREAM ?
+ "yes" : "no");
+ printf("Receive & Send FPDMA Queued %s\n", atasata(parm) &&
+ parm->satacapabilities2 & ATA_SUPPORT_RCVSND_FPDMA_QUEUED ?
+ "yes" : "no");
+
printf("SMART %s %s\n",
parm->support.command1 & ATA_SUPPORT_SMART ? "yes" : "no",
parm->enabled.command1 & ATA_SUPPORT_SMART ? "yes" : "no");
@@ -1399,6 +1441,9 @@ atacapprint(struct ata_params *parm)
printf("unload %s %s\n",
parm->support.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no",
parm->enabled.extension & ATA_SUPPORT_UNLOAD ? "yes" : "no");
+ printf("general purpose logging %s %s\n",
+ parm->support.extension & ATA_SUPPORT_GENLOG ? "yes" : "no",
+ parm->enabled.extension & ATA_SUPPORT_GENLOG ? "yes" : "no");
printf("free-fall %s %s\n",
parm->support2 & ATA_SUPPORT_FREEFALL ? "yes" : "no",
parm->enabled2 & ATA_SUPPORT_FREEFALL ? "yes" : "no");
@@ -3001,7 +3046,8 @@ atasecurity(struct cam_device *device, int retry_count, int timeout,
* Returns the number of parsed components, or 0.
*/
static int
-parse_btl(char *tstr, int *bus, int *target, int *lun, cam_argmask *arglst)
+parse_btl(char *tstr, path_id_t *bus, target_id_t *target, lun_id_t *lun,
+ cam_argmask *arglst)
{
char *tmpstr;
int convs = 0;
@@ -3037,7 +3083,9 @@ dorescan_or_reset(int argc, char **argv, int rescan)
static const char must[] =
"you must specify \"all\", a bus, or a bus:target:lun to %s";
int rv, error = 0;
- int bus = -1, target = -1, lun = -1;
+ path_id_t bus = CAM_BUS_WILDCARD;
+ target_id_t target = CAM_TARGET_WILDCARD;
+ lun_id_t lun = CAM_LUN_WILDCARD;
char *tstr;
if (argc < 3) {
@@ -3069,7 +3117,7 @@ dorescan_or_reset(int argc, char **argv, int rescan)
}
static int
-rescan_or_reset_bus(int bus, int rescan)
+rescan_or_reset_bus(path_id_t bus, int rescan)
{
union ccb ccb, matchccb;
int fd, retval;
@@ -3083,7 +3131,7 @@ rescan_or_reset_bus(int bus, int rescan)
return(1);
}
- if (bus != -1) {
+ if (bus != CAM_BUS_WILDCARD) {
ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS : XPT_RESET_BUS;
ccb.ccb_h.path_id = bus;
ccb.ccb_h.target_id = CAM_TARGET_WILDCARD;
@@ -3183,7 +3231,7 @@ rescan_or_reset_bus(int bus, int rescan)
* We don't want to rescan or reset the xpt bus.
* See above.
*/
- if ((int)bus_result->path_id == -1)
+ if (bus_result->path_id == CAM_XPT_PATH_ID)
continue;
ccb.ccb_h.func_code = rescan ? XPT_SCAN_BUS :
@@ -3236,7 +3284,7 @@ bailout:
}
static int
-scanlun_or_reset_dev(int bus, int target, int lun, int scan)
+scanlun_or_reset_dev(path_id_t bus, target_id_t target, lun_id_t lun, int scan)
{
union ccb ccb;
struct cam_device *device;
@@ -3244,18 +3292,18 @@ scanlun_or_reset_dev(int bus, int target, int lun, int scan)
device = NULL;
- if (bus < 0) {
+ if (bus == CAM_BUS_WILDCARD) {
warnx("invalid bus number %d", bus);
return(1);
}
- if (target < 0) {
+ if (target == CAM_TARGET_WILDCARD) {
warnx("invalid target number %d", target);
return(1);
}
- if (lun < 0) {
- warnx("invalid lun number %d", lun);
+ if (lun == CAM_LUN_WILDCARD) {
+ warnx("invalid lun number %jx", (uintmax_t)lun);
return(1);
}
@@ -3313,12 +3361,12 @@ scanlun_or_reset_dev(int bus, int target, int lun, int scan)
if (((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
|| ((!scan)
&& ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_BDR_SENT))) {
- fprintf(stdout, "%s of %d:%d:%d was successful\n",
- scan? "Re-scan" : "Reset", bus, target, lun);
+ fprintf(stdout, "%s of %d:%d:%jx was successful\n",
+ scan? "Re-scan" : "Reset", bus, target, (uintmax_t)lun);
return(0);
} else {
- fprintf(stdout, "%s of %d:%d:%d returned error %#x\n",
- scan? "Re-scan" : "Reset", bus, target, lun,
+ fprintf(stdout, "%s of %d:%d:%jx returned error %#x\n",
+ scan? "Re-scan" : "Reset", bus, target, (uintmax_t)lun,
ccb.ccb_h.status & CAM_STATUS_MASK);
return(1);
}
@@ -4200,7 +4248,9 @@ static int
camdebug(int argc, char **argv, char *combinedopt)
{
int c, fd;
- int bus = -1, target = -1, lun = -1;
+ path_id_t bus = CAM_BUS_WILDCARD;
+ target_id_t target = CAM_TARGET_WILDCARD;
+ lun_id_t lun = CAM_LUN_WILDCARD;
char *tstr, *tmpstr = NULL;
union ccb ccb;
int error = 0;
@@ -4320,8 +4370,8 @@ camdebug(int argc, char **argv, char *combinedopt)
} else {
fprintf(stderr,
"Debugging enabled for "
- "%d:%d:%d\n",
- bus, target, lun);
+ "%d:%d:%jx\n",
+ bus, target, (uintmax_t)lun);
}
}
}
@@ -7968,7 +8018,9 @@ main(int argc, char **argv)
int error = 0, optstart = 2;
int devopen = 1;
#ifndef MINIMALISTIC
- int bus, target, lun;
+ path_id_t bus;
+ target_id_t target;
+ lun_id_t lun;
#endif /* MINIMALISTIC */
cmdlist = CAM_CMD_NONE;
@@ -8178,7 +8230,7 @@ main(int argc, char **argv)
break;
#endif /* MINIMALISTIC */
case CAM_CMD_DEVTREE:
- error = getdevtree();
+ error = getdevtree(argc, argv, combinedopt);
break;
#ifndef MINIMALISTIC
case CAM_CMD_TUR:
diff --git a/sbin/camcontrol/modeedit.c b/sbin/camcontrol/modeedit.c
index 8504208..00ab974 100644
--- a/sbin/camcontrol/modeedit.c
+++ b/sbin/camcontrol/modeedit.c
@@ -886,12 +886,12 @@ mode_list(struct cam_device *device, int page_control, int dbd,
timeout, data, sizeof(data));
mh = (struct scsi_mode_header_6 *)data;
- len = mh->blk_desc_len; /* Skip block descriptors. */
+ len = sizeof(*mh) + mh->blk_desc_len; /* Skip block descriptors. */
/* Iterate through the pages in the reply. */
while (len < mh->data_length) {
/* Locate the next mode page header. */
mph = (struct scsi_mode_page_header *)
- ((intptr_t)mh + sizeof(*mh) + len);
+ ((intptr_t)mh + len);
mph->page_code &= SMS_PAGE_CODE;
nameentry = nameentry_lookup(mph->page_code);
diff --git a/sbin/casperd/Makefile b/sbin/casperd/Makefile
new file mode 100644
index 0000000..f5a8e05
--- /dev/null
+++ b/sbin/casperd/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+PROG= casperd
+
+SRCS= casperd.c zygote.c
+
+DPADD= ${LIBCASPER} ${LIBCAPSICUM} ${LIBNV} ${LIBPJDLOG} ${LIBUTIL}
+LDADD= -lcasper -lcapsicum -lnv -lpjdlog -lutil
+
+MAN= casperd.8
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../../lib/libcapsicum
+CFLAGS+=-I${.CURDIR}/../../lib/libcasper
+CFLAGS+=-I${.CURDIR}/../../lib/libnv
+CFLAGS+=-I${.CURDIR}/../../lib/libpjdlog
+
+.include <bsd.prog.mk>
diff --git a/sbin/casperd/casperd.8 b/sbin/casperd/casperd.8
new file mode 100644
index 0000000..ebe560d
--- /dev/null
+++ b/sbin/casperd/casperd.8
@@ -0,0 +1,126 @@
+.\" Copyright (c) 2013 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This documentation was written by Pawel Jakub Dawidek under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE 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 October 26, 2013
+.Dt CASPERD 8
+.Os
+.Sh NAME
+.Nm casperd
+.Nd "Capability Services friendly daemon"
+.Sh SYNOPSIS
+.Nm
+[-Fhv] [-D servconfdir] [-P pidfile] [-S sockpath]
+.Op Fl Fhv
+.Op Fl D Ar servconfdir
+.Op Fl P Ar pidfile
+.Op Fl S Ar sockpath
+.Sh DESCRIPTION
+The
+.Nm
+daemon hosts various services that can be accessed through
+libcapsicum's capabilities by programs running in sandboxes.
+For example it is prohibited to send UDP packets to arbitrary destinations
+when operating in capability mode, which makes DNS resolution impossible.
+To make it possible the
+.Nm
+daemon provides the
+.Nm system.dns
+service that proxies DNS resolution requests through a dedicated,
+non-sandboxed process provided by
+.Nm .
+.Pp
+The
+.Nm
+daemon can be started with the following command line arguments:
+.Bl -tag -width ".Fl D Ar servconfdir"
+.It Fl D Ar servconfdir
+Specify alternative location of the service configuration directory.
+The default location is
+.Pa /etc/casper/ .
+.It Fl F
+Start the
+.Nm
+daemon in the foreground.
+By default
+.Nm
+starts in the background.
+.It Fl h
+Print the
+.Nm
+usage message.
+.It Fl P Ar pidfile
+Specify alternative location of a file where main process PID will be
+stored.
+The default location is
+.Pa /var/run/casperd.pid .
+.It Fl S Ar sockpath
+Specify alternative location of the
+.Xr unix 4
+domain socket used to connect to the
+.Nm
+daemon.
+The default location is
+.Pa /var/run/casper .
+.It Fl v
+Print or log verbose/debugging information.
+This option can be specified multiple times to raise the verbosity
+level.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /var/run/casperd.pid" -compact
+.It Pa /etc/casper/
+The configuration directory for
+.Nm
+services.
+.It Pa /var/run/casper
+.Xr unix 4
+domain socket used to connect to the
+.Nm
+daemon.
+.It Pa /var/run/casperd.pid
+The default location of the
+.Nm
+PID file.
+.El
+.Sh EXIT STATUS
+The
+.Nm
+daemon exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr cap_enter 2 ,
+.Xr libcapsicum 3 ,
+.Xr pidfile 3 ,
+.Xr capsicum 4 ,
+.Xr unix 4
+.Sh AUTHORS
+The
+.Nm
+was implemented by
+.An Pawel Jakub Dawidek Aq pawel@dawidek.net
+under sponsorship from the FreeBSD Foundation.
diff --git a/sbin/casperd/casperd.c b/sbin/casperd/casperd.c
new file mode 100644
index 0000000..4b9037b
--- /dev/null
+++ b/sbin/casperd/casperd.c
@@ -0,0 +1,715 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/capsicum.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libutil.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <libcapsicum.h>
+#include <libcapsicum_impl.h>
+#include <libcasper.h>
+#include <libcasper_impl.h>
+#include <msgio.h>
+#include <nv.h>
+#include <pjdlog.h>
+
+#include "msgio.h"
+
+#include "zygote.h"
+
+#define CASPERD_PIDFILE "/var/run/casperd.pid"
+#define CASPERD_SERVCONFDIR "/etc/casper"
+#define CASPERD_SOCKPATH "/var/run/casper"
+
+typedef void service_function_t(struct service_connection *, const nvlist_t *,
+ nvlist_t *);
+
+struct casper_service {
+ const char *cs_name;
+ const char *cs_execpath;
+ struct service *cs_service;
+ nvlist_t *cs_attrs;
+ TAILQ_ENTRY(casper_service) cs_next;
+};
+
+static TAILQ_HEAD(, casper_service) casper_services =
+ TAILQ_HEAD_INITIALIZER(casper_services);
+
+#define SERVICE_IS_CORE(service) ((service)->cs_execpath == NULL)
+
+static void service_external_execute(int chanfd);
+
+#define KEEP_ERRNO(work) do { \
+ int _serrno; \
+ \
+ _serrno = errno; \
+ work; \
+ errno = _serrno; \
+} while (0)
+
+static struct casper_service *
+service_find(const char *name)
+{
+ struct casper_service *casserv;
+
+ TAILQ_FOREACH(casserv, &casper_services, cs_next) {
+ if (strcmp(casserv->cs_name, name) == 0)
+ break;
+ }
+ return (casserv);
+}
+
+/*
+ * Function always consumes the given attrs.
+ */
+static void
+service_register(nvlist_t *attrs)
+{
+ struct casper_service *casserv;
+ const char *name;
+
+ PJDLOG_ASSERT(nvlist_exists_string(attrs, "name"));
+ PJDLOG_ASSERT(nvlist_exists_string(attrs, "execpath") ||
+ (nvlist_exists_number(attrs, "commandfunc") &&
+ nvlist_exists_number(attrs, "limitfunc")));
+
+ name = nvlist_get_string(attrs, "name");
+ PJDLOG_ASSERT(name != NULL);
+ if (name[0] == '\0') {
+ pjdlog_error("Unable to register service with an empty name.");
+ nvlist_destroy(attrs);
+ return;
+ }
+ if (service_find(name) != NULL) {
+ pjdlog_error("Service \"%s\" is already registered.", name);
+ nvlist_destroy(attrs);
+ return;
+ }
+
+ casserv = malloc(sizeof(*casserv));
+ if (casserv == NULL) {
+ pjdlog_errno(LOG_ERR, "Unable to register service \"%s\"",
+ name);
+ nvlist_destroy(attrs);
+ return;
+ }
+ casserv->cs_name = name;
+ if (nvlist_exists_string(attrs, "execpath")) {
+ struct stat sb;
+
+ PJDLOG_ASSERT(!nvlist_exists_number(attrs, "commandfunc"));
+ PJDLOG_ASSERT(!nvlist_exists_number(attrs, "limitfunc"));
+
+ casserv->cs_service = NULL;
+
+ casserv->cs_execpath = nvlist_get_string(attrs, "execpath");
+ if (casserv->cs_execpath == NULL ||
+ casserv->cs_execpath[0] == '\0') {
+ pjdlog_error("Unable to register service with an empty execpath.");
+ free(casserv);
+ nvlist_destroy(attrs);
+ return;
+ }
+ if (stat(casserv->cs_execpath, &sb) == -1) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to register service \"%s\", problem with executable \"%s\"",
+ name, casserv->cs_execpath);
+ free(casserv);
+ nvlist_destroy(attrs);
+ return;
+ }
+ } else /* if (nvlist_exists_number(attrs, "commandfunc")) */ {
+ PJDLOG_ASSERT(!nvlist_exists_string(attrs, "execpath"));
+
+ casserv->cs_execpath = NULL;
+
+ casserv->cs_service = service_alloc(name,
+ (void *)(uintptr_t)nvlist_get_number(attrs, "limitfunc"),
+ (void *)(uintptr_t)nvlist_get_number(attrs, "commandfunc"));
+ if (casserv->cs_service == NULL) {
+ pjdlog_errno(LOG_ERR,
+ "Unable to register service \"%s\"", name);
+ free(casserv);
+ nvlist_destroy(attrs);
+ return;
+ }
+ }
+ casserv->cs_attrs = attrs;
+ TAILQ_INSERT_TAIL(&casper_services, casserv, cs_next);
+ pjdlog_debug(1, "Service %s successfully registered.",
+ casserv->cs_name);
+}
+
+static bool
+casper_allowed_service(const nvlist_t *limits, const char *service)
+{
+
+ if (limits == NULL)
+ return (true);
+
+ if (nvlist_exists_null(limits, service))
+ return (true);
+
+ return (false);
+}
+
+static int
+casper_limit(const nvlist_t *oldlimits, const nvlist_t *newlimits)
+{
+ const char *name;
+ int type;
+ void *cookie;
+
+ cookie = NULL;
+ while ((name = nvlist_next(newlimits, &type, &cookie)) != NULL) {
+ if (type != NV_TYPE_NULL)
+ return (EINVAL);
+ if (!casper_allowed_service(oldlimits, name))
+ return (ENOTCAPABLE);
+ }
+
+ return (0);
+}
+
+static int
+casper_command(const char *cmd, const nvlist_t *limits, nvlist_t *nvlin,
+ nvlist_t *nvlout)
+{
+ struct casper_service *casserv;
+ const char *servname;
+ nvlist_t *nvl;
+ int chanfd, execfd, procfd, error;
+
+ if (strcmp(cmd, "open") != 0)
+ return (EINVAL);
+ if (!nvlist_exists_string(nvlin, "service"))
+ return (EINVAL);
+
+ servname = nvlist_get_string(nvlin, "service");
+
+ casserv = service_find(servname);
+ if (casserv == NULL)
+ return (ENOENT);
+
+ if (!casper_allowed_service(limits, servname))
+ return (ENOTCAPABLE);
+
+#ifdef O_EXEC_WORKING
+ execfd = open(casserv->cs_execpath, O_EXEC);
+#else
+ execfd = open(casserv->cs_execpath, O_RDONLY);
+#endif
+ if (execfd < -1) {
+ error = errno;
+ pjdlog_errno(LOG_ERR,
+ "Unable to open executable '%s' of service '%s'",
+ casserv->cs_execpath, casserv->cs_name);
+ return (error);
+ }
+
+ if (zygote_clone(service_external_execute, 0, &chanfd, &procfd) == -1) {
+ error = errno;
+ close(execfd);
+ return (error);
+ }
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "service", casserv->cs_name);
+ if (nvlist_exists_descriptor(nvlin, "stderrfd")) {
+ nvlist_move_descriptor(nvl, "stderrfd",
+ nvlist_take_descriptor(nvlin, "stderrfd"));
+ }
+ nvlist_move_descriptor(nvl, "execfd", execfd);
+ nvlist_move_descriptor(nvl, "procfd", procfd);
+ if (nvlist_send(chanfd, nvl) == -1) {
+ error = errno;
+ pjdlog_errno(LOG_ERR, "Unable to send nvlist");
+ nvlist_destroy(nvl);
+ close(chanfd);
+ return (error);
+ }
+ nvlist_destroy(nvl);
+
+ nvlist_move_descriptor(nvlout, "chanfd", chanfd);
+
+ return (0);
+}
+
+static void
+fdswap(int *fd0, int *fd1)
+{
+ int tmpfd;
+
+ PJDLOG_VERIFY((tmpfd = dup(*fd0)) != -1);
+ PJDLOG_VERIFY(dup2(*fd1, *fd0) != -1);
+ PJDLOG_VERIFY(dup2(tmpfd, *fd1) != -1);
+ close(tmpfd);
+ tmpfd = *fd0;
+ *fd0 = *fd1;
+ *fd1 = tmpfd;
+}
+
+static void
+fdmove(int *oldfdp, int newfd)
+{
+
+ if (*oldfdp != newfd) {
+ PJDLOG_VERIFY(dup2(*oldfdp, newfd) != -1);
+ close(*oldfdp);
+ *oldfdp = newfd;
+ }
+}
+
+static void
+fdcloexec(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFD);
+ PJDLOG_ASSERT(flags != -1);
+ if ((flags & FD_CLOEXEC) != 0)
+ PJDLOG_VERIFY(fcntl(fd, F_SETFD, flags & ~FD_CLOEXEC) != -1);
+}
+
+static void
+service_register_core(void)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "name", "core.casper");
+ nvlist_add_number(nvl, "limitfunc", (uint64_t)(uintptr_t)casper_limit);
+ nvlist_add_number(nvl, "commandfunc",
+ (uint64_t)(uintptr_t)casper_command);
+ service_register(nvl);
+}
+
+static int
+setup_creds(int sock)
+{
+ struct cmsgcred cred;
+
+ if (cred_recv(sock, &cred) == -1)
+ return (-1);
+
+ if (setgroups((int)cred.cmcred_ngroups, cred.cmcred_groups) == -1)
+ return (-1);
+
+ if (setgid(cred.cmcred_groups[0]) == -1)
+ return (-1);
+
+ if (setuid(cred.cmcred_euid) == -1)
+ return (-1);
+
+ return (0);
+}
+
+static void
+service_external_execute(int chanfd)
+{
+ char *service, *argv[3];
+ int stderrfd, execfd, procfd;
+ nvlist_t *nvl;
+
+ nvl = nvlist_recv(chanfd);
+ if (nvl == NULL)
+ pjdlog_exit(1, "Unable to receive nvlist");
+ service = nvlist_take_string(nvl, "service");
+ PJDLOG_ASSERT(service != NULL);
+ if (nvlist_exists_descriptor(nvl, "stderrfd")) {
+ stderrfd = nvlist_take_descriptor(nvl, "stderrfd");
+ } else {
+ stderrfd = open(_PATH_DEVNULL, O_RDWR);
+ if (stderrfd < 0)
+ pjdlog_exit(1, "Unable to open %s", _PATH_DEVNULL);
+ }
+ execfd = nvlist_take_descriptor(nvl, "execfd");
+ procfd = nvlist_take_descriptor(nvl, "procfd");
+ nvlist_destroy(nvl);
+
+ /*
+ * Move all descriptors into right slots.
+ */
+
+ if (stderrfd != STDERR_FILENO) {
+ if (chanfd == STDERR_FILENO)
+ fdswap(&stderrfd, &chanfd);
+ else if (execfd == STDERR_FILENO)
+ fdswap(&stderrfd, &execfd);
+ else if (procfd == STDERR_FILENO)
+ fdswap(&stderrfd, &procfd);
+ fdmove(&stderrfd, STDERR_FILENO);
+ }
+ fdcloexec(stderrfd);
+
+ if (chanfd != PARENT_FILENO) {
+ if (execfd == PARENT_FILENO)
+ fdswap(&chanfd, &execfd);
+ else if (procfd == PARENT_FILENO)
+ fdswap(&chanfd, &procfd);
+ fdmove(&chanfd, PARENT_FILENO);
+ }
+ fdcloexec(chanfd);
+
+ if (execfd != EXECUTABLE_FILENO) {
+ if (procfd == EXECUTABLE_FILENO)
+ fdswap(&execfd, &procfd);
+ fdmove(&execfd, EXECUTABLE_FILENO);
+ }
+ fdcloexec(execfd);
+
+ if (procfd != PROC_FILENO)
+ fdmove(&procfd, PROC_FILENO);
+ fdcloexec(procfd);
+
+ /*
+ * Use credentials of the caller process.
+ */
+ setup_creds(chanfd);
+
+ argv[0] = service;
+ asprintf(&argv[1], "%d", pjdlog_debug_get());
+ argv[2] = NULL;
+
+ fexecve(execfd, argv, NULL);
+ pjdlog_exit(1, "Unable to execute service %s", service);
+}
+
+static void
+service_register_external_one(const char *dirpath, int dfd,
+ const char *filename)
+{
+ char execpath[FILENAME_MAX];
+ nvlist_t *nvl;
+ ssize_t done;
+ int fd;
+
+ fd = openat(dfd, filename, O_RDONLY);
+ if (fd == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to open \"%s/%s\"", dirpath,
+ filename);
+ return;
+ }
+
+ done = read(fd, execpath, sizeof(execpath));
+ if (done == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to read content of \"%s/%s\"",
+ dirpath, filename);
+ close(fd);
+ return;
+ }
+ close(fd);
+ if (done == sizeof(execpath)) {
+ pjdlog_error("Executable path too long in \"%s/%s\".", dirpath,
+ filename);
+ return;
+ }
+ execpath[done] = '\0';
+ while (done > 0) {
+ if (execpath[--done] == '\n')
+ execpath[done] = '\0';
+ }
+
+ nvl = nvlist_create(0);
+ nvlist_add_string(nvl, "name", filename);
+ nvlist_add_string(nvl, "execpath", execpath);
+ if (nvlist_error(nvl) != 0) {
+ pjdlog_common(LOG_ERR, 0, nvlist_error(nvl),
+ "Unable to allocate attributes for service \"%s/%s\"",
+ dirpath, filename);
+ nvlist_destroy(nvl);
+ return;
+ }
+
+ service_register(nvl);
+ /* service_register() consumed nvl. */
+}
+
+static uint8_t
+file_type(int dfd, const char *filename)
+{
+ struct stat sb;
+
+ if (fstatat(dfd, filename, &sb, AT_SYMLINK_NOFOLLOW) == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to stat \"%s\"", filename);
+ return (DT_UNKNOWN);
+ }
+ return (IFTODT(sb.st_mode));
+}
+
+static void
+service_register_external(const char *dirpath)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int dfd;
+
+ dirp = opendir(dirpath);
+ if (dirp == NULL) {
+ pjdlog_errno(LOG_WARNING, "Unable to open \"%s\"", dirpath);
+ return;
+ }
+ dfd = dirfd(dirp);
+ PJDLOG_ASSERT(dfd >= 0);
+ while ((dp = readdir(dirp)) != NULL) {
+ dp->d_type = file_type(dfd, dp->d_name);
+ /* We are only interested in regular files, skip the rest. */
+ if (dp->d_type != DT_REG) {
+ pjdlog_debug(1,
+ "File \"%s/%s\" is not a regular file, skipping.",
+ dirpath, dp->d_name);
+ continue;
+ }
+ service_register_external_one(dirpath, dfd, dp->d_name);
+ }
+ closedir(dirp);
+}
+
+static void
+casper_accept(int lsock)
+{
+ struct casper_service *casserv;
+ struct service_connection *sconn;
+ int sock;
+
+ sock = accept(lsock, NULL, NULL);
+ if (sock == -1) {
+ pjdlog_errno(LOG_ERR, "Unable to accept casper connection");
+ return;
+ }
+ casserv = service_find("core.casper");
+ PJDLOG_ASSERT(casserv != NULL);
+
+ sconn = service_connection_add(casserv->cs_service, sock, NULL);
+ if (sconn == NULL) {
+ close(sock);
+ return;
+ }
+}
+
+static void
+main_loop(const char *sockpath, struct pidfh *pfh)
+{
+ fd_set fds;
+ struct sockaddr_un sun;
+ struct casper_service *casserv;
+ struct service_connection *sconn, *sconntmp;
+ int lsock, sock, maxfd, ret;
+ mode_t oldumask;
+
+ lsock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (lsock == -1)
+ pjdlog_exit(1, "Unable to create socket");
+
+ (void)unlink(sockpath);
+
+ bzero(&sun, sizeof(sun));
+ sun.sun_family = AF_UNIX;
+ PJDLOG_VERIFY(strlcpy(sun.sun_path, sockpath, sizeof(sun.sun_path)) <
+ sizeof(sun.sun_path));
+ sun.sun_len = SUN_LEN(&sun);
+
+ oldumask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
+ if (bind(lsock, (struct sockaddr *)&sun, sizeof(sun)) == -1)
+ pjdlog_exit(1, "Unable to bind to %s", sockpath);
+ (void)umask(oldumask);
+ if (listen(lsock, 8) == -1)
+ pjdlog_exit(1, "Unable to listen on %s", sockpath);
+
+ for (;;) {
+ FD_ZERO(&fds);
+ FD_SET(lsock, &fds);
+ maxfd = lsock;
+ TAILQ_FOREACH(casserv, &casper_services, cs_next) {
+ /* We handle only core services. */
+ if (!SERVICE_IS_CORE(casserv))
+ continue;
+ for (sconn = service_connection_first(casserv->cs_service);
+ sconn != NULL;
+ sconn = service_connection_next(sconn)) {
+ sock = service_connection_get_sock(sconn);
+ FD_SET(sock, &fds);
+ maxfd = sock > maxfd ? sock : maxfd;
+ }
+ }
+ maxfd++;
+
+ PJDLOG_ASSERT(maxfd <= (int)FD_SETSIZE);
+ ret = select(maxfd, &fds, NULL, NULL, NULL);
+ PJDLOG_ASSERT(ret == -1 || ret > 0); /* select() cannot timeout */
+ if (ret == -1) {
+ if (errno == EINTR)
+ continue;
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(1, "select() failed");
+ }
+
+ if (FD_ISSET(lsock, &fds))
+ casper_accept(lsock);
+ TAILQ_FOREACH(casserv, &casper_services, cs_next) {
+ /* We handle only core services. */
+ if (!SERVICE_IS_CORE(casserv))
+ continue;
+ for (sconn = service_connection_first(casserv->cs_service);
+ sconn != NULL; sconn = sconntmp) {
+ /*
+ * Prepare for connection to be removed from
+ * the list on failure.
+ */
+ sconntmp = service_connection_next(sconn);
+ sock = service_connection_get_sock(sconn);
+ if (FD_ISSET(sock, &fds)) {
+ service_message(casserv->cs_service,
+ sconn);
+ }
+ }
+ }
+ }
+}
+
+static void
+usage(void)
+{
+
+ pjdlog_exitx(1,
+ "usage: casperd [-Fhv] [-D servconfdir] [-P pidfile] [-S sockpath]");
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct pidfh *pfh;
+ const char *pidfile, *servconfdir, *sockpath;
+ pid_t otherpid;
+ int ch, debug;
+ bool foreground;
+
+ pjdlog_init(PJDLOG_MODE_STD);
+
+ debug = 0;
+ foreground = false;
+ pidfile = CASPERD_PIDFILE;
+ servconfdir = CASPERD_SERVCONFDIR;
+ sockpath = CASPERD_SOCKPATH;
+
+ while ((ch = getopt(argc, argv, "D:FhP:S:v")) != -1) {
+ switch (ch) {
+ case 'D':
+ servconfdir = optarg;
+ break;
+ case 'F':
+ foreground = true;
+ break;
+ case 'P':
+ pidfile = optarg;
+ break;
+ case 'S':
+ sockpath = optarg;
+ break;
+ case 'v':
+ debug++;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 0)
+ usage();
+
+ if (!foreground)
+ pjdlog_mode_set(PJDLOG_MODE_SYSLOG);
+ pjdlog_prefix_set("(casperd) ");
+ pjdlog_debug_set(debug);
+
+ if (zygote_init() < 0)
+ pjdlog_exit(1, "Unable to create zygote process");
+
+ pfh = pidfile_open(pidfile, 0600, &otherpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST) {
+ pjdlog_exitx(1, "casperd already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ pjdlog_errno(LOG_WARNING, "Cannot open or create pidfile %s",
+ pidfile);
+ }
+
+ if (!foreground) {
+ if (daemon(0, 0) == -1) {
+ KEEP_ERRNO((void)pidfile_remove(pfh));
+ pjdlog_exit(1, "Unable to go into background");
+ }
+ }
+
+ /* Write PID to a file. */
+ if (pidfile_write(pfh) == -1) {
+ pjdlog_errno(LOG_WARNING, "Unable to write to pidfile %s",
+ pidfile);
+ } else {
+ pjdlog_debug(1, "PID stored in %s.", pidfile);
+ }
+
+ /*
+ * Register core services.
+ */
+ service_register_core();
+ /*
+ * Register external services.
+ */
+ service_register_external(servconfdir);
+
+ /*
+ * Wait for connections.
+ */
+ main_loop(sockpath, pfh);
+}
diff --git a/sbin/casperd/zygote.c b/sbin/casperd/zygote.c
new file mode 100644
index 0000000..be3d9e5
--- /dev/null
+++ b/sbin/casperd/zygote.c
@@ -0,0 +1,229 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/capsicum.h>
+#include <sys/procdesc.h>
+#include <sys/socket.h>
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <paths.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <libcapsicum.h>
+#include <libcapsicum_impl.h>
+#include <nv.h>
+#include <pjdlog.h>
+
+#include "zygote.h"
+
+/* Zygote info. */
+static int zygote_sock = -1;
+
+static void
+stdnull(void)
+{
+ int fd;
+
+ fd = open(_PATH_DEVNULL, O_RDWR);
+ if (fd == -1)
+ errx(1, "Unable to open %s", _PATH_DEVNULL);
+
+ if (setsid() == -1)
+ errx(1, "Unable to detach from session");
+
+ if (dup2(fd, STDIN_FILENO) == -1)
+ errx(1, "Unable to cover stdin");
+ if (dup2(fd, STDOUT_FILENO) == -1)
+ errx(1, "Unable to cover stdout");
+ if (dup2(fd, STDERR_FILENO) == -1)
+ errx(1, "Unable to cover stderr");
+
+ close(fd);
+}
+
+int
+zygote_clone(zygote_func_t *func, int flags, int *chanfdp, int *procfdp)
+{
+ nvlist_t *nvl;
+ int error;
+
+ if (zygote_sock == -1) {
+ /* Zygote didn't start. */
+ errno = ENXIO;
+ return (-1);
+ }
+
+ nvl = nvlist_create(0);
+ nvlist_add_number(nvl, "func", (uint64_t)(uintptr_t)func);
+ nvlist_add_number(nvl, "flags", (uint64_t)flags);
+ nvl = nvlist_xfer(zygote_sock, nvl);
+ if (nvl == NULL)
+ return (-1);
+ if (nvlist_exists_number(nvl, "error")) {
+ error = (int)nvlist_get_number(nvl, "error");
+ nvlist_destroy(nvl);
+ errno = error;
+ return (-1);
+ }
+
+ *chanfdp = nvlist_take_descriptor(nvl, "chanfd");
+ *procfdp = nvlist_take_descriptor(nvl, "procfd");
+
+ nvlist_destroy(nvl);
+ return (0);
+}
+
+/*
+ * This function creates sandboxes on-demand whoever has access to it via
+ * 'sock' socket. Function sends two descriptors to the caller: process
+ * descriptor of the sandbox and socket pair descriptor for communication
+ * between sandbox and its owner.
+ */
+static void
+zygote_main(int sock)
+{
+ int error, fd, flags, procfd;
+ int chanfd[2];
+ nvlist_t *nvlin, *nvlout;
+ zygote_func_t *func;
+ pid_t pid;
+
+ assert(sock > STDERR_FILENO);
+
+ setproctitle("zygote");
+
+ if (pjdlog_mode_get() != PJDLOG_MODE_STD)
+ stdnull();
+ for (fd = STDERR_FILENO + 1; fd < sock; fd++)
+ close(fd);
+ closefrom(sock + 1);
+
+ for (;;) {
+ nvlin = nvlist_recv(sock);
+ if (nvlin == NULL) {
+ if (errno == ENOTCONN) {
+ /* Casperd exited. */
+ exit(0);
+ }
+ continue;
+ }
+ func = (zygote_func_t *)(uintptr_t)nvlist_get_number(nvlin,
+ "func");
+ flags = (int)nvlist_get_number(nvlin, "flags");
+ nvlist_destroy(nvlin);
+
+ /*
+ * Someone is requesting a new process, create one.
+ */
+ procfd = -1;
+ chanfd[0] = -1;
+ chanfd[1] = -1;
+ error = 0;
+ if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0,
+ chanfd) == -1) {
+ error = errno;
+ goto send;
+ }
+ pid = pdfork(&procfd, 0);
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ error = errno;
+ break;
+ case 0:
+ /* Child. */
+ close(sock);
+ close(chanfd[0]);
+ func(chanfd[1]);
+ /* NOTREACHED */
+ exit(1);
+ default:
+ /* Parent. */
+ close(chanfd[1]);
+ break;
+ }
+send:
+ nvlout = nvlist_create(0);
+ if (error != 0) {
+ nvlist_add_number(nvlout, "error", (uint64_t)error);
+ if (chanfd[0] >= 0)
+ close(chanfd[0]);
+ if (procfd >= 0)
+ close(procfd);
+ } else {
+ nvlist_move_descriptor(nvlout, "chanfd", chanfd[0]);
+ nvlist_move_descriptor(nvlout, "procfd", procfd);
+ }
+ (void)nvlist_send(sock, nvlout);
+ nvlist_destroy(nvlout);
+ }
+ /* NOTREACHED */
+}
+
+int
+zygote_init(void)
+{
+ int serrno, sp[2];
+ pid_t pid;
+
+ if (socketpair(PF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, sp) == -1)
+ return (-1);
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ serrno = errno;
+ close(sp[0]);
+ close(sp[1]);
+ errno = serrno;
+ return (-1);
+ case 0:
+ /* Child. */
+ close(sp[0]);
+ zygote_main(sp[1]);
+ /* NOTREACHED */
+ abort();
+ default:
+ /* Parent. */
+ zygote_sock = sp[0];
+ close(sp[1]);
+ return (0);
+ }
+ /* NOTREACHED */
+}
diff --git a/sbin/casperd/zygote.h b/sbin/casperd/zygote.h
new file mode 100644
index 0000000..75ef2ef
--- /dev/null
+++ b/sbin/casperd/zygote.h
@@ -0,0 +1,40 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE 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$
+ */
+
+#ifndef _ZYGOTE_H_
+#define _ZYGOTE_H_
+
+typedef void zygote_func_t(int);
+
+int zygote_init(void);
+int zygote_clone(zygote_func_t *func, int flags, int *chanfdp, int *procfdp);
+
+#endif /* !_ZYGOTE_H_ */
diff --git a/sbin/devd/devd.8 b/sbin/devd/devd.8
index 1869de6..fa34df2 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 dn
+.Op Fl dnq
.Op Fl f Ar file
.Op Fl l Ar num
.Sh DESCRIPTION
@@ -63,6 +63,8 @@ The default connection limit is 10.
.It Fl n
Do not process all pending events before becoming a daemon.
Instead, call daemon right away.
+.It Fl q
+Quiet mode. Only log messages at priority LOG_WARNING or above.
.El
.Sh IMPLEMENTATION NOTES
The
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index 447ab87..ce2a4f3 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -102,7 +102,20 @@ __FBSDID("$FreeBSD$");
#define PIPE "/var/run/devd.pipe"
#define CF "/etc/devd.conf"
-#define SYSCTL "hw.bus.devctl_disable"
+#define SYSCTL "hw.bus.devctl_queue"
+
+/*
+ * Since the client socket is nonblocking, we must increase its send buffer to
+ * handle brief event storms. On FreeBSD, AF_UNIX sockets don't have a receive
+ * buffer, so the client can't increate the buffersize by itself.
+ *
+ * For example, when creating a ZFS pool, devd emits one 165 character
+ * resource.fs.zfs.statechange message for each vdev in the pool. A 64k
+ * buffer has enough space for almost 400 drives, which would be very large but
+ * not impossibly large pool. A 128k buffer has enough space for 794 drives,
+ * which is more than can fit in a rack with modern technology.
+ */
+#define CLIENT_BUFSIZE 131072
using namespace std;
@@ -116,8 +129,9 @@ static const char detach = '-';
static struct pidfh *pfh;
-int dflag;
-int nflag;
+static int no_daemon = 0;
+static int daemonize_quick = 0;
+static int quiet_mode = 0;
static unsigned total_events = 0;
static volatile sig_atomic_t got_siginfo = 0;
static volatile sig_atomic_t romeo_must_die = 0;
@@ -248,7 +262,7 @@ bool
action::do_action(config &c)
{
string s = c.expand_string(_cmd.c_str());
- devdlog(LOG_NOTICE, "Executing '%s'\n", s.c_str());
+ devdlog(LOG_INFO, "Executing '%s'\n", s.c_str());
my_system(s.c_str());
return (true);
}
@@ -278,7 +292,7 @@ match::do_match(config &c)
* can consume excessive amounts of systime inside of connect(). Only
* log when we're in -d mode.
*/
- if (dflag) {
+ if (no_daemon) {
devdlog(LOG_DEBUG, "Testing %s=%s against %s, invert=%d\n",
_var.c_str(), value.c_str(), _re.c_str(), _inv);
}
@@ -388,7 +402,7 @@ var_list::set_variable(const string &var, const string &val)
* can consume excessive amounts of systime inside of connect(). Only
* log when we're in -d mode.
*/
- if (dflag)
+ if (no_daemon)
devdlog(LOG_DEBUG, "setting %s=%s\n", var.c_str(), val.c_str());
_vars[var] = val;
}
@@ -759,7 +773,7 @@ process_event(char *buffer)
char *sp;
sp = buffer + 1;
- devdlog(LOG_DEBUG, "Processing event '%s'\n", buffer);
+ devdlog(LOG_INFO, "Processing event '%s'\n", buffer);
type = *buffer++;
cfg.push_var_table();
// No match doesn't have a device, and the format is a little
@@ -892,6 +906,7 @@ void
new_client(int fd)
{
int s;
+ int sndbuf_size;
/*
* First go reap any zombie clients, then accept the connection, and
@@ -901,10 +916,15 @@ new_client(int fd)
check_clients();
s = accept(fd, NULL, NULL);
if (s != -1) {
+ sndbuf_size = CLIENT_BUFSIZE;
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sndbuf_size,
+ sizeof(sndbuf_size)))
+ err(1, "setsockopt");
shutdown(s, SHUT_RD);
clients.push_back(s);
++num_clients;
- }
+ } else
+ err(1, "accept");
}
static void
@@ -926,7 +946,7 @@ event_loop(void)
accepting = 1;
max_fd = max(fd, server_fd) + 1;
while (!romeo_must_die) {
- if (!once && !dflag && !nflag) {
+ if (!once && !no_daemon && !daemonize_quick) {
// Check to see if we have any events pending.
tv.tv_sec = 0;
tv.tv_usec = 0;
@@ -970,7 +990,7 @@ event_loop(void)
}
rv = select(max_fd, &fds, NULL, NULL, &tv);
if (got_siginfo) {
- devdlog(LOG_INFO, "Events received so far=%u\n",
+ devdlog(LOG_NOTICE, "Events received so far=%u\n",
total_events);
got_siginfo = 0;
}
@@ -1111,7 +1131,7 @@ siginfohand(int)
}
/*
- * Local logging function. Prints to syslog if we're daemonized; syslog
+ * Local logging function. Prints to syslog if we're daemonized; stderr
* otherwise.
*/
static void
@@ -1120,9 +1140,9 @@ devdlog(int priority, const char* fmt, ...)
va_list argp;
va_start(argp, fmt);
- if (dflag)
+ if (no_daemon)
vfprintf(stderr, fmt, argp);
- else
+ else if ((! quiet_mode) || (priority <= LOG_WARNING))
vsyslog(priority, fmt, argp);
va_end(argp);
}
@@ -1130,7 +1150,7 @@ devdlog(int priority, const char* fmt, ...)
static void
usage()
{
- fprintf(stderr, "usage: %s [-dn] [-l connlimit] [-f file]\n",
+ fprintf(stderr, "usage: %s [-dnq] [-l connlimit] [-f file]\n",
getprogname());
exit(1);
}
@@ -1144,9 +1164,9 @@ check_devd_enabled()
len = sizeof(val);
if (sysctlbyname(SYSCTL, &val, &len, NULL, 0) != 0)
errx(1, "devctl sysctl missing from kernel!");
- if (val) {
- warnx("Setting " SYSCTL " to 0");
- val = 0;
+ if (val == 0) {
+ warnx("Setting " SYSCTL " to 1000");
+ val = 1000;
sysctlbyname(SYSCTL, NULL, NULL, &val, sizeof(val));
}
}
@@ -1160,10 +1180,10 @@ main(int argc, char **argv)
int ch;
check_devd_enabled();
- while ((ch = getopt(argc, argv, "df:l:n")) != -1) {
+ while ((ch = getopt(argc, argv, "df:l:nq")) != -1) {
switch (ch) {
case 'd':
- dflag++;
+ no_daemon = 1;
break;
case 'f':
configfile = optarg;
@@ -1172,7 +1192,10 @@ main(int argc, char **argv)
max_clients = MAX(1, strtoul(optarg, NULL, 0));
break;
case 'n':
- nflag++;
+ daemonize_quick = 1;
+ break;
+ case 'q':
+ quiet_mode = 1;
break;
default:
usage();
@@ -1180,7 +1203,7 @@ main(int argc, char **argv)
}
cfg.parse();
- if (!dflag && nflag) {
+ if (!no_daemon && daemonize_quick) {
cfg.open_pidfile();
daemon(0, 0);
cfg.write_pidfile();
diff --git a/sbin/dhclient/Makefile b/sbin/dhclient/Makefile
index 74d1c4d..57c9211 100644
--- a/sbin/dhclient/Makefile
+++ b/sbin/dhclient/Makefile
@@ -31,6 +31,8 @@
# OF THE POSSIBILITY OF SUCH DAMAGE.
#
+.include <bsd.own.mk>
+
SRCS= dhclient.c clparse.c alloc.c dispatch.c hash.c bpf.c options.c \
tree.c conflex.c errwarn.c inet.c packet.c convert.c tables.c \
parse.c privsep.c
@@ -44,4 +46,8 @@ LDADD= -lutil
WARNS?= 2
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c
index c0a1720..7c2e531 100644
--- a/sbin/dhclient/bpf.c
+++ b/sbin/dhclient/bpf.c
@@ -43,11 +43,11 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include "dhcpd.h"
#include "privsep.h"
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include <sys/ioctl.h>
#include <sys/uio.h>
@@ -269,7 +269,7 @@ if_register_receive(struct interface_info *info)
if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0)
error("Cannot lock bpf");
- cap_rights_init(&rights, CAP_IOCTL, CAP_POLL_EVENT, CAP_READ);
+ cap_rights_init(&rights, CAP_IOCTL, CAP_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)
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index e16e464..c43bda9 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -56,12 +56,12 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include "dhcpd.h"
#include "privsep.h"
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include <net80211/ieee80211_freebsd.h>
@@ -393,7 +393,7 @@ main(int argc, char *argv[])
if (path_dhclient_pidfile == NULL)
error("asprintf");
}
- pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid);
+ pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid);
if (pidfile == NULL) {
if (errno == EEXIST)
error("dhclient already running, pid: %d.", otherpid);
@@ -494,7 +494,7 @@ main(int argc, char *argv[])
add_protocol("AF_ROUTE", routefd, routehandler, ifi);
if (shutdown(routefd, SHUT_WR) < 0)
error("can't shutdown route socket: %m");
- cap_rights_init(&rights, CAP_POLL_EVENT, CAP_READ);
+ cap_rights_init(&rights, CAP_EVENT, CAP_READ);
if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS)
error("can't limit route socket: %m");
diff --git a/sbin/dhclient/tests/Makefile b/sbin/dhclient/tests/Makefile
new file mode 100644
index 0000000..b092eea
--- /dev/null
+++ b/sbin/dhclient/tests/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sbin/dhclient
+
+.PATH: ${.CURDIR}/..
+
+PLAIN_TESTS_C= option-domain-search_test
+SRCS.option-domain-search_test= alloc.c convert.c hash.c options.c \
+ tables.c fake.c option-domain-search.c
+CFLAGS.option-domain-search_test+= -I${.CURDIR}/..
+LDADD.option-domain-search_test= -lutil
+
+WARNS?= 2
+
+.include <bsd.test.mk>
diff --git a/sbin/dhclient/tests/fake.c b/sbin/dhclient/tests/fake.c
new file mode 100644
index 0000000..c204d49
--- /dev/null
+++ b/sbin/dhclient/tests/fake.c
@@ -0,0 +1,64 @@
+/* $FreeBSD$ */
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "dhcpd.h"
+
+extern jmp_buf env;
+
+void
+error(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ longjmp(env, 1);
+}
+
+int
+warning(char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ /*
+ * The original warning() would return "ret" here. We do this to
+ * check warnings explicitely.
+ */
+ longjmp(env, 1);
+}
+
+int
+note(char *fmt, ...)
+{
+ int ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ return ret;
+}
+
+void
+bootp(struct packet *packet)
+{
+}
+
+void
+dhcp(struct packet *packet)
+{
+}
diff --git a/sbin/dhclient/tests/option-domain-search.c b/sbin/dhclient/tests/option-domain-search.c
new file mode 100644
index 0000000..b79f9a5
--- /dev/null
+++ b/sbin/dhclient/tests/option-domain-search.c
@@ -0,0 +1,328 @@
+/* $FreeBSD$ */
+
+#include <setjmp.h>
+#include <stdlib.h>
+
+#include "dhcpd.h"
+
+jmp_buf env;
+
+void expand_domain_search(struct packet *packet);
+
+void
+no_option_present()
+{
+ int ret;
+ struct option_data option;
+ struct packet p;
+
+ option.data = NULL;
+ option.len = 0;
+ p.options[DHO_DOMAIN_SEARCH] = option;
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (p.options[DHO_DOMAIN_SEARCH].len != 0 ||
+ p.options[DHO_DOMAIN_SEARCH].data != NULL)
+ abort();
+}
+
+void
+one_domain_valid()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data = "\007example\003org\0";
+ char *expected = "example.org.";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 13;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (option->len != strlen(expected) ||
+ strcmp(option->data, expected) != 0)
+ abort();
+
+ free(option->data);
+}
+
+void
+one_domain_truncated1()
+{
+ int ret;
+ struct option_data *option;
+ struct packet p;
+
+ char *data = "\007example\003org";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 12;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+one_domain_truncated2()
+{
+ int ret;
+ struct option_data *option;
+ struct packet p;
+
+ char *data = "\007ex";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 3;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_valid()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data = "\007example\003org\0\007example\003com\0";
+ char *expected = "example.org. example.com.";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 26;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (option->len != strlen(expected) ||
+ strcmp(option->data, expected) != 0)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_truncated1()
+{
+ int ret;
+ struct option_data *option;
+ struct packet p;
+
+ char *data = "\007example\003org\0\007example\003com";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 25;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_truncated2()
+{
+ int ret;
+ struct option_data *option;
+ struct packet p;
+
+ char *data = "\007example\003org\0\007ex";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 16;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_compressed()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data = "\007example\003org\0\006foobar\xc0\x08";
+ char *expected = "example.org. foobar.org.";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 22;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (option->len != strlen(expected) ||
+ strcmp(option->data, expected) != 0)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_infloop()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data = "\007example\003org\0\006foobar\xc0\x0d";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 22;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_forwardptr()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data = "\007example\003org\xc0\x0d\006foobar\0";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 22;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+two_domains_truncatedptr()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data = "\007example\003org\0\006foobar\xc0";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 21;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (ret != 1)
+ abort();
+
+ free(option->data);
+}
+
+void
+multiple_domains_valid()
+{
+ int ret;
+ struct packet p;
+ struct option_data *option;
+
+ char *data =
+ "\007example\003org\0\002cl\006foobar\003com\0\002fr\xc0\x10";
+
+ char *expected = "example.org. cl.foobar.com. fr.foobar.com.";
+
+ option = &p.options[DHO_DOMAIN_SEARCH];
+ option->len = 33;
+ option->data = malloc(option->len);
+ memcpy(option->data, data, option->len);
+
+ ret = setjmp(env);
+ if (ret == 0)
+ expand_domain_search(&p);
+
+ if (option->len != strlen(expected) ||
+ strcmp(option->data, expected) != 0)
+ abort();
+
+ free(option->data);
+}
+
+int
+main(int argc, char *argv[])
+{
+
+ no_option_present();
+
+ one_domain_valid();
+ one_domain_truncated1();
+ one_domain_truncated2();
+
+ two_domains_valid();
+ two_domains_truncated1();
+ two_domains_truncated2();
+
+ two_domains_compressed();
+ two_domains_infloop();
+ two_domains_forwardptr();
+ two_domains_truncatedptr();
+
+ multiple_domains_valid();
+
+ return (0);
+}
diff --git a/sbin/etherswitchcfg/etherswitchcfg.8 b/sbin/etherswitchcfg/etherswitchcfg.8
index 9cdbdd6..c5b93e9 100644
--- a/sbin/etherswitchcfg/etherswitchcfg.8
+++ b/sbin/etherswitchcfg/etherswitchcfg.8
@@ -1,4 +1,29 @@
+.\" Copyright (c) 2011-2012 Stefan Bethke.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
.\" $FreeBSD$
+.\"
.Dd September 20, 2013
.Dt ETHERSWITCHCFG 8
.Os
@@ -35,13 +60,14 @@ The
utility is used to configure an Ethernet switch built into the system.
.Nm
accepts a number of options:
+.Pp
.Bl -tag -width ".Fl f" -compact
.It Fl "f control file"
Specifies the
.Xr etherswitch 4
control file that represents the switch to be configured.
It defaults to
-.Li /dev/etherswitch0 .
+.Pa /dev/etherswitch0 .
.It Fl m
When reporting port information, also list available media options for
that port.
@@ -54,6 +80,7 @@ options are omitted.
The config command provides access to global switch configuration
parameters.
It support the following commands:
+.Pp
.Bl -tag -width ".Ar vlan_mode mode" -compact
.It Ar vlan_mode mode
Sets the switch VLAN mode (depends on the hardware).
@@ -74,6 +101,7 @@ 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:
+.Pp
.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.
@@ -88,8 +116,10 @@ for details on
and
.Ar mediaopt .
.El
+.Pp
And the following flags (please note that not all flags
-are supporterd by all switch drivers):
+are supported by all switch drivers):
+.Pp
.Bl -tag -width ".Ar addtag" -compact
.It Ar addtag
Add VLAN tag to each packet sent by the port.
@@ -100,7 +130,7 @@ 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.
+This options makes the switch port lock on the first MAC address it sees.
After that, usually you need to reset the switch to learn different
MAC addresses.
.It Ar -firstlock
@@ -125,6 +155,7 @@ The reg command provides access to the registers of the switch controller.
.Ss vlangroup
The vlangroup command selects one of the VLAN groups for configuration.
It supports the following commands:
+.Pp
.Bl -tag -width ".Ar vlangroup" -compact
.It Ar vlan VID
Sets the VLAN ID (802.1q VID) for this VLAN group.
@@ -142,13 +173,14 @@ to indicate that frames on this port are tagged.
.Sh FILES
.Bl -tag -width /dev/etherswitch? -compact
.It Pa /dev/etherswitch?
-Control file for the ethernet switch driver.
+Control file for the Ethernet switch driver.
.El
.Sh EXAMPLES
Configure VLAN group 1 with a VID of 2 and make ports 0 and 5 its 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.
+.Pp
.Dl # etherswitchcfg vlangroup1 vlan 2 members 0,5t port0 pvid 2
.Sh SEE ALSO
.Xr etherswitch 4
diff --git a/sbin/fdisk/fdisk.c b/sbin/fdisk/fdisk.c
index da5af0c..34b96ef 100644
--- a/sbin/fdisk/fdisk.c
+++ b/sbin/fdisk/fdisk.c
@@ -75,7 +75,8 @@ static int secsize = 0; /* the sensed sector size */
static char *disk;
-static int cyls, sectors, heads, cylsecs, disksecs;
+static int cyls, sectors, heads, cylsecs;
+static u_int32_t disksecs;
struct mboot {
unsigned char *bootinst; /* boot code */
@@ -873,10 +874,13 @@ get_params()
o = g_mediasize(fd);
if (o < 0)
return (-1);
- disksecs = o / u;
+ if (o / u <= NO_DISK_SECTORS)
+ disksecs = o / u;
+ else
+ disksecs = NO_DISK_SECTORS;
cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
- return (disksecs);
+ return (0);
}
static int
diff --git a/sbin/fsck_ffs/Makefile b/sbin/fsck_ffs/Makefile
index db2930b..028a486 100644
--- a/sbin/fsck_ffs/Makefile
+++ b/sbin/fsck_ffs/Makefile
@@ -7,7 +7,8 @@ LINKS+= ${BINDIR}/fsck_ffs ${BINDIR}/fsck_4.2bsd
MAN= fsck_ffs.8
MLINKS= fsck_ffs.8 fsck_ufs.8 fsck_ffs.8 fsck_4.2bsd.8
SRCS= dir.c ea.c fsutil.c inode.c main.c pass1.c pass1b.c pass2.c pass3.c \
- pass4.c pass5.c setup.c suj.c utilities.c gjournal.c getmntopts.c
+ pass4.c pass5.c setup.c suj.c utilities.c gjournal.c getmntopts.c \
+ globs.c
DPADD= ${LIBUFS}
LDADD= -lufs
WARNS?= 2
diff --git a/sbin/fsck_ffs/dir.c b/sbin/fsck_ffs/dir.c
index 965e3e3..7640f70 100644
--- a/sbin/fsck_ffs/dir.c
+++ b/sbin/fsck_ffs/dir.c
@@ -48,20 +48,14 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
-const char *lfname = "lost+found";
-int lfmode = 0700;
-struct dirtemplate emptydir = {
+static struct dirtemplate emptydir = {
0, DIRBLKSIZ, DT_UNKNOWN, 0, "",
0, 0, DT_UNKNOWN, 0, ""
};
-struct dirtemplate dirhead = {
+static struct dirtemplate dirhead = {
0, 12, DT_DIR, 1, ".",
0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
};
-struct odirtemplate odirhead = {
- 0, 12, 1, ".",
- 0, DIRBLKSIZ - 12, 2, ".."
-};
static int chgino(struct inodesc *);
static int dircheck(struct inodesc *, struct direct *);
@@ -133,6 +127,7 @@ dirscan(struct inodesc *idesc)
(size_t)dsize);
dirty(bp);
sbdirty();
+ rerun = 1;
}
if (n & STOP)
return (n);
diff --git a/sbin/fsck_ffs/ea.c b/sbin/fsck_ffs/ea.c
index 3517011..e9c3fce 100644
--- a/sbin/fsck_ffs/ea.c
+++ b/sbin/fsck_ffs/ea.c
@@ -65,7 +65,7 @@ eascan(struct inodesc *idesc, struct ufs2_dinode *dp)
char dbuf[DIRBLKSIZ];
printf("Inode %ju extsize %ju\n",
- (intmax_t)idesc->id_number, (intmax_t)dp->di_extsize);
+ (intmax_t)idesc->id_number, (uintmax_t)dp->di_extsize);
if (dp->di_extsize == 0)
return 0;
if (dp->di_extsize <= sblock.fs_fsize)
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
index 632d454..c0ec651 100644
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -192,15 +192,15 @@ struct bufarea {
"Inode Block", \
"Directory Contents", \
"User Data" }
-long readcnt[BT_NUMBUFTYPES];
-long totalreadcnt[BT_NUMBUFTYPES];
-struct timespec readtime[BT_NUMBUFTYPES];
-struct timespec totalreadtime[BT_NUMBUFTYPES];
-struct timespec startprog;
+extern long readcnt[BT_NUMBUFTYPES];
+extern long totalreadcnt[BT_NUMBUFTYPES];
+extern struct timespec readtime[BT_NUMBUFTYPES];
+extern struct timespec totalreadtime[BT_NUMBUFTYPES];
+extern struct timespec startprog;
-struct bufarea sblk; /* file system superblock */
-struct bufarea *pdirbp; /* current directory contents */
-struct bufarea *pbp; /* current inode block */
+extern struct bufarea sblk; /* file system superblock */
+extern struct bufarea *pdirbp; /* current directory contents */
+extern struct bufarea *pbp; /* current inode block */
#define dirty(bp) do { \
if (fswritefd < 0) \
@@ -219,7 +219,7 @@ struct bufarea *pbp; /* current inode block */
#define sblock (*sblk.b_un.b_fs)
enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
-ino_t cursnapshot;
+extern ino_t cursnapshot;
struct inodesc {
enum fixstate id_fix; /* policy on fixing errors */
@@ -282,63 +282,64 @@ struct inoinfo {
u_int i_numblks; /* size of block array in bytes */
ufs2_daddr_t i_blks[1]; /* actually longer */
} **inphead, **inpsort;
-long numdirs, dirhash, listmax, inplast;
-long countdirs; /* number of directories we actually found */
+extern long numdirs, dirhash, listmax, inplast;
+extern long countdirs; /* number of directories we actually found */
#define MIBSIZE 3 /* size of fsck sysctl MIBs */
-int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
-int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
-int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
-int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
-int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
-int adjnffree[MIBSIZE]; /* MIB command to adjust number of free frags */
-int adjnumclusters[MIBSIZE]; /* MIB command to adjust number of free clusters */
-int freefiles[MIBSIZE]; /* MIB command to free a set of files */
-int freedirs[MIBSIZE]; /* MIB command to free a set of directories */
-int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */
-struct fsck_cmd cmd; /* sysctl file system update commands */
-char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
-char *cdevname; /* name of device being checked */
-long dev_bsize; /* computed value of DEV_BSIZE */
-long secsize; /* actual disk sector size */
-u_int real_dev_bsize; /* actual disk sector size, not overriden */
-char nflag; /* assume a no response */
-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; /* 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 */
-int bkgrdcheck; /* determine if background check is possible */
-int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */
-char usedsoftdep; /* just fix soft dependency inconsistencies */
-char preen; /* just fix normal inconsistencies */
-char rerun; /* rerun fsck. Only used in non-preen mode */
-int returntosingle; /* 1 => return to single user mode on exit */
-char resolved; /* cleared if unresolved changes => not clean */
-char havesb; /* superblock has been read */
-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 */
-ino_t maxino; /* number of inodes in file system */
-
-ino_t lfdir; /* lost & found directory inode number */
-const char *lfname; /* lost & found directory name */
-int lfmode; /* lost & found directory creation mode */
-
-ufs2_daddr_t n_blks; /* number of blocks in use */
-ino_t n_files; /* number of files in use */
-
-volatile sig_atomic_t got_siginfo; /* received a SIGINFO */
-volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
+extern int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
+extern int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
+extern int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
+extern int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
+extern int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
+extern int adjnffree[MIBSIZE]; /* MIB command to adjust number of free frags */
+extern int adjnumclusters[MIBSIZE]; /* MIB command to adjust number of free clusters */
+extern int freefiles[MIBSIZE]; /* MIB command to free a set of files */
+extern int freedirs[MIBSIZE]; /* MIB command to free a set of directories */
+extern int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */
+extern struct fsck_cmd cmd; /* sysctl file system update commands */
+extern char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
+extern char *cdevname; /* name of device being checked */
+extern long dev_bsize; /* computed value of DEV_BSIZE */
+extern long secsize; /* actual disk sector size */
+extern u_int real_dev_bsize; /* actual disk sector size, not overriden */
+extern char nflag; /* assume a no response */
+extern char yflag; /* assume a yes response */
+extern int bkgrdflag; /* use a snapshot to run on an active system */
+extern int bflag; /* location of alternate super block */
+extern int debug; /* output debugging info */
+extern int Eflag; /* delete empty data blocks */
+extern int Zflag; /* zero empty data blocks */
+extern int inoopt; /* trim out unused inodes */
+extern char ckclean; /* only do work if not cleanly unmounted */
+extern int cvtlevel; /* convert to newer file system format */
+extern int bkgrdcheck; /* determine if background check is possible */
+extern int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */
+extern char usedsoftdep; /* just fix soft dependency inconsistencies */
+extern char preen; /* just fix normal inconsistencies */
+extern char rerun; /* rerun fsck. Only used in non-preen mode */
+extern int returntosingle; /* 1 => return to single user mode on exit */
+extern char resolved; /* cleared if unresolved changes => not clean */
+extern char havesb; /* superblock has been read */
+extern char skipclean; /* skip clean file systems if preening */
+extern int fsmodified; /* 1 => write done to file system */
+extern int fsreadfd; /* file descriptor for reading file system */
+extern int fswritefd; /* file descriptor for writing file system */
+extern int surrender; /* Give up if reads fail */
+extern int wantrestart; /* Restart fsck on early termination */
+
+extern ufs2_daddr_t maxfsblock; /* number of blocks in the file system */
+extern char *blockmap; /* ptr to primary blk allocation map */
+extern ino_t maxino; /* number of inodes in file system */
+
+extern ino_t lfdir; /* lost & found directory inode number */
+extern const char *lfname; /* lost & found directory name */
+extern int lfmode; /* lost & found directory creation mode */
+
+extern ufs2_daddr_t n_blks; /* number of blocks in use */
+extern ino_t n_files; /* number of files in use */
+
+extern volatile sig_atomic_t got_siginfo; /* received a SIGINFO */
+extern volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
#define clearinode(dp) \
if (sblock.fs_magic == FS_UFS1_MAGIC) { \
@@ -346,8 +347,8 @@ volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
} else { \
(dp)->dp2 = ufs2_zino; \
}
-struct ufs1_dinode ufs1_zino;
-struct ufs2_dinode ufs2_zino;
+extern struct ufs1_dinode ufs1_zino;
+extern struct ufs2_dinode ufs2_zino;
#define setbmap(blkno) setbit(blockmap, blkno)
#define testbmap(blkno) isset(blockmap, blkno)
@@ -360,6 +361,7 @@ struct ufs2_dinode ufs2_zino;
#define FOUND 0x10
#define EEXIT 8 /* Standard error exit. */
+#define ERESTART -1
int flushentry(void);
/*
@@ -367,7 +369,7 @@ int flushentry(void);
* to get space.
*/
static inline void*
-Malloc(int size)
+Malloc(size_t size)
{
void *retval;
@@ -382,7 +384,7 @@ Malloc(int size)
* to get space.
*/
static inline void*
-Calloc(int cnt, int size)
+Calloc(size_t cnt, size_t size)
{
void *retval;
@@ -428,6 +430,7 @@ void flush(int fd, struct bufarea *bp);
void freeblk(ufs2_daddr_t blkno, long frags);
void freeino(ino_t ino);
void freeinodebuf(void);
+void fsutilinit(void);
int ftypeok(union dinode *dp);
void getblk(struct bufarea *bp, ufs2_daddr_t blk, long size);
struct bufarea *cgget(int cg);
@@ -466,5 +469,6 @@ int setup(char *dev);
void gjournal_check(const char *filesys);
int suj_check(const char *filesys);
void update_maps(struct cg *, struct cg*, int);
+void fsckinit(void);
#endif /* !_FSCK_H_ */
diff --git a/sbin/fsck_ffs/fsck_ffs.8 b/sbin/fsck_ffs/fsck_ffs.8
index adf08d7..828df27 100644
--- a/sbin/fsck_ffs/fsck_ffs.8
+++ b/sbin/fsck_ffs/fsck_ffs.8
@@ -38,7 +38,7 @@
.Nd file system consistency check and interactive repair
.Sh SYNOPSIS
.Nm
-.Op Fl BEFfnpryZ
+.Op Fl BEFfnpRryZ
.Op Fl b Ar block
.Op Fl c Ar level
.Op Fl m Ar mode
@@ -266,6 +266,11 @@ which is assumed to be affirmative;
do not open the file system for writing.
.It Fl p
Preen file systems (see above).
+.It Fl R
+Instruct fsck_ffs to restart itself if it encounters certain errors that
+warrant another run. It will limit itself to a maximum of 10 restarts
+in a given run in order to avoid an endless loop with extremely corrupted
+filesystems.
.It Fl r
Free up excess unused inodes.
Decreasing the number of preallocated inodes reduces the
diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c
index 16ef819..bc80e2f 100644
--- a/sbin/fsck_ffs/fsutil.c
+++ b/sbin/fsck_ffs/fsutil.c
@@ -74,6 +74,25 @@ static struct bufarea cgblk; /* backup buffer for cylinder group blocks */
static TAILQ_HEAD(buflist, bufarea) bufhead; /* head of buffer cache list */
static int numbufs; /* size of buffer cache */
static char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
+static struct bufarea *cgbufs; /* header for cylinder group cache */
+static int flushtries; /* number of tries to reclaim memory */
+
+void
+fsutilinit(void)
+{
+ diskreads = totaldiskreads = totalreads = 0;
+ bzero(&startpass, sizeof(struct timespec));
+ bzero(&finishpass, sizeof(struct timespec));
+ bzero(&slowio_starttime, sizeof(struct timeval));
+ slowio_delay_usec = 10000;
+ slowio_pollcnt = 0;
+ bzero(&cgblk, sizeof(struct bufarea));
+ TAILQ_INIT(&bufhead);
+ numbufs = 0;
+ /* buftype ? */
+ cgbufs = NULL;
+ flushtries = 0;
+}
int
ftypeok(union dinode *dp)
@@ -206,7 +225,7 @@ cgget(int cg)
struct cg *cgp;
if (cgbufs == NULL) {
- cgbufs = Calloc(sblock.fs_ncg, sizeof(struct bufarea));
+ cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea));
if (cgbufs == NULL)
errx(EEXIT, "cannot allocate cylinder group buffers");
}
@@ -235,6 +254,8 @@ flushentry(void)
{
struct bufarea *cgbp;
+ if (flushtries == sblock.fs_ncg || cgbufs == NULL)
+ return (0);
cgbp = &cgbufs[flushtries++];
if (cgbp->b_un.b_cg == NULL)
return (0);
@@ -415,13 +436,15 @@ ckfini(int markclean)
}
if (numbufs != cnt)
errx(EEXIT, "panic: lost %d buffers", numbufs - cnt);
- for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
- if (cgbufs[cnt].b_un.b_cg == NULL)
- continue;
- flush(fswritefd, &cgbufs[cnt]);
- free(cgbufs[cnt].b_un.b_cg);
+ if (cgbufs != NULL) {
+ for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
+ if (cgbufs[cnt].b_un.b_cg == NULL)
+ continue;
+ flush(fswritefd, &cgbufs[cnt]);
+ free(cgbufs[cnt].b_un.b_cg);
+ }
+ free(cgbufs);
}
- free(cgbufs);
pbp = pdirbp = (struct bufarea *)0;
if (cursnapshot == 0 && sblock.fs_clean != markclean) {
if ((sblock.fs_clean = markclean) != 0) {
diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c
new file mode 100644
index 0000000..c5b1e1b
--- /dev/null
+++ b/sbin/fsck_ffs/globs.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 1980, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if 0
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1986, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/14/95";
+#endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#include <string.h>
+#include "fsck.h"
+
+long readcnt[BT_NUMBUFTYPES];
+long totalreadcnt[BT_NUMBUFTYPES];
+struct timespec readtime[BT_NUMBUFTYPES];
+struct timespec totalreadtime[BT_NUMBUFTYPES];
+struct timespec startprog;
+struct bufarea sblk; /* file system superblock */
+struct bufarea *pdirbp; /* current directory contents */
+struct bufarea *pbp; /* current inode block */
+ino_t cursnapshot;
+long numdirs, dirhash, listmax, inplast;
+long countdirs; /* number of directories we actually found */
+int adjrefcnt[MIBSIZE]; /* MIB command to adjust inode reference cnt */
+int adjblkcnt[MIBSIZE]; /* MIB command to adjust inode block count */
+int adjndir[MIBSIZE]; /* MIB command to adjust number of directories */
+int adjnbfree[MIBSIZE]; /* MIB command to adjust number of free blocks */
+int adjnifree[MIBSIZE]; /* MIB command to adjust number of free inodes */
+int adjnffree[MIBSIZE]; /* MIB command to adjust number of free frags */
+int adjnumclusters[MIBSIZE]; /* MIB command to adjust number of free clusters */
+int freefiles[MIBSIZE]; /* MIB command to free a set of files */
+int freedirs[MIBSIZE]; /* MIB command to free a set of directories */
+int freeblks[MIBSIZE]; /* MIB command to free a set of data blocks */
+struct fsck_cmd cmd; /* sysctl file system update commands */
+char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
+char *cdevname; /* name of device being checked */
+long dev_bsize; /* computed value of DEV_BSIZE */
+long secsize; /* actual disk sector size */
+u_int real_dev_bsize; /* actual disk sector size, not overriden */
+char nflag; /* assume a no response */
+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; /* 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 */
+int bkgrdcheck; /* determine if background check is possible */
+int bkgrdsumadj; /* whether the kernel have ability to adjust superblock summary */
+char usedsoftdep; /* just fix soft dependency inconsistencies */
+char preen; /* just fix normal inconsistencies */
+char rerun; /* rerun fsck. Only used in non-preen mode */
+int returntosingle; /* 1 => return to single user mode on exit */
+char resolved; /* cleared if unresolved changes => not clean */
+char havesb; /* superblock has been read */
+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 */
+int wantrestart; /* Restart fsck on early termination */
+ufs2_daddr_t maxfsblock; /* number of blocks in the file system */
+char *blockmap; /* ptr to primary blk allocation map */
+ino_t maxino; /* number of inodes in file system */
+ino_t lfdir; /* lost & found directory inode number */
+const char *lfname; /* lost & found directory name */
+int lfmode; /* lost & found directory creation mode */
+ufs2_daddr_t n_blks; /* number of blocks in use */
+ino_t n_files; /* number of files in use */
+volatile sig_atomic_t got_siginfo; /* received a SIGINFO */
+volatile sig_atomic_t got_sigalarm; /* received a SIGALRM */
+struct ufs1_dinode ufs1_zino;
+struct ufs2_dinode ufs2_zino;
+
+void
+fsckinit(void)
+{
+ bzero(readcnt, sizeof(long) * BT_NUMBUFTYPES);
+ bzero(totalreadcnt, sizeof(long) * BT_NUMBUFTYPES);
+ bzero(readtime, sizeof(struct timespec) * BT_NUMBUFTYPES);
+ bzero(totalreadtime, sizeof(struct timespec) * BT_NUMBUFTYPES);
+ bzero(&startprog, sizeof(struct timespec));;
+ bzero(&sblk, sizeof(struct bufarea));
+ pdirbp = NULL;
+ pbp = NULL;
+ cursnapshot = 0;
+ numdirs = dirhash = listmax = inplast = 0;
+ countdirs = 0;
+ bzero(adjrefcnt, sizeof(int) * MIBSIZE);
+ bzero(adjblkcnt, sizeof(int) * MIBSIZE);
+ bzero(adjndir, sizeof(int) * MIBSIZE);
+ bzero(adjnbfree, sizeof(int) * MIBSIZE);
+ bzero(adjnifree, sizeof(int) * MIBSIZE);
+ bzero(adjnffree, sizeof(int) * MIBSIZE);
+ bzero(adjnumclusters, sizeof(int) * MIBSIZE);
+ bzero(freefiles, sizeof(int) * MIBSIZE);
+ bzero(freedirs, sizeof(int) * MIBSIZE);
+ bzero(freeblks, sizeof(int) * MIBSIZE);
+ bzero(&cmd, sizeof(struct fsck_cmd));
+ bzero(snapname, sizeof(char) * BUFSIZ);
+ cdevname = NULL;
+ dev_bsize = 0;
+ secsize = 0;
+ real_dev_bsize = 0;
+ bkgrdsumadj = 0;
+ usedsoftdep = 0;
+ rerun = 0;
+ returntosingle = 0;
+ resolved = 0;
+ havesb = 0;
+ fsmodified = 0;
+ fsreadfd = 0;
+ fswritefd = 0;
+ maxfsblock = 0;
+ blockmap = NULL;
+ maxino = 0;
+ lfdir = 0;
+ lfname = "lost+found";
+ lfmode = 0700;
+ n_blks = 0;
+ n_files = 0;
+ got_siginfo = 0;
+ got_sigalarm = 0;
+ bzero(&ufs1_zino, sizeof(struct ufs1_dinode));
+ bzero(&ufs2_zino, sizeof(struct ufs2_dinode));
+}
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
index 1a1c03b..08c7745 100644
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
#include "fsck.h"
+int restarts;
+
static void usage(void) __dead2;
static int argtoi(int flag, const char *req, const char *str, int base);
static int checkfilesys(char *filesys);
@@ -82,7 +84,7 @@ main(int argc, char *argv[])
sync();
skipclean = 1;
inoopt = 0;
- while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:nprSyZ")) != -1) {
+ while ((ch = getopt(argc, argv, "b:Bc:CdEfFm:npRrSyZ")) != -1) {
switch (ch) {
case 'b':
skipclean = 0;
@@ -138,6 +140,9 @@ main(int argc, char *argv[])
ckclean++;
break;
+ case 'R':
+ wantrestart = 1;
+ break;
case 'r':
inoopt++;
break;
@@ -186,8 +191,12 @@ main(int argc, char *argv[])
rlimit.rlim_cur = rlimit.rlim_max;
(void)setrlimit(RLIMIT_DATA, &rlimit);
}
- while (argc-- > 0)
- (void)checkfilesys(*argv++);
+ while (argc > 0) {
+ if (checkfilesys(*argv) == ERESTART)
+ continue;
+ argc--;
+ argv++;
+ }
if (returntosingle)
ret = 2;
@@ -228,6 +237,8 @@ checkfilesys(char *filesys)
iov = NULL;
iovlen = 0;
errmsg[0] = '\0';
+ fsutilinit();
+ fsckinit();
cdevname = filesys;
if (debug && ckclean)
@@ -550,8 +561,12 @@ checkfilesys(char *filesys)
inostathead = NULL;
if (fsmodified && !preen)
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
- if (rerun)
+ if (rerun) {
+ if (wantrestart && (restarts++ < 10) &&
+ (preen || reply("RESTART")))
+ return (ERESTART);
printf("\n***** PLEASE RERUN FSCK *****\n");
+ }
if (chkdoreload(mntp) != 0) {
if (!fsmodified)
return (0);
@@ -654,3 +669,15 @@ usage(void)
getprogname());
exit(1);
}
+
+void
+infohandler(int sig __unused)
+{
+ got_siginfo = 1;
+}
+
+void
+alarmhandler(int sig __unused)
+{
+ got_sigalarm = 1;
+}
diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c
index 3199541..67fba6e 100644
--- a/sbin/fsck_ffs/pass1.c
+++ b/sbin/fsck_ffs/pass1.c
@@ -68,6 +68,8 @@ pass1(void)
u_int8_t *cp;
int c, rebuildcg;
+ badblk = dupblk = lastino = 0;
+
/*
* Set file system reserved blocks in used block map.
*/
@@ -463,6 +465,7 @@ pass1check(struct inodesc *idesc)
ckfini(0);
exit(EEXIT);
}
+ rerun = 1;
return (STOP);
}
}
@@ -483,6 +486,7 @@ pass1check(struct inodesc *idesc)
ckfini(0);
exit(EEXIT);
}
+ rerun = 1;
return (STOP);
}
new = (struct dups *)Malloc(sizeof(struct dups));
@@ -492,6 +496,7 @@ pass1check(struct inodesc *idesc)
ckfini(0);
exit(EEXIT);
}
+ rerun = 1;
return (STOP);
}
new->dup = blkno;
diff --git a/sbin/fsck_ffs/pass1b.c b/sbin/fsck_ffs/pass1b.c
index e635935..69a23c2 100644
--- a/sbin/fsck_ffs/pass1b.c
+++ b/sbin/fsck_ffs/pass1b.c
@@ -80,8 +80,10 @@ pass1b(void)
continue;
idesc.id_number = inumber;
if (inoinfo(inumber)->ino_state != USTATE &&
- (ckinode(dp, &idesc) & STOP))
+ (ckinode(dp, &idesc) & STOP)) {
+ rerun = 1;
return;
+ }
}
}
}
@@ -106,8 +108,10 @@ pass1bcheck(struct inodesc *idesc)
if (dlp == muldup)
break;
}
- if (muldup == 0 || duphead == muldup->next)
+ if (muldup == 0 || duphead == muldup->next) {
+ rerun = 1;
return (STOP);
+ }
}
return (res);
}
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index 5fca0f5..9d6a2ec 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -125,26 +125,26 @@ struct suj_cg {
int sc_cgx;
};
-LIST_HEAD(cghd, suj_cg) cghash[SUJ_HASHSIZE];
-LIST_HEAD(dblkhd, data_blk) dbhash[SUJ_HASHSIZE];
-struct suj_cg *lastcg;
-struct data_blk *lastblk;
+static LIST_HEAD(cghd, suj_cg) cghash[SUJ_HASHSIZE];
+static LIST_HEAD(dblkhd, data_blk) dbhash[SUJ_HASHSIZE];
+static struct suj_cg *lastcg;
+static struct data_blk *lastblk;
-TAILQ_HEAD(seghd, suj_seg) allsegs;
-uint64_t oldseq;
+static TAILQ_HEAD(seghd, suj_seg) allsegs;
+static uint64_t oldseq;
static struct uufsd *disk = NULL;
static struct fs *fs = NULL;
-ino_t sujino;
+static ino_t sujino;
/*
* Summary statistics.
*/
-uint64_t freefrags;
-uint64_t freeblocks;
-uint64_t freeinos;
-uint64_t freedir;
-uint64_t jbytes;
-uint64_t jrecs;
+static uint64_t freefrags;
+static uint64_t freeblocks;
+static uint64_t freeinos;
+static uint64_t freedir;
+static uint64_t jbytes;
+static uint64_t jrecs;
static jmp_buf jmpbuf;
@@ -155,6 +155,7 @@ static void ino_decr(ino_t);
static void ino_adjust(struct suj_ino *);
static void ino_build(struct suj_ino *);
static int blk_isfree(ufs2_daddr_t);
+static void initsuj(void);
static void *
errmalloc(size_t n)
@@ -2413,7 +2414,7 @@ struct jextent {
int je_blocks; /* Disk block count. */
};
-struct jblocks *suj_jblocks;
+static struct jblocks *suj_jblocks;
static struct jblocks *
jblocks_create(void)
@@ -2673,8 +2674,8 @@ suj_check(const char *filesys)
struct suj_seg *seg;
struct suj_seg *segn;
+ initsuj();
opendisk(filesys);
- TAILQ_INIT(&allsegs);
/*
* Set an exit point when SUJ check failed
@@ -2763,3 +2764,28 @@ suj_check(const char *filesys)
return (0);
}
+
+static void
+initsuj(void)
+{
+ int i;
+
+ for (i = 0; i < SUJ_HASHSIZE; i++) {
+ LIST_INIT(&cghash[i]);
+ LIST_INIT(&dbhash[i]);
+ }
+ lastcg = NULL;
+ lastblk = NULL;
+ TAILQ_INIT(&allsegs);
+ oldseq = 0;
+ disk = NULL;
+ fs = NULL;
+ sujino = 0;
+ freefrags = 0;
+ freeblocks = 0;
+ freeinos = 0;
+ freedir = 0;
+ jbytes = 0;
+ jrecs = 0;
+ suj_jblocks = NULL;
+}
diff --git a/sbin/fsck_ffs/utilities.c b/sbin/fsck_ffs/utilities.c
index 5e7d69c..4e82c31 100644
--- a/sbin/fsck_ffs/utilities.c
+++ b/sbin/fsck_ffs/utilities.c
@@ -108,14 +108,3 @@ retry:
return (origname);
}
-void
-infohandler(int sig __unused)
-{
- got_siginfo = 1;
-}
-
-void
-alarmhandler(int sig __unused)
-{
- got_sigalarm = 1;
-}
diff --git a/sbin/fsdb/Makefile b/sbin/fsdb/Makefile
index 65333ef..f921e89 100644
--- a/sbin/fsdb/Makefile
+++ b/sbin/fsdb/Makefile
@@ -6,7 +6,7 @@ PROG= fsdb
MAN= fsdb.8
SRCS= fsdb.c fsdbutil.c \
dir.c ea.c fsutil.c inode.c pass1.c pass1b.c pass2.c pass3.c pass4.c \
- pass5.c setup.c utilities.c ffs_subr.c ffs_tables.c
+ pass5.c setup.c utilities.c ffs_subr.c ffs_tables.c globs.c
CFLAGS+= -I${.CURDIR}/../fsck_ffs
WARNS?= 2
LDADD= -ledit -ltermcap
diff --git a/sbin/gbde/gbde.c b/sbin/gbde/gbde.c
index 5f0462b..b6baa95 100644
--- a/sbin/gbde/gbde.c
+++ b/sbin/gbde/gbde.c
@@ -805,6 +805,7 @@ main(int argc, char **argv)
break;
case 'i':
i_opt = !i_opt;
+ break;
case 'k':
k_opt = optarg;
break;
diff --git a/sbin/geom/Makefile b/sbin/geom/Makefile
index 88b8240..ced5842 100644
--- a/sbin/geom/Makefile
+++ b/sbin/geom/Makefile
@@ -9,7 +9,7 @@
PROG= geom
SRCS= geom.c geom_label.c geom_part.c subr.c
-NO_MAN=
+MAN=
WARNS?= 2
CFLAGS+=-I${.CURDIR} -I${.CURDIR}/core -DSTATIC_GEOM_CLASSES
diff --git a/sbin/geom/class/eli/geom_eli.c b/sbin/geom/class/eli/geom_eli.c
index 3eee6f2..7df4d90 100644
--- a/sbin/geom/class/eli/geom_eli.c
+++ b/sbin/geom/class/eli/geom_eli.c
@@ -789,7 +789,7 @@ eli_init(struct gctl_req *req)
if (val == 0)
md.md_sectorsize = secsize;
else {
- if (val < 0 || (val % secsize) != 0) {
+ if (val < 0 || (val % secsize) != 0 || !powerof2(val)) {
gctl_error(req, "Invalid sector size.");
return;
}
diff --git a/sbin/geom/class/mirror/geom_mirror.c b/sbin/geom/class/mirror/geom_mirror.c
index 9f0acc6..30f5f84 100644
--- a/sbin/geom/class/mirror/geom_mirror.c
+++ b/sbin/geom/class/mirror/geom_mirror.c
@@ -28,6 +28,7 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <err.h>
#include <errno.h>
#include <paths.h>
#include <stdio.h>
@@ -53,6 +54,7 @@ static void mirror_activate(struct gctl_req *req);
static void mirror_clear(struct gctl_req *req);
static void mirror_dump(struct gctl_req *req);
static void mirror_label(struct gctl_req *req);
+static void mirror_resize(struct gctl_req *req, unsigned flags);
struct g_command class_commands[] = {
{ "activate", G_FLAG_VERBOSE, mirror_main, G_NULL_OPTS,
@@ -80,6 +82,13 @@ struct g_command class_commands[] = {
{ "deactivate", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
"[-v] name prov ..."
},
+ { "destroy", G_FLAG_VERBOSE, NULL,
+ {
+ { 'f', "force", NULL, G_TYPE_BOOL },
+ G_OPT_SENTINEL
+ },
+ "[-fv] name ..."
+ },
{ "dump", 0, mirror_main, G_NULL_OPTS,
"prov ..."
},
@@ -112,6 +121,13 @@ struct g_command class_commands[] = {
{ "remove", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
"[-v] name prov ..."
},
+ { "resize", G_FLAG_VERBOSE, mirror_resize,
+ {
+ { 's', "size", "*", G_TYPE_STRING },
+ G_OPT_SENTINEL
+ },
+ "[-s size] [-v] name"
+ },
{ "stop", G_FLAG_VERBOSE, NULL,
{
{ 'f', "force", NULL, G_TYPE_BOOL },
@@ -376,3 +392,96 @@ mirror_activate(struct gctl_req *req)
printf("Provider %s activated.\n", path);
}
}
+
+static struct gclass *
+find_class(struct gmesh *mesh, const char *name)
+{
+ struct gclass *classp;
+
+ LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
+ if (strcmp(classp->lg_name, name) == 0)
+ return (classp);
+ }
+ return (NULL);
+}
+
+static struct ggeom *
+find_geom(struct gclass *classp, const char *name)
+{
+ struct ggeom *gp;
+
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
+ if (strcmp(gp->lg_name, name) == 0)
+ return (gp);
+ }
+ return (NULL);
+}
+
+static void
+mirror_resize(struct gctl_req *req, unsigned flags __unused)
+{
+ struct gmesh mesh;
+ struct gclass *classp;
+ struct ggeom *gp;
+ struct gprovider *pp;
+ struct gconsumer *cp;
+ off_t size;
+ int error, nargs;
+ const char *name;
+ char ssize[30];
+
+ nargs = gctl_get_int(req, "nargs");
+ if (nargs < 1) {
+ gctl_error(req, "Too few arguments.");
+ return;
+ }
+ error = geom_gettree(&mesh);
+ if (error)
+ errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
+ name = gctl_get_ascii(req, "class");
+ if (name == NULL)
+ abort();
+ classp = find_class(&mesh, name);
+ if (classp == NULL)
+ errx(EXIT_FAILURE, "Class %s not found.", name);
+ name = gctl_get_ascii(req, "arg0");
+ if (name == NULL)
+ abort();
+ gp = find_geom(classp, name);
+ if (gp == NULL)
+ errx(EXIT_FAILURE, "No such geom: %s.", name);
+ pp = LIST_FIRST(&gp->lg_provider);
+ if (pp == NULL)
+ errx(EXIT_FAILURE, "Provider of geom %s not found.", name);
+ size = pp->lg_mediasize;
+ name = gctl_get_ascii(req, "size");
+ if (name == NULL)
+ errx(EXIT_FAILURE, "The size is not specified.");
+ if (*name == '*') {
+#define CSZ(c) ((c)->lg_provider->lg_mediasize - \
+ (c)->lg_provider->lg_sectorsize)
+ /* Find the maximum possible size */
+ LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
+ if (CSZ(cp) > size)
+ size = CSZ(cp);
+ }
+ LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
+ if (CSZ(cp) < size)
+ size = CSZ(cp);
+ }
+#undef CSZ
+ if (size == pp->lg_mediasize)
+ errx(EXIT_FAILURE,
+ "Cannot expand provider %s\n",
+ pp->lg_name);
+ } else {
+ error = g_parse_lba(name, pp->lg_sectorsize, &size);
+ if (error)
+ errc(EXIT_FAILURE, error, "Invalid size param");
+ size *= pp->lg_sectorsize;
+ }
+ snprintf(ssize, sizeof(ssize), "%ju", (uintmax_t)size);
+ gctl_change_param(req, "size", -1, ssize);
+ geom_deletetree(&mesh);
+ gctl_issue(req);
+}
diff --git a/sbin/geom/class/mirror/gmirror.8 b/sbin/geom/class/mirror/gmirror.8
index 58ff8af..bca5bdb 100644
--- a/sbin/geom/class/mirror/gmirror.8
+++ b/sbin/geom/class/mirror/gmirror.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 8, 2009
+.Dd December 27, 2013
.Dt GMIRROR 8
.Os
.Sh NAME
@@ -60,6 +60,11 @@
.Ar name
.Ar prov ...
.Nm
+.Cm resize
+.Op Fl v
+.Op Fl s Ar size
+.Ar name
+.Nm
.Cm insert
.Op Fl hiv
.Op Fl p Ar priority
@@ -81,6 +86,10 @@
.Ar name
.Ar prov ...
.Nm
+.Cm destroy
+.Op Fl fv
+.Ar name ...
+.Nm
.Cm forget
.Op Fl v
.Ar name ...
@@ -193,6 +202,16 @@ balance algorithm.
Rebuild the given mirror components forcibly.
If autosynchronization was not turned off for the given device, this command
should be unnecessary.
+.It Cm resize
+Change the size of the given mirror.
+.Pp
+Additional options include:
+.Bl -tag -width ".Fl s Ar size"
+.It Fl s Ar size
+New size of the mirror is expressed in logical block numbers.
+This option can be omitted, then it will be automatically calculated to
+maximum available size.
+.El
.It Cm insert
Add the given component(s) to the existing mirror.
.Pp
@@ -212,6 +231,14 @@ Activate the given component(s), which were marked as inactive before.
.It Cm deactivate
Mark the given component(s) as inactive, so it will not be automatically
connected to the mirror.
+.It Cm destroy
+Stop the given mirror and clear metadata on all its components.
+.Pp
+Additional options include:
+.Bl -tag -width ".Fl f"
+.It Fl f
+Stop the given mirror even if it is opened.
+.El
.It Cm forget
Forget about components which are not connected.
This command is useful when a disk has failed and cannot be reconnected, preventing the
@@ -300,9 +327,7 @@ gmirror activate data da1
.Sh NOTES
Doing kernel dumps to
.Nm
-providers.
-.Pp
-This is possible, but some conditions have to be met.
+providers is possible, but some conditions have to be met.
First of all, a kernel dump will go only to one component and
.Nm
always chooses the component with the highest priority.
diff --git a/sbin/geom/class/part/geom_part.c b/sbin/geom/class/part/geom_part.c
index 9b3e0e5..ee4b2a9 100644
--- a/sbin/geom/class/part/geom_part.c
+++ b/sbin/geom/class/part/geom_part.c
@@ -364,7 +364,11 @@ gpart_autofill_resize(struct gctl_req *req)
}
offset = (pp->lg_stripeoffset / pp->lg_sectorsize) % alignment;
- last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0);
+ s = find_geomcfg(gp, "last");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "Final block not found for geom %s",
+ gp->lg_name);
+ last = (off_t)strtoimax(s, NULL, 0);
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
s = find_provcfg(pp, "index");
if (s == NULL)
@@ -450,8 +454,19 @@ gpart_autofill(struct gctl_req *req)
if (s == NULL)
abort();
gp = find_geom(cp, s);
- if (gp == NULL)
- errx(EXIT_FAILURE, "No such geom: %s.", s);
+ if (gp == NULL) {
+ if (g_device_path(s) == NULL) {
+ errx(EXIT_FAILURE, "No such geom %s.", s);
+ } else {
+ /*
+ * We don't free memory allocated by g_device_path() as
+ * we are about to exit.
+ */
+ errx(EXIT_FAILURE,
+ "No partitioning scheme found on geom %s. Create one first using 'gpart create'.",
+ s);
+ }
+ }
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
if (pp == NULL)
errx(EXIT_FAILURE, "Provider for geom %s not found.", s);
@@ -502,8 +517,16 @@ gpart_autofill(struct gctl_req *req)
if (size > alignment)
size = ALIGNDOWN(size, alignment);
- first = (off_t)strtoimax(find_geomcfg(gp, "first"), NULL, 0);
- last = (off_t)strtoimax(find_geomcfg(gp, "last"), NULL, 0);
+ s = find_geomcfg(gp, "first");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "Starting block not found for geom %s",
+ gp->lg_name);
+ first = (off_t)strtoimax(s, NULL, 0);
+ s = find_geomcfg(gp, "last");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "Final block not found for geom %s",
+ gp->lg_name);
+ last = (off_t)strtoimax(s, NULL, 0);
grade = ~0ULL;
a_first = ALIGNUP(first + offset, alignment);
last = ALIGNDOWN(last + offset, alignment);
@@ -587,12 +610,22 @@ gpart_show_geom(struct ggeom *gp, const char *element, int show_providers)
int idx, wblocks, wname, wmax;
scheme = find_geomcfg(gp, "scheme");
+ if (scheme == NULL)
+ errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name);
s = find_geomcfg(gp, "first");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "Starting block not found for geom %s",
+ gp->lg_name);
first = (off_t)strtoimax(s, NULL, 0);
s = find_geomcfg(gp, "last");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "Final block not found for geom %s",
+ gp->lg_name);
last = (off_t)strtoimax(s, NULL, 0);
wblocks = strlen(s);
s = find_geomcfg(gp, "state");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "State not found for geom %s", gp->lg_name);
if (s != NULL && *s != 'C')
s = NULL;
wmax = strlen(gp->lg_name);
@@ -748,6 +781,8 @@ gpart_backup(struct gctl_req *req, unsigned int fl __unused)
abort();
pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
s = find_geomcfg(gp, "last");
+ if (s == NULL)
+ abort();
wblocks = strlen(s);
wtype = 0;
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
@@ -757,6 +792,8 @@ gpart_backup(struct gctl_req *req, unsigned int fl __unused)
wtype = i;
}
s = find_geomcfg(gp, "entries");
+ if (s == NULL)
+ abort();
windex = strlen(s);
printf("%s %s\n", scheme, s);
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
@@ -1177,6 +1214,8 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl)
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
s = find_geomcfg(gp, "scheme");
+ if (s == NULL)
+ errx(EXIT_FAILURE, "Scheme not found for geom %s", gp->lg_name);
vtoc8 = 0;
if (strcmp(s, "VTOC8") == 0)
vtoc8 = 1;
diff --git a/sbin/geom/class/part/gpart.8 b/sbin/geom/class/part/gpart.8
index 3ce79a8..194a19f 100644
--- a/sbin/geom/class/part/gpart.8
+++ b/sbin/geom/class/part/gpart.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 1, 2013
+.Dd April 2, 2014
.Dt GPART 8
.Os
.Sh NAME
@@ -557,6 +557,16 @@ Interface (EFI).
In such cases, the GPT partitioning scheme is used and the
actual partition type for the system partition can also be specified as
.Qq Li "!c12a7328-f81f-11d2-ba4b-00a0c93ec93b" .
+.It Cm fat16
+A partition that contains a FAT16 filesystem.
+The scheme-specific type is
+.Qq Li "!6"
+for MBR.
+.It Cm fat32
+A partition that contains a FAT32 filesystem.
+The scheme-specific type is
+.Qq Li "!11"
+for MBR.
.It Cm freebsd
A
.Fx
@@ -620,6 +630,16 @@ A partition that is sub-partitioned by a Master Boot Record (MBR).
This type is known as
.Qq Li "!024dee41-33e7-11d3-9d69-0008c781f39f"
by GPT.
+.It Cm ms-basic-data
+A basic data partition (BDP) for Microsoft operating systems.
+In the GPT this type is the equivalent to partition types
+.Cm fat16 , fat32
+and
+.Cm ntfs
+in MBR.
+The scheme-specific type is
+.Qq Li "!ebd0a0a2-b9e5-4433-87c0-68b6b72699c7"
+for GPT.
.It Cm ms-ldm-data
A partition that contains Logical Disk Manager (LDM) volumes.
The scheme-specific types are
@@ -632,6 +652,11 @@ A partition that contains Logical Disk Manager (LDM) database.
The scheme-specific type is
.Qq Li "!5808c8aa-7e8f-42e0-85d2-e1e90434cfb3"
for GPT.
+.It Cm ntfs
+A partition that contains a NTFS or exFAT filesystem.
+The scheme-specific type is
+.Qq Li "!7"
+for MBR.
.El
.Sh ATTRIBUTES
The scheme-specific attributes for EBR:
diff --git a/sbin/growfs/Makefile b/sbin/growfs/Makefile
index f464ed7..58ce41d 100644
--- a/sbin/growfs/Makefile
+++ b/sbin/growfs/Makefile
@@ -6,6 +6,8 @@
#GFSDBG=
+.include <bsd.own.mk>
+
.PATH: ${.CURDIR}/../mount
PROG= growfs
@@ -20,4 +22,8 @@ SRCS+= debug.c
DPADD= ${LIBUTIL}
LDADD= -lutil
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/sbin/growfs/debug.c b/sbin/growfs/debug.c
index 26a5668..55e2b13 100644
--- a/sbin/growfs/debug.c
+++ b/sbin/growfs/debug.c
@@ -765,7 +765,7 @@ dbg_dump_ufs2_ino(struct fs *sb, const char *comment, struct ufs2_dinode *ino)
fprintf(dbg_log, "gen int32_t 0x%08x\n", ino->di_gen);
fprintf(dbg_log, "kernflags u_int32_t 0x%08x\n", ino->di_kernflags);
fprintf(dbg_log, "flags u_int32_t 0x%08x\n", ino->di_flags);
- fprintf(dbg_log, "extsize int32_t 0x%08x\n", ino->di_extsize);
+ fprintf(dbg_log, "extsize u_int32_t 0x%08x\n", ino->di_extsize);
/* XXX: What do we do with di_extb[NXADDR]? */
diff --git a/sbin/growfs/growfs.8 b/sbin/growfs/growfs.8
index 664e723..9d62a83 100644
--- a/sbin/growfs/growfs.8
+++ b/sbin/growfs/growfs.8
@@ -37,7 +37,7 @@
.\" $TSHeader: src/sbin/growfs/growfs.8,v 1.3 2000/12/12 19:31:00 tomsoft Exp $
.\" $FreeBSD$
.\"
-.Dd April 30, 2012
+.Dd November 26, 2013
.Dt GROWFS 8
.Os
.Sh NAME
diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c
index b8a81c2..96897e2 100644
--- a/sbin/growfs/growfs.c
+++ b/sbin/growfs/growfs.c
@@ -201,7 +201,7 @@ growfs(int fsi, int fso, unsigned int Nflag)
* Now build the cylinders group blocks and
* then print out indices of cylinder groups.
*/
- printf("super-block backups (for fsck -b #) at:\n");
+ printf("super-block backups (for fsck_ffs -b #) at:\n");
i = 0;
width = charsperline();
diff --git a/sbin/growfs/tests/Makefile b/sbin/growfs/tests/Makefile
new file mode 100644
index 0000000..7a6a831
--- /dev/null
+++ b/sbin/growfs/tests/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sbin/growfs
+
+TAP_TESTS_PERL= legacy_test
+
+.include <bsd.test.mk>
diff --git a/sbin/growfs/tests/legacy_test.pl b/sbin/growfs/tests/legacy_test.pl
new file mode 100755
index 0000000..7316951
--- /dev/null
+++ b/sbin/growfs/tests/legacy_test.pl
@@ -0,0 +1,89 @@
+# $FreeBSD$
+
+use strict;
+use warnings;
+use Test::More tests => 19;
+use Fcntl qw(:DEFAULT :seek);
+
+use constant BLK => 512;
+use constant BLKS_PER_MB => 2048;
+
+my $unit;
+END { system "mdconfig -du$unit" if defined $unit };
+
+sub setsize {
+ my ($partszMB, $unitszMB) = @_;
+
+ open my $fd, "|-", "disklabel -R md$unit /dev/stdin" or die;
+ print $fd "a: ", ($partszMB * BLKS_PER_MB), " 0 4.2BSD 1024 8192\n";
+ print $fd "c: ", ($unitszMB * BLKS_PER_MB), " 0 unused 0 0\n";
+ close $fd;
+}
+
+sub fill {
+ my ($start, $size, $content) = @_;
+
+ my $content512 = $content x (int(512 / length $content) + 1);
+ substr($content512, 512) = "";
+ sysopen my $fd, "/dev/md$unit", O_RDWR or die "/dev/md$unit: $!";
+ seek($fd, $start * BLK, SEEK_SET);
+ while ($size) {
+ syswrite($fd, $content512) == 512 or die "write: $!";
+ $size--;
+ }
+}
+
+SKIP: {
+ skip "Cannot test without UID 0", 19 if $<;
+
+ chomp(my $md = `mdconfig -s40m`);
+ like($md, qr/^md\d+$/, "Created $md with size 40m") or die;
+ $unit = substr $md, 2;
+
+ for my $type (1..2) {
+
+ initialise: {
+ ok(setsize(10, 40), "Sized ${md}a to 10m");
+ system "newfs -O $type -U ${md}a >/dev/null";
+ is($?, 0, "Initialised the filesystem on ${md}a as UFS$type");
+ chomp(my @out = `fsck -tufs -y ${md}a`);
+ ok(!grep(/MODIFIED/, @out), "fsck says ${md}a is clean, " .
+ scalar(@out) . " lines of output");
+ }
+
+ extend20_zeroed: {
+ ok(setsize(20, 40), "Sized ${md}a to 20m");
+ diag "Filling the extent with zeros";
+ fill(10 * BLKS_PER_MB, 10 * BLKS_PER_MB, chr(0));
+ my $out = `growfs -y ${md}a`;
+ is($?, 0, "Extended the filesystem on ${md}a") or print $out;
+
+ my ($unallocated) = $out =~ m{\d+ sectors cannot be allocated};
+ fill(30 * BLKS_PER_MB - $unallocated, $unallocated, chr(0))
+ if $unallocated;
+
+ chomp(my @out = `fsck -tufs -y ${md}a`);
+ ok(!grep(/MODIFIED/, @out), "fsck says ${md}a is clean, " .
+ scalar(@out) . " lines of output");
+ }
+
+ extend30_garbaged: {
+ ok(setsize(30, 40), "Sized ${md}a to 30m");
+ diag "Filling the extent with garbage";
+ fill(20 * BLKS_PER_MB, 10 * BLKS_PER_MB, chr(0xaa) . chr(0x55));
+ my $out = `growfs -y ${md}a`;
+ is($?, 0, "Extended the filesystem on ${md}a") or print $out;
+
+ my ($unallocated) = $out =~ m{\d+ sectors cannot be allocated};
+ fill(30 * BLKS_PER_MB - $unallocated, $unallocated, chr(0))
+ if $unallocated;
+
+ chomp(my @out = `fsck -tufs -y ${md}a`);
+ ok(!grep(/MODIFIED/, @out), "fsck says ${md}a is clean, " .
+ scalar(@out) . " lines of output");
+ }
+ }
+
+ system "mdconfig -du$unit";
+ undef $unit;
+}
diff --git a/sbin/gvinum/gvinum.c b/sbin/gvinum/gvinum.c
index bb4b47d..5760d2b 100644
--- a/sbin/gvinum/gvinum.c
+++ b/sbin/gvinum/gvinum.c
@@ -421,6 +421,7 @@ create_drive(char *device)
const char *errstr;
char *drivename, *dname;
int drives, i, flags, volumes, subdisks, plexes;
+ int found = 0;
flags = plexes = subdisks = volumes = 0;
drives = 1;
@@ -448,10 +449,8 @@ create_drive(char *device)
errstr = gctl_issue(req);
if (errstr != NULL) {
warnx("error creating drive: %s", errstr);
- gctl_free(req);
- return (NULL);
+ drivename = NULL;
} else {
- gctl_free(req);
/* XXX: This is needed because we have to make sure the drives
* are created before we return. */
/* Loop until it's in the config. */
@@ -461,14 +460,18 @@ create_drive(char *device)
/* If we got a different name, quit. */
if (dname == NULL)
continue;
- if (strcmp(dname, drivename)) {
- free(dname);
- return (drivename);
- }
+ if (strcmp(dname, drivename))
+ found = 1;
free(dname);
dname = NULL;
+ if (found)
+ break;
usleep(100000); /* Sleep for 0.1s */
}
+ if (found == 0) {
+ warnx("error creating drive");
+ drivename = NULL;
+ }
}
gctl_free(req);
return (drivename);
diff --git a/sbin/hastctl/hastctl.c b/sbin/hastctl/hastctl.c
index 11b5b8d..474f1b2 100644
--- a/sbin/hastctl/hastctl.c
+++ b/sbin/hastctl/hastctl.c
@@ -355,6 +355,13 @@ control_list(struct nv *nv)
(uintmax_t)nv_get_uint64(nv, "stat_write_error%u", ii),
(uintmax_t)nv_get_uint64(nv, "stat_delete_error%u", ii),
(uintmax_t)nv_get_uint64(nv, "stat_flush_error%u", ii));
+ printf(" queues: "
+ "local: %ju, send: %ju, recv: %ju, done: %ju, idle: %ju\n",
+ (uintmax_t)nv_get_uint64(nv, "local_queue_size%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "send_queue_size%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "recv_queue_size%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "done_queue_size%u", ii),
+ (uintmax_t)nv_get_uint64(nv, "idle_queue_size%u", ii));
}
return (ret);
}
diff --git a/sbin/hastd/control.c b/sbin/hastd/control.c
index 922f507..364225b 100644
--- a/sbin/hastd/control.c
+++ b/sbin/hastd/control.c
@@ -215,6 +215,16 @@ control_status_worker(struct hast_resource *res, struct nv *nvout,
"stat_delete_error%u", no);
nv_add_uint64(nvout, nv_get_uint64(cnvin, "stat_flush_error"),
"stat_flush_error%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "idle_queue_size"),
+ "idle_queue_size%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "local_queue_size"),
+ "local_queue_size%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "send_queue_size"),
+ "send_queue_size%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "recv_queue_size"),
+ "recv_queue_size%u", no);
+ nv_add_uint64(nvout, nv_get_uint64(cnvin, "done_queue_size"),
+ "done_queue_size%u", no);
end:
if (cnvin != NULL)
nv_free(cnvin);
@@ -478,6 +488,7 @@ ctrl_thread(void *arg)
nv_add_uint64(nvout, res->hr_stat_flush_error +
res->hr_stat_activemap_flush_error,
"stat_flush_error");
+ res->output_status_aux(nvout);
nv_add_int16(nvout, 0, "error");
break;
case CONTROL_RELOAD:
diff --git a/sbin/hastd/hast.h b/sbin/hastd/hast.h
index 65c24f8..c529de5 100644
--- a/sbin/hastd/hast.h
+++ b/sbin/hastd/hast.h
@@ -137,6 +137,8 @@ struct hastd_config {
#define HAST_CHECKSUM_CRC32 1
#define HAST_CHECKSUM_SHA256 2
+struct nv;
+
/*
* Structure that describes single resource.
*/
@@ -254,6 +256,9 @@ struct hast_resource {
/* Number of activemap flush errors. */
uint64_t hr_stat_activemap_flush_error;
+ /* Function to output worker specific info on control status request. */
+ void (*output_status_aux)(struct nv *);
+
/* Next resource. */
TAILQ_ENTRY(hast_resource) hr_next;
};
diff --git a/sbin/hastd/hastd.8 b/sbin/hastd/hastd.8
index 017e895..68c98cb 100644
--- a/sbin/hastd/hastd.8
+++ b/sbin/hastd/hastd.8
@@ -171,7 +171,7 @@ The default location is
.Pa /var/run/hastd.pid .
.El
.Sh FILES
-.Bl -tag -width ".Pa /var/run/hastctl" -compact
+.Bl -tag -width ".Pa /var/run/hastd.pid" -compact
.It Pa /etc/hast.conf
The configuration file for
.Nm
diff --git a/sbin/hastd/hastd.c b/sbin/hastd/hastd.c
index 06b38e9..bac390a 100644
--- a/sbin/hastd/hastd.c
+++ b/sbin/hastd/hastd.c
@@ -806,12 +806,6 @@ listen_accept(struct hastd_listen *lst)
*/
version = 1;
}
- if (version > HAST_PROTO_VERSION) {
- pjdlog_info("Remote protocol version %hhu is not supported, falling back to version %hhu.",
- version, (unsigned char)HAST_PROTO_VERSION);
- version = HAST_PROTO_VERSION;
- }
- pjdlog_debug(1, "Negotiated protocol version %hhu.", version);
token = nv_get_uint8_array(nvin, &size, "token");
/*
* NULL token means that this is first connection.
@@ -925,6 +919,12 @@ listen_accept(struct hastd_listen *lst)
*/
if (token == NULL) {
+ if (version > HAST_PROTO_VERSION) {
+ pjdlog_info("Remote protocol version %hhu is not supported, falling back to version %hhu.",
+ version, (unsigned char)HAST_PROTO_VERSION);
+ version = HAST_PROTO_VERSION;
+ }
+ pjdlog_debug(1, "Negotiated protocol version %hhu.", version);
res->hr_version = version;
arc4random_buf(res->hr_token, sizeof(res->hr_token));
nvout = nv_alloc();
diff --git a/sbin/hastd/nv.c b/sbin/hastd/nv.c
index 8dcf697..fefc2df 100644
--- a/sbin/hastd/nv.c
+++ b/sbin/hastd/nv.c
@@ -566,7 +566,7 @@ nv_get_string(struct nv *nv, const char *namefmt, ...)
return (NULL);
PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);
PJDLOG_ASSERT(nvh->nvh_dsize >= 1);
- str = NVH_DATA(nvh);
+ str = (char *)NVH_DATA(nvh);
PJDLOG_ASSERT(str[nvh->nvh_dsize - 1] == '\0');
PJDLOG_ASSERT(strlen(str) == nvh->nvh_dsize - 1);
return (str);
diff --git a/sbin/hastd/primary.c b/sbin/hastd/primary.c
index 09ae17b..385a52a 100644
--- a/sbin/hastd/primary.c
+++ b/sbin/hastd/primary.c
@@ -94,6 +94,15 @@ struct hio {
*/
bool hio_done;
/*
+ * Number of components we are still waiting before sending write
+ * completion ack to GEOM Gate. Used for memsync.
+ */
+ refcnt_t hio_writecount;
+ /*
+ * Memsync request was acknowleged by remote.
+ */
+ bool hio_memsyncacked;
+ /*
* Remember replication from the time the request was initiated,
* so we won't get confused when replication changes on reload.
*/
@@ -108,6 +117,7 @@ struct hio {
* until some in-progress requests are freed.
*/
static TAILQ_HEAD(, hio) hio_free_list;
+static size_t hio_free_list_size;
static pthread_mutex_t hio_free_list_lock;
static pthread_cond_t hio_free_list_cond;
/*
@@ -116,20 +126,26 @@ static pthread_cond_t hio_free_list_cond;
* responsible for managing his own send list.
*/
static TAILQ_HEAD(, hio) *hio_send_list;
+static size_t *hio_send_list_size;
static pthread_mutex_t *hio_send_list_lock;
static pthread_cond_t *hio_send_list_cond;
+#define hio_send_local_list_size hio_send_list_size[0]
+#define hio_send_remote_list_size hio_send_list_size[1]
/*
* There is one recv list for every component, although local components don't
* use recv lists as local requests are done synchronously.
*/
static TAILQ_HEAD(, hio) *hio_recv_list;
+static size_t *hio_recv_list_size;
static pthread_mutex_t *hio_recv_list_lock;
static pthread_cond_t *hio_recv_list_cond;
+#define hio_recv_remote_list_size hio_recv_list_size[1]
/*
* Request is placed on done list by the slowest component (the one that
* decreased hio_countdown from 1 to 0).
*/
static TAILQ_HEAD(, hio) hio_done_list;
+static size_t hio_done_list_size;
static pthread_mutex_t hio_done_list_lock;
static pthread_cond_t hio_done_list_cond;
/*
@@ -164,25 +180,21 @@ static pthread_mutex_t metadata_lock;
((res)->hr_remotein != NULL && (res)->hr_remoteout != NULL)
#define QUEUE_INSERT1(hio, name, ncomp) do { \
- bool _wakeup; \
- \
mtx_lock(&hio_##name##_list_lock[(ncomp)]); \
- _wakeup = TAILQ_EMPTY(&hio_##name##_list[(ncomp)]); \
+ if (TAILQ_EMPTY(&hio_##name##_list[(ncomp)])) \
+ cv_broadcast(&hio_##name##_list_cond[(ncomp)]); \
TAILQ_INSERT_TAIL(&hio_##name##_list[(ncomp)], (hio), \
hio_next[(ncomp)]); \
- mtx_unlock(&hio_##name##_list_lock[ncomp]); \
- if (_wakeup) \
- cv_broadcast(&hio_##name##_list_cond[(ncomp)]); \
+ hio_##name##_list_size[(ncomp)]++; \
+ mtx_unlock(&hio_##name##_list_lock[(ncomp)]); \
} while (0)
#define QUEUE_INSERT2(hio, name) do { \
- bool _wakeup; \
- \
mtx_lock(&hio_##name##_list_lock); \
- _wakeup = TAILQ_EMPTY(&hio_##name##_list); \
+ if (TAILQ_EMPTY(&hio_##name##_list)) \
+ cv_broadcast(&hio_##name##_list_cond); \
TAILQ_INSERT_TAIL(&hio_##name##_list, (hio), hio_##name##_next);\
+ hio_##name##_list_size++; \
mtx_unlock(&hio_##name##_list_lock); \
- if (_wakeup) \
- cv_broadcast(&hio_##name##_list_cond); \
} while (0)
#define QUEUE_TAKE1(hio, name, ncomp, timeout) do { \
bool _last; \
@@ -196,6 +208,8 @@ static pthread_mutex_t metadata_lock;
_last = true; \
} \
if (hio != NULL) { \
+ PJDLOG_ASSERT(hio_##name##_list_size[(ncomp)] != 0); \
+ hio_##name##_list_size[(ncomp)]--; \
TAILQ_REMOVE(&hio_##name##_list[(ncomp)], (hio), \
hio_next[(ncomp)]); \
} \
@@ -207,10 +221,16 @@ static pthread_mutex_t metadata_lock;
cv_wait(&hio_##name##_list_cond, \
&hio_##name##_list_lock); \
} \
+ PJDLOG_ASSERT(hio_##name##_list_size != 0); \
+ hio_##name##_list_size--; \
TAILQ_REMOVE(&hio_##name##_list, (hio), hio_##name##_next); \
mtx_unlock(&hio_##name##_list_lock); \
} while (0)
+#define ISFULLSYNC(hio) ((hio)->hio_replication == HAST_REPLICATION_FULLSYNC)
+#define ISMEMSYNC(hio) ((hio)->hio_replication == HAST_REPLICATION_MEMSYNC)
+#define ISASYNC(hio) ((hio)->hio_replication == HAST_REPLICATION_ASYNC)
+
#define SYNCREQ(hio) do { \
(hio)->hio_ggio.gctl_unit = -1; \
(hio)->hio_ggio.gctl_seq = 1; \
@@ -219,6 +239,9 @@ static pthread_mutex_t metadata_lock;
#define SYNCREQDONE(hio) do { (hio)->hio_ggio.gctl_unit = -2; } while (0)
#define ISSYNCREQDONE(hio) ((hio)->hio_ggio.gctl_unit == -2)
+#define ISMEMSYNCWRITE(hio) (ISMEMSYNC(hio) && \
+ (hio)->hio_ggio.gctl_cmd == BIO_WRITE && !ISSYNCREQ(hio))
+
static struct hast_resource *gres;
static pthread_mutex_t range_lock;
@@ -239,6 +262,22 @@ static void *sync_thread(void *arg);
static void *guard_thread(void *arg);
static void
+output_status_aux(struct nv *nvout)
+{
+
+ nv_add_uint64(nvout, (uint64_t)hio_free_list_size,
+ "idle_queue_size");
+ nv_add_uint64(nvout, (uint64_t)hio_send_local_list_size,
+ "local_queue_size");
+ nv_add_uint64(nvout, (uint64_t)hio_send_remote_list_size,
+ "send_queue_size");
+ nv_add_uint64(nvout, (uint64_t)hio_recv_remote_list_size,
+ "recv_queue_size");
+ nv_add_uint64(nvout, (uint64_t)hio_done_list_size,
+ "done_queue_size");
+}
+
+static void
cleanup(struct hast_resource *res)
{
int rerrno;
@@ -355,6 +394,12 @@ init_environment(struct hast_resource *res __unused)
"Unable to allocate %zu bytes of memory for send lists.",
sizeof(hio_send_list[0]) * ncomps);
}
+ hio_send_list_size = malloc(sizeof(hio_send_list_size[0]) * ncomps);
+ if (hio_send_list_size == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for send list counters.",
+ sizeof(hio_send_list_size[0]) * ncomps);
+ }
hio_send_list_lock = malloc(sizeof(hio_send_list_lock[0]) * ncomps);
if (hio_send_list_lock == NULL) {
primary_exitx(EX_TEMPFAIL,
@@ -373,6 +418,12 @@ init_environment(struct hast_resource *res __unused)
"Unable to allocate %zu bytes of memory for recv lists.",
sizeof(hio_recv_list[0]) * ncomps);
}
+ hio_recv_list_size = malloc(sizeof(hio_recv_list_size[0]) * ncomps);
+ if (hio_recv_list_size == NULL) {
+ primary_exitx(EX_TEMPFAIL,
+ "Unable to allocate %zu bytes of memory for recv list counters.",
+ sizeof(hio_recv_list_size[0]) * ncomps);
+ }
hio_recv_list_lock = malloc(sizeof(hio_recv_list_lock[0]) * ncomps);
if (hio_recv_list_lock == NULL) {
primary_exitx(EX_TEMPFAIL,
@@ -393,16 +444,18 @@ init_environment(struct hast_resource *res __unused)
}
/*
- * Initialize lists, their locks and theirs condition variables.
+ * Initialize lists, their counters, locks and condition variables.
*/
TAILQ_INIT(&hio_free_list);
mtx_init(&hio_free_list_lock);
cv_init(&hio_free_list_cond);
for (ii = 0; ii < HAST_NCOMPONENTS; ii++) {
TAILQ_INIT(&hio_send_list[ii]);
+ hio_send_list_size[ii] = 0;
mtx_init(&hio_send_list_lock[ii]);
cv_init(&hio_send_list_cond[ii]);
TAILQ_INIT(&hio_recv_list[ii]);
+ hio_recv_list_size[ii] = 0;
mtx_init(&hio_recv_list_lock[ii]);
cv_init(&hio_recv_list_cond[ii]);
rw_init(&hio_remote_lock[ii]);
@@ -445,6 +498,7 @@ init_environment(struct hast_resource *res __unused)
hio->hio_ggio.gctl_length = MAXPHYS;
hio->hio_ggio.gctl_error = 0;
TAILQ_INSERT_HEAD(&hio_free_list, hio, hio_free_next);
+ hio_free_list_size++;
}
}
@@ -781,6 +835,7 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
free(map);
goto close;
}
+ mtx_lock(&res->hr_amp_lock);
/*
* Merge local and remote bitmaps.
*/
@@ -790,7 +845,6 @@ init_remote(struct hast_resource *res, struct proto_conn **inp,
* Now that we merged bitmaps from both nodes, flush it to the
* disk before we start to synchronize.
*/
- mtx_lock(&res->hr_amp_lock);
(void)hast_activemap_flush(res);
}
nv_free(nvin);
@@ -963,6 +1017,7 @@ hastd_primary(struct hast_resource *res)
}
gres = res;
+ res->output_status_aux = output_status_aux;
mode = pjdlog_mode_get();
debuglevel = pjdlog_debug_get();
@@ -1299,6 +1354,10 @@ ggate_recv_thread(void *arg)
} else {
mtx_unlock(&res->hr_amp_lock);
}
+ if (ISMEMSYNC(hio)) {
+ hio->hio_memsyncacked = false;
+ refcnt_init(&hio->hio_writecount, ncomps);
+ }
break;
case BIO_DELETE:
res->hr_stat_delete++;
@@ -1309,13 +1368,7 @@ ggate_recv_thread(void *arg)
}
pjdlog_debug(2,
"ggate_recv: (%p) Moving request to the send queues.", hio);
- if (hio->hio_replication == HAST_REPLICATION_MEMSYNC &&
- ggio->gctl_cmd == BIO_WRITE) {
- /* Each remote request needs two responses in memsync. */
- refcnt_init(&hio->hio_countdown, ncomps + 1);
- } else {
- refcnt_init(&hio->hio_countdown, ncomps);
- }
+ refcnt_init(&hio->hio_countdown, ncomps);
for (ii = ncomp; ii < ncomps; ii++)
QUEUE_INSERT1(hio, send, ii);
}
@@ -1386,8 +1439,7 @@ local_send_thread(void *arg)
ret, (intmax_t)ggio->gctl_length);
} else {
hio->hio_errors[ncomp] = 0;
- if (hio->hio_replication ==
- HAST_REPLICATION_ASYNC) {
+ if (ISASYNC(hio)) {
ggio->gctl_error = 0;
write_complete(res, hio);
}
@@ -1425,42 +1477,13 @@ local_send_thread(void *arg)
}
break;
}
-
- if (hio->hio_replication != HAST_REPLICATION_MEMSYNC ||
- ggio->gctl_cmd != BIO_WRITE || ISSYNCREQ(hio)) {
- if (refcnt_release(&hio->hio_countdown) > 0)
- continue;
- } else {
- /*
- * Depending on hio_countdown value, requests finished
- * in the following order:
- * 0: remote memsync, remote final, local write
- * 1: remote memsync, local write, (remote final)
- * 2: local write, (remote memsync), (remote final)
- */
- switch (refcnt_release(&hio->hio_countdown)) {
- case 0:
- /*
- * Local write finished as last.
- */
- break;
- case 1:
- /*
- * Local write finished after remote memsync
- * reply arrvied. We can complete the write now.
- */
- if (hio->hio_errors[0] == 0)
- write_complete(res, hio);
- continue;
- case 2:
- /*
- * Local write finished as first.
- */
- continue;
- default:
- PJDLOG_ABORT("Invalid hio_countdown.");
+ if (ISMEMSYNCWRITE(hio)) {
+ if (refcnt_release(&hio->hio_writecount) == 0) {
+ write_complete(res, hio);
}
}
+ if (refcnt_release(&hio->hio_countdown) > 0)
+ continue;
if (ISSYNCREQ(hio)) {
mtx_lock(&sync_lock);
SYNCREQDONE(hio);
@@ -1582,10 +1605,8 @@ remote_send_thread(void *arg)
nv_add_uint64(nv, (uint64_t)ggio->gctl_seq, "seq");
nv_add_uint64(nv, offset, "offset");
nv_add_uint64(nv, length, "length");
- if (hio->hio_replication == HAST_REPLICATION_MEMSYNC &&
- ggio->gctl_cmd == BIO_WRITE && !ISSYNCREQ(hio)) {
+ if (ISMEMSYNCWRITE(hio))
nv_add_uint8(nv, 1, "memsync");
- }
if (nv_error(nv) != 0) {
hio->hio_errors[ncomp] = nv_error(nv);
pjdlog_debug(2,
@@ -1617,6 +1638,7 @@ remote_send_thread(void *arg)
mtx_lock(&hio_recv_list_lock[ncomp]);
wakeup = TAILQ_EMPTY(&hio_recv_list[ncomp]);
TAILQ_INSERT_TAIL(&hio_recv_list[ncomp], hio, hio_next[ncomp]);
+ hio_recv_list_size[ncomp]++;
mtx_unlock(&hio_recv_list_lock[ncomp]);
if (hast_proto_send(res, res->hr_remoteout, nv, data,
data != NULL ? length : 0) == -1) {
@@ -1628,17 +1650,9 @@ remote_send_thread(void *arg)
"Unable to send request (%s): ",
strerror(hio->hio_errors[ncomp]));
remote_close(res, ncomp);
- /*
- * Take request back from the receive queue and move
- * it immediately to the done queue.
- */
- mtx_lock(&hio_recv_list_lock[ncomp]);
- TAILQ_REMOVE(&hio_recv_list[ncomp], hio,
- hio_next[ncomp]);
- mtx_unlock(&hio_recv_list_lock[ncomp]);
- goto done_queue;
+ } else {
+ rw_unlock(&hio_remote_lock[ncomp]);
}
- rw_unlock(&hio_remote_lock[ncomp]);
nv_free(nv);
if (wakeup)
cv_signal(&hio_recv_list_cond[ncomp]);
@@ -1662,8 +1676,12 @@ done_queue:
} else {
mtx_unlock(&res->hr_amp_lock);
}
- if (hio->hio_replication == HAST_REPLICATION_MEMSYNC)
- (void)refcnt_release(&hio->hio_countdown);
+ if (ISMEMSYNCWRITE(hio)) {
+ if (refcnt_release(&hio->hio_writecount) == 0) {
+ if (hio->hio_errors[0] == 0)
+ write_complete(res, hio);
+ }
+ }
}
if (refcnt_release(&hio->hio_countdown) > 0)
continue;
@@ -1719,7 +1737,9 @@ remote_recv_thread(void *arg)
PJDLOG_ASSERT(hio != NULL);
TAILQ_REMOVE(&hio_recv_list[ncomp], hio,
hio_next[ncomp]);
+ hio_recv_list_size[ncomp]--;
mtx_unlock(&hio_recv_list_lock[ncomp]);
+ hio->hio_errors[ncomp] = ENOTCONN;
goto done_queue;
}
if (hast_proto_recv_hdr(res->hr_remotein, &nv) == -1) {
@@ -1742,6 +1762,7 @@ remote_recv_thread(void *arg)
if (hio->hio_ggio.gctl_seq == seq) {
TAILQ_REMOVE(&hio_recv_list[ncomp], hio,
hio_next[ncomp]);
+ hio_recv_list_size[ncomp]--;
break;
}
}
@@ -1792,80 +1813,34 @@ remote_recv_thread(void *arg)
hio->hio_errors[ncomp] = 0;
nv_free(nv);
done_queue:
- if (hio->hio_replication != HAST_REPLICATION_MEMSYNC ||
- hio->hio_ggio.gctl_cmd != BIO_WRITE || ISSYNCREQ(hio)) {
- if (refcnt_release(&hio->hio_countdown) > 0)
- continue;
- } else {
- /*
- * Depending on hio_countdown value, requests finished
- * in the following order:
- *
- * 0: local write, remote memsync, remote final
- * or
- * 0: remote memsync, local write, remote final
- *
- * 1: local write, remote memsync, (remote final)
- * or
- * 1: remote memsync, remote final, (local write)
- *
- * 2: remote memsync, (local write), (remote final)
- * or
- * 2: remote memsync, (remote final), (local write)
- */
- switch (refcnt_release(&hio->hio_countdown)) {
- case 0:
- /*
- * Remote final reply arrived.
- */
- PJDLOG_ASSERT(!memsyncack);
- break;
- case 1:
- if (memsyncack) {
- /*
- * Local request already finished, so we
- * can complete the write.
- */
+ if (ISMEMSYNCWRITE(hio)) {
+ if (!hio->hio_memsyncacked) {
+ PJDLOG_ASSERT(memsyncack ||
+ hio->hio_errors[ncomp] != 0);
+ /* Remote ack arrived. */
+ if (refcnt_release(&hio->hio_writecount) == 0) {
if (hio->hio_errors[0] == 0)
write_complete(res, hio);
- /*
- * We still need to wait for final
- * remote reply.
- */
+ }
+ hio->hio_memsyncacked = true;
+ if (hio->hio_errors[ncomp] == 0) {
pjdlog_debug(2,
- "remote_recv: (%p) Moving request back to the recv queue.",
- hio);
+ "remote_recv: (%p) Moving request "
+ "back to the recv queue.", hio);
mtx_lock(&hio_recv_list_lock[ncomp]);
TAILQ_INSERT_TAIL(&hio_recv_list[ncomp],
hio, hio_next[ncomp]);
+ hio_recv_list_size[ncomp]++;
mtx_unlock(&hio_recv_list_lock[ncomp]);
- } else {
- /*
- * Remote final reply arrived before
- * local write finished.
- * Nothing to do in such case.
- */
+ continue;
}
- continue;
- case 2:
- /*
- * We received remote memsync reply even before
- * local write finished.
- */
- PJDLOG_ASSERT(memsyncack);
-
- pjdlog_debug(2,
- "remote_recv: (%p) Moving request back to the recv queue.",
- hio);
- mtx_lock(&hio_recv_list_lock[ncomp]);
- TAILQ_INSERT_TAIL(&hio_recv_list[ncomp], hio,
- hio_next[ncomp]);
- mtx_unlock(&hio_recv_list_lock[ncomp]);
- continue;
- default:
- PJDLOG_ABORT("Invalid hio_countdown.");
+ } else {
+ PJDLOG_ASSERT(!memsyncack);
+ /* Remote final reply arrived. */
}
}
+ if (refcnt_release(&hio->hio_countdown) > 0)
+ continue;
if (ISSYNCREQ(hio)) {
mtx_lock(&sync_lock);
SYNCREQDONE(hio);
diff --git a/sbin/hastd/proto.c b/sbin/hastd/proto.c
index 73487c0..53bbf7a 100644
--- a/sbin/hastd/proto.c
+++ b/sbin/hastd/proto.c
@@ -298,8 +298,8 @@ proto_connection_send(const struct proto_conn *conn, struct proto_conn *mconn)
protoname = mconn->pc_proto->prt_name;
PJDLOG_ASSERT(protoname != NULL);
- ret = conn->pc_proto->prt_send(conn->pc_ctx, protoname,
- strlen(protoname) + 1, fd);
+ ret = conn->pc_proto->prt_send(conn->pc_ctx,
+ (const unsigned char *)protoname, strlen(protoname) + 1, fd);
proto_close(mconn);
if (ret != 0) {
errno = ret;
@@ -325,7 +325,7 @@ proto_connection_recv(const struct proto_conn *conn, bool client,
bzero(protoname, sizeof(protoname));
- ret = conn->pc_proto->prt_recv(conn->pc_ctx, protoname,
+ ret = conn->pc_proto->prt_recv(conn->pc_ctx, (unsigned char *)protoname,
sizeof(protoname) - 1, &fd);
if (ret != 0) {
errno = ret;
diff --git a/sbin/hastd/refcnt.h b/sbin/hastd/refcnt.h
index 1246043..11801cb 100644
--- a/sbin/hastd/refcnt.h
+++ b/sbin/hastd/refcnt.h
@@ -10,9 +10,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the author nor the names of any co-contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff --git a/sbin/hastd/secondary.c b/sbin/hastd/secondary.c
index 067c5d9..5e1207a 100644
--- a/sbin/hastd/secondary.c
+++ b/sbin/hastd/secondary.c
@@ -82,18 +82,21 @@ static struct hast_resource *gres;
* until some in-progress requests are freed.
*/
static TAILQ_HEAD(, hio) hio_free_list;
+static size_t hio_free_list_size;
static pthread_mutex_t hio_free_list_lock;
static pthread_cond_t hio_free_list_cond;
/*
* Disk thread (the one that does I/O requests) takes requests from this list.
*/
static TAILQ_HEAD(, hio) hio_disk_list;
+static size_t hio_disk_list_size;
static pthread_mutex_t hio_disk_list_lock;
static pthread_cond_t hio_disk_list_cond;
/*
* Thread that sends requests back to primary takes requests from this list.
*/
static TAILQ_HEAD(, hio) hio_send_list;
+static size_t hio_send_list_size;
static pthread_mutex_t hio_send_list_lock;
static pthread_cond_t hio_send_list_cond;
@@ -107,14 +110,12 @@ static void *disk_thread(void *arg);
static void *send_thread(void *arg);
#define QUEUE_INSERT(name, hio) do { \
- bool _wakeup; \
- \
mtx_lock(&hio_##name##_list_lock); \
- _wakeup = TAILQ_EMPTY(&hio_##name##_list); \
+ if (TAILQ_EMPTY(&hio_##name##_list)) \
+ cv_broadcast(&hio_##name##_list_cond); \
TAILQ_INSERT_TAIL(&hio_##name##_list, (hio), hio_next); \
+ hio_##name##_list_size++; \
mtx_unlock(&hio_##name##_list_lock); \
- if (_wakeup) \
- cv_broadcast(&hio_##name##_list_cond); \
} while (0)
#define QUEUE_TAKE(name, hio) do { \
mtx_lock(&hio_##name##_list_lock); \
@@ -122,11 +123,22 @@ static void *send_thread(void *arg);
cv_wait(&hio_##name##_list_cond, \
&hio_##name##_list_lock); \
} \
+ PJDLOG_ASSERT(hio_##name##_list_size != 0); \
+ hio_##name##_list_size--; \
TAILQ_REMOVE(&hio_##name##_list, (hio), hio_next); \
mtx_unlock(&hio_##name##_list_lock); \
} while (0)
static void
+output_status_aux(struct nv *nvout)
+{
+
+ nv_add_uint64(nvout, (uint64_t)hio_free_list_size, "idle_queue_size");
+ nv_add_uint64(nvout, (uint64_t)hio_disk_list_size, "local_queue_size");
+ nv_add_uint64(nvout, (uint64_t)hio_send_list_size, "send_queue_size");
+}
+
+static void
hio_clear(struct hio *hio)
{
@@ -190,6 +202,7 @@ init_environment(void)
}
hio_clear(hio);
TAILQ_INSERT_HEAD(&hio_free_list, hio, hio_next);
+ hio_free_list_size++;
}
}
@@ -441,6 +454,7 @@ hastd_secondary(struct hast_resource *res, struct nv *nvin)
}
gres = res;
+ res->output_status_aux = output_status_aux;
mode = pjdlog_mode_get();
debuglevel = pjdlog_debug_get();
diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c
index 0e9930b..738e5f2 100644
--- a/sbin/hastd/subr.c
+++ b/sbin/hastd/subr.c
@@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$");
#include <sys/jail.h>
#include <sys/stat.h>
#ifdef HAVE_CAPSICUM
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include <geom/gate/g_gate.h>
#endif
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index a98840d..44c2319 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -21,7 +21,6 @@ SRCS+= af_inet.c # IPv4 support
.if ${MK_INET6_SUPPORT} != "no"
SRCS+= af_inet6.c # IPv6 support
.endif
-SRCS+= af_atalk.c # AppleTalk support
.if ${MK_INET6_SUPPORT} != "no"
SRCS+= af_nd6.c # ND6 support
.endif
@@ -40,7 +39,9 @@ LDADD+= -lbsdxml -lsbuf
SRCS+= carp.c # SIOC[GS]VH support
SRCS+= ifgroup.c # ...
+.if ${MK_PF} != "no"
SRCS+= ifpfsync.c # pfsync(4) support
+.endif
SRCS+= ifbridge.c # bridge support
SRCS+= iflagg.c # lagg support
@@ -51,11 +52,6 @@ CFLAGS+= -DINET6
.if ${MK_INET_SUPPORT} != "no"
CFLAGS+= -DINET
.endif
-.if ${MK_IPX_SUPPORT} != "no" && !defined(RELEASE_CRUNCH)
-SRCS+= af_ipx.c # IPX support
-DPADD+= ${LIBIPX}
-LDADD+= -lipx
-.endif
.if ${MK_JAIL} != "no" && !defined(RELEASE_CRUNCH) && !defined(RESCUE)
CFLAGS+= -DJAIL
DPADD+= ${LIBJAIL}
@@ -67,4 +63,8 @@ MAN= ifconfig.8
CFLAGS+= -Wall -Wmissing-prototypes -Wcast-qual -Wwrite-strings -Wnested-externs
WARNS?= 2
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/sbin/ifconfig/af_atalk.c b/sbin/ifconfig/af_atalk.c
deleted file mode 100644
index c50e0fd1..0000000
--- a/sbin/ifconfig/af_atalk.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#include <netatalk/at.h>
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <ifaddrs.h>
-
-#include <arpa/inet.h>
-
-#include "ifconfig.h"
-
-static struct netrange at_nr; /* AppleTalk net range */
-static struct ifaliasreq at_addreq;
-
-/* XXX FIXME -- should use strtoul for better parsing. */
-static void
-setatrange(const char *range, int dummy __unused, int s,
- const struct afswtch *afp)
-{
- u_int first = 123, last = 123;
-
- if (sscanf(range, "%u-%u", &first, &last) != 2
- || first == 0 || first > 0xffff
- || last == 0 || last > 0xffff || first > last)
- errx(1, "%s: illegal net range: %u-%u", range, first, last);
- at_nr.nr_firstnet = htons(first);
- at_nr.nr_lastnet = htons(last);
-}
-
-static void
-setatphase(const char *phase, int dummy __unused, int s,
- const struct afswtch *afp)
-{
- if (!strcmp(phase, "1"))
- at_nr.nr_phase = 1;
- else if (!strcmp(phase, "2"))
- at_nr.nr_phase = 2;
- else
- errx(1, "%s: illegal phase", phase);
-}
-
-static void
-at_status(int s __unused, const struct ifaddrs *ifa)
-{
- struct sockaddr_at *sat, null_sat;
- struct netrange *nr;
-
- memset(&null_sat, 0, sizeof(null_sat));
-
- sat = (struct sockaddr_at *)ifa->ifa_addr;
- if (sat == NULL)
- return;
- nr = &sat->sat_range.r_netrange;
- printf("\tatalk %d.%d range %d-%d phase %d",
- ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
- ntohs(nr->nr_firstnet), ntohs(nr->nr_lastnet), nr->nr_phase);
- if (ifa->ifa_flags & IFF_POINTOPOINT) {
- sat = (struct sockaddr_at *)ifa->ifa_dstaddr;
- if (sat == NULL)
- sat = &null_sat;
- printf("--> %d.%d",
- ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
- }
- if (ifa->ifa_flags & IFF_BROADCAST) {
- sat = (struct sockaddr_at *)ifa->ifa_broadaddr;
- if (sat != NULL)
- printf(" broadcast %d.%d",
- ntohs(sat->sat_addr.s_net),
- sat->sat_addr.s_node);
- }
-
- putchar('\n');
-}
-
-static void
-at_getaddr(const char *addr, int which)
-{
- struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
- u_int net, node;
-
- sat->sat_family = AF_APPLETALK;
- sat->sat_len = sizeof(*sat);
- if (which == MASK)
- errx(1, "AppleTalk does not use netmasks");
- if (sscanf(addr, "%u.%u", &net, &node) != 2
- || net > 0xffff || node > 0xfe)
- errx(1, "%s: illegal address", addr);
- sat->sat_addr.s_net = htons(net);
- sat->sat_addr.s_node = node;
-}
-
-static void
-at_postproc(int s, const struct afswtch *afp)
-{
- struct sockaddr_at *sat = (struct sockaddr_at *) &at_addreq.ifra_addr;
-
- if (at_nr.nr_phase == 0)
- at_nr.nr_phase = 2; /* Default phase 2 */
- if (at_nr.nr_firstnet == 0)
- at_nr.nr_firstnet = /* Default range of one */
- at_nr.nr_lastnet = sat->sat_addr.s_net;
- printf("\tatalk %d.%d range %d-%d phase %d\n",
- ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node,
- ntohs(at_nr.nr_firstnet), ntohs(at_nr.nr_lastnet),
- at_nr.nr_phase);
- if ((u_short) ntohs(at_nr.nr_firstnet) >
- (u_short) ntohs(sat->sat_addr.s_net)
- || (u_short) ntohs(at_nr.nr_lastnet) <
- (u_short) ntohs(sat->sat_addr.s_net))
- errx(1, "AppleTalk address is not in range");
- sat->sat_range.r_netrange = at_nr;
-}
-
-static struct cmd atalk_cmds[] = {
- DEF_CMD_ARG("range", setatrange),
- DEF_CMD_ARG("phase", setatphase),
-};
-
-static struct afswtch af_atalk = {
- .af_name = "atalk",
- .af_af = AF_APPLETALK,
- .af_status = at_status,
- .af_getaddr = at_getaddr,
- .af_postproc = at_postproc,
- .af_difaddr = SIOCDIFADDR,
- .af_aifaddr = SIOCAIFADDR,
- .af_ridreq = &at_addreq,
- .af_addreq = &at_addreq,
-};
-
-static __constructor void
-atalk_ctor(void)
-{
-#define N(a) (sizeof(a) / sizeof(a[0]))
- size_t i;
-
- for (i = 0; i < N(atalk_cmds); i++)
- cmd_register(&atalk_cmds[i]);
- af_register(&af_atalk);
-#undef N
-}
diff --git a/sbin/ifconfig/af_ipx.c b/sbin/ifconfig/af_ipx.c
deleted file mode 100644
index bc5d500..0000000
--- a/sbin/ifconfig/af_ipx.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <net/if.h>
-
-#include <err.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ifaddrs.h>
-
-#include <net/if_var.h>
-#define IPTUNNEL
-#include <netipx/ipx.h>
-#include <netipx/ipx_if.h>
-
-#include "ifconfig.h"
-
-static struct ifaliasreq ipx_addreq;
-static struct ifreq ipx_ridreq;
-
-static void
-ipx_status(int s __unused, const struct ifaddrs *ifa)
-{
- struct sockaddr_ipx *sipx, null_sipx;
-
- sipx = (struct sockaddr_ipx *)ifa->ifa_addr;
- if (sipx == NULL)
- return;
-
- printf("\tipx %s ", ipx_ntoa(sipx->sipx_addr));
-
- if (ifa->ifa_flags & IFF_POINTOPOINT) {
- sipx = (struct sockaddr_ipx *)ifa->ifa_dstaddr;
- if (sipx == NULL) {
- memset(&null_sipx, 0, sizeof(null_sipx));
- sipx = &null_sipx;
- }
- printf("--> %s ", ipx_ntoa(sipx->sipx_addr));
- }
- putchar('\n');
-}
-
-#define SIPX(x) ((struct sockaddr_ipx *) &(x))
-struct sockaddr_ipx *sipxtab[] = {
- SIPX(ipx_ridreq.ifr_addr), SIPX(ipx_addreq.ifra_addr),
- SIPX(ipx_addreq.ifra_mask), SIPX(ipx_addreq.ifra_broadaddr)
-};
-
-static void
-ipx_getaddr(const char *addr, int which)
-{
- struct sockaddr_ipx *sipx = sipxtab[which];
-
- sipx->sipx_family = AF_IPX;
- sipx->sipx_len = sizeof(*sipx);
- sipx->sipx_addr = ipx_addr(addr);
- if (which == MASK)
- printf("Attempt to set IPX netmask will be ineffectual\n");
-}
-
-static void
-ipx_postproc(int s, const struct afswtch *afp)
-{
-
-}
-
-static struct afswtch af_ipx = {
- .af_name = "ipx",
- .af_af = AF_IPX,
- .af_status = ipx_status,
- .af_getaddr = ipx_getaddr,
- .af_postproc = ipx_postproc,
- .af_difaddr = SIOCDIFADDR,
- .af_aifaddr = SIOCAIFADDR,
- .af_ridreq = &ipx_ridreq,
- .af_addreq = &ipx_addreq,
-};
-
-static __constructor void
-ipx_ctor(void)
-{
- af_register(&af_ipx);
-}
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index d0d8671..8116cb7 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" From: @(#)ifconfig.8 8.3 (Berkeley) 1/5/94
.\" $FreeBSD$
.\"
-.Dd January 10, 2013
+.Dd October 21, 2013
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -158,13 +158,8 @@ The address or protocol families currently
supported are
.Dq inet ,
.Dq inet6 ,
-.Dq atalk ,
-.Dq ipx ,
-.\" .Dq iso ,
and
.Dq link .
-.\" and
-.\" .Dq ns .
The default if available is
.Dq inet
or otherwise
@@ -309,12 +304,6 @@ using the
kernel configuration option, or the
.Va net.fibs
tunable.
-.It Cm ipdst
-This is used to specify an Internet host who is willing to receive
-IP packets encapsulating IPX packets bound for a remote network.
-An apparent point to point link is constructed, and
-the address specified will be taken as the IPX address and network
-of the destination.
.It Cm maclabel Ar label
If Mandatory Access Control support is enabled in the kernel,
set the MAC label to
@@ -572,42 +561,6 @@ The prefix can also be specified using the slash notation after the address.
See the
.Ar address
option above for more information.
-.\" see
-.\" Xr eon 5 .
-.\" .It Cm nsellength Ar n
-.\" .Pf ( Tn ISO
-.\" only)
-.\" This specifies a trailing number of bytes for a received
-.\" .Tn NSAP
-.\" used for local identification, the remaining leading part of which is
-.\" taken to be the
-.\" .Tn NET
-.\" (Network Entity Title).
-.\" The default value is 1, which is conformant to US
-.\" .Tn GOSIP .
-.\" When an ISO address is set in an ifconfig command,
-.\" it is really the
-.\" .Tn NSAP
-.\" which is being specified.
-.\" For example, in
-.\" .Tn US GOSIP ,
-.\" 20 hex digits should be
-.\" specified in the
-.\" .Tn ISO NSAP
-.\" to be assigned to the interface.
-.\" There is some evidence that a number different from 1 may be useful
-.\" for
-.\" .Tn AFI
-.\" 37 type addresses.
-.It Cm range Ar netrange
-Under appletalk, set the interface to respond to a
-.Ar netrange
-of the form
-.Ar startnet Ns - Ns Ar endnet .
-Appletalk uses this scheme instead of
-netmasks though
-.Fx
-implements it internally as a set of netmasks.
.It Cm remove
Another name for the
.Fl alias
@@ -615,10 +568,6 @@ parameter.
Introduced for compatibility
with
.Bsx .
-.It Cm phase
-The argument following this specifies the version (phase) of the
-Appletalk network attached to the interface.
-Values of 1 or 2 are permitted.
.Sm off
.It Cm link Op Cm 0 No - Cm 2
.Sm on
@@ -2690,7 +2639,7 @@ as a synonym for the canonical form of the option
.Pp
Configure a single CARP redundant address on igb0, and then switch it
to be master:
-.Dl # ifconfig igb0 vhid 1 10.0.0.1/24 pass foobar
+.Dl # ifconfig igb0 vhid 1 10.0.0.1/24 pass foobar up
.Dl # ifconfig igb0 vhid 1 state master
.Pp
Configure the interface
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 983e21f..d2ddeca 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -741,20 +741,6 @@ setifbroadaddr(const char *addr, int dummy __unused, int s,
}
static void
-setifipdst(const char *addr, int dummy __unused, int s,
- const struct afswtch *afp)
-{
- const struct afswtch *inet;
-
- inet = af_getbyname("inet");
- if (inet == NULL)
- return;
- inet->af_getaddr(addr, DSTADDR);
- clearaddr = 0;
- newaddr = 0;
-}
-
-static void
notealias(const char *addr, int param, int s, const struct afswtch *afp)
{
#define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr))
@@ -909,7 +895,7 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp)
}
#define IFFBITS \
-"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \
+"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \
"\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
"\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP"
@@ -1176,7 +1162,6 @@ static struct cmd basic_cmds[] = {
DEF_CMD_ARG("netmask", setifnetmask),
DEF_CMD_ARG("metric", setifmetric),
DEF_CMD_ARG("broadcast", setifbroadaddr),
- DEF_CMD_ARG("ipdst", setifipdst),
DEF_CMD_ARG2("tunnel", settunnel),
DEF_CMD("-tunnel", 0, deletetunnel),
DEF_CMD("deletetunnel", 0, deletetunnel),
diff --git a/sbin/ifconfig/ifgroup.c b/sbin/ifconfig/ifgroup.c
index 9eaac3b..f8b18b4 100644
--- a/sbin/ifconfig/ifgroup.c
+++ b/sbin/ifconfig/ifgroup.c
@@ -57,7 +57,7 @@ setifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
errx(1, "setifgroup: group name too long");
- if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1)
+ if (ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr) == -1 && errno != EEXIST)
err(1," SIOCAIFGROUP");
}
@@ -75,7 +75,7 @@ unsetifgroup(const char *group_name, int d, int s, const struct afswtch *rafp)
if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ)
errx(1, "unsetifgroup: group name too long");
- if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1)
+ if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1 && errno != ENOENT)
err(1, "SIOCDIFGROUP");
}
diff --git a/sbin/ifconfig/tests/Makefile b/sbin/ifconfig/tests/Makefile
new file mode 100644
index 0000000..9b7aa07
--- /dev/null
+++ b/sbin/ifconfig/tests/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/sbin/ifconfig
+
+ATF_TESTS_SH= fibs_test
+
+.include <bsd.test.mk>
diff --git a/sbin/ifconfig/tests/fibs_test.sh b/sbin/ifconfig/tests/fibs_test.sh
new file mode 100755
index 0000000..2a25458
--- /dev/null
+++ b/sbin/ifconfig/tests/fibs_test.sh
@@ -0,0 +1,126 @@
+#
+# Copyright (c) 2014 Spectra Logic 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,
+# without modification.
+# 2. Redistributions in binary form must reproduce at minimum a disclaimer
+# substantially similar to the "NO WARRANTY" disclaimer below
+# ("Disclaimer") and any redistribution must be conditioned upon
+# including a substantially similar Disclaimer requirement for further
+# binary redistribution.
+#
+# NO WARRANTY
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+#
+# Authors: Alan Somers (Spectra Logic Corporation)
+#
+# $FreeBSD$
+
+
+# Regression test for bin/187551
+atf_test_case process_fib cleanup
+process_fib_head()
+{
+ atf_set "descr" "ifconfig will set its process fib whenever configuring an interface with nondefault fib"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+process_fib_body()
+{
+ atf_expect_fail "bin/187551 ifconfig should change its process fib when configuring an interface with nondefault fib"
+ # Configure the TAP interface to use an RFC5737 nonrouteable address
+ # and a non-default fib
+ ADDR="192.0.2.2"
+ SUBNET="192.0.2.0"
+ MASK="24"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 1
+
+ # Configure a TAP interface
+ get_tap
+ ktrace ifconfig $TAP ${ADDR}/${MASK} fib $FIB0
+ if kdump -s | egrep -q 'CALL[[:space:]]+setfib'; then
+ atf_pass
+ else
+ atf_fail "ifconfig never called setfib(2)"
+ fi
+}
+
+process_fib_cleanup()
+{
+ cleanup_tap
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case process_fib
+}
+
+
+# parameter numfibs The number of fibs to lookup
+get_fibs()
+{
+ NUMFIBS=$1
+ net_fibs=`sysctl -n net.fibs`
+ i=0
+ while [ $i -lt "$NUMFIBS" ]; do
+ fib=`atf_config_get "fibs" | \
+ awk -v i=$(( i + 1 )) '{print $i}'`
+ echo "fib is ${fib}"
+ eval FIB${i}=${fib}
+ if [ "$fib" -ge "$net_fibs" ]; then
+ atf_skip "The ${i}th configured fib is ${fib}, which is not less than net.fibs, which is ${net_fibs}"
+ fi
+ i=$(( $i + 1 ))
+ done
+}
+
+
+
+# Creates a new tap(4) interface, registers it for cleanup, and returns the
+# name via the environment variable TAP
+get_tap()
+{
+ local TAPN=0
+ while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do
+ if [ "$TAPN" -ge 8 ]; then
+ atf_skip "Could not create a tap(4) interface"
+ else
+ TAPN=$(($TAPN + 1))
+ fi
+ done
+ local TAPD=tap${TAPN}
+ # Record the TAP device so we can clean it up later
+ echo ${TAPD} >> "tap_devices_to_cleanup"
+ TAP=${TAPD}
+}
+
+
+
+
+cleanup_tap()
+{
+ for TAPD in `cat "tap_devices_to_cleanup"`; do
+ ifconfig ${TAPD} destroy
+ done
+}
+
diff --git a/sbin/init/init.c b/sbin/init/init.c
index 99041c9..8583ba5 100644
--- a/sbin/init/init.c
+++ b/sbin/init/init.c
@@ -143,7 +143,6 @@ static const char *get_shell(void);
static void write_stderr(const char *message);
typedef struct init_session {
- int se_index; /* index of entry in ttys file */
pid_t se_process; /* controlling process */
time_t se_started; /* used to avoid thrashing */
int se_flags; /* status of session */
@@ -163,7 +162,7 @@ typedef struct init_session {
} session_t;
static void free_session(session_t *);
-static session_t *new_session(session_t *, int, struct ttyent *);
+static session_t *new_session(session_t *, struct ttyent *);
static session_t *sessions;
static char **construct_argv(char *);
@@ -1005,7 +1004,7 @@ free_session(session_t *sp)
* Mark it SE_PRESENT.
*/
static session_t *
-new_session(session_t *sprev, int session_index, struct ttyent *typ)
+new_session(session_t *sprev, struct ttyent *typ)
{
session_t *sp;
int fd;
@@ -1017,7 +1016,6 @@ new_session(session_t *sprev, int session_index, struct ttyent *typ)
sp = (session_t *) calloc(1, sizeof (session_t));
- sp->se_index = session_index;
sp->se_flags |= SE_PRESENT;
sp->se_device = malloc(sizeof(_PATH_DEV) + strlen(typ->ty_name));
@@ -1107,7 +1105,6 @@ setupargv(session_t *sp, struct ttyent *typ)
static state_func_t
read_ttys(void)
{
- int session_index = 0;
session_t *sp, *snext;
struct ttyent *typ;
@@ -1128,7 +1125,7 @@ read_ttys(void)
* Note that sp starts at 0.
*/
while ((typ = getttyent()) != NULL)
- if ((snext = new_session(sp, ++session_index, typ)) != NULL)
+ if ((snext = new_session(sp, typ)) != NULL)
sp = snext;
endttyent();
@@ -1380,7 +1377,6 @@ clean_ttys(void)
{
session_t *sp, *sprev;
struct ttyent *typ;
- int session_index = 0;
int devlen;
char *old_getty, *old_window, *old_type;
@@ -1394,8 +1390,6 @@ clean_ttys(void)
devlen = sizeof(_PATH_DEV) - 1;
while ((typ = getttyent()) != NULL) {
- ++session_index;
-
for (sprev = 0, sp = sessions; sp; sprev = sp, sp = sp->se_next)
if (strcmp(typ->ty_name, sp->se_device + devlen) == 0)
break;
@@ -1403,12 +1397,6 @@ clean_ttys(void)
if (sp) {
/* we want this one to live */
sp->se_flags |= SE_PRESENT;
- if (sp->se_index != session_index) {
- warning("port %s changed utmp index from %d to %d",
- sp->se_device, sp->se_index,
- session_index);
- sp->se_index = session_index;
- }
if ((typ->ty_status & TTY_ON) == 0 ||
typ->ty_getty == 0) {
sp->se_flags |= SE_SHUTDOWN;
@@ -1448,7 +1436,7 @@ clean_ttys(void)
continue;
}
- new_session(sprev, session_index, typ);
+ new_session(sprev, typ);
}
endttyent();
diff --git a/sbin/ipfw/Makefile b/sbin/ipfw/Makefile
index b25f38c..6aea26b 100644
--- a/sbin/ipfw/Makefile
+++ b/sbin/ipfw/Makefile
@@ -1,8 +1,16 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
PROG= ipfw
-SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c altq.c
+SRCS= ipfw2.c dummynet.c ipv6.c main.c nat.c
WARNS?= 2
+
+.if ${MK_PF} != "no"
+SRCS+= altq.c
+CFLAGS+=-DPF
+.endif
+
DPADD= ${LIBUTIL}
LDADD= -lutil
MAN= ipfw.8
diff --git a/sbin/ipfw/ipfw.8 b/sbin/ipfw/ipfw.8
index 65fa334..bc8d819 100644
--- a/sbin/ipfw/ipfw.8
+++ b/sbin/ipfw/ipfw.8
@@ -335,8 +335,7 @@ Section below for details.
If the world and the kernel get out of sync the
.Nm
ABI may break, preventing you from being able to add any rules.
-This can
-adversely effect the booting process.
+This can adversely affect the booting process.
You can use
.Nm
.Cm disable
@@ -2933,6 +2932,11 @@ and
must be strictly lower than 5 seconds, the period of
repetition of keepalives.
The firewall enforces that.
+.It Va net.inet.ip.fw.dyn_keep_states: No 0
+Keep dynamic states on rule/set deletion.
+States are relinked to default rule (65535).
+This can be handly for ruleset reload.
+Turned off by default.
.It Va net.inet.ip.fw.enable : No 1
Enables the firewall.
Setting this variable to 0 lets you run your machine without
diff --git a/sbin/ipfw/ipfw2.c b/sbin/ipfw/ipfw2.c
index 577d644..98b25b3 100644
--- a/sbin/ipfw/ipfw2.c
+++ b/sbin/ipfw/ipfw2.c
@@ -60,6 +60,8 @@ int resvd_set_number = RESVD_SET;
int ipfw_socket = -1;
+uint32_t ipfw_tables_max = 0; /* Number of tables supported by kernel */
+
#ifndef s6_addr32
#define s6_addr32 __u6_addr.__u6_addr32
#endif
@@ -2203,6 +2205,7 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
{
int len = 0;
uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
+ uint32_t tables_max;
cmd->o.len &= ~F_LEN_MASK; /* zero len */
@@ -2221,6 +2224,10 @@ fill_ip(ipfw_insn_ip *cmd, char *av, int cblen)
*p++ = '\0';
cmd->o.opcode = O_IP_DST_LOOKUP;
cmd->o.arg1 = strtoul(av + 6, NULL, 0);
+ tables_max = ipfw_get_tables_max();
+ if (cmd->o.arg1 > tables_max)
+ errx(EX_USAGE, "The table number exceeds the maximum "
+ "allowed value (%u)", tables_max - 1);
if (p) {
cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
d[0] = strtoul(p, NULL, 0);
@@ -4119,6 +4126,33 @@ static void table_list(uint16_t num, int need_header);
static void table_fill_xentry(char *arg, ipfw_table_xentry *xent);
/*
+ * Retrieve maximum number of tables supported by ipfw(4) module.
+ */
+uint32_t
+ipfw_get_tables_max()
+{
+ size_t len;
+ uint32_t tables_max;
+
+ if (ipfw_tables_max != 0)
+ return (ipfw_tables_max);
+
+ len = sizeof(tables_max);
+ if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
+ NULL, 0) == -1) {
+ if (co.test_only)
+ tables_max = 128; /* Old conservative default */
+ else
+ errx(1, "Can't determine maximum number of ipfw tables."
+ " Perhaps you forgot to load ipfw module?");
+ }
+
+ ipfw_tables_max = tables_max;
+
+ return (ipfw_tables_max);
+}
+
+/*
* This one handles all table-related commands
* ipfw table N add addr[/masklen] [value]
* ipfw table N delete addr[/masklen]
@@ -4131,19 +4165,10 @@ ipfw_table_handler(int ac, char *av[])
ipfw_table_xentry xent;
int do_add;
int is_all;
- size_t len;
uint32_t a;
uint32_t tables_max;
- len = sizeof(tables_max);
- if (sysctlbyname("net.inet.ip.fw.tables_max", &tables_max, &len,
- NULL, 0) == -1) {
- if (co.test_only)
- tables_max = 128; /* Old conservative default */
- else
- errx(1, "Can't determine maximum number of ipfw tables."
- " Perhaps you forgot to load ipfw module?");
- }
+ tables_max = ipfw_get_tables_max();
memset(&xent, 0, sizeof(xent));
@@ -4274,13 +4299,24 @@ table_fill_xentry(char *arg, ipfw_table_xentry *xent)
addrlen = sizeof(struct in6_addr);
} else {
/* Port or any other key */
- key = strtol(arg, &p, 10);
/* Skip non-base 10 entries like 'fa1' */
- if (p != arg) {
+ key = strtol(arg, &p, 10);
+ if (*p == '\0') {
pkey = (uint32_t *)paddr;
*pkey = htonl(key);
type = IPFW_TABLE_CIDR;
+ masklen = 32;
addrlen = sizeof(uint32_t);
+ } else if ((p != arg) && (*p == '.')) {
+ /*
+ * Warn on IPv4 address strings
+ * which are "valid" for inet_aton() but not
+ * in inet_pton().
+ *
+ * Typical examples: '10.5' or '10.0.0.05'
+ */
+ errx(EX_DATAERR,
+ "Invalid IPv4 address: %s", arg);
}
}
}
diff --git a/sbin/ipfw/ipfw2.h b/sbin/ipfw/ipfw2.h
index d592930..6e895b8 100644
--- a/sbin/ipfw/ipfw2.h
+++ b/sbin/ipfw/ipfw2.h
@@ -228,6 +228,8 @@ char const *match_value(struct _s_x *p, int value);
int do_cmd(int optname, void *optval, uintptr_t optlen);
+uint32_t ipfw_get_tables_max(void);
+
struct in6_addr;
void n2mask(struct in6_addr *mask, int n);
int contigmask(uint8_t *p, int len);
@@ -266,11 +268,14 @@ void ipfw_flush(int force);
void ipfw_zero(int ac, char *av[], int optname);
void ipfw_list(int ac, char *av[], int show_counters);
+#ifdef PF
/* altq.c */
void altq_set_enabled(int enabled);
u_int32_t altq_name_to_qid(const char *name);
-
void print_altq_cmd(struct _ipfw_insn_altq *altqptr);
+#else
+#define NO_ALTQ
+#endif
/* dummynet.c */
void dummynet_list(int ac, char *av[], int show_counters);
diff --git a/sbin/iscontrol/fsm.c b/sbin/iscontrol/fsm.c
index a4660bb..eebde7c 100644
--- a/sbin/iscontrol/fsm.c
+++ b/sbin/iscontrol/fsm.c
@@ -199,6 +199,7 @@ tcpConnect(isess_t *sess)
perror("connect");
switch(sv_errno) {
case ECONNREFUSED:
+ case EHOSTUNREACH:
case ENETUNREACH:
case ETIMEDOUT:
if((sess->flags & SESS_REDIRECT) == 0) {
diff --git a/sbin/iscontrol/iscsi.conf.5 b/sbin/iscontrol/iscsi.conf.5
index f87fef6..2e7a68d 100644
--- a/sbin/iscontrol/iscsi.conf.5
+++ b/sbin/iscontrol/iscsi.conf.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 10, 2013
+.Dd December 17, 2013
.Dt ISCSI.CONF 5
.Os
.Sh NAME
@@ -145,10 +145,9 @@ the chap-name, defaults to
.Em hostname .
.It Cm chapDigest
can be MD5 or SHA1.
-.It Cm tgtChapSecret/tgtChapName
-same as the none
-.Em tgt
-counterpart, but to authenticate the target.
+.It Cm tgtChapName/tgtChapSecret
+name and secret used for mutual CHAP; by default, mutual CHAP
+is not used.
.El
.Sh FILES
.Bl -tag -width indent
diff --git a/sbin/kldconfig/kldconfig.c b/sbin/kldconfig/kldconfig.c
index 403251d..30dc876 100644
--- a/sbin/kldconfig/kldconfig.c
+++ b/sbin/kldconfig/kldconfig.c
@@ -40,15 +40,6 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <unistd.h>
-#if defined(__FreeBSD_version)
-#if __FreeBSD_version < 500000
-#define NEED_SLASHTERM
-#endif /* < 500000 */
-#else /* defined(__FreeBSD_version) */
-/* just in case.. */
-#define NEED_SLASHTERM
-#endif /* defined(__FreeBSD_version) */
-
/* the default sysctl name */
#define PATHCTL "kern.module_path"
@@ -163,18 +154,9 @@ addpath(struct pathhead *pathq, char *path, int force, int insert)
strlcpy(pathbuf, path, sizeof(pathbuf));
len = strlen(pathbuf);
-#ifdef NEED_SLASHTERM
- /* slash-terminate, because the kernel linker said so. */
- if ((len == 0) || (pathbuf[len-1] != '/')) {
- if (len == sizeof(pathbuf) - 1)
- errx(1, "path too long: %s", pathbuf);
- pathbuf[len] = '/';
- }
-#else /* NEED_SLASHTERM */
/* remove a terminating slash if present */
if ((len > 0) && (pathbuf[len-1] == '/'))
pathbuf[--len] = '\0';
-#endif /* NEED_SLASHTERM */
/* is it already in there? */
TAILQ_FOREACH(pe, pathq, next)
@@ -219,18 +201,9 @@ rempath(struct pathhead *pathq, char *path, int force, int insert __unused)
strlcpy(pathbuf, path, sizeof(pathbuf));
len = strlen(pathbuf);
-#ifdef NEED_SLASHTERM
- /* slash-terminate, because the kernel linker said so. */
- if ((len == 0) || (pathbuf[len-1] != '/')) {
- if (len == sizeof(pathbuf) - 1)
- errx(1, "path too long: %s", pathbuf);
- pathbuf[len] = '/';
- }
-#else /* NEED_SLASHTERM */
/* remove a terminating slash if present */
if ((len > 0) && (pathbuf[len-1] == '/'))
pathbuf[--len] = '\0';
-#endif /* NEED_SLASHTERM */
/* Is it in there? */
TAILQ_FOREACH(pe, pathq, next)
diff --git a/sbin/kldload/kldload.c b/sbin/kldload/kldload.c
index 84589eb..3891f33 100644
--- a/sbin/kldload/kldload.c
+++ b/sbin/kldload/kldload.c
@@ -181,7 +181,22 @@ main(int argc, char** argv)
printf("%s is already "
"loaded\n", argv[0]);
} else {
- warn("can't load %s", argv[0]);
+ switch (errno) {
+ case EEXIST:
+ warnx("can't load %s: module "
+ "already loaded or "
+ "in kernel", argv[0]);
+ break;
+ case ENOEXEC:
+ warnx("an error occurred while "
+ "loading the module. "
+ "Please check dmesg(8) for "
+ "more details.");
+ break;
+ default:
+ warn("can't load %s", argv[0]);
+ break;
+ }
errors++;
}
} else {
diff --git a/sbin/kldstat/kldstat.8 b/sbin/kldstat/kldstat.8
index 6f040e2..bebabe8 100644
--- a/sbin/kldstat/kldstat.8
+++ b/sbin/kldstat/kldstat.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 23, 2005
+.Dd January 22, 2014
.Dt KLDSTAT 8
.Os
.Sh NAME
@@ -33,6 +33,7 @@
.Nd display status of dynamic kernel linker
.Sh SYNOPSIS
.Nm
+.Op Fl q
.Op Fl v
.Op Fl i Ar id
.Op Fl n Ar filename
diff --git a/sbin/kldstat/kldstat.c b/sbin/kldstat/kldstat.c
index 575fca8..8785c00 100644
--- a/sbin/kldstat/kldstat.c
+++ b/sbin/kldstat/kldstat.c
@@ -78,7 +78,7 @@ printfile(int fileid, int verbose)
static void
usage(void)
{
- fprintf(stderr, "usage: kldstat [-v] [-i id] [-n filename]\n");
+ fprintf(stderr, "usage: kldstat [-q] [-v] [-i id] [-n filename]\n");
fprintf(stderr, " kldstat [-q] [-m modname]\n");
exit(1);
}
@@ -146,8 +146,13 @@ main(int argc, char** argv)
}
if (filename != NULL) {
- if ((fileid = kldfind(filename)) < 0)
- err(1, "can't find file %s", filename);
+ if ((fileid = kldfind(filename)) < 0) {
+ if (!quiet)
+ warn("can't find file %s", filename);
+ return 1;
+ } else if (quiet) {
+ return 0;
+ }
}
printf("Id Refs Address%*c Size Name\n", POINTER_WIDTH - 7, ' ');
diff --git a/sbin/mdconfig/Makefile b/sbin/mdconfig/Makefile
index be8b1b5..4b9b940 100644
--- a/sbin/mdconfig/Makefile
+++ b/sbin/mdconfig/Makefile
@@ -1,9 +1,15 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
PROG= mdconfig
MAN= mdconfig.8
DPADD= ${LIBUTIL} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF}
LDADD= -lutil -lgeom -lbsdxml -lsbuf
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/sbin/mdconfig/mdconfig.8 b/sbin/mdconfig/mdconfig.8
index 9e30896..6b52bec 100644
--- a/sbin/mdconfig/mdconfig.8
+++ b/sbin/mdconfig/mdconfig.8
@@ -16,11 +16,7 @@
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
-.\" 3. All advertising materials mentioning features or use of this software
-.\" must display the following acknowledgement:
-.\" This product includes software developed by the University of
-.\" California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
@@ -41,7 +37,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 20, 2013
+.Dd November 30, 2013
.Dt MDCONFIG 8
.Os
.Sh NAME
@@ -89,6 +85,9 @@ Options indicate an action to be performed:
Attach a memory disk.
This will configure and attach a memory disk with the
parameters specified and attach it to the system.
+If the
+.Fl u Ar unit
+option is not provided, the newly created device name will be printed on stdout.
.It Fl d
Detach a memory disk from the system and release all resources.
.It Fl r
@@ -119,6 +118,8 @@ Using
backing is generally preferred instead of using
.Cm malloc
backing.
+.It Cm null
+Bitsink; all writes do nothing, all reads return zeroes.
.El
.It Fl f Ar file
Filename to use for the vnode type memory disk.
@@ -209,9 +210,12 @@ that might adversely affect the system.
Enable/disable readonly mode.
.El
.It Fl u Ar unit
-Request a specific unit number for the
+Request a specific unit number or device name for the
.Xr md 4
device instead of automatic allocation.
+If a device name is specified, it must be start with
+.Dq md
+followed by the unit number.
.El
.Pp
The last form,
@@ -237,19 +241,19 @@ with
.Pa /tmp/boot.flp
as backing storage:
.Pp
-.Dl mdconfig -a -t vnode -f /tmp/boot.flp -u 4
+.Dl mdconfig -a -t vnode -f /tmp/boot.flp -u md4
.Pp
Detach and free all resources used by
.Pa /dev/md4 :
.Pp
-.Dl mdconfig -d -u 4
+.Dl mdconfig -d -u md4
.Pp
Create a 128MByte swap backed disk, initialize an
.Xr ffs 7
file system on it, and mount it on
.Pa /tmp :
.Bd -literal -offset indent
-mdconfig -a -t swap -s 128M -u 10
+mdconfig -a -t swap -s 128M -u md10
newfs -U /dev/md10
mount /dev/md10 /tmp
chmod 1777 /tmp
@@ -263,7 +267,7 @@ are implied
.Pc :
.Bd -literal -offset indent
dd if=/dev/zero of=somebackingfile bs=1k count=5k
-mdconfig -f somebackingfile -u 0
+mdconfig -f somebackingfile -u md0
bsdlabel -w md0 auto
newfs md0c
mount /dev/md0c /mnt
@@ -290,7 +294,7 @@ is used to skip over the header information, positioning
.Pa md1.nop
to the start of the filesystem in the image.
.Bd -literal -offset indent
-mdconfig -f diskimage.img -u 1
+mdconfig -f diskimage.img -u md1
gnop create -o 512K md1
mount /dev/md1.nop /mnt
.Ed
diff --git a/sbin/mdconfig/mdconfig.c b/sbin/mdconfig/mdconfig.c
index 233058d..d741c77 100644
--- a/sbin/mdconfig/mdconfig.c
+++ b/sbin/mdconfig/mdconfig.c
@@ -155,6 +155,9 @@ main(int argc, char **argv)
} else if (!strcmp(optarg, "swap")) {
mdio.md_type = MD_SWAP;
mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
+ } else if (!strcmp(optarg, "null")) {
+ mdio.md_type = MD_NULL;
+ mdio.md_options |= MD_CLUSTER | MD_AUTOUNIT | MD_COMPRESS;
} else
errx(1, "unknown type: %s", optarg);
break;
@@ -287,9 +290,10 @@ main(int argc, char **argv)
}
}
- if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP) &&
- sflag == NULL)
- errx(1, "must specify -s for -t malloc or -t swap");
+ if ((mdio.md_type == MD_MALLOC || mdio.md_type == MD_SWAP ||
+ mdio.md_type == MD_NULL) && sflag == NULL)
+ errx(1, "must specify -s for -t malloc, -t swap, "
+ "or -t null");
if (mdio.md_type == MD_VNODE && mdio.md_file[0] == '\0')
errx(1, "must specify -f for -t vnode");
} else {
@@ -481,12 +485,18 @@ md_list(const char *units, int opt, const char *fflag)
printf("\n");
/* XXX: Check if it's enough to clean everything. */
geom_stats_snapshot_free(sq);
- 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);
+ if (opt & OPT_UNIT) {
+ if (((fflag == NULL) && ufound) ||
+ ((fflag == NULL) && (units != NULL) && ufound) ||
+ ((fflag != NULL) && ffound) ||
+ ((fflag != NULL) && (units != NULL) && ufound && ffound))
+ return (0);
+ } else if (opt & OPT_LIST) {
+ if ((fflag == NULL) ||
+ ((fflag != NULL) && ffound))
+ return (0);
+ }
+ return (-1);
}
/*
diff --git a/sbin/mdconfig/tests/Makefile b/sbin/mdconfig/tests/Makefile
new file mode 100644
index 0000000..17284bb
--- /dev/null
+++ b/sbin/mdconfig/tests/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/sbin/mdconfig
+
+TAP_TESTS_SH= legacy_test
+TAP_TESTS_SH_SED_legacy_test= 's,__PERL__,${TAP_PERL_INTERPRETER},g'
+TEST_METADATA.legacy_test+= required_programs="${TAP_PERL_INTERPRETER}"
+
+FILESDIR= ${TESTSDIR}
+FILES= mdconfig.test
+FILES+= run.pl
+
+.include <bsd.test.mk>
diff --git a/sbin/mdconfig/tests/legacy_test.sh b/sbin/mdconfig/tests/legacy_test.sh
new file mode 100644
index 0000000..728224d
--- /dev/null
+++ b/sbin/mdconfig/tests/legacy_test.sh
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Copyright (c) 2012 Edward Tomasz Napierała <trasz@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# This is a wrapper script to run mdconfig.test.
+
+echo "1..1"
+
+if [ `whoami` != "root" ]; then
+ echo "ok 1 # skip You need to be root to run this test."
+ exit 0
+fi
+
+TESTDIR=$(dirname $(realpath $0))
+
+__PERL__ -w -U $TESTDIR/run.pl $TESTDIR/mdconfig.test > /dev/null
+
+if [ $? -eq 0 ]; then
+ echo "ok 1"
+else
+ echo "not ok 1"
+fi
diff --git a/sbin/mdconfig/tests/mdconfig.test b/sbin/mdconfig/tests/mdconfig.test
new file mode 100644
index 0000000..65d3670
--- /dev/null
+++ b/sbin/mdconfig/tests/mdconfig.test
@@ -0,0 +1,231 @@
+# Copyright (c) 2012 Edward Tomasz Napierała <trasz@FreeBSD.org>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+# This is a test for mdconfig(8) functionality. Run it as root:
+#
+# /usr/src/tools/regression/mdconfig/run /usr/src/tools/regression/mdconfig/mdconfig.test
+#
+# WARNING: Creates files in unsafe way.
+
+$ whoami
+> root
+$ umask 022
+$ truncate -s 1gb xxx
+
+$ mdconfig -l
+
+$ mdconfig -af xxx
+> md0
+
+# This awk thing is to strip the file path.
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 vnode 1024M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 2097152 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Check different valid syntax variations: implicit -a.
+
+$ mdconfig xxx
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 vnode 1024M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 2097152 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Explicit -t vnode.
+
+$ mdconfig -a -t vnode -f xxx
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 vnode 1024M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 2097152 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Size for vnodes - smaller than the actual file.
+
+$ mdconfig -a -t vnode -f xxx -s 128m
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 vnode 128M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 134217728 # mediasize in bytes (128M)
+> 262144 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Size for vnodes - larger than the actual file.
+
+$ mdconfig -a -t vnode -f xxx -s 128g
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 vnode 128G
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 137438953472 # mediasize in bytes (128G)
+> 268435456 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Sector size for vnodes.
+
+$ mdconfig -a -t vnode -f xxx -S 2048
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 vnode 1024M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 2048 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 524288 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Malloc type.
+
+$ mdconfig -a -t malloc -s 1g
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 malloc 1024M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 2097152 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Swap type.
+
+$ mdconfig -a -t swap -s 1g
+> md0
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 swap 1024M
+
+$ diskinfo -v /dev/md0 | expand
+> /dev/md0
+> 512 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 2097152 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 0
+
+# Attaching with a specific unit number.
+
+$ mdconfig -as 1g -u 42
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md42 swap 1024M
+
+$ diskinfo -v /dev/md42 | expand
+> /dev/md42
+> 512 # sectorsize
+> 1073741824 # mediasize in bytes (1.0G)
+> 2097152 # mediasize in sectors
+> 0 # stripesize
+> 0 # stripeoffset
+>
+
+$ mdconfig -du 42
+
+# Querying.
+
+$ mdconfig -as 1g
+> md0
+$ mdconfig -as 2g -u 42
+
+$ mdconfig -lv | awk '{ print $1, $2, $3 }'
+> md0 swap 1024M
+> md42 swap 2048M
+
+$ mdconfig -lvu 0 | awk '{ print $1, $2, $3 }'
+> md0 swap 1024M
+
+$ mdconfig -lvu 42 | awk '{ print $1, $2, $3 }'
+> md42 swap 2048M
+
+$ mdconfig -lvu 24 | awk '{ print $1, $2, $3 }'
+
+$ mdconfig -du 42
+$ mdconfig -du 0
+
+$ rm xxx
diff --git a/sbin/mdconfig/tests/run.pl b/sbin/mdconfig/tests/run.pl
new file mode 100644
index 0000000..383f47e
--- /dev/null
+++ b/sbin/mdconfig/tests/run.pl
@@ -0,0 +1,329 @@
+#!/usr/bin/perl -w -U
+
+# Copyright (c) 2007, 2008 Andreas Gruenbacher.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions, and the following disclaimer,
+# without modification, immediately at the beginning of the file.
+# 2. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# Alternatively, this software may be distributed under the terms of the
+# GNU Public License ("GPL").
+#
+# 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$
+#
+
+#
+# Possible improvements:
+#
+# - distinguish stdout and stderr output
+# - add environment variable like assignments
+# - run up to a specific line
+# - resume at a specific line
+#
+
+use strict;
+use FileHandle;
+use Getopt::Std;
+use POSIX qw(isatty setuid getcwd);
+use vars qw($opt_l $opt_v);
+
+no warnings qw(taint);
+
+$opt_l = ~0; # a really huge number
+getopts('l:v');
+
+my ($OK, $FAILED) = ("ok", "failed");
+if (isatty(fileno(STDOUT))) {
+ $OK = "\033[32m" . $OK . "\033[m";
+ $FAILED = "\033[31m\033[1m" . $FAILED . "\033[m";
+}
+
+sub exec_test($$);
+sub process_test($$$$);
+
+my ($prog, $in, $out) = ([], [], []);
+my $prog_line = 0;
+my ($tests, $failed) = (0,0);
+my $lineno;
+my $width = ($ENV{COLUMNS} || 80) >> 1;
+
+for (;;) {
+ my $line = <>; $lineno++;
+ if (defined $line) {
+ # Substitute %VAR and %{VAR} with environment variables.
+ $line =~ s[%(\w+)][$ENV{$1}]eg;
+ $line =~ s[%{(\w+)}][$ENV{$1}]eg;
+ }
+ if (defined $line) {
+ if ($line =~ s/^\s*< ?//) {
+ push @$in, $line;
+ } elsif ($line =~ s/^\s*> ?//) {
+ push @$out, $line;
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+ last if $prog_line >= $opt_l;
+
+ $prog = [];
+ $prog_line = 0;
+ }
+ if ($line =~ s/^\s*\$ ?//) {
+ $prog = [ map { s/\\(.)/$1/g; $_ } split /(?<!\\)\s+/, $line ];
+ $prog_line = $lineno;
+ $in = [];
+ $out = [];
+ }
+ } else {
+ process_test($prog, $prog_line, $in, $out);
+ last;
+ }
+}
+
+my $status = sprintf("%d commands (%d passed, %d failed)",
+ $tests, $tests-$failed, $failed);
+if (isatty(fileno(STDOUT))) {
+ if ($failed) {
+ $status = "\033[31m\033[1m" . $status . "\033[m";
+ } else {
+ $status = "\033[32m" . $status . "\033[m";
+ }
+}
+print $status, "\n";
+exit $failed ? 1 : 0;
+
+
+sub process_test($$$$) {
+ my ($prog, $prog_line, $in, $out) = @_;
+
+ return unless @$prog;
+
+ my $p = [ @$prog ];
+ print "[$prog_line] \$ ", join(' ',
+ map { s/\s/\\$&/g; $_ } @$p), " -- ";
+ my $result = exec_test($prog, $in);
+ my @good = ();
+ my $nmax = (@$out > @$result) ? @$out : @$result;
+ for (my $n=0; $n < $nmax; $n++) {
+ my $use_re;
+ if (defined $out->[$n] && $out->[$n] =~ /^~ /) {
+ $use_re = 1;
+ $out->[$n] =~ s/^~ //g;
+ }
+
+ if (!defined($out->[$n]) || !defined($result->[$n]) ||
+ (!$use_re && $result->[$n] ne $out->[$n]) ||
+ ( $use_re && $result->[$n] !~ /^$out->[$n]/)) {
+ push @good, ($use_re ? '!~' : '!=');
+ }
+ else {
+ push @good, ($use_re ? '=~' : '==');
+ }
+ }
+ my $good = !(grep /!/, @good);
+ $tests++;
+ $failed++ unless $good;
+ print $good ? $OK : $FAILED, "\n";
+ if (!$good || $opt_v) {
+ for (my $n=0; $n < $nmax; $n++) {
+ my $l = defined($out->[$n]) ? $out->[$n] : "~";
+ chomp $l;
+ my $r = defined($result->[$n]) ? $result->[$n] : "~";
+ chomp $r;
+ print sprintf("%-" . ($width-3) . "s %s %s\n",
+ $r, $good[$n], $l);
+ }
+ }
+}
+
+
+sub su($) {
+ my ($user) = @_;
+
+ $user ||= "root";
+
+ my ($login, $pass, $uid, $gid) = getpwnam($user)
+ or return [ "su: user $user does not exist\n" ];
+ my @groups = ();
+ my $fh = new FileHandle("/etc/group")
+ or return [ "opening /etc/group: $!\n" ];
+ while (<$fh>) {
+ chomp;
+ my ($group, $passwd, $gid, $users) = split /:/;
+ foreach my $u (split /,/, $users) {
+ push @groups, $gid
+ if ($user eq $u);
+ }
+ }
+ $fh->close;
+
+ my $groups = join(" ", ($gid, $gid, @groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ if ($!) {
+ return [ "su: $!\n" ];
+ }
+ if ($uid != 0) {
+ $> = $uid;
+ #$< = $uid;
+ if ($!) {
+ return [ "su: $prog->[1]: $!\n" ];
+ }
+ }
+ #print STDERR "[($>,$<)($(,$))]";
+ return [];
+}
+
+
+sub sg($) {
+ my ($group) = @_;
+
+ my $gid = getgrnam($group)
+ or return [ "sg: group $group does not exist\n" ];
+ my %groups = map { $_ eq $gid ? () : ($_ => 1) } (split /\s/, $));
+
+ #print STDERR "<<", join("/", keys %groups), ">>\n";
+ my $groups = join(" ", ($gid, $gid, keys %groups));
+ #print STDERR "[[$groups]]\n";
+ $! = 0; # reset errno
+ if ($> != 0) {
+ my $uid = $>;
+ $> = 0;
+ $( = $gid;
+ $) = $groups;
+ $> = $uid;
+ } else {
+ $( = $gid;
+ $) = $groups;
+ }
+ if ($!) {
+ return [ "sg: $!\n" ];
+ }
+ print STDERR "[($>,$<)($(,$))]";
+ return [];
+}
+
+
+sub exec_test($$) {
+ my ($prog, $in) = @_;
+ local (*IN, *IN_DUP, *IN2, *OUT_DUP, *OUT, *OUT2);
+ my $needs_shell = (join('', @$prog) =~ /[][|<>"'`\$\*\?]/);
+
+ if ($prog->[0] eq "umask") {
+ umask oct $prog->[1];
+ return [];
+ } elsif ($prog->[0] eq "cd") {
+ if (!chdir $prog->[1]) {
+ return [ "chdir: $prog->[1]: $!\n" ];
+ }
+ $ENV{PWD} = getcwd;
+ return [];
+ } elsif ($prog->[0] eq "su") {
+ return su($prog->[1]);
+ } elsif ($prog->[0] eq "sg") {
+ return sg($prog->[1]);
+ } elsif ($prog->[0] eq "export") {
+ my ($name, $value) = split /=/, $prog->[1];
+ # FIXME: need to evaluate $value, so that things like this will work:
+ # export dir=$PWD/dir
+ $ENV{$name} = $value;
+ return [];
+ } elsif ($prog->[0] eq "unset") {
+ delete $ENV{$prog->[1]};
+ return [];
+ }
+
+ pipe *IN2, *OUT
+ or die "Can't create pipe for reading: $!";
+ open *IN_DUP, "<&STDIN"
+ or *IN_DUP = undef;
+ open *STDIN, "<&IN2"
+ or die "Can't duplicate pipe for reading: $!";
+ close *IN2;
+
+ open *OUT_DUP, ">&STDOUT"
+ or die "Can't duplicate STDOUT: $!";
+ pipe *IN, *OUT2
+ or die "Can't create pipe for writing: $!";
+ open *STDOUT, ">&OUT2"
+ or die "Can't duplicate pipe for writing: $!";
+ close *OUT2;
+
+ *STDOUT->autoflush();
+ *OUT->autoflush();
+
+ $SIG{CHLD} = 'IGNORE';
+
+ if (fork()) {
+ # Server
+ if (*IN_DUP) {
+ open *STDIN, "<&IN_DUP"
+ or die "Can't duplicate STDIN: $!";
+ close *IN_DUP
+ or die "Can't close STDIN duplicate: $!";
+ }
+ open *STDOUT, ">&OUT_DUP"
+ or die "Can't duplicate STDOUT: $!";
+ close *OUT_DUP
+ or die "Can't close STDOUT duplicate: $!";
+
+ foreach my $line (@$in) {
+ #print "> $line";
+ print OUT $line;
+ }
+ close *OUT
+ or die "Can't close pipe for writing: $!";
+
+ my $result = [];
+ while (<IN>) {
+ #print "< $_";
+ if ($needs_shell) {
+ s#^/bin/sh: line \d+: ##;
+ }
+ push @$result, $_;
+ }
+ return $result;
+ } else {
+ # Client
+ $< = $>;
+ close IN
+ or die "Can't close read end for input pipe: $!";
+ close OUT
+ or die "Can't close write end for output pipe: $!";
+ close OUT_DUP
+ or die "Can't close STDOUT duplicate: $!";
+ local *ERR_DUP;
+ open ERR_DUP, ">&STDERR"
+ or die "Can't duplicate STDERR: $!";
+ open STDERR, ">&STDOUT"
+ or die "Can't join STDOUT and STDERR: $!";
+
+ if ($needs_shell) {
+ exec ('/bin/sh', '-c', join(" ", @$prog));
+ } else {
+ exec @$prog;
+ }
+ print STDERR $prog->[0], ": $!\n";
+ exit;
+ }
+}
+
diff --git a/sbin/mount_fusefs/Makefile b/sbin/mount_fusefs/Makefile
index 0af8a80..9c84fa6 100644
--- a/sbin/mount_fusefs/Makefile
+++ b/sbin/mount_fusefs/Makefile
@@ -23,7 +23,6 @@ DEBUG_FLAGS+= -DFUSE4BSD_VERSION="\"${F4BVERS}\""
PROG= mount_fusefs
SRCS= mount_fusefs.c getmntopts.c
MAN8= mount_fusefs.8
-NO_MANCOMPRESS?= yes
MOUNT= ${.CURDIR}/../mount
CFLAGS+= -I${MOUNT}
diff --git a/sbin/mount_nfs/mount_nfs.8 b/sbin/mount_nfs/mount_nfs.8
index 216b248..da11c29 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 July 8, 2013
+.Dd December 7, 2013
.Dt MOUNT_NFS 8
.Os
.Sh NAME
@@ -257,6 +257,19 @@ servers on the client.
Note that this option will only be honored when performing the
initial mount, it will be silently ignored if used while updating
the mount options.
+.It Cm noncontigwr
+This mount option allows the NFS client to
+combine non-contiguous byte ranges being written
+such that the dirty byte range becomes a superset of the bytes
+that are dirty.
+This reduces the number of writes significantly for software
+builds.
+The merging of byte ranges isn't done if the file has been file
+locked, since most applications modifying a file from multiple
+clients will use file locking.
+As such, this option could result in a corrupted file for the
+rare case of an application modifying the file from multiple
+clients concurrently without using file locking.
.It Cm principal
For the RPCSEC_GSS security flavors, such as krb5, krb5i and krb5p,
this option sets the name of the host based principal name expected
diff --git a/sbin/mount_udf/mount_udf.c b/sbin/mount_udf/mount_udf.c
index 01fa44f..7585c50 100644
--- a/sbin/mount_udf/mount_udf.c
+++ b/sbin/mount_udf/mount_udf.c
@@ -77,9 +77,9 @@ main(int argc, char **argv)
char fstype[] = "udf";
struct iovec *iov;
char *cs_disk, *cs_local, *dev, *dir;
- int ch, i, iovlen, mntflags, udf_flags, verbose;
+ int ch, iovlen, mntflags, udf_flags, verbose;
- i = iovlen = mntflags = udf_flags = verbose = 0;
+ iovlen = mntflags = udf_flags = verbose = 0;
cs_disk = cs_local = NULL;
iov = NULL;
while ((ch = getopt(argc, argv, "o:vC:")) != -1)
@@ -129,7 +129,7 @@ main(int argc, char **argv)
build_iovec(&iov, &iovlen, "cs_disk", cs_disk, (size_t)-1);
build_iovec(&iov, &iovlen, "cs_local", cs_local, (size_t)-1);
}
- if (nmount(iov, i, mntflags) < 0)
+ if (nmount(iov, iovlen, mntflags) < 0)
err(1, "%s", dev);
exit(0);
}
diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c
index a4cfa8d..ee6ed96 100644
--- a/sbin/newfs/mkfs.c
+++ b/sbin/newfs/mkfs.c
@@ -134,12 +134,10 @@ mkfs(struct partition *pp, char *fsys)
*/
disk.d_bsize = sectorsize;
disk.d_ufs = Oflag;
- if (Rflag) {
+ if (Rflag)
utime = 1000000000;
- } else {
+ else
time(&utime);
- arc4random_stir();
- }
sblock.fs_old_flags = FS_FLAGS_UPDATED;
sblock.fs_flags = 0;
if (Uflag)
@@ -546,7 +544,7 @@ restart:
* Now build the cylinders group blocks and
* then print out indices of cylinder groups.
*/
- printf("super-block backups (for fsck -b #) at:\n");
+ printf("super-block backups (for fsck_ffs -b #) at:\n");
i = 0;
width = charsperline();
/*
diff --git a/sbin/newfs_msdos/newfs_msdos.c b/sbin/newfs_msdos/newfs_msdos.c
index 217b720..1f5b438 100644
--- a/sbin/newfs_msdos/newfs_msdos.c
+++ b/sbin/newfs_msdos/newfs_msdos.c
@@ -64,11 +64,11 @@ static const char rcsid[] =
#define DEFRDE 512 /* default root directory entries */
#define RESFTE 2 /* reserved FAT entries */
#define MINCLS12 1U /* minimum FAT12 clusters */
-#define MINCLS16 0x1000U /* minimum FAT16 clusters */
-#define MINCLS32 2U /* minimum FAT32 clusters */
-#define MAXCLS12 0xfedU /* maximum FAT12 clusters */
-#define MAXCLS16 0xfff5U /* maximum FAT16 clusters */
-#define MAXCLS32 0xffffff5U /* maximum FAT32 clusters */
+#define MINCLS16 0xff5U /* minimum FAT16 clusters */
+#define MINCLS32 0xfff5U /* minimum FAT32 clusters */
+#define MAXCLS12 0xff4U /* maximum FAT12 clusters */
+#define MAXCLS16 0xfff4U /* maximum FAT16 clusters */
+#define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */
#define mincls(fat) ((fat) == 12 ? MINCLS12 : \
(fat) == 16 ? MINCLS16 : \
diff --git a/sbin/newfs_nandfs/newfs_nandfs.c b/sbin/newfs_nandfs/newfs_nandfs.c
index 5242318..fda2b9ed 100644
--- a/sbin/newfs_nandfs/newfs_nandfs.c
+++ b/sbin/newfs_nandfs/newfs_nandfs.c
@@ -988,10 +988,10 @@ calculate_geometry(int fd)
/* Get storage erase unit size */
if (!is_nand)
erasesize = NANDFS_DEF_ERASESIZE;
- else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) == -1)
- errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
- else
+ else if (ioctl(fd, NAND_IO_GET_CHIP_PARAM, &chip_params) != -1)
erasesize = chip_params.page_size * chip_params.pages_per_block;
+ else
+ errx(1, "Cannot ioctl(NAND_IO_GET_CHIP_PARAM)");
debug("erasesize: %#jx", (uintmax_t)erasesize);
diff --git a/sbin/nos-tun/nos-tun.c b/sbin/nos-tun/nos-tun.c
index 83e7144..ee0fc4c 100644
--- a/sbin/nos-tun/nos-tun.c
+++ b/sbin/nos-tun/nos-tun.c
@@ -96,7 +96,7 @@ Set_address(char *addr, struct sockaddr_in *sin)
bzero((char *)sin, sizeof(struct sockaddr));
sin->sin_family = AF_INET;
- if((sin->sin_addr.s_addr = inet_addr(addr)) == (in_addr_t)-1) {
+ if((sin->sin_addr.s_addr = inet_addr(addr)) == INADDR_NONE) {
hp = gethostbyname(addr);
if (!hp) {
syslog(LOG_ERR,"unknown host %s", addr);
diff --git a/sbin/nvmecontrol/devlist.c b/sbin/nvmecontrol/devlist.c
index f73d643..35a46c1 100644
--- a/sbin/nvmecontrol/devlist.c
+++ b/sbin/nvmecontrol/devlist.c
@@ -99,11 +99,11 @@ devlist(int argc, char *argv[])
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",
+ printf(" %10s (%lldMB)\n",
name,
nsdata.nsze *
(long long)ns_get_sector_size(&nsdata) /
- 1024 / 1024 / 1024);
+ 1024 / 1024);
}
close(fd);
diff --git a/sbin/nvmecontrol/firmware.c b/sbin/nvmecontrol/firmware.c
index cb7fb0f..281fabe 100644
--- a/sbin/nvmecontrol/firmware.c
+++ b/sbin/nvmecontrol/firmware.c
@@ -141,7 +141,7 @@ update_firmware(int fd, uint8_t *payload, int32_t payload_size)
}
}
-static void
+static int
activate_firmware(int fd, int slot, int activate_action)
{
struct nvme_pt_command pt;
@@ -154,8 +154,14 @@ activate_firmware(int fd, int slot, int activate_action)
if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0)
err(1, "firmware activate request failed");
+ if (pt.cpl.status.sct == NVME_SCT_COMMAND_SPECIFIC &&
+ pt.cpl.status.sc == NVME_SC_FIRMWARE_REQUIRES_RESET)
+ return 1;
+
if (nvme_completion_is_error(&pt.cpl))
errx(1, "firmware activate request returned error");
+
+ return 0;
}
static void
@@ -171,6 +177,7 @@ firmware(int argc, char *argv[])
{
int fd = -1, slot = 0;
int a_flag, s_flag, f_flag;
+ int activate_action, reboot_required;
char ch, *p, *image = NULL;
char *controller = NULL, prompt[64];
void *buf = NULL;
@@ -287,21 +294,27 @@ firmware(int argc, char *argv[])
if (f_flag) {
update_firmware(fd, buf, size);
if (a_flag)
- activate_firmware(fd, slot,
- NVME_AA_REPLACE_ACTIVATE);
+ activate_action = NVME_AA_REPLACE_ACTIVATE;
else
- activate_firmware(fd, slot,
- NVME_AA_REPLACE_NO_ACTIVATE);
+ activate_action = NVME_AA_REPLACE_NO_ACTIVATE;
} else {
- activate_firmware(fd, slot, NVME_AA_ACTIVATE);
+ activate_action = NVME_AA_ACTIVATE;
}
+ reboot_required = activate_firmware(fd, slot, activate_action);
+
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);
+ if (reboot_required) {
+ printf("New firmware image activated but requires "
+ "conventional reset (i.e. reboot) to "
+ "complete activation.\n");
+ } else {
+ 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);
diff --git a/sbin/nvmecontrol/perftest.c b/sbin/nvmecontrol/perftest.c
index 15e4975..cc91198 100644
--- a/sbin/nvmecontrol/perftest.c
+++ b/sbin/nvmecontrol/perftest.c
@@ -64,8 +64,6 @@ print_perftest(struct nvme_io_test *io_test, bool perthread)
for (i = 0; i < io_test->num_threads; i++)
printf("\t%3d: %8ju IO/s\n", i,
(uintmax_t)io_test->io_completed[i]/io_test->time);
-
- exit(1);
}
static void
diff --git a/sbin/pfctl/Makefile b/sbin/pfctl/Makefile
index 26c2258..5b3735c 100644
--- a/sbin/pfctl/Makefile
+++ b/sbin/pfctl/Makefile
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <bsd.own.mk>
+
# pf_ruleset.c is shared between kernel and pfctl
.PATH: ${.CURDIR}/../../sys/netpfil/pf
@@ -16,6 +18,14 @@ CFLAGS+= -Wall -Wmissing-prototypes -Wno-uninitialized
CFLAGS+= -Wstrict-prototypes
CFLAGS+= -DENABLE_ALTQ -I${.CURDIR}
+# Need to use "WITH_" prefix to not conflict with the l/y INET/INET6 keywords
+.if ${MK_INET6_SUPPORT} != "no"
+CFLAGS+= -DWITH_INET6
+.endif
+.if ${MK_INET_SUPPORT} != "no"
+CFLAGS+= -DWITH_INET
+.endif
+
YFLAGS=
LDADD+= -lm -lmd
diff --git a/sbin/pfctl/pf_print_state.c b/sbin/pfctl/pf_print_state.c
index d4a2c1d..46d4523 100644
--- a/sbin/pfctl/pf_print_state.c
+++ b/sbin/pfctl/pf_print_state.c
@@ -285,8 +285,13 @@ print_state(struct pfsync_state *s, int opts)
const char *states[] = PFUDPS_NAMES;
printf(" %s:%s\n", states[src->state], states[dst->state]);
+#ifndef INET6
} else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES &&
dst->state < PFOTHERS_NSTATES) {
+#else
+ } else if (s->proto != IPPROTO_ICMP && s->proto != IPPROTO_ICMPV6 &&
+ src->state < PFOTHERS_NSTATES && dst->state < PFOTHERS_NSTATES) {
+#endif
/* XXX ICMP doesn't really have state levels */
const char *states[] = PFOTHERS_NAMES;
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 90a2bb5..f90fd70 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -38,10 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
-
-#ifdef __FreeBSD__
#include <sys/endian.h>
-#endif
#include <net/if.h>
#include <netinet/in.h>
@@ -55,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -234,13 +232,13 @@ usage(void)
{
extern char *__progname;
- fprintf(stderr, "usage: %s [-AdeghmNnOPqRrvz] ", __progname);
- fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
- fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n");
- fprintf(stderr, "\t[-k host | network | label | id] ");
- fprintf(stderr, "[-o level] [-p device]\n");
- fprintf(stderr, "\t[-s modifier] ");
- fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n");
+ fprintf(stderr,
+"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
+ "\t[-f file] [-i interface] [-K host | network]\n"
+ "\t[-k host | network | label | id] [-o level] [-p device]\n"
+ "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
+ __progname);
+
exit(1);
}
@@ -250,10 +248,8 @@ pfctl_enable(int dev, int opts)
if (ioctl(dev, DIOCSTART)) {
if (errno == EEXIST)
errx(1, "pf already enabled");
-#ifdef __FreeBSD__
else if (errno == ESRCH)
errx(1, "pfil registeration failed");
-#endif
else
err(1, "DIOCSTART");
}
@@ -796,17 +792,17 @@ pfctl_print_rule_counters(struct pf_rule *rule, int opts)
}
if (opts & PF_OPT_VERBOSE) {
printf(" [ Evaluations: %-8llu Packets: %-8llu "
- "Bytes: %-10llu States: %-6u]\n",
+ "Bytes: %-10llu States: %-6ju]\n",
(unsigned long long)rule->evaluations,
(unsigned long long)(rule->packets[0] +
rule->packets[1]),
(unsigned long long)(rule->bytes[0] +
- rule->bytes[1]), rule->states_cur);
+ rule->bytes[1]), (uintmax_t)rule->u_states_cur);
if (!(opts & PF_OPT_DEBUG))
printf(" [ Inserted: uid %u pid %u "
- "State Creations: %-6u]\n",
+ "State Creations: %-6ju]\n",
(unsigned)rule->cuid, (unsigned)rule->cpid,
- rule->states_tot);
+ (uintmax_t)rule->u_states_tot);
}
}
@@ -908,7 +904,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
case PFCTL_SHOW_LABELS:
if (pr.rule.label[0]) {
printf("%s %llu %llu %llu %llu"
- " %llu %llu %llu %llu\n",
+ " %llu %llu %llu %ju\n",
pr.rule.label,
(unsigned long long)pr.rule.evaluations,
(unsigned long long)(pr.rule.packets[0] +
@@ -919,7 +915,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format,
(unsigned long long)pr.rule.bytes[0],
(unsigned long long)pr.rule.packets[1],
(unsigned long long)pr.rule.bytes[1],
- (unsigned long long)pr.rule.states_tot);
+ (uintmax_t)pr.rule.u_states_tot);
}
break;
case PFCTL_SHOW_RULES:
@@ -2185,7 +2181,7 @@ main(int argc, char *argv[])
/* turn off options */
opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE);
clearopt = showopt = debugopt = NULL;
-#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ)
+#if !defined(ENABLE_ALTQ)
altqsupport = 0;
#else
altqsupport = 1;
diff --git a/sbin/pfctl/pfctl_altq.c b/sbin/pfctl/pfctl_altq.c
index 40e11d5..ae566f8 100644
--- a/sbin/pfctl/pfctl_altq.c
+++ b/sbin/pfctl/pfctl_altq.c
@@ -1122,7 +1122,7 @@ getifspeed(char *ifname)
struct ifreq ifr;
struct if_data ifrdat;
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
err(1, "socket");
bzero(&ifr, sizeof(ifr));
if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
@@ -1143,7 +1143,7 @@ getifmtu(char *ifname)
int s;
struct ifreq ifr;
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0)
err(1, "socket");
bzero(&ifr, sizeof(ifr));
if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index f248995..1f4375a 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -1231,6 +1231,26 @@ ifa_load(void)
freeifaddrs(ifap);
}
+int
+get_socket_domain(void)
+{
+ int sdom;
+
+ sdom = AF_UNSPEC;
+#ifdef WITH_INET6
+ if (sdom == AF_UNSPEC && feature_present("inet6"))
+ sdom = AF_INET6;
+#endif
+#ifdef WITH_INET
+ if (sdom == AF_UNSPEC && feature_present("inet"))
+ sdom = AF_INET;
+#endif
+ if (sdom == AF_UNSPEC)
+ sdom = AF_LINK;
+
+ return (sdom);
+}
+
struct node_host *
ifa_exists(const char *ifa_name)
{
@@ -1242,7 +1262,7 @@ ifa_exists(const char *ifa_name)
ifa_load();
/* check wether this is a group */
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1)
err(1, "socket");
bzero(&ifgr, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
@@ -1273,7 +1293,7 @@ ifa_grouplookup(const char *ifa_name, int flags)
int s, len;
struct node_host *n, *h = NULL;
- if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1)
err(1, "socket");
bzero(&ifgr, sizeof(ifgr));
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name));
diff --git a/sbin/pfctl/pfctl_parser.h b/sbin/pfctl/pfctl_parser.h
index 4560d66..5c909e9 100644
--- a/sbin/pfctl/pfctl_parser.h
+++ b/sbin/pfctl/pfctl_parser.h
@@ -294,6 +294,7 @@ void set_ipmask(struct node_host *, u_int8_t);
int check_netmask(struct node_host *, sa_family_t);
int unmask(struct pf_addr *, sa_family_t);
void ifa_load(void);
+int get_socket_domain(void);
struct node_host *ifa_exists(const char *);
struct node_host *ifa_lookup(const char *, int);
struct node_host *host(const char *);
diff --git a/sbin/ping/Makefile b/sbin/ping/Makefile
index 838e1ea..c3dda69 100644
--- a/sbin/ping/Makefile
+++ b/sbin/ping/Makefile
@@ -1,6 +1,8 @@
# @(#)Makefile 8.1 (Berkeley) 6/5/93
# $FreeBSD$
+.include <bsd.own.mk>
+
PROG= ping
MAN= ping.8
BINOWN= root
@@ -9,6 +11,12 @@ WARNS?= 2
DPADD= ${LIBM}
LDADD= -lm
+.if ${MK_CASPER} != "no" && !defined(RESCUE)
+DPADD+= ${LIBCAPSICUM} ${LIBNV}
+LDADD+= -lcapsicum -lnv
+CFLAGS+=-DHAVE_LIBCAPSICUM
+.endif
+
.if !defined(RELEASE_CRUNCH)
CFLAGS+=-DIPSEC
DPADD+= ${LIBIPSEC}
diff --git a/sbin/ping/ping.c b/sbin/ping/ping.c
index 85d0348..283c22b 100644
--- a/sbin/ping/ping.c
+++ b/sbin/ping/ping.c
@@ -63,6 +63,7 @@ __FBSDID("$FreeBSD$");
*/
#include <sys/param.h> /* NB: we rely on this for <sys/types.h> */
+#include <sys/capsicum.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
@@ -74,6 +75,11 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
#include <arpa/inet.h>
+#ifdef HAVE_LIBCAPSICUM
+#include <libcapsicum.h>
+#include <libcapsicum_dns.h>
+#include <libcapsicum_service.h>
+#endif
#ifdef IPSEC
#include <netipsec/ipsec.h>
@@ -157,7 +163,8 @@ char rcvd_tbl[MAX_DUP_CHK / 8];
struct sockaddr_in whereto; /* who to ping */
int datalen = DEFDATALEN;
int maxpayload;
-int s; /* socket file descriptor */
+int ssend; /* send socket file descriptor */
+int srecv; /* receive socket file descriptor */
u_char outpackhdr[IP_MAXPACKET], *outpack;
char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */
char BSPACE = '\b'; /* characters written for flood */
@@ -197,8 +204,15 @@ double tsumsq = 0.0; /* sum of all times squared, for std. dev. */
volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */
volatile sig_atomic_t siginfo_p;
+#ifdef HAVE_LIBCAPSICUM
+static cap_channel_t *capdns;
+#endif
+
static void fill(char *, char *);
static u_short in_cksum(u_short *, int);
+#ifdef HAVE_LIBCAPSICUM
+static cap_channel_t *capdns_setup(void);
+#endif
static void check_status(void);
static void finish(void) __dead2;
static void pinger(void);
@@ -233,8 +247,8 @@ main(int argc, char *const *argv)
struct sockaddr_in *to;
double t;
u_long alarmtimeout, ultmp;
- int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno,
- tos, ttl;
+ int almost_done, ch, df, hold, i, icmp_len, mib[4], preload;
+ int ssend_errno, srecv_errno, tos, ttl;
char ctrl[CMSG_SPACE(sizeof(struct timeval))];
char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN];
#ifdef IP_OPTIONS
@@ -246,14 +260,26 @@ main(int argc, char *const *argv)
#ifdef IPSEC_POLICY_IPSEC
policy_in = policy_out = NULL;
#endif
+ cap_rights_t rights;
+ bool cansandbox;
/*
* Do the stuff that we need root priv's for *first*, and
* then drop our setuid bit. Save error reporting for
* after arg parsing.
+ *
+ * Historicaly ping was using one socket 's' for sending and for
+ * receiving. After capsicum(4) related changes we use two
+ * sockets. It was done for special ping use case - when user
+ * issue ping on multicast or broadcast address replies come
+ * from different addresses, not from the address we
+ * connect(2)'ed to, and send socket do not receive those
+ * packets.
*/
- s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- sockerrno = errno;
+ ssend = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ ssend_errno = errno;
+ srecv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ srecv_errno = errno;
if (setuid(getuid()) != 0)
err(EX_NOPERM, "setuid() failed");
@@ -527,13 +553,22 @@ main(int argc, char *const *argv)
if (options & F_PINGFILLED) {
fill((char *)datap, payload);
}
+#ifdef HAVE_LIBCAPSICUM
+ capdns = capdns_setup();
+#endif
if (source) {
bzero((char *)&sock_in, sizeof(sock_in));
sock_in.sin_family = AF_INET;
if (inet_aton(source, &sock_in.sin_addr) != 0) {
shostname = source;
} else {
- hp = gethostbyname2(source, AF_INET);
+#ifdef HAVE_LIBCAPSICUM
+ if (capdns != NULL)
+ hp = cap_gethostbyname2(capdns, source,
+ AF_INET);
+ else
+#endif
+ hp = gethostbyname2(source, AF_INET);
if (!hp)
errx(EX_NOHOST, "cannot resolve %s: %s",
source, hstrerror(h_errno));
@@ -549,7 +584,8 @@ main(int argc, char *const *argv)
snamebuf[sizeof(snamebuf) - 1] = '\0';
shostname = snamebuf;
}
- if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1)
+ if (bind(ssend, (struct sockaddr *)&sock_in, sizeof sock_in) ==
+ -1)
err(1, "bind");
}
@@ -560,7 +596,12 @@ main(int argc, char *const *argv)
if (inet_aton(target, &to->sin_addr) != 0) {
hostname = target;
} else {
- hp = gethostbyname2(target, AF_INET);
+#ifdef HAVE_LIBCAPSICUM
+ if (capdns != NULL)
+ hp = cap_gethostbyname2(capdns, target, AF_INET);
+ else
+#endif
+ hp = gethostbyname2(target, AF_INET);
if (!hp)
errx(EX_NOHOST, "cannot resolve %s: %s",
target, hstrerror(h_errno));
@@ -573,6 +614,30 @@ main(int argc, char *const *argv)
hostname = hnamebuf;
}
+#ifdef HAVE_LIBCAPSICUM
+ /* From now on we will use only reverse DNS lookups. */
+ if (capdns != NULL) {
+ const char *types[1];
+
+ types[0] = "ADDR";
+ if (cap_dns_type_limit(capdns, types, 1) < 0)
+ err(1, "unable to limit access to system.dns service");
+ }
+#endif
+
+ if (ssend < 0) {
+ errno = ssend_errno;
+ err(EX_OSERR, "ssend socket");
+ }
+
+ if (srecv < 0) {
+ errno = srecv_errno;
+ err(EX_OSERR, "srecv socket");
+ }
+
+ if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0)
+ err(1, "connect");
+
if (options & F_FLOOD && options & F_INTERVAL)
errx(EX_USAGE, "-f and -i: incompatible options");
@@ -593,16 +658,15 @@ main(int argc, char *const *argv)
ident = getpid() & 0xFFFF;
- if (s < 0) {
- errno = sockerrno;
- err(EX_OSERR, "socket");
- }
hold = 1;
- if (options & F_SO_DEBUG)
- (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ if (options & F_SO_DEBUG) {
+ (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold,
sizeof(hold));
+ (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold,
+ sizeof(hold));
+ }
if (options & F_SO_DONTROUTE)
- (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
+ (void)setsockopt(ssend, SOL_SOCKET, SO_DONTROUTE, (char *)&hold,
sizeof(hold));
#ifdef IPSEC
#ifdef IPSEC_POLICY_IPSEC
@@ -612,7 +676,7 @@ main(int argc, char *const *argv)
buf = ipsec_set_policy(policy_in, strlen(policy_in));
if (buf == NULL)
errx(EX_CONFIG, "%s", ipsec_strerror());
- if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ if (setsockopt(srecv, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0)
err(EX_CONFIG,
"ipsec policy cannot be configured");
@@ -623,7 +687,7 @@ main(int argc, char *const *argv)
buf = ipsec_set_policy(policy_out, strlen(policy_out));
if (buf == NULL)
errx(EX_CONFIG, "%s", ipsec_strerror());
- if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY,
+ if (setsockopt(ssend, IPPROTO_IP, IP_IPSEC_POLICY,
buf, ipsec_get_policylen(buf)) < 0)
err(EX_CONFIG,
"ipsec policy cannot be configured");
@@ -644,7 +708,7 @@ main(int argc, char *const *argv)
if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1)
err(1, "sysctl(net.inet.ip.ttl)");
}
- setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
+ setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold));
ip->ip_v = IPVERSION;
ip->ip_hl = sizeof(struct ip) >> 2;
ip->ip_tos = tos;
@@ -655,6 +719,35 @@ main(int argc, char *const *argv)
ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY;
ip->ip_dst = to->sin_addr;
}
+
+ if (options & F_NUMERIC)
+ cansandbox = true;
+#ifdef HAVE_LIBCAPSICUM
+ else if (capdns != NULL)
+ cansandbox = true;
+#endif
+ else
+ cansandbox = false;
+
+ /*
+ * Here we enter capability mode. Further down access to global
+ * namespaces (e.g filesystem) is restricted (see capsicum(4)).
+ * We must connect(2) our socket before this point.
+ */
+ if (cansandbox && cap_enter() < 0 && errno != ENOSYS)
+ err(1, "cap_enter");
+
+ if (cap_sandboxed())
+ fprintf(stderr, "capability mode sandbox enabled\n");
+
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT);
+ if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit srecv");
+
+ cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT);
+ if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit ssend");
+
/* record route option */
if (options & F_RROUTE) {
#ifdef IP_OPTIONS
@@ -663,7 +756,7 @@ main(int argc, char *const *argv)
rspace[IPOPT_OLEN] = sizeof(rspace) - 1;
rspace[IPOPT_OFFSET] = IPOPT_MINOFF;
rspace[sizeof(rspace) - 1] = IPOPT_EOL;
- if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace,
+ if (setsockopt(ssend, IPPROTO_IP, IP_OPTIONS, rspace,
sizeof(rspace)) < 0)
err(EX_OSERR, "setsockopt IP_OPTIONS");
#else
@@ -673,32 +766,32 @@ main(int argc, char *const *argv)
}
if (options & F_TTL) {
- if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl,
+ if (setsockopt(ssend, IPPROTO_IP, IP_TTL, &ttl,
sizeof(ttl)) < 0) {
err(EX_OSERR, "setsockopt IP_TTL");
}
}
if (options & F_NOLOOP) {
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
+ if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_LOOP, &loop,
sizeof(loop)) < 0) {
err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP");
}
}
if (options & F_MTTL) {
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
+ if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_TTL, &mttl,
sizeof(mttl)) < 0) {
err(EX_OSERR, "setsockopt IP_MULTICAST_TTL");
}
}
if (options & F_MIF) {
- if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
+ if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr,
sizeof(ifaddr)) < 0) {
err(EX_OSERR, "setsockopt IP_MULTICAST_IF");
}
}
#ifdef SO_TIMESTAMP
{ int on = 1;
- if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
+ if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0)
err(EX_OSERR, "setsockopt SO_TIMESTAMP");
}
#endif
@@ -733,11 +826,19 @@ main(int argc, char *const *argv)
* as well.
*/
hold = IP_MAXPACKET + 128;
- (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
+ (void)setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold,
sizeof(hold));
+ /* CAP_SETSOCKOPT removed */
+ cap_rights_init(&rights, CAP_RECV, CAP_EVENT);
+ if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit srecv setsockopt");
if (uid == 0)
- (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
+ (void)setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, (char *)&hold,
sizeof(hold));
+ /* CAP_SETSOCKOPT removed */
+ cap_rights_init(&rights, CAP_SEND);
+ if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS)
+ err(1, "cap_rights_limit ssend setsockopt");
if (to->sin_family == AF_INET) {
(void)printf("PING %s (%s)", hostname,
@@ -817,10 +918,10 @@ main(int argc, char *const *argv)
int cc, n;
check_status();
- if ((unsigned)s >= FD_SETSIZE)
+ if ((unsigned)srecv >= FD_SETSIZE)
errx(EX_OSERR, "descriptor too large");
FD_ZERO(&rfds);
- FD_SET(s, &rfds);
+ FD_SET(srecv, &rfds);
(void)gettimeofday(&now, NULL);
timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
@@ -834,7 +935,7 @@ main(int argc, char *const *argv)
}
if (timeout.tv_sec < 0)
timerclear(&timeout);
- n = select(s + 1, &rfds, NULL, NULL, &timeout);
+ n = select(srecv + 1, &rfds, NULL, NULL, &timeout);
if (n < 0)
continue; /* Must be EINTR. */
if (n == 1) {
@@ -845,7 +946,7 @@ main(int argc, char *const *argv)
msg.msg_controllen = sizeof(ctrl);
#endif
msg.msg_namelen = sizeof(from);
- if ((cc = recvmsg(s, &msg, 0)) < 0) {
+ if ((cc = recvmsg(srecv, &msg, 0)) < 0) {
if (errno == EINTR)
continue;
warn("recvmsg");
@@ -981,9 +1082,7 @@ pinger(void)
ip->ip_sum = in_cksum((u_short *)outpackhdr, cc);
packet = outpackhdr;
}
- i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto,
- sizeof(whereto));
-
+ i = send(ssend, (char *)packet, cc, 0);
if (i < 0 || i != cc) {
if (i < 0) {
if (options & F_FLOOD && errno == ENOBUFS) {
@@ -1604,12 +1703,21 @@ pr_addr(struct in_addr ina)
struct hostent *hp;
static char buf[16 + 3 + MAXHOSTNAMELEN];
- if ((options & F_NUMERIC) ||
- !(hp = gethostbyaddr((char *)&ina, 4, AF_INET)))
+ if (options & F_NUMERIC)
return inet_ntoa(ina);
+
+#ifdef HAVE_LIBCAPSICUM
+ if (capdns != NULL)
+ hp = cap_gethostbyaddr(capdns, (char *)&ina, 4, AF_INET);
else
- (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
- inet_ntoa(ina));
+#endif
+ hp = gethostbyaddr((char *)&ina, 4, AF_INET);
+
+ if (hp == NULL)
+ return inet_ntoa(ina);
+
+ (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
+ inet_ntoa(ina));
return(buf);
}
@@ -1682,6 +1790,36 @@ fill(char *bp, char *patp)
}
}
+#ifdef HAVE_LIBCAPSICUM
+static cap_channel_t *
+capdns_setup(void)
+{
+ cap_channel_t *capcas, *capdnsloc;
+ const char *types[2];
+ int families[1];
+
+ capcas = cap_init();
+ if (capcas == NULL) {
+ warn("unable to contact casperd");
+ return (NULL);
+ }
+ capdnsloc = cap_service_open(capcas, "system.dns");
+ /* Casper capability no longer needed. */
+ cap_close(capcas);
+ if (capdnsloc == NULL)
+ err(1, "unable to open system.dns service");
+ types[0] = "NAME";
+ types[1] = "ADDR";
+ if (cap_dns_type_limit(capdnsloc, types, 2) < 0)
+ err(1, "unable to limit access to system.dns service");
+ families[0] = AF_INET;
+ if (cap_dns_family_limit(capdnsloc, families, 1) < 0)
+ err(1, "unable to limit access to system.dns service");
+
+ return (capdnsloc);
+}
+#endif /* HAVE_LIBCAPSICUM */
+
#if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC)
#define SECOPT " [-P policy]"
#else
diff --git a/sbin/route/keywords b/sbin/route/keywords
index adfba7c..8b64be2 100644
--- a/sbin/route/keywords
+++ b/sbin/route/keywords
@@ -1,8 +1,9 @@
# @(#)keywords 8.2 (Berkeley) 3/19/94
# $FreeBSD$
+4
+6
add
-atalk
blackhole
change
cloning
@@ -39,6 +40,7 @@ osi
prefixlen
proto1
proto2
+proto3
proxy
recvpipe
reject
diff --git a/sbin/route/route.8 b/sbin/route/route.8
index b786106..000fbe9 100644
--- a/sbin/route/route.8
+++ b/sbin/route/route.8
@@ -28,7 +28,7 @@
.\" @(#)route.8 8.3 (Berkeley) 3/19/94
.\" $FreeBSD$
.\"
-.Dd November 17, 2012
+.Dd January 11, 2014
.Dt ROUTE 8
.Os
.Sh NAME
@@ -62,6 +62,14 @@ programmatic interface discussed in
.Pp
The following options are available:
.Bl -tag -width indent
+.It Fl 4
+Specify
+.Cm inet
+address family as family hint for subcommands.
+.It Fl 6
+Specify
+.Cm inet
+address family as family hint for subcommands.
.It Fl d
Run in debug-only mode, i.e., do not actually modify the routing table.
.It Fl n
@@ -136,12 +144,20 @@ will ``flush'' the routing tables of all gateway entries.
When the address family may is specified by any of the
.Fl osi ,
.Fl xns ,
-.Fl atalk ,
.Fl inet6 ,
or
.Fl inet
modifiers, only routes having destinations with addresses in the
delineated family will be deleted.
+Additionally,
+.Fl 4
+or
+.Fl 6
+can be used as aliases for
+.Fl inet
+and
+.Fl inet6
+modifiers.
When a
.Fl fib
option is specified, the operation will be applied to
@@ -238,14 +254,12 @@ if the local or remote addresses change.
The optional modifiers
.Fl xns ,
.Fl osi ,
-.Fl atalk ,
and
.Fl link
specify that all subsequent addresses are in the
-.Tn XNS ,
-.Tn OSI ,
+.Tn XNS
or
-.Tn AppleTalk
+.Tn OSI
address families,
or are specified as link-level addresses,
and the names must be numeric specifications rather than
@@ -301,6 +315,7 @@ by indicating the following corresponding modifiers:
-blackhole RTF_BLACKHOLE - silently discard pkts (during updates)
-proto1 RTF_PROTO1 - set protocol specific routing flag #1
-proto2 RTF_PROTO2 - set protocol specific routing flag #2
+-proto3 RTF_PROTO3 - set protocol specific routing flag #3
.Ed
.Pp
The optional modifiers
@@ -324,6 +339,17 @@ specify that all ensuing metrics may be locked by the
.Fl lockrest
meta-modifier.
.Pp
+Note that
+.Fl expire
+accepts expiration time of the route as the number of seconds since the
+Epoch
+.Pq see Xr time 3 .
+When the first character of the number is
+.Dq +
+or
+.Dq - ,
+it is interpreted as a value relative to the current time.
+.Pp
The optional modifier
.Fl fib Ar number
specifies that the command will be applied to a non-default FIB.
@@ -458,7 +484,6 @@ The next-hop gateway should be reachable through a different route.
.Xr netintro 4 ,
.Xr route 4 ,
.Xr arp 8 ,
-.Xr IPXrouted 8 ,
.Xr routed 8
.\".Xr XNSrouted 8
.Sh HISTORY
diff --git a/sbin/route/route.c b/sbin/route/route.c
index 6c2bbe2..794f143 100644
--- a/sbin/route/route.c
+++ b/sbin/route/route.c
@@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$");
#include <net/if_dl.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
-#include <netatalk/at.h>
#include <arpa/inet.h>
#include <netdb.h>
@@ -63,17 +62,27 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <paths.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
+#include <time.h>
#include <unistd.h>
#include <ifaddrs.h>
+struct fibl {
+ TAILQ_ENTRY(fibl) fl_next;
+
+ int fl_num;
+ int fl_error;
+ int fl_errno;
+};
+
static struct keytab {
const char *kt_cp;
int kt_i;
-} keywords[] = {
+} const keywords[] = {
#include "keywords.h"
{0, 0}
};
@@ -81,7 +90,7 @@ static struct keytab {
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 nflag, af, qflag, tflag;
static int verbose, aflen;
static int locking, lockrest, debugonly;
static struct rt_metrics rt_metrics;
@@ -89,9 +98,19 @@ static u_long rtm_inits;
static uid_t uid;
static int defaultfib;
static int numfibs;
+static char domain[MAXHOSTNAMELEN + 1];
+static bool domain_initialized;
+static int rtm_seq;
+static char rt_line[NI_MAXHOST];
+static char net_line[MAXHOSTNAMELEN + 1];
+
+static struct {
+ struct rt_msghdr m_rtm;
+ char m_space[512];
+} m_rtmsg;
+
+static TAILQ_HEAD(fibl_head_t, fibl) fibl_head;
-static int atalk_aton(const char *, struct at_addr *);
-static char *atalk_ntoa(struct at_addr);
static void printb(int, const char *);
static void flushroutes(int argc, char *argv[]);
static int flushroutes_fib(int);
@@ -120,16 +139,6 @@ static void set_metric(char *, int);
static int set_sofib(int);
static void sockaddr(char *, struct sockaddr *, size_t);
static void sodump(struct sockaddr *, const char *);
-
-struct fibl {
- TAILQ_ENTRY(fibl) fl_next;
-
- int fl_num;
- int fl_error;
- int fl_errno;
-};
-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 *);
@@ -140,7 +149,7 @@ usage(const char *cp)
{
if (cp != NULL)
warnx("bad keyword: %s", cp);
- errx(EX_USAGE, "usage: route [-dnqtv] command [[modifiers] args]");
+ errx(EX_USAGE, "usage: route [-46dnqtv] command [[modifiers] args]");
/* NOTREACHED */
}
@@ -153,8 +162,24 @@ main(int argc, char **argv)
if (argc < 2)
usage(NULL);
- while ((ch = getopt(argc, argv, "nqdtv")) != -1)
+ while ((ch = getopt(argc, argv, "46nqdtv")) != -1)
switch(ch) {
+ case '4':
+#ifdef INET
+ af = AF_INET;
+ aflen = sizeof(struct sockaddr_in);
+#else
+ errx(1, "IPv4 support is not compiled in");
+#endif
+ break;
+ case '6':
+#ifdef INET6
+ af = AF_INET6;
+ aflen = sizeof(struct sockaddr_in6);
+#else
+ errx(1, "IPv6 support is not compiled in");
+#endif
+ break;
case 'n':
nflag = 1;
break;
@@ -368,18 +393,17 @@ flushroutes(int argc, char *argv[])
usage(*argv);
switch (keyword(*argv + 1)) {
#ifdef INET
+ case K_4:
case K_INET:
af = AF_INET;
break;
#endif
#ifdef INET6
+ case K_6:
case K_INET6:
af = AF_INET6;
break;
#endif
- case K_ATALK:
- af = AF_APPLETALK;
- break;
case K_LINK:
af = AF_LINK;
break;
@@ -494,12 +518,10 @@ routename(struct sockaddr *sa)
{
struct sockaddr_dl *sdl;
const char *cp;
- static char line[NI_MAXHOST];
- static char domain[MAXHOSTNAMELEN + 1];
- static int first = 1, n;
+ int n;
- if (first) {
- first = 0;
+ if (!domain_initialized) {
+ domain_initialized = true;
if (gethostname(domain, MAXHOSTNAMELEN) == 0 &&
(cp = strchr(domain, '.'))) {
domain[MAXHOSTNAMELEN] = '\0';
@@ -557,38 +579,33 @@ routename(struct sockaddr *sa)
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,
+ rt_line, sizeof(rt_line), NULL, 0,
(nflag == 0) ? 0 : NI_NUMERICHOST);
if (error) {
warnx("getnameinfo(): %s", gai_strerror(error));
- strncpy(line, "invalid", sizeof(line));
+ strncpy(rt_line, "invalid", sizeof(rt_line));
}
/* Remove the domain part if any. */
- p = strchr(line, '.');
+ p = strchr(rt_line, '.');
if (p != NULL && strcmp(p + 1, domain) == 0)
*p = '\0';
- return (line);
+ return (rt_line);
break;
}
#endif
- case AF_APPLETALK:
- (void)snprintf(line, sizeof(line), "atalk %s",
- atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr));
- break;
-
case AF_LINK:
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",
+ n = snprintf(rt_line, sizeof(rt_line), "link#%d",
sdl->sdl_index);
- if (n > (int)sizeof(line))
- line[0] = '\0';
- return (line);
+ if (n > (int)sizeof(rt_line))
+ rt_line[0] = '\0';
+ return (rt_line);
} else
return (link_ntoa(sdl));
break;
@@ -597,8 +614,8 @@ routename(struct sockaddr *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);
+ char *cps = rt_line + sprintf(rt_line, "(%d)", sa->sa_family);
+ char *cpe = rt_line + sizeof(rt_line);
while (++sp < splim && cps < cpe) /* start with sa->sa_data */
if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0)
@@ -608,7 +625,7 @@ routename(struct sockaddr *sa)
break;
}
}
- return (line);
+ return (rt_line);
}
/*
@@ -619,7 +636,6 @@ static const char *
netname(struct sockaddr *sa)
{
struct sockaddr_dl *sdl;
- static char line[MAXHOSTNAMELEN + 1];
int n;
#ifdef INET
struct netent *np = NULL;
@@ -644,17 +660,17 @@ netname(struct sockaddr *sa)
}
#define C(x) (unsigned)((x) & 0xff)
if (cp != NULL)
- strncpy(line, cp, sizeof(line));
+ strncpy(net_line, cp, sizeof(net_line));
else if ((in.s_addr & 0xffffff) == 0)
- (void)sprintf(line, "%u", C(in.s_addr >> 24));
+ (void)sprintf(net_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(net_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(net_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(net_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
@@ -674,29 +690,23 @@ netname(struct sockaddr *sa)
if (nflag)
niflags |= NI_NUMERICHOST;
if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
- line, sizeof(line), NULL, 0, niflags) != 0)
- strncpy(line, "invalid", sizeof(line));
+ net_line, sizeof(net_line), NULL, 0, niflags) != 0)
+ strncpy(net_line, "invalid", sizeof(net_line));
- return(line);
+ return(net_line);
}
#endif
-
- case AF_APPLETALK:
- (void)snprintf(line, sizeof(line), "atalk %s",
- atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr));
- break;
-
case AF_LINK:
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",
+ n = snprintf(net_line, sizeof(net_line), "link#%d",
sdl->sdl_index);
- if (n > (int)sizeof(line))
- line[0] = '\0';
- return (line);
+ if (n > (int)sizeof(net_line))
+ net_line[0] = '\0';
+ return (net_line);
} else
return (link_ntoa(sdl));
break;
@@ -705,8 +715,8 @@ netname(struct sockaddr *sa)
{
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);
+ char *cps = net_line + sprintf(net_line, "af %d:", sa->sa_family);
+ char *cpe = net_line + sizeof(net_line);
while (sp < splim && cps < cpe)
if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0)
@@ -716,13 +726,14 @@ netname(struct sockaddr *sa)
break;
}
}
- return (line);
+ return (net_line);
}
static void
set_metric(char *value, int key)
{
int flag = 0;
+ char *endptr;
u_long noval, *valp = &noval;
switch (key) {
@@ -742,7 +753,18 @@ set_metric(char *value, int key)
rt_metrics.rmx_locks |= flag;
if (locking)
locking = 0;
- *valp = atoi(value);
+ errno = 0;
+ *valp = strtol(value, &endptr, 0);
+ if (errno == 0 && *endptr != '\0')
+ errno = EINVAL;
+ if (errno)
+ err(EX_USAGE, "%s", value);
+ if (flag & RTV_EXPIRE && (value[0] == '+' || value[0] == '-')) {
+ struct timespec ts;
+
+ clock_gettime(CLOCK_REALTIME_FAST, &ts);
+ *valp += ts.tv_sec;
+ }
}
#define F_ISHOST 0x01
@@ -780,21 +802,19 @@ newroute(int argc, char **argv)
aflen = sizeof(struct sockaddr_dl);
break;
#ifdef INET
+ case K_4:
case K_INET:
af = AF_INET;
aflen = sizeof(struct sockaddr_in);
break;
#endif
#ifdef INET6
+ case K_6:
case K_INET6:
af = AF_INET6;
aflen = sizeof(struct sockaddr_in6);
break;
#endif
- case K_ATALK:
- af = AF_APPLETALK;
- aflen = sizeof(struct sockaddr_at);
- break;
case K_SA:
af = PF_ROUTE;
aflen = sizeof(struct sockaddr_storage);
@@ -827,6 +847,9 @@ newroute(int argc, char **argv)
case K_PROTO2:
flags |= RTF_PROTO2;
break;
+ case K_PROTO3:
+ flags |= RTF_PROTO3;
+ break;
case K_PROXY:
nrflags |= F_PROXY;
break;
@@ -928,11 +951,18 @@ newroute(int argc, char **argv)
}
}
+ /* Do some sanity checks on resulting request */
if (so[RTAX_DST].ss_len == 0) {
warnx("destination parameter required");
usage(NULL);
}
+ if (so[RTAX_NETMASK].ss_len != 0 &&
+ so[RTAX_DST].ss_family != so[RTAX_NETMASK].ss_family) {
+ warnx("destination and netmask family need to be the same");
+ usage(NULL);
+ }
+
if (nrflags & F_FORCEHOST) {
nrflags |= F_ISHOST;
#ifdef INET6
@@ -1215,7 +1245,7 @@ getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
*/
switch (idx) {
case RTAX_DST:
- forcenet++;
+ nrflags |= F_FORCENET;
getaddr(RTAX_NETMASK, str, 0, nrflags);
break;
}
@@ -1247,16 +1277,6 @@ getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
return (0);
}
#endif /* INET6 */
-
- case AF_APPLETALK:
- {
- 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 || sat->sat_addr.s_node != 0);
- }
case AF_LINK:
link_addr(str, (struct sockaddr_dl *)(void *)sa);
return (1);
@@ -1288,10 +1308,10 @@ getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
}
*q = '/';
}
- if ((idx != RTAX_DST || forcenet == 0) &&
+ if ((idx != RTAX_DST || (nrflags & F_FORCENET) == 0) &&
inet_aton(str, &sin->sin_addr)) {
val = sin->sin_addr.s_addr;
- if (idx != RTAX_DST || forcehost ||
+ if (idx != RTAX_DST || nrflags & F_FORCEHOST ||
inet_lnaof(sin->sin_addr) != INADDR_ANY)
return (1);
else {
@@ -1299,7 +1319,7 @@ getaddr(int idx, char *str, struct hostent **hpp, int nrflags)
goto netdone;
}
}
- if (idx == RTAX_DST && forcehost == 0 &&
+ if (idx == RTAX_DST && (nrflags & F_FORCEHOST) == 0 &&
((val = inet_network(str)) != INADDR_NONE ||
((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) {
netdone:
@@ -1458,15 +1478,9 @@ monitor(int argc, char *argv[])
}
}
-static struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
-} m_rtmsg;
-
static int
rtmsg(int cmd, int flags, int fib)
{
- static int seq;
int rlen;
char *cp = m_rtmsg.m_space;
int l;
@@ -1502,7 +1516,7 @@ rtmsg(int cmd, int flags, int fib)
rtm.rtm_type = cmd;
rtm.rtm_flags = flags;
rtm.rtm_version = RTM_VERSION;
- rtm.rtm_seq = ++seq;
+ rtm.rtm_seq = ++rtm_seq;
rtm.rtm_addrs = rtm_addrs;
rtm.rtm_rmx = rt_metrics;
rtm.rtm_inits = rtm_inits;
@@ -1527,7 +1541,7 @@ rtmsg(int cmd, int flags, int fib)
if (cmd == RTM_GET) {
do {
l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
- } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
+ } while (l > 0 && (rtm.rtm_seq != rtm_seq || rtm.rtm_pid != pid));
if (l < 0)
warn("read from routing socket");
else
@@ -1537,7 +1551,7 @@ rtmsg(int cmd, int flags, int fib)
return (0);
}
-static const char *msgtypes[] = {
+static const char *const msgtypes[] = {
"",
"RTM_ADD: Add Route",
"RTM_DELETE: Delete Route",
@@ -1681,6 +1695,7 @@ static void
print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
{
struct sockaddr *sp[RTAX_MAX];
+ struct timespec ts;
char *cp;
int i;
@@ -1733,15 +1748,18 @@ print_getmsg(struct rt_msghdr *rtm, int msglen, int fib)
#define msec(u) (((u) + 500) / 1000) /* usec to msec */
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));
- printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
- printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
- printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT));
- if (rtm->rtm_rmx.rmx_expire)
- rtm->rtm_rmx.rmx_expire -= time(0);
- printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH));
+ printf("%8lu%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU));
+ printf("%8lu%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT));
+ if (rtm->rtm_rmx.rmx_expire > 0)
+ clock_gettime(CLOCK_REALTIME_FAST, &ts);
+ else
+ ts.tv_sec = 0;
+ printf("%8ld%c\n", (long)(rtm->rtm_rmx.rmx_expire - ts.tv_sec),
+ lock(EXPIRE));
#undef lock
#undef msec
#define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD)
@@ -1827,7 +1845,7 @@ printb(int b, const char *str)
int
keyword(const char *cp)
{
- struct keytab *kt = keywords;
+ const struct keytab *kt = keywords;
while (kt->kt_cp != NULL && strcmp(kt->kt_cp, cp) != 0)
kt++;
@@ -1859,10 +1877,6 @@ sodump(struct sockaddr *sa, const char *which)
sizeof(nbuf)));
break;
#endif
- case AF_APPLETALK:
- (void)printf("%s: atalk %s; ", which,
- atalk_ntoa(((struct sockaddr_at *)(void *)sa)->sat_addr));
- break;
}
(void)fflush(stdout);
}
@@ -1916,26 +1930,3 @@ sockaddr(char *addr, struct sockaddr *sa, size_t size)
} while (cp < cplim);
sa->sa_len = cp - (char *)sa;
}
-
-static int
-atalk_aton(const char *text, struct at_addr *addr)
-{
- u_int net, node;
-
- if (sscanf(text, "%u.%u", &net, &node) != 2
- || net > 0xffff || node > 0xff)
- return(0);
- addr->s_net = htons(net);
- addr->s_node = node;
- return(1);
-}
-
-static char *
-atalk_ntoa(struct at_addr at)
-{
- static char buf[20];
-
- (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/rtsol/Makefile b/sbin/rtsol/Makefile
index 39ef258..d738008 100644
--- a/sbin/rtsol/Makefile
+++ b/sbin/rtsol/Makefile
@@ -20,7 +20,7 @@ SRCDIR= ${.CURDIR}/../../usr.sbin/rtsold
PROG= rtsol
SRCS= rtsold.c rtsol.c if.c probe.c dump.c rtsock.c
-NO_MAN=
+MAN=
WARNS?= 3
CFLAGS+= -DHAVE_ARC4RANDOM -DHAVE_POLL_H -DSMALL
diff --git a/sbin/savecore/savecore.c b/sbin/savecore/savecore.c
index bdbf7e3..0f1d41e 100644
--- a/sbin/savecore/savecore.c
+++ b/sbin/savecore/savecore.c
@@ -618,7 +618,7 @@ DoFile(const char *savedir, const char *device)
*/
fdinfo = open(infoname, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (fdinfo < 0) {
- syslog(LOG_ERR, "%s: %m", buf);
+ syslog(LOG_ERR, "%s: %m", infoname);
nerr++;
goto closefd;
}
@@ -672,7 +672,7 @@ DoFile(const char *savedir, const char *device)
if (fclose(fp) < 0) {
syslog(LOG_ERR, "error on %s: %m", corename);
nerr++;
- goto closeall;
+ goto closefd;
}
symlinks_remove();
diff --git a/sbin/swapon/swapon.8 b/sbin/swapon/swapon.8
index ec2ad72..c4286d7 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 21, 2013
+.Dd November 22, 2013
.Dt SWAPON 8
.Os
.Sh NAME
@@ -60,9 +60,7 @@ At boot time all swap entries in
.Pa /etc/fstab
are added automatically when the system goes multi-user.
Swap devices use a fixed interleave; the maximum number of devices
-is specified by the kernel configuration option
-.Dv NSWAPDEV ,
-which is typically set to 4.
+is unlimited.
There is no priority mechanism.
.Pp
The
@@ -193,8 +191,8 @@ overridden.
512 byte blocks are used by default.
.El
.Sh FILES
-.Bl -tag -width ".Pa /dev/{ad,da}?s?b" -compact
-.It Pa /dev/{ad,da}?s?b
+.Bl -tag -width ".Pa /dev/{ada,da}?s?b" -compact
+.It Pa /dev/{ada,da}?s?b
standard paging devices
.It Pa /dev/md?
memory disk devices
diff --git a/sbin/swapon/swapon.c b/sbin/swapon/swapon.c
index bf621c1..5c6086d 100644
--- a/sbin/swapon/swapon.c
+++ b/sbin/swapon/swapon.c
@@ -266,7 +266,8 @@ static const char *
swap_on_off_gbde(const char *name, int doingall)
{
const char *ret;
- char pass[64 * 2 + 1], bpass[64];
+ char pass[64 * 2 + 1];
+ unsigned char bpass[64];
char *dname;
int i, error;
diff --git a/sbin/sysctl/sysctl.8 b/sbin/sysctl/sysctl.8
index fe0a75a..b81de6e 100644
--- a/sbin/sysctl/sysctl.8
+++ b/sbin/sysctl/sysctl.8
@@ -130,7 +130,7 @@ to standard error.
.It Fl T
Display only variables that are setable via loader (CTLFLAG_TUN).
.It Fl W
-Display only wriable variables that are not statistical.
+Display only writable variables that are not statistical.
Useful for determining the set of runtime tunable sysctls.
.It Fl X
Equivalent to
diff --git a/sbin/sysctl/sysctl.c b/sbin/sysctl/sysctl.c
index 43592b3..a86d659 100644
--- a/sbin/sysctl/sysctl.c
+++ b/sbin/sysctl/sysctl.c
@@ -201,7 +201,7 @@ parse(const char *string, int lineno)
cp = buf;
if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) {
- warn("oid too long: '%s'%s", string, line);
+ warnx("oid too long: '%s'%s", string, line);
return (1);
}
bufp = strsep(&cp, "=:");
@@ -260,7 +260,7 @@ parse(const char *string, int lineno)
}
} else {
if ((kind & CTLTYPE) == CTLTYPE_NODE) {
- warn("oid '%s' isn't a leaf node%s", bufp, line);
+ warnx("oid '%s' isn't a leaf node%s", bufp, line);
return (1);
}
diff --git a/sbin/tests/Makefile b/sbin/tests/Makefile
new file mode 100644
index 0000000..a298f87
--- /dev/null
+++ b/sbin/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/sbin
+
+.PATH: ${.CURDIR:H:H}/tests
+KYUAFILE= yes
+
+.include <bsd.test.mk>
OpenPOWER on IntegriCloud