summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
authorsjg <sjg@FreeBSD.org>2014-11-19 01:07:58 +0000
committersjg <sjg@FreeBSD.org>2014-11-19 01:07:58 +0000
commitb137080f19736ee33fede2e88bb54438604cf86b (patch)
tree377ac0ac449528621eb192cd245adadb5fd53668 /usr.sbin
parentab21a29eb607d4dfe389b965fbdee27558e791aa (diff)
parent4a8d07956d121238d006d34ffe7d6269744e8b1a (diff)
downloadFreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.zip
FreeBSD-src-b137080f19736ee33fede2e88bb54438604cf86b.tar.gz
Merge from head@274682
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile7
-rw-r--r--usr.sbin/Makefile.amd643
-rw-r--r--usr.sbin/Makefile.i3863
-rw-r--r--usr.sbin/acpi/acpiconf/Makefile1
-rw-r--r--usr.sbin/acpi/acpidb/Makefile22
-rw-r--r--usr.sbin/acpi/acpidb/acpidb.c17
-rw-r--r--usr.sbin/acpi/acpidump/Makefile1
-rw-r--r--usr.sbin/acpi/acpidump/acpi.c4
-rw-r--r--usr.sbin/acpi/iasl/Makefile65
-rw-r--r--usr.sbin/amd/amd/Makefile2
-rw-r--r--usr.sbin/amd/amq/Makefile2
-rw-r--r--usr.sbin/amd/fixmount/Makefile2
-rw-r--r--usr.sbin/amd/fsinfo/Makefile2
-rw-r--r--usr.sbin/amd/hlfsd/Makefile2
-rw-r--r--usr.sbin/amd/mk-amd-map/Makefile2
-rw-r--r--usr.sbin/amd/pawd/Makefile2
-rw-r--r--usr.sbin/amd/wire-test/Makefile2
-rw-r--r--usr.sbin/auditdistd/Makefile4
-rw-r--r--usr.sbin/autofs/Makefile33
-rw-r--r--usr.sbin/autofs/auto_master.5276
-rw-r--r--usr.sbin/autofs/automount.8107
-rw-r--r--usr.sbin/autofs/automount.c347
-rw-r--r--usr.sbin/autofs/automountd.8103
-rw-r--r--usr.sbin/autofs/automountd.c575
-rw-r--r--usr.sbin/autofs/autounmountd.888
-rw-r--r--usr.sbin/autofs/autounmountd.c341
-rw-r--r--usr.sbin/autofs/common.c1209
-rw-r--r--usr.sbin/autofs/common.h114
-rw-r--r--usr.sbin/autofs/defined.c272
-rw-r--r--usr.sbin/autofs/log.c198
-rw-r--r--usr.sbin/autofs/popen.c193
-rw-r--r--usr.sbin/autofs/token.l (renamed from usr.sbin/pkg/elf_tables.h)65
-rw-r--r--usr.sbin/bhyve/Makefile1
-rw-r--r--usr.sbin/bhyve/acpi.c57
-rw-r--r--usr.sbin/bhyve/bhyve.84
-rw-r--r--usr.sbin/bhyve/bhyverun.c21
-rw-r--r--usr.sbin/bhyve/block_if.c188
-rw-r--r--usr.sbin/bhyve/mem.c23
-rw-r--r--usr.sbin/bhyve/mem.h1
-rw-r--r--usr.sbin/bhyve/pci_ahci.c164
-rw-r--r--usr.sbin/bhyve/pci_emul.c218
-rw-r--r--usr.sbin/bhyve/pci_emul.h1
-rw-r--r--usr.sbin/bhyve/pci_irq.c15
-rw-r--r--usr.sbin/bhyve/pci_virtio_block.c7
-rw-r--r--usr.sbin/bhyve/pci_virtio_net.c85
-rw-r--r--usr.sbin/bhyve/pci_virtio_rnd.c1
-rw-r--r--usr.sbin/bhyve/pmtmr.c173
-rw-r--r--usr.sbin/bhyve/rtc.c4
-rw-r--r--usr.sbin/bhyve/smbiostbl.c2
-rw-r--r--usr.sbin/bhyve/task_switch.c18
-rw-r--r--usr.sbin/bhyve/virtio.c11
-rw-r--r--usr.sbin/bhyve/virtio.h2
-rw-r--r--usr.sbin/bhyve/xmsr.c180
-rw-r--r--usr.sbin/bhyve/xmsr.h1
-rw-r--r--usr.sbin/bhyvectl/bhyvectl.c1854
-rw-r--r--usr.sbin/binmiscctl/binmiscctl.88
-rw-r--r--usr.sbin/bsdconfig/Makefile5
-rw-r--r--usr.sbin/bsdconfig/bsdconfig.811
-rw-r--r--usr.sbin/bsdconfig/console/Makefile3
-rw-r--r--usr.sbin/bsdconfig/console/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/Makefile3
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/docsinstall/Makefile3
-rw-r--r--usr.sbin/bsdconfig/docsinstall/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/dot/Makefile3
-rw-r--r--usr.sbin/bsdconfig/dot/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/examples/Makefile3
-rw-r--r--usr.sbin/bsdconfig/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/includes/Makefile3
-rw-r--r--usr.sbin/bsdconfig/includes/include/Makefile3
-rwxr-xr-xusr.sbin/bsdconfig/includes/includes8
-rw-r--r--usr.sbin/bsdconfig/mouse/Makefile3
-rw-r--r--usr.sbin/bsdconfig/mouse/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/networking/Makefile3
-rw-r--r--usr.sbin/bsdconfig/networking/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/networking/share/Makefile3
-rw-r--r--usr.sbin/bsdconfig/networking/share/device.subr2
-rw-r--r--usr.sbin/bsdconfig/packages/Makefile3
-rw-r--r--usr.sbin/bsdconfig/packages/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/password/Makefile3
-rw-r--r--usr.sbin/bsdconfig/password/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/password/share/Makefile3
-rw-r--r--usr.sbin/bsdconfig/security/Makefile3
-rw-r--r--usr.sbin/bsdconfig/security/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/share/Makefile3
-rw-r--r--usr.sbin/bsdconfig/share/common.subr36
-rw-r--r--usr.sbin/bsdconfig/share/device.subr5
-rw-r--r--usr.sbin/bsdconfig/share/dialog.subr26
-rw-r--r--usr.sbin/bsdconfig/share/media/Makefile3
-rw-r--r--usr.sbin/bsdconfig/share/packages/Makefile3
-rw-r--r--usr.sbin/bsdconfig/share/packages/index.subr8
-rw-r--r--usr.sbin/bsdconfig/share/packages/packages.subr6
-rw-r--r--usr.sbin/bsdconfig/startup/Makefile3
-rw-r--r--usr.sbin/bsdconfig/startup/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/startup/share/Makefile3
-rw-r--r--usr.sbin/bsdconfig/timezone/Makefile3
-rw-r--r--usr.sbin/bsdconfig/timezone/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/timezone/share/Makefile3
-rwxr-xr-xusr.sbin/bsdconfig/timezone/timezone5
-rw-r--r--usr.sbin/bsdconfig/ttys/Makefile3
-rw-r--r--usr.sbin/bsdconfig/ttys/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/usermgmt/Makefile3
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/Makefile3
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/Makefile3
-rw-r--r--usr.sbin/bsdinstall/bsdinstall.868
-rw-r--r--usr.sbin/bsdinstall/distextract/distextract.c301
-rw-r--r--usr.sbin/bsdinstall/distfetch/distfetch.c72
-rw-r--r--usr.sbin/bsdinstall/partedit/gpart_ops.c129
-rw-r--r--usr.sbin/bsdinstall/partedit/part_wizard.c37
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit.c9
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit.h8
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_generic.c7
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_pc98.c11
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_powerpc.c11
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_sparc64.c22
-rw-r--r--usr.sbin/bsdinstall/partedit/partedit_x86.c78
-rw-r--r--usr.sbin/bsdinstall/partedit/sade.84
-rw-r--r--usr.sbin/bsdinstall/partedit/scripted.c2
-rwxr-xr-xusr.sbin/bsdinstall/scripts/auto51
-rwxr-xr-xusr.sbin/bsdinstall/scripts/config1
-rwxr-xr-xusr.sbin/bsdinstall/scripts/jail24
-rwxr-xr-xusr.sbin/bsdinstall/scripts/services1
-rwxr-xr-xusr.sbin/bsdinstall/scripts/zfsboot62
-rw-r--r--usr.sbin/btxld/Makefile2
-rw-r--r--usr.sbin/config/config.82
-rw-r--r--usr.sbin/cron/cron/Makefile2
-rw-r--r--usr.sbin/cron/cron/do_command.c7
-rw-r--r--usr.sbin/cron/crontab/Makefile2
-rw-r--r--usr.sbin/crunch/crunchgen/Makefile2
-rw-r--r--usr.sbin/crunch/crunchide/Makefile2
-rw-r--r--usr.sbin/ctladm/Makefile4
-rw-r--r--usr.sbin/ctladm/ctladm.856
-rw-r--r--usr.sbin/ctladm/ctladm.c170
-rw-r--r--usr.sbin/ctld/Makefile7
-rw-r--r--usr.sbin/ctld/chap.c435
-rw-r--r--usr.sbin/ctld/ctl.conf.5407
-rw-r--r--usr.sbin/ctld/ctld.87
-rw-r--r--usr.sbin/ctld/ctld.c600
-rw-r--r--usr.sbin/ctld/ctld.h70
-rw-r--r--usr.sbin/ctld/discovery.c93
-rw-r--r--usr.sbin/ctld/isns.c258
-rw-r--r--usr.sbin/ctld/isns.h92
-rw-r--r--usr.sbin/ctld/kernel.c62
-rw-r--r--usr.sbin/ctld/keys.c6
-rw-r--r--usr.sbin/ctld/log.c4
-rw-r--r--usr.sbin/ctld/login.c390
-rw-r--r--usr.sbin/ctld/parse.y193
-rw-r--r--usr.sbin/ctld/pdu.c4
-rw-r--r--usr.sbin/ctld/token.l13
-rw-r--r--usr.sbin/editmap/Makefile2
-rw-r--r--usr.sbin/etcupdate/etcupdate.864
-rw-r--r--usr.sbin/fdread/fdutil.c26
-rw-r--r--usr.sbin/fifolog/fifolog_create/Makefile2
-rw-r--r--usr.sbin/fifolog/fifolog_reader/Makefile6
-rw-r--r--usr.sbin/fifolog/fifolog_writer/Makefile6
-rw-r--r--usr.sbin/freebsd-update/freebsd-update.sh8
-rw-r--r--usr.sbin/ftp-proxy/Makefile16
-rw-r--r--usr.sbin/ftp-proxy/Makefile.inc5
-rw-r--r--usr.sbin/gstat/Makefile4
-rw-r--r--usr.sbin/hyperv/Makefile7
-rw-r--r--usr.sbin/hyperv/Makefile.inc3
-rw-r--r--usr.sbin/hyperv/tools/Makefile13
-rw-r--r--usr.sbin/i2c/i2c.c10
-rw-r--r--usr.sbin/inetd/inetd.c20
-rw-r--r--usr.sbin/iscsid/Makefile6
-rw-r--r--usr.sbin/iscsid/chap.c435
-rw-r--r--usr.sbin/iscsid/discovery.c4
-rw-r--r--usr.sbin/iscsid/iscsid.812
-rw-r--r--usr.sbin/iscsid/iscsid.c4
-rw-r--r--usr.sbin/iscsid/iscsid.h33
-rw-r--r--usr.sbin/iscsid/keys.c6
-rw-r--r--usr.sbin/iscsid/log.c4
-rw-r--r--usr.sbin/iscsid/login.c272
-rw-r--r--usr.sbin/iscsid/pdu.c4
-rw-r--r--usr.sbin/jail/command.c68
-rw-r--r--usr.sbin/jail/config.c12
-rw-r--r--usr.sbin/jail/jail.817
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.121
-rw-r--r--usr.sbin/kbdcontrol/kbdcontrol.c2
-rw-r--r--usr.sbin/kbdcontrol/kbdmap.55
-rw-r--r--usr.sbin/kbdmap/kbdmap.16
-rw-r--r--usr.sbin/kbdmap/kbdmap.c29
-rw-r--r--usr.sbin/kbdmap/kbdmap.h11
-rw-r--r--usr.sbin/lpr/chkprintcap/Makefile2
-rw-r--r--usr.sbin/lpr/lpc/Makefile2
-rw-r--r--usr.sbin/lpr/lpd/Makefile2
-rw-r--r--usr.sbin/lpr/lpd/printjob.c2
-rw-r--r--usr.sbin/lpr/lpq/Makefile2
-rw-r--r--usr.sbin/lpr/lpr/Makefile2
-rw-r--r--usr.sbin/lpr/lprm/Makefile2
-rw-r--r--usr.sbin/lpr/pac/Makefile2
-rw-r--r--usr.sbin/mailstats/Makefile2
-rw-r--r--usr.sbin/mailwrapper/mailwrapper.86
-rw-r--r--usr.sbin/mailwrapper/mailwrapper.c19
-rw-r--r--usr.sbin/makefs/Makefile2
-rw-r--r--usr.sbin/makefs/ffs.c3
-rw-r--r--usr.sbin/makemap/Makefile2
-rw-r--r--usr.sbin/mfiutil/mfi_properties.c100
-rw-r--r--usr.sbin/mountd/exports.511
-rw-r--r--usr.sbin/mountd/mountd.c2
-rw-r--r--usr.sbin/mtree/Makefile2
-rw-r--r--usr.sbin/newsyslog/newsyslog.83
-rw-r--r--usr.sbin/newsyslog/newsyslog.c4
-rw-r--r--usr.sbin/nfsd/nfsd.820
-rw-r--r--usr.sbin/nmtree/Makefile7
-rw-r--r--usr.sbin/nmtree/tests/Makefile32
-rw-r--r--usr.sbin/nscd/query.c4
-rw-r--r--usr.sbin/ntp/ntp-keygen/Makefile2
-rw-r--r--usr.sbin/ntp/ntpd/Makefile2
-rw-r--r--usr.sbin/ntp/ntpdate/Makefile2
-rw-r--r--usr.sbin/ntp/ntpdc/Makefile2
-rw-r--r--usr.sbin/ntp/ntpq/Makefile2
-rw-r--r--usr.sbin/ntp/ntptime/Makefile2
-rw-r--r--usr.sbin/pciconf/pciconf.c6
-rw-r--r--usr.sbin/pkg/Makefile4
-rw-r--r--usr.sbin/pkg/config.c361
-rw-r--r--usr.sbin/pmcstat/pmcstat.810
-rw-r--r--usr.sbin/ppp/Makefile4
-rw-r--r--usr.sbin/praliases/Makefile2
-rw-r--r--usr.sbin/pstat/pstat.84
-rw-r--r--usr.sbin/pw/Makefile6
-rw-r--r--usr.sbin/pw/pw.c8
-rw-r--r--usr.sbin/pw/pw_group.c14
-rw-r--r--usr.sbin/pw/pw_user.c27
-rw-r--r--usr.sbin/pw/tests/Makefile24
-rw-r--r--usr.sbin/pw/tests/group3
-rwxr-xr-xusr.sbin/pw/tests/helper_functions.shin15
-rw-r--r--usr.sbin/pw/tests/master.passwd4
-rwxr-xr-xusr.sbin/pw/tests/pw_delete.sh47
-rwxr-xr-xusr.sbin/pw/tests/pw_etcdir.sh18
-rwxr-xr-xusr.sbin/pw/tests/pw_lock.sh22
-rwxr-xr-xusr.sbin/pw/tests/pw_modify.sh80
-rw-r--r--usr.sbin/route6d/route6d.c2
-rw-r--r--usr.sbin/rpcbind/Makefile4
-rw-r--r--usr.sbin/rtadvd/advcap.c4
-rw-r--r--usr.sbin/rtadvd/config.c19
-rw-r--r--usr.sbin/rtsold/rtsol.c3
-rw-r--r--usr.sbin/sendmail/Makefile2
-rw-r--r--usr.sbin/smbmsg/smbmsg.82
-rw-r--r--usr.sbin/sysrc/sysrc26
-rw-r--r--usr.sbin/sysrc/sysrc.814
-rw-r--r--usr.sbin/timed/timedc/timedc.c2
-rw-r--r--usr.sbin/traceroute/Makefile2
-rw-r--r--usr.sbin/tzsetup/tzsetup.c9
-rw-r--r--usr.sbin/unbound/anchor/Makefile2
-rw-r--r--usr.sbin/unbound/checkconf/Makefile2
-rw-r--r--usr.sbin/unbound/control/Makefile2
-rw-r--r--usr.sbin/unbound/daemon/Makefile2
-rwxr-xr-xusr.sbin/unbound/local-setup/local-unbound-setup.sh2
-rw-r--r--usr.sbin/usbconfig/dump.c83
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.149
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.c39
-rw-r--r--usr.sbin/watchdogd/watchdog.84
-rw-r--r--usr.sbin/watchdogd/watchdogd.86
-rw-r--r--usr.sbin/watchdogd/watchdogd.c2
-rw-r--r--usr.sbin/wlandebug/wlandebug.c2
-rw-r--r--usr.sbin/wpa/wpa_cli/Makefile6
257 files changed, 10404 insertions, 3052 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index fa0c995..df9f867 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -5,6 +5,7 @@
SUBDIR= adduser \
arp \
+ autofs \
binmiscctl \
bootparamd \
bsdconfig \
@@ -25,7 +26,6 @@ SUBDIR= adduser \
digictl \
diskinfo \
dumpcis \
- etcupdate \
extattr \
extattrctl \
fifolog \
@@ -160,7 +160,6 @@ SUBDIR+= gpioctl
.endif
.if ${MK_INET6} != "no"
-SUBDIR+= faithd
SUBDIR+= ip6addrctl
SUBDIR+= mld6query
SUBDIR+= ndp
@@ -277,6 +276,10 @@ SUBDIR+= repquota
SUBDIR+= rwhod
.endif
+.if ${MK_RCS} != "no"
+SUBDIR+= etcupdate
+.endif
+
.if ${MK_SENDMAIL} != "no"
SUBDIR+= editmap
SUBDIR+= mailstats
diff --git a/usr.sbin/Makefile.amd64 b/usr.sbin/Makefile.amd64
index b821625..2d1a3e8 100644
--- a/usr.sbin/Makefile.amd64
+++ b/usr.sbin/Makefile.amd64
@@ -18,6 +18,9 @@ SUBDIR+= boot0cfg
SUBDIR+= btxld
.endif
SUBDIR+= cpucontrol
+.if ${MK_HYPERV} != "no"
+SUBDIR+= hyperv
+.endif
SUBDIR+= kgmon
SUBDIR+= lptcontrol
SUBDIR+= mount_smbfs
diff --git a/usr.sbin/Makefile.i386 b/usr.sbin/Makefile.i386
index 7d66f78..772c11d 100644
--- a/usr.sbin/Makefile.i386
+++ b/usr.sbin/Makefile.i386
@@ -28,6 +28,9 @@ SUBDIR+= zzz
SUBDIR+= acpi
.endif
SUBDIR+= boot0cfg
+.if ${MK_HYPERV} != "no"
+SUBDIR+= hyperv
+.endif
.if ${MK_WIRELESS} != "no"
SUBDIR+= wlconfig
.endif
diff --git a/usr.sbin/acpi/acpiconf/Makefile b/usr.sbin/acpi/acpiconf/Makefile
index 5f862a2..0bbadc1 100644
--- a/usr.sbin/acpi/acpiconf/Makefile
+++ b/usr.sbin/acpi/acpiconf/Makefile
@@ -3,5 +3,6 @@
PROG= acpiconf
MAN= acpiconf.8
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/usr.sbin/acpi/acpidb/Makefile b/usr.sbin/acpi/acpidb/Makefile
index c08c70b..15d114d 100644
--- a/usr.sbin/acpi/acpidb/Makefile
+++ b/usr.sbin/acpi/acpidb/Makefile
@@ -3,10 +3,13 @@
PROG= acpidb
SRCS= acpidb.c
+# common
+SRCS+= acgetline.c ahids.c ahuuids.c cmfsize.c
+
# components/debugger
SRCS+= dbcmds.c dbconvert.c dbdisply.c dbexec.c dbfileio.c \
dbhistry.c dbinput.c dbmethod.c dbnames.c dbstats.c \
- dbutils.c dbxface.c
+ dbtest.c dbutils.c dbxface.c
# components/disassembler
SRCS+= dmbuffer.c dmdeferred.c dmnames.c dmobject.c dmopcode.c \
@@ -46,26 +49,27 @@ SRCS+= psargs.c psloop.c psobject.c psopcode.c psopinfo.c \
psparse.c psscope.c pstree.c psutils.c pswalk.c \
psxface.c
-# components/os_specific/service_layers
-SRCS+= osunixxf.c
-
# components/resources
SRCS+= rsaddr.c rscalc.c rscreate.c rsdump.c rsdumpinfo.c \
rsinfo.c rsio.c rsirq.c rslist.c rsmemory.c rsmisc.c \
rsserial.c rsutils.c rsxface.c
# components/tables
-SRCS+= tbfadt.c tbfind.c tbinstal.c tbprint.c tbutils.c \
- tbxface.c tbxfload.c
+SRCS+= tbdata.c tbfadt.c tbfind.c tbinstal.c tbprint.c \
+ tbutils.c tbxface.c tbxfload.c
# components/utilities
SRCS+= utaddress.c utalloc.c utbuffer.c utcache.c utcopy.c \
utdebug.c utdecode.c utdelete.c uterror.c uteval.c \
- utexcep.c utglobal.c utids.c utinit.c utlock.c utmath.c \
- utmisc.c utmutex.c utobject.c utosi.c utownerid.c \
- utpredef.c utresrc.c utstate.c utstring.c uttrack.c \
+ utexcep.c utfileio.c utglobal.c uthex.c utids.c \
+ utinit.c utlock.c utmath.c utmisc.c utmutex.c \
+ utobject.c utosi.c utownerid.c utpredef.c utprint.c \
+ utresrc.c utstate.c utstring.c uttrack.c utuuid.c \
utxface.c utxferror.c utxfinit.c
+# os_specific/service_layers
+SRCS+= oslibcfs.c osunixxf.c
+
MAN= acpidb.8
WARNS?= 3
diff --git a/usr.sbin/acpi/acpidb/acpidb.c b/usr.sbin/acpi/acpidb/acpidb.c
index 3cd8d3f..3688caf 100644
--- a/usr.sbin/acpi/acpidb/acpidb.c
+++ b/usr.sbin/acpi/acpidb/acpidb.c
@@ -45,6 +45,7 @@
#include <contrib/dev/acpica/include/acpi.h>
#include <contrib/dev/acpica/include/accommon.h>
#include <contrib/dev/acpica/include/acdebug.h>
+#include <contrib/dev/acpica/include/amlresrc.h>
/*
* Dummy DSDT Table Header
@@ -89,9 +90,9 @@ static UINT64 aml_simulate_prompt(char *msg, UINT64 def_val);
static void aml_simulation_regload(const char *dumpfile);
static void aml_simulation_regdump(const char *dumpfile);
-/* Stubs to simplify linkage to the ACPI CA core subsystem. */
+/* Stubs to simplify linkage to the ACPICA core subsystem. */
ACPI_PHYSICAL_ADDRESS
-AeLocalGetRootPointer(void)
+AcpiOsGetRootPointer(void)
{
return (0);
@@ -102,6 +103,18 @@ AeTableOverride(ACPI_TABLE_HEADER *ExistingTable, ACPI_TABLE_HEADER **NewTable)
{
}
+void
+MpSaveGpioInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource,
+ UINT32 PinCount, UINT16 *PinList, char *DeviceName)
+{
+}
+
+void
+MpSaveSerialInfo(ACPI_PARSE_OBJECT *Op, AML_RESOURCE *Resource,
+ char *DeviceName)
+{
+}
+
static void
aml_simulation_init(void)
{
diff --git a/usr.sbin/acpi/acpidump/Makefile b/usr.sbin/acpi/acpidump/Makefile
index e004500..e258f8e 100644
--- a/usr.sbin/acpi/acpidump/Makefile
+++ b/usr.sbin/acpi/acpidump/Makefile
@@ -3,5 +3,6 @@
PROG= acpidump
MAN= acpidump.8
SRCS= acpi.c acpi_user.c acpidump.c
+WARNS?= 3
.include <bsd.prog.mk>
diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c
index 66cd7bd..ae7ebf2 100644
--- a/usr.sbin/acpi/acpidump/acpi.c
+++ b/usr.sbin/acpi/acpidump/acpi.c
@@ -934,10 +934,10 @@ acpi_handle_dmar_remapping_structure(void *addr, int remaining)
case ACPI_DMAR_TYPE_RESERVED_MEMORY:
acpi_handle_dmar_rmrr(addr);
break;
- case ACPI_DMAR_TYPE_ATSR:
+ case ACPI_DMAR_TYPE_ROOT_ATS:
acpi_handle_dmar_atsr(addr);
break;
- case ACPI_DMAR_HARDWARE_AFFINITY:
+ case ACPI_DMAR_TYPE_HARDWARE_AFFINITY:
acpi_handle_dmar_rhsa(addr);
break;
default:
diff --git a/usr.sbin/acpi/iasl/Makefile b/usr.sbin/acpi/iasl/Makefile
index 161b2f4..8f021a3 100644
--- a/usr.sbin/acpi/iasl/Makefile
+++ b/usr.sbin/acpi/iasl/Makefile
@@ -1,29 +1,31 @@
# $FreeBSD$
PROG= iasl
-SRCS= adfile.c adisasm.c adwalk.c
# common
-SRCS+= ahpredef.c dmextern.c dmrestag.c dmtable.c dmtbdump.c \
- dmtbinfo.c getopt.c
+SRCS= adfile.c adisasm.c adwalk.c ahids.c ahpredef.c \
+ ahuuids.c cmfsize.c dmextern.c dmrestag.c dmtable.c \
+ dmtbdump.c dmtbinfo.c getopt.c
# compiler
-SRCS+= aslanalyze.c aslbtypes.c aslcodegen.c aslcompile.c \
- aslcompiler.y.h aslcompilerlex.c aslcompilerparse.c \
- aslerror.c aslfileio.c aslfiles.c aslfold.c aslhex.c \
- asllength.c asllisting.c asllistsup.c aslload.c \
- asllookup.c aslmain.c aslmap.c aslmethod.c aslnamesp.c \
- asloffset.c aslopcodes.c asloperands.c aslopt.c \
- asloptions.c aslpredef.c aslprepkg.c aslresource.c \
- aslrestype1.c aslrestype1i.c aslrestype2.c \
- aslrestype2d.c aslrestype2e.c aslrestype2q.c \
- aslrestype2s.c aslrestype2w.c aslstartup.c aslstubs.c \
- asltransform.c asltree.c aslutils.c asluuid.c \
- aslwalks.c aslxref.c dtcompile.c dtexpress.c dtfield.c \
- dtio.c dtparser.y.h dtparserlex.c dtparserparse.c \
- dtsubtable.c dttable.c dttemplate.c dtutils.c \
- prexpress.c prmacros.c prparser.y.h prparserlex.c \
- prparserparse.c prscan.c prutils.c
+SRCS+= aslanalyze.c aslascii.c aslbtypes.c aslcodegen.c \
+ aslcompile.c aslcompiler.y.h aslcompilerlex.c \
+ aslcompilerparse.c aslerror.c aslfileio.c aslfiles.c \
+ aslfold.c aslhex.c asllength.c asllisting.c \
+ asllistsup.c aslload.c asllookup.c aslmain.c aslmap.c \
+ aslmapenter.c aslmapoutput.c aslmaputils.c \
+ aslmessages.c aslmethod.c aslnamesp.c asloffset.c \
+ aslopcodes.c asloperands.c aslopt.c asloptions.c \
+ aslpredef.c aslprepkg.c aslresource.c aslrestype1.c \
+ aslrestype1i.c aslrestype2.c aslrestype2d.c \
+ aslrestype2e.c aslrestype2q.c aslrestype2s.c \
+ aslrestype2w.c aslstartup.c aslstubs.c asltransform.c \
+ asltree.c aslutils.c asluuid.c aslwalks.c aslxref.c \
+ dtcompile.c dtexpress.c dtfield.c dtio.c dtparser.y.h \
+ dtparserlex.c dtparserparse.c dtsubtable.c dttable.c \
+ dttemplate.c dtutils.c prexpress.c prmacros.c \
+ prparser.y.h prparserlex.c prparserparse.c prscan.c \
+ prutils.c
# components/debugger
SRCS+= dbfileio.c
@@ -52,17 +54,19 @@ SRCS+= nsaccess.c nsalloc.c nsdump.c nsnames.c nsobject.c \
nsparse.c nssearch.c nsutils.c nswalk.c
# components/tables
-SRCS+= tbfadt.c tbinstal.c tbprint.c tbutils.c tbxface.c
+SRCS+= tbdata.c tbfadt.c tbinstal.c tbprint.c tbutils.c \
+ tbxface.c
# components/utilities
SRCS+= utaddress.c utalloc.c utbuffer.c utcache.c utcopy.c \
utdebug.c utdecode.c utdelete.c uterror.c utexcep.c \
- utglobal.c utinit.c utlock.c utmath.c utmisc.c \
- utmutex.c utobject.c utownerid.c utpredef.c utresrc.c \
- utstate.c utstring.c utxface.c utxferror.c
+ utfileio.c utglobal.c uthex.c utinit.c utlock.c \
+ utmath.c utmisc.c utmutex.c utobject.c utownerid.c \
+ utpredef.c utprint.c utresrc.c utstate.c utstring.c \
+ utuuid.c utxface.c utxferror.c
# os_specific/service_layers
-SRCS+= osunixxf.c
+SRCS+= oslibcfs.c osunixxf.c
WARNS?= 2
@@ -72,15 +76,20 @@ CFLAGS+= -DACPI_ASL_COMPILER -I.
LFLAGS= -i -s
YFLAGS= -d
-CLEANFILES= aslcompiler.y.h aslcompilerlex.c aslcompilerparse.c \
- aslcompilerparse.h dtparser.y.h dtparserlex.c \
- dtparserparse.c dtparserparse.h prparser.y.h \
- prparserlex.c prparserparse.c prparserparse.h
+CLEANFILES= aslcompiler.y aslcompiler.y.h aslcompilerlex.c \
+ aslcompilerparse.c aslcompilerparse.h dtparser.y.h \
+ dtparserlex.c dtparserparse.c dtparserparse.h \
+ prparser.y.h prparserlex.c prparserparse.c \
+ prparserparse.h
aslcompilerlex.c: aslcompiler.l aslsupport.l
${LEX} ${LFLAGS} -PAslCompiler -o${.TARGET} \
${ACPICA_DIR}/compiler/aslcompiler.l
+aslcompiler.y: aslparser.y aslrules.y aslsupport.y asltokens.y asltypes.y
+ m4 -P -I${ACPICA_DIR}/compiler \
+ ${ACPICA_DIR}/compiler/aslparser.y > ${.TARGET}
+
.ORDER: aslcompilerparse.c aslcompilerparse.h
aslcompilerparse.c aslcompilerparse.h: aslcompiler.y
${YACC} ${YFLAGS} -pAslCompiler -oaslcompilerparse.c ${.ALLSRC}
diff --git a/usr.sbin/amd/amd/Makefile b/usr.sbin/amd/amd/Makefile
index fdcbd60..1fc41bf 100644
--- a/usr.sbin/amd/amd/Makefile
+++ b/usr.sbin/amd/amd/Makefile
@@ -24,8 +24,6 @@ SRCS+= ops_nullfs.c ops_pcfs.c ops_tfs.c ops_ufs.c ops_umapfs.c
SRCS+= ops_unionfs.c opts.c readdir.c restart.c rpc_fwd.c sched.c
SRCS+= srvr_amfs_auto.c srvr_nfs.c
-NO_PIE= yes
-
CFLAGS+= -I${.CURDIR}/../../../contrib/amd/amd \
-I${DESTDIR}/usr/include/rpcsvc
diff --git a/usr.sbin/amd/amq/Makefile b/usr.sbin/amd/amq/Makefile
index 40257c3..74fc749 100644
--- a/usr.sbin/amd/amq/Makefile
+++ b/usr.sbin/amd/amq/Makefile
@@ -17,6 +17,4 @@ CFLAGS+= -I${.CURDIR}/../../../contrib/amd/amq
DPADD= ${LIBAMU}
LDADD= ${LIBAMU}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/fixmount/Makefile b/usr.sbin/amd/fixmount/Makefile
index 1838fb2..7f96a45 100644
--- a/usr.sbin/amd/fixmount/Makefile
+++ b/usr.sbin/amd/fixmount/Makefile
@@ -18,6 +18,4 @@ SRCS+= checkmount_bsd44.c
DPADD= ${LIBAMU} ${LIBRPCSVC}
LDADD= ${LIBAMU} -lrpcsvc
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/fsinfo/Makefile b/usr.sbin/amd/fsinfo/Makefile
index 83becb2..1695a46 100644
--- a/usr.sbin/amd/fsinfo/Makefile
+++ b/usr.sbin/amd/fsinfo/Makefile
@@ -13,8 +13,6 @@ SRCS= fsi_gram.y fsi_lex.l
SRCS+= fsi_analyze.c fsi_dict.c fsi_util.c fsinfo.c wr_atab.c
SRCS+= wr_bparam.c wr_dumpset.c wr_exportfs.c wr_fstab.c
-NO_PIE= yes
-
CFLAGS+= -I${.CURDIR}/../../../contrib/amd/fsinfo
DPADD= ${LIBAMU}
diff --git a/usr.sbin/amd/hlfsd/Makefile b/usr.sbin/amd/hlfsd/Makefile
index dca94da..5b863dd 100644
--- a/usr.sbin/amd/hlfsd/Makefile
+++ b/usr.sbin/amd/hlfsd/Makefile
@@ -16,6 +16,4 @@ CFLAGS+= -I${.CURDIR}/../../../contrib/amd/hlfsd
DPADD= ${LIBAMU}
LDADD= ${LIBAMU}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/mk-amd-map/Makefile b/usr.sbin/amd/mk-amd-map/Makefile
index bed9e30..57fd6a5 100644
--- a/usr.sbin/amd/mk-amd-map/Makefile
+++ b/usr.sbin/amd/mk-amd-map/Makefile
@@ -13,6 +13,4 @@ MAN= mk-amd-map.8
DPADD= ${LIBAMU}
LDADD= ${LIBAMU}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/pawd/Makefile b/usr.sbin/amd/pawd/Makefile
index 612aced..c6bb1cc 100644
--- a/usr.sbin/amd/pawd/Makefile
+++ b/usr.sbin/amd/pawd/Makefile
@@ -17,6 +17,4 @@ CFLAGS+= -I${.CURDIR}/../../../contrib/amd/amq
DPADD= ${LIBAMU}
LDADD= ${LIBAMU}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/wire-test/Makefile b/usr.sbin/amd/wire-test/Makefile
index f960768..a07e690 100644
--- a/usr.sbin/amd/wire-test/Makefile
+++ b/usr.sbin/amd/wire-test/Makefile
@@ -13,6 +13,4 @@ MAN= wire-test.8
DPADD= ${LIBAMU}
LDADD= ${LIBAMU}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/auditdistd/Makefile b/usr.sbin/auditdistd/Makefile
index ee18bca..b323dcd 100644
--- a/usr.sbin/auditdistd/Makefile
+++ b/usr.sbin/auditdistd/Makefile
@@ -30,4 +30,8 @@ YFLAGS+=-v
CLEANFILES=parse.c parse.h parse.output
+# auditdistd cannot use FreeBSD specific lock annotation macros. Disable
+# thread safety analysis completely.
+NO_WTHREAD_SAFETY=
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/autofs/Makefile b/usr.sbin/autofs/Makefile
new file mode 100644
index 0000000..fab6865
--- /dev/null
+++ b/usr.sbin/autofs/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+PROG= automountd
+SRCS= automount.c
+SRCS+= automountd.c
+SRCS+= autounmountd.c
+SRCS+= common.c
+SRCS+= defined.c
+SRCS+= getmntopts.c
+SRCS+= log.c
+SRCS+= popen.c
+SRCS+= token.l
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../../sys/fs/autofs
+
+MAN= automount.8 automountd.8 autounmountd.8 auto_master.5
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+# Needed for getmntopts.c
+MOUNT= ${.CURDIR}/../../sbin/mount
+CFLAGS+=-I${MOUNT}
+
+WARNS= 6
+
+LINKS= ${BINDIR}/automountd ${BINDIR}/automount
+LINKS+= ${BINDIR}/automountd ${BINDIR}/autounmountd
+
+.PATH: ${MOUNT}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/autofs/auto_master.5 b/usr.sbin/autofs/auto_master.5
new file mode 100644
index 0000000..892ce32
--- /dev/null
+++ b/usr.sbin/autofs/auto_master.5
@@ -0,0 +1,276 @@
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 November 17, 2014
+.Dt AUTO_MASTER 5
+.Os
+.Sh NAME
+.Nm auto_master
+.Nd auto_master and map file format
+.Sh DESCRIPTION
+The
+.Nm
+configuration file is used by the
+.Xr automount 8
+command.
+Map files are read by the
+.Xr automountd 8
+daemon.
+.Sh AUTO_MASTER SYNTAX
+The
+.Nm
+file consists of lines with two or three entries separated by whitespace
+and terminated by newline character:
+.Bd -literal -offset indent
+.Pa mountpoint Pa map_name Op Ar -options
+.Ed
+.Pp
+.Pa mountpoint
+is either a fully specified path, or
+.Li /- .
+When
+.Pa mountpoint
+is a full path,
+.Pa map_name
+must reference an indirect map.
+Otherwise,
+.Pa map_name
+must reference a direct map.
+See
+.Sx "MAP SYNTAX" below.
+.Pp
+.Pa map_name
+specifies map to use.
+If
+.Pa map_name
+begins with
+.Li - ,
+it specifies a special map.
+See
+.Sx "MAP SYNTAX"
+below.
+If
+.Pa map_name
+is not a fully specified path
+.Pq it does not start with Li / ,
+.Xr automountd 8
+will search for that name in
+.Li /etc .
+Otherwise it will use the path as given.
+If the file indicated by
+.Pa map_name
+is executable,
+.Xr automountd 8
+will assume it is an executable map.
+See
+.Sx "MAP SYNTAX"
+below.
+Otherwise, the file is opened and the contents parsed.
+.Pp
+.Pa -options
+is an optional field that starts with
+.Li -
+and can contain generic filesystem mount options.
+.Pp
+The following example specifies that the /etc/auto_example indirect map
+will be mounted on /example.
+.Bd -literal -offset indent
+/example auto_example
+.Ed
+.Sh MAP SYNTAX
+Map files consist of lines with a number of entries separated by whitespace
+and terminated by newline character:
+.Bd -literal -offset indent
+.Pa key Oo Ar -options Oc Oo Ar mountpoint Oo -options Oc Oc Ar location Op ...
+.Ed
+.Pp
+In most cases, it can be simplified to:
+.Bd -literal -offset indent
+.Pa key Oo Ar -options Oc Ar location
+.Ed
+.Pp
+.Pa key
+is the path component used by
+.Xr automountd 8
+to find the right map entry to use.
+It is also used to form the final mountpoint.
+.Pp
+The
+.Ar options
+field, if present, must begin with
+.Li - .
+When mounting the filesystem, options supplied to
+.Nm
+and options specified in the map entry are concatenated together.
+The special option
+.Li fstype
+is used to specify filesystem type.
+It is not passed to the mount program as an option.
+Instead, it is passed as argument to
+.Cm "mount -t".
+The special option
+.Li nobrowse
+is used to disable creation of top-level directories for special
+and executable maps.
+.Pp
+The optional
+.Pa mountpoint
+field is used to specify multiple mount points
+for a single key.
+.Pp
+The
+.Ar location
+field specifies the filesystem to be mounted.
+To pass location that begins with
+.Li / ,
+prefix it with colon.
+For example,
+.Li :/dev/cd0 .
+.Pp
+This example, when used with the
+.Nm
+example above, specifies that the NFS share
+.Li 192.168.1.1:/share/example/x
+will be mounted on
+.Pa /example/x/
+when any process attempts to access that mountpoint, with
+.Li intr
+and
+.Li nfsv4
+mount options:
+.Bd -literal -offset indent
+.Li x -intr,nfsv4 192.168.1.1:/share/example/x
+.Ed
+.Pp
+Automatically mount the CD drive on access:
+.Bd -literal -offset indent
+.Li cd -fstype=cd9660 :/dev/cd0
+.Ed
+.Sh SPECIAL MAPS
+Special maps have names beginning with
+.Li - .
+Supported special maps are:
+.Pp
+.Bl -tag -width "-hosts" -compact
+.It Li -hosts
+This map queries the remote NFS server and maps exported volumes.
+It is traditionally mounted on
+.Pa /net .
+It enables access to files on a remote NFS server by accessing
+.Pa /net/nfs-server-ip/share-name/
+directory, without the need for any further configuration.
+.It Li -null
+This map prevents the
+.Xr automountd 8
+from mounting anything on the mountpoint.
+.El
+.Sh EXECUTABLE MAPS
+If the map file specified in
+.Nm
+has execute bit set, the
+.Xr automountd 8
+will execute it and parse the standard output instead of parsing
+the file contents.
+.Sh INDIRECT VERSUS DIRECT MAPS
+Indirect maps are referred to in
+.Nm
+by entries with a fully qualified path as a mount point, and must contain only
+relative paths as keys.
+Direct maps are referred to in
+.Nm
+by entries with
+.Li /-
+as the mountpoint, and must contain only fully qualified paths as keys.
+For indirect maps, the final mount point is determined by concatenating the
+.Nm
+mountpoint with the map entry key and optional map entry mountpoint.
+For direct maps, the final mount point is determined by concatenating
+the map entry key with the optional map entry mountpoint.
+.Pp
+The example above could be rewritten using direct map, by placing this in
+.Nm :
+.Bd -literal -offset indent
+.Li /- auto_example
+.Ed
+.Pp
+and this in
+.Li /etc/auto_example
+map file:
+.Bd -literal -offset indent
+.Li /example/x -intr,nfsv4 192.168.1.1:/share/example/x
+.Li /example/cd -fstype=cd9660 :/dev/cd0
+.Ed
+.Sh DIRECTORY SERVICES
+Both
+.Nm
+and maps may contain entries consisting of a plus sign and map name:
+.Bd -literal -offset indent
+.Li +auto_master
+.Ed
+.Pp
+Those entries cause
+.Xr automountd 8
+daemon to retrieve the named map from directory services (like LDAP)
+and include it where the entry was.
+.Pp
+If the file containing the map referenced in
+.Nm
+is not found, the map will be retrieved from directory services instead.
+.Pp
+To retrieve entries from directory services,
+.Xr automountd 8
+daemon runs
+.Pa /etc/autofs/include ,
+which is usually a shell script, with map name as the only command line
+parameter.
+The script should output entries formatted according to
+.Nm
+or automounter map syntax to standard output.
+An example script to use LDAP is included in
+.Pa /etc/autofs/include_ldap .
+It can be symlinked to
+.Pa /etc/autofs/include .
+.Sh FILES
+.Bl -tag -width ".Pa /etc/auto_master" -compact
+.It Pa /etc/auto_master
+The default location of the
+.Pa auto_master
+file.
+.El
+.Sh SEE ALSO
+.Xr autofs 5 ,
+.Xr automount 8 ,
+.Xr automountd 8 ,
+.Xr autounmountd 8
+.Sh AUTHORS
+The
+.Nm
+configuration file functionality was developed by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
+under sponsorship from the FreeBSD Foundation.
diff --git a/usr.sbin/autofs/automount.8 b/usr.sbin/autofs/automount.8
new file mode 100644
index 0000000..2988c68
--- /dev/null
+++ b/usr.sbin/autofs/automount.8
@@ -0,0 +1,107 @@
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 April 20, 2014
+.Dt AUTOMOUNT 8
+.Os
+.Sh NAME
+.Nm automount
+.Nd update autofs mounts
+.Sh SYNOPSIS
+.Nm
+.Op Fl D Ar name=value
+.Op Fl L
+.Op Fl f
+.Op Fl o Ar options
+.Op Fl v
+.Op Fl u
+.Sh DESCRIPTION
+When called without options, the
+.Nm
+command parses the
+.Xr auto_master 5
+configuration file and any direct maps that it references, and mounts
+or unmounts
+.Xr autofs 4
+filesystems to match.
+These options are available:
+.Bl -tag -width ".Fl v"
+.It Fl D
+Define a variable.
+It is only useful with
+.Fl L .
+.It Fl L
+Do not mount or unmount anything.
+Instead parse
+.Xr auto_master 5
+and any direct maps, then print them to standard output.
+When specified more than once, all the maps, including indirect ones,
+will be parsed and shown.
+This is useful when debugging configuration problems.
+.It Fl f
+Force unmount, to be used with
+.Fl u .
+.It Fl o
+Specify mount options to be used along with the ones specified in the maps.
+It is only useful with
+.Fl L .
+.It Fl u
+Try to unmount filesystems mounted by
+.Xr automountd 8 .
+.Xr autofs 5
+mounts are not unmounted.
+To unmount all
+.Xr autofs
+mounts, use
+.Cm "umount -At autofs".
+.It Fl v
+Increase verbosity.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh EXAMPLES
+Unmount all filesystems mounted by
+.Xr automountd 8 :
+.Dl Nm Fl u
+.Sh SEE ALSO
+.Xr auto_master 5 ,
+.Xr autofs 5 ,
+.Xr automountd 8 ,
+.Xr autounmountd 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
+under sponsorship from the FreeBSD Foundation.
diff --git a/usr.sbin/autofs/automount.c b/usr.sbin/autofs/automount.c
new file mode 100644
index 0000000..a956b08
--- /dev/null
+++ b/usr.sbin/autofs/automount.c
@@ -0,0 +1,347 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "common.h"
+#include "mntopts.h"
+
+static int
+unmount_by_statfs(const struct statfs *sb, bool force)
+{
+ char *fsid_str;
+ int error, ret, flags;
+
+ ret = asprintf(&fsid_str, "FSID:%d:%d",
+ sb->f_fsid.val[0], sb->f_fsid.val[1]);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ log_debugx("unmounting %s using %s", sb->f_mntonname, fsid_str);
+
+ flags = MNT_BYFSID;
+ if (force)
+ flags |= MNT_FORCE;
+ error = unmount(fsid_str, flags);
+ free(fsid_str);
+ if (error != 0)
+ log_warn("cannot unmount %s", sb->f_mntonname);
+
+ return (error);
+}
+
+static const struct statfs *
+find_statfs(const struct statfs *mntbuf, int nitems, const char *mountpoint)
+{
+ int i;
+
+ for (i = 0; i < nitems; i++) {
+ if (strcmp(mntbuf[i].f_mntonname, mountpoint) == 0)
+ return (mntbuf + i);
+ }
+
+ return (NULL);
+}
+
+static void
+mount_autofs(const char *from, const char *fspath, const char *options,
+ const char *prefix)
+{
+ struct iovec *iov = NULL;
+ char errmsg[255];
+ int error, iovlen = 0;
+
+ create_directory(fspath);
+
+ log_debugx("mounting %s on %s, prefix \"%s\", options \"%s\"",
+ from, fspath, prefix, options);
+ memset(errmsg, 0, sizeof(errmsg));
+
+ build_iovec(&iov, &iovlen, "fstype",
+ __DECONST(void *, "autofs"), (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath",
+ __DECONST(void *, fspath), (size_t)-1);
+ build_iovec(&iov, &iovlen, "from",
+ __DECONST(void *, from), (size_t)-1);
+ build_iovec(&iov, &iovlen, "errmsg",
+ errmsg, sizeof(errmsg));
+
+ /*
+ * Append the options and mountpoint defined in auto_master(5);
+ * this way automountd(8) does not need to parse it.
+ */
+ build_iovec(&iov, &iovlen, "master_options",
+ __DECONST(void *, options), (size_t)-1);
+ build_iovec(&iov, &iovlen, "master_prefix",
+ __DECONST(void *, prefix), (size_t)-1);
+
+ error = nmount(iov, iovlen, 0);
+ if (error != 0) {
+ if (*errmsg != '\0') {
+ log_err(1, "cannot mount %s on %s: %s",
+ from, fspath, errmsg);
+ } else {
+ log_err(1, "cannot mount %s on %s", from, fspath);
+ }
+ }
+}
+
+static void
+mount_if_not_already(const struct node *n, const char *map,
+ const struct statfs *mntbuf, int nitems)
+{
+ const struct statfs *sb;
+ char *mountpoint;
+ char *from;
+ int ret;
+
+ ret = asprintf(&from, "map %s", map);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ mountpoint = node_path(n);
+ sb = find_statfs(mntbuf, nitems, mountpoint);
+ if (sb != NULL) {
+ if (strcmp(sb->f_fstypename, "autofs") != 0) {
+ log_debugx("unknown filesystem mounted "
+ "on %s; mounting", mountpoint);
+ /*
+ * XXX: Compare options and 'from',
+ * and update the mount if necessary.
+ */
+ } else {
+ log_debugx("autofs already mounted "
+ "on %s", mountpoint);
+ free(from);
+ free(mountpoint);
+ return;
+ }
+ } else {
+ log_debugx("nothing mounted on %s; mounting",
+ mountpoint);
+ }
+
+ mount_autofs(from, mountpoint, n->n_options, n->n_key);
+ free(from);
+ free(mountpoint);
+}
+
+static void
+mount_unmount(struct node *root)
+{
+ struct statfs *mntbuf;
+ struct node *n, *n2, *n3;
+ int i, nitems;
+
+ nitems = getmntinfo(&mntbuf, MNT_WAIT);
+ if (nitems <= 0)
+ log_err(1, "getmntinfo");
+
+ log_debugx("unmounting stale autofs mounts");
+
+ for (i = 0; i < nitems; i++) {
+ if (strcmp(mntbuf[i].f_fstypename, "autofs") != 0) {
+ log_debugx("skipping %s, filesystem type is not autofs",
+ mntbuf[i].f_mntonname);
+ continue;
+ }
+
+ n = node_find(root, mntbuf[i].f_mntonname);
+ if (n != NULL) {
+ log_debugx("leaving autofs mounted on %s",
+ mntbuf[i].f_mntonname);
+ continue;
+ }
+
+ log_debugx("autofs mounted on %s not found "
+ "in new configuration; unmounting", mntbuf[i].f_mntonname);
+ unmount_by_statfs(&(mntbuf[i]), false);
+ }
+
+ log_debugx("mounting new autofs mounts");
+
+ TAILQ_FOREACH(n, &root->n_children, n_next) {
+ if (!node_is_direct_map(n)) {
+ mount_if_not_already(n, n->n_map, mntbuf, nitems);
+ continue;
+ }
+
+ TAILQ_FOREACH(n2, &n->n_children, n_next) {
+ TAILQ_FOREACH(n3, &n2->n_children, n_next) {
+ mount_if_not_already(n3, n->n_map,
+ mntbuf, nitems);
+ }
+ }
+ }
+}
+
+static void
+unmount_automounted(bool force)
+{
+ struct statfs *mntbuf;
+ int i, nitems;
+
+ nitems = getmntinfo(&mntbuf, MNT_WAIT);
+ if (nitems <= 0)
+ log_err(1, "getmntinfo");
+
+ log_debugx("unmounting automounted filesystems");
+
+ for (i = 0; i < nitems; i++) {
+ if (strcmp(mntbuf[i].f_fstypename, "autofs") == 0) {
+ log_debugx("skipping %s, filesystem type is autofs",
+ mntbuf[i].f_mntonname);
+ continue;
+ }
+
+ if ((mntbuf[i].f_flags & MNT_AUTOMOUNTED) == 0) {
+ log_debugx("skipping %s, not automounted",
+ mntbuf[i].f_mntonname);
+ continue;
+ }
+
+ unmount_by_statfs(&(mntbuf[i]), force);
+ }
+}
+
+static void
+usage_automount(void)
+{
+
+ fprintf(stderr, "usage: automount [-D name=value][-o opts][-Lfuv]\n");
+ exit(1);
+}
+
+int
+main_automount(int argc, char **argv)
+{
+ struct node *root;
+ int ch, debug = 0, show_maps = 0;
+ char *options = NULL;
+ bool do_unmount = false, force_unmount = false;
+
+ /*
+ * Note that in automount(8), the only purpose of variable
+ * handling is to aid in debugging maps (automount -L).
+ */
+ defined_init();
+
+ while ((ch = getopt(argc, argv, "D:Lfo:uv")) != -1) {
+ switch (ch) {
+ case 'D':
+ defined_parse_and_add(optarg);
+ break;
+ case 'L':
+ show_maps++;
+ break;
+ case 'f':
+ force_unmount = true;
+ break;
+ case 'o':
+ if (options == NULL) {
+ options = checked_strdup(optarg);
+ } else {
+ options =
+ separated_concat(options, optarg, ',');
+ }
+ break;
+ case 'u':
+ do_unmount = true;
+ break;
+ case 'v':
+ debug++;
+ break;
+ case '?':
+ default:
+ usage_automount();
+ }
+ }
+ argc -= optind;
+ if (argc != 0)
+ usage_automount();
+
+ if (force_unmount && !do_unmount)
+ usage_automount();
+
+ log_init(debug);
+
+ if (do_unmount) {
+ unmount_automounted(force_unmount);
+ return (0);
+ }
+
+ root = node_new_root();
+ parse_master(root, AUTO_MASTER_PATH);
+
+ if (show_maps) {
+ if (options != NULL) {
+ root->n_options = separated_concat(options,
+ root->n_options, ',');
+ }
+ if (show_maps > 1) {
+ node_expand_indirect_maps(root);
+ node_expand_ampersand(root, NULL);
+ }
+ node_expand_defined(root);
+ node_print(root);
+ return (0);
+ }
+
+ mount_unmount(root);
+
+ return (0);
+}
diff --git a/usr.sbin/autofs/automountd.8 b/usr.sbin/autofs/automountd.8
new file mode 100644
index 0000000..31fc8f2
--- /dev/null
+++ b/usr.sbin/autofs/automountd.8
@@ -0,0 +1,103 @@
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 April 20, 2014
+.Dt AUTOMOUNTD 8
+.Os
+.Sh NAME
+.Nm automountd
+.Nd daemon handling autofs mount requests
+.Sh SYNOPSIS
+.Nm
+.Op Fl D Ar name=value
+.Op Fl i
+.Op Fl m Ar maxproc
+.Op Fl o Ar options
+.Op Fl d
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+daemon is responsible for handling
+.Xr autofs 5
+mount requests, parsing maps,
+and mounting filesystems they specify.
+On startup,
+.Nm
+forks into background and waits for kernel requests.
+When a request is received,
+.Nm
+forks a child process.
+The child process parses the appropriate map and mounts filesystems accordingly.
+Then it signals the kernel to release blocked processes that were waiting
+for the mount.
+.Bl -tag -width ".Fl v"
+.It Fl D
+Define a variable.
+.It Fl i
+For indirect mounts, only create subdirectories if there are no wildcard
+entries.
+Without
+.Fl i ,
+.Nm
+creates all the subdirectories it can.
+Users may not realize that the wildcard map entry makes it possible to access
+directories that have not yet been created.
+.It Fl m Ar maxproc
+Limit the number of forked
+.Nm
+processes, and thus the number of mount requests being handled in parallel.
+The default is 30.
+.It Fl d
+Debug mode: increase verbosity and do not daemonize.
+.It Fl o Ar options
+Specify mount options.
+Options specified here ill be overridden by options entered in maps or
+.Xr auto_master 5 .
+.It Fl v
+Increase verbosity.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr auto_master 5 ,
+.Xr autofs 5 ,
+.Xr automount 8 ,
+.Xr autounmountd 8
+.Sh HISTORY
+The
+.Nm
+daemon appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
+under sponsorship from the FreeBSD Foundation.
diff --git a/usr.sbin/autofs/automountd.c b/usr.sbin/autofs/automountd.c
new file mode 100644
index 0000000..44143e5
--- /dev/null
+++ b/usr.sbin/autofs/automountd.c
@@ -0,0 +1,575 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "autofs_ioctl.h"
+
+#include "common.h"
+
+#define AUTOMOUNTD_PIDFILE "/var/run/automountd.pid"
+
+static int nchildren = 0;
+static int autofs_fd;
+static int request_id;
+
+static void
+done(int request_error, bool wildcards)
+{
+ struct autofs_daemon_done add;
+ int error;
+
+ memset(&add, 0, sizeof(add));
+ add.add_id = request_id;
+ add.add_wildcards = wildcards;
+ add.add_error = request_error;
+
+ log_debugx("completing request %d with error %d",
+ request_id, request_error);
+
+ error = ioctl(autofs_fd, AUTOFSDONE, &add);
+ if (error != 0) {
+ /*
+ * Do this instead of log_err() to avoid calling
+ * done() again with error, from atexit handler.
+ */
+ log_warn("AUTOFSDONE");
+ }
+ quick_exit(1);
+}
+
+/*
+ * Remove "fstype=whatever" from optionsp and return the "whatever" part.
+ */
+static char *
+pick_option(const char *option, char **optionsp)
+{
+ char *tofree, *pair, *newoptions;
+ char *picked = NULL;
+ bool first = true;
+
+ tofree = *optionsp;
+
+ newoptions = calloc(strlen(*optionsp) + 1, 1);
+ if (newoptions == NULL)
+ log_err(1, "calloc");
+
+ while ((pair = strsep(optionsp, ",")) != NULL) {
+ /*
+ * XXX: strncasecmp(3) perhaps?
+ */
+ if (strncmp(pair, option, strlen(option)) == 0) {
+ picked = checked_strdup(pair + strlen(option));
+ } else {
+ if (first == false)
+ strcat(newoptions, ",");
+ else
+ first = false;
+ strcat(newoptions, pair);
+ }
+ }
+
+ free(tofree);
+ *optionsp = newoptions;
+
+ return (picked);
+}
+
+static void
+create_subtree(const struct node *node, bool incomplete)
+{
+ const struct node *child;
+ char *path;
+ bool wildcard_found = false;
+
+ /*
+ * Skip wildcard nodes.
+ */
+ if (strcmp(node->n_key, "*") == 0)
+ return;
+
+ path = node_path(node);
+ log_debugx("creating subtree at %s", path);
+ create_directory(path);
+
+ if (incomplete) {
+ TAILQ_FOREACH(child, &node->n_children, n_next) {
+ if (strcmp(child->n_key, "*") == 0) {
+ wildcard_found = true;
+ break;
+ }
+ }
+
+ if (wildcard_found) {
+ log_debugx("node %s contains wildcard entry; "
+ "not creating its subdirectories due to -d flag",
+ path);
+ free(path);
+ return;
+ }
+ }
+
+ free(path);
+
+ TAILQ_FOREACH(child, &node->n_children, n_next)
+ create_subtree(child, incomplete);
+}
+
+static void
+exit_callback(void)
+{
+
+ done(EIO, true);
+}
+
+static void
+handle_request(const struct autofs_daemon_request *adr, char *cmdline_options,
+ bool incomplete_hierarchy)
+{
+ const char *map;
+ struct node *root, *parent, *node;
+ FILE *f;
+ char *options, *fstype, *nobrowse, *retrycnt, *tmp;
+ int error;
+ bool wildcards;
+
+ log_debugx("got request %d: from %s, path %s, prefix \"%s\", "
+ "key \"%s\", options \"%s\"", adr->adr_id, adr->adr_from,
+ adr->adr_path, adr->adr_prefix, adr->adr_key, adr->adr_options);
+
+ /*
+ * Try to notify the kernel about any problems.
+ */
+ request_id = adr->adr_id;
+ atexit(exit_callback);
+
+ if (strncmp(adr->adr_from, "map ", 4) != 0) {
+ log_errx(1, "invalid mountfrom \"%s\"; failing request",
+ adr->adr_from);
+ }
+
+ map = adr->adr_from + 4; /* 4 for strlen("map "); */
+ root = node_new_root();
+ if (adr->adr_prefix[0] == '\0' || strcmp(adr->adr_prefix, "/") == 0) {
+ parent = root;
+ } else {
+ parent = node_new_map(root, checked_strdup(adr->adr_prefix),
+ checked_strdup(adr->adr_options), checked_strdup(map),
+ checked_strdup("[kernel request]"), lineno);
+ }
+
+ /*
+ * "Wildcards" here actually means "make autofs(4) request
+ * automountd(8) action if the node being looked up does not
+ * exist, even though the parent is marked as cached". This
+ * needs to be done for maps with wildcard entries, but also
+ * for special and executable maps.
+ */
+ parse_map(parent, map, adr->adr_key[0] != '\0' ? adr->adr_key : NULL,
+ &wildcards);
+ if (!wildcards)
+ wildcards = node_has_wildcards(parent);
+ if (wildcards)
+ log_debugx("map may contain wildcard entries");
+ else
+ log_debugx("map does not contain wildcard entries");
+
+ if (adr->adr_key[0] != '\0')
+ node_expand_wildcard(root, adr->adr_key);
+
+ node = node_find(root, adr->adr_path);
+ if (node == NULL) {
+ log_errx(1, "map %s does not contain key for \"%s\"; "
+ "failing mount", map, adr->adr_path);
+ }
+
+ if (node->n_location == NULL) {
+ log_debugx("found node defined at %s:%d; not a mountpoint",
+ node->n_config_file, node->n_config_line);
+
+ options = node_options(node);
+
+ /*
+ * Prepend options passed via automountd(8) command line.
+ */
+ if (cmdline_options != NULL) {
+ options =
+ separated_concat(cmdline_options, options, ',');
+ }
+
+ nobrowse = pick_option("nobrowse", &options);
+ if (nobrowse != NULL && adr->adr_key[0] == '\0') {
+ log_debugx("skipping map %s due to \"nobrowse\" "
+ "option; exiting", map);
+ done(0, true);
+
+ /*
+ * Exit without calling exit_callback().
+ */
+ quick_exit(0);
+ }
+
+ /*
+ * Not a mountpoint; create directories in the autofs mount
+ * and complete the request.
+ */
+ create_subtree(node, incomplete_hierarchy);
+
+ if (incomplete_hierarchy && adr->adr_key[0] != '\0') {
+ /*
+ * We still need to create the single subdirectory
+ * user is trying to access.
+ */
+ tmp = separated_concat(adr->adr_path,
+ adr->adr_key, '/');
+ node = node_find(root, tmp);
+ if (node != NULL)
+ create_subtree(node, false);
+ }
+
+ log_debugx("nothing to mount; exiting");
+ done(0, wildcards);
+
+ /*
+ * Exit without calling exit_callback().
+ */
+ quick_exit(0);
+ }
+
+ log_debugx("found node defined at %s:%d; it is a mountpoint",
+ node->n_config_file, node->n_config_line);
+
+ node_expand_ampersand(node,
+ adr->adr_key[0] != '\0' ? adr->adr_key : NULL);
+ error = node_expand_defined(node);
+ if (error != 0) {
+ log_errx(1, "variable expansion failed for %s; "
+ "failing mount", adr->adr_path);
+ }
+
+ options = node_options(node);
+
+ /*
+ * Prepend options passed via automountd(8) command line.
+ */
+ if (cmdline_options != NULL)
+ options = separated_concat(cmdline_options, options, ',');
+
+ /*
+ * Append "automounted".
+ */
+ options = separated_concat(options, "automounted", ',');
+
+ /*
+ * Remove "nobrowse", mount(8) doesn't understand it.
+ */
+ pick_option("nobrowse", &options);
+
+ /*
+ * Figure out fstype.
+ */
+ fstype = pick_option("fstype=", &options);
+ if (fstype == NULL) {
+ log_debugx("fstype not specified in options; "
+ "defaulting to \"nfs\"");
+ fstype = checked_strdup("nfs");
+ }
+
+ if (strcmp(fstype, "nfs") == 0) {
+ /*
+ * The mount_nfs(8) command defaults to retry undefinitely.
+ * We do not want that behaviour, because it leaves mount_nfs(8)
+ * instances and automountd(8) children hanging forever.
+ * Disable retries unless the option was passed explicitly.
+ */
+ retrycnt = pick_option("retrycnt=", &options);
+ if (retrycnt == NULL) {
+ log_debugx("retrycnt not specified in options; "
+ "defaulting to 1");
+ options = separated_concat(options,
+ separated_concat("retrycnt", "1", '='), ',');
+ } else {
+ options = separated_concat(options,
+ separated_concat("retrycnt", retrycnt, '='), ',');
+ }
+ }
+
+ f = auto_popen("mount", "-t", fstype, "-o", options,
+ node->n_location, adr->adr_path, NULL);
+ assert(f != NULL);
+ error = auto_pclose(f);
+ if (error != 0)
+ log_errx(1, "mount failed");
+
+ log_debugx("mount done; exiting");
+ done(0, wildcards);
+
+ /*
+ * Exit without calling exit_callback().
+ */
+ quick_exit(0);
+}
+
+static void
+sigchld_handler(int dummy __unused)
+{
+
+ /*
+ * The only purpose of this handler is to make SIGCHLD
+ * interrupt the AUTOFSREQUEST ioctl(2), so we can call
+ * wait_for_children().
+ */
+}
+
+static void
+register_sigchld(void)
+{
+ struct sigaction sa;
+ int error;
+
+ bzero(&sa, sizeof(sa));
+ sa.sa_handler = sigchld_handler;
+ sigfillset(&sa.sa_mask);
+ error = sigaction(SIGCHLD, &sa, NULL);
+ if (error != 0)
+ log_err(1, "sigaction");
+
+}
+
+
+static int
+wait_for_children(bool block)
+{
+ pid_t pid;
+ int status;
+ int num = 0;
+
+ for (;;) {
+ /*
+ * If "block" is true, wait for at least one process.
+ */
+ if (block && num == 0)
+ pid = wait4(-1, &status, 0, NULL);
+ else
+ pid = wait4(-1, &status, WNOHANG, NULL);
+ if (pid <= 0)
+ break;
+ if (WIFSIGNALED(status)) {
+ log_warnx("child process %d terminated with signal %d",
+ pid, WTERMSIG(status));
+ } else if (WEXITSTATUS(status) != 0) {
+ log_debugx("child process %d terminated with exit status %d",
+ pid, WEXITSTATUS(status));
+ } else {
+ log_debugx("child process %d terminated gracefully", pid);
+ }
+ num++;
+ }
+
+ return (num);
+}
+
+static void
+usage_automountd(void)
+{
+
+ fprintf(stderr, "usage: automountd [-D name=value][-m maxproc]"
+ "[-o opts][-Tidv]\n");
+ exit(1);
+}
+
+int
+main_automountd(int argc, char **argv)
+{
+ struct pidfh *pidfh;
+ pid_t pid, otherpid;
+ const char *pidfile_path = AUTOMOUNTD_PIDFILE;
+ char *options = NULL;
+ struct autofs_daemon_request request;
+ int ch, debug = 0, error, maxproc = 30, retval, saved_errno;
+ bool dont_daemonize = false, incomplete_hierarchy = false;
+
+ defined_init();
+
+ while ((ch = getopt(argc, argv, "D:Tdim:o:v")) != -1) {
+ switch (ch) {
+ case 'D':
+ defined_parse_and_add(optarg);
+ break;
+ case 'T':
+ /*
+ * For compatibility with other implementations,
+ * such as OS X.
+ */
+ debug++;
+ break;
+ case 'd':
+ dont_daemonize = true;
+ debug++;
+ break;
+ case 'i':
+ incomplete_hierarchy = true;
+ break;
+ case 'm':
+ maxproc = atoi(optarg);
+ break;
+ case 'o':
+ if (options == NULL) {
+ options = checked_strdup(optarg);
+ } else {
+ options =
+ separated_concat(options, optarg, ',');
+ }
+ break;
+ case 'v':
+ debug++;
+ break;
+ case '?':
+ default:
+ usage_automountd();
+ }
+ }
+ argc -= optind;
+ if (argc != 0)
+ usage_automountd();
+
+ log_init(debug);
+
+ pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
+ if (pidfh == NULL) {
+ if (errno == EEXIST) {
+ log_errx(1, "daemon already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ log_err(1, "cannot open or create pidfile \"%s\"",
+ pidfile_path);
+ }
+
+ autofs_fd = open(AUTOFS_PATH, O_RDWR | O_CLOEXEC);
+ if (autofs_fd < 0 && errno == ENOENT) {
+ saved_errno = errno;
+ retval = kldload("autofs");
+ if (retval != -1)
+ autofs_fd = open(AUTOFS_PATH, O_RDWR | O_CLOEXEC);
+ else
+ errno = saved_errno;
+ }
+ if (autofs_fd < 0)
+ log_err(1, "failed to open %s", AUTOFS_PATH);
+
+ if (dont_daemonize == false) {
+ if (daemon(0, 0) == -1) {
+ log_warn("cannot daemonize");
+ pidfile_remove(pidfh);
+ exit(1);
+ }
+ } else {
+ lesser_daemon();
+ }
+
+ pidfile_write(pidfh);
+
+ register_sigchld();
+
+ for (;;) {
+ log_debugx("waiting for request from the kernel");
+
+ memset(&request, 0, sizeof(request));
+ error = ioctl(autofs_fd, AUTOFSREQUEST, &request);
+ if (error != 0) {
+ if (errno == EINTR) {
+ nchildren -= wait_for_children(false);
+ assert(nchildren >= 0);
+ continue;
+ }
+
+ log_err(1, "AUTOFSREQUEST");
+ }
+
+ if (dont_daemonize) {
+ log_debugx("not forking due to -d flag; "
+ "will exit after servicing a single request");
+ } else {
+ nchildren -= wait_for_children(false);
+ assert(nchildren >= 0);
+
+ while (maxproc > 0 && nchildren >= maxproc) {
+ log_debugx("maxproc limit of %d child processes hit; "
+ "waiting for child process to exit", maxproc);
+ nchildren -= wait_for_children(true);
+ assert(nchildren >= 0);
+ }
+ log_debugx("got request; forking child process #%d",
+ nchildren);
+ nchildren++;
+
+ pid = fork();
+ if (pid < 0)
+ log_err(1, "fork");
+ if (pid > 0)
+ continue;
+ }
+
+ pidfile_close(pidfh);
+ handle_request(&request, options, incomplete_hierarchy);
+ }
+
+ pidfile_close(pidfh);
+
+ return (0);
+}
+
diff --git a/usr.sbin/autofs/autounmountd.8 b/usr.sbin/autofs/autounmountd.8
new file mode 100644
index 0000000..1b5d9a8
--- /dev/null
+++ b/usr.sbin/autofs/autounmountd.8
@@ -0,0 +1,88 @@
+.\" Copyright (c) 2014 The FreeBSD Foundation
+.\" All rights reserved.
+.\"
+.\" This software was developed by Edward Tomasz Napierala under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 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 April 20, 2014
+.Dt AUTOUNMOUNTD 8
+.Os
+.Sh NAME
+.Nm autounmountd
+.Nd daemon unmounting automounted filesystems
+.Sh SYNOPSIS
+.Nm
+.Op Fl d
+.Op Fl r time
+.Op Fl t time
+.Op Fl v
+.Sh DESCRIPTION
+The
+.Nm
+daemon is responsible for unmounting filesystems mounted by
+.Xr automountd 8 .
+On startup,
+.Nm
+retrieves a list of filesystems that have the
+.Li automounted
+mount option set.
+The list is updated every time a filesystem is mounted or unmounted.
+After a specified time passes,
+.Nm
+attempts to unmount a filesystem, retrying after some time if necessary.
+.Pp
+These options are available:
+.Bl -tag -width ".Fl v"
+.It Fl d
+Debug mode: increase verbosity and do not daemonize.
+.It Fl r
+Number of seconds to wait before trying to unmount an expired filesystem
+after a previous attempt failed, possibly due to filesystem being busy.
+The default value is 600, or ten minutes.
+.It Fl t
+Number of seconds to wait before trying to unmount a filesystem.
+The default value is 600, or ten minutes.
+.It Fl v
+Increase verbosity.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh SEE ALSO
+.Xr auto_master 5 ,
+.Xr autofs 5 ,
+.Xr automount 8 ,
+.Xr automountd 8
+.Sh HISTORY
+The
+.Nm
+daemon appeared in
+.Fx 10.1 .
+.Sh AUTHORS
+The
+.Nm
+was developed by
+.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
+under sponsorship from the FreeBSD Foundation.
diff --git a/usr.sbin/autofs/autounmountd.c b/usr.sbin/autofs/autounmountd.c
new file mode 100644
index 0000000..0f52b66
--- /dev/null
+++ b/usr.sbin/autofs/autounmountd.c
@@ -0,0 +1,341 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/mount.h>
+#include <sys/time.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libutil.h>
+
+#include "common.h"
+
+#define AUTOUNMOUNTD_PIDFILE "/var/run/autounmountd.pid"
+
+struct automounted_fs {
+ TAILQ_ENTRY(automounted_fs) af_next;
+ time_t af_mount_time;
+ bool af_mark;
+ fsid_t af_fsid;
+ char af_mountpoint[MNAMELEN];
+};
+
+static TAILQ_HEAD(, automounted_fs) automounted;
+
+static struct automounted_fs *
+automounted_find(fsid_t fsid)
+{
+ struct automounted_fs *af;
+
+ TAILQ_FOREACH(af, &automounted, af_next) {
+ if (af->af_fsid.val[0] == fsid.val[0] &&
+ af->af_fsid.val[1] == fsid.val[1])
+ return (af);
+ }
+
+ return (NULL);
+}
+
+static struct automounted_fs *
+automounted_add(fsid_t fsid, const char *mountpoint)
+{
+ struct automounted_fs *af;
+
+ af = calloc(sizeof(*af), 1);
+ if (af == NULL)
+ log_err(1, "calloc");
+ af->af_mount_time = time(NULL);
+ af->af_fsid = fsid;
+ strlcpy(af->af_mountpoint, mountpoint, sizeof(af->af_mountpoint));
+
+ TAILQ_INSERT_TAIL(&automounted, af, af_next);
+
+ return (af);
+}
+
+static void
+automounted_remove(struct automounted_fs *af)
+{
+
+ TAILQ_REMOVE(&automounted, af, af_next);
+ free(af);
+}
+
+static void
+refresh_automounted(void)
+{
+ struct automounted_fs *af, *tmpaf;
+ struct statfs *mntbuf;
+ int i, nitems;
+
+ nitems = getmntinfo(&mntbuf, MNT_WAIT);
+ if (nitems <= 0)
+ log_err(1, "getmntinfo");
+
+ log_debugx("refreshing list of automounted filesystems");
+
+ TAILQ_FOREACH(af, &automounted, af_next)
+ af->af_mark = false;
+
+ for (i = 0; i < nitems; i++) {
+ if (strcmp(mntbuf[i].f_fstypename, "autofs") == 0) {
+ log_debugx("skipping %s, filesystem type is autofs",
+ mntbuf[i].f_mntonname);
+ continue;
+ }
+
+ if ((mntbuf[i].f_flags & MNT_AUTOMOUNTED) == 0) {
+ log_debugx("skipping %s, not automounted",
+ mntbuf[i].f_mntonname);
+ continue;
+ }
+
+ af = automounted_find(mntbuf[i].f_fsid);
+ if (af == NULL) {
+ log_debugx("new automounted filesystem found on %s "
+ "(FSID:%d:%d)", mntbuf[i].f_mntonname,
+ mntbuf[i].f_fsid.val[0], mntbuf[i].f_fsid.val[1]);
+ af = automounted_add(mntbuf[i].f_fsid,
+ mntbuf[i].f_mntonname);
+ } else {
+ log_debugx("already known automounted filesystem "
+ "found on %s (FSID:%d:%d)", mntbuf[i].f_mntonname,
+ mntbuf[i].f_fsid.val[0], mntbuf[i].f_fsid.val[1]);
+ }
+ af->af_mark = true;
+ }
+
+ TAILQ_FOREACH_SAFE(af, &automounted, af_next, tmpaf) {
+ if (af->af_mark)
+ continue;
+ log_debugx("lost filesystem mounted on %s (FSID:%d:%d)",
+ af->af_mountpoint, af->af_fsid.val[0], af->af_fsid.val[1]);
+ automounted_remove(af);
+ }
+}
+
+static int
+unmount_by_fsid(const fsid_t fsid, const char *mountpoint)
+{
+ char *fsid_str;
+ int error, ret;
+
+ ret = asprintf(&fsid_str, "FSID:%d:%d", fsid.val[0], fsid.val[1]);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ error = unmount(fsid_str, MNT_BYFSID);
+ if (error != 0) {
+ if (errno == EBUSY) {
+ log_debugx("cannot unmount %s (%s): %s",
+ mountpoint, fsid_str, strerror(errno));
+ } else {
+ log_warn("cannot unmount %s (%s)",
+ mountpoint, fsid_str);
+ }
+ }
+
+ free(fsid_str);
+
+ return (error);
+}
+
+static double
+expire_automounted(double expiration_time)
+{
+ struct automounted_fs *af, *tmpaf;
+ time_t now;
+ double mounted_for, mounted_max = 0;
+ int error;
+
+ now = time(NULL);
+
+ log_debugx("expiring automounted filesystems");
+
+ TAILQ_FOREACH_SAFE(af, &automounted, af_next, tmpaf) {
+ mounted_for = difftime(now, af->af_mount_time);
+
+ if (mounted_for < expiration_time) {
+ log_debugx("skipping %s (FSID:%d:%d), mounted "
+ "for %.0f seconds", af->af_mountpoint,
+ af->af_fsid.val[0], af->af_fsid.val[1],
+ mounted_for);
+
+ if (mounted_for > mounted_max)
+ mounted_max = mounted_for;
+
+ continue;
+ }
+
+ log_debugx("filesystem mounted on %s (FSID:%d:%d), "
+ "was mounted for %.0f seconds; unmounting",
+ af->af_mountpoint, af->af_fsid.val[0], af->af_fsid.val[1],
+ mounted_for);
+ error = unmount_by_fsid(af->af_fsid, af->af_mountpoint);
+ if (error != 0) {
+ if (mounted_for > mounted_max)
+ mounted_max = mounted_for;
+ }
+ }
+
+ return (mounted_max);
+}
+
+static void
+usage_autounmountd(void)
+{
+
+ fprintf(stderr, "usage: autounmountd [-r time][-t time][-dv]\n");
+ exit(1);
+}
+
+static void
+do_wait(int kq, double sleep_time)
+{
+ struct timespec timeout;
+ struct kevent unused;
+ int error;
+
+ assert(sleep_time > 0);
+ timeout.tv_sec = sleep_time;
+ timeout.tv_nsec = 0;
+
+ log_debugx("waiting for filesystem event for %.0f seconds", sleep_time);
+ error = kevent(kq, NULL, 0, &unused, 1, &timeout);
+ if (error < 0)
+ log_err(1, "kevent");
+
+ if (error == 0)
+ log_debugx("timeout reached");
+ else
+ log_debugx("got filesystem event");
+}
+
+int
+main_autounmountd(int argc, char **argv)
+{
+ struct kevent event;
+ struct pidfh *pidfh;
+ pid_t otherpid;
+ const char *pidfile_path = AUTOUNMOUNTD_PIDFILE;
+ int ch, debug = 0, error, kq;
+ double expiration_time = 600, retry_time = 600, mounted_max, sleep_time;
+ bool dont_daemonize = false;
+
+ while ((ch = getopt(argc, argv, "dr:t:v")) != -1) {
+ switch (ch) {
+ case 'd':
+ dont_daemonize = true;
+ debug++;
+ break;
+ case 'r':
+ retry_time = atoi(optarg);
+ break;
+ case 't':
+ expiration_time = atoi(optarg);
+ break;
+ case 'v':
+ debug++;
+ break;
+ case '?':
+ default:
+ usage_autounmountd();
+ }
+ }
+ argc -= optind;
+ if (argc != 0)
+ usage_autounmountd();
+
+ if (retry_time <= 0)
+ log_errx(1, "retry time must be greater than zero");
+ if (expiration_time <= 0)
+ log_errx(1, "expiration time must be greater than zero");
+
+ log_init(debug);
+
+ pidfh = pidfile_open(pidfile_path, 0600, &otherpid);
+ if (pidfh == NULL) {
+ if (errno == EEXIST) {
+ log_errx(1, "daemon already running, pid: %jd.",
+ (intmax_t)otherpid);
+ }
+ log_err(1, "cannot open or create pidfile \"%s\"",
+ pidfile_path);
+ }
+
+ if (dont_daemonize == false) {
+ if (daemon(0, 0) == -1) {
+ log_warn("cannot daemonize");
+ pidfile_remove(pidfh);
+ exit(1);
+ }
+ }
+
+ pidfile_write(pidfh);
+
+ TAILQ_INIT(&automounted);
+
+ kq = kqueue();
+ if (kq < 0)
+ log_err(1, "kqueue");
+
+ EV_SET(&event, 0, EVFILT_FS, EV_ADD | EV_CLEAR, 0, 0, NULL);
+ error = kevent(kq, &event, 1, NULL, 0, NULL);
+ if (error < 0)
+ log_err(1, "kevent");
+
+ for (;;) {
+ refresh_automounted();
+ mounted_max = expire_automounted(expiration_time);
+ if (mounted_max < expiration_time) {
+ sleep_time = difftime(expiration_time, mounted_max);
+ log_debugx("some filesystems expire in %.0f seconds",
+ sleep_time);
+ } else {
+ sleep_time = retry_time;
+ log_debugx("some expired filesystems remain mounted, "
+ "will retry in %.0f seconds", sleep_time);
+ }
+
+ do_wait(kq, sleep_time);
+ }
+
+ return (0);
+}
diff --git a/usr.sbin/autofs/common.c b/usr.sbin/autofs/common.c
new file mode 100644
index 0000000..6fd8a05
--- /dev/null
+++ b/usr.sbin/autofs/common.c
@@ -0,0 +1,1209 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#define _WITH_GETLINE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "autofs_ioctl.h"
+
+#include "common.h"
+
+extern FILE *yyin;
+extern char *yytext;
+extern int yylex(void);
+
+static void parse_master_yyin(struct node *root, const char *master);
+static void parse_map_yyin(struct node *parent, const char *map,
+ const char *executable_key);
+
+char *
+checked_strdup(const char *s)
+{
+ char *c;
+
+ assert(s != NULL);
+
+ c = strdup(s);
+ if (c == NULL)
+ log_err(1, "strdup");
+ return (c);
+}
+
+/*
+ * Take two pointers to strings, concatenate the contents with "/" in the
+ * middle, make the first pointer point to the result, the second pointer
+ * to NULL, and free the old strings.
+ *
+ * Concatenate pathnames, basically.
+ */
+static void
+concat(char **p1, char **p2)
+{
+ int ret;
+ char *path;
+
+ assert(p1 != NULL);
+ assert(p2 != NULL);
+
+ if (*p1 == NULL)
+ *p1 = checked_strdup("");
+
+ if (*p2 == NULL)
+ *p2 = checked_strdup("");
+
+ ret = asprintf(&path, "%s/%s", *p1, *p2);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ /*
+ * XXX
+ */
+ //free(*p1);
+ //free(*p2);
+
+ *p1 = path;
+ *p2 = NULL;
+}
+
+/*
+ * Concatenate two strings, inserting separator between them, unless not needed.
+ *
+ * This function is very convenient to use when you do not care about freeing
+ * memory - which is okay here, because we are a short running process.
+ */
+char *
+separated_concat(const char *s1, const char *s2, char separator)
+{
+ char *result;
+ int ret;
+
+ assert(s1 != NULL);
+ assert(s2 != NULL);
+
+ if (s1[0] == '\0' || s2[0] == '\0' ||
+ s1[strlen(s1) - 1] == separator || s2[0] == separator) {
+ ret = asprintf(&result, "%s%s", s1, s2);
+ } else {
+ ret = asprintf(&result, "%s%c%s", s1, separator, s2);
+ }
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ //log_debugx("separated_concat: got %s and %s, returning %s", s1, s2, result);
+
+ return (result);
+}
+
+void
+create_directory(const char *path)
+{
+ char *component, *copy, *tofree, *partial;
+ int error;
+
+ assert(path[0] == '/');
+
+ /*
+ * +1 to skip the leading slash.
+ */
+ copy = tofree = checked_strdup(path + 1);
+
+ partial = NULL;
+ for (;;) {
+ component = strsep(&copy, "/");
+ if (component == NULL)
+ break;
+ concat(&partial, &component);
+ //log_debugx("creating \"%s\"", partial);
+ error = mkdir(partial, 0755);
+ if (error != 0 && errno != EEXIST) {
+ log_warn("cannot create %s", partial);
+ return;
+ }
+ }
+
+ free(tofree);
+}
+
+struct node *
+node_new_root(void)
+{
+ struct node *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL)
+ log_err(1, "calloc");
+ // XXX
+ n->n_key = checked_strdup("/");
+ n->n_options = checked_strdup("");
+
+ TAILQ_INIT(&n->n_children);
+
+ return (n);
+}
+
+struct node *
+node_new(struct node *parent, char *key, char *options, char *location,
+ const char *config_file, int config_line)
+{
+ struct node *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL)
+ log_err(1, "calloc");
+
+ TAILQ_INIT(&n->n_children);
+ assert(key != NULL);
+ assert(key[0] != '\0');
+ n->n_key = key;
+ if (options != NULL)
+ n->n_options = options;
+ else
+ n->n_options = strdup("");
+ n->n_location = location;
+ assert(config_file != NULL);
+ n->n_config_file = config_file;
+ assert(config_line >= 0);
+ n->n_config_line = config_line;
+
+ assert(parent != NULL);
+ n->n_parent = parent;
+ TAILQ_INSERT_TAIL(&parent->n_children, n, n_next);
+
+ return (n);
+}
+
+struct node *
+node_new_map(struct node *parent, char *key, char *options, char *map,
+ const char *config_file, int config_line)
+{
+ struct node *n;
+
+ n = calloc(1, sizeof(*n));
+ if (n == NULL)
+ log_err(1, "calloc");
+
+ TAILQ_INIT(&n->n_children);
+ assert(key != NULL);
+ assert(key[0] != '\0');
+ n->n_key = key;
+ if (options != NULL)
+ n->n_options = options;
+ else
+ n->n_options = strdup("");
+ n->n_map = map;
+ assert(config_file != NULL);
+ n->n_config_file = config_file;
+ assert(config_line >= 0);
+ n->n_config_line = config_line;
+
+ assert(parent != NULL);
+ n->n_parent = parent;
+ TAILQ_INSERT_TAIL(&parent->n_children, n, n_next);
+
+ return (n);
+}
+
+static struct node *
+node_duplicate(const struct node *o, struct node *parent)
+{
+ const struct node *child;
+ struct node *n;
+
+ if (parent == NULL)
+ parent = o->n_parent;
+
+ n = node_new(parent, o->n_key, o->n_options, o->n_location,
+ o->n_config_file, o->n_config_line);
+
+ TAILQ_FOREACH(child, &o->n_children, n_next)
+ node_duplicate(child, n);
+
+ return (n);
+}
+
+static void
+node_delete(struct node *n)
+{
+ struct node *child, *tmp;
+
+ assert (n != NULL);
+
+ TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp)
+ node_delete(child);
+
+ if (n->n_parent != NULL)
+ TAILQ_REMOVE(&n->n_parent->n_children, n, n_next);
+
+ free(n);
+}
+
+/*
+ * Move (reparent) node 'n' to make it sibling of 'previous', placed
+ * just after it.
+ */
+static void
+node_move_after(struct node *n, struct node *previous)
+{
+
+ TAILQ_REMOVE(&n->n_parent->n_children, n, n_next);
+ n->n_parent = previous->n_parent;
+ TAILQ_INSERT_AFTER(&previous->n_parent->n_children, previous, n, n_next);
+}
+
+static void
+node_expand_includes(struct node *root, bool is_master)
+{
+ struct node *n, *n2, *tmp, *tmp2, *tmproot;
+ int error;
+
+ TAILQ_FOREACH_SAFE(n, &root->n_children, n_next, tmp) {
+ if (n->n_key[0] != '+')
+ continue;
+
+ error = access(AUTO_INCLUDE_PATH, F_OK);
+ if (error != 0) {
+ log_errx(1, "directory services not configured; "
+ "%s does not exist", AUTO_INCLUDE_PATH);
+ }
+
+ /*
+ * "+1" to skip leading "+".
+ */
+ yyin = auto_popen(AUTO_INCLUDE_PATH, n->n_key + 1, NULL);
+ assert(yyin != NULL);
+
+ tmproot = node_new_root();
+ if (is_master)
+ parse_master_yyin(tmproot, n->n_key);
+ else
+ parse_map_yyin(tmproot, n->n_key, NULL);
+
+ error = auto_pclose(yyin);
+ yyin = NULL;
+ if (error != 0) {
+ log_errx(1, "failed to handle include \"%s\"",
+ n->n_key);
+ }
+
+ /*
+ * Entries to be included are now in tmproot. We need to merge
+ * them with the rest, preserving their place and ordering.
+ */
+ TAILQ_FOREACH_REVERSE_SAFE(n2,
+ &tmproot->n_children, nodehead, n_next, tmp2) {
+ node_move_after(n2, n);
+ }
+
+ node_delete(n);
+ node_delete(tmproot);
+ }
+}
+
+static char *
+expand_ampersand(char *string, const char *key)
+{
+ char c, *expanded;
+ int i, ret, before_len = 0;
+ bool backslashed = false;
+
+ assert(key[0] != '\0');
+
+ expanded = checked_strdup(string);
+
+ for (i = 0; string[i] != '\0'; i++) {
+ c = string[i];
+ if (c == '\\' && backslashed == false) {
+ backslashed = true;
+ continue;
+ }
+ if (backslashed) {
+ backslashed = false;
+ continue;
+ }
+ backslashed = false;
+ if (c != '&')
+ continue;
+
+ /*
+ * The 'before_len' variable contains the number
+ * of characters before the '&'.
+ */
+ before_len = i;
+ //assert(i + 1 < (int)strlen(string));
+
+ ret = asprintf(&expanded, "%.*s%s%s",
+ before_len, string, key, string + before_len + 1);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ //log_debugx("\"%s\" expanded with key \"%s\" to \"%s\"",
+ // string, key, expanded);
+
+ /*
+ * Figure out where to start searching for next variable.
+ */
+ string = expanded;
+ i = before_len + strlen(key);
+ backslashed = false;
+ //assert(i < (int)strlen(string));
+ }
+
+ return (expanded);
+}
+
+/*
+ * Expand "&" in n_location. If the key is NULL, try to use
+ * key from map entries themselves. Keep in mind that maps
+ * consist of tho levels of node structures, the key is one
+ * level up.
+ *
+ * Variant with NULL key is for "automount -LL".
+ */
+void
+node_expand_ampersand(struct node *n, const char *key)
+{
+ struct node *child;
+
+ if (n->n_location != NULL) {
+ if (key == NULL) {
+ if (n->n_parent != NULL &&
+ strcmp(n->n_parent->n_key, "*") != 0) {
+ n->n_location = expand_ampersand(n->n_location,
+ n->n_parent->n_key);
+ }
+ } else {
+ n->n_location = expand_ampersand(n->n_location, key);
+ }
+ }
+
+ TAILQ_FOREACH(child, &n->n_children, n_next)
+ node_expand_ampersand(child, key);
+}
+
+/*
+ * Expand "*" in n_key.
+ */
+void
+node_expand_wildcard(struct node *n, const char *key)
+{
+ struct node *child, *expanded;
+
+ assert(key != NULL);
+
+ if (strcmp(n->n_key, "*") == 0) {
+ expanded = node_duplicate(n, NULL);
+ expanded->n_key = checked_strdup(key);
+ node_move_after(expanded, n);
+ }
+
+ TAILQ_FOREACH(child, &n->n_children, n_next)
+ node_expand_wildcard(child, key);
+}
+
+int
+node_expand_defined(struct node *n)
+{
+ struct node *child;
+ int error, cumulated_error = 0;
+
+ if (n->n_location != NULL) {
+ n->n_location = defined_expand(n->n_location);
+ if (n->n_location == NULL) {
+ log_warnx("failed to expand location for %s",
+ node_path(n));
+ return (EINVAL);
+ }
+ }
+
+ TAILQ_FOREACH(child, &n->n_children, n_next) {
+ error = node_expand_defined(child);
+ if (error != 0 && cumulated_error == 0)
+ cumulated_error = error;
+ }
+
+ return (cumulated_error);
+}
+
+bool
+node_is_direct_map(const struct node *n)
+{
+
+ for (;;) {
+ assert(n->n_parent != NULL);
+ if (n->n_parent->n_parent == NULL)
+ break;
+ n = n->n_parent;
+ }
+
+ assert(n->n_key != NULL);
+ if (strcmp(n->n_key, "/-") != 0)
+ return (false);
+
+ return (true);
+}
+
+bool
+node_has_wildcards(const struct node *n)
+{
+ const struct node *child;
+
+ TAILQ_FOREACH(child, &n->n_children, n_next) {
+ if (strcmp(child->n_key, "*") == 0)
+ return (true);
+ }
+
+ return (false);
+}
+
+static void
+node_expand_maps(struct node *n, bool indirect)
+{
+ struct node *child, *tmp;
+
+ TAILQ_FOREACH_SAFE(child, &n->n_children, n_next, tmp) {
+ if (node_is_direct_map(child)) {
+ if (indirect)
+ continue;
+ } else {
+ if (indirect == false)
+ continue;
+ }
+
+ /*
+ * This is the first-level map node; the one that contains
+ * the key and subnodes with mountpoints and actual map names.
+ */
+ if (child->n_map == NULL)
+ continue;
+
+ if (indirect) {
+ log_debugx("map \"%s\" is an indirect map, parsing",
+ child->n_map);
+ } else {
+ log_debugx("map \"%s\" is a direct map, parsing",
+ child->n_map);
+ }
+ parse_map(child, child->n_map, NULL, NULL);
+ }
+}
+
+static void
+node_expand_direct_maps(struct node *n)
+{
+
+ node_expand_maps(n, false);
+}
+
+void
+node_expand_indirect_maps(struct node *n)
+{
+
+ node_expand_maps(n, true);
+}
+
+static char *
+node_path_x(const struct node *n, char *x)
+{
+ char *path;
+ size_t len;
+
+ if (n->n_parent == NULL)
+ return (x);
+
+ /*
+ * Return "/-" for direct maps only if we were asked for path
+ * to the "/-" node itself, not to any of its subnodes.
+ */
+ if (n->n_parent->n_parent == NULL &&
+ strcmp(n->n_key, "/-") == 0 &&
+ x[0] != '\0') {
+ return (x);
+ }
+
+ assert(n->n_key[0] != '\0');
+ path = separated_concat(n->n_key, x, '/');
+ free(x);
+
+ /*
+ * Strip trailing slash.
+ */
+ len = strlen(path);
+ assert(len > 0);
+ if (path[len - 1] == '/')
+ path[len - 1] = '\0';
+
+ return (node_path_x(n->n_parent, path));
+}
+
+/*
+ * Return full path for node, consisting of concatenated
+ * paths of node itself and all its parents, up to the root.
+ */
+char *
+node_path(const struct node *n)
+{
+
+ return (node_path_x(n, checked_strdup("")));
+}
+
+static char *
+node_options_x(const struct node *n, char *x)
+{
+ char *options;
+
+ options = separated_concat(x, n->n_options, ',');
+ if (n->n_parent == NULL)
+ return (options);
+
+ return (node_options_x(n->n_parent, options));
+}
+
+/*
+ * Return options for node, consisting of concatenated
+ * options from the node itself and all its parents,
+ * up to the root.
+ */
+char *
+node_options(const struct node *n)
+{
+
+ return (node_options_x(n, checked_strdup("")));
+}
+
+static void
+node_print_indent(const struct node *n, int indent)
+{
+ const struct node *child, *first_child;
+ char *path, *options;
+
+ path = node_path(n);
+ options = node_options(n);
+
+ /*
+ * Do not show both parent and child node if they have the same
+ * mountpoint; only show the child node. This means the typical,
+ * "key location", map entries are shown in a single line;
+ * the "key mountpoint1 location2 mountpoint2 location2" entries
+ * take multiple lines.
+ */
+ first_child = TAILQ_FIRST(&n->n_children);
+ if (first_child == NULL || TAILQ_NEXT(first_child, n_next) != NULL ||
+ strcmp(path, node_path(first_child)) != 0) {
+ assert(n->n_location == NULL || n->n_map == NULL);
+ printf("%*.s%-*s %s%-*s %-*s # %s map %s at %s:%d\n",
+ indent, "",
+ 25 - indent,
+ path,
+ options[0] != '\0' ? "-" : " ",
+ 20,
+ options[0] != '\0' ? options : "",
+ 20,
+ n->n_location != NULL ? n->n_location : n->n_map != NULL ? n->n_map : "",
+ node_is_direct_map(n) ? "direct" : "indirect",
+ indent == 0 ? "referenced" : "defined",
+ n->n_config_file, n->n_config_line);
+ }
+
+ free(path);
+ free(options);
+
+ TAILQ_FOREACH(child, &n->n_children, n_next)
+ node_print_indent(child, indent + 2);
+}
+
+void
+node_print(const struct node *n)
+{
+ const struct node *child;
+
+ TAILQ_FOREACH(child, &n->n_children, n_next)
+ node_print_indent(child, 0);
+}
+
+struct node *
+node_find(struct node *node, const char *path)
+{
+ struct node *child, *found;
+ char *tmp;
+ size_t tmplen;
+
+ //log_debugx("looking up %s in %s", path, node->n_key);
+
+ tmp = node_path(node);
+ tmplen = strlen(tmp);
+ if (strncmp(tmp, path, tmplen) != 0) {
+ free(tmp);
+ return (NULL);
+ }
+ if (path[tmplen] != '/' && path[tmplen] != '\0') {
+ /*
+ * If we have two map entries like 'foo' and 'foobar', make
+ * sure the search for 'foobar' won't match 'foo' instead.
+ */
+ free(tmp);
+ return (NULL);
+ }
+ free(tmp);
+
+ TAILQ_FOREACH(child, &node->n_children, n_next) {
+ found = node_find(child, path);
+ if (found != NULL)
+ return (found);
+ }
+
+ return (node);
+}
+
+/*
+ * Canonical form of a map entry looks like this:
+ *
+ * key [-options] [ [/mountpoint] [-options2] location ... ]
+ *
+ * Entries for executable maps are slightly different, as they
+ * lack the 'key' field and are always single-line; the key field
+ * for those maps is taken from 'executable_key' argument.
+ *
+ * We parse it in such a way that a map always has two levels - first
+ * for key, and the second, for the mountpoint.
+ */
+static void
+parse_map_yyin(struct node *parent, const char *map, const char *executable_key)
+{
+ char *key = NULL, *options = NULL, *mountpoint = NULL,
+ *options2 = NULL, *location = NULL;
+ int ret;
+ struct node *node;
+
+ lineno = 1;
+
+ if (executable_key != NULL)
+ key = checked_strdup(executable_key);
+
+ for (;;) {
+ ret = yylex();
+ if (ret == 0 || ret == NEWLINE) {
+ /*
+ * In case of executable map, the key is always
+ * non-NULL, even if the map is empty. So, make sure
+ * we don't fail empty maps here.
+ */
+ if ((key != NULL && executable_key == NULL) ||
+ options != NULL) {
+ log_errx(1, "truncated entry at %s, line %d",
+ map, lineno);
+ }
+ if (ret == 0 || executable_key != NULL) {
+ /*
+ * End of file.
+ */
+ break;
+ } else {
+ key = options = NULL;
+ continue;
+ }
+ }
+ if (key == NULL) {
+ key = checked_strdup(yytext);
+ if (key[0] == '+') {
+ node_new(parent, key, NULL, NULL, map, lineno);
+ key = options = NULL;
+ continue;
+ }
+ continue;
+ } else if (yytext[0] == '-') {
+ if (options != NULL) {
+ log_errx(1, "duplicated options at %s, line %d",
+ map, lineno);
+ }
+ /*
+ * +1 to skip leading "-".
+ */
+ options = checked_strdup(yytext + 1);
+ continue;
+ }
+
+ /*
+ * We cannot properly handle a situation where the map key
+ * is "/". Ignore such entries.
+ *
+ * XXX: According to Piete Brooks, Linux automounter uses
+ * "/" as a wildcard character in LDAP maps. Perhaps
+ * we should work around this braindamage by substituting
+ * "*" for "/"?
+ */
+ if (strcmp(key, "/") == 0) {
+ log_warnx("nonsensical map key \"/\" at %s, line %d; "
+ "ignoring map entry ", map, lineno);
+
+ /*
+ * Skip the rest of the entry.
+ */
+ do {
+ ret = yylex();
+ } while (ret != 0 && ret != NEWLINE);
+
+ key = options = NULL;
+ continue;
+ }
+
+ //log_debugx("adding map node, %s", key);
+ node = node_new(parent, key, options, NULL, map, lineno);
+ key = options = NULL;
+
+ for (;;) {
+ if (yytext[0] == '/') {
+ if (mountpoint != NULL) {
+ log_errx(1, "duplicated mountpoint "
+ "in %s, line %d", map, lineno);
+ }
+ if (options2 != NULL || location != NULL) {
+ log_errx(1, "mountpoint out of order "
+ "in %s, line %d", map, lineno);
+ }
+ mountpoint = checked_strdup(yytext);
+ goto again;
+ }
+
+ if (yytext[0] == '-') {
+ if (options2 != NULL) {
+ log_errx(1, "duplicated options "
+ "in %s, line %d", map, lineno);
+ }
+ if (location != NULL) {
+ log_errx(1, "options out of order "
+ "in %s, line %d", map, lineno);
+ }
+ options2 = checked_strdup(yytext + 1);
+ goto again;
+ }
+
+ if (location != NULL) {
+ log_errx(1, "too many arguments "
+ "in %s, line %d", map, lineno);
+ }
+
+ /*
+ * If location field starts with colon, e.g. ":/dev/cd0",
+ * then strip it.
+ */
+ if (yytext[0] == ':') {
+ location = checked_strdup(yytext + 1);
+ if (location[0] == '\0') {
+ log_errx(1, "empty location in %s, "
+ "line %d", map, lineno);
+ }
+ } else {
+ location = checked_strdup(yytext);
+ }
+
+ if (mountpoint == NULL)
+ mountpoint = checked_strdup("/");
+ if (options2 == NULL)
+ options2 = checked_strdup("");
+
+#if 0
+ log_debugx("adding map node, %s %s %s",
+ mountpoint, options2, location);
+#endif
+ node_new(node, mountpoint, options2, location,
+ map, lineno);
+ mountpoint = options2 = location = NULL;
+again:
+ ret = yylex();
+ if (ret == 0 || ret == NEWLINE) {
+ if (mountpoint != NULL || options2 != NULL ||
+ location != NULL) {
+ log_errx(1, "truncated entry "
+ "in %s, line %d", map, lineno);
+ }
+ break;
+ }
+ }
+ }
+}
+
+/*
+ * Parse output of a special map called without argument. It is a list
+ * of keys, separated by newlines. They can contain whitespace, so use
+ * getline(3) instead of lexer used for maps.
+ */
+static void
+parse_map_keys_yyin(struct node *parent, const char *map)
+{
+ char *line = NULL, *key;
+ size_t linecap = 0;
+ ssize_t linelen;
+
+ lineno = 1;
+
+ for (;;) {
+ linelen = getline(&line, &linecap, yyin);
+ if (linelen < 0) {
+ /*
+ * End of file.
+ */
+ break;
+ }
+ if (linelen <= 1) {
+ /*
+ * Empty line, consisting of just the newline.
+ */
+ continue;
+ }
+
+ /*
+ * "-1" to strip the trailing newline.
+ */
+ key = strndup(line, linelen - 1);
+
+ log_debugx("adding key \"%s\"", key);
+ node_new(parent, key, NULL, NULL, map, lineno);
+ lineno++;
+ }
+ free(line);
+}
+
+static bool
+file_is_executable(const char *path)
+{
+ struct stat sb;
+ int error;
+
+ error = stat(path, &sb);
+ if (error != 0)
+ log_err(1, "cannot stat %s", path);
+ if ((sb.st_mode & S_IXUSR) || (sb.st_mode & S_IXGRP) ||
+ (sb.st_mode & S_IXOTH))
+ return (true);
+ return (false);
+}
+
+/*
+ * Parse a special map, e.g. "-hosts".
+ */
+static void
+parse_special_map(struct node *parent, const char *map, const char *key)
+{
+ char *path;
+ int error, ret;
+
+ assert(map[0] == '-');
+
+ /*
+ * +1 to skip leading "-" in map name.
+ */
+ ret = asprintf(&path, "%s/special_%s", AUTO_SPECIAL_PREFIX, map + 1);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ yyin = auto_popen(path, key, NULL);
+ assert(yyin != NULL);
+
+ if (key == NULL) {
+ parse_map_keys_yyin(parent, map);
+ } else {
+ parse_map_yyin(parent, map, key);
+ }
+
+ error = auto_pclose(yyin);
+ yyin = NULL;
+ if (error != 0)
+ log_errx(1, "failed to handle special map \"%s\"", map);
+
+ node_expand_includes(parent, false);
+ node_expand_direct_maps(parent);
+
+ free(path);
+}
+
+/*
+ * Retrieve and parse map from directory services, e.g. LDAP.
+ * Note that it is different from executable maps, in that
+ * the include script outputs the whole map to standard output
+ * (as opposed to executable maps that only output a single
+ * entry, without the key), and it takes the map name as an
+ * argument, instead of key.
+ */
+static void
+parse_included_map(struct node *parent, const char *map)
+{
+ int error;
+
+ assert(map[0] != '-');
+ assert(map[0] != '/');
+
+ error = access(AUTO_INCLUDE_PATH, F_OK);
+ if (error != 0) {
+ log_errx(1, "directory services not configured;"
+ " %s does not exist", AUTO_INCLUDE_PATH);
+ }
+
+ yyin = auto_popen(AUTO_INCLUDE_PATH, map, NULL);
+ assert(yyin != NULL);
+
+ parse_map_yyin(parent, map, NULL);
+
+ error = auto_pclose(yyin);
+ yyin = NULL;
+ if (error != 0)
+ log_errx(1, "failed to handle remote map \"%s\"", map);
+
+ node_expand_includes(parent, false);
+ node_expand_direct_maps(parent);
+}
+
+void
+parse_map(struct node *parent, const char *map, const char *key,
+ bool *wildcards)
+{
+ char *path = NULL;
+ int error, ret;
+ bool executable;
+
+ assert(map != NULL);
+ assert(map[0] != '\0');
+
+ log_debugx("parsing map \"%s\"", map);
+
+ if (wildcards != NULL)
+ *wildcards = false;
+
+ if (map[0] == '-') {
+ if (wildcards != NULL)
+ *wildcards = true;
+ return (parse_special_map(parent, map, key));
+ }
+
+ if (map[0] == '/') {
+ path = checked_strdup(map);
+ } else {
+ ret = asprintf(&path, "%s/%s", AUTO_MAP_PREFIX, map);
+ if (ret < 0)
+ log_err(1, "asprintf");
+ log_debugx("map \"%s\" maps to \"%s\"", map, path);
+
+ /*
+ * See if the file exists. If not, try to obtain the map
+ * from directory services.
+ */
+ error = access(path, F_OK);
+ if (error != 0) {
+ log_debugx("map file \"%s\" does not exist; falling "
+ "back to directory services", path);
+ return (parse_included_map(parent, map));
+ }
+ }
+
+ executable = file_is_executable(path);
+
+ if (executable) {
+ log_debugx("map \"%s\" is executable", map);
+
+ if (wildcards != NULL)
+ *wildcards = true;
+
+ if (key != NULL) {
+ yyin = auto_popen(path, key, NULL);
+ } else {
+ yyin = auto_popen(path, NULL);
+ }
+ assert(yyin != NULL);
+ } else {
+ yyin = fopen(path, "r");
+ if (yyin == NULL)
+ log_err(1, "unable to open \"%s\"", path);
+ }
+
+ free(path);
+ path = NULL;
+
+ parse_map_yyin(parent, map, executable ? key : NULL);
+
+ if (executable) {
+ error = auto_pclose(yyin);
+ yyin = NULL;
+ if (error != 0) {
+ log_errx(1, "failed to handle executable map \"%s\"",
+ map);
+ }
+ } else {
+ fclose(yyin);
+ }
+ yyin = NULL;
+
+ log_debugx("done parsing map \"%s\"", map);
+
+ node_expand_includes(parent, false);
+ node_expand_direct_maps(parent);
+}
+
+static void
+parse_master_yyin(struct node *root, const char *master)
+{
+ char *mountpoint = NULL, *map = NULL, *options = NULL;
+ int ret;
+
+ /*
+ * XXX: 1 gives incorrect values; wtf?
+ */
+ lineno = 0;
+
+ for (;;) {
+ ret = yylex();
+ if (ret == 0 || ret == NEWLINE) {
+ if (mountpoint != NULL) {
+ //log_debugx("adding map for %s", mountpoint);
+ node_new_map(root, mountpoint, options, map,
+ master, lineno);
+ }
+ if (ret == 0) {
+ break;
+ } else {
+ mountpoint = map = options = NULL;
+ continue;
+ }
+ }
+ if (mountpoint == NULL) {
+ mountpoint = checked_strdup(yytext);
+ } else if (map == NULL) {
+ map = checked_strdup(yytext);
+ } else if (options == NULL) {
+ /*
+ * +1 to skip leading "-".
+ */
+ options = checked_strdup(yytext + 1);
+ } else {
+ log_errx(1, "too many arguments at %s, line %d",
+ master, lineno);
+ }
+ }
+}
+
+void
+parse_master(struct node *root, const char *master)
+{
+
+ log_debugx("parsing auto_master file at \"%s\"", master);
+
+ yyin = fopen(master, "r");
+ if (yyin == NULL)
+ err(1, "unable to open %s", master);
+
+ parse_master_yyin(root, master);
+
+ fclose(yyin);
+ yyin = NULL;
+
+ log_debugx("done parsing \"%s\"", master);
+
+ node_expand_includes(root, true);
+ node_expand_direct_maps(root);
+}
+
+/*
+ * Two things daemon(3) does, that we actually also want to do
+ * when running in foreground, is closing the stdin and chdiring
+ * to "/". This is what we do here.
+ */
+void
+lesser_daemon(void)
+{
+ int error, fd;
+
+ error = chdir("/");
+ if (error != 0)
+ log_warn("chdir");
+
+ fd = open(_PATH_DEVNULL, O_RDWR, 0);
+ if (fd < 0) {
+ log_warn("cannot open %s", _PATH_DEVNULL);
+ return;
+ }
+
+ error = dup2(fd, STDIN_FILENO);
+ if (error != 0)
+ log_warn("dup2");
+
+ error = close(fd);
+ if (error != 0) {
+ /* Bloody hell. */
+ log_warn("close");
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ char *cmdname;
+
+ if (argv[0] == NULL)
+ log_errx(1, "NULL command name");
+
+ cmdname = basename(argv[0]);
+
+ if (strcmp(cmdname, "automount") == 0)
+ return (main_automount(argc, argv));
+ else if (strcmp(cmdname, "automountd") == 0)
+ return (main_automountd(argc, argv));
+ else if (strcmp(cmdname, "autounmountd") == 0)
+ return (main_autounmountd(argc, argv));
+ else
+ log_errx(1, "binary name should be either \"automount\", "
+ "\"automountd\", or \"autounmountd\"");
+}
diff --git a/usr.sbin/autofs/common.h b/usr.sbin/autofs/common.h
new file mode 100644
index 0000000..16a8d73
--- /dev/null
+++ b/usr.sbin/autofs/common.h
@@ -0,0 +1,114 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef AUTOMOUNTD_H
+#define AUTOMOUNTD_H
+
+#include <sys/queue.h>
+#include <stdbool.h>
+
+#define AUTO_MASTER_PATH "/etc/auto_master"
+#define AUTO_MAP_PREFIX "/etc"
+#define AUTO_SPECIAL_PREFIX "/etc/autofs"
+#define AUTO_INCLUDE_PATH AUTO_SPECIAL_PREFIX "/include"
+
+struct node {
+ TAILQ_ENTRY(node) n_next;
+ TAILQ_HEAD(nodehead, node) n_children;
+ struct node *n_parent;
+ char *n_key;
+ char *n_options;
+ char *n_location;
+ char *n_map;
+ const char *n_config_file;
+ int n_config_line;
+};
+
+struct defined_value {
+ TAILQ_ENTRY(defined_value) d_next;
+ char *d_name;
+ char *d_value;
+};
+
+void log_init(int level);
+void log_set_peer_name(const char *name);
+void log_set_peer_addr(const char *addr);
+void log_err(int, const char *, ...)
+ __dead2 __printf0like(2, 3);
+void log_errx(int, const char *, ...)
+ __dead2 __printf0like(2, 3);
+void log_warn(const char *, ...) __printf0like(1, 2);
+void log_warnx(const char *, ...) __printflike(1, 2);
+void log_debugx(const char *, ...) __printf0like(1, 2);
+
+char *checked_strdup(const char *);
+char *separated_concat(const char *s1, const char *s2, char separator);
+void create_directory(const char *path);
+
+struct node *node_new_root(void);
+struct node *node_new(struct node *parent, char *key, char *options,
+ char *location, const char *config_file, int config_line);
+struct node *node_new_map(struct node *parent, char *key, char *options,
+ char *map, const char *config_file, int config_line);
+struct node *node_find(struct node *root, const char *mountpoint);
+bool node_is_direct_map(const struct node *n);
+bool node_has_wildcards(const struct node *n);
+char *node_path(const struct node *n);
+char *node_options(const struct node *n);
+void node_expand_ampersand(struct node *root, const char *key);
+void node_expand_wildcard(struct node *root, const char *key);
+int node_expand_defined(struct node *root);
+void node_expand_indirect_maps(struct node *n);
+void node_print(const struct node *n);
+void parse_master(struct node *root, const char *path);
+void parse_map(struct node *parent, const char *map, const char *args,
+ bool *wildcards);
+char *defined_expand(const char *string);
+void defined_init(void);
+void defined_parse_and_add(char *def);
+void lesser_daemon(void);
+
+int main_automount(int argc, char **argv);
+int main_automountd(int argc, char **argv);
+int main_autounmountd(int argc, char **argv);
+
+FILE *auto_popen(const char *argv0, ...);
+int auto_pclose(FILE *iop);
+
+/*
+ * lex(1) stuff.
+ */
+extern int lineno;
+
+#define STR 1
+#define NEWLINE 2
+
+#endif /* !AUTOMOUNTD_H */
diff --git a/usr.sbin/autofs/defined.c b/usr.sbin/autofs/defined.c
new file mode 100644
index 0000000..eaaea28
--- /dev/null
+++ b/usr.sbin/autofs/defined.c
@@ -0,0 +1,272 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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.
+ *
+ */
+
+/*
+ * All the "defined" stuff is for handling variables,
+ * such as ${OSNAME}, in maps.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/linker.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+#include "common.h"
+
+static TAILQ_HEAD(, defined_value) defined_values;
+
+static const char *
+defined_find(const char *name)
+{
+ struct defined_value *d;
+
+ TAILQ_FOREACH(d, &defined_values, d_next) {
+ if (strcmp(d->d_name, name) == 0)
+ return (d->d_value);
+ }
+
+ return (NULL);
+}
+
+char *
+defined_expand(const char *string)
+{
+ const char *value;
+ char c, *expanded, *name;
+ int i, ret, before_len = 0, name_off = 0, name_len = 0, after_off = 0;
+ bool backslashed = false, bracketed = false;
+
+ expanded = checked_strdup(string);
+
+ for (i = 0; string[i] != '\0'; i++) {
+ c = string[i];
+ if (c == '\\' && backslashed == false) {
+ backslashed = true;
+ continue;
+ }
+ if (backslashed) {
+ backslashed = false;
+ continue;
+ }
+ backslashed = false;
+ if (c != '$')
+ continue;
+
+ /*
+ * The 'before_len' variable contains the number
+ * of characters before the '$'.
+ */
+ before_len = i;
+ assert(i + 1 < (int)strlen(string));
+ if (string[i + 1] == '{')
+ bracketed = true;
+
+ if (string[i + 1] == '\0') {
+ log_warnx("truncated variable");
+ return (NULL);
+ }
+
+ /*
+ * Skip '$'.
+ */
+ i++;
+
+ if (bracketed) {
+ if (string[i + 1] == '\0') {
+ log_warnx("truncated variable");
+ return (NULL);
+ }
+
+ /*
+ * Skip '{'.
+ */
+ i++;
+ }
+
+ /*
+ * The 'name_off' variable contains the number
+ * of characters before the variable name,
+ * including the "$" or "${".
+ */
+ name_off = i;
+
+ for (; string[i] != '\0'; i++) {
+ c = string[i];
+ /*
+ * XXX: Decide on the set of characters that can be
+ * used in a variable name.
+ */
+ if (isalnum(c) || c == '_')
+ continue;
+
+ /*
+ * End of variable name.
+ */
+ if (bracketed) {
+ if (c != '}')
+ continue;
+
+ /*
+ * The 'after_off' variable contains the number
+ * of characters before the rest of the string,
+ * i.e. after the variable name.
+ */
+ after_off = i + 1;
+ assert(i > 1);
+ assert(i - 1 > name_off);
+ name_len = i - name_off;
+ break;
+ }
+
+ after_off = i;
+ assert(i > 1);
+ assert(i > name_off);
+ name_len = i - name_off;
+ break;
+ }
+
+ name = strndup(string + name_off, name_len);
+ if (name == NULL)
+ log_err(1, "strndup");
+ value = defined_find(name);
+ if (value == NULL) {
+ log_warnx("undefined variable ${%s}", name);
+ return (NULL);
+ }
+
+ /*
+ * Concatenate it back.
+ */
+ ret = asprintf(&expanded, "%.*s%s%s",
+ before_len, string, value, string + after_off);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ //log_debugx("\"%s\" expanded to \"%s\"", string, expanded);
+ free(name);
+
+ /*
+ * Figure out where to start searching for next variable.
+ */
+ string = expanded;
+ i = before_len + strlen(value);
+ backslashed = bracketed = false;
+ before_len = name_off = name_len = after_off = 0;
+ assert(i <= (int)strlen(string));
+ }
+
+ if (before_len != 0 || name_off != 0 || name_len != 0 || after_off != 0) {
+ log_warnx("truncated variable");
+ return (NULL);
+ }
+
+ return (expanded);
+}
+
+static void
+defined_add(const char *name, const char *value)
+{
+ struct defined_value *d;
+ const char *found;
+
+ found = defined_find(name);
+ if (found != NULL)
+ log_errx(1, "variable %s already defined", name);
+
+ log_debugx("defining variable %s=%s", name, value);
+
+ d = calloc(sizeof(*d), 1);
+ if (d == NULL)
+ log_err(1, "calloc");
+ d->d_name = checked_strdup(name);
+ d->d_value = checked_strdup(value);
+
+ TAILQ_INSERT_TAIL(&defined_values, d, d_next);
+}
+
+void
+defined_parse_and_add(char *def)
+{
+ char *name, *value;
+
+ value = def;
+ name = strsep(&value, "=");
+
+ if (value == NULL || value[0] == '\0')
+ log_errx(1, "missing variable value");
+ if (name == NULL || name[0] == '\0')
+ log_errx(1, "missing variable name");
+
+ defined_add(name, value);
+}
+
+void
+defined_init(void)
+{
+ struct utsname name;
+ int error;
+
+ TAILQ_INIT(&defined_values);
+
+ error = uname(&name);
+ if (error != 0)
+ log_err(1, "uname");
+
+ defined_add("ARCH", name.machine);
+ defined_add("CPU", name.machine);
+ defined_add("HOST", name.nodename);
+ defined_add("OSNAME", name.sysname);
+ defined_add("OSREL", name.release);
+ defined_add("OSVERS", name.version);
+}
diff --git a/usr.sbin/autofs/log.c b/usr.sbin/autofs/log.c
new file mode 100644
index 0000000..d5682cc
--- /dev/null
+++ b/usr.sbin/autofs/log.c
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2012 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <vis.h>
+
+#include "common.h"
+
+static int log_level = 0;
+static char *peer_name = NULL;
+static char *peer_addr = NULL;
+
+#define MSGBUF_LEN 1024
+
+void
+log_init(int level)
+{
+
+ log_level = level;
+ openlog(getprogname(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
+}
+
+void
+log_set_peer_name(const char *name)
+{
+
+ /*
+ * XXX: Turn it into assertion?
+ */
+ if (peer_name != NULL)
+ log_errx(1, "%s called twice", __func__);
+ if (peer_addr == NULL)
+ log_errx(1, "%s called before log_set_peer_addr", __func__);
+
+ peer_name = checked_strdup(name);
+}
+
+void
+log_set_peer_addr(const char *addr)
+{
+
+ /*
+ * XXX: Turn it into assertion?
+ */
+ if (peer_addr != NULL)
+ log_errx(1, "%s called twice", __func__);
+
+ peer_addr = checked_strdup(addr);
+}
+
+static void
+log_common(int priority, int log_errno, const char *fmt, va_list ap)
+{
+ static char msgbuf[MSGBUF_LEN];
+ static char msgbuf_strvised[MSGBUF_LEN * 4 + 1];
+ int ret;
+
+ ret = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
+ if (ret < 0) {
+ fprintf(stderr, "%s: snprintf failed", getprogname());
+ syslog(LOG_CRIT, "snprintf failed");
+ exit(1);
+ }
+
+ ret = strnvis(msgbuf_strvised, sizeof(msgbuf_strvised), msgbuf, VIS_NL);
+ if (ret < 0) {
+ fprintf(stderr, "%s: strnvis failed", getprogname());
+ syslog(LOG_CRIT, "strnvis failed");
+ exit(1);
+ }
+
+ if (log_errno == -1) {
+ if (peer_name != NULL) {
+ fprintf(stderr, "%s: %s (%s): %s\n", getprogname(),
+ peer_addr, peer_name, msgbuf_strvised);
+ syslog(priority, "%s (%s): %s",
+ peer_addr, peer_name, msgbuf_strvised);
+ } else if (peer_addr != NULL) {
+ fprintf(stderr, "%s: %s: %s\n", getprogname(),
+ peer_addr, msgbuf_strvised);
+ syslog(priority, "%s: %s",
+ peer_addr, msgbuf_strvised);
+ } else {
+ fprintf(stderr, "%s: %s\n", getprogname(), msgbuf_strvised);
+ syslog(priority, "%s", msgbuf_strvised);
+ }
+
+ } else {
+ if (peer_name != NULL) {
+ fprintf(stderr, "%s: %s (%s): %s: %s\n", getprogname(),
+ peer_addr, peer_name, msgbuf_strvised, strerror(errno));
+ syslog(priority, "%s (%s): %s: %s",
+ peer_addr, peer_name, msgbuf_strvised, strerror(errno));
+ } else if (peer_addr != NULL) {
+ fprintf(stderr, "%s: %s: %s: %s\n", getprogname(),
+ peer_addr, msgbuf_strvised, strerror(errno));
+ syslog(priority, "%s: %s: %s",
+ peer_addr, msgbuf_strvised, strerror(errno));
+ } else {
+ fprintf(stderr, "%s: %s: %s\n", getprogname(),
+ msgbuf_strvised, strerror(errno));
+ syslog(priority, "%s: %s",
+ msgbuf_strvised, strerror(errno));
+ }
+ }
+}
+
+void
+log_err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ log_common(LOG_CRIT, errno, fmt, ap);
+ va_end(ap);
+
+ exit(eval);
+}
+
+void
+log_errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ log_common(LOG_CRIT, -1, fmt, ap);
+ va_end(ap);
+
+ exit(eval);
+}
+
+void
+log_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ log_common(LOG_WARNING, errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+log_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ log_common(LOG_WARNING, -1, fmt, ap);
+ va_end(ap);
+}
+
+void
+log_debugx(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (log_level == 0)
+ return;
+
+ va_start(ap, fmt);
+ log_common(LOG_DEBUG, -1, fmt, ap);
+ va_end(ap);
+}
diff --git a/usr.sbin/autofs/popen.c b/usr.sbin/autofs/popen.c
new file mode 100644
index 0000000..6cd964d
--- /dev/null
+++ b/usr.sbin/autofs/popen.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This code is derived from software written by Ken Arnold and
+ * published in UNIX Review, Vol. 6, No. 8.
+ *
+ * Portions of this software were developed by Edward Tomasz Napierala
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/wait.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <paths.h>
+
+#include "common.h"
+
+extern char **environ;
+
+struct pid {
+ SLIST_ENTRY(pid) next;
+ FILE *outfp;
+ pid_t pid;
+ char *command;
+};
+static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist);
+
+#define ARGV_LEN 42
+
+/*
+ * Replacement for popen(3), without stdin (which we do not use), but with
+ * stderr, proper logging, and improved command line arguments passing.
+ * Error handling is built in - if it returns, then it succeeded.
+ */
+FILE *
+auto_popen(const char *argv0, ...)
+{
+ va_list ap;
+ struct pid *cur, *p;
+ pid_t pid;
+ int error, i, nullfd, outfds[2];
+ char *arg, *argv[ARGV_LEN], *command;
+
+ nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
+ if (nullfd < 0)
+ log_err(1, "cannot open %s", _PATH_DEVNULL);
+
+ error = pipe(outfds);
+ if (error != 0)
+ log_err(1, "pipe");
+
+ cur = malloc(sizeof(struct pid));
+ if (cur == NULL)
+ log_err(1, "malloc");
+
+ argv[0] = checked_strdup(argv0);
+ command = argv[0];
+
+ va_start(ap, argv0);
+ for (i = 1;; i++) {
+ if (i >= ARGV_LEN)
+ log_errx(1, "too many arguments to auto_popen");
+ arg = va_arg(ap, char *);
+ argv[i] = arg;
+ if (arg == NULL)
+ break;
+
+ command = separated_concat(command, arg, ' ');
+ }
+ va_end(ap);
+
+ cur->command = checked_strdup(command);
+
+ switch (pid = fork()) {
+ case -1: /* Error. */
+ log_err(1, "fork");
+ /* NOTREACHED */
+ case 0: /* Child. */
+ dup2(nullfd, STDIN_FILENO);
+ dup2(outfds[1], STDOUT_FILENO);
+
+ close(nullfd);
+ close(outfds[0]);
+ close(outfds[1]);
+
+ SLIST_FOREACH(p, &pidlist, next)
+ close(fileno(p->outfp));
+ execvp(argv[0], argv);
+ log_err(1, "failed to execute %s", argv[0]);
+ /* NOTREACHED */
+ }
+
+ log_debugx("executing \"%s\" as pid %d", command, pid);
+
+ /* Parent; assume fdopen cannot fail. */
+ cur->outfp = fdopen(outfds[0], "r");
+ close(nullfd);
+ close(outfds[1]);
+
+ /* Link into list of file descriptors. */
+ cur->pid = pid;
+ SLIST_INSERT_HEAD(&pidlist, cur, next);
+
+ return (cur->outfp);
+}
+
+int
+auto_pclose(FILE *iop)
+{
+ struct pid *cur, *last = NULL;
+ int status;
+ pid_t pid;
+
+ /*
+ * Find the appropriate file pointer and remove it from the list.
+ */
+ SLIST_FOREACH(cur, &pidlist, next) {
+ if (cur->outfp == iop)
+ break;
+ last = cur;
+ }
+ if (cur == NULL) {
+ return (-1);
+ }
+ if (last == NULL)
+ SLIST_REMOVE_HEAD(&pidlist, next);
+ else
+ SLIST_REMOVE_AFTER(last, next);
+
+ fclose(cur->outfp);
+
+ do {
+ pid = wait4(cur->pid, &status, 0, NULL);
+ } while (pid == -1 && errno == EINTR);
+
+ if (WIFSIGNALED(status)) {
+ log_warnx("\"%s\", pid %d, terminated with signal %d",
+ cur->command, pid, WTERMSIG(status));
+ return (status);
+ }
+
+ if (WEXITSTATUS(status) != 0) {
+ log_warnx("\"%s\", pid %d, terminated with exit status %d",
+ cur->command, pid, WEXITSTATUS(status));
+ return (status);
+ }
+
+ log_debugx("\"%s\", pid %d, terminated gracefully", cur->command, pid);
+
+ free(cur->command);
+ free(cur);
+
+ return (pid == -1 ? -1 : status);
+}
diff --git a/usr.sbin/pkg/elf_tables.h b/usr.sbin/autofs/token.l
index 55fd3bb..6a92b7f 100644
--- a/usr.sbin/pkg/elf_tables.h
+++ b/usr.sbin/autofs/token.l
@@ -1,8 +1,11 @@
+%{
/*-
- * Copyright (c) 2012 Olivier Houchard <cognet@FreeBSD.org>
- * Copyright (c) 2012 Baptiste Daroussin <bapt@FreeBSD.org>
+ * Copyright (c) 2014 The FreeBSD Foundation
* All rights reserved.
- *
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -11,7 +14,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.
- *
+ *
* 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
@@ -27,43 +30,29 @@
* $FreeBSD$
*/
-#ifndef ELF_TABLES_H_
-#define ELF_TABLES_H_
-struct _elf_corres {
- int elf_nb;
- const char *string;
-};
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
-static struct _elf_corres mach_corres[] = {
- { EM_386, "x86" },
- { EM_AMD64, "x86" },
- { EM_ARM, "arm" },
- { EM_MIPS, "mips" },
- { EM_PPC, "powerpc" },
- { EM_PPC64, "powerpc" },
- { EM_SPARCV9, "sparc64" },
- { -1, NULL },
-};
+#include "common.h"
-static struct _elf_corres wordsize_corres[] = {
- { ELFCLASS32, "32" },
- { ELFCLASS64, "64" },
- { -1, NULL},
-};
+int lineno;
-static struct _elf_corres endian_corres[] = {
- { ELFDATA2MSB, "eb" },
- { ELFDATA2LSB, "el" },
- { -1, NULL}
-};
+#define YY_DECL int yylex(void)
+extern int yylex(void);
-#ifndef EF_MIPS_ABI
-#define EF_MIPS_ABI 0x0000f000
-#endif
-#define E_MIPS_ABI_O32 0x00001000
-#define E_MIPS_ABI_N32 0x00000020
+%}
-#define NT_VERSION 1
-#define NT_ARCH 2
+%option noinput
+%option nounput
+%option noyywrap
-#endif /* ELF_TABLES_H_ */
+%%
+\"[^"]+\" { yytext++; yytext[strlen(yytext) - 1] = '\0'; return STR; };
+[a-zA-Z0-9\.\+-_/\:\[\]$&%{}]+ { return STR; }
+#.*\n { lineno++; return NEWLINE; };
+\\\n { lineno++; };
+\n { lineno++; return NEWLINE; }
+[ \t]+ /* ignore whitespace */;
+. { return STR; }
+%%
diff --git a/usr.sbin/bhyve/Makefile b/usr.sbin/bhyve/Makefile
index 1c95f77..377a2e6 100644
--- a/usr.sbin/bhyve/Makefile
+++ b/usr.sbin/bhyve/Makefile
@@ -31,7 +31,6 @@ SRCS= \
pci_virtio_rnd.c \
pci_uart.c \
pm.c \
- pmtmr.c \
post.c \
rtc.c \
smbiostbl.c \
diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c
index c4ec020..a5a6559 100644
--- a/usr.sbin/bhyve/acpi.c
+++ b/usr.sbin/bhyve/acpi.c
@@ -40,12 +40,13 @@
* Layout
* ------
* RSDP -> 0xf2400 (36 bytes fixed)
- * RSDT -> 0xf2440 (36 bytes + 4*N table addrs, 2 used)
- * XSDT -> 0xf2480 (36 bytes + 8*N table addrs, 2 used)
+ * RSDT -> 0xf2440 (36 bytes + 4*7 table addrs, 4 used)
+ * XSDT -> 0xf2480 (36 bytes + 8*7 table addrs, 4 used)
* MADT -> 0xf2500 (depends on #CPUs)
* FADT -> 0xf2600 (268 bytes)
* HPET -> 0xf2740 (56 bytes)
- * FACS -> 0xf2780 (64 bytes)
+ * MCFG -> 0xf2780 (60 bytes)
+ * FACS -> 0xf27C0 (64 bytes)
* DSDT -> 0xf2800 (variable - can go up to 0x100000)
*/
@@ -80,7 +81,8 @@ __FBSDID("$FreeBSD$");
#define MADT_OFFSET 0x100
#define FADT_OFFSET 0x200
#define HPET_OFFSET 0x340
-#define FACS_OFFSET 0x380
+#define MCFG_OFFSET 0x380
+#define FACS_OFFSET 0x3C0
#define DSDT_OFFSET 0x400
#define BHYVE_ASL_TEMPLATE "bhyve.XXXXXXX"
@@ -178,6 +180,8 @@ basl_fwrite_rsdt(FILE *fp)
basl_acpi_base + FADT_OFFSET);
EFPRINTF(fp, "[0004]\t\tACPI Table Address 2 : %08X\n",
basl_acpi_base + HPET_OFFSET);
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address 3 : %08X\n",
+ basl_acpi_base + MCFG_OFFSET);
EFFLUSH(fp);
@@ -216,6 +220,8 @@ basl_fwrite_xsdt(FILE *fp)
basl_acpi_base + FADT_OFFSET);
EFPRINTF(fp, "[0004]\t\tACPI Table Address 2 : 00000000%08X\n",
basl_acpi_base + HPET_OFFSET);
+ EFPRINTF(fp, "[0004]\t\tACPI Table Address 3 : 00000000%08X\n",
+ basl_acpi_base + MCFG_OFFSET);
EFFLUSH(fp);
@@ -424,7 +430,10 @@ basl_fwrite_fadt(FILE *fp)
EFPRINTF(fp, "\n");
EFPRINTF(fp, "[0001]\t\tValue to cause reset : 06\n");
- EFPRINTF(fp, "[0003]\t\tReserved : 000000\n");
+ EFPRINTF(fp, "[0002]\t\tARM Flags (decoded below): 0000\n");
+ EFPRINTF(fp, "\t\t\tPSCI Compliant : 0\n");
+ EFPRINTF(fp, "\t\t\tMust use HVC for PSCI : 0\n");
+ EFPRINTF(fp, "[0001]\t\tFADT Minor Revision : 01\n");
EFPRINTF(fp, "[0008]\t\tFACS Address : 00000000%08X\n",
basl_acpi_base + FACS_OFFSET);
EFPRINTF(fp, "[0008]\t\tDSDT Address : 00000000%08X\n",
@@ -483,7 +492,7 @@ basl_fwrite_fadt(FILE *fp)
EFPRINTF(fp,
"[0012]\t\tPM Timer Block : [Generic Address Structure]\n");
EFPRINTF(fp, "[0001]\t\tSpace ID : 01 [SystemIO]\n");
- EFPRINTF(fp, "[0001]\t\tBit Width : 32\n");
+ EFPRINTF(fp, "[0001]\t\tBit Width : 20\n");
EFPRINTF(fp, "[0001]\t\tBit Offset : 00\n");
EFPRINTF(fp,
"[0001]\t\tEncoded Access Width : 03 [DWord Access:32]\n");
@@ -493,7 +502,7 @@ basl_fwrite_fadt(FILE *fp)
EFPRINTF(fp, "[0012]\t\tGPE0 Block : [Generic Address Structure]\n");
EFPRINTF(fp, "[0001]\t\tSpace ID : 01 [SystemIO]\n");
- EFPRINTF(fp, "[0001]\t\tBit Width : 80\n");
+ EFPRINTF(fp, "[0001]\t\tBit Width : 00\n");
EFPRINTF(fp, "[0001]\t\tBit Offset : 00\n");
EFPRINTF(fp, "[0001]\t\tEncoded Access Width : 01 [Byte Access:8]\n");
EFPRINTF(fp, "[0008]\t\tAddress : 0000000000000000\n");
@@ -583,6 +592,39 @@ err_exit:
}
static int
+basl_fwrite_mcfg(FILE *fp)
+{
+ int err = 0;
+
+ EFPRINTF(fp, "/*\n");
+ EFPRINTF(fp, " * bhyve MCFG template\n");
+ EFPRINTF(fp, " */\n");
+ EFPRINTF(fp, "[0004]\t\tSignature : \"MCFG\"\n");
+ EFPRINTF(fp, "[0004]\t\tTable Length : 00000000\n");
+ EFPRINTF(fp, "[0001]\t\tRevision : 01\n");
+ EFPRINTF(fp, "[0001]\t\tChecksum : 00\n");
+ EFPRINTF(fp, "[0006]\t\tOem ID : \"BHYVE \"\n");
+ EFPRINTF(fp, "[0008]\t\tOem Table ID : \"BVMCFG \"\n");
+ EFPRINTF(fp, "[0004]\t\tOem Revision : 00000001\n");
+
+ /* iasl will fill in the compiler ID/revision fields */
+ EFPRINTF(fp, "[0004]\t\tAsl Compiler ID : \"xxxx\"\n");
+ EFPRINTF(fp, "[0004]\t\tAsl Compiler Revision : 00000000\n");
+ EFPRINTF(fp, "[0008]\t\tReserved : 0\n");
+ EFPRINTF(fp, "\n");
+
+ EFPRINTF(fp, "[0008]\t\tBase Address : %016lX\n", pci_ecfg_base());
+ EFPRINTF(fp, "[0002]\t\tSegment Group: 0000\n");
+ EFPRINTF(fp, "[0001]\t\tStart Bus: 00\n");
+ EFPRINTF(fp, "[0001]\t\tEnd Bus: FF\n");
+ EFPRINTF(fp, "[0004]\t\tReserved : 0\n");
+ EFFLUSH(fp);
+ return (0);
+err_exit:
+ return (errno);
+}
+
+static int
basl_fwrite_facs(FILE *fp)
{
int err;
@@ -921,6 +963,7 @@ static struct {
{ basl_fwrite_madt, MADT_OFFSET },
{ basl_fwrite_fadt, FADT_OFFSET },
{ basl_fwrite_hpet, HPET_OFFSET },
+ { basl_fwrite_mcfg, MCFG_OFFSET },
{ basl_fwrite_facs, FACS_OFFSET },
{ basl_fwrite_dsdt, DSDT_OFFSET },
{ NULL }
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 114aaf1..755fa33 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 26, 2014
+.Dd September 17, 2014
.Dt BHYVE 8
.Os
.Sh NAME
@@ -43,7 +43,7 @@
.Ar vmname
.Sh DESCRIPTION
.Nm
-is an experimental hypervisor that runs guest operating systems inside a
+is a hypervisor that runs guest operating systems inside a
virtual machine.
.Pp
Parameters such as the number of virtual CPUs, amount of guest memory, and
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index 7dcf6d0..5971993 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -445,6 +445,20 @@ vmexit_vmx(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
}
static int
+vmexit_svm(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
+{
+
+ fprintf(stderr, "vm exit[%d]\n", *pvcpu);
+ fprintf(stderr, "\treason\t\tSVM\n");
+ fprintf(stderr, "\trip\t\t0x%016lx\n", vmexit->rip);
+ fprintf(stderr, "\tinst_length\t%d\n", vmexit->inst_length);
+ fprintf(stderr, "\texitcode\t%#lx\n", vmexit->u.svm.exitcode);
+ fprintf(stderr, "\texitinfo1\t%#lx\n", vmexit->u.svm.exitinfo1);
+ fprintf(stderr, "\texitinfo2\t%#lx\n", vmexit->u.svm.exitinfo2);
+ return (VMEXIT_ABORT);
+}
+
+static int
vmexit_bogus(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
{
@@ -555,6 +569,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
[VM_EXITCODE_INOUT] = vmexit_inout,
[VM_EXITCODE_INOUT_STR] = vmexit_inout,
[VM_EXITCODE_VMX] = vmexit_vmx,
+ [VM_EXITCODE_SVM] = vmexit_svm,
[VM_EXITCODE_BOGUS] = vmexit_bogus,
[VM_EXITCODE_RDMSR] = vmexit_rdmsr,
[VM_EXITCODE_WRMSR] = vmexit_wrmsr,
@@ -803,6 +818,12 @@ main(int argc, char *argv[])
exit(1);
}
+ error = init_msr();
+ if (error) {
+ fprintf(stderr, "init_msr error %d", error);
+ exit(1);
+ }
+
init_mem();
init_inout();
pci_irq_init(ctx);
diff --git a/usr.sbin/bhyve/block_if.c b/usr.sbin/bhyve/block_if.c
index 1ec0344..8687e9a 100644
--- a/usr.sbin/bhyve/block_if.c
+++ b/usr.sbin/bhyve/block_if.c
@@ -43,25 +43,30 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <pthread.h>
#include <pthread_np.h>
+#include <signal.h>
#include <unistd.h>
+#include <machine/atomic.h>
+
#include "bhyverun.h"
+#include "mevent.h"
#include "block_if.h"
#define BLOCKIF_SIG 0xb109b109
-#define BLOCKIF_MAXREQ 32
+#define BLOCKIF_MAXREQ 33
enum blockop {
BOP_READ,
BOP_WRITE,
- BOP_FLUSH,
- BOP_CANCEL
+ BOP_FLUSH
};
enum blockstat {
BST_FREE,
- BST_INUSE
+ BST_PEND,
+ BST_BUSY,
+ BST_DONE
};
struct blockif_elem {
@@ -69,6 +74,7 @@ struct blockif_elem {
struct blockif_req *be_req;
enum blockop be_op;
enum blockstat be_status;
+ pthread_t be_tid;
};
struct blockif_ctxt {
@@ -82,13 +88,25 @@ struct blockif_ctxt {
pthread_cond_t bc_cond;
int bc_closing;
- /* Request elements and free/inuse queues */
+ /* Request elements and free/pending/busy queues */
TAILQ_HEAD(, blockif_elem) bc_freeq;
- TAILQ_HEAD(, blockif_elem) bc_inuseq;
+ TAILQ_HEAD(, blockif_elem) bc_pendq;
+ TAILQ_HEAD(, blockif_elem) bc_busyq;
u_int bc_req_count;
struct blockif_elem bc_reqs[BLOCKIF_MAXREQ];
};
+static pthread_once_t blockif_once = PTHREAD_ONCE_INIT;
+
+struct blockif_sig_elem {
+ pthread_mutex_t bse_mtx;
+ pthread_cond_t bse_cond;
+ int bse_pending;
+ struct blockif_sig_elem *bse_next;
+};
+
+static struct blockif_sig_elem *blockif_bse_head;
+
static int
blockif_enqueue(struct blockif_ctxt *bc, struct blockif_req *breq,
enum blockop op)
@@ -102,10 +120,10 @@ blockif_enqueue(struct blockif_ctxt *bc, struct blockif_req *breq,
assert(be->be_status == BST_FREE);
TAILQ_REMOVE(&bc->bc_freeq, be, be_link);
- be->be_status = BST_INUSE;
+ be->be_status = BST_PEND;
be->be_req = breq;
be->be_op = op;
- TAILQ_INSERT_TAIL(&bc->bc_inuseq, be, be_link);
+ TAILQ_INSERT_TAIL(&bc->bc_pendq, be, be_link);
bc->bc_req_count++;
@@ -113,26 +131,38 @@ blockif_enqueue(struct blockif_ctxt *bc, struct blockif_req *breq,
}
static int
-blockif_dequeue(struct blockif_ctxt *bc, struct blockif_elem *el)
+blockif_dequeue(struct blockif_ctxt *bc, struct blockif_elem **bep)
{
struct blockif_elem *be;
if (bc->bc_req_count == 0)
return (ENOENT);
- be = TAILQ_FIRST(&bc->bc_inuseq);
+ be = TAILQ_FIRST(&bc->bc_pendq);
assert(be != NULL);
- assert(be->be_status == BST_INUSE);
- *el = *be;
+ assert(be->be_status == BST_PEND);
+ TAILQ_REMOVE(&bc->bc_pendq, be, be_link);
+ be->be_status = BST_BUSY;
+ be->be_tid = bc->bc_btid;
+ TAILQ_INSERT_TAIL(&bc->bc_busyq, be, be_link);
+
+ *bep = be;
+
+ return (0);
+}
- TAILQ_REMOVE(&bc->bc_inuseq, be, be_link);
+static void
+blockif_complete(struct blockif_ctxt *bc, struct blockif_elem *be)
+{
+ assert(be->be_status == BST_DONE);
+
+ TAILQ_REMOVE(&bc->bc_busyq, be, be_link);
+ be->be_tid = 0;
be->be_status = BST_FREE;
be->be_req = NULL;
TAILQ_INSERT_TAIL(&bc->bc_freeq, be, be_link);
-
- bc->bc_req_count--;
- return (0);
+ bc->bc_req_count--;
}
static void
@@ -159,14 +189,13 @@ blockif_proc(struct blockif_ctxt *bc, struct blockif_elem *be)
break;
case BOP_FLUSH:
break;
- case BOP_CANCEL:
- err = EINTR;
- break;
default:
err = EINVAL;
break;
}
+ be->be_status = BST_DONE;
+
(*br->br_callback)(br, err);
}
@@ -174,16 +203,17 @@ static void *
blockif_thr(void *arg)
{
struct blockif_ctxt *bc;
- struct blockif_elem req;
+ struct blockif_elem *be;
bc = arg;
for (;;) {
pthread_mutex_lock(&bc->bc_mtx);
- while (!blockif_dequeue(bc, &req)) {
+ while (!blockif_dequeue(bc, &be)) {
pthread_mutex_unlock(&bc->bc_mtx);
- blockif_proc(bc, &req);
+ blockif_proc(bc, be);
pthread_mutex_lock(&bc->bc_mtx);
+ blockif_complete(bc, be);
}
pthread_cond_wait(&bc->bc_cond, &bc->bc_mtx);
pthread_mutex_unlock(&bc->bc_mtx);
@@ -199,6 +229,38 @@ blockif_thr(void *arg)
return (NULL);
}
+static void
+blockif_sigcont_handler(int signal, enum ev_type type, void *arg)
+{
+ struct blockif_sig_elem *bse;
+
+ for (;;) {
+ /*
+ * Process the entire list even if not intended for
+ * this thread.
+ */
+ do {
+ bse = blockif_bse_head;
+ if (bse == NULL)
+ return;
+ } while (!atomic_cmpset_ptr((uintptr_t *)&blockif_bse_head,
+ (uintptr_t)bse,
+ (uintptr_t)bse->bse_next));
+
+ pthread_mutex_lock(&bse->bse_mtx);
+ bse->bse_pending = 0;
+ pthread_cond_signal(&bse->bse_cond);
+ pthread_mutex_unlock(&bse->bse_mtx);
+ }
+}
+
+static void
+blockif_init(void)
+{
+ mevent_add(SIGCONT, EVF_SIGNAL, blockif_sigcont_handler, NULL);
+ (void) signal(SIGCONT, SIG_IGN);
+}
+
struct blockif_ctxt *
blockif_open(const char *optstr, const char *ident)
{
@@ -210,6 +272,8 @@ blockif_open(const char *optstr, const char *ident)
int extra, fd, i, sectsz;
int nocache, sync, ro;
+ pthread_once(&blockif_once, blockif_init);
+
nocache = 0;
sync = 0;
ro = 0;
@@ -278,12 +342,14 @@ blockif_open(const char *optstr, const char *ident)
bc->bc_magic = BLOCKIF_SIG;
bc->bc_fd = fd;
+ bc->bc_rdonly = ro;
bc->bc_size = size;
bc->bc_sectsz = sectsz;
pthread_mutex_init(&bc->bc_mtx, NULL);
pthread_cond_init(&bc->bc_cond, NULL);
TAILQ_INIT(&bc->bc_freeq);
- TAILQ_INIT(&bc->bc_inuseq);
+ TAILQ_INIT(&bc->bc_pendq);
+ TAILQ_INIT(&bc->bc_busyq);
bc->bc_req_count = 0;
for (i = 0; i < BLOCKIF_MAXREQ; i++) {
bc->bc_reqs[i].be_status = BST_FREE;
@@ -355,9 +421,81 @@ blockif_flush(struct blockif_ctxt *bc, struct blockif_req *breq)
int
blockif_cancel(struct blockif_ctxt *bc, struct blockif_req *breq)
{
+ struct blockif_elem *be;
assert(bc->bc_magic == BLOCKIF_SIG);
- return (blockif_request(bc, breq, BOP_CANCEL));
+
+ pthread_mutex_lock(&bc->bc_mtx);
+ /*
+ * Check pending requests.
+ */
+ TAILQ_FOREACH(be, &bc->bc_pendq, be_link) {
+ if (be->be_req == breq)
+ break;
+ }
+ if (be != NULL) {
+ /*
+ * Found it.
+ */
+ TAILQ_REMOVE(&bc->bc_pendq, be, be_link);
+ be->be_status = BST_FREE;
+ be->be_req = NULL;
+ TAILQ_INSERT_TAIL(&bc->bc_freeq, be, be_link);
+ bc->bc_req_count--;
+ pthread_mutex_unlock(&bc->bc_mtx);
+
+ return (0);
+ }
+
+ /*
+ * Check in-flight requests.
+ */
+ TAILQ_FOREACH(be, &bc->bc_busyq, be_link) {
+ if (be->be_req == breq)
+ break;
+ }
+ if (be == NULL) {
+ /*
+ * Didn't find it.
+ */
+ pthread_mutex_unlock(&bc->bc_mtx);
+ return (EINVAL);
+ }
+
+ /*
+ * Interrupt the processing thread to force it return
+ * prematurely via it's normal callback path.
+ */
+ while (be->be_status == BST_BUSY) {
+ struct blockif_sig_elem bse, *old_head;
+
+ pthread_mutex_init(&bse.bse_mtx, NULL);
+ pthread_cond_init(&bse.bse_cond, NULL);
+
+ bse.bse_pending = 1;
+
+ do {
+ old_head = blockif_bse_head;
+ bse.bse_next = old_head;
+ } while (!atomic_cmpset_ptr((uintptr_t *)&blockif_bse_head,
+ (uintptr_t)old_head,
+ (uintptr_t)&bse));
+
+ pthread_kill(be->be_tid, SIGCONT);
+
+ pthread_mutex_lock(&bse.bse_mtx);
+ while (bse.bse_pending)
+ pthread_cond_wait(&bse.bse_cond, &bse.bse_mtx);
+ pthread_mutex_unlock(&bse.bse_mtx);
+ }
+
+ pthread_mutex_unlock(&bc->bc_mtx);
+
+ /*
+ * The processing thread has been interrupted. Since it's not
+ * clear if the callback has been invoked yet, return EBUSY.
+ */
+ return (EBUSY);
}
int
@@ -462,7 +600,7 @@ blockif_queuesz(struct blockif_ctxt *bc)
{
assert(bc->bc_magic == BLOCKIF_SIG);
- return (BLOCKIF_MAXREQ);
+ return (BLOCKIF_MAXREQ - 1);
}
int
diff --git a/usr.sbin/bhyve/mem.c b/usr.sbin/bhyve/mem.c
index 37cf055..2a9f430 100644
--- a/usr.sbin/bhyve/mem.c
+++ b/usr.sbin/bhyve/mem.c
@@ -162,7 +162,7 @@ emulate_mem(struct vmctx *ctx, int vcpu, uint64_t paddr, struct vie *vie,
{
struct mmio_rb_range *entry;
- int err;
+ int err, immutable;
pthread_rwlock_rdlock(&mmio_rwlock);
/*
@@ -186,9 +186,27 @@ emulate_mem(struct vmctx *ctx, int vcpu, uint64_t paddr, struct vie *vie,
}
assert(entry != NULL);
+
+ /*
+ * An 'immutable' memory range is guaranteed to be never removed
+ * so there is no need to hold 'mmio_rwlock' while calling the
+ * handler.
+ *
+ * XXX writes to the PCIR_COMMAND register can cause register_mem()
+ * to be called. If the guest is using PCI extended config space
+ * to modify the PCIR_COMMAND register then register_mem() can
+ * deadlock on 'mmio_rwlock'. However by registering the extended
+ * config space window as 'immutable' the deadlock can be avoided.
+ */
+ immutable = (entry->mr_param.flags & MEM_F_IMMUTABLE);
+ if (immutable)
+ pthread_rwlock_unlock(&mmio_rwlock);
+
err = vmm_emulate_instruction(ctx, vcpu, paddr, vie, paging,
mem_read, mem_write, &entry->mr_param);
- pthread_rwlock_unlock(&mmio_rwlock);
+
+ if (!immutable)
+ pthread_rwlock_unlock(&mmio_rwlock);
return (err);
}
@@ -246,6 +264,7 @@ unregister_mem(struct mem_range *memp)
mr = &entry->mr_param;
assert(mr->name == memp->name);
assert(mr->base == memp->base && mr->size == memp->size);
+ assert((mr->flags & MEM_F_IMMUTABLE) == 0);
RB_REMOVE(mmio_rb_tree, &mmio_rb_root, entry);
/* flush Per-vCPU cache */
diff --git a/usr.sbin/bhyve/mem.h b/usr.sbin/bhyve/mem.h
index eb648c1..f671eae 100644
--- a/usr.sbin/bhyve/mem.h
+++ b/usr.sbin/bhyve/mem.h
@@ -48,6 +48,7 @@ struct mem_range {
#define MEM_F_READ 0x1
#define MEM_F_WRITE 0x2
#define MEM_F_RW 0x3
+#define MEM_F_IMMUTABLE 0x4 /* mem_range cannot be unregistered */
void init_mem(void);
int emulate_mem(struct vmctx *, int vcpu, uint64_t paddr, struct vie *vie,
diff --git a/usr.sbin/bhyve/pci_ahci.c b/usr.sbin/bhyve/pci_ahci.c
index 52724bb..ab40854 100644
--- a/usr.sbin/bhyve/pci_ahci.c
+++ b/usr.sbin/bhyve/pci_ahci.c
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
+#include <pthread_np.h>
#include <inttypes.h>
#include "bhyverun.h"
@@ -115,7 +116,8 @@ static FILE *dbg;
struct ahci_ioreq {
struct blockif_req io_req;
struct ahci_port *io_pr;
- STAILQ_ENTRY(ahci_ioreq) io_list;
+ STAILQ_ENTRY(ahci_ioreq) io_flist;
+ TAILQ_ENTRY(ahci_ioreq) io_blist;
uint8_t *cfis;
uint32_t len;
uint32_t done;
@@ -160,6 +162,7 @@ struct ahci_port {
struct ahci_ioreq *ioreq;
int ioqsz;
STAILQ_HEAD(ahci_fhead, ahci_ioreq) iofhd;
+ TAILQ_HEAD(ahci_bhead, ahci_ioreq) iobhd;
};
struct ahci_cmd_hdr {
@@ -336,8 +339,9 @@ ahci_write_fis_d2h(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t tfd)
fis[13] = cfis[13];
if (fis[2] & ATA_S_ERROR)
p->is |= AHCI_P_IX_TFE;
+ else
+ p->ci &= ~(1 << slot);
p->tfd = tfd;
- p->ci &= ~(1 << slot);
ahci_write_fis(p, FIS_TYPE_REGD2H, fis);
}
@@ -359,6 +363,72 @@ ahci_write_reset_fis_d2h(struct ahci_port *p)
}
static void
+ahci_check_stopped(struct ahci_port *p)
+{
+ /*
+ * If we are no longer processing the command list and nothing
+ * is in-flight, clear the running bit, the current command
+ * slot, the command issue and active bits.
+ */
+ if (!(p->cmd & AHCI_P_CMD_ST)) {
+ if (p->pending == 0) {
+ p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
+ p->ci = 0;
+ p->sact = 0;
+ }
+ }
+}
+
+static void
+ahci_port_stop(struct ahci_port *p)
+{
+ struct ahci_ioreq *aior;
+ uint8_t *cfis;
+ int slot;
+ int ncq;
+ int error;
+
+ assert(pthread_mutex_isowned_np(&p->pr_sc->mtx));
+
+ TAILQ_FOREACH(aior, &p->iobhd, io_blist) {
+ /*
+ * Try to cancel the outstanding blockif request.
+ */
+ error = blockif_cancel(p->bctx, &aior->io_req);
+ if (error != 0)
+ continue;
+
+ slot = aior->slot;
+ cfis = aior->cfis;
+ if (cfis[2] == ATA_WRITE_FPDMA_QUEUED ||
+ cfis[2] == ATA_READ_FPDMA_QUEUED)
+ ncq = 1;
+
+ if (ncq)
+ p->sact &= ~(1 << slot);
+ else
+ p->ci &= ~(1 << slot);
+
+ /*
+ * This command is now done.
+ */
+ p->pending &= ~(1 << slot);
+
+ /*
+ * Delete the blockif request from the busy list
+ */
+ TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+ /*
+ * Move the blockif request back to the free list
+ */
+ STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
+ }
+
+ ahci_check_stopped(p);
+}
+
+static void
ahci_port_reset(struct ahci_port *pr)
{
pr->sctl = 0;
@@ -491,7 +561,7 @@ ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
*/
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
- STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+ STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
aior->cfis = cfis;
aior->slot = slot;
aior->len = len;
@@ -502,15 +572,21 @@ ahci_handle_dma(struct ahci_port *p, int slot, uint8_t *cfis, uint32_t done,
if (iovcnt > BLOCKIF_IOV_MAX) {
aior->prdtl = iovcnt - BLOCKIF_IOV_MAX;
iovcnt = BLOCKIF_IOV_MAX;
- /*
- * Mark this command in-flight.
- */
- p->pending |= 1 << slot;
} else
aior->prdtl = 0;
breq->br_iovcnt = iovcnt;
/*
+ * Mark this command in-flight.
+ */
+ p->pending |= 1 << slot;
+
+ /*
+ * Stuff request onto busy list
+ */
+ TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
+ /*
* Build up the iovec based on the prdt
*/
for (i = 0; i < iovcnt; i++) {
@@ -545,7 +621,7 @@ ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
*/
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
- STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+ STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
aior->cfis = cfis;
aior->slot = slot;
aior->len = 0;
@@ -553,6 +629,16 @@ ahci_handle_flush(struct ahci_port *p, int slot, uint8_t *cfis)
aior->prdtl = 0;
breq = &aior->io_req;
+ /*
+ * Mark this command in-flight.
+ */
+ p->pending |= 1 << slot;
+
+ /*
+ * Stuff request onto busy list
+ */
+ TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
err = blockif_flush(p->bctx, breq);
assert(err == 0);
}
@@ -651,8 +737,8 @@ handle_identify(struct ahci_port *p, int slot, uint8_t *cfis)
write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
p->tfd = ATA_S_DSC | ATA_S_READY;
p->is |= AHCI_P_IX_DP;
+ p->ci &= ~(1 << slot);
}
- p->ci &= ~(1 << slot);
ahci_generate_intr(p->pr_sc);
}
@@ -694,8 +780,8 @@ handle_atapi_identify(struct ahci_port *p, int slot, uint8_t *cfis)
write_prdt(p, slot, cfis, (void *)buf, sizeof(buf));
p->tfd = ATA_S_DSC | ATA_S_READY;
p->is |= AHCI_P_IX_DHR;
+ p->ci &= ~(1 << slot);
}
- p->ci &= ~(1 << slot);
ahci_generate_intr(p->pr_sc);
}
@@ -960,7 +1046,7 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
*/
aior = STAILQ_FIRST(&p->iofhd);
assert(aior != NULL);
- STAILQ_REMOVE_HEAD(&p->iofhd, io_list);
+ STAILQ_REMOVE_HEAD(&p->iofhd, io_flist);
aior->cfis = cfis;
aior->slot = slot;
aior->len = len;
@@ -976,6 +1062,16 @@ atapi_read(struct ahci_port *p, int slot, uint8_t *cfis,
breq->br_iovcnt = iovcnt;
/*
+ * Mark this command in-flight.
+ */
+ p->pending |= 1 << slot;
+
+ /*
+ * Stuff request onto busy list
+ */
+ TAILQ_INSERT_HEAD(&p->iobhd, aior, io_blist);
+
+ /*
* Build up the iovec based on the prdt
*/
for (i = 0; i < iovcnt; i++) {
@@ -1298,7 +1394,6 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
if (!p->atapi) {
p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
p->is |= AHCI_P_IX_TFE;
- p->ci &= ~(1 << slot);
ahci_generate_intr(p->pr_sc);
} else
handle_packet_cmd(p, slot, cfis);
@@ -1307,7 +1402,6 @@ ahci_handle_cmd(struct ahci_port *p, int slot, uint8_t *cfis)
WPRINTF("Unsupported cmd:%02x\n", cfis[2]);
p->tfd = (ATA_E_ABORT << 8) | ATA_S_READY | ATA_S_ERROR;
p->is |= AHCI_P_IX_TFE;
- p->ci &= ~(1 << slot);
ahci_generate_intr(p->pr_sc);
break;
}
@@ -1375,8 +1469,11 @@ ahci_handle_port(struct ahci_port *p)
* are already in-flight.
*/
for (i = 0; (i < 32) && p->ci; i++) {
- if ((p->ci & (1 << i)) && !(p->pending & (1 << i)))
+ if ((p->ci & (1 << i)) && !(p->pending & (1 << i))) {
+ p->cmd &= ~AHCI_P_CMD_CCS_MASK;
+ p->cmd |= i << AHCI_P_CMD_CCS_SHIFT;
ahci_handle_slot(p, i);
+ }
}
}
@@ -1413,9 +1510,14 @@ ata_ioreq_cb(struct blockif_req *br, int err)
pthread_mutex_lock(&sc->mtx);
/*
+ * Delete the blockif request from the busy list
+ */
+ TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+ /*
* Move the blockif request back to the free list
*/
- STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+ STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
if (pending && !err) {
ahci_handle_dma(p, slot, cfis, aior->done,
@@ -1436,17 +1538,18 @@ ata_ioreq_cb(struct blockif_req *br, int err)
p->serr |= (1 << slot);
}
- /*
- * This command is now complete.
- */
- p->pending &= ~(1 << slot);
-
if (ncq) {
p->sact &= ~(1 << slot);
ahci_write_fis_sdb(p, slot, tfd);
} else
ahci_write_fis_d2h(p, slot, cfis, tfd);
+ /*
+ * This command is now complete.
+ */
+ p->pending &= ~(1 << slot);
+
+ ahci_check_stopped(p);
out:
pthread_mutex_unlock(&sc->mtx);
DPRINTF("%s exit\n", __func__);
@@ -1476,9 +1579,14 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
pthread_mutex_lock(&sc->mtx);
/*
+ * Delete the blockif request from the busy list
+ */
+ TAILQ_REMOVE(&p->iobhd, aior, io_blist);
+
+ /*
* Move the blockif request back to the free list
*/
- STAILQ_INSERT_TAIL(&p->iofhd, aior, io_list);
+ STAILQ_INSERT_TAIL(&p->iofhd, aior, io_flist);
if (pending && !err) {
atapi_read(p, slot, cfis, aior->done, hdr->prdtl - pending);
@@ -1498,6 +1606,12 @@ atapi_ioreq_cb(struct blockif_req *br, int err)
cfis[4] = (cfis[4] & ~7) | ATA_I_CMD | ATA_I_IN;
ahci_write_fis_d2h(p, slot, cfis, tfd);
+ /*
+ * This command is now complete.
+ */
+ p->pending &= ~(1 << slot);
+
+ ahci_check_stopped(p);
out:
pthread_mutex_unlock(&sc->mtx);
DPRINTF("%s exit\n", __func__);
@@ -1524,8 +1638,10 @@ pci_ahci_ioreq_init(struct ahci_port *pr)
else
vr->io_req.br_callback = atapi_ioreq_cb;
vr->io_req.br_param = vr;
- STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_list);
+ STAILQ_INSERT_TAIL(&pr->iofhd, vr, io_flist);
}
+
+ TAILQ_INIT(&pr->iobhd);
}
static void
@@ -1563,9 +1679,7 @@ pci_ahci_port_write(struct pci_ahci_softc *sc, uint64_t offset, uint64_t value)
p->cmd = value;
if (!(value & AHCI_P_CMD_ST)) {
- p->cmd &= ~(AHCI_P_CMD_CR | AHCI_P_CMD_CCS_MASK);
- p->ci = 0;
- p->sact = 0;
+ ahci_port_stop(p);
} else {
uint64_t clb;
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 458ba76..6b906ed 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -109,16 +109,20 @@ static uint64_t pci_emul_membase64;
#define PCI_EMUL_IOBASE 0x2000
#define PCI_EMUL_IOLIMIT 0x10000
-#define PCI_EMUL_MEMLIMIT32 0xE0000000 /* 3.5GB */
+#define PCI_EMUL_ECFG_BASE 0xE0000000 /* 3.5GB */
+#define PCI_EMUL_ECFG_SIZE (MAXBUSES * 1024 * 1024) /* 1MB per bus */
+SYSRES_MEM(PCI_EMUL_ECFG_BASE, PCI_EMUL_ECFG_SIZE);
+
+#define PCI_EMUL_MEMLIMIT32 PCI_EMUL_ECFG_BASE
#define PCI_EMUL_MEMBASE64 0xD000000000UL
#define PCI_EMUL_MEMLIMIT64 0xFD00000000UL
static struct pci_devemu *pci_emul_finddev(char *name);
-static void pci_lintr_route(struct pci_devinst *pi);
-static void pci_lintr_update(struct pci_devinst *pi);
-
-static struct mem_range pci_mem_hole;
+static void pci_lintr_route(struct pci_devinst *pi);
+static void pci_lintr_update(struct pci_devinst *pi);
+static void pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot,
+ int func, int coff, int bytes, uint32_t *val);
/*
* I/O access
@@ -1023,12 +1027,37 @@ pci_emul_fallback_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
return (0);
}
+static int
+pci_emul_ecfg_handler(struct vmctx *ctx, int vcpu, int dir, uint64_t addr,
+ int bytes, uint64_t *val, void *arg1, long arg2)
+{
+ int bus, slot, func, coff, in;
+
+ coff = addr & 0xfff;
+ func = (addr >> 12) & 0x7;
+ slot = (addr >> 15) & 0x1f;
+ bus = (addr >> 20) & 0xff;
+ in = (dir == MEM_F_READ);
+ if (in)
+ *val = ~0UL;
+ pci_cfgrw(ctx, vcpu, in, bus, slot, func, coff, bytes, (uint32_t *)val);
+ return (0);
+}
+
+uint64_t
+pci_ecfg_base(void)
+{
+
+ return (PCI_EMUL_ECFG_BASE);
+}
+
#define BUSIO_ROUNDUP 32
#define BUSMEM_ROUNDUP (1024 * 1024)
int
init_pci(struct vmctx *ctx)
{
+ struct mem_range mr;
struct pci_devemu *pde;
struct businfo *bi;
struct slotinfo *si;
@@ -1112,22 +1141,34 @@ init_pci(struct vmctx *ctx)
* The guest physical memory map looks like the following:
* [0, lowmem) guest system memory
* [lowmem, lowmem_limit) memory hole (may be absent)
- * [lowmem_limit, 4GB) PCI hole (32-bit BAR allocation)
+ * [lowmem_limit, 0xE0000000) PCI hole (32-bit BAR allocation)
+ * [0xE0000000, 0xF0000000) PCI extended config window
+ * [0xF0000000, 4GB) LAPIC, IOAPIC, HPET, firmware
* [4GB, 4GB + highmem)
- *
+ */
+
+ /*
* Accesses to memory addresses that are not allocated to system
* memory or PCI devices return 0xff's.
*/
lowmem = vm_get_lowmem_size(ctx);
+ bzero(&mr, sizeof(struct mem_range));
+ mr.name = "PCI hole";
+ mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
+ mr.base = lowmem;
+ mr.size = (4ULL * 1024 * 1024 * 1024) - lowmem;
+ mr.handler = pci_emul_fallback_handler;
+ error = register_mem_fallback(&mr);
+ assert(error == 0);
- memset(&pci_mem_hole, 0, sizeof(struct mem_range));
- pci_mem_hole.name = "PCI hole";
- pci_mem_hole.flags = MEM_F_RW;
- pci_mem_hole.base = lowmem;
- pci_mem_hole.size = (4ULL * 1024 * 1024 * 1024) - lowmem;
- pci_mem_hole.handler = pci_emul_fallback_handler;
-
- error = register_mem_fallback(&pci_mem_hole);
+ /* PCI extended config space */
+ bzero(&mr, sizeof(struct mem_range));
+ mr.name = "PCI ECFG";
+ mr.flags = MEM_F_RW | MEM_F_IMMUTABLE;
+ mr.base = PCI_EMUL_ECFG_BASE;
+ mr.size = PCI_EMUL_ECFG_SIZE;
+ mr.handler = pci_emul_ecfg_handler;
+ error = register_mem(&mr);
assert(error == 0);
return (0);
@@ -1612,41 +1653,6 @@ pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv)
}
}
-static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff;
-
-static int
-pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
-{
- uint32_t x;
-
- if (bytes != 4) {
- if (in)
- *eax = (bytes == 2) ? 0xffff : 0xff;
- return (0);
- }
-
- if (in) {
- x = (cfgbus << 16) |
- (cfgslot << 11) |
- (cfgfunc << 8) |
- cfgoff;
- if (cfgenable)
- x |= CONF1_ENABLE;
- *eax = x;
- } else {
- x = *eax;
- cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
- cfgoff = x & PCI_REGMAX;
- cfgfunc = (x >> 8) & PCI_FUNCMAX;
- cfgslot = (x >> 11) & PCI_SLOTMAX;
- cfgbus = (x >> 16) & PCI_BUSMAX;
- }
-
- return (0);
-}
-INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr);
-
static uint32_t
bits_changed(uint32_t old, uint32_t new, uint32_t mask)
{
@@ -1709,41 +1715,51 @@ pci_emul_cmdwrite(struct pci_devinst *pi, uint32_t new, int bytes)
pci_lintr_update(pi);
}
-static int
-pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
+static void
+pci_cfgrw(struct vmctx *ctx, int vcpu, int in, int bus, int slot, int func,
+ int coff, int bytes, uint32_t *eax)
{
struct businfo *bi;
struct slotinfo *si;
struct pci_devinst *pi;
struct pci_devemu *pe;
- int coff, idx, needcfg;
+ int idx, needcfg;
uint64_t addr, bar, mask;
- assert(bytes == 1 || bytes == 2 || bytes == 4);
-
- if ((bi = pci_businfo[cfgbus]) != NULL) {
- si = &bi->slotinfo[cfgslot];
- pi = si->si_funcs[cfgfunc].fi_devi;
+ if ((bi = pci_businfo[bus]) != NULL) {
+ si = &bi->slotinfo[slot];
+ pi = si->si_funcs[func].fi_devi;
} else
pi = NULL;
- coff = cfgoff + (port - CONF1_DATA_PORT);
-
-#if 0
- printf("pcicfg-%s from 0x%0x of %d bytes (%d/%d/%d)\n\r",
- in ? "read" : "write", coff, bytes, cfgbus, cfgslot, cfgfunc);
-#endif
-
/*
- * Just return if there is no device at this cfgslot:cfgfunc,
- * if the guest is doing an un-aligned access, or if the config
- * address word isn't enabled.
+ * Just return if there is no device at this slot:func or if the
+ * the guest is doing an un-aligned access.
*/
- if (!cfgenable || pi == NULL || (coff & (bytes - 1)) != 0) {
+ if (pi == NULL || (bytes != 1 && bytes != 2 && bytes != 4) ||
+ (coff & (bytes - 1)) != 0) {
if (in)
*eax = 0xffffffff;
- return (0);
+ return;
+ }
+
+ /*
+ * Ignore all writes beyond the standard config space and return all
+ * ones on reads.
+ */
+ if (coff >= PCI_REGMAX + 1) {
+ if (in) {
+ *eax = 0xffffffff;
+ /*
+ * Extended capabilities begin at offset 256 in config
+ * space. Absence of extended capabilities is signaled
+ * with all 0s in the extended capability header at
+ * offset 256.
+ */
+ if (coff <= PCI_REGMAX + 4)
+ *eax = 0x00000000;
+ }
+ return;
}
pe = pi->pi_d;
@@ -1754,8 +1770,8 @@ pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
if (in) {
/* Let the device emulation override the default handler */
if (pe->pe_cfgread != NULL) {
- needcfg = pe->pe_cfgread(ctx, vcpu, pi,
- coff, bytes, eax);
+ needcfg = pe->pe_cfgread(ctx, vcpu, pi, coff, bytes,
+ eax);
} else {
needcfg = 1;
}
@@ -1769,12 +1785,12 @@ pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
*eax = pci_get_cfgdata32(pi, coff);
}
- pci_emul_hdrtype_fixup(cfgbus, cfgslot, coff, bytes, eax);
+ pci_emul_hdrtype_fixup(bus, slot, coff, bytes, eax);
} else {
/* Let the device emulation override the default handler */
if (pe->pe_cfgwrite != NULL &&
(*pe->pe_cfgwrite)(ctx, vcpu, pi, coff, bytes, *eax) == 0)
- return (0);
+ return;
/*
* Special handling for write to BAR registers
@@ -1785,7 +1801,7 @@ pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
* 4-byte aligned.
*/
if (bytes != 4 || (coff & 0x3) != 0)
- return (0);
+ return;
idx = (coff - PCIR_BAR(0)) / 4;
mask = ~(pi->pi_bar[idx].size - 1);
switch (pi->pi_bar[idx].type) {
@@ -1843,7 +1859,57 @@ pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
CFGWRITE(pi, coff, *eax, bytes);
}
}
+}
+
+static int cfgenable, cfgbus, cfgslot, cfgfunc, cfgoff;
+
+static int
+pci_emul_cfgaddr(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
+ uint32_t *eax, void *arg)
+{
+ uint32_t x;
+
+ if (bytes != 4) {
+ if (in)
+ *eax = (bytes == 2) ? 0xffff : 0xff;
+ return (0);
+ }
+
+ if (in) {
+ x = (cfgbus << 16) | (cfgslot << 11) | (cfgfunc << 8) | cfgoff;
+ if (cfgenable)
+ x |= CONF1_ENABLE;
+ *eax = x;
+ } else {
+ x = *eax;
+ cfgenable = (x & CONF1_ENABLE) == CONF1_ENABLE;
+ cfgoff = x & PCI_REGMAX;
+ cfgfunc = (x >> 8) & PCI_FUNCMAX;
+ cfgslot = (x >> 11) & PCI_SLOTMAX;
+ cfgbus = (x >> 16) & PCI_BUSMAX;
+ }
+
+ return (0);
+}
+INOUT_PORT(pci_cfgaddr, CONF1_ADDR_PORT, IOPORT_F_INOUT, pci_emul_cfgaddr);
+
+static int
+pci_emul_cfgdata(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
+ uint32_t *eax, void *arg)
+{
+ int coff;
+ assert(bytes == 1 || bytes == 2 || bytes == 4);
+
+ coff = cfgoff + (port - CONF1_DATA_PORT);
+ if (cfgenable) {
+ pci_cfgrw(ctx, vcpu, in, cfgbus, cfgslot, cfgfunc, coff, bytes,
+ eax);
+ } else {
+ /* Ignore accesses to cfgdata if not enabled by cfgaddr */
+ if (in)
+ *eax = 0xffffffff;
+ }
return (0);
}
diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h
index 866ffc5..6b8c4e0 100644
--- a/usr.sbin/bhyve/pci_emul.h
+++ b/usr.sbin/bhyve/pci_emul.h
@@ -235,6 +235,7 @@ uint64_t pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size);
int pci_count_lintr(int bus);
void pci_walk_lintr(int bus, pci_lintr_cb cb, void *arg);
void pci_write_dsdt(void);
+uint64_t pci_ecfg_base(void);
int pci_bus_configured(int bus);
static __inline void
diff --git a/usr.sbin/bhyve/pci_irq.c b/usr.sbin/bhyve/pci_irq.c
index 653aeb0..20e033f 100644
--- a/usr.sbin/bhyve/pci_irq.c
+++ b/usr.sbin/bhyve/pci_irq.c
@@ -115,7 +115,7 @@ void
pci_irq_reserve(int irq)
{
- assert(irq < nitems(irq_counts));
+ assert(irq >= 0 && irq < nitems(irq_counts));
assert(pirq_cold);
assert(irq_counts[irq] == 0 || irq_counts[irq] == IRQ_DISABLED);
irq_counts[irq] = IRQ_DISABLED;
@@ -125,10 +125,10 @@ void
pci_irq_use(int irq)
{
- assert(irq < nitems(irq_counts));
+ assert(irq >= 0 && irq < nitems(irq_counts));
assert(pirq_cold);
- if (irq_counts[irq] != IRQ_DISABLED)
- irq_counts[irq]++;
+ assert(irq_counts[irq] != IRQ_DISABLED);
+ irq_counts[irq]++;
}
void
@@ -197,7 +197,7 @@ pirq_alloc_pin(struct vmctx *ctx)
{
int best_count, best_irq, best_pin, irq, pin;
- pirq_cold = 1;
+ pirq_cold = 0;
/* First, find the least-used PIRQ pin. */
best_pin = 0;
@@ -222,7 +222,7 @@ pirq_alloc_pin(struct vmctx *ctx)
best_count = irq_counts[irq];
}
}
- assert(best_irq != 0);
+ assert(best_irq >= 0);
irq_counts[best_irq]++;
pirqs[best_pin].reg = best_irq;
vm_isa_set_irq_trigger(ctx, best_irq, LEVEL_TRIGGER);
@@ -234,9 +234,6 @@ pirq_alloc_pin(struct vmctx *ctx)
int
pirq_irq(int pin)
{
-
- if (pin == -1)
- return (255);
assert(pin > 0 && pin <= nitems(pirqs));
return (pirqs[pin - 1].reg & PIRQ_IRQ);
}
diff --git a/usr.sbin/bhyve/pci_virtio_block.c b/usr.sbin/bhyve/pci_virtio_block.c
index cf1c655..c66ad68 100644
--- a/usr.sbin/bhyve/pci_virtio_block.c
+++ b/usr.sbin/bhyve/pci_virtio_block.c
@@ -94,6 +94,8 @@ struct vtblk_config {
struct virtio_blk_hdr {
#define VBH_OP_READ 0
#define VBH_OP_WRITE 1
+#define VBH_OP_FLUSH 4
+#define VBH_OP_FLUSH_OUT 5
#define VBH_OP_IDENT 8
#define VBH_FLAG_BARRIER 0x80000000 /* OR'ed into vbh_type */
uint32_t vbh_type;
@@ -133,6 +135,7 @@ static struct virtio_consts vtblk_vi_consts = {
pci_vtblk_notify, /* device-wide qnotify */
pci_vtblk_cfgread, /* read PCI config */
pci_vtblk_cfgwrite, /* write PCI config */
+ NULL, /* apply negotiated features */
VTBLK_S_HOSTCAPS, /* our capabilities */
};
@@ -216,6 +219,10 @@ pci_vtblk_proc(struct pci_vtblk_softc *sc, struct vqueue_info *vq)
MIN(iov[1].iov_len, sizeof(sc->vbsc_ident)));
err = 0;
break;
+ case VBH_OP_FLUSH:
+ case VBH_OP_FLUSH_OUT:
+ err = fsync(sc->vbsc_fd);
+ break;
default:
err = -ENOSYS;
break;
diff --git a/usr.sbin/bhyve/pci_virtio_net.c b/usr.sbin/bhyve/pci_virtio_net.c
index c3b8690..5ac9ecd 100644
--- a/usr.sbin/bhyve/pci_virtio_net.c
+++ b/usr.sbin/bhyve/pci_virtio_net.c
@@ -135,11 +135,14 @@ struct pci_vtnet_softc {
int vsc_rx_ready;
volatile int resetting; /* set and checked outside lock */
- uint32_t vsc_features;
+ uint64_t vsc_features; /* negotiated features */
+
struct virtio_net_config vsc_config;
pthread_mutex_t rx_mtx;
int rx_in_progress;
+ int rx_vhdrlen;
+ int rx_merge; /* merged rx bufs in use */
pthread_t tx_tid;
pthread_mutex_t tx_mtx;
@@ -151,6 +154,7 @@ static void pci_vtnet_reset(void *);
/* static void pci_vtnet_notify(void *, struct vqueue_info *); */
static int pci_vtnet_cfgread(void *, int, int, uint32_t *);
static int pci_vtnet_cfgwrite(void *, int, int, uint32_t);
+static void pci_vtnet_neg_features(void *, uint64_t);
static struct virtio_consts vtnet_vi_consts = {
"vtnet", /* our name */
@@ -160,6 +164,7 @@ static struct virtio_consts vtnet_vi_consts = {
NULL, /* device-wide qnotify -- not used */
pci_vtnet_cfgread, /* read PCI config */
pci_vtnet_cfgwrite, /* write PCI config */
+ pci_vtnet_neg_features, /* apply negotiated features */
VTNET_S_HOSTCAPS, /* our capabilities */
};
@@ -212,6 +217,8 @@ pci_vtnet_reset(void *vsc)
pci_vtnet_rxwait(sc);
sc->vsc_rx_ready = 0;
+ sc->rx_merge = 1;
+ sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);
/* now reset rings, MSI-X vectors, and negotiated capabilities */
vi_reset_dev(&sc->vsc_vs);
@@ -253,14 +260,34 @@ pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
*/
static uint8_t dummybuf[2048];
+static __inline struct iovec *
+rx_iov_trim(struct iovec *iov, int *niov, int tlen)
+{
+ struct iovec *riov;
+
+ /* XXX short-cut: assume first segment is >= tlen */
+ assert(iov[0].iov_len >= tlen);
+
+ iov[0].iov_len -= tlen;
+ if (iov[0].iov_len == 0) {
+ assert(*niov > 1);
+ *niov -= 1;
+ riov = &iov[1];
+ } else {
+ iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + tlen);
+ riov = &iov[0];
+ }
+
+ return (riov);
+}
+
static void
pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
{
+ struct iovec iov[VTNET_MAXSEGS], *riov;
struct vqueue_info *vq;
- struct virtio_net_rxhdr *vrx;
- uint8_t *buf;
- int len;
- struct iovec iov;
+ void *vrx;
+ int len, n;
/*
* Should never be called without a valid tap fd
@@ -296,21 +323,19 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
do {
/*
- * Get descriptor chain, which should have just
- * one descriptor in it.
- * ??? allow guests to use multiple descs?
+ * Get descriptor chain.
*/
- assert(vq_getchain(vq, &iov, 1, NULL) == 1);
+ n = vq_getchain(vq, iov, VTNET_MAXSEGS, NULL);
+ assert(n >= 1 && n <= VTNET_MAXSEGS);
/*
* Get a pointer to the rx header, and use the
* data immediately following it for the packet buffer.
*/
- vrx = iov.iov_base;
- buf = (uint8_t *)(vrx + 1);
+ vrx = iov[0].iov_base;
+ riov = rx_iov_trim(iov, &n, sc->rx_vhdrlen);
- len = read(sc->vsc_tapfd, buf,
- iov.iov_len - sizeof(struct virtio_net_rxhdr));
+ len = readv(sc->vsc_tapfd, riov, n);
if (len < 0 && errno == EWOULDBLOCK) {
/*
@@ -323,16 +348,21 @@ pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
/*
* The only valid field in the rx packet header is the
- * number of buffers, which is always 1 without TSO
- * support.
+ * number of buffers if merged rx bufs were negotiated.
*/
- memset(vrx, 0, sizeof(struct virtio_net_rxhdr));
- vrx->vrh_bufs = 1;
+ memset(vrx, 0, sc->rx_vhdrlen);
+
+ if (sc->rx_merge) {
+ struct virtio_net_rxhdr *vrxh;
+
+ vrxh = vrx;
+ vrxh->vrh_bufs = 1;
+ }
/*
* Release this chain and handle more chains.
*/
- vq_relchain(vq, len + sizeof(struct virtio_net_rxhdr));
+ vq_relchain(vq, len + sc->rx_vhdrlen);
} while (vq_has_descs(vq));
/* Interrupt if needed, including for NOTIFY_ON_EMPTY. */
@@ -623,6 +653,8 @@ pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
sc->resetting = 0;
+ sc->rx_merge = 1;
+ sc->rx_vhdrlen = sizeof(struct virtio_net_rxhdr);
sc->rx_in_progress = 0;
pthread_mutex_init(&sc->rx_mtx, NULL);
@@ -656,9 +688,10 @@ pci_vtnet_cfgwrite(void *vsc, int offset, int size, uint32_t value)
ptr = &sc->vsc_config.mac[offset];
memcpy(ptr, &value, size);
} else {
+ /* silently ignore other writes */
DPRINTF(("vtnet: write to readonly reg %d\n\r", offset));
- return (1);
}
+
return (0);
}
@@ -673,6 +706,20 @@ pci_vtnet_cfgread(void *vsc, int offset, int size, uint32_t *retval)
return (0);
}
+static void
+pci_vtnet_neg_features(void *vsc, uint64_t negotiated_features)
+{
+ struct pci_vtnet_softc *sc = vsc;
+
+ sc->vsc_features = negotiated_features;
+
+ if (!(sc->vsc_features & VIRTIO_NET_F_MRG_RXBUF)) {
+ sc->rx_merge = 0;
+ /* non-merge rx header is 2 bytes shorter */
+ sc->rx_vhdrlen -= 2;
+ }
+}
+
struct pci_devemu pci_de_vnet = {
.pe_emu = "virtio-net",
.pe_init = pci_vtnet_init,
diff --git a/usr.sbin/bhyve/pci_virtio_rnd.c b/usr.sbin/bhyve/pci_virtio_rnd.c
index 4d53183..0a31080 100644
--- a/usr.sbin/bhyve/pci_virtio_rnd.c
+++ b/usr.sbin/bhyve/pci_virtio_rnd.c
@@ -80,6 +80,7 @@ static struct virtio_consts vtrnd_vi_consts = {
pci_vtrnd_notify, /* device-wide qnotify */
NULL, /* read virtio config */
NULL, /* write virtio config */
+ NULL, /* apply negotiated features */
0, /* our capabilities */
};
diff --git a/usr.sbin/bhyve/pmtmr.c b/usr.sbin/bhyve/pmtmr.c
deleted file mode 100644
index 3a46f9b..0000000
--- a/usr.sbin/bhyve/pmtmr.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*-
- * Copyright (c) 2012 NetApp, Inc.
- * 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 NETAPP, INC ``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 NETAPP, INC OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#include <sys/time.h>
-#include <machine/cpufunc.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <assert.h>
-#include <pthread.h>
-
-#include "acpi.h"
-#include "inout.h"
-
-/*
- * The ACPI Power Management timer is a free-running 24- or 32-bit
- * timer with a frequency of 3.579545MHz
- *
- * This implementation will be 32-bits
- */
-
-#define PMTMR_FREQ 3579545 /* 3.579545MHz */
-
-static pthread_mutex_t pmtmr_mtx;
-static pthread_once_t pmtmr_once = PTHREAD_ONCE_INIT;
-
-static uint64_t pmtmr_old;
-
-static uint64_t pmtmr_tscf;
-static uint64_t pmtmr_tsc_old;
-
-static clockid_t clockid = CLOCK_UPTIME_FAST;
-static struct timespec pmtmr_uptime_old;
-
-#define timespecsub(vvp, uvp) \
- do { \
- (vvp)->tv_sec -= (uvp)->tv_sec; \
- (vvp)->tv_nsec -= (uvp)->tv_nsec; \
- if ((vvp)->tv_nsec < 0) { \
- (vvp)->tv_sec--; \
- (vvp)->tv_nsec += 1000000000; \
- } \
- } while (0)
-
-static uint64_t
-timespec_to_pmtmr(const struct timespec *tsnew, const struct timespec *tsold)
-{
- struct timespec tsdiff;
- int64_t nsecs;
-
- tsdiff = *tsnew;
- timespecsub(&tsdiff, tsold);
- nsecs = tsdiff.tv_sec * 1000000000 + tsdiff.tv_nsec;
- assert(nsecs >= 0);
-
- return (nsecs * PMTMR_FREQ / 1000000000 + pmtmr_old);
-}
-
-static uint64_t
-tsc_to_pmtmr(uint64_t tsc_new, uint64_t tsc_old)
-{
-
- return ((tsc_new - tsc_old) * PMTMR_FREQ / pmtmr_tscf + pmtmr_old);
-}
-
-static void
-pmtmr_init(void)
-{
- size_t len;
- int smp_tsc, err;
- struct timespec tsnew, tsold = { 0 };
-
- len = sizeof(smp_tsc);
- err = sysctlbyname("kern.timecounter.smp_tsc", &smp_tsc, &len, NULL, 0);
- assert(err == 0);
-
- if (smp_tsc) {
- len = sizeof(pmtmr_tscf);
- err = sysctlbyname("machdep.tsc_freq", &pmtmr_tscf, &len,
- NULL, 0);
- assert(err == 0);
-
- pmtmr_tsc_old = rdtsc();
- pmtmr_old = tsc_to_pmtmr(pmtmr_tsc_old, 0);
- } else {
- if (getenv("BHYVE_PMTMR_PRECISE") != NULL)
- clockid = CLOCK_UPTIME;
-
- err = clock_gettime(clockid, &tsnew);
- assert(err == 0);
-
- pmtmr_uptime_old = tsnew;
- pmtmr_old = timespec_to_pmtmr(&tsnew, &tsold);
- }
- pthread_mutex_init(&pmtmr_mtx, NULL);
-}
-
-static uint32_t
-pmtmr_val(void)
-{
- struct timespec tsnew;
- uint64_t pmtmr_tsc_new;
- uint64_t pmtmr_new;
- int error;
-
- pthread_once(&pmtmr_once, pmtmr_init);
-
- pthread_mutex_lock(&pmtmr_mtx);
-
- if (pmtmr_tscf) {
- pmtmr_tsc_new = rdtsc();
- pmtmr_new = tsc_to_pmtmr(pmtmr_tsc_new, pmtmr_tsc_old);
- pmtmr_tsc_old = pmtmr_tsc_new;
- } else {
- error = clock_gettime(clockid, &tsnew);
- assert(error == 0);
-
- pmtmr_new = timespec_to_pmtmr(&tsnew, &pmtmr_uptime_old);
- pmtmr_uptime_old = tsnew;
- }
- pmtmr_old = pmtmr_new;
-
- pthread_mutex_unlock(&pmtmr_mtx);
-
- return (pmtmr_new);
-}
-
-static int
-pmtmr_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
- uint32_t *eax, void *arg)
-{
- assert(in == 1);
-
- if (bytes != 4)
- return (-1);
-
- *eax = pmtmr_val();
-
- return (0);
-}
-
-INOUT_PORT(pmtmr, IO_PMTMR, IOPORT_F_IN, pmtmr_handler);
diff --git a/usr.sbin/bhyve/rtc.c b/usr.sbin/bhyve/rtc.c
index b3631fc..459c900 100644
--- a/usr.sbin/bhyve/rtc.c
+++ b/usr.sbin/bhyve/rtc.c
@@ -375,4 +375,8 @@ rtc_dsdt(void)
}
LPC_DSDT(rtc_dsdt);
+/*
+ * Reserve the extended RTC I/O ports although they are not emulated at this
+ * time.
+ */
SYSRES_IO(0x72, 6);
diff --git a/usr.sbin/bhyve/smbiostbl.c b/usr.sbin/bhyve/smbiostbl.c
index 28c7eb2..59a1358 100644
--- a/usr.sbin/bhyve/smbiostbl.c
+++ b/usr.sbin/bhyve/smbiostbl.c
@@ -737,7 +737,7 @@ smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)
smbios_ep->eplen = 0x1F;
assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen);
smbios_ep->major = 2;
- smbios_ep->minor = 4;
+ smbios_ep->minor = 6;
smbios_ep->revision = 0;
memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR,
SMBIOS_ENTRY_IANCHORLEN);
diff --git a/usr.sbin/bhyve/task_switch.c b/usr.sbin/bhyve/task_switch.c
index 0002da8..b939c1a 100644
--- a/usr.sbin/bhyve/task_switch.c
+++ b/usr.sbin/bhyve/task_switch.c
@@ -725,6 +725,21 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
assert(paging->cpu_mode == CPU_MODE_PROTECTED);
/*
+ * Calculate the %eip to store in the old TSS before modifying the
+ * 'inst_length'.
+ */
+ eip = vmexit->rip + vmexit->inst_length;
+
+ /*
+ * Set the 'inst_length' to '0'.
+ *
+ * If an exception is triggered during emulation of the task switch
+ * then the exception handler should return to the instruction that
+ * caused the task switch as opposed to the subsequent instruction.
+ */
+ vmexit->inst_length = 0;
+
+ /*
* Section 4.6, "Access Rights" in Intel SDM Vol 3.
* The following page table accesses are implicitly supervisor mode:
* - accesses to GDT or LDT to load segment descriptors
@@ -839,7 +854,6 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
}
/* Save processor state in old TSS */
- eip = vmexit->rip + vmexit->inst_length;
tss32_save(ctx, vcpu, task_switch, eip, &oldtss, ot_iov);
/*
@@ -870,7 +884,7 @@ vmexit_task_switch(struct vmctx *ctx, struct vm_exit *vmexit, int *pvcpu)
* the saved instruction pointer will belong to the new task.
*/
vmexit->rip = newtss.tss_eip;
- vmexit->inst_length = 0;
+ assert(vmexit->inst_length == 0);
/* Load processor state from new TSS */
error = tss32_restore(ctx, vcpu, task_switch, ot_sel, &newtss, nt_iov);
diff --git a/usr.sbin/bhyve/virtio.c b/usr.sbin/bhyve/virtio.c
index 1f27300..19c0d47 100644
--- a/usr.sbin/bhyve/virtio.c
+++ b/usr.sbin/bhyve/virtio.c
@@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
+#include <pthread_np.h>
#include "bhyverun.h"
#include "pci_emul.h"
@@ -89,6 +90,9 @@ vi_reset_dev(struct virtio_softc *vs)
struct vqueue_info *vq;
int i, nvq;
+ if (vs->vs_mtx)
+ assert(pthread_mutex_isowned_np(vs->vs_mtx));
+
nvq = vs->vs_vc->vc_nvq;
for (vq = vs->vs_queues, i = 0; i < nvq; vq++, i++) {
vq->vq_flags = 0;
@@ -99,11 +103,9 @@ vi_reset_dev(struct virtio_softc *vs)
vs->vs_negotiated_caps = 0;
vs->vs_curq = 0;
/* vs->vs_status = 0; -- redundant */
- VS_LOCK(vs);
if (vs->vs_isr)
pci_lintr_deassert(vs->vs_pi);
vs->vs_isr = 0;
- VS_UNLOCK(vs);
vs->vs_msix_cfg_idx = VIRTIO_MSI_NO_VECTOR;
}
@@ -137,7 +139,9 @@ vi_intr_init(struct virtio_softc *vs, int barnum, int use_msix)
if (use_msix) {
vs->vs_flags |= VIRTIO_USE_MSIX;
+ VS_LOCK(vs);
vi_reset_dev(vs); /* set all vectors to NO_VECTOR */
+ VS_UNLOCK(vs);
nvec = vs->vs_vc->vc_nvq + 1;
if (pci_emul_add_msixcap(vs->vs_pi, nvec, barnum))
return (1);
@@ -694,6 +698,9 @@ bad:
switch (offset) {
case VTCFG_R_GUESTCAP:
vs->vs_negotiated_caps = value & vc->vc_hv_caps;
+ if (vc->vc_apply_features)
+ (*vc->vc_apply_features)(DEV_SOFTC(vs),
+ vs->vs_negotiated_caps);
break;
case VTCFG_R_PFN:
if (vs->vs_curq >= vc->vc_nvq)
diff --git a/usr.sbin/bhyve/virtio.h b/usr.sbin/bhyve/virtio.h
index 1f29dfa..6f655f3 100644
--- a/usr.sbin/bhyve/virtio.h
+++ b/usr.sbin/bhyve/virtio.h
@@ -352,6 +352,8 @@ struct virtio_consts {
/* called to read config regs */
int (*vc_cfgwrite)(void *, int, int, uint32_t);
/* called to write config regs */
+ void (*vc_apply_features)(void *, uint64_t);
+ /* called to apply negotiated features */
uint64_t vc_hv_caps; /* hypervisor-provided capabilities */
};
diff --git a/usr.sbin/bhyve/xmsr.c b/usr.sbin/bhyve/xmsr.c
index 63522bf..d50a939 100644
--- a/usr.sbin/bhyve/xmsr.c
+++ b/usr.sbin/bhyve/xmsr.c
@@ -31,33 +31,191 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <machine/cpufunc.h>
#include <machine/vmm.h>
+#include <machine/specialreg.h>
+
#include <vmmapi.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "xmsr.h"
+static int cpu_vendor_intel, cpu_vendor_amd;
+
int
-emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t code, uint64_t val)
+emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t val)
{
- switch (code) {
- case 0xd04: /* Sandy Bridge uncore PMC MSRs */
- case 0xc24:
- return (0);
- case 0x79:
- return (0); /* IA32_BIOS_UPDT_TRIG MSR */
- default:
- break;
+ if (cpu_vendor_intel) {
+ switch (num) {
+ case 0xd04: /* Sandy Bridge uncore PMCs */
+ case 0xc24:
+ return (0);
+ case MSR_BIOS_UPDT_TRIG:
+ return (0);
+ case MSR_BIOS_SIGN:
+ return (0);
+ default:
+ break;
+ }
+ } else if (cpu_vendor_amd) {
+ switch (num) {
+ case MSR_HWCR:
+ /*
+ * Ignore writes to hardware configuration MSR.
+ */
+ return (0);
+
+ case MSR_NB_CFG1:
+ case MSR_IC_CFG:
+ return (0); /* Ignore writes */
+
+ case MSR_PERFEVSEL0:
+ case MSR_PERFEVSEL1:
+ case MSR_PERFEVSEL2:
+ case MSR_PERFEVSEL3:
+ /* Ignore writes to the PerfEvtSel MSRs */
+ return (0);
+
+ case MSR_K7_PERFCTR0:
+ case MSR_K7_PERFCTR1:
+ case MSR_K7_PERFCTR2:
+ case MSR_K7_PERFCTR3:
+ /* Ignore writes to the PerfCtr MSRs */
+ return (0);
+
+ case MSR_P_STATE_CONTROL:
+ /* Ignore write to change the P-state */
+ return (0);
+
+ default:
+ break;
+ }
}
return (-1);
}
int
-emulate_rdmsr(struct vmctx *ctx, int vcpu, uint32_t code, uint64_t *val)
+emulate_rdmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t *val)
{
+ int error = 0;
- return (-1);
+ if (cpu_vendor_intel) {
+ switch (num) {
+ case MSR_BIOS_SIGN:
+ case MSR_IA32_PLATFORM_ID:
+ case MSR_PKG_ENERGY_STATUS:
+ case MSR_PP0_ENERGY_STATUS:
+ case MSR_PP1_ENERGY_STATUS:
+ case MSR_DRAM_ENERGY_STATUS:
+ *val = 0;
+ break;
+ case MSR_RAPL_POWER_UNIT:
+ /*
+ * Use the default value documented in section
+ * "RAPL Interfaces" in Intel SDM vol3.
+ */
+ *val = 0x000a1003;
+ break;
+ default:
+ error = -1;
+ break;
+ }
+ } else if (cpu_vendor_amd) {
+ switch (num) {
+ case MSR_BIOS_SIGN:
+ *val = 0;
+ break;
+ case MSR_HWCR:
+ /*
+ * Bios and Kernel Developer's Guides for AMD Families
+ * 12H, 14H, 15H and 16H.
+ */
+ *val = 0x01000010; /* Reset value */
+ *val |= 1 << 9; /* MONITOR/MWAIT disable */
+ break;
+
+ case MSR_NB_CFG1:
+ case MSR_IC_CFG:
+ /*
+ * The reset value is processor family dependent so
+ * just return 0.
+ */
+ *val = 0;
+ break;
+
+ case MSR_PERFEVSEL0:
+ case MSR_PERFEVSEL1:
+ case MSR_PERFEVSEL2:
+ case MSR_PERFEVSEL3:
+ /*
+ * PerfEvtSel MSRs are not properly virtualized so just
+ * return zero.
+ */
+ *val = 0;
+ break;
+
+ case MSR_K7_PERFCTR0:
+ case MSR_K7_PERFCTR1:
+ case MSR_K7_PERFCTR2:
+ case MSR_K7_PERFCTR3:
+ /*
+ * PerfCtr MSRs are not properly virtualized so just
+ * return zero.
+ */
+ *val = 0;
+ break;
+
+ case MSR_SMM_ADDR:
+ case MSR_SMM_MASK:
+ /*
+ * Return the reset value defined in the AMD Bios and
+ * Kernel Developer's Guide.
+ */
+ *val = 0;
+ break;
+
+ case MSR_P_STATE_LIMIT:
+ case MSR_P_STATE_CONTROL:
+ case MSR_P_STATE_STATUS:
+ case MSR_P_STATE_CONFIG(0): /* P0 configuration */
+ *val = 0;
+ break;
+
+ default:
+ error = -1;
+ break;
+ }
+ } else {
+ error = -1;
+ }
+ return (error);
+}
+
+int
+init_msr(void)
+{
+ int error;
+ u_int regs[4];
+ char cpu_vendor[13];
+
+ do_cpuid(0, regs);
+ ((u_int *)&cpu_vendor)[0] = regs[1];
+ ((u_int *)&cpu_vendor)[1] = regs[3];
+ ((u_int *)&cpu_vendor)[2] = regs[2];
+ cpu_vendor[12] = '\0';
+
+ error = 0;
+ if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
+ cpu_vendor_amd = 1;
+ } else if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
+ cpu_vendor_intel = 1;
+ } else {
+ fprintf(stderr, "Unknown cpu vendor \"%s\"\n", cpu_vendor);
+ error = -1;
+ }
+ return (error);
}
diff --git a/usr.sbin/bhyve/xmsr.h b/usr.sbin/bhyve/xmsr.h
index b097cf8..bcf65b7 100644
--- a/usr.sbin/bhyve/xmsr.h
+++ b/usr.sbin/bhyve/xmsr.h
@@ -29,6 +29,7 @@
#ifndef _XMSR_H_
#define _XMSR_H_
+int init_msr(void);
int emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t code, uint64_t val);
int emulate_rdmsr(struct vmctx *ctx, int vcpu, uint32_t code, uint64_t *val);
diff --git a/usr.sbin/bhyvectl/bhyvectl.c b/usr.sbin/bhyvectl/bhyvectl.c
index b6006b7..0c4457e 100644
--- a/usr.sbin/bhyvectl/bhyvectl.c
+++ b/usr.sbin/bhyvectl/bhyvectl.c
@@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
#include <unistd.h>
#include <libgen.h>
#include <libutil.h>
@@ -45,9 +47,12 @@ __FBSDID("$FreeBSD$");
#include <getopt.h>
#include <assert.h>
+#include <machine/cpufunc.h>
#include <machine/vmm.h>
+#include <machine/specialreg.h>
#include <vmmapi.h>
+#include "amd/vmcb.h"
#include "intel/vmcs.h"
#define MB (1UL << 20)
@@ -60,7 +65,7 @@ __FBSDID("$FreeBSD$");
static const char *progname;
static void
-usage(void)
+usage(bool cpu_intel)
{
(void)fprintf(stderr,
@@ -141,48 +146,6 @@ usage(void)
" [--get-ss]\n"
" [--get-tr]\n"
" [--get-ldtr]\n"
- " [--get-vmcs-pinbased-ctls]\n"
- " [--get-vmcs-procbased-ctls]\n"
- " [--get-vmcs-procbased-ctls2]\n"
- " [--get-vmcs-entry-interruption-info]\n"
- " [--set-vmcs-entry-interruption-info=<info>]\n"
- " [--get-vmcs-eptp]\n"
- " [--get-vmcs-guest-physical-address\n"
- " [--get-vmcs-guest-linear-address\n"
- " [--set-vmcs-exception-bitmap]\n"
- " [--get-vmcs-exception-bitmap]\n"
- " [--get-vmcs-io-bitmap-address]\n"
- " [--get-vmcs-tsc-offset]\n"
- " [--get-vmcs-guest-pat]\n"
- " [--get-vmcs-host-pat]\n"
- " [--get-vmcs-host-cr0]\n"
- " [--get-vmcs-host-cr3]\n"
- " [--get-vmcs-host-cr4]\n"
- " [--get-vmcs-host-rip]\n"
- " [--get-vmcs-host-rsp]\n"
- " [--get-vmcs-cr0-mask]\n"
- " [--get-vmcs-cr0-shadow]\n"
- " [--get-vmcs-cr4-mask]\n"
- " [--get-vmcs-cr4-shadow]\n"
- " [--get-vmcs-cr3-targets]\n"
- " [--get-vmcs-apic-access-address]\n"
- " [--get-vmcs-virtual-apic-address]\n"
- " [--get-vmcs-tpr-threshold]\n"
- " [--get-vmcs-msr-bitmap]\n"
- " [--get-vmcs-msr-bitmap-address]\n"
- " [--get-vmcs-vpid]\n"
- " [--get-vmcs-ple-gap]\n"
- " [--get-vmcs-ple-window]\n"
- " [--get-vmcs-instruction-error]\n"
- " [--get-vmcs-exit-ctls]\n"
- " [--get-vmcs-entry-ctls]\n"
- " [--get-vmcs-guest-sysenter]\n"
- " [--get-vmcs-link]\n"
- " [--get-vmcs-exit-reason]\n"
- " [--get-vmcs-exit-qualification]\n"
- " [--get-vmcs-exit-interruption-info]\n"
- " [--get-vmcs-exit-interruption-error]\n"
- " [--get-vmcs-interruptibility]\n"
" [--set-x2apic-state=<state>]\n"
" [--get-x2apic-state]\n"
" [--unassign-pptdev=<bus/slot/func>]\n"
@@ -196,8 +159,64 @@ usage(void)
" [--force-poweroff]\n"
" [--get-active-cpus]\n"
" [--get-suspended-cpus]\n"
- " [--get-intinfo]\n",
+ " [--get-intinfo]\n"
+ " [--get-eptp]\n"
+ " [--set-exception-bitmap]\n"
+ " [--get-exception-bitmap]\n"
+ " [--get-tsc-offset]\n"
+ " [--get-guest-pat]\n"
+ " [--get-io-bitmap-address]\n"
+ " [--get-msr-bitmap]\n"
+ " [--get-msr-bitmap-address]\n"
+ " [--get-guest-sysenter]\n"
+ " [--get-exit-reason]\n",
progname);
+
+ if (cpu_intel) {
+ (void)fprintf(stderr,
+ " [--get-vmcs-pinbased-ctls]\n"
+ " [--get-vmcs-procbased-ctls]\n"
+ " [--get-vmcs-procbased-ctls2]\n"
+ " [--get-vmcs-entry-interruption-info]\n"
+ " [--set-vmcs-entry-interruption-info=<info>]\n"
+ " [--get-vmcs-guest-physical-address\n"
+ " [--get-vmcs-guest-linear-address\n"
+ " [--get-vmcs-host-pat]\n"
+ " [--get-vmcs-host-cr0]\n"
+ " [--get-vmcs-host-cr3]\n"
+ " [--get-vmcs-host-cr4]\n"
+ " [--get-vmcs-host-rip]\n"
+ " [--get-vmcs-host-rsp]\n"
+ " [--get-vmcs-cr0-mask]\n"
+ " [--get-vmcs-cr0-shadow]\n"
+ " [--get-vmcs-cr4-mask]\n"
+ " [--get-vmcs-cr4-shadow]\n"
+ " [--get-vmcs-cr3-targets]\n"
+ " [--get-vmcs-apic-access-address]\n"
+ " [--get-vmcs-virtual-apic-address]\n"
+ " [--get-vmcs-tpr-threshold]\n"
+ " [--get-vmcs-vpid]\n"
+ " [--get-vmcs-instruction-error]\n"
+ " [--get-vmcs-exit-ctls]\n"
+ " [--get-vmcs-entry-ctls]\n"
+ " [--get-vmcs-link]\n"
+ " [--get-vmcs-exit-qualification]\n"
+ " [--get-vmcs-exit-interruption-info]\n"
+ " [--get-vmcs-exit-interruption-error]\n"
+ " [--get-vmcs-interruptibility]\n"
+ );
+ } else {
+ (void)fprintf(stderr,
+ " [--get-vmcb-intercepts]\n"
+ " [--get-vmcb-asid]\n"
+ " [--get-vmcb-exit-details]\n"
+ " [--get-vmcb-tlb-ctrl]\n"
+ " [--get-vmcb-virq]\n"
+ " [--get-avic-apic-bar]\n"
+ " [--get-avic-backing-page]\n"
+ " [--get-avic-table]\n"
+ );
+ }
exit(1);
}
@@ -234,6 +253,12 @@ static int unassign_pptdev, bus, slot, func;
static int run;
/*
+ * VMCB specific.
+ */
+static int get_vmcb_intercept, get_vmcb_exit_details, get_vmcb_tlb_ctrl;
+static int get_vmcb_virq, get_avic_table;
+
+/*
* VMCS-specific fields
*/
static int get_pinbased_ctls, get_procbased_ctls, get_procbased_ctls2;
@@ -248,13 +273,13 @@ static int get_cr4_mask, get_cr4_shadow;
static int get_cr3_targets;
static int get_apic_access_addr, get_virtual_apic_addr, get_tpr_threshold;
static int get_msr_bitmap, get_msr_bitmap_address;
-static int get_vpid, get_ple_gap, get_ple_window;
+static int get_vpid_asid;
static int get_inst_err, get_exit_ctls, get_entry_ctls;
static int get_host_cr0, get_host_cr3, get_host_cr4;
static int get_host_rip, get_host_rsp;
static int get_guest_pat, get_host_pat;
static int get_guest_sysenter, get_vmcs_link;
-static int get_vmcs_exit_reason, get_vmcs_exit_qualification;
+static int get_exit_reason, get_vmcs_exit_qualification;
static int get_vmcs_exit_interruption_info, get_vmcs_exit_interruption_error;
static uint64_t desc_base;
@@ -289,29 +314,115 @@ dump_vm_run_exitcode(struct vm_exit *vmexit, int vcpu)
printf("\tinst_type\t\t%d\n", vmexit->u.vmx.inst_type);
printf("\tinst_error\t\t%d\n", vmexit->u.vmx.inst_error);
break;
+ case VM_EXITCODE_SVM:
+ printf("\treason\t\tSVM\n");
+ printf("\texit_reason\t\t%#lx\n", vmexit->u.svm.exitcode);
+ printf("\texitinfo1\t\t%#lx\n", vmexit->u.svm.exitinfo1);
+ printf("\texitinfo2\t\t%#lx\n", vmexit->u.svm.exitinfo2);
+ break;
default:
printf("*** unknown vm run exitcode %d\n", vmexit->exitcode);
break;
}
}
-static int
-dump_vmcs_msr_bitmap(int vcpu, u_long addr)
+/* AMD 6th generation and Intel compatible MSRs */
+#define MSR_AMD6TH_START 0xC0000000
+#define MSR_AMD6TH_END 0xC0001FFF
+/* AMD 7th and 8th generation compatible MSRs */
+#define MSR_AMD7TH_START 0xC0010000
+#define MSR_AMD7TH_END 0xC0011FFF
+
+static const char *
+msr_name(uint32_t msr)
{
- int error, fd, byte, bit, readable, writeable;
- u_int msr;
- const char *bitmap;
+ static char buf[32];
+
+ switch(msr) {
+ case MSR_TSC:
+ return ("MSR_TSC");
+ case MSR_EFER:
+ return ("MSR_EFER");
+ case MSR_STAR:
+ return ("MSR_STAR");
+ case MSR_LSTAR:
+ return ("MSR_LSTAR");
+ case MSR_CSTAR:
+ return ("MSR_CSTAR");
+ case MSR_SF_MASK:
+ return ("MSR_SF_MASK");
+ case MSR_FSBASE:
+ return ("MSR_FSBASE");
+ case MSR_GSBASE:
+ return ("MSR_GSBASE");
+ case MSR_KGSBASE:
+ return ("MSR_KGSBASE");
+ case MSR_SYSENTER_CS_MSR:
+ return ("MSR_SYSENTER_CS_MSR");
+ case MSR_SYSENTER_ESP_MSR:
+ return ("MSR_SYSENTER_ESP_MSR");
+ case MSR_SYSENTER_EIP_MSR:
+ return ("MSR_SYSENTER_EIP_MSR");
+ case MSR_PAT:
+ return ("MSR_PAT");
+ }
+ snprintf(buf, sizeof(buf), "MSR %#08x", msr);
+
+ return (buf);
+}
- error = -1;
- bitmap = MAP_FAILED;
+static inline void
+print_msr_pm(uint64_t msr, int vcpu, int readable, int writeable)
+{
- fd = open("/dev/mem", O_RDONLY, 0);
- if (fd < 0)
- goto done;
+ if (readable || writeable) {
+ printf("%-20s[%d]\t\t%c%c\n", msr_name(msr), vcpu,
+ readable ? 'R' : '-', writeable ? 'W' : '-');
+ }
+}
- bitmap = mmap(NULL, PAGE_SIZE, PROT_READ, 0, fd, addr);
- if (bitmap == MAP_FAILED)
- goto done;
+/*
+ * Reference APM vol2, section 15.11 MSR Intercepts.
+ */
+static void
+dump_amd_msr_pm(const char *bitmap, int vcpu)
+{
+ int byte, bit, readable, writeable;
+ uint32_t msr;
+
+ for (msr = 0; msr < 0x2000; msr++) {
+ byte = msr / 4;
+ bit = (msr % 4) * 2;
+
+ /* Look at MSRs in the range 0x00000000 to 0x00001FFF */
+ readable = (bitmap[byte] & (1 << bit)) ? 0 : 1;
+ writeable = (bitmap[byte] & (2 << bit)) ? 0 : 1;
+ print_msr_pm(msr, vcpu, readable, writeable);
+
+ /* Look at MSRs in the range 0xC0000000 to 0xC0001FFF */
+ byte += 2048;
+ readable = (bitmap[byte] & (1 << bit)) ? 0 : 1;
+ writeable = (bitmap[byte] & (2 << bit)) ? 0 : 1;
+ print_msr_pm(msr + MSR_AMD6TH_START, vcpu, readable,
+ writeable);
+
+ /* MSR 0xC0010000 to 0xC0011FF is only for AMD */
+ byte += 4096;
+ readable = (bitmap[byte] & (1 << bit)) ? 0 : 1;
+ writeable = (bitmap[byte] & (2 << bit)) ? 0 : 1;
+ print_msr_pm(msr + MSR_AMD7TH_START, vcpu, readable,
+ writeable);
+ }
+}
+
+/*
+ * Reference Intel SDM Vol3 Section 24.6.9 MSR-Bitmap Address
+ */
+static void
+dump_intel_msr_pm(const char *bitmap, int vcpu)
+{
+ int byte, bit, readable, writeable;
+ uint32_t msr;
for (msr = 0; msr < 0x2000; msr++) {
byte = msr / 8;
@@ -319,31 +430,56 @@ dump_vmcs_msr_bitmap(int vcpu, u_long addr)
/* Look at MSRs in the range 0x00000000 to 0x00001FFF */
readable = (bitmap[byte] & (1 << bit)) ? 0 : 1;
- writeable = (bitmap[2048 + byte] & (1 << bit)) ? 0 : 1;
- if (readable || writeable) {
- printf("msr 0x%08x[%d]\t\t%c%c\n", msr, vcpu,
- readable ? 'R' : '-',
- writeable ? 'W' : '-');
- }
+ writeable = (bitmap[2048 + byte] & (1 << bit)) ? 0 : 1;
+ print_msr_pm(msr, vcpu, readable, writeable);
/* Look at MSRs in the range 0xC0000000 to 0xC0001FFF */
byte += 1024;
readable = (bitmap[byte] & (1 << bit)) ? 0 : 1;
- writeable = (bitmap[2048 + byte] & (1 << bit)) ? 0 : 1;
- if (readable || writeable) {
- printf("msr 0x%08x[%d]\t\t%c%c\n",
- 0xc0000000 + msr, vcpu,
- readable ? 'R' : '-',
- writeable ? 'W' : '-');
- }
+ writeable = (bitmap[2048 + byte] & (1 << bit)) ? 0 : 1;
+ print_msr_pm(msr + MSR_AMD6TH_START, vcpu, readable,
+ writeable);
}
+}
+
+static int
+dump_msr_bitmap(int vcpu, uint64_t addr, bool cpu_intel)
+{
+ int error, fd, map_size;
+ const char *bitmap;
+
+ error = -1;
+ bitmap = MAP_FAILED;
+
+ fd = open("/dev/mem", O_RDONLY, 0);
+ if (fd < 0) {
+ perror("Couldn't open /dev/mem");
+ goto done;
+ }
+
+ if (cpu_intel)
+ map_size = PAGE_SIZE;
+ else
+ map_size = 2 * PAGE_SIZE;
+
+ bitmap = mmap(NULL, map_size, PROT_READ, MAP_SHARED, fd, addr);
+ if (bitmap == MAP_FAILED) {
+ perror("mmap failed");
+ goto done;
+ }
+
+ if (cpu_intel)
+ dump_intel_msr_pm(bitmap, vcpu);
+ else
+ dump_amd_msr_pm(bitmap, vcpu);
error = 0;
done:
if (bitmap != MAP_FAILED)
- munmap((void *)bitmap, PAGE_SIZE);
+ munmap((void *)bitmap, map_size);
if (fd >= 0)
close(fd);
+
return (error);
}
@@ -361,6 +497,22 @@ vm_set_vmcs_field(struct vmctx *ctx, int vcpu, int field, uint64_t val)
return (vm_set_register(ctx, vcpu, VMCS_IDENT(field), val));
}
+static int
+vm_get_vmcb_field(struct vmctx *ctx, int vcpu, int off, int bytes,
+ uint64_t *ret_val)
+{
+
+ return (vm_get_register(ctx, vcpu, VMCB_ACCESS(off, bytes), ret_val));
+}
+
+static int
+vm_set_vmcb_field(struct vmctx *ctx, int vcpu, int off, int bytes,
+ uint64_t val)
+{
+
+ return (vm_set_register(ctx, vcpu, VMCB_ACCESS(off, bytes), val));
+}
+
enum {
VMNAME = 1000, /* avoid collision with return values from getopt */
VCPU,
@@ -386,7 +538,7 @@ enum {
SET_TR,
SET_LDTR,
SET_X2APIC_STATE,
- SET_VMCS_EXCEPTION_BITMAP,
+ SET_EXCEPTION_BITMAP,
SET_VMCS_ENTRY_INTERRUPTION_INFO,
SET_CAP,
CAPNAME,
@@ -445,25 +597,647 @@ print_intinfo(const char *banner, uint64_t info)
printf("\n");
}
-int
-main(int argc, char *argv[])
+static bool
+cpu_vendor_intel(void)
{
- char *vmname;
- int error, ch, vcpu, ptenum;
- vm_paddr_t gpa, gpa_pmap;
- size_t len;
- struct vm_exit vmexit;
- uint64_t ctl, eptp, bm, addr, u64, pteval[4], *pte, info[2];
- struct vmctx *ctx;
- int wired;
- cpuset_t cpus;
+ u_int regs[4];
+ char cpu_vendor[13];
+
+ do_cpuid(0, regs);
+ ((u_int *)&cpu_vendor)[0] = regs[1];
+ ((u_int *)&cpu_vendor)[1] = regs[3];
+ ((u_int *)&cpu_vendor)[2] = regs[2];
+ cpu_vendor[12] = '\0';
+
+ if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
+ return (false);
+ } else if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
+ return (true);
+ } else {
+ fprintf(stderr, "Unknown cpu vendor \"%s\"\n", cpu_vendor);
+ exit(1);
+ }
+}
- uint64_t cr0, cr3, cr4, dr7, rsp, rip, rflags, efer, pat;
+static int
+get_all_registers(struct vmctx *ctx, int vcpu)
+{
+ uint64_t cr0, cr3, cr4, dr7, rsp, rip, rflags, efer;
uint64_t rax, rbx, rcx, rdx, rsi, rdi, rbp;
uint64_t r8, r9, r10, r11, r12, r13, r14, r15;
+ int error;
+
+ if (get_efer || get_all) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_EFER, &efer);
+ if (error == 0)
+ printf("efer[%d]\t\t0x%016lx\n", vcpu, efer);
+ }
+
+ if (!error && (get_cr0 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CR0, &cr0);
+ if (error == 0)
+ printf("cr0[%d]\t\t0x%016lx\n", vcpu, cr0);
+ }
+
+ if (!error && (get_cr3 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CR3, &cr3);
+ if (error == 0)
+ printf("cr3[%d]\t\t0x%016lx\n", vcpu, cr3);
+ }
+
+ if (!error && (get_cr4 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CR4, &cr4);
+ if (error == 0)
+ printf("cr4[%d]\t\t0x%016lx\n", vcpu, cr4);
+ }
+
+ if (!error && (get_dr7 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_DR7, &dr7);
+ if (error == 0)
+ printf("dr7[%d]\t\t0x%016lx\n", vcpu, dr7);
+ }
+
+ if (!error && (get_rsp || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RSP, &rsp);
+ if (error == 0)
+ printf("rsp[%d]\t\t0x%016lx\n", vcpu, rsp);
+ }
+
+ if (!error && (get_rip || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RIP, &rip);
+ if (error == 0)
+ printf("rip[%d]\t\t0x%016lx\n", vcpu, rip);
+ }
+
+ if (!error && (get_rax || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RAX, &rax);
+ if (error == 0)
+ printf("rax[%d]\t\t0x%016lx\n", vcpu, rax);
+ }
+
+ if (!error && (get_rbx || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RBX, &rbx);
+ if (error == 0)
+ printf("rbx[%d]\t\t0x%016lx\n", vcpu, rbx);
+ }
+
+ if (!error && (get_rcx || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RCX, &rcx);
+ if (error == 0)
+ printf("rcx[%d]\t\t0x%016lx\n", vcpu, rcx);
+ }
+
+ if (!error && (get_rdx || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RDX, &rdx);
+ if (error == 0)
+ printf("rdx[%d]\t\t0x%016lx\n", vcpu, rdx);
+ }
+
+ if (!error && (get_rsi || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RSI, &rsi);
+ if (error == 0)
+ printf("rsi[%d]\t\t0x%016lx\n", vcpu, rsi);
+ }
+
+ if (!error && (get_rdi || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RDI, &rdi);
+ if (error == 0)
+ printf("rdi[%d]\t\t0x%016lx\n", vcpu, rdi);
+ }
+
+ if (!error && (get_rbp || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RBP, &rbp);
+ if (error == 0)
+ printf("rbp[%d]\t\t0x%016lx\n", vcpu, rbp);
+ }
+
+ if (!error && (get_r8 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R8, &r8);
+ if (error == 0)
+ printf("r8[%d]\t\t0x%016lx\n", vcpu, r8);
+ }
+
+ if (!error && (get_r9 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R9, &r9);
+ if (error == 0)
+ printf("r9[%d]\t\t0x%016lx\n", vcpu, r9);
+ }
+
+ if (!error && (get_r10 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R10, &r10);
+ if (error == 0)
+ printf("r10[%d]\t\t0x%016lx\n", vcpu, r10);
+ }
+
+ if (!error && (get_r11 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R11, &r11);
+ if (error == 0)
+ printf("r11[%d]\t\t0x%016lx\n", vcpu, r11);
+ }
+
+ if (!error && (get_r12 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R12, &r12);
+ if (error == 0)
+ printf("r12[%d]\t\t0x%016lx\n", vcpu, r12);
+ }
+
+ if (!error && (get_r13 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R13, &r13);
+ if (error == 0)
+ printf("r13[%d]\t\t0x%016lx\n", vcpu, r13);
+ }
+
+ if (!error && (get_r14 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R14, &r14);
+ if (error == 0)
+ printf("r14[%d]\t\t0x%016lx\n", vcpu, r14);
+ }
+
+ if (!error && (get_r15 || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R15, &r15);
+ if (error == 0)
+ printf("r15[%d]\t\t0x%016lx\n", vcpu, r15);
+ }
+
+ if (!error && (get_rflags || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RFLAGS,
+ &rflags);
+ if (error == 0)
+ printf("rflags[%d]\t0x%016lx\n", vcpu, rflags);
+ }
+
+ return (error);
+}
+
+static int
+get_all_segments(struct vmctx *ctx, int vcpu)
+{
+ int error;
uint64_t cs, ds, es, fs, gs, ss, tr, ldtr;
- struct option opts[] = {
+ if (get_desc_ds || get_all) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_DS,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("ds desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_es || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_ES,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("es desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_fs || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_FS,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("fs desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_gs || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_GS,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("gs desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_ss || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_SS,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("ss desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_cs || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_CS,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("cs desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_tr || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_TR,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("tr desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_ldtr || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_LDTR,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("ldtr desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
+ vcpu, desc_base, desc_limit, desc_access);
+ }
+ }
+
+ if (!error && (get_desc_gdtr || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_GDTR,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("gdtr[%d]\t\t0x%016lx/0x%08x\n",
+ vcpu, desc_base, desc_limit);
+ }
+ }
+
+ if (!error && (get_desc_idtr || get_all)) {
+ error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_IDTR,
+ &desc_base, &desc_limit, &desc_access);
+ if (error == 0) {
+ printf("idtr[%d]\t\t0x%016lx/0x%08x\n",
+ vcpu, desc_base, desc_limit);
+ }
+ }
+
+ if (!error && (get_cs || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CS, &cs);
+ if (error == 0)
+ printf("cs[%d]\t\t0x%04lx\n", vcpu, cs);
+ }
+
+ if (!error && (get_ds || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_DS, &ds);
+ if (error == 0)
+ printf("ds[%d]\t\t0x%04lx\n", vcpu, ds);
+ }
+
+ if (!error && (get_es || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_ES, &es);
+ if (error == 0)
+ printf("es[%d]\t\t0x%04lx\n", vcpu, es);
+ }
+
+ if (!error && (get_fs || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_FS, &fs);
+ if (error == 0)
+ printf("fs[%d]\t\t0x%04lx\n", vcpu, fs);
+ }
+
+ if (!error && (get_gs || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_GS, &gs);
+ if (error == 0)
+ printf("gs[%d]\t\t0x%04lx\n", vcpu, gs);
+ }
+
+ if (!error && (get_ss || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_SS, &ss);
+ if (error == 0)
+ printf("ss[%d]\t\t0x%04lx\n", vcpu, ss);
+ }
+
+ if (!error && (get_tr || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_TR, &tr);
+ if (error == 0)
+ printf("tr[%d]\t\t0x%04lx\n", vcpu, tr);
+ }
+
+ if (!error && (get_ldtr || get_all)) {
+ error = vm_get_register(ctx, vcpu, VM_REG_GUEST_LDTR, &ldtr);
+ if (error == 0)
+ printf("ldtr[%d]\t\t0x%04lx\n", vcpu, ldtr);
+ }
+
+ return (error);
+}
+
+static int
+get_misc_vmcs(struct vmctx *ctx, int vcpu)
+{
+ uint64_t ctl, cr0, cr3, cr4, rsp, rip, pat, addr, u64;
+ int error;
+
+ if (get_cr0_mask || get_all) {
+ uint64_t cr0mask;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR0_MASK, &cr0mask);
+ if (error == 0)
+ printf("cr0_mask[%d]\t\t0x%016lx\n", vcpu, cr0mask);
+ }
+
+ if (!error && (get_cr0_shadow || get_all)) {
+ uint64_t cr0shadow;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR0_SHADOW,
+ &cr0shadow);
+ if (error == 0)
+ printf("cr0_shadow[%d]\t\t0x%016lx\n", vcpu, cr0shadow);
+ }
+
+ if (!error && (get_cr4_mask || get_all)) {
+ uint64_t cr4mask;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR4_MASK, &cr4mask);
+ if (error == 0)
+ printf("cr4_mask[%d]\t\t0x%016lx\n", vcpu, cr4mask);
+ }
+
+ if (!error && (get_cr4_shadow || get_all)) {
+ uint64_t cr4shadow;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR4_SHADOW,
+ &cr4shadow);
+ if (error == 0)
+ printf("cr4_shadow[%d]\t\t0x%016lx\n", vcpu, cr4shadow);
+ }
+
+ if (!error && (get_cr3_targets || get_all)) {
+ uint64_t target_count, target_addr;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET_COUNT,
+ &target_count);
+ if (error == 0) {
+ printf("cr3_target_count[%d]\t0x%016lx\n",
+ vcpu, target_count);
+ }
+
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET0,
+ &target_addr);
+ if (error == 0) {
+ printf("cr3_target0[%d]\t\t0x%016lx\n",
+ vcpu, target_addr);
+ }
+
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET1,
+ &target_addr);
+ if (error == 0) {
+ printf("cr3_target1[%d]\t\t0x%016lx\n",
+ vcpu, target_addr);
+ }
+
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET2,
+ &target_addr);
+ if (error == 0) {
+ printf("cr3_target2[%d]\t\t0x%016lx\n",
+ vcpu, target_addr);
+ }
+
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET3,
+ &target_addr);
+ if (error == 0) {
+ printf("cr3_target3[%d]\t\t0x%016lx\n",
+ vcpu, target_addr);
+ }
+ }
+
+ if (!error && (get_pinbased_ctls || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_PIN_BASED_CTLS, &ctl);
+ if (error == 0)
+ printf("pinbased_ctls[%d]\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_procbased_ctls || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_PRI_PROC_BASED_CTLS, &ctl);
+ if (error == 0)
+ printf("procbased_ctls[%d]\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_procbased_ctls2 || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_SEC_PROC_BASED_CTLS, &ctl);
+ if (error == 0)
+ printf("procbased_ctls2[%d]\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_vmcs_gla || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_LINEAR_ADDRESS, &u64);
+ if (error == 0)
+ printf("gla[%d]\t\t0x%016lx\n", vcpu, u64);
+ }
+
+ if (!error && (get_vmcs_gpa || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_PHYSICAL_ADDRESS, &u64);
+ if (error == 0)
+ printf("gpa[%d]\t\t0x%016lx\n", vcpu, u64);
+ }
+
+ if (!error && (get_vmcs_entry_interruption_info ||
+ get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_ENTRY_INTR_INFO,&u64);
+ if (error == 0) {
+ printf("entry_interruption_info[%d]\t0x%016lx\n",
+ vcpu, u64);
+ }
+ }
+
+ if (!error && (get_tpr_threshold || get_all)) {
+ uint64_t threshold;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_TPR_THRESHOLD,
+ &threshold);
+ if (error == 0)
+ printf("tpr_threshold[%d]\t0x%016lx\n", vcpu, threshold);
+ }
+
+ if (!error && (get_inst_err || get_all)) {
+ uint64_t insterr;
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_INSTRUCTION_ERROR,
+ &insterr);
+ if (error == 0) {
+ printf("instruction_error[%d]\t0x%016lx\n",
+ vcpu, insterr);
+ }
+ }
+
+ if (!error && (get_exit_ctls || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_CTLS, &ctl);
+ if (error == 0)
+ printf("exit_ctls[%d]\t\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_entry_ctls || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_ENTRY_CTLS, &ctl);
+ if (error == 0)
+ printf("entry_ctls[%d]\t\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_host_pat || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_IA32_PAT, &pat);
+ if (error == 0)
+ printf("host_pat[%d]\t\t0x%016lx\n", vcpu, pat);
+ }
+
+ if (!error && (get_host_cr0 || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_CR0, &cr0);
+ if (error == 0)
+ printf("host_cr0[%d]\t\t0x%016lx\n", vcpu, cr0);
+ }
+
+ if (!error && (get_host_cr3 || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_CR3, &cr3);
+ if (error == 0)
+ printf("host_cr3[%d]\t\t0x%016lx\n", vcpu, cr3);
+ }
+
+ if (!error && (get_host_cr4 || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_CR4, &cr4);
+ if (error == 0)
+ printf("host_cr4[%d]\t\t0x%016lx\n", vcpu, cr4);
+ }
+
+ if (!error && (get_host_rip || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_RIP, &rip);
+ if (error == 0)
+ printf("host_rip[%d]\t\t0x%016lx\n", vcpu, rip);
+ }
+
+ if (!error && (get_host_rsp || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_RSP, &rsp);
+ if (error == 0)
+ printf("host_rsp[%d]\t\t0x%016lx\n", vcpu, rsp);
+ }
+
+ if (!error && (get_vmcs_link || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_LINK_POINTER, &addr);
+ if (error == 0)
+ printf("vmcs_pointer[%d]\t0x%016lx\n", vcpu, addr);
+ }
+
+ if (!error && (get_vmcs_exit_interruption_info || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_INTR_INFO, &u64);
+ if (error == 0) {
+ printf("vmcs_exit_interruption_info[%d]\t0x%016lx\n",
+ vcpu, u64);
+ }
+ }
+
+ if (!error && (get_vmcs_exit_interruption_error || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_INTR_ERRCODE,
+ &u64);
+ if (error == 0) {
+ printf("vmcs_exit_interruption_error[%d]\t0x%016lx\n",
+ vcpu, u64);
+ }
+ }
+
+ if (!error && (get_vmcs_interruptibility || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_INTERRUPTIBILITY, &u64);
+ if (error == 0) {
+ printf("vmcs_guest_interruptibility[%d]\t0x%016lx\n",
+ vcpu, u64);
+ }
+ }
+
+ if (!error && (get_vmcs_exit_qualification || get_all)) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_QUALIFICATION,
+ &u64);
+ if (error == 0)
+ printf("vmcs_exit_qualification[%d]\t0x%016lx\n",
+ vcpu, u64);
+ }
+
+ return (error);
+}
+
+static int
+get_misc_vmcb(struct vmctx *ctx, int vcpu)
+{
+ uint64_t ctl, addr;
+ int error;
+
+ if (get_vmcb_intercept || get_all) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_CR_INTERCEPT, 4,
+ &ctl);
+ if (error == 0)
+ printf("cr_intercept[%d]\t0x%08x\n", vcpu, (int)ctl);
+
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_DR_INTERCEPT, 4,
+ &ctl);
+ if (error == 0)
+ printf("dr_intercept[%d]\t0x%08x\n", vcpu, (int)ctl);
+
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_EXC_INTERCEPT, 4,
+ &ctl);
+ if (error == 0)
+ printf("exc_intercept[%d]\t0x%08x\n", vcpu, (int)ctl);
+
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_INST1_INTERCEPT,
+ 4, &ctl);
+ if (error == 0)
+ printf("inst1_intercept[%d]\t0x%08x\n", vcpu, (int)ctl);
+
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_INST2_INTERCEPT,
+ 4, &ctl);
+ if (error == 0)
+ printf("inst2_intercept[%d]\t0x%08x\n", vcpu, (int)ctl);
+ }
+
+ if (!error && (get_vmcb_tlb_ctrl || get_all)) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_TLB_CTRL,
+ 4, &ctl);
+ if (error == 0)
+ printf("TLB ctrl[%d]\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_vmcb_exit_details || get_all)) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_EXITINFO1,
+ 8, &ctl);
+ if (error == 0)
+ printf("exitinfo1[%d]\t0x%016lx\n", vcpu, ctl);
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_EXITINFO2,
+ 8, &ctl);
+ if (error == 0)
+ printf("exitinfo2[%d]\t0x%016lx\n", vcpu, ctl);
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_EXITINTINFO,
+ 8, &ctl);
+ if (error == 0)
+ printf("exitintinfo[%d]\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_vmcb_virq || get_all)) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_VIRQ,
+ 8, &ctl);
+ if (error == 0)
+ printf("v_irq/tpr[%d]\t0x%016lx\n", vcpu, ctl);
+ }
+
+ if (!error && (get_apic_access_addr || get_all)) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_AVIC_BAR, 8,
+ &addr);
+ if (error == 0)
+ printf("AVIC apic_bar[%d]\t0x%016lx\n", vcpu, addr);
+ }
+
+ if (!error && (get_virtual_apic_addr || get_all)) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_AVIC_PAGE, 8,
+ &addr);
+ if (error == 0)
+ printf("AVIC backing page[%d]\t0x%016lx\n", vcpu, addr);
+ }
+
+ if (!error && (get_avic_table || get_all)) {
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_AVIC_LT, 8,
+ &addr);
+ if (error == 0)
+ printf("AVIC logical table[%d]\t0x%016lx\n",
+ vcpu, addr);
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_AVIC_PT, 8,
+ &addr);
+ if (error == 0)
+ printf("AVIC physical table[%d]\t0x%016lx\n",
+ vcpu, addr);
+ }
+
+ return (error);
+}
+
+static struct option *
+setup_options(bool cpu_intel)
+{
+ const struct option common_opts[] = {
{ "vm", REQ_ARG, 0, VMNAME },
{ "cpu", REQ_ARG, 0, VCPU },
{ "set-mem", REQ_ARG, 0, SET_MEM },
@@ -488,10 +1262,8 @@ main(int argc, char *argv[])
{ "set-tr", REQ_ARG, 0, SET_TR },
{ "set-ldtr", REQ_ARG, 0, SET_LDTR },
{ "set-x2apic-state",REQ_ARG, 0, SET_X2APIC_STATE },
- { "set-vmcs-exception-bitmap",
- REQ_ARG, 0, SET_VMCS_EXCEPTION_BITMAP },
- { "set-vmcs-entry-interruption-info",
- REQ_ARG, 0, SET_VMCS_ENTRY_INTERRUPTION_INFO },
+ { "set-exception-bitmap",
+ REQ_ARG, 0, SET_EXCEPTION_BITMAP },
{ "capname", REQ_ARG, 0, CAPNAME },
{ "unassign-pptdev", REQ_ARG, 0, UNASSIGN_PPTDEV },
{ "setcap", REQ_ARG, 0, SET_CAP },
@@ -552,6 +1324,35 @@ main(int argc, char *argv[])
{ "get-ss", NO_ARG, &get_ss, 1 },
{ "get-tr", NO_ARG, &get_tr, 1 },
{ "get-ldtr", NO_ARG, &get_ldtr, 1 },
+ { "get-eptp", NO_ARG, &get_eptp, 1 },
+ { "get-exception-bitmap",
+ NO_ARG, &get_exception_bitmap, 1 },
+ { "get-io-bitmap-address",
+ NO_ARG, &get_io_bitmap, 1 },
+ { "get-tsc-offset", NO_ARG, &get_tsc_offset, 1 },
+ { "get-msr-bitmap",
+ NO_ARG, &get_msr_bitmap, 1 },
+ { "get-msr-bitmap-address",
+ NO_ARG, &get_msr_bitmap_address, 1 },
+ { "get-guest-pat", NO_ARG, &get_guest_pat, 1 },
+ { "get-guest-sysenter",
+ NO_ARG, &get_guest_sysenter, 1 },
+ { "get-exit-reason",
+ NO_ARG, &get_exit_reason, 1 },
+ { "get-x2apic-state", NO_ARG, &get_x2apic_state, 1 },
+ { "get-all", NO_ARG, &get_all, 1 },
+ { "run", NO_ARG, &run, 1 },
+ { "create", NO_ARG, &create, 1 },
+ { "destroy", NO_ARG, &destroy, 1 },
+ { "inject-nmi", NO_ARG, &inject_nmi, 1 },
+ { "force-reset", NO_ARG, &force_reset, 1 },
+ { "force-poweroff", NO_ARG, &force_poweroff, 1 },
+ { "get-active-cpus", NO_ARG, &get_active_cpus, 1 },
+ { "get-suspended-cpus", NO_ARG, &get_suspended_cpus, 1 },
+ { "get-intinfo", NO_ARG, &get_intinfo, 1 },
+ };
+
+ const struct option intel_opts[] = {
{ "get-vmcs-pinbased-ctls",
NO_ARG, &get_pinbased_ctls, 1 },
{ "get-vmcs-procbased-ctls",
@@ -564,74 +1365,123 @@ main(int argc, char *argv[])
NO_ARG, &get_vmcs_gpa, 1 },
{ "get-vmcs-entry-interruption-info",
NO_ARG, &get_vmcs_entry_interruption_info, 1},
- { "get-vmcs-eptp", NO_ARG, &get_eptp, 1 },
- { "get-vmcs-exception-bitmap",
- NO_ARG, &get_exception_bitmap, 1 },
- { "get-vmcs-io-bitmap-address",
- NO_ARG, &get_io_bitmap, 1 },
- { "get-vmcs-tsc-offset", NO_ARG,&get_tsc_offset, 1 },
{ "get-vmcs-cr0-mask", NO_ARG, &get_cr0_mask, 1 },
{ "get-vmcs-cr0-shadow", NO_ARG,&get_cr0_shadow, 1 },
- { "get-vmcs-cr4-mask", NO_ARG, &get_cr4_mask, 1 },
- { "get-vmcs-cr4-shadow", NO_ARG,&get_cr4_shadow, 1 },
- { "get-vmcs-cr3-targets", NO_ARG, &get_cr3_targets, 1},
- { "get-vmcs-apic-access-address",
- NO_ARG, &get_apic_access_addr, 1},
- { "get-vmcs-virtual-apic-address",
- NO_ARG, &get_virtual_apic_addr, 1},
+ { "get-vmcs-cr4-mask", NO_ARG, &get_cr4_mask, 1 },
+ { "get-vmcs-cr4-shadow", NO_ARG, &get_cr4_shadow, 1 },
+ { "get-vmcs-cr3-targets", NO_ARG, &get_cr3_targets, 1 },
{ "get-vmcs-tpr-threshold",
- NO_ARG, &get_tpr_threshold, 1 },
- { "get-vmcs-msr-bitmap",
- NO_ARG, &get_msr_bitmap, 1 },
- { "get-vmcs-msr-bitmap-address",
- NO_ARG, &get_msr_bitmap_address, 1 },
- { "get-vmcs-vpid", NO_ARG, &get_vpid, 1 },
- { "get-vmcs-ple-gap", NO_ARG, &get_ple_gap, 1 },
- { "get-vmcs-ple-window", NO_ARG,&get_ple_window,1 },
- { "get-vmcs-instruction-error",
- NO_ARG, &get_inst_err, 1 },
- { "get-vmcs-exit-ctls", NO_ARG, &get_exit_ctls, 1 },
+ NO_ARG, &get_tpr_threshold, 1 },
+ { "get-vmcs-vpid", NO_ARG, &get_vpid_asid, 1 },
+ { "get-vmcs-exit-ctls", NO_ARG, &get_exit_ctls, 1 },
{ "get-vmcs-entry-ctls",
NO_ARG, &get_entry_ctls, 1 },
- { "get-vmcs-guest-pat", NO_ARG, &get_guest_pat, 1 },
+ { "get-vmcs-instruction-error",
+ NO_ARG, &get_inst_err, 1 },
{ "get-vmcs-host-pat", NO_ARG, &get_host_pat, 1 },
{ "get-vmcs-host-cr0",
- NO_ARG, &get_host_cr0, 1 },
+ NO_ARG, &get_host_cr0, 1 },
+ { "set-vmcs-entry-interruption-info",
+ REQ_ARG, 0, SET_VMCS_ENTRY_INTERRUPTION_INFO },
+ { "get-vmcs-exit-qualification",
+ NO_ARG, &get_vmcs_exit_qualification, 1 },
+ { "get-vmcs-interruptibility",
+ NO_ARG, &get_vmcs_interruptibility, 1 },
+ { "get-vmcs-exit-interruption-error",
+ NO_ARG, &get_vmcs_exit_interruption_error, 1 },
+ { "get-vmcs-exit-interruption-info",
+ NO_ARG, &get_vmcs_exit_interruption_info, 1 },
+ { "get-vmcs-link", NO_ARG, &get_vmcs_link, 1 },
{ "get-vmcs-host-cr3",
- NO_ARG, &get_host_cr3, 1 },
+ NO_ARG, &get_host_cr3, 1 },
{ "get-vmcs-host-cr4",
NO_ARG, &get_host_cr4, 1 },
{ "get-vmcs-host-rip",
NO_ARG, &get_host_rip, 1 },
{ "get-vmcs-host-rsp",
NO_ARG, &get_host_rsp, 1 },
- { "get-vmcs-guest-sysenter",
- NO_ARG, &get_guest_sysenter, 1 },
- { "get-vmcs-link", NO_ARG, &get_vmcs_link, 1 },
- { "get-vmcs-exit-reason",
- NO_ARG, &get_vmcs_exit_reason, 1 },
- { "get-vmcs-exit-qualification",
- NO_ARG, &get_vmcs_exit_qualification, 1 },
- { "get-vmcs-exit-interruption-info",
- NO_ARG, &get_vmcs_exit_interruption_info, 1},
- { "get-vmcs-exit-interruption-error",
- NO_ARG, &get_vmcs_exit_interruption_error, 1},
- { "get-vmcs-interruptibility",
- NO_ARG, &get_vmcs_interruptibility, 1 },
- { "get-x2apic-state",NO_ARG, &get_x2apic_state, 1 },
- { "get-all", NO_ARG, &get_all, 1 },
- { "run", NO_ARG, &run, 1 },
- { "create", NO_ARG, &create, 1 },
- { "destroy", NO_ARG, &destroy, 1 },
- { "inject-nmi", NO_ARG, &inject_nmi, 1 },
- { "force-reset", NO_ARG, &force_reset, 1 },
- { "force-poweroff", NO_ARG, &force_poweroff, 1 },
- { "get-active-cpus", NO_ARG, &get_active_cpus, 1 },
- { "get-suspended-cpus", NO_ARG, &get_suspended_cpus, 1 },
- { "get-intinfo", NO_ARG, &get_intinfo, 1 },
- { NULL, 0, NULL, 0 }
+ { "get-apic-access-address",
+ NO_ARG, &get_apic_access_addr, 1},
+ { "get-virtual-apic-address",
+ NO_ARG, &get_virtual_apic_addr, 1}
+ };
+
+ const struct option amd_opts[] = {
+ { "get-vmcb-intercepts",
+ NO_ARG, &get_vmcb_intercept, 1 },
+ { "get-vmcb-asid",
+ NO_ARG, &get_vpid_asid, 1 },
+ { "get-vmcb-exit-details",
+ NO_ARG, &get_vmcb_exit_details, 1 },
+ { "get-vmcb-tlb-ctrl",
+ NO_ARG, &get_vmcb_tlb_ctrl, 1 },
+ { "get-vmcb-virq",
+ NO_ARG, &get_vmcb_virq, 1 },
+ { "get-avic-apic-bar",
+ NO_ARG, &get_apic_access_addr, 1 },
+ { "get-avic-backing-page",
+ NO_ARG, &get_virtual_apic_addr, 1 },
+ { "get-avic-table",
+ NO_ARG, &get_avic_table, 1 }
};
+ const struct option null_opt = {
+ NULL, 0, NULL, 0
+ };
+
+ struct option *all_opts;
+ char *cp;
+ int optlen;
+
+ optlen = sizeof(common_opts);
+
+ if (cpu_intel)
+ optlen += sizeof(intel_opts);
+ else
+ optlen += sizeof(amd_opts);
+
+ optlen += sizeof(null_opt);
+
+ all_opts = malloc(optlen);
+
+ cp = (char *)all_opts;
+ memcpy(cp, common_opts, sizeof(common_opts));
+ cp += sizeof(common_opts);
+
+ if (cpu_intel) {
+ memcpy(cp, intel_opts, sizeof(intel_opts));
+ cp += sizeof(intel_opts);
+ } else {
+ memcpy(cp, amd_opts, sizeof(amd_opts));
+ cp += sizeof(amd_opts);
+ }
+
+ memcpy(cp, &null_opt, sizeof(null_opt));
+ cp += sizeof(null_opt);
+
+ return (all_opts);
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *vmname;
+ int error, ch, vcpu, ptenum;
+ vm_paddr_t gpa, gpa_pmap;
+ size_t len;
+ struct vm_exit vmexit;
+ uint64_t rax, cr0, cr3, cr4, dr7, rsp, rip, rflags, efer, pat;
+ uint64_t eptp, bm, addr, u64, pteval[4], *pte, info[2];
+ struct vmctx *ctx;
+ int wired;
+ cpuset_t cpus;
+ bool cpu_intel;
+ uint64_t cs, ds, es, fs, gs, ss, tr, ldtr;
+ struct option *opts;
+
+ cpu_intel = cpu_vendor_intel();
+ opts = setup_options(cpu_intel);
+
vcpu = 0;
vmname = NULL;
assert_lapic_lvt = -1;
@@ -732,7 +1582,7 @@ main(int argc, char *argv[])
x2apic_state = strtol(optarg, NULL, 0);
set_x2apic_state = 1;
break;
- case SET_VMCS_EXCEPTION_BITMAP:
+ case SET_EXCEPTION_BITMAP:
exception_bitmap = strtoul(optarg, NULL, 0);
set_exception_bitmap = 1;
break;
@@ -754,20 +1604,20 @@ main(int argc, char *argv[])
case UNASSIGN_PPTDEV:
unassign_pptdev = 1;
if (sscanf(optarg, "%d/%d/%d", &bus, &slot, &func) != 3)
- usage();
+ usage(cpu_intel);
break;
case ASSERT_LAPIC_LVT:
assert_lapic_lvt = atoi(optarg);
break;
default:
- usage();
+ usage(cpu_intel);
}
}
argc -= optind;
argv += optind;
if (vmname == NULL)
- usage();
+ usage(cpu_intel);
error = 0;
@@ -776,8 +1626,10 @@ main(int argc, char *argv[])
if (!error) {
ctx = vm_open(vmname);
- if (ctx == NULL)
- error = -1;
+ if (ctx == NULL) {
+ printf("VM:%s is not created.\n", vmname);
+ exit (1);
+ }
}
if (!error && memsize)
@@ -893,11 +1745,17 @@ main(int argc, char *argv[])
error = vm_unassign_pptdev(ctx, bus, slot, func);
if (!error && set_exception_bitmap) {
- error = vm_set_vmcs_field(ctx, vcpu, VMCS_EXCEPTION_BITMAP,
- exception_bitmap);
+ if (cpu_intel)
+ error = vm_set_vmcs_field(ctx, vcpu,
+ VMCS_EXCEPTION_BITMAP,
+ exception_bitmap);
+ else
+ error = vm_set_vmcb_field(ctx, vcpu,
+ VMCB_OFF_EXC_INTERCEPT,
+ 4, exception_bitmap);
}
- if (!error && set_vmcs_entry_interruption_info) {
+ if (!error && cpu_intel && set_vmcs_entry_interruption_info) {
error = vm_set_vmcs_field(ctx, vcpu, VMCS_ENTRY_INTR_INFO,
vmcs_entry_interruption_info);
}
@@ -926,621 +1784,172 @@ main(int argc, char *argv[])
wired ? " wired" : "");
}
- if (!error && (get_efer || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_EFER, &efer);
- if (error == 0)
- printf("efer[%d]\t\t0x%016lx\n", vcpu, efer);
- }
-
- if (!error && (get_cr0 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CR0, &cr0);
- if (error == 0)
- printf("cr0[%d]\t\t0x%016lx\n", vcpu, cr0);
- }
-
- if (!error && (get_cr3 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CR3, &cr3);
- if (error == 0)
- printf("cr3[%d]\t\t0x%016lx\n", vcpu, cr3);
- }
-
- if (!error && (get_cr4 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CR4, &cr4);
- if (error == 0)
- printf("cr4[%d]\t\t0x%016lx\n", vcpu, cr4);
- }
-
- if (!error && (get_dr7 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_DR7, &dr7);
- if (error == 0)
- printf("dr7[%d]\t\t0x%016lx\n", vcpu, dr7);
- }
-
- if (!error && (get_rsp || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RSP, &rsp);
- if (error == 0)
- printf("rsp[%d]\t\t0x%016lx\n", vcpu, rsp);
- }
-
- if (!error && (get_rip || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RIP, &rip);
- if (error == 0)
- printf("rip[%d]\t\t0x%016lx\n", vcpu, rip);
- }
-
- if (!error && (get_rax || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RAX, &rax);
- if (error == 0)
- printf("rax[%d]\t\t0x%016lx\n", vcpu, rax);
- }
-
- if (!error && (get_rbx || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RBX, &rbx);
- if (error == 0)
- printf("rbx[%d]\t\t0x%016lx\n", vcpu, rbx);
- }
-
- if (!error && (get_rcx || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RCX, &rcx);
- if (error == 0)
- printf("rcx[%d]\t\t0x%016lx\n", vcpu, rcx);
- }
-
- if (!error && (get_rdx || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RDX, &rdx);
- if (error == 0)
- printf("rdx[%d]\t\t0x%016lx\n", vcpu, rdx);
- }
-
- if (!error && (get_rsi || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RSI, &rsi);
- if (error == 0)
- printf("rsi[%d]\t\t0x%016lx\n", vcpu, rsi);
- }
-
- if (!error && (get_rdi || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RDI, &rdi);
- if (error == 0)
- printf("rdi[%d]\t\t0x%016lx\n", vcpu, rdi);
- }
-
- if (!error && (get_rbp || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RBP, &rbp);
- if (error == 0)
- printf("rbp[%d]\t\t0x%016lx\n", vcpu, rbp);
- }
-
- if (!error && (get_r8 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R8, &r8);
- if (error == 0)
- printf("r8[%d]\t\t0x%016lx\n", vcpu, r8);
- }
-
- if (!error && (get_r9 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R9, &r9);
- if (error == 0)
- printf("r9[%d]\t\t0x%016lx\n", vcpu, r9);
- }
-
- if (!error && (get_r10 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R10, &r10);
- if (error == 0)
- printf("r10[%d]\t\t0x%016lx\n", vcpu, r10);
- }
-
- if (!error && (get_r11 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R11, &r11);
- if (error == 0)
- printf("r11[%d]\t\t0x%016lx\n", vcpu, r11);
- }
-
- if (!error && (get_r12 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R12, &r12);
- if (error == 0)
- printf("r12[%d]\t\t0x%016lx\n", vcpu, r12);
- }
-
- if (!error && (get_r13 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R13, &r13);
- if (error == 0)
- printf("r13[%d]\t\t0x%016lx\n", vcpu, r13);
- }
-
- if (!error && (get_r14 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R14, &r14);
- if (error == 0)
- printf("r14[%d]\t\t0x%016lx\n", vcpu, r14);
- }
-
- if (!error && (get_r15 || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_R15, &r15);
- if (error == 0)
- printf("r15[%d]\t\t0x%016lx\n", vcpu, r15);
- }
-
- if (!error && (get_rflags || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RFLAGS,
- &rflags);
- if (error == 0)
- printf("rflags[%d]\t0x%016lx\n", vcpu, rflags);
- }
-
- if (!error && (get_stats || get_all)) {
- int i, num_stats;
- uint64_t *stats;
- struct timeval tv;
- const char *desc;
-
- stats = vm_get_stats(ctx, vcpu, &tv, &num_stats);
- if (stats != NULL) {
- printf("vcpu%d\n", vcpu);
- for (i = 0; i < num_stats; i++) {
- desc = vm_get_stat_desc(ctx, i);
- printf("%-40s\t%ld\n", desc, stats[i]);
- }
- }
- }
-
- if (!error && (get_desc_ds || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_DS,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("ds desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
-
- if (!error && (get_desc_es || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_ES,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("es desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
-
- if (!error && (get_desc_fs || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_FS,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("fs desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
-
- if (!error && (get_desc_gs || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_GS,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("gs desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
-
- if (!error && (get_desc_ss || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_SS,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("ss desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
-
- if (!error && (get_desc_cs || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_CS,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("cs desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
+ if (!error)
+ error = get_all_registers(ctx, vcpu);
- if (!error && (get_desc_tr || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_TR,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("tr desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
+ if (!error)
+ error = get_all_segments(ctx, vcpu);
- if (!error && (get_desc_ldtr || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_LDTR,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("ldtr desc[%d]\t0x%016lx/0x%08x/0x%08x\n",
- vcpu, desc_base, desc_limit, desc_access);
- }
- }
-
- if (!error && (get_desc_gdtr || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_GDTR,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("gdtr[%d]\t\t0x%016lx/0x%08x\n",
- vcpu, desc_base, desc_limit);
- }
- }
-
- if (!error && (get_desc_idtr || get_all)) {
- error = vm_get_desc(ctx, vcpu, VM_REG_GUEST_IDTR,
- &desc_base, &desc_limit, &desc_access);
- if (error == 0) {
- printf("idtr[%d]\t\t0x%016lx/0x%08x\n",
- vcpu, desc_base, desc_limit);
- }
- }
-
- if (!error && (get_cs || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_CS, &cs);
- if (error == 0)
- printf("cs[%d]\t\t0x%04lx\n", vcpu, cs);
- }
-
- if (!error && (get_ds || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_DS, &ds);
- if (error == 0)
- printf("ds[%d]\t\t0x%04lx\n", vcpu, ds);
- }
-
- if (!error && (get_es || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_ES, &es);
- if (error == 0)
- printf("es[%d]\t\t0x%04lx\n", vcpu, es);
- }
-
- if (!error && (get_fs || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_FS, &fs);
- if (error == 0)
- printf("fs[%d]\t\t0x%04lx\n", vcpu, fs);
- }
-
- if (!error && (get_gs || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_GS, &gs);
- if (error == 0)
- printf("gs[%d]\t\t0x%04lx\n", vcpu, gs);
- }
-
- if (!error && (get_ss || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_SS, &ss);
- if (error == 0)
- printf("ss[%d]\t\t0x%04lx\n", vcpu, ss);
- }
-
- if (!error && (get_tr || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_TR, &tr);
- if (error == 0)
- printf("tr[%d]\t\t0x%04lx\n", vcpu, tr);
- }
-
- if (!error && (get_ldtr || get_all)) {
- error = vm_get_register(ctx, vcpu, VM_REG_GUEST_LDTR, &ldtr);
- if (error == 0)
- printf("ldtr[%d]\t\t0x%04lx\n", vcpu, ldtr);
+ if (!error) {
+ if (cpu_intel)
+ error = get_misc_vmcs(ctx, vcpu);
+ else
+ error = get_misc_vmcb(ctx, vcpu);
}
-
+
if (!error && (get_x2apic_state || get_all)) {
error = vm_get_x2apic_state(ctx, vcpu, &x2apic_state);
if (error == 0)
printf("x2apic_state[%d]\t%d\n", vcpu, x2apic_state);
}
- if (!error && (get_pinbased_ctls || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_PIN_BASED_CTLS, &ctl);
- if (error == 0)
- printf("pinbased_ctls[%d]\t0x%08lx\n", vcpu, ctl);
- }
-
- if (!error && (get_procbased_ctls || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_PRI_PROC_BASED_CTLS, &ctl);
- if (error == 0)
- printf("procbased_ctls[%d]\t0x%08lx\n", vcpu, ctl);
- }
-
- if (!error && (get_procbased_ctls2 || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_SEC_PROC_BASED_CTLS, &ctl);
- if (error == 0)
- printf("procbased_ctls2[%d]\t0x%08lx\n", vcpu, ctl);
- }
-
- if (!error && (get_vmcs_gla || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_GUEST_LINEAR_ADDRESS, &u64);
- if (error == 0)
- printf("gla[%d]\t\t0x%016lx\n", vcpu, u64);
- }
-
- if (!error && (get_vmcs_gpa || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_GUEST_PHYSICAL_ADDRESS, &u64);
- if (error == 0)
- printf("gpa[%d]\t\t0x%016lx\n", vcpu, u64);
- }
-
- if (!error && (get_vmcs_entry_interruption_info || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_ENTRY_INTR_INFO,&u64);
- if (error == 0) {
- printf("entry_interruption_info[%d]\t0x%08lx\n",
- vcpu, u64);
- }
- }
-
if (!error && (get_eptp || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EPTP, &eptp);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_EPTP, &eptp);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_NPT_BASE,
+ 8, &eptp);
if (error == 0)
- printf("eptp[%d]\t\t0x%016lx\n", vcpu, eptp);
+ printf("%s[%d]\t\t0x%016lx\n",
+ cpu_intel ? "eptp" : "rvi/npt", vcpu, eptp);
}
if (!error && (get_exception_bitmap || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXCEPTION_BITMAP,
- &bm);
+ if(cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_EXCEPTION_BITMAP, &bm);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_EXC_INTERCEPT,
+ 4, &bm);
if (error == 0)
- printf("exception_bitmap[%d]\t0x%08lx\n", vcpu, bm);
+ printf("exception_bitmap[%d]\t%#lx\n", vcpu, bm);
}
if (!error && (get_io_bitmap || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_IO_BITMAP_A, &bm);
- if (error == 0)
- printf("io_bitmap_a[%d]\t0x%08lx\n", vcpu, bm);
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_IO_BITMAP_B, &bm);
- if (error == 0)
- printf("io_bitmap_b[%d]\t0x%08lx\n", vcpu, bm);
+ if (cpu_intel) {
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_IO_BITMAP_A,
+ &bm);
+ if (error == 0)
+ printf("io_bitmap_a[%d]\t%#lx\n", vcpu, bm);
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_IO_BITMAP_B,
+ &bm);
+ if (error == 0)
+ printf("io_bitmap_b[%d]\t%#lx\n", vcpu, bm);
+ } else {
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_IO_PERM, 8, &bm);
+ if (error == 0)
+ printf("io_bitmap[%d]\t%#lx\n", vcpu, bm);
+ }
}
if (!error && (get_tsc_offset || get_all)) {
uint64_t tscoff;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_TSC_OFFSET, &tscoff);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_TSC_OFFSET,
+ &tscoff);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_TSC_OFFSET,
+ 8, &tscoff);
if (error == 0)
printf("tsc_offset[%d]\t0x%016lx\n", vcpu, tscoff);
}
- if (!error && (get_cr0_mask || get_all)) {
- uint64_t cr0mask;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR0_MASK, &cr0mask);
- if (error == 0)
- printf("cr0_mask[%d]\t\t0x%016lx\n", vcpu, cr0mask);
- }
-
- if (!error && (get_cr0_shadow || get_all)) {
- uint64_t cr0shadow;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR0_SHADOW,
- &cr0shadow);
- if (error == 0)
- printf("cr0_shadow[%d]\t\t0x%016lx\n", vcpu, cr0shadow);
- }
-
- if (!error && (get_cr4_mask || get_all)) {
- uint64_t cr4mask;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR4_MASK, &cr4mask);
- if (error == 0)
- printf("cr4_mask[%d]\t\t0x%016lx\n", vcpu, cr4mask);
- }
-
- if (!error && (get_cr4_shadow || get_all)) {
- uint64_t cr4shadow;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR4_SHADOW,
- &cr4shadow);
- if (error == 0)
- printf("cr4_shadow[%d]\t\t0x%016lx\n", vcpu, cr4shadow);
- }
-
- if (!error && (get_cr3_targets || get_all)) {
- uint64_t target_count, target_addr;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET_COUNT,
- &target_count);
- if (error == 0) {
- printf("cr3_target_count[%d]\t0x%08lx\n",
- vcpu, target_count);
- }
-
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET0,
- &target_addr);
- if (error == 0) {
- printf("cr3_target0[%d]\t\t0x%016lx\n",
- vcpu, target_addr);
- }
-
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET1,
- &target_addr);
- if (error == 0) {
- printf("cr3_target1[%d]\t\t0x%016lx\n",
- vcpu, target_addr);
- }
-
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET2,
- &target_addr);
- if (error == 0) {
- printf("cr3_target2[%d]\t\t0x%016lx\n",
- vcpu, target_addr);
- }
-
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_CR3_TARGET3,
- &target_addr);
- if (error == 0) {
- printf("cr3_target3[%d]\t\t0x%016lx\n",
- vcpu, target_addr);
- }
- }
-
- if (!error && (get_apic_access_addr || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_APIC_ACCESS, &addr);
- if (error == 0)
- printf("apic_access_addr[%d]\t0x%016lx\n", vcpu, addr);
- }
-
- if (!error && (get_virtual_apic_addr || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_VIRTUAL_APIC, &addr);
- if (error == 0)
- printf("virtual_apic_addr[%d]\t0x%016lx\n", vcpu, addr);
- }
-
- if (!error && (get_tpr_threshold || get_all)) {
- uint64_t threshold;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_TPR_THRESHOLD,
- &threshold);
- if (error == 0)
- printf("tpr_threshold[%d]\t0x%08lx\n", vcpu, threshold);
- }
-
if (!error && (get_msr_bitmap_address || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_MSR_BITMAP, &addr);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_MSR_BITMAP,
+ &addr);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_MSR_PERM, 8, &addr);
if (error == 0)
- printf("msr_bitmap[%d]\t\t0x%016lx\n", vcpu, addr);
+ printf("msr_bitmap[%d]\t\t%#lx\n", vcpu, addr);
}
if (!error && (get_msr_bitmap || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_MSR_BITMAP, &addr);
- if (error == 0)
- error = dump_vmcs_msr_bitmap(vcpu, addr);
- }
-
- if (!error && (get_vpid || get_all)) {
- uint64_t vpid;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_VPID, &vpid);
- if (error == 0)
- printf("vpid[%d]\t\t0x%04lx\n", vcpu, vpid);
- }
-
- if (!error && (get_ple_window || get_all)) {
- uint64_t window;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_PLE_WINDOW, &window);
- if (error == 0)
- printf("ple_window[%d]\t\t0x%08lx\n", vcpu, window);
- }
-
- if (!error && (get_ple_gap || get_all)) {
- uint64_t gap;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_PLE_GAP, &gap);
- if (error == 0)
- printf("ple_gap[%d]\t\t0x%08lx\n", vcpu, gap);
- }
-
- if (!error && (get_inst_err || get_all)) {
- uint64_t insterr;
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_INSTRUCTION_ERROR,
- &insterr);
- if (error == 0) {
- printf("instruction_error[%d]\t0x%08lx\n",
- vcpu, insterr);
+ if (cpu_intel) {
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_MSR_BITMAP, &addr);
+ } else {
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_MSR_PERM, 8,
+ &addr);
}
- }
- if (!error && (get_exit_ctls || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_CTLS, &ctl);
if (error == 0)
- printf("exit_ctls[%d]\t\t0x%08lx\n", vcpu, ctl);
+ error = dump_msr_bitmap(vcpu, addr, cpu_intel);
}
- if (!error && (get_entry_ctls || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_ENTRY_CTLS, &ctl);
- if (error == 0)
- printf("entry_ctls[%d]\t\t0x%08lx\n", vcpu, ctl);
- }
-
- if (!error && (get_host_pat || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_IA32_PAT, &pat);
+ if (!error && (get_vpid_asid || get_all)) {
+ uint64_t vpid;
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_VPID, &vpid);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu, VMCB_OFF_ASID,
+ 4, &vpid);
if (error == 0)
- printf("host_pat[%d]\t\t0x%016lx\n", vcpu, pat);
+ printf("%s[%d]\t\t0x%04lx\n",
+ cpu_intel ? "vpid" : "asid", vcpu, vpid);
}
if (!error && (get_guest_pat || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_GUEST_IA32_PAT, &pat);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_IA32_PAT, &pat);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_GUEST_PAT, 8, &pat);
if (error == 0)
printf("guest_pat[%d]\t\t0x%016lx\n", vcpu, pat);
}
- if (!error && (get_host_cr0 || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_CR0, &cr0);
- if (error == 0)
- printf("host_cr0[%d]\t\t0x%016lx\n", vcpu, cr0);
- }
-
- if (!error && (get_host_cr3 || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_CR3, &cr3);
- if (error == 0)
- printf("host_cr3[%d]\t\t0x%016lx\n", vcpu, cr3);
- }
-
- if (!error && (get_host_cr4 || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_CR4, &cr4);
- if (error == 0)
- printf("host_cr4[%d]\t\t0x%016lx\n", vcpu, cr4);
- }
-
- if (!error && (get_host_rip || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_RIP, &rip);
- if (error == 0)
- printf("host_rip[%d]\t\t0x%016lx\n", vcpu, rip);
- }
-
- if (!error && (get_host_rsp || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_HOST_RSP, &rsp);
- if (error == 0)
- printf("host_rsp[%d]\t\t0x%016lx\n", vcpu, rsp);
- }
-
if (!error && (get_guest_sysenter || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_GUEST_IA32_SYSENTER_CS, &cs);
- if (error == 0)
- printf("guest_sysenter_cs[%d]\t0x%08lx\n", vcpu, cs);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_IA32_SYSENTER_CS,
+ &cs);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_SYSENTER_CS, 8,
+ &cs);
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_GUEST_IA32_SYSENTER_ESP, &rsp);
if (error == 0)
- printf("guest_sysenter_sp[%d]\t0x%016lx\n", vcpu, rsp);
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_GUEST_IA32_SYSENTER_EIP, &rip);
- if (error == 0)
- printf("guest_sysenter_ip[%d]\t0x%016lx\n", vcpu, rip);
- }
+ printf("guest_sysenter_cs[%d]\t%#lx\n", vcpu, cs);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_IA32_SYSENTER_ESP,
+ &rsp);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_SYSENTER_ESP, 8,
+ &rsp);
- if (!error && (get_vmcs_link || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_LINK_POINTER, &addr);
if (error == 0)
- printf("vmcs_pointer[%d]\t0x%016lx\n", vcpu, addr);
- }
-
- if (!error && (get_vmcs_exit_reason || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_REASON, &u64);
+ printf("guest_sysenter_sp[%d]\t%#lx\n", vcpu, rsp);
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu,
+ VMCS_GUEST_IA32_SYSENTER_EIP,
+ &rip);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_SYSENTER_EIP, 8,
+ &rip);
if (error == 0)
- printf("vmcs_exit_reason[%d]\t0x%016lx\n", vcpu, u64);
+ printf("guest_sysenter_ip[%d]\t%#lx\n", vcpu, rip);
}
- if (!error && (get_vmcs_exit_qualification || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_QUALIFICATION,
- &u64);
+ if (!error && (get_exit_reason || get_all)) {
+ if (cpu_intel)
+ error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_REASON,
+ &u64);
+ else
+ error = vm_get_vmcb_field(ctx, vcpu,
+ VMCB_OFF_EXIT_REASON, 8,
+ &u64);
if (error == 0)
- printf("vmcs_exit_qualification[%d]\t0x%016lx\n",
- vcpu, u64);
- }
-
- if (!error && (get_vmcs_exit_interruption_info || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_INTR_INFO, &u64);
- if (error == 0) {
- printf("vmcs_exit_interruption_info[%d]\t0x%08lx\n",
- vcpu, u64);
- }
- }
-
- if (!error && (get_vmcs_exit_interruption_error || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu, VMCS_EXIT_INTR_ERRCODE,
- &u64);
- if (error == 0) {
- printf("vmcs_exit_interruption_error[%d]\t0x%08lx\n",
- vcpu, u64);
- }
- }
-
- if (!error && (get_vmcs_interruptibility || get_all)) {
- error = vm_get_vmcs_field(ctx, vcpu,
- VMCS_GUEST_INTERRUPTIBILITY, &u64);
- if (error == 0) {
- printf("vmcs_guest_interruptibility[%d]\t0x%08lx\n",
- vcpu, u64);
- }
+ printf("exit_reason[%d]\t%#lx\n", vcpu, u64);
}
if (!error && setcap) {
@@ -1608,6 +2017,22 @@ main(int argc, char *argv[])
}
}
+ if (!error && (get_stats || get_all)) {
+ int i, num_stats;
+ uint64_t *stats;
+ struct timeval tv;
+ const char *desc;
+
+ stats = vm_get_stats(ctx, vcpu, &tv, &num_stats);
+ if (stats != NULL) {
+ printf("vcpu%d stats:\n", vcpu);
+ for (i = 0; i < num_stats; i++) {
+ desc = vm_get_stat_desc(ctx, i);
+ printf("%-40s\t%ld\n", desc, stats[i]);
+ }
+ }
+ }
+
if (!error && run) {
error = vm_get_register(ctx, vcpu, VM_REG_GUEST_RIP, &rip);
assert(error == 0);
@@ -1631,5 +2056,6 @@ main(int argc, char *argv[])
if (!error && destroy)
vm_destroy(ctx);
+ free (opts);
exit(error);
}
diff --git a/usr.sbin/binmiscctl/binmiscctl.8 b/usr.sbin/binmiscctl/binmiscctl.8
index c6aeca4..761810e 100644
--- a/usr.sbin/binmiscctl/binmiscctl.8
+++ b/usr.sbin/binmiscctl/binmiscctl.8
@@ -28,7 +28,7 @@
.\" Support for miscellaneous binary image activators
.\"
.Dd April 10, 2014
-.Dt BINMISCCTL 8
+.Dt BINMISCCTL 8
.Os
.Sh NAME
.Nm binmiscctl
@@ -142,7 +142,7 @@ Enable the activator entry identified with
.It Cm lookup Ar name
Look up and print out the activator entry identified with
.Ar name .
-.It Cm list
+.It Cm list
Take a snapshot and print all the activator entries currently configured.
.El
.Sh EXAMPLES
@@ -162,13 +162,13 @@ Set its state to enabled.
.Pp
.Dl # binmiscctl disable llvmbc
.Pp
-Set the state of the
+Set the state of the
.Ar llvmbc
image activator to disabled.
.Pp
.Dl # binmiscctl enable llvmbc
.Pp
-Set the state of the
+Set the state of the
.Ar llvmbc
image activator to enabled.
.Pp
diff --git a/usr.sbin/bsdconfig/Makefile b/usr.sbin/bsdconfig/Makefile
index 72187de..1f1ec9e 100644
--- a/usr.sbin/bsdconfig/Makefile
+++ b/usr.sbin/bsdconfig/Makefile
@@ -25,9 +25,4 @@ SCRIPTS= bsdconfig
MAN= bsdconfig.8
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
- mkdir -p ${DESTDIR}${SCRIPTSDIR}
- mkdir -p ${DESTDIR}${MANDIR}8
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/bsdconfig.8 b/usr.sbin/bsdconfig/bsdconfig.8
index 3f25c95c..849f85b 100644
--- a/usr.sbin/bsdconfig/bsdconfig.8
+++ b/usr.sbin/bsdconfig/bsdconfig.8
@@ -172,16 +172,27 @@ Shortcut to the Delete menu under the View/Edit Startup Configuration menu
(startup_rcconf) of startup.
.It Cm startup_rcvar
Shortcut to the Toggle Startup Services menu under startup.
+.\" use neutral name, e.g. console_keymap instead of syscons_keymap?
+.\" font (encoding) selection not applicable to vt(4)!
.It Cm syscons_font
Shortcut to the Font menu under console.
+.\" .It Cm console_keymap
+.\" Shortcut to the Keymap menu under console.
.It Cm syscons_keymap
Shortcut to the Keymap menu under console.
+.\" .It Cm vt_repeat
+.\" Shortcut to the Repeat menu under console.
.It Cm syscons_repeat
Shortcut to the Repeat menu under console.
+.\" .It Cm vt_saver
+.\" Shortcut to the Saver menu under console.
.It Cm syscons_saver
Shortcut to the Saver menu under console.
+.\" screenmap (encoding) selection not applicable to vt(4)!
.It Cm syscons_screenmap
Shortcut to the Screenmap menu under console.
+.\" .It Cm vt_syscons_ttys
+.\" Shortcut to the Ttys menu under console.
.It Cm syscons_ttys
Shortcut to the Ttys menu under console.
.It Cm timezone
diff --git a/usr.sbin/bsdconfig/console/Makefile b/usr.sbin/bsdconfig/console/Makefile
index aa6c6f1..c765a33 100644
--- a/usr.sbin/bsdconfig/console/Makefile
+++ b/usr.sbin/bsdconfig/console/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= console font keymap repeat saver screenmap ttys
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/console/include/Makefile b/usr.sbin/bsdconfig/console/include/Makefile
index e915751..d2a17a0 100644
--- a/usr.sbin/bsdconfig/console/include/Makefile
+++ b/usr.sbin/bsdconfig/console/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/080.console/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/diskmgmt/Makefile b/usr.sbin/bsdconfig/diskmgmt/Makefile
index 894c62c..fc659f8 100644
--- a/usr.sbin/bsdconfig/diskmgmt/Makefile
+++ b/usr.sbin/bsdconfig/diskmgmt/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= diskmgmt
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/diskmgmt/include/Makefile b/usr.sbin/bsdconfig/diskmgmt/include/Makefile
index 9c94c0e..33b93e0 100644
--- a/usr.sbin/bsdconfig/diskmgmt/include/Makefile
+++ b/usr.sbin/bsdconfig/diskmgmt/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/050.diskmgmt/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/docsinstall/Makefile b/usr.sbin/bsdconfig/docsinstall/Makefile
index de03d7d..4b67834 100644
--- a/usr.sbin/bsdconfig/docsinstall/Makefile
+++ b/usr.sbin/bsdconfig/docsinstall/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= docsinstall
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/docsinstall/include/Makefile b/usr.sbin/bsdconfig/docsinstall/include/Makefile
index 9f75f7d..b86091a 100644
--- a/usr.sbin/bsdconfig/docsinstall/include/Makefile
+++ b/usr.sbin/bsdconfig/docsinstall/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/020.docsinstall/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/dot/Makefile b/usr.sbin/bsdconfig/dot/Makefile
index 5a87282..0f11518 100644
--- a/usr.sbin/bsdconfig/dot/Makefile
+++ b/usr.sbin/bsdconfig/dot/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= dot
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/dot/include/Makefile b/usr.sbin/bsdconfig/dot/include/Makefile
index 9bbdea0..891279f 100644
--- a/usr.sbin/bsdconfig/dot/include/Makefile
+++ b/usr.sbin/bsdconfig/dot/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/dot/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/examples/Makefile b/usr.sbin/bsdconfig/examples/Makefile
index 156ccaf..33899d8 100644
--- a/usr.sbin/bsdconfig/examples/Makefile
+++ b/usr.sbin/bsdconfig/examples/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${SHAREDIR}/examples/bsdconfig
FILES= add_some_packages.sh browse_packages_http.sh bsdconfigrc
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/include/Makefile b/usr.sbin/bsdconfig/include/Makefile
index ee21cec..50bef4c 100644
--- a/usr.sbin/bsdconfig/include/Makefile
+++ b/usr.sbin/bsdconfig/include/Makefile
@@ -6,7 +6,4 @@ FILESDIR= ${LIBEXECDIR}/bsdconfig/include
FILES= bsdconfig.hlp media.hlp messages.subr network_device.hlp \
options.hlp tcp.hlp usage.hlp
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/includes/Makefile b/usr.sbin/bsdconfig/includes/Makefile
index f7cbc1e..4717d34 100644
--- a/usr.sbin/bsdconfig/includes/Makefile
+++ b/usr.sbin/bsdconfig/includes/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= includes
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/includes/include/Makefile b/usr.sbin/bsdconfig/includes/include/Makefile
index 79c4481..21d55a1 100644
--- a/usr.sbin/bsdconfig/includes/include/Makefile
+++ b/usr.sbin/bsdconfig/includes/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/includes/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/includes/includes b/usr.sbin/bsdconfig/includes/includes
index d831649..6e9906f 100755
--- a/usr.sbin/bsdconfig/includes/includes
+++ b/usr.sbin/bsdconfig/includes/includes
@@ -69,10 +69,12 @@ show_include()
-v use_color=${USE_COLOR:-0} \
-v re="$pattern" \
-v show_desc=${SHOW_DESC:-0} '
- function asorti(src, dest)
+ function _asorti(src, dest)
{
+ k = nitems = 0;
+
# Copy src indices to dest and calculate array length
- nitems = 0; for (i in src) dest[++nitems] = i
+ for (i in src) dest[++nitems] = i
# Sort the array of indices (dest) using insertion sort method
for (i = 1; i <= nitems; k = i++)
@@ -118,7 +120,7 @@ show_include()
}
}
END {
- n = asorti(syntax, sorted_indices)
+ n = _asorti(syntax, sorted_indices)
for (i = 1; i <= n; i++)
printf "%s", syntax[sorted_indices[i]]
}' "$file" )
diff --git a/usr.sbin/bsdconfig/mouse/Makefile b/usr.sbin/bsdconfig/mouse/Makefile
index 3b68cad..b054c8b 100644
--- a/usr.sbin/bsdconfig/mouse/Makefile
+++ b/usr.sbin/bsdconfig/mouse/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= disable enable flags mouse port type
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/mouse/include/Makefile b/usr.sbin/bsdconfig/mouse/include/Makefile
index ed0b24d..5071db8 100644
--- a/usr.sbin/bsdconfig/mouse/include/Makefile
+++ b/usr.sbin/bsdconfig/mouse/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/110.mouse/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/networking/Makefile b/usr.sbin/bsdconfig/networking/Makefile
index 4b7d528..fcd8421 100644
--- a/usr.sbin/bsdconfig/networking/Makefile
+++ b/usr.sbin/bsdconfig/networking/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= defaultrouter devices hostname nameservers networking
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/networking/include/Makefile b/usr.sbin/bsdconfig/networking/include/Makefile
index c93d486..b76349a 100644
--- a/usr.sbin/bsdconfig/networking/include/Makefile
+++ b/usr.sbin/bsdconfig/networking/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/120.networking/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/networking/share/Makefile b/usr.sbin/bsdconfig/networking/share/Makefile
index cf1119d..3cb2d4e 100644
--- a/usr.sbin/bsdconfig/networking/share/Makefile
+++ b/usr.sbin/bsdconfig/networking/share/Makefile
@@ -6,7 +6,4 @@ FILESDIR= ${SHAREDIR}/bsdconfig/networking
FILES= common.subr device.subr hostname.subr ipaddr.subr media.subr \
netmask.subr resolv.subr routing.subr services.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/networking/share/device.subr b/usr.sbin/bsdconfig/networking/share/device.subr
index 42010ab..bb41be3 100644
--- a/usr.sbin/bsdconfig/networking/share/device.subr
+++ b/usr.sbin/bsdconfig/networking/share/device.subr
@@ -82,7 +82,7 @@ f_dialog_menu_netdev()
f_struct "$dev" get name if || continue
# Skip unsavory interfaces
case "$if" in
- lo[0-9]*|ppp[0-9]*|sl[0-9]*|faith[0-9]*) continue ;;
+ lo[0-9]*|ppp[0-9]*|sl[0-9]*) continue ;;
esac
iflist="$iflist $if"
done
diff --git a/usr.sbin/bsdconfig/packages/Makefile b/usr.sbin/bsdconfig/packages/Makefile
index fd96757..6450e06 100644
--- a/usr.sbin/bsdconfig/packages/Makefile
+++ b/usr.sbin/bsdconfig/packages/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= packages
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/packages/include/Makefile b/usr.sbin/bsdconfig/packages/include/Makefile
index ed2a1f3..0c72bd4 100644
--- a/usr.sbin/bsdconfig/packages/include/Makefile
+++ b/usr.sbin/bsdconfig/packages/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/030.packages/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/password/Makefile b/usr.sbin/bsdconfig/password/Makefile
index 7330c31..0c4851f 100644
--- a/usr.sbin/bsdconfig/password/Makefile
+++ b/usr.sbin/bsdconfig/password/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= password
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/password/include/Makefile b/usr.sbin/bsdconfig/password/include/Makefile
index 27ad607..dba8f19 100644
--- a/usr.sbin/bsdconfig/password/include/Makefile
+++ b/usr.sbin/bsdconfig/password/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/040.password/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/password/share/Makefile b/usr.sbin/bsdconfig/password/share/Makefile
index ceba510..af707b3 100644
--- a/usr.sbin/bsdconfig/password/share/Makefile
+++ b/usr.sbin/bsdconfig/password/share/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${SHAREDIR}/bsdconfig/password
FILES= password.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/security/Makefile b/usr.sbin/bsdconfig/security/Makefile
index c230973..4caa6ae 100644
--- a/usr.sbin/bsdconfig/security/Makefile
+++ b/usr.sbin/bsdconfig/security/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= kern_securelevel security
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/security/include/Makefile b/usr.sbin/bsdconfig/security/include/Makefile
index a94c127..8b49a81 100644
--- a/usr.sbin/bsdconfig/security/include/Makefile
+++ b/usr.sbin/bsdconfig/security/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/130.security/include
FILES= messages.subr securelevel.hlp
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/share/Makefile b/usr.sbin/bsdconfig/share/Makefile
index 5b81af4..400cc11 100644
--- a/usr.sbin/bsdconfig/share/Makefile
+++ b/usr.sbin/bsdconfig/share/Makefile
@@ -9,7 +9,4 @@ FILES= common.subr device.subr dialog.subr geom.subr keymap.subr \
mustberoot.subr script.subr strings.subr struct.subr \
sysrc.subr variable.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/share/common.subr b/usr.sbin/bsdconfig/share/common.subr
index 8fb9adaa..b7f4ee7 100644
--- a/usr.sbin/bsdconfig/share/common.subr
+++ b/usr.sbin/bsdconfig/share/common.subr
@@ -220,6 +220,36 @@ f_have()
f_quietly type "$@"
}
+# setvar $var_to_set [$value]
+#
+# Implement setvar for shells unlike FreeBSD sh(1).
+#
+if ! f_have setvar; then
+setvar()
+{
+ [ $# -gt 0 ] || return $SUCCESS
+ local __setvar_var_to_set="$1" __setvar_right="$2" __setvar_left=
+ case $# in
+ 1) unset "$__setvar_var_to_set"
+ return $? ;;
+ 2) : fall through ;;
+ *) f_err "setvar: too many arguments\n"
+ return $FAILURE
+ esac
+ case "$__setvar_var_to_set" in *[!0-9A-Za-z_]*)
+ f_err "setvar: %s: bad variable name\n" "$__setvar_var_to_set"
+ return 2
+ esac
+ while case "$__setvar_r" in *\'*) : ;; *) false ; esac
+ do
+ __setvar_left="$__setvar_left${__setvar_right%%\'*}'\\''"
+ __setvar_right="${__setvar_right#*\'}"
+ done
+ __setvar_left="$__setvar_left${__setvar_right#*\'}"
+ eval "$__setvar_var_to_set='$__setvar_left'"
+}
+fi
+
# f_which $anything [$var_to_set]
#
# A fast built-in replacement for syntaxes such as foo=$( which bar ). In a
@@ -233,10 +263,10 @@ f_which()
{
local __name="$1" __var_to_set="$2"
case "$__name" in */*|'') return $FAILURE; esac
- local __p IFS=":" __found=
+ local __p __exec IFS=":" __found=
for __p in $PATH; do
- local __exec="$__p/$__name"
- [ -f "$__exec" -a -x "$__exec" ] && __found=1 && break
+ __exec="$__p/$__name"
+ [ -f "$__exec" -a -x "$__exec" ] && __found=1 break
done
if [ "$__found" ]; then
if [ "$__var_to_set" ]; then
diff --git a/usr.sbin/bsdconfig/share/device.subr b/usr.sbin/bsdconfig/share/device.subr
index d93cd9b..d95684d 100644
--- a/usr.sbin/bsdconfig/share/device.subr
+++ b/usr.sbin/bsdconfig/share/device.subr
@@ -1116,8 +1116,9 @@ f_device_shutdown()
f_device_sort_by_awk='
# Variables that should be defined on the invocation line:
# -v prop="property"
-function asorti(src, dest)
+function _asorti(src, dest)
{
+ k = nitems = 0
for (i in src) dest[++nitems] = i
for (i = 1; i <= nitems; k = i++) {
idx = dest[i]
@@ -1136,7 +1137,7 @@ function asorti(src, dest)
}
}
END {
- nitems = asorti(devices, devices_sorted)
+ nitems = _asorti(devices, devices_sorted)
for (i = 1; i <= nitems; i++) print devices[devices_sorted[i]]
}
'
diff --git a/usr.sbin/bsdconfig/share/dialog.subr b/usr.sbin/bsdconfig/share/dialog.subr
index e0dfe80..db99a70 100644
--- a/usr.sbin/bsdconfig/share/dialog.subr
+++ b/usr.sbin/bsdconfig/share/dialog.subr
@@ -1557,12 +1557,22 @@ f_dialog_info()
# EOF. This implies that you must execute this either as an rvalue to a pipe,
# lvalue to indirection or in a sub-shell that provides data on stdin.
#
+# To open an Xdialog(1) infobox that does not disappear until expeclitly dis-
+# missed, use the following:
+#
+# f_xdialog_info "$info_text" < /dev/tty &
+# pid=$!
+# # Perform some lengthy actions
+# kill $pid
+#
+# NB: Check $USE_XDIALOG if you need to support both dialog(1) and Xdialog(1).
+#
f_xdialog_info()
{
local info_text="$*" height width
f_dialog_infobox_size height width \
"$DIALOG_TITLE" "$DIALOG_BACKTITLE" "$info_text"
- $DIALOG \
+ exec $DIALOG \
--title "$DIALOG_TITLE" \
--backtitle "$DIALOG_BACKTITLE" \
--no-close --no-buttons \
@@ -2099,9 +2109,14 @@ f_dialog_init()
#
# Process stored command-line arguments
#
+ # NB: Using backticks instead of $(...) for portability since Linux
+ # bash(1) balks at the right parentheses encountered in the case-
+ # statement (incorrectly interpreting it as the close of $(...)).
+ #
f_dprintf "f_dialog_init: ARGV=[%s] GETOPTS_STDARGS=[%s]" \
"$ARGV" "$GETOPTS_STDARGS"
- SECURE=$( set -- $ARGV
+ SECURE=`set -- $ARGV
+ OPTIND=1
while getopts \
"$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" \
flag > /dev/null; do
@@ -2109,8 +2124,9 @@ f_dialog_init()
S) echo 1 ;;
esac
done
- )
- USE_XDIALOG=$( set -- $ARGV
+ ` # END-BACKTICK
+ USE_XDIALOG=`set -- $ARGV
+ OPTIND=1
while getopts \
"$GETOPTS_STDARGS$GETOPTS_EXTRA$GETOPTS_ALLFLAGS" \
flag > /dev/null; do
@@ -2118,7 +2134,7 @@ f_dialog_init()
S|X) echo 1 ;;
esac
done
- )
+ ` # END-BACKTICK
f_dprintf "f_dialog_init: SECURE=[%s] USE_XDIALOG=[%s]" \
"$SECURE" "$USE_XDIALOG"
diff --git a/usr.sbin/bsdconfig/share/media/Makefile b/usr.sbin/bsdconfig/share/media/Makefile
index 6436749..7be059b 100644
--- a/usr.sbin/bsdconfig/share/media/Makefile
+++ b/usr.sbin/bsdconfig/share/media/Makefile
@@ -7,7 +7,4 @@ FILES= any.subr cdrom.subr common.subr directory.subr dos.subr \
floppy.subr ftp.subr http.subr httpproxy.subr network.subr \
nfs.subr options.subr tcpip.subr ufs.subr usb.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/share/packages/Makefile b/usr.sbin/bsdconfig/share/packages/Makefile
index cb06b80..8146346 100644
--- a/usr.sbin/bsdconfig/share/packages/Makefile
+++ b/usr.sbin/bsdconfig/share/packages/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${SHAREDIR}/bsdconfig/packages
FILES= categories.subr index.subr musthavepkg.subr packages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/share/packages/index.subr b/usr.sbin/bsdconfig/share/packages/index.subr
index 35ef0da..f3c1713 100644
--- a/usr.sbin/bsdconfig/share/packages/index.subr
+++ b/usr.sbin/bsdconfig/share/packages/index.subr
@@ -241,10 +241,12 @@ f_index_read()
export msg_packages
eval "$( debug= f_getvar "$var_to_get" | awk -F'|' '
- function asorti(src, dest)
+ function _asorti(src, dest)
{
+ k = nitems = 0
+
# Copy src indices to dest and calculate array length
- nitems = 0; for (i in src) dest[++nitems] = i
+ for (i in src) dest[++nitems] = i
# Sort the array of indices (dest) using insertion sort method
for (i = 1; i <= nitems; k = i++)
@@ -290,7 +292,7 @@ f_index_read()
END {
print "_npkgs=" tpkgs # For convenience, total package count
- n = asorti(categories, categories_sorted)
+ n = _asorti(categories, categories_sorted)
# Produce package counts for each category
for (i = 1; i <= n; i++)
diff --git a/usr.sbin/bsdconfig/share/packages/packages.subr b/usr.sbin/bsdconfig/share/packages/packages.subr
index a041fb6..f3ec707 100644
--- a/usr.sbin/bsdconfig/share/packages/packages.subr
+++ b/usr.sbin/bsdconfig/share/packages/packages.subr
@@ -1029,9 +1029,11 @@ f_package_extract()
# Request the package be added via pkg-install(8)
if f_debugging; then
- f_eval_catch $funcname pkg 'pkg -d install -y "%s"' "$name"
+ f_eval_catch $funcname pkg \
+ 'pkg -d install -${depended:+A}y "%s"' "$name"
else
- f_eval_catch $funcname pkg 'pkg install -y "%s"' "$name"
+ f_eval_catch $funcname pkg \
+ 'pkg install -${depended:+A}y "%s"' "$name"
fi
if [ $? -ne $SUCCESS ]; then
$alert "$msg_pkg_install_apparently_did_not_like_the_package" \
diff --git a/usr.sbin/bsdconfig/startup/Makefile b/usr.sbin/bsdconfig/startup/Makefile
index 0bba510..afab7b1 100644
--- a/usr.sbin/bsdconfig/startup/Makefile
+++ b/usr.sbin/bsdconfig/startup/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= misc rcadd rcconf rcdelete rcedit rcvar startup
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/startup/include/Makefile b/usr.sbin/bsdconfig/startup/include/Makefile
index 1634314..40a6539 100644
--- a/usr.sbin/bsdconfig/startup/include/Makefile
+++ b/usr.sbin/bsdconfig/startup/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/140.startup/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/startup/share/Makefile b/usr.sbin/bsdconfig/startup/share/Makefile
index 01c7d03..221c38b 100644
--- a/usr.sbin/bsdconfig/startup/share/Makefile
+++ b/usr.sbin/bsdconfig/startup/share/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${SHAREDIR}/bsdconfig/startup
FILES= rcconf.subr rcedit.subr rcvar.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/timezone/Makefile b/usr.sbin/bsdconfig/timezone/Makefile
index b4ef0cb..ea6a6a6 100644
--- a/usr.sbin/bsdconfig/timezone/Makefile
+++ b/usr.sbin/bsdconfig/timezone/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= timezone
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/timezone/include/Makefile b/usr.sbin/bsdconfig/timezone/include/Makefile
index 887536e..82787e1 100644
--- a/usr.sbin/bsdconfig/timezone/include/Makefile
+++ b/usr.sbin/bsdconfig/timezone/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/090.timezone/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/timezone/share/Makefile b/usr.sbin/bsdconfig/timezone/share/Makefile
index 1b7b80c..bd67741 100644
--- a/usr.sbin/bsdconfig/timezone/share/Makefile
+++ b/usr.sbin/bsdconfig/timezone/share/Makefile
@@ -6,7 +6,4 @@ FILESDIR= ${SHAREDIR}/bsdconfig/timezone
FILES= continents.subr countries.subr iso3166.subr menus.subr \
zones.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/timezone/timezone b/usr.sbin/bsdconfig/timezone/timezone
index 0452230..66f2d78 100755
--- a/usr.sbin/bsdconfig/timezone/timezone
+++ b/usr.sbin/bsdconfig/timezone/timezone
@@ -62,7 +62,7 @@ _PATH_WALL_CMOS_CLOCK="/etc/wall_cmos_clock"
REALLYDOIT=1
REINSTALL=
USEDIALOG=1
-SKIPUTC=
+SKIPUTC= # See MAIN
VERBOSE=
TZ_OR_FAIL=
CHROOTENV=
@@ -119,6 +119,9 @@ dialog_menu_main()
############################################################ MAIN
+# Skip initial question regarding UTC v. Wall-Clock time if run in VM
+[ "$( sysctl -n kern.vm_guest 2> /dev/null )" = "none" ] || SKIPUTC=1
+
# Incorporate rc-file if it exists
[ -f "$HOME/.bsdconfigrc" ] && f_include "$HOME/.bsdconfigrc"
diff --git a/usr.sbin/bsdconfig/ttys/Makefile b/usr.sbin/bsdconfig/ttys/Makefile
index b77bc24..d53314c 100644
--- a/usr.sbin/bsdconfig/ttys/Makefile
+++ b/usr.sbin/bsdconfig/ttys/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= ttys
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/ttys/include/Makefile b/usr.sbin/bsdconfig/ttys/include/Makefile
index 9333abe..2f32175 100644
--- a/usr.sbin/bsdconfig/ttys/include/Makefile
+++ b/usr.sbin/bsdconfig/ttys/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/150.ttys/include
FILES= messages.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/Makefile b/usr.sbin/bsdconfig/usermgmt/Makefile
index 5211c3c..d82f6d6 100644
--- a/usr.sbin/bsdconfig/usermgmt/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/Makefile
@@ -10,7 +10,4 @@ FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
SCRIPTS= groupadd groupdel groupedit useradd userdel useredit usermgmt
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/include/Makefile b/usr.sbin/bsdconfig/usermgmt/include/Makefile
index 25d2a07..a63b1fe 100644
--- a/usr.sbin/bsdconfig/usermgmt/include/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/include/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt/include
FILES= messages.subr usermgmt.hlp
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/usermgmt/share/Makefile b/usr.sbin/bsdconfig/usermgmt/share/Makefile
index 7f27c92..a13c200 100644
--- a/usr.sbin/bsdconfig/usermgmt/share/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/share/Makefile
@@ -5,7 +5,4 @@ NO_OBJ=
FILESDIR= ${SHAREDIR}/bsdconfig/usermgmt
FILES= group.subr group_input.subr user.subr user_input.subr
-beforeinstall:
- mkdir -p ${DESTDIR}${FILESDIR}
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdinstall/bsdinstall.8 b/usr.sbin/bsdinstall/bsdinstall.8
index 98bab0a..f3d06fa 100644
--- a/usr.sbin/bsdinstall/bsdinstall.8
+++ b/usr.sbin/bsdinstall/bsdinstall.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 15, 2013
+.Dd October 31, 2014
.Dt BSDINSTALL 8
.Os
.Sh NAME
@@ -73,10 +73,6 @@ targets.
.Bl -tag -width ".Cm jail Ar destination"
.It Cm auto
Run the standard interactive installation, including disk partitioning.
-.It Cm entropy
-Reads a small amount of data from
-.Pa /dev/random
-and stores it in a file in the new system's root directory.
.It Cm jail Ar destination
Sets up a new chroot system at
.Pa destination ,
@@ -95,6 +91,8 @@ for more information on this target.
.It Cm keymap
If the current controlling TTY is a
.Xr syscons 4
+or
+.Xr vt 4
console, asks the user to set the current keymap, and saves the result to the
new system's
.Pa rc.conf .
@@ -117,32 +115,28 @@ If
is set, also configures the network interfaces of the current system to match.
.It Cm autopart
Provides the installer's interactive guided disk partitioner for single-disk
-installations. Partitions disks, runs
-.Xr newfs 8 ,
-and writes the new system's
-.Pa fstab .
+installations. Defaults to UFS.
.It Cm zfsboot
-Provides the installer's
-.Pq experimental
-interactive/scriptable ZFS partitioner for multi-disk installations.
+Provides an alternative ZFS-only automatic interactive disk partitioner.
Creates a single
.Ic zpool
-with datasets and writes to the new system's
-.Pa rc.conf ,
-.Pa loader.conf ,
+with separate datasets for
+.Pa /tmp ,
+.Pa /usr ,
+.Pa /usr/home ,
+.Pa /usr/ports ,
+.Pa /usr/src ,
and
-.Pa fstab .
-Supports
-.Xr geli 8 ,
-.Xr gnop 8 ,
-and many other features.
+.Pa /var .
+Optionally can set up
+.Xr geli 8
+to encrypt the disk.
.It Cm partedit
-Provides the installer's interactive manual disk partitioner, with support
-for multi disk setups, non-UFS file systems, and manual selection of
-partition schemes. Partitions disks, runs
-.Xr newfs 8 ,
-and writes the new system's
-.Pa fstab .
+Provides the installer's interactive manual disk partitioner with an interface
+identical to
+.Xr sade 8 .
+Supports multiple disks as well as UFS, ZFS, and FAT file systems. ZFS
+is set up with one pool and dataset per partition.
.It Cm scriptedpart Ar parameters
Sets up disks like
.Cm autopart
@@ -188,13 +182,19 @@ keyword causes the partition to take all the remaining space on the disk. The
.Ar type
option chooses the
.Xr gpart 8
-filesystem type (e.g. freebsd-ufs or freebsd-swap).
+filesystem type (e.g. freebsd-ufs, freebsd-zfs, or freebsd-swap).
The optional
.Ar mount point
argument sets where the created partition is to be mounted in the installed
system. As an example, a typical invocation looks like:
.Pp
bsdinstall scriptedpart ada0 { 20G freebsd-ufs /, 4G freebsd-swap, 20G freebsd-ufs /var, auto freebsd-ufs /usr }
+.Pp
+A shorter invocation to use the default partitioning (as
+.Cm autopart
+would have used) on the same disk:
+.Pp
+bsdinstall scriptedpart ada0
.It Cm mount
Mounts the file systems previously configured by
.Cm autopart ,
@@ -233,6 +233,10 @@ Interactively sets the time, date, and time zone of the new system.
Queries the user for the system daemons to begin at system startup,
writing the result into the new system's
.Pa rc.conf .
+.It Cm entropy
+Reads a small amount of data from
+.Pa /dev/random
+and stores it in a file in the new system's root directory.
.It Cm config
Installs the configuration files destined for the new system (e.g. rc.conf
fragments generated by
@@ -344,14 +348,14 @@ which is passed to the
.Cm scriptedpart
target to control disk setup.
Alternatively,
+to use
+.Cm zfsboot
instead of
-.Ev PARTITIONS ,
+.Cm partedit ,
the preamble can contain the variable
.Ev ZFSBOOT_DATASETS
-which is parsed by the
-.Pq experimental
-.Cm zfsboot
-target to control ZFS datasets/options of the boot pool setup.
+instead of
+.Ev PARTITIONS .
.Ss SETUP SCRIPT
Following the preamble is an optional shell script, beginning with a #!
declaration. This script will be run at the end of the installation process
diff --git a/usr.sbin/bsdinstall/distextract/distextract.c b/usr.sbin/bsdinstall/distextract/distextract.c
index a35dbd6..54e0171 100644
--- a/usr.sbin/bsdinstall/distextract/distextract.c
+++ b/usr.sbin/bsdinstall/distextract/distextract.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2011 Nathan Whitehorn
+ * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,114 +23,199 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/param.h>
-#include <stdio.h>
-#include <errno.h>
-#include <limits.h>
#include <archive.h>
+#include <ctype.h>
#include <dialog.h>
-
-static int extract_files(int nfiles, const char **files);
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Data to process */
+static char *distdir = NULL;
+struct file_node {
+ char *path;
+ char *name;
+ int length;
+ struct file_node *next;
+};
+static struct file_node *dists = NULL;
+
+/* Function prototypes */
+static int count_files(const char *file);
+static int extract_files(int nfiles, struct file_node *files);
+
+#if __FreeBSD_version <= 1000008 /* r232154: bump for libarchive update */
+#define archive_read_support_filter_all(x) \
+ archive_read_support_compression_all(x)
+#endif
+
+#define _errx(...) (end_dialog(), errx(__VA_ARGS__))
int
main(void)
{
- char *diststring;
- const char **dists;
- int i, retval, ndists = 0;
-
- if (getenv("DISTRIBUTIONS") == NULL) {
- fprintf(stderr, "DISTRIBUTIONS variable is not set\n");
- return (1);
- }
-
- diststring = strdup(getenv("DISTRIBUTIONS"));
- for (i = 0; diststring[i] != 0; i++)
- if (isspace(diststring[i]) && !isspace(diststring[i+1]))
- ndists++;
- ndists++; /* Last one */
-
- dists = calloc(ndists, sizeof(const char *));
- if (dists == NULL) {
- fprintf(stderr, "Out of memory!\n");
- free(diststring);
- return (1);
- }
-
- for (i = 0; i < ndists; i++)
- dists[i] = strsep(&diststring, " \t");
-
+ char *chrootdir;
+ char *distributions;
+ int ndists = 0;
+ int retval;
+ size_t file_node_size = sizeof(struct file_node);
+ size_t span;
+ struct file_node *dist = dists;
+ char error[PATH_MAX + 512];
+
+ if ((distributions = getenv("DISTRIBUTIONS")) == NULL)
+ errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set");
+ if ((distdir = getenv("BSDINSTALL_DISTDIR")) == NULL)
+ distdir = __DECONST(char *, "");
+
+ /* Initialize dialog(3) */
init_dialog(stdin, stdout);
dialog_vars.backtitle = __DECONST(char *, "FreeBSD Installer");
dlg_put_backtitle();
- if (chdir(getenv("BSDINSTALL_CHROOT")) != 0) {
- char error[512];
- sprintf(error, "Could could change to directory %s: %s\n",
- getenv("BSDINSTALL_DISTDIR"), strerror(errno));
+ dialog_msgbox("",
+ "Checking distribution archives.\nPlease wait...", 4, 35, FALSE);
+
+ /*
+ * Parse $DISTRIBUTIONS into linked-list
+ */
+ while (*distributions != '\0') {
+ span = strcspn(distributions, "\t\n\v\f\r ");
+ if (span < 1) { /* currently on whitespace */
+ distributions++;
+ continue;
+ }
+ ndists++;
+
+ /* Allocate a new struct for the distribution */
+ if (dist == NULL) {
+ if ((dist = calloc(1, file_node_size)) == NULL)
+ _errx(EXIT_FAILURE, "Out of memory!");
+ dists = dist;
+ } else {
+ dist->next = calloc(1, file_node_size);
+ if (dist->next == NULL)
+ _errx(EXIT_FAILURE, "Out of memory!");
+ dist = dist->next;
+ }
+
+ /* Set path */
+ if ((dist->path = malloc(span + 1)) == NULL)
+ _errx(EXIT_FAILURE, "Out of memory!");
+ snprintf(dist->path, span + 1, "%s", distributions);
+ dist->path[span] = '\0';
+
+ /* Set display name */
+ dist->name = strrchr(dist->path, '/');
+ if (dist->name == NULL)
+ dist->name = dist->path;
+
+ /* Set initial length in files (-1 == error) */
+ dist->length = count_files(dist->path);
+ if (dist->length < 0) {
+ end_dialog();
+ return (EXIT_FAILURE);
+ }
+
+ distributions += span;
+ }
+
+ /* Optionally chdir(2) into $BSDINSTALL_CHROOT */
+ chrootdir = getenv("BSDINSTALL_CHROOT");
+ if (chrootdir != NULL && chdir(chrootdir) != 0) {
+ snprintf(error, sizeof(error),
+ "Could not change to directory %s: %s\n",
+ chrootdir, strerror(errno));
dialog_msgbox("Error", error, 0, 0, TRUE);
end_dialog();
- return (1);
+ return (EXIT_FAILURE);
}
retval = extract_files(ndists, dists);
end_dialog();
- free(diststring);
- free(dists);
+ while ((dist = dists) != NULL) {
+ dists = dist->next;
+ if (dist->path != NULL)
+ free(dist->path);
+ free(dist);
+ }
return (retval);
}
+/*
+ * Returns number of files in archive file. Parses $BSDINSTALL_DISTDIR/MANIFEST
+ * if it exists, otherwise uses archive(3) to read the archive file.
+ */
static int
count_files(const char *file)
{
+ static FILE *manifest = NULL;
+ char *p;
+ int file_count;
+ int retval;
+ size_t span;
struct archive *archive;
struct archive_entry *entry;
- static FILE *manifest = NULL;
- char path[MAXPATHLEN];
- char errormsg[512];
- int file_count, err;
+ char line[512];
+ char path[PATH_MAX];
+ char errormsg[PATH_MAX + 512];
if (manifest == NULL) {
- sprintf(path, "%s/MANIFEST", getenv("BSDINSTALL_DISTDIR"));
+ snprintf(path, sizeof(path), "%s/MANIFEST", distdir);
manifest = fopen(path, "r");
}
if (manifest != NULL) {
- char line[512];
- char *tok1, *tok2;
-
rewind(manifest);
while (fgets(line, sizeof(line), manifest) != NULL) {
- tok2 = line;
- tok1 = strsep(&tok2, "\t");
- if (tok1 == NULL || strcmp(tok1, file) != 0)
+ p = &line[0];
+ span = strcspn(p, "\t") ;
+ if (span < 1 || strncmp(p, file, span) != 0)
continue;
/*
* We're at the right manifest line. The file count is
* in the third element
*/
- tok1 = strsep(&tok2, "\t");
- tok1 = strsep(&tok2, "\t");
- if (tok1 != NULL)
- return atoi(tok1);
+ span = strcspn(p += span + (*p != '\0' ? 1 : 0), "\t");
+ span = strcspn(p += span + (*p != '\0' ? 1 : 0), "\t");
+ if (span > 0) {
+ file_count = (int)strtol(p, (char **)NULL, 10);
+ if (file_count == 0 && errno == EINVAL)
+ continue;
+ return (file_count);
+ }
}
}
- /* Either we didn't have a manifest, or this archive wasn't there */
- archive = archive_read_new();
+ /*
+ * Either no manifest, or manifest didn't mention this archive.
+ * Use archive(3) to read the archive, counting files within.
+ */
+ if ((archive = archive_read_new()) == NULL) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error: %s\n", archive_error_string(NULL));
+ dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
+ return (-1);
+ }
archive_read_support_format_all(archive);
archive_read_support_filter_all(archive);
- sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), file);
- err = archive_read_open_filename(archive, path, 4096);
- if (err != ARCHIVE_OK) {
+ snprintf(path, sizeof(path), "%s/%s", distdir, file);
+ retval = archive_read_open_filename(archive, path, 4096);
+ if (retval != ARCHIVE_OK) {
snprintf(errormsg, sizeof(errormsg),
"Error while extracting %s: %s\n", file,
archive_error_string(archive));
@@ -146,76 +232,83 @@ count_files(const char *file)
}
static int
-extract_files(int nfiles, const char **files)
+extract_files(int nfiles, struct file_node *files)
{
- const char *items[nfiles*2];
- char path[PATH_MAX];
+ int archive_file;
int archive_files[nfiles];
- int total_files, current_files, archive_file;
+ int current_files = 0;
+ int i;
+ int last_progress;
+ int progress = 0;
+ int retval;
+ int total_files = 0;
struct archive *archive;
struct archive_entry *entry;
- char errormsg[512];
+ struct file_node *file;
char status[8];
- int i, err, progress, last_progress;
+ static char title[] = "Archive Extraction";
+ static char pprompt[] = "Extracting distribution files...\n";
+ char path[PATH_MAX];
+ char errormsg[PATH_MAX + 512];
+ const char *items[nfiles*2];
- err = 0;
- progress = 0;
-
/* Make the transfer list for dialog */
- for (i = 0; i < nfiles; i++) {
- items[i*2] = strrchr(files[i], '/');
- if (items[i*2] != NULL)
- items[i*2]++;
- else
- items[i*2] = files[i];
+ i = 0;
+ for (file = files; file != NULL; file = file->next) {
+ items[i*2] = file->name;
items[i*2 + 1] = "Pending";
- }
+ archive_files[i] = file->length;
- dialog_msgbox("",
- "Checking distribution archives.\nPlease wait...", 0, 0, FALSE);
-
- /* Count all the files */
- total_files = 0;
- for (i = 0; i < nfiles; i++) {
- archive_files[i] = count_files(files[i]);
- if (archive_files[i] < 0)
- return (-1);
- total_files += archive_files[i];
+ total_files += file->length;
+ i++;
}
- current_files = 0;
-
- for (i = 0; i < nfiles; i++) {
- archive = archive_read_new();
+ i = 0;
+ for (file = files; file != NULL; file = file->next) {
+ if ((archive = archive_read_new()) == NULL) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error: %s\n", archive_error_string(NULL));
+ dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
+ return (EXIT_FAILURE);
+ }
archive_read_support_format_all(archive);
archive_read_support_filter_all(archive);
- sprintf(path, "%s/%s", getenv("BSDINSTALL_DISTDIR"), files[i]);
- err = archive_read_open_filename(archive, path, 4096);
+ snprintf(path, sizeof(path), "%s/%s", distdir, file->path);
+ retval = archive_read_open_filename(archive, path, 4096);
+ if (retval != 0) {
+ snprintf(errormsg, sizeof(errormsg),
+ "Error opening %s: %s\n", file->name,
+ archive_error_string(archive));
+ dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
+ return (EXIT_FAILURE);
+ }
items[i*2 + 1] = "In Progress";
archive_file = 0;
- while ((err = archive_read_next_header(archive, &entry)) ==
+ dialog_mixedgauge(title, pprompt, 0, 0, progress, nfiles,
+ __DECONST(char **, items));
+
+ while ((retval = archive_read_next_header(archive, &entry)) ==
ARCHIVE_OK) {
last_progress = progress;
progress = (current_files*100)/total_files;
- sprintf(status, "-%d",
+ snprintf(status, sizeof(status), "-%d",
(archive_file*100)/archive_files[i]);
items[i*2 + 1] = status;
if (progress > last_progress)
- dialog_mixedgauge("Archive Extraction",
- "Extracting distribution files...", 0, 0,
+ dialog_mixedgauge(title, pprompt, 0, 0,
progress, nfiles,
__DECONST(char **, items));
- err = archive_read_extract(archive, entry,
+ retval = archive_read_extract(archive, entry,
ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_OWNER |
ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL |
ARCHIVE_EXTRACT_XATTR | ARCHIVE_EXTRACT_FFLAGS);
- if (err != ARCHIVE_OK)
+ if (retval != ARCHIVE_OK)
break;
archive_file++;
@@ -224,18 +317,22 @@ extract_files(int nfiles, const char **files)
items[i*2 + 1] = "Done";
- if (err != ARCHIVE_EOF) {
+ if (retval != ARCHIVE_EOF) {
snprintf(errormsg, sizeof(errormsg),
"Error while extracting %s: %s\n", items[i*2],
archive_error_string(archive));
items[i*2 + 1] = "Failed";
- dialog_msgbox("Extract Error", errormsg, 0, 0,
- TRUE);
- return (err);
+ dialog_msgbox("Extract Error", errormsg, 0, 0, TRUE);
+ return (retval);
}
+ progress = (current_files*100)/total_files;
+ dialog_mixedgauge(title, pprompt, 0, 0, progress, nfiles,
+ __DECONST(char **, items));
+
archive_read_free(archive);
+ i++;
}
- return (0);
+ return (EXIT_SUCCESS);
}
diff --git a/usr.sbin/bsdinstall/distfetch/distfetch.c b/usr.sbin/bsdinstall/distfetch/distfetch.c
index ae5766c..4e870c8 100644
--- a/usr.sbin/bsdinstall/distfetch/distfetch.c
+++ b/usr.sbin/bsdinstall/distfetch/distfetch.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2011 Nathan Whitehorn
+ * Copyright (c) 2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,15 +23,21 @@
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
- *
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/param.h>
-#include <stdio.h>
+#include <ctype.h>
+#include <err.h>
+#include <dialog.h>
#include <errno.h>
#include <fetch.h>
-#include <dialog.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
static int fetch_files(int nfiles, char **urls);
@@ -39,12 +46,13 @@ main(void)
{
char *diststring;
char **urls;
- int i, nfetched, ndists = 0;
+ int i;
+ int ndists = 0;
+ int nfetched;
+ char error[PATH_MAX + 512];
- if (getenv("DISTRIBUTIONS") == NULL) {
- fprintf(stderr, "DISTRIBUTIONS variable is not set\n");
- return (1);
- }
+ if (getenv("DISTRIBUTIONS") == NULL)
+ errx(EXIT_FAILURE, "DISTRIBUTIONS variable is not set");
diststring = strdup(getenv("DISTRIBUTIONS"));
for (i = 0; diststring[i] != 0; i++)
@@ -54,9 +62,8 @@ main(void)
urls = calloc(ndists, sizeof(const char *));
if (urls == NULL) {
- fprintf(stderr, "Out of memory!\n");
free(diststring);
- return (1);
+ errx(EXIT_FAILURE, "Out of memory!");
}
init_dialog(stdin, stdout);
@@ -65,17 +72,17 @@ main(void)
for (i = 0; i < ndists; i++) {
urls[i] = malloc(PATH_MAX);
- sprintf(urls[i], "%s/%s", getenv("BSDINSTALL_DISTSITE"),
- strsep(&diststring, " \t"));
+ snprintf(urls[i], PATH_MAX, "%s/%s",
+ getenv("BSDINSTALL_DISTSITE"), strsep(&diststring, " \t"));
}
if (chdir(getenv("BSDINSTALL_DISTDIR")) != 0) {
- char error[512];
- sprintf(error, "Could could change to directory %s: %s\n",
+ snprintf(error, sizeof(error),
+ "Could could change to directory %s: %s\n",
getenv("BSDINSTALL_DISTDIR"), strerror(errno));
dialog_msgbox("Error", error, 0, 0, TRUE);
end_dialog();
- return (1);
+ return (EXIT_FAILURE);
}
nfetched = fetch_files(ndists, urls);
@@ -87,31 +94,32 @@ main(void)
free(urls[i]);
free(urls);
- return ((nfetched == ndists) ? 0 : 1);
+ return ((nfetched == ndists) ? EXIT_SUCCESS : EXIT_FAILURE);
}
static int
fetch_files(int nfiles, char **urls)
{
+ FILE *fetch_out;
+ FILE *file_out;
const char **items;
- FILE *fetch_out, *file_out;
- struct url_stat ustat;
- off_t total_bytes, current_bytes, fsize;
+ int i;
+ int last_progress;
+ int nsuccess = 0; /* Number of files successfully downloaded */
+ int progress = 0;
+ size_t chunk;
+ off_t current_bytes;
+ off_t fsize;
+ off_t total_bytes;
char status[8];
- char errormsg[512];
+ struct url_stat ustat;
+ char errormsg[PATH_MAX + 512];
uint8_t block[4096];
- size_t chunk;
- int i, progress, last_progress;
- int nsuccess = 0; /* Number of files successfully downloaded */
- progress = 0;
-
/* Make the transfer list for dialog */
items = calloc(sizeof(char *), nfiles * 2);
- if (items == NULL) {
- fprintf(stderr, "Out of memory!\n");
- return (-1);
- }
+ if (items == NULL)
+ errx(EXIT_FAILURE, "Out of memory!");
for (i = 0; i < nfiles; i++) {
items[i*2] = strrchr(urls[i], '/');
@@ -177,7 +185,8 @@ fetch_files(int nfiles, char **urls)
}
if (ustat.size > 0) {
- sprintf(status, "-%jd", (fsize*100)/ustat.size);
+ snprintf(status, sizeof(status), "-%jd",
+ (fsize*100)/ustat.size);
items[i*2 + 1] = status;
}
@@ -212,4 +221,3 @@ fetch_files(int nfiles, char **urls)
free(items);
return (nsuccess);
}
-
diff --git a/usr.sbin/bsdinstall/partedit/gpart_ops.c b/usr.sbin/bsdinstall/partedit/gpart_ops.c
index 27feb57..37b172e 100644
--- a/usr.sbin/bsdinstall/partedit/gpart_ops.c
+++ b/usr.sbin/bsdinstall/partedit/gpart_ops.c
@@ -27,6 +27,7 @@
*/
#include <sys/param.h>
+#include <sys/stat.h>
#include <errno.h>
#include <libutil.h>
#include <inttypes.h>
@@ -119,6 +120,53 @@ newfs_command(const char *fstype, char *command, int use_default)
else if (strcmp(items[i].name, "TRIM") == 0)
strcat(command, "-t ");
}
+ } else if (strcmp(fstype, "freebsd-zfs") == 0) {
+ int i;
+ DIALOG_LISTITEM items[] = {
+ {"fletcher4", "checksum algorithm: fletcher4",
+ "Use fletcher4 for data integrity checking. "
+ "(default)", 1 },
+ {"fletcher2", "checksum algorithm: fletcher2",
+ "Use fletcher2 for data integrity checking. "
+ "(not recommended)", 0 },
+ {"sha256", "checksum algorithm: sha256",
+ "Use sha256 for data integrity checking. "
+ "(not recommended)", 0 },
+ {"atime", "Update atimes for files",
+ "Disable atime update", 0 },
+ };
+
+ if (!use_default) {
+ int choice;
+ choice = dlg_checklist("ZFS Options", "", 0, 0, 0,
+ sizeof(items)/sizeof(items[0]), items, NULL,
+ FLAG_CHECK, &i);
+ if (choice == 1) /* Cancel */
+ return;
+ }
+
+ strcpy(command, "zpool create -f -m none ");
+ if (getenv("BSDINSTALL_TMPBOOT") != NULL) {
+ char zfsboot_path[MAXPATHLEN];
+ sprintf(zfsboot_path, "%s/zfs",
+ getenv("BSDINSTALL_TMPBOOT"));
+ mkdir(zfsboot_path, S_IRWXU | S_IRGRP | S_IXGRP |
+ S_IROTH | S_IXOTH);
+ sprintf(command, "%s -o cachefile=%s/zpool.cache ",
+ command, zfsboot_path);
+ }
+ for (i = 0; i < (int)(sizeof(items)/sizeof(items[0])); i++) {
+ if (items[i].state == 0)
+ continue;
+ if (strcmp(items[i].name, "fletcher4") == 0)
+ strcat(command, "-O checksum=fletcher4 ");
+ else if (strcmp(items[i].name, "fletcher2") == 0)
+ strcat(command, "-O checksum=fletcher2 ");
+ else if (strcmp(items[i].name, "sha256") == 0)
+ strcat(command, "-O checksum=sha256 ");
+ else if (strcmp(items[i].name, "atime") == 0)
+ strcat(command, "-O atime=off ");
+ }
} else if (strcmp(fstype, "fat32") == 0 || strcmp(fstype, "efi") == 0) {
int i;
DIALOG_LISTITEM items[] = {
@@ -329,7 +377,7 @@ gpart_bootcode(struct ggeom *gp)
}
static void
-gpart_partcode(struct gprovider *pp)
+gpart_partcode(struct gprovider *pp, const char *fstype)
{
struct gconfig *gc;
const char *scheme;
@@ -344,7 +392,7 @@ gpart_partcode(struct gprovider *pp)
}
/* Make sure this partition scheme needs partcode on this platform */
- if (partcode_path(scheme) == NULL)
+ if (partcode_path(scheme, fstype) == NULL)
return;
LIST_FOREACH(gc, &pp->lg_config, lg_config) {
@@ -356,7 +404,7 @@ gpart_partcode(struct gprovider *pp)
/* Shell out to gpart for partcode for now */
sprintf(command, "gpart bootcode -p %s -i %s %s",
- partcode_path(scheme), indexstr, pp->lg_geom->lg_name);
+ partcode_path(scheme, fstype), indexstr, pp->lg_geom->lg_name);
if (system(command) != 0) {
sprintf(message, "Error installing partcode on partition %s",
pp->lg_name);
@@ -416,15 +464,15 @@ gpart_edit(struct gprovider *pp)
const char *errstr, *oldtype, *scheme;
struct partition_metadata *md;
char sizestr[32];
- char newfs[64];
+ char newfs[255];
intmax_t idx;
int hadlabel, choice, junk, nitems;
unsigned i;
DIALOG_FORMITEM items[] = {
{0, "Type:", 5, 0, 0, FALSE, "", 11, 0, 12, 15, 0,
- FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)",
- FALSE},
+ FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, "
+ "freebsd-swap)", FALSE},
{0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 0, 0,
FALSE, "Partition size. Append K, M, G for kilobytes, "
"megabytes or gigabytes.", FALSE},
@@ -565,6 +613,8 @@ set_default_part_metadata(const char *name, const char *scheme,
const char *type, const char *mountpoint, const char *newfs)
{
struct partition_metadata *md;
+ char *zpool_name = NULL;
+ int i;
/* Set part metadata */
md = get_part_metadata(name, 1);
@@ -577,8 +627,18 @@ set_default_part_metadata(const char *name, const char *scheme,
if (newfs != NULL && newfs[0] != '\0') {
md->newfs = malloc(strlen(newfs) + strlen(" /dev/") +
- strlen(name) + 1);
- sprintf(md->newfs, "%s /dev/%s", newfs, name);
+ strlen(mountpoint) + 5 + strlen(name) + 1);
+ if (strcmp("freebsd-zfs", type) == 0) {
+ zpool_name = strdup((strlen(mountpoint) == 1) ?
+ "root" : &mountpoint[1]);
+ for (i = 0; zpool_name[i] != 0; i++)
+ if (!isalnum(zpool_name[i]))
+ zpool_name[i] = '_';
+ sprintf(md->newfs, "%s %s /dev/%s", newfs,
+ zpool_name, name);
+ } else {
+ sprintf(md->newfs, "%s /dev/%s", newfs, name);
+ }
}
}
@@ -587,8 +647,9 @@ set_default_part_metadata(const char *name, const char *scheme,
if (strcmp(type, bootpart_type(scheme)) == 0)
md->bootcode = 1;
- /* VTOC8 needs partcode in UFS partitions */
- if (strcmp(scheme, "VTOC8") == 0 && strcmp(type, "freebsd-ufs") == 0)
+ /* VTOC8 needs partcode at the start of partitions */
+ if (strcmp(scheme, "VTOC8") == 0 && (strcmp(type, "freebsd-ufs") == 0
+ || strcmp(type, "freebsd-zfs") == 0))
md->bootcode = 1;
if (mountpoint == NULL || mountpoint[0] == '\0') {
@@ -611,8 +672,13 @@ set_default_part_metadata(const char *name, const char *scheme,
free(md->fstab->fs_mntops);
free(md->fstab->fs_type);
}
- md->fstab->fs_spec = malloc(strlen(name) + 6);
- sprintf(md->fstab->fs_spec, "/dev/%s", name);
+ if (strcmp("freebsd-zfs", type) == 0) {
+ md->fstab->fs_spec = strdup(zpool_name);
+ } else {
+ md->fstab->fs_spec = malloc(strlen(name) +
+ strlen("/dev/") + 1);
+ sprintf(md->fstab->fs_spec, "/dev/%s", name);
+ }
md->fstab->fs_file = strdup(mountpoint);
/* Get VFS from text after freebsd-, if possible */
if (strncmp("freebsd-", type, 8) == 0)
@@ -625,6 +691,10 @@ set_default_part_metadata(const char *name, const char *scheme,
md->fstab->fs_type = strdup(FSTAB_SW);
md->fstab->fs_freq = 0;
md->fstab->fs_passno = 0;
+ } else if (strcmp(type, "freebsd-zfs") == 0) {
+ md->fstab->fs_type = strdup(FSTAB_RW);
+ md->fstab->fs_freq = 0;
+ md->fstab->fs_passno = 0;
} else {
md->fstab->fs_type = strdup(FSTAB_RW);
if (strcmp(mountpoint, "/") == 0) {
@@ -637,6 +707,9 @@ set_default_part_metadata(const char *name, const char *scheme,
}
md->fstab->fs_mntops = strdup(md->fstab->fs_type);
}
+
+ if (zpool_name != NULL)
+ free(zpool_name);
}
static
@@ -748,7 +821,7 @@ gpart_create(struct gprovider *pp, char *default_type, char *default_size,
struct ggeom *geom;
const char *errstr, *scheme;
char sizestr[32], startstr[32], output[64], *newpartname;
- char newfs[64], options_fstype[64];
+ char newfs[255], options_fstype[64];
intmax_t maxsize, size, sector, firstfree, stripe;
uint64_t bytes;
int nitems, choice, junk;
@@ -756,8 +829,8 @@ gpart_create(struct gprovider *pp, char *default_type, char *default_size,
DIALOG_FORMITEM items[] = {
{0, "Type:", 5, 0, 0, FALSE, "freebsd-ufs", 11, 0, 12, 15, 0,
- FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-swap)",
- FALSE},
+ FALSE, "Filesystem type (e.g. freebsd-ufs, freebsd-zfs, "
+ "freebsd-swap)", FALSE},
{0, "Size:", 5, 1, 0, FALSE, "", 11, 1, 12, 15, 0,
FALSE, "Partition size. Append K, M, G for kilobytes, "
"megabytes or gigabytes.", FALSE},
@@ -935,6 +1008,20 @@ addpartform:
goto addpartform;
}
+ /* If this is the root partition, check that this fs is bootable */
+ if (strcmp(items[2].text, "/") == 0 && !is_fs_bootable(scheme,
+ items[0].text)) {
+ char message[512];
+ sprintf(message, "This file system (%s) is not bootable "
+ "on this system. Are you sure you want to proceed?",
+ items[0].text);
+ dialog_vars.defaultno = TRUE;
+ choice = dialog_yesno("Warning", message, 0, 0);
+ dialog_vars.defaultno = FALSE;
+ if (choice == 1) /* cancel */
+ goto addpartform;
+ }
+
/*
* If this is the root partition, and we need a boot partition, ask
* the user to add one.
@@ -1177,12 +1264,22 @@ gpart_commit(struct gmesh *mesh)
struct gctl_req *r;
const char *errstr;
const char *modified;
+ const char *rootfs;
LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
if (strcmp(classp->lg_name, "PART") == 0)
break;
}
+ /* Figure out what filesystem / uses */
+ rootfs = "ufs"; /* Assume ufs if nothing else present */
+ TAILQ_FOREACH(md, &part_metadata, metadata) {
+ if (md->fstab != NULL && strcmp(md->fstab->fs_file, "/") == 0) {
+ rootfs = md->fstab->fs_vfstype;
+ break;
+ }
+ }
+
if (strcmp(classp->lg_name, "PART") != 0) {
dialog_msgbox("Error", "gpart not found!", 0, 0, TRUE);
return;
@@ -1222,7 +1319,7 @@ gpart_commit(struct gmesh *mesh)
break;
if (cp == NULL) /* No sub-partitions */
- gpart_partcode(pp);
+ gpart_partcode(pp, rootfs);
}
r = gctl_get_handle();
diff --git a/usr.sbin/bsdinstall/partedit/part_wizard.c b/usr.sbin/bsdinstall/partedit/part_wizard.c
index a304fb8..3f7ccd5 100644
--- a/usr.sbin/bsdinstall/partedit/part_wizard.c
+++ b/usr.sbin/bsdinstall/partedit/part_wizard.c
@@ -31,6 +31,9 @@
#include <libutil.h>
#include <inttypes.h>
+#include <sys/sysctl.h>
+#include <string.h>
+
#include <libgeom.h>
#include <dialog.h>
#include <dlg_keys.h>
@@ -44,10 +47,16 @@ static char *boot_disk(struct gmesh *mesh);
static char *wizard_partition(struct gmesh *mesh, const char *disk);
int
-part_wizard(void) {
+part_wizard(const char *fsreq) {
int error;
struct gmesh mesh;
char *disk, *schemeroot;
+ const char *fstype;
+
+ if (fsreq != NULL)
+ fstype = fsreq;
+ else
+ fstype = "ufs";
startwizard:
error = geom_gettree(&mesh);
@@ -70,11 +79,11 @@ startwizard:
dlg_put_backtitle();
error = geom_gettree(&mesh);
- error = wizard_makeparts(&mesh, schemeroot, 1);
+ error = wizard_makeparts(&mesh, schemeroot, fstype, 1);
if (error)
goto startwizard;
free(schemeroot);
-
+
geom_deletetree(&mesh);
return (0);
@@ -106,9 +115,9 @@ boot_disk(struct gmesh *mesh)
LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
desc = type = NULL;
LIST_FOREACH(gc, &pp->lg_config, lg_config) {
- if (strcmp(gc->lg_name, "type") == 0)
+ if (strcmp(gc->lg_name, "type") == 0)
type = gc->lg_val;
- if (strcmp(gc->lg_name, "descr") == 0)
+ if (strcmp(gc->lg_name, "descr") == 0)
desc = gc->lg_val;
}
@@ -200,7 +209,7 @@ wizard_partition(struct gmesh *mesh, const char *disk)
break;
if (classp != NULL) {
- LIST_FOREACH(gpart, &classp->lg_geom, lg_geom)
+ LIST_FOREACH(gpart, &classp->lg_geom, lg_geom)
if (strcmp(gpart->lg_name, disk) == 0)
break;
}
@@ -282,21 +291,29 @@ query:
}
int
-wizard_makeparts(struct gmesh *mesh, const char *disk, int interactive)
+wizard_makeparts(struct gmesh *mesh, const char *disk, const char *fstype, int interactive)
{
struct gmesh submesh;
struct gclass *classp;
struct ggeom *gp;
struct gprovider *pp;
intmax_t swapsize, available;
- char swapsizestr[10], rootsizestr[10];
+ char swapsizestr[10], rootsizestr[10], *fsname;
+ char *fsnames[] = {"freebsd-ufs", "freebsd-zfs"};
int retval;
+ if (strcmp(fstype, "zfs") == 0) {
+ fsname = fsnames[1];
+ } else {
+ /* default to UFS */
+ fsname = fsnames[0];
+ }
+
LIST_FOREACH(classp, &mesh->lg_class, lg_class)
if (strcmp(classp->lg_name, "PART") == 0)
break;
- LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
+ LIST_FOREACH(gp, &classp->lg_geom, lg_geom)
if (strcmp(gp->lg_name, disk) == 0)
break;
@@ -331,7 +348,7 @@ wizard_makeparts(struct gmesh *mesh, const char *disk, int interactive)
geom_gettree(&submesh);
pp = provider_for_name(&submesh, disk);
- gpart_create(pp, "freebsd-ufs", rootsizestr, "/", NULL, 0);
+ gpart_create(pp, fsname, rootsizestr, "/", NULL, 0);
geom_deletetree(&submesh);
geom_gettree(&submesh);
diff --git a/usr.sbin/bsdinstall/partedit/partedit.c b/usr.sbin/bsdinstall/partedit/partedit.c
index eff87fe..ac3cd8a 100644
--- a/usr.sbin/bsdinstall/partedit/partedit.c
+++ b/usr.sbin/bsdinstall/partedit/partedit.c
@@ -95,7 +95,12 @@ main(int argc, const char **argv)
if (strcmp(basename(argv[0]), "autopart") == 0) { /* Guided */
prompt = "Please review the disk setup. When complete, press "
"the Finish button.";
- part_wizard();
+ /* Experimental ZFS autopartition support */
+ if (argc > 1 && strcmp(argv[1], "zfs") == 0) {
+ part_wizard("zfs");
+ } else {
+ part_wizard("ufs");
+ }
} else if (strcmp(basename(argv[0]), "scriptedpart") == 0) {
error = scripted_editor(argc, argv);
prompt = NULL;
@@ -162,7 +167,7 @@ main(int argc, const char **argv)
init_fstab_metadata();
break;
case 4: /* Auto */
- part_wizard();
+ part_wizard("ufs");
break;
}
diff --git a/usr.sbin/bsdinstall/partedit/partedit.h b/usr.sbin/bsdinstall/partedit/partedit.h
index 32e3a36..b6f7258 100644
--- a/usr.sbin/bsdinstall/partedit/partedit.h
+++ b/usr.sbin/bsdinstall/partedit/partedit.h
@@ -54,9 +54,10 @@ struct partition_metadata {
struct partition_metadata *get_part_metadata(const char *name, int create);
void delete_part_metadata(const char *name);
-int part_wizard(void);
+int part_wizard(const char *fstype);
int scripted_editor(int argc, const char **argv);
-int wizard_makeparts(struct gmesh *mesh, const char *disk, int interactive);
+int wizard_makeparts(struct gmesh *mesh, const char *disk, const char *fstype,
+ int interactive);
/* gpart operations */
void gpart_delete(struct gprovider *pp);
@@ -75,9 +76,10 @@ void set_default_part_metadata(const char *name, const char *scheme,
/* machine-dependent bootability checks */
const char *default_scheme(void);
int is_scheme_bootable(const char *scheme);
+int is_fs_bootable(const char *scheme, const char *fs);
size_t bootpart_size(const char *scheme);
const char *bootpart_type(const char *scheme);
const char *bootcode_path(const char *scheme);
-const char *partcode_path(const char *scheme);
+const char *partcode_path(const char *scheme, const char *fs_type);
#endif
diff --git a/usr.sbin/bsdinstall/partedit/partedit_generic.c b/usr.sbin/bsdinstall/partedit/partedit_generic.c
index 8498a78..ceee95a 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_generic.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_generic.c
@@ -50,6 +50,11 @@ is_scheme_bootable(const char *part_type) {
return (1);
}
+int
+is_fs_bootable(const char *part_type, const char *fs) {
+ return (1);
+}
+
/* No clue => no boot partition, bootcode, or partcode */
size_t
@@ -68,7 +73,7 @@ bootcode_path(const char *part_type) {
}
const char *
-partcode_path(const char *part_type) {
+partcode_path(const char *part_type, const char *fs_type) {
return (NULL);
}
diff --git a/usr.sbin/bsdinstall/partedit/partedit_pc98.c b/usr.sbin/bsdinstall/partedit/partedit_pc98.c
index dd075a1..8e914ea 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_pc98.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_pc98.c
@@ -45,6 +45,15 @@ is_scheme_bootable(const char *part_type) {
return (0);
}
+int
+is_fs_bootable(const char *part_type, const char *fs)
+{
+ if (strcmp(fs, "freebsd-ufs") == 0)
+ return (1);
+
+ return (0);
+}
+
size_t
bootpart_size(const char *part_type) {
/* No boot partition */
@@ -67,7 +76,7 @@ bootcode_path(const char *part_type) {
}
const char *
-partcode_path(const char *part_type) {
+partcode_path(const char *part_type, const char *fs_type) {
/* No partcode */
return (NULL);
}
diff --git a/usr.sbin/bsdinstall/partedit/partedit_powerpc.c b/usr.sbin/bsdinstall/partedit/partedit_powerpc.c
index 77c682a..6a5dbb2 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_powerpc.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_powerpc.c
@@ -67,6 +67,15 @@ is_scheme_bootable(const char *part_type) {
return (0);
}
+int
+is_fs_bootable(const char *part_type, const char *fs)
+{
+ if (strcmp(fs, "freebsd-ufs") == 0)
+ return (1);
+
+ return (0);
+}
+
size_t
bootpart_size(const char *part_type) {
size_t platlen = sizeof(platform);
@@ -100,7 +109,7 @@ bootcode_path(const char *part_type) {
}
const char *
-partcode_path(const char *part_type) {
+partcode_path(const char *part_type, const char *fs_type) {
size_t platlen = sizeof(platform);
if (strlen(platform) == 0)
sysctlbyname("hw.platform", platform, &platlen, NULL, -1);
diff --git a/usr.sbin/bsdinstall/partedit/partedit_sparc64.c b/usr.sbin/bsdinstall/partedit/partedit_sparc64.c
index 8232c55..c420f6a 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_sparc64.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_sparc64.c
@@ -42,6 +42,15 @@ is_scheme_bootable(const char *part_type) {
return (0);
}
+int
+is_fs_bootable(const char *part_type, const char *fs)
+{
+ if (strcmp(fs, "freebsd-ufs") == 0 || strcmp(fs, "freebsd-zfs") == 0)
+ return (1);
+ return (0);
+}
+
+
size_t
bootpart_size(const char *part_type) {
/* No standalone boot partition */
@@ -58,11 +67,16 @@ const char *
bootcode_path(const char *part_type) {
return (NULL);
}
-
+
const char *
-partcode_path(const char *part_type) {
- if (strcmp(part_type, "VTOC8") == 0)
- return ("/boot/boot1");
+partcode_path(const char *part_type, const char *fs_type) {
+ if (strcmp(part_type, "VTOC8") == 0) {
+ if (strcmp(fs_type, "ufs") == 0) {
+ return ("/boot/boot1");
+ } else if (strcmp(fs_type, "zfs") == 0) {
+ return ("/boot/zfsboot");
+ }
+ }
return (NULL);
}
diff --git a/usr.sbin/bsdinstall/partedit/partedit_x86.c b/usr.sbin/bsdinstall/partedit/partedit_x86.c
index b458475..cc6a571 100644
--- a/usr.sbin/bsdinstall/partedit/partedit_x86.c
+++ b/usr.sbin/bsdinstall/partedit/partedit_x86.c
@@ -32,23 +32,35 @@
#include "partedit.h"
-static char platform[255] = "";
-static const char *platform_sysctl = "machdep.bootmethod";
+static const char *
+x86_bootmethod(void)
+{
+ static char fw[255] = "";
+ size_t len = sizeof(fw);
+ int error;
+
+ if (strlen(fw) == 0) {
+ error = sysctlbyname("machdep.bootmethod", fw, &len, NULL, -1);
+ if (error != 0)
+ return ("BIOS");
+ }
+
+ return (fw);
+}
const char *
-default_scheme(void) {
+default_scheme(void)
+{
return ("GPT");
}
int
-is_scheme_bootable(const char *part_type) {
- size_t platlen = sizeof(platform);
- if (strlen(platform) == 0)
- sysctlbyname(platform_sysctl, platform, &platlen, NULL, -1);
+is_scheme_bootable(const char *part_type)
+{
if (strcmp(part_type, "GPT") == 0)
return (1);
- if (strcmp(platform, "BIOS") == 0) {
+ if (strcmp(x86_bootmethod(), "BIOS") == 0) {
if (strcmp(part_type, "BSD") == 0)
return (1);
if (strcmp(part_type, "MBR") == 0)
@@ -58,17 +70,30 @@ is_scheme_bootable(const char *part_type) {
return (0);
}
+int
+is_fs_bootable(const char *part_type, const char *fs)
+{
+
+ if (strcmp(fs, "freebsd-ufs") == 0)
+ return (1);
+
+ if (strcmp(fs, "freebsd-zfs") == 0 &&
+ strcmp(part_type, "GPT") == 0 &&
+ strcmp(x86_bootmethod(), "BIOS") == 0)
+ return (1);
+
+ return (0);
+}
+
size_t
-bootpart_size(const char *scheme) {
- size_t platlen = sizeof(platform);
- if (strlen(platform) == 0)
- sysctlbyname(platform_sysctl, platform, &platlen, NULL, -1);
+bootpart_size(const char *scheme)
+{
/* No partcode except for GPT */
if (strcmp(scheme, "GPT") != 0)
return (0);
- if (strcmp(platform, "BIOS") == 0)
+ if (strcmp(x86_bootmethod(), "BIOS") == 0)
return (512*1024);
else
return (800*1024);
@@ -77,23 +102,20 @@ bootpart_size(const char *scheme) {
}
const char *
-bootpart_type(const char *scheme) {
- size_t platlen = sizeof(platform);
- if (strlen(platform) == 0)
- sysctlbyname(platform_sysctl, platform, &platlen, NULL, -1);
+bootpart_type(const char *scheme)
+{
- if (strcmp(platform, "UEFI") == 0)
+ if (strcmp(x86_bootmethod(), "UEFI") == 0)
return ("efi");
return ("freebsd-boot");
}
const char *
-bootcode_path(const char *part_type) {
- size_t platlen = sizeof(platform);
- if (strlen(platform) == 0)
- sysctlbyname(platform_sysctl, platform, &platlen, NULL, -1);
- if (strcmp(platform, "UEFI") == 0)
+bootcode_path(const char *part_type)
+{
+
+ if (strcmp(x86_bootmethod(), "UEFI") == 0)
return (NULL);
if (strcmp(part_type, "GPT") == 0)
@@ -107,14 +129,14 @@ bootcode_path(const char *part_type) {
}
const char *
-partcode_path(const char *part_type) {
- size_t platlen = sizeof(platform);
- if (strlen(platform) == 0)
- sysctlbyname(platform_sysctl, platform, &platlen, NULL, -1);
+partcode_path(const char *part_type, const char *fs_type)
+{
if (strcmp(part_type, "GPT") == 0) {
- if (strcmp(platform, "UEFI") == 0)
+ if (strcmp(x86_bootmethod(), "UEFI") == 0)
return ("/boot/boot1.efifat");
+ else if (strcmp(fs_type, "zfs") == 0)
+ return ("/boot/gptzfsboot");
else
return ("/boot/gptboot");
}
diff --git a/usr.sbin/bsdinstall/partedit/sade.8 b/usr.sbin/bsdinstall/partedit/sade.8
index 79df079..3bb1c65 100644
--- a/usr.sbin/bsdinstall/partedit/sade.8
+++ b/usr.sbin/bsdinstall/partedit/sade.8
@@ -68,7 +68,5 @@ with the equivalent part of
.Sh BUGS
The utility misses a lot of nice features, such as tools for
manipulating
-.Xr gmirror 8
-or
-.Xr zfs 8 .
+.Xr gmirror 8 .
These will be added later.
diff --git a/usr.sbin/bsdinstall/partedit/scripted.c b/usr.sbin/bsdinstall/partedit/scripted.c
index 4ac3482..876df54 100644
--- a/usr.sbin/bsdinstall/partedit/scripted.c
+++ b/usr.sbin/bsdinstall/partedit/scripted.c
@@ -109,7 +109,7 @@ part_config(char *disk, const char *scheme, char *config)
/* Create partitions */
if (config == NULL) {
- wizard_makeparts(&mesh, disk, 0);
+ wizard_makeparts(&mesh, disk, "ufs", 0);
goto finished;
}
diff --git a/usr.sbin/bsdinstall/scripts/auto b/usr.sbin/bsdinstall/scripts/auto
index c2d8fc0..433744e 100755
--- a/usr.sbin/bsdinstall/scripts/auto
+++ b/usr.sbin/bsdinstall/scripts/auto
@@ -35,11 +35,15 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
############################################################ FUNCTIONS
error() {
+ local msg
+ if [ -n "$1" ]; then
+ msg="$1\n\n"
+ fi
test -n "$DISTDIR_IS_UNIONFS" && umount -f $BSDINSTALL_DISTDIR
test -f $PATH_FSTAB && bsdinstall umount
dialog --backtitle "FreeBSD Installer" --title "Abort" \
--no-label "Exit" --yes-label "Restart" --yesno \
- "An installation step has been aborted. Would you like to restart the installation or exit the installer?" 0 0
+ "${msg}An installation step has been aborted. Would you like to restart the installation or exit the installer?" 0 0
if [ $? -ne 0 ]; then
exit 1
else
@@ -58,7 +62,7 @@ trap true SIGINT # This section is optional
bsdinstall keymap
trap error SIGINT # Catch cntrl-C here
-bsdinstall hostname || error
+bsdinstall hostname || error "Set hostname failed"
export DISTRIBUTIONS="base.txz kernel.txz"
if [ -f $BSDINSTALL_DISTDIR/MANIFEST ]; then
@@ -95,7 +99,7 @@ if [ -n "$FETCH_DISTRIBUTIONS" ]; then
BSDINSTALL_DISTSITE=$(`dirname $0`/mirrorselect 2>&1 1>&3)
MIRROR_BUTTON=$?
exec 3>&-
- test $MIRROR_BUTTON -eq 0 || error
+ test $MIRROR_BUTTON -eq 0 || error "No mirror selected"
export BSDINSTALL_DISTSITE
fi
@@ -103,14 +107,14 @@ rm -f $PATH_FSTAB
touch $PATH_FSTAB
PMODES="\
-Guided \"Partitioning Tool (Recommended for Beginners)\" \
-Manual \"Manually Configure Partitions (Expert)\" \
+\"Auto (UFS)\" \"Guided Disk Setup\" \
+Manual \"Manual Disk Setup (experts)\" \
Shell \"Open a shell and partition by hand\""
CURARCH=$( uname -m )
case $CURARCH in
amd64|i386) # Booting ZFS Supported
- PMODES="$PMODES ZFS \"Automatic Root-on-ZFS (Experimental)\""
+ PMODES="$PMODES \"Auto (ZFS)\" \"Guided Root-on-ZFS\""
;;
*) # Booting ZFS Unspported
;;
@@ -124,9 +128,9 @@ PARTMODE=`echo $PMODES | xargs dialog --backtitle "FreeBSD Installer" \
exec 3>&-
case "$PARTMODE" in
-"Guided") # Guided
- bsdinstall autopart || error
- bsdinstall mount || error
+"Auto (UFS)") # Guided
+ bsdinstall autopart || error "Partitioning error"
+ bsdinstall mount || error "Failed to mount filesystem"
;;
"Shell") # Shell
clear
@@ -136,18 +140,18 @@ case "$PARTMODE" in
"Manual") # Manual
if f_isset debugFile; then
# Give partedit the path to our logfile so it can append
- BSDINSTALL_LOG="${debugFile#+}" bsdinstall partedit || error
+ BSDINSTALL_LOG="${debugFile#+}" bsdinstall partedit || error "Partitioning error"
else
- bsdinstall partedit || error
+ bsdinstall partedit || error "Partitioning error"
fi
- bsdinstall mount || error
+ bsdinstall mount || error "Failed to mount filesystem"
;;
-"ZFS") # ZFS
- bsdinstall zfsboot || error
- bsdinstall mount || error
+"Auto (ZFS)") # ZFS
+ bsdinstall zfsboot || error "ZFS setup failed"
+ bsdinstall mount || error "Failed to mount filesystem"
;;
*)
- error
+ error "Unknown partitioning mode"
;;
esac
@@ -156,7 +160,7 @@ if [ ! -z "$FETCH_DISTRIBUTIONS" ]; then
# Download to a directory in the new system as scratch space
BSDINSTALL_FETCHDEST="$BSDINSTALL_CHROOT/usr/freebsd-dist"
- mkdir -p "$BSDINSTALL_FETCHDEST" || error
+ mkdir -p "$BSDINSTALL_FETCHDEST" || error "Could not create directory $BSDINSTALL_FETCHDEST"
export DISTRIBUTIONS="$FETCH_DISTRIBUTIONS"
# Try to use any existing distfiles
@@ -169,13 +173,13 @@ if [ ! -z "$FETCH_DISTRIBUTIONS" ]; then
fi
export FTP_PASSIVE_MODE=YES
- bsdinstall distfetch || error
+ bsdinstall distfetch || error "Failed to fetch distribution"
export DISTRIBUTIONS="$ALL_DISTRIBUTIONS"
fi
-bsdinstall checksum || error
-bsdinstall distextract || error
-bsdinstall rootpass || error
+bsdinstall checksum || error "Distribution checksum failed"
+bsdinstall distextract || error "Distribution extract failed"
+bsdinstall rootpass || error "Could not set root password"
trap true SIGINT # This section is optional
if [ "$NETCONFIG_DONE" != yes ]; then
@@ -239,7 +243,7 @@ finalconfig() {
finalconfig
trap error SIGINT # SIGINT is bad again
-bsdinstall config || error
+bsdinstall config || error "Failed to save config"
if [ ! -z "$BSDINSTALL_FETCHDEST" ]; then
[ "$BSDINSTALL_FETCHDEST" != "$BSDINSTALL_DISTDIR" ] && \
@@ -248,7 +252,8 @@ if [ ! -z "$BSDINSTALL_FETCHDEST" ]; then
fi
dialog --backtitle "FreeBSD Installer" --title "Manual Configuration" \
- --yesno "The installation is now finished. Before exiting the installer, would you like to open a shell in the new system to make any final manual modifications?" 0 0
+ --default-button no --yesno \
+ "The installation is now finished. Before exiting the installer, would you like to open a shell in the new system to make any final manual modifications?" 0 0
if [ $? -eq 0 ]; then
clear
mount -t devfs devfs "$BSDINSTALL_CHROOT/dev"
diff --git a/usr.sbin/bsdinstall/scripts/config b/usr.sbin/bsdinstall/scripts/config
index 98baade..bc3d723 100755
--- a/usr.sbin/bsdinstall/scripts/config
+++ b/usr.sbin/bsdinstall/scripts/config
@@ -36,6 +36,7 @@ cp $BSDINSTALL_TMPETC/* $BSDINSTALL_CHROOT/etc
cat $BSDINSTALL_TMPBOOT/loader.conf.* >> $BSDINSTALL_TMPBOOT/loader.conf
rm $BSDINSTALL_TMPBOOT/loader.conf.*
+df -t zfs $BSDINSTALL_CHROOT > /dev/null && echo "zfs_load=\"YES\"" >> $BSDINSTALL_TMPBOOT/loader.conf
cp $BSDINSTALL_TMPBOOT/* $BSDINSTALL_CHROOT/boot
diff --git a/usr.sbin/bsdinstall/scripts/jail b/usr.sbin/bsdinstall/scripts/jail
index e709145..cb86060 100755
--- a/usr.sbin/bsdinstall/scripts/jail
+++ b/usr.sbin/bsdinstall/scripts/jail
@@ -38,9 +38,13 @@ f_dprintf "Began Installation at %s" "$( date )"
export BSDINSTALL_CHROOT=$1
error() {
+ local msg
+ if [ -n "$1" ]; then
+ msg="$1\n\n"
+ fi
dialog --backtitle "FreeBSD Installer" --title "Abort" \
--no-label "Exit" --yes-label "Restart" --yesno \
- "An installation step has been aborted. Would you like to restart the installation or exit the installer?" 0 0
+ "${msg}An installation step has been aborted. Would you like to restart the installation or exit the installer?" 0 0
if [ $? -ne 0 ]; then
exit
else
@@ -51,7 +55,7 @@ error() {
rm -rf $BSDINSTALL_TMPETC
mkdir $BSDINSTALL_TMPETC
-mkdir -p $1 || error
+mkdir -p $1 || error "mkdir failed for $1"
test ! -d $BSDINSTALL_DISTDIR && mkdir -p $BSDINSTALL_DISTDIR
@@ -60,9 +64,9 @@ if [ ! -f $BSDINSTALL_DISTDIR/MANIFEST -a -z "$BSDINSTALL_DISTSITE" ]; then
BSDINSTALL_DISTSITE=$(`dirname $0`/mirrorselect 2>&1 1>&3)
MIRROR_BUTTON=$?
exec 3>&-
- test $MIRROR_BUTTON -eq 0 || error
+ test $MIRROR_BUTTON -eq 0 || error "No mirror selected"
export BSDINSTALL_DISTSITE
- fetch -o $BSDINSTALL_DISTDIR/MANIFEST $BSDINSTALL_DISTSITE/MANIFEST || error
+ fetch -o $BSDINSTALL_DISTDIR/MANIFEST $BSDINSTALL_DISTSITE/MANIFEST || error "Could not download $BSDINSTALL_DISTSITE/MANIFEST"
fi
export DISTRIBUTIONS="base.txz"
@@ -94,17 +98,17 @@ if [ -n "$FETCH_DISTRIBUTIONS" -a -z "$BSDINSTALL_DISTSITE" ]; then
BSDINSTALL_DISTSITE=`bsdinstall mirrorselect 2>&1 1>&3`
MIRROR_BUTTON=$?
exec 3>&-
- test $MIRROR_BUTTON -eq 0 || error
+ test $MIRROR_BUTTON -eq 0 || error "No mirror selected"
export BSDINSTALL_DISTSITE
fi
if [ ! -z "$FETCH_DISTRIBUTIONS" ]; then
- bsdinstall distfetch || error
+ bsdinstall distfetch || error "Failed to fetch distribution"
fi
-bsdinstall checksum || error
-bsdinstall distextract || error
-bsdinstall rootpass || error
+bsdinstall checksum || error "Distribution checksum failed"
+bsdinstall distextract || error "Distribution extract failed"
+bsdinstall rootpass || error "Could not set root password"
trap true SIGINT # This section is optional
bsdinstall services
@@ -114,7 +118,7 @@ dialog --backtitle "FreeBSD Installer" --title "Add User Accounts" --yesno \
bsdinstall adduser
trap error SIGINT # SIGINT is bad again
-bsdinstall config || error
+bsdinstall config || error "Failed to save config"
cp /etc/resolv.conf $1/etc
cp /etc/localtime $1/etc
diff --git a/usr.sbin/bsdinstall/scripts/services b/usr.sbin/bsdinstall/scripts/services
index 54c5018..83786c2 100755
--- a/usr.sbin/bsdinstall/scripts/services
+++ b/usr.sbin/bsdinstall/scripts/services
@@ -43,6 +43,7 @@ DAEMONS=$( dialog --backtitle "FreeBSD Installer" \
--title "System Configuration" --nocancel --separate-output \
--checklist "Choose the services you would like to be started at boot:" \
0 0 0 \
+ local_unbound "Local caching validating resolver" ${local_unbound:-off} \
sshd "Secure shell daemon" ${sshd_enable:-off} \
moused "PS/2 mouse pointer on console" ${moused_enable:-off} \
ntpd "Synchronize system and network time" ${ntpd_enable:-off} \
diff --git a/usr.sbin/bsdinstall/scripts/zfsboot b/usr.sbin/bsdinstall/scripts/zfsboot
index 9f1abb8..2b01dea 100755
--- a/usr.sbin/bsdinstall/scripts/zfsboot
+++ b/usr.sbin/bsdinstall/scripts/zfsboot
@@ -156,7 +156,7 @@ f_isset ZFSBOOT_DATASETS || ZFSBOOT_DATASETS="
/usr/src
# Create /var and friends
- /var mountpoint=/var
+ /var mountpoint=/var,canmount=off
/var/crash exec=off,setuid=off
/var/log exec=off,setuid=off
/var/mail atime=on
@@ -293,6 +293,7 @@ msg_swap_mirror_help="Mirror swap partitions for redundancy, breaks crash dumps"
msg_swap_size="Swap Size"
msg_swap_size_help="Customize how much swap space is allocated to each selected disk"
msg_these_disks_are_too_small="These disks are too small given the amount of requested\nswap (%s) and/or geli(8) (%s) partitions, which would\ntake 50%% or more of each of the following selected disk\ndevices (not recommended):\n\n %s\n\nRecommend changing partition size(s) and/or selecting a\ndifferent set of devices."
+msg_uefi_not_supported="The FreeBSD UEFI loader does not currently support booting root-on-ZFS. Your system will need to boot in legacy (CSM) mode.\nDo you want to continue?"
msg_unable_to_get_disk_capacity="Unable to get disk capacity of \`%s'"
msg_unsupported_partition_scheme="%s is an unsupported partition scheme"
msg_user_cancelled="User Cancelled."
@@ -687,6 +688,48 @@ dialog_menu_layout()
return $DIALOG_OK
}
+# dialog_uefi_prompt
+#
+# Confirm that the user wants to continue with the installation on a BIOS
+# system when they have booted with UEFI
+#
+dialog_uefi_prompt()
+{
+ local title="$DIALOG_TITLE"
+ local btitle="$DIALOG_BACKTITLE"
+ local prompt # Calculated below
+ local hline="$hline_arrows_tab_enter"
+
+ local height=8 width=50 prefix=" "
+ local plen=${#prefix} list= line=
+ local max_width=$(( $width - 3 - $plen ))
+
+ local yes no defaultno extra_args format
+ if [ "$USE_XDIALOG" ]; then
+ yes=ok no=cancel defaultno=default-no
+ extra_args="--wrap --left"
+ format="$msg_uefi_not_supported"
+ else
+ yes=yes no=no defaultno=defaultno
+ extra_args="--cr-wrap"
+ format="$msg_uefi_not_supported"
+ fi
+
+ # Add height for Xdialog(1)
+ [ "$USE_XDIALOG" ] && height=$(( $height + $height / 5 + 3 ))
+
+ prompt=$( printf "$format" )
+ f_dprintf "%s: UEFI prompt" "$0"
+ $DIALOG \
+ --title "$title" \
+ --backtitle "$btitle" \
+ --hline "$hline" \
+ --$yes-label "$msg_yes" \
+ --$no-label "$msg_no" \
+ $extra_args \
+ --yesno "$prompt" $height $width
+}
+
# zfs_create_diskpart $disk $index
#
# For each block device to be used in the zpool, rather than just create the
@@ -1272,8 +1315,6 @@ zfs_create_boot()
"$funcname"
f_eval_catch $funcname echo "$ECHO_APPEND" 'zfs_enable=\"YES\"' \
$BSDINSTALL_TMPETC/rc.conf.zfs || return $FAILURE
- f_eval_catch $funcname echo "$ECHO_APPEND" 'zfs_load=\"YES\"' \
- $BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE
f_eval_catch $funcname echo "$ECHO_APPEND" \
'kern.geom.label.disk_ident.enable=\"0\"' \
$BSDINSTALL_TMPBOOT/loader.conf.zfs || return $FAILURE
@@ -1386,6 +1427,21 @@ f_dprintf "BSDINSTALL_TMPETC=[%s]" "$BSDINSTALL_TMPETC"
f_dprintf "FSTAB_FMT=[%s]" "$FSTAB_FMT"
#
+# If the system was booted with UEFI, warn the user that FreeBSD can't do
+# ZFS with UEFI yet
+#
+if f_interactive; then
+ bootmethod=$(sysctl -n machdep.bootmethod)
+ f_dprintf "machdep.bootmethod=[%s]" "$bootmethod"
+ if [ "$bootmethod" != "BIOS" ]; then
+ dialog_uefi_prompt
+ retval=$?
+ f_dprintf "uefi_prompt=[%s]" "$retval"
+ [ $retval -eq $DIALOG_OK ] || f_die
+ fi
+fi
+
+#
# Loop over the main menu until we've accomplished what we came here to do
#
while :; do
diff --git a/usr.sbin/btxld/Makefile b/usr.sbin/btxld/Makefile
index 8df8fa1..32cf99d 100644
--- a/usr.sbin/btxld/Makefile
+++ b/usr.sbin/btxld/Makefile
@@ -4,6 +4,4 @@ PROG= btxld
MAN= btxld.8
SRCS= btxld.c elfh.c
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/config/config.8 b/usr.sbin/config/config.8
index 79520a7..bfaded9 100644
--- a/usr.sbin/config/config.8
+++ b/usr.sbin/config/config.8
@@ -73,7 +73,7 @@ This flag is kept for backward compatibility.
.It Fl I Ar path
Search in
.Ar path
-for any file included by the
+for any file included by the
.Ic include
directive. This option may be specified more than once.
.It Fl d Ar destdir
diff --git a/usr.sbin/cron/cron/Makefile b/usr.sbin/cron/cron/Makefile
index c7762f1..d9a1d24 100644
--- a/usr.sbin/cron/cron/Makefile
+++ b/usr.sbin/cron/cron/Makefile
@@ -11,6 +11,4 @@ LDADD= ${LIBCRON} ${MINUSLPAM} -lutil
WARNS?= 2
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/cron/cron/do_command.c b/usr.sbin/cron/cron/do_command.c
index fee4131..8dfd4f6 100644
--- a/usr.sbin/cron/cron/do_command.c
+++ b/usr.sbin/cron/cron/do_command.c
@@ -481,14 +481,17 @@ child_process(e, u)
auto char mailcmd[MAX_COMMAND];
auto char hostname[MAXHOSTNAMELEN];
- (void) gethostname(hostname, MAXHOSTNAMELEN);
+ if (gethostname(hostname, MAXHOSTNAMELEN) == -1)
+ hostname[0] = '\0';
+ hostname[sizeof(hostname) - 1] = '\0';
(void) snprintf(mailcmd, sizeof(mailcmd),
MAILARGS, MAILCMD);
if (!(mail = cron_popen(mailcmd, "w", e))) {
warn("%s", MAILCMD);
(void) _exit(ERROR_EXIT);
}
- fprintf(mail, "From: %s (Cron Daemon)\n", usernm);
+ fprintf(mail, "From: Cron Daemon <%s@%s>\n",
+ usernm, hostname);
fprintf(mail, "To: %s\n", mailto);
fprintf(mail, "Subject: Cron <%s@%s> %s\n",
usernm, first_word(hostname, "."),
diff --git a/usr.sbin/cron/crontab/Makefile b/usr.sbin/cron/crontab/Makefile
index cd9600a..829128e 100644
--- a/usr.sbin/cron/crontab/Makefile
+++ b/usr.sbin/cron/crontab/Makefile
@@ -15,6 +15,4 @@ CFLAGS+= -I${.CURDIR}/../cron
DPADD= ${LIBCRON} ${LIBMD} ${LIBUTIL}
LDADD= ${LIBCRON} -lmd -lutil
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/crunch/crunchgen/Makefile b/usr.sbin/crunch/crunchgen/Makefile
index 7b07f2b..8d0a78b 100644
--- a/usr.sbin/crunch/crunchgen/Makefile
+++ b/usr.sbin/crunch/crunchgen/Makefile
@@ -4,8 +4,6 @@ PROG= crunchgen
SRCS= crunchgen.c crunched_skel.c
CLEANFILES+= crunched_skel.c
-NO_PIE= yes
-
crunched_skel.c: crunched_main.c
sh -e ${.CURDIR}/mkskel.sh ${.CURDIR}/crunched_main.c >crunched_skel.c
diff --git a/usr.sbin/crunch/crunchide/Makefile b/usr.sbin/crunch/crunchide/Makefile
index e328aa4..ab8b902 100644
--- a/usr.sbin/crunch/crunchide/Makefile
+++ b/usr.sbin/crunch/crunchide/Makefile
@@ -3,8 +3,6 @@
PROG= crunchide
SRCS= crunchide.c
-NO_PIE= yes
-
TARGET_ARCH?= ${MACHINE_ARCH}
.if ${TARGET_ARCH} == i386 && ${MACHINE_ARCH} == i386
diff --git a/usr.sbin/ctladm/Makefile b/usr.sbin/ctladm/Makefile
index 4d08f6e..a9f6bfd 100644
--- a/usr.sbin/ctladm/Makefile
+++ b/usr.sbin/ctladm/Makefile
@@ -2,12 +2,12 @@
PROG= ctladm
SRCS= ctladm.c util.c ctl_util.c ctl_scsi_all.c
-.PATH: ${.CURDIR}/../../sys/cam/ctl
+.PATH: ${.CURDIR}/../../sys/cam/ctl
SDIR= ${.CURDIR}/../../sys
CFLAGS+= -I${SDIR}
# This is necessary because of these warnings:
# warning: cast increases required alignment of target type
-# The solution is to either upgrade the compiler (preferred), or do void
+# The solution is to either upgrade the compiler (preferred), or do void
# pointer gymnastics to get around the warning. For now, disable the
# warning instead of doing the void pointer workaround.
.if ${MACHINE_CPUARCH} == "arm"
diff --git a/usr.sbin/ctladm/ctladm.8 b/usr.sbin/ctladm/ctladm.8
index f58a760..23f63d4 100644
--- a/usr.sbin/ctladm/ctladm.8
+++ b/usr.sbin/ctladm/ctladm.8
@@ -34,7 +34,7 @@
.\" $Id: //depot/users/kenm/FreeBSD-test2/usr.sbin/ctladm/ctladm.8#3 $
.\" $FreeBSD$
.\"
-.Dd July 9, 2014
+.Dd November 5, 2014
.Dt CTLADM 8
.Os
.Sh NAME
@@ -193,6 +193,14 @@
.Op Fl q
.Op Fl x
.Nm
+.Ic portlist
+.Op Fl f Ar frontend
+.Op Fl i
+.Op Fl p Ar targ_port
+.Op Fl q
+.Op Fl v
+.Op Fl x
+.Nm
.Ic dumpooa
.Nm
.Ic dumpstructs
@@ -768,6 +776,22 @@ As a general rule, the WWPN must be different for every port in the system.
.It Fl x
Output the port list in XML format.
.El
+.It Ic portlist
+List CTL frontend ports.
+.Bl -tag -width 12n
+.It Fl f Ar frontend
+Specify the frontend type.
+.It Fl i
+Report target and connected initiators addresses
+.It Fl p Ar targ_port
+Specify the frontend port number.
+.It Fl q
+Omit the header in the port list output.
+.It Fl v
+Enable verbose output (report all port options).
+.It Fl x
+Output the port list in XML format.
+.El
.It Ic dumpooa
Dump the OOA (Order Of Arrival) queue for each LUN registered with CTL.
.It Ic dumpstructs
@@ -959,8 +983,36 @@ Setting to "on" allows EXTENDED COPY command sent to this LUN access
other LUNs on this host, not accessible otherwise.
This allows to offload copying between different iSCSI targets residing
on the same host in trusted environments.
+.It Va readcache
+Set to "off", disables read caching for the LUN, if supported by the backend.
+.It Va readonly
+Set to "on", blocks all media write operations to the LUN, reporting it
+as write protected.
+.It Va reordering
+Set to "unrestricted", allows target to process commands with SIMPLE task
+attribute in arbitrary order. Any data integrity exposures related to
+command sequence order shall be explicitly handled by the application
+client through the selection of appropriate commands and task attributes.
+The default value is "restricted". It improves data integrity, but may
+introduce some additional delays.
+.It Va rpm
+Specifies medium rotation rate of the device: 0 -- not reported,
+1 -- non-rotating (SSD), >1024 -- value in revolutions per minute.
+.It Va formfactor
+Specifies nominal form factor of the device: 0 -- not reported, 1 -- 5.25",
+2 -- 3.5", 3 -- 2.5", 4 -- 1.8", 5 -- less then 1.8".
.It Va unmap
-Set to "on", enables UNMAP support for the LUN.
+Set to "on", enables UNMAP support for the LUN, if supported by the backend.
+.It Va avail-threshold
+.It Va used-threshold
+.It Va pool-avail-threshold
+.It Va pool-used-threshold
+Set per-LUN/-pool thin provisioning soft thresholds for ZVOL-backed LUNs.
+LUN will establish UNIT ATTENTION condition if its or pool available space
+get below configured avail values, or its or pool used space get above
+configured used values.
+.It Va writecache
+Set to "off", disables write caching for the LUN, if supported by the backend.
.El
.Pp
Options specific for block backend:
diff --git a/usr.sbin/ctladm/ctladm.c b/usr.sbin/ctladm/ctladm.c
index c362f5c..03f46c9 100644
--- a/usr.sbin/ctladm/ctladm.c
+++ b/usr.sbin/ctladm/ctladm.c
@@ -148,7 +148,7 @@ typedef enum {
CTLADM_ARG_ONOFFLINE = 0x0080000,
CTLADM_ARG_ONESHOT = 0x0100000,
CTLADM_ARG_TIMEOUT = 0x0200000,
- CTLADM_ARG_INITIATOR = 0x0400000,
+ CTLADM_ARG_INITIATOR = 0x0400000,
CTLADM_ARG_NOCOPY = 0x0800000,
CTLADM_ARG_NEED_TL = 0x1000000
} ctladm_cmdargs;
@@ -191,7 +191,7 @@ static struct ctladm_opts option_table[] = {
{"modesense", CTLADM_CMD_MODESENSE, CTLADM_ARG_NEED_TL, "P:S:dlm:c:"},
{"modify", CTLADM_CMD_MODIFY, CTLADM_ARG_NONE, "b:l:s:"},
{"port", CTLADM_CMD_PORT, CTLADM_ARG_NONE, "lo:p:qt:w:W:x"},
- {"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:vx"},
+ {"portlist", CTLADM_CMD_PORTLIST, CTLADM_ARG_NONE, "f:ip:qvx"},
{"prin", CTLADM_CMD_PRES_IN, CTLADM_ARG_NEED_TL, "a:"},
{"prout", CTLADM_CMD_PRES_OUT, CTLADM_ARG_NEED_TL, "a:k:r:s:"},
{"read", CTLADM_CMD_READ, CTLADM_ARG_NEED_TL, rw_opts},
@@ -237,7 +237,7 @@ static int cctl_sync_cache(int fd, int target, int lun, int iid, int retries,
int argc, char **argv, char *combinedopt);
static int cctl_start_stop(int fd, int target, int lun, int iid, int retries,
int start, int argc, char **argv, char *combinedopt);
-static int cctl_mode_sense(int fd, int target, int lun, int iid, int retries,
+static int cctl_mode_sense(int fd, int target, int lun, int iid, int retries,
int argc, char **argv, char *combinedopt);
static int cctl_read_capacity(int fd, int target, int lun, int iid,
int retries, int argc, char **argv,
@@ -258,7 +258,7 @@ static int cctl_req_sense(int fd, int target, int lun, int iid, int retries);
static int cctl_persistent_reserve_in(int fd, int target, int lun,
int initiator, int argc, char **argv,
char *combinedopt, int retry_count);
-static int cctl_persistent_reserve_out(int fd, int target, int lun,
+static int cctl_persistent_reserve_out(int fd, int target, int lun,
int initiator, int argc, char **argv,
char *combinedopt, int retry_count);
static int cctl_create_lun(int fd, int argc, char **argv, char *combinedopt);
@@ -394,7 +394,7 @@ retry:
cmd_latency = ts.tv_sec * 1000;
if (ts.tv_nsec > 0)
cmd_latency += ts.tv_nsec / 1000000;
-
+
fprintf(stdout, "LUN %jd tag 0x%04x%s%s%s%s%s: %s. CDB: %s "
"(%0.0Lf ms)\n",
(intmax_t)entry->lun_num, entry->tag_num,
@@ -622,7 +622,7 @@ cctl_port(int fd, int argc, char **argv, char *combinedopt)
case 'o':
if (port_mode != CCTL_PORT_MODE_NONE)
goto bailout_badarg;
-
+
if (strcasecmp(optarg, "on") == 0)
port_mode = CCTL_PORT_MODE_ON;
else if (strcasecmp(optarg, "off") == 0)
@@ -1041,7 +1041,7 @@ static struct ctladm_opts cctl_err_patterns[] = {
};
static int
-cctl_error_inject(int fd, uint32_t target, uint32_t lun, int argc, char **argv,
+cctl_error_inject(int fd, uint32_t target, uint32_t lun, int argc, char **argv,
char *combinedopt)
{
int retval = 0;
@@ -1206,12 +1206,12 @@ cctl_error_inject(int fd, uint32_t target, uint32_t lun, int argc, char **argv,
if (fd_sense == 1) {
ssize_t amt_read;
int amt_to_read = sense_len;
- u_int8_t *buf_ptr = (uint8_t *)&err_desc.custom_sense;
+ u_int8_t *buf_ptr = (uint8_t *)&err_desc.custom_sense;
for (amt_read = 0; amt_to_read > 0;
amt_read = read(STDIN_FILENO, buf_ptr, amt_to_read)) {
if (amt_read == -1) {
- warn("error reading sense data from stdin");
+ warn("error reading sense data from stdin");
retval = 1;
goto bailout;
}
@@ -1617,7 +1617,7 @@ cctl_startup_shutdown(int fd, int target, int lun, int iid,
}
if (ooa_info.status != CTL_OOA_SUCCESS) {
- printf("%s CTL_CHECK_OOA returned status %d\n",
+ printf("%s CTL_CHECK_OOA returned status %d\n",
scsi_path, ooa_info.status);
continue;
}
@@ -1629,7 +1629,7 @@ cctl_startup_shutdown(int fd, int target, int lun, int iid,
continue;
}
}
-
+
ctl_scsi_start_stop(/*io*/ io,
/*start*/(command == CTLADM_CMD_STARTUP) ?
1 : 0,
@@ -1682,7 +1682,7 @@ cctl_sync_cache(int fd, int target, int lun, int iid, int retries,
int retval;
uint64_t our_lba = 0;
uint32_t our_block_count = 0;
- int reladr = 0, immed = 0;
+ int reladr = 0, immed = 0;
int c;
id.id = iid;
@@ -1830,7 +1830,7 @@ bailout:
}
static int
-cctl_mode_sense(int fd, int target, int lun, int iid, int retries,
+cctl_mode_sense(int fd, int target, int lun, int iid, int retries,
int argc, char **argv, char *combinedopt)
{
union ctl_io *io;
@@ -2048,8 +2048,8 @@ bailout:
}
static int
-cctl_read_capacity(int fd, int target, int lun, int iid, int retries,
- int argc, char **argv, char *combinedopt)
+cctl_read_capacity(int fd, int target, int lun, int iid, int retries,
+ int argc, char **argv, char *combinedopt)
{
union ctl_io *io;
struct ctl_id id;
@@ -2518,7 +2518,7 @@ cctl_tur(int fd, int target, int lun, int iid, int retries)
}
static int
-cctl_get_inquiry(int fd, int target, int lun, int iid, int retries,
+cctl_get_inquiry(int fd, int target, int lun, int iid, int retries,
char *path_str, int path_len,
struct scsi_inquiry_data *inq_data)
{
@@ -2669,7 +2669,7 @@ cctl_report_target_port_group(int fd, int target, int lun, int initiator)
dataptr = (uint8_t *)malloc(datalen);
if (dataptr == NULL) {
warn("%s: can't allocate %d bytes", __func__, datalen);
- retval = 1;
+ retval = 1;
goto bailout;
}
@@ -2737,7 +2737,7 @@ cctl_inquiry_vpd_devid(int fd, int target, int lun, int initiator)
dataptr = (uint8_t *)malloc(datalen);
if (dataptr == NULL) {
warn("%s: can't allocate %d bytes", __func__, datalen);
- retval = 1;
+ retval = 1;
goto bailout;
}
@@ -2784,7 +2784,7 @@ bailout:
}
static int
-cctl_persistent_reserve_in(int fd, int target, int lun, int initiator,
+cctl_persistent_reserve_in(int fd, int target, int lun, int initiator,
int argc, char **argv, char *combinedopt,
int retry_count)
{
@@ -2827,7 +2827,7 @@ cctl_persistent_reserve_in(int fd, int target, int lun, int initiator,
dataptr = (uint8_t *)malloc(datalen);
if (dataptr == NULL) {
warn("%s: can't allocate %d bytes", __func__, datalen);
- retval = 1;
+ retval = 1;
goto bailout;
}
@@ -2890,8 +2890,8 @@ bailout:
}
static int
-cctl_persistent_reserve_out(int fd, int target, int lun, int initiator,
- int argc, char **argv, char *combinedopt,
+cctl_persistent_reserve_out(int fd, int target, int lun, int initiator,
+ int argc, char **argv, char *combinedopt,
int retry_count)
{
union ctl_io *io;
@@ -3174,14 +3174,18 @@ cctl_create_lun(int fd, int argc, char **argv, char *combinedopt)
goto bailout;
}
- if (req.status == CTL_LUN_ERROR) {
- warnx("%s: error returned from LUN creation request:\n%s",
- __func__, req.error_str);
+ switch (req.status) {
+ case CTL_LUN_ERROR:
+ warnx("LUN creation error: %s", req.error_str);
retval = 1;
goto bailout;
- } else if (req.status != CTL_LUN_OK) {
- warnx("%s: unknown LUN creation request status %d",
- __func__, req.status);
+ case CTL_LUN_WARNING:
+ warnx("LUN creation warning: %s", req.error_str);
+ break;
+ case CTL_LUN_OK:
+ break;
+ default:
+ warnx("unknown LUN creation status: %d", req.status);
retval = 1;
goto bailout;
}
@@ -3320,19 +3324,23 @@ cctl_rm_lun(int fd, int argc, char **argv, char *combinedopt)
goto bailout;
}
- if (req.status == CTL_LUN_ERROR) {
- warnx("%s: error returned from LUN removal request:\n%s",
- __func__, req.error_str);
+ switch (req.status) {
+ case CTL_LUN_ERROR:
+ warnx("LUN removal error: %s", req.error_str);
retval = 1;
goto bailout;
- } else if (req.status != CTL_LUN_OK) {
- warnx("%s: unknown LUN removal request status %d",
- __func__, req.status);
+ case CTL_LUN_WARNING:
+ warnx("LUN removal warning: %s", req.error_str);
+ break;
+ case CTL_LUN_OK:
+ break;
+ default:
+ warnx("unknown LUN removal status: %d", req.status);
retval = 1;
goto bailout;
}
- printf("LUN %d deleted successfully\n", lun_id);
+ printf("LUN %d removed successfully\n", lun_id);
bailout:
return (retval);
@@ -3397,14 +3405,18 @@ cctl_modify_lun(int fd, int argc, char **argv, char *combinedopt)
goto bailout;
}
- if (req.status == CTL_LUN_ERROR) {
- warnx("%s: error returned from LUN modification request:\n%s",
- __func__, req.error_str);
+ switch (req.status) {
+ case CTL_LUN_ERROR:
+ warnx("LUN modification error: %s", req.error_str);
retval = 1;
goto bailout;
- } else if (req.status != CTL_LUN_OK) {
- warnx("%s: unknown LUN modification request status %d",
- __func__, req.status);
+ case CTL_LUN_WARNING:
+ warnx("LUN modification warning: %s", req.error_str);
+ break;
+ case CTL_LUN_OK:
+ break;
+ default:
+ warnx("unknown LUN modification status: %d", req.status);
retval = 1;
goto bailout;
}
@@ -3823,7 +3835,7 @@ struct cctl_lun_nv {
};
/*
- * Backend LUN information.
+ * Backend LUN information.
*/
struct cctl_lun {
uint64_t lun_id;
@@ -3939,7 +3951,7 @@ cctl_end_element(void *user_data, const char *name)
} else if (strcmp(name, "lun") == 0) {
devlist->cur_lun = NULL;
} else if (strcmp(name, "ctllunlist") == 0) {
-
+ /* Nothing. */
} else {
struct cctl_lun_nv *nv;
@@ -4088,7 +4100,8 @@ struct cctl_port {
char *frontend_type;
char *name;
int pp, vp;
- char *wwnn, *wwpn;
+ char *target, *port;
+ STAILQ_HEAD(,cctl_lun_nv) init_list;
STAILQ_HEAD(,cctl_lun_nv) attr_list;
STAILQ_ENTRY(cctl_port) links;
};
@@ -4132,6 +4145,7 @@ cctl_start_pelement(void *user_data, const char *name, const char **attr)
portlist->num_ports++;
portlist->cur_port = cur_port;
+ STAILQ_INIT(&cur_port->init_list);
STAILQ_INIT(&cur_port->attr_list);
STAILQ_INSERT_TAIL(&portlist->port_list, cur_port, links);
@@ -4193,16 +4207,16 @@ cctl_end_pelement(void *user_data, const char *name)
cur_port->pp = strtoull(str, NULL, 0);
} else if (strcmp(name, "virtual_port") == 0) {
cur_port->vp = strtoull(str, NULL, 0);
- } else if (strcmp(name, "wwnn") == 0) {
- cur_port->wwnn = str;
+ } else if (strcmp(name, "target") == 0) {
+ cur_port->target = str;
str = NULL;
- } else if (strcmp(name, "wwpn") == 0) {
- cur_port->wwpn = str;
+ } else if (strcmp(name, "port") == 0) {
+ cur_port->port = str;
str = NULL;
} else if (strcmp(name, "targ_port") == 0) {
portlist->cur_port = NULL;
} else if (strcmp(name, "ctlportlist") == 0) {
-
+ /* Nothing. */
} else {
struct cctl_lun_nv *nv;
@@ -4218,7 +4232,10 @@ cctl_end_pelement(void *user_data, const char *name)
nv->value = str;
str = NULL;
- STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
+ if (strcmp(name, "initiator") == 0)
+ STAILQ_INSERT_TAIL(&cur_port->init_list, nv, links);
+ else
+ STAILQ_INSERT_TAIL(&cur_port->attr_list, nv, links);
}
free(str);
@@ -4246,7 +4263,8 @@ cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
int dump_xml = 0;
int retval, c;
char *frontend = NULL;
- int verbose = 0;
+ uint64_t portarg = UINT64_MAX;
+ int verbose = 0, init = 0, quiet = 0;
retval = 0;
port_len = 4096;
@@ -4259,6 +4277,15 @@ cctl_portlist(int fd, int argc, char **argv, char *combinedopt)
case 'f':
frontend = strdup(optarg);
break;
+ case 'i':
+ init++;
+ break;
+ case 'p':
+ portarg = strtoll(optarg, NULL, 0);
+ break;
+ case 'q':
+ quiet++;
+ break;
case 'v':
verbose++;
break;
@@ -4315,8 +4342,8 @@ retry:
goto bailout;
}
- printf("Port Online Frontend %-12s pp vp %-18s %-18s\n",
- "Name", "WWNN", "WWPN");
+ if (quiet == 0)
+ printf("Port Online Frontend Name pp vp\n");
STAILQ_FOREACH(port, &portlist.port_list, links) {
struct cctl_lun_nv *nv;
@@ -4324,16 +4351,26 @@ retry:
&& (strcmp(port->frontend_type, frontend) != 0))
continue;
- printf("%-4ju %-6s %-8s %-12s %-2d %-2d %-18s %-18s\n",
+ if ((portarg != UINT64_MAX) && (portarg != port->port_id))
+ continue;
+
+ printf("%-4ju %-6s %-8s %-8s %-2d %-2d %s\n",
(uintmax_t)port->port_id, port->online,
port->frontend_type, port->name, port->pp, port->vp,
- port->wwnn, port->wwpn);
+ port->port ? port->port : "");
- if (verbose == 0)
- continue;
+ if (init || verbose) {
+ if (port->target)
+ printf(" Target: %s\n", port->target);
+ STAILQ_FOREACH(nv, &port->init_list, links) {
+ printf(" Initiator: %s\n", nv->value);
+ }
+ }
- STAILQ_FOREACH(nv, &port->attr_list, links) {
- printf(" %s=%s\n", nv->name, nv->value);
+ if (verbose) {
+ STAILQ_FOREACH(nv, &port->attr_list, links) {
+ printf(" %s=%s\n", nv->name, nv->value);
+ }
}
}
bailout:
@@ -4389,7 +4426,7 @@ usage(int error)
" [-s len fmt [args]] [-c] [-d delete_id]\n"
" ctladm port <-l | -o <on|off> | [-w wwnn][-W wwpn]>\n"
" [-p targ_port] [-t port_type] [-q] [-x]\n"
-" ctladm portlist [-f frontend] [-v] [-x]\n"
+" ctladm portlist [-f frontend] [-i] [-p targ_port] [-q] [-v] [-x]\n"
" ctladm islist [-v | -x]\n"
" ctladm islogout <-a | -c connection-id | -i name | -p portal>\n"
" ctladm isterminate <-a | -c connection-id | -i name | -p portal>\n"
@@ -4475,6 +4512,13 @@ usage(int error)
"-p targ_port : specify target port number\n"
"-q : omit header in list output\n"
"-x : output port list in XML format\n"
+"portlist options:\n"
+"-f fronetnd : specify frontend type\n"
+"-i : report target and initiators addresses\n"
+"-p targ_port : specify target port number\n"
+"-q : omit header in list output\n"
+"-v : verbose output (report all port options)\n"
+"-x : output port list in XML format\n"
"bbrread options:\n"
"-l lba : starting LBA\n"
"-d datalen : length, in bytes, to read\n",
@@ -4531,7 +4575,7 @@ main(int argc, char **argv)
}
if (cmdargs & CTLADM_ARG_NEED_TL) {
- if ((argc < 3)
+ if ((argc < 3)
|| (!isdigit(argv[2][0]))) {
warnx("option %s requires a target:lun argument",
argv[1]);
@@ -4758,12 +4802,12 @@ main(int argc, char **argv)
retval = cctl_dump_structs(fd, cmdargs);
break;
case CTLADM_CMD_PRES_IN:
- retval = cctl_persistent_reserve_in(fd, target, lun, initid,
+ retval = cctl_persistent_reserve_in(fd, target, lun, initid,
argc, argv, combinedopt,
retries);
break;
case CTLADM_CMD_PRES_OUT:
- retval = cctl_persistent_reserve_out(fd, target, lun, initid,
+ retval = cctl_persistent_reserve_out(fd, target, lun, initid,
argc, argv, combinedopt,
retries);
break;
diff --git a/usr.sbin/ctld/Makefile b/usr.sbin/ctld/Makefile
index e6c292d..149ae39 100644
--- a/usr.sbin/ctld/Makefile
+++ b/usr.sbin/ctld/Makefile
@@ -1,7 +1,8 @@
# $FreeBSD$
PROG= ctld
-SRCS= ctld.c discovery.c kernel.c keys.c log.c login.c parse.y pdu.c token.l y.tab.h
+SRCS= chap.c ctld.c discovery.c isns.c kernel.c keys.c log.c
+SRCS+= login.c parse.y pdu.c token.l y.tab.h
CFLAGS+= -I${.CURDIR}
CFLAGS+= -I${.CURDIR}/../../sys
CFLAGS+= -I${.CURDIR}/../../sys/cam/ctl
@@ -9,8 +10,8 @@ CFLAGS+= -I${.CURDIR}/../../sys/dev/iscsi
#CFLAGS+= -DICL_KERNEL_PROXY
MAN= ctld.8 ctl.conf.5
-DPADD= ${LIBCAM} ${LIBSBUF} ${LIBBSDXML} ${LIBUTIL}
-LDADD= -lbsdxml -lcam -lcrypto -lfl -lsbuf -lssl -lutil
+DPADD= ${LIBBSDXML} ${LIBCRYPTO} ${LIBL} ${LIBSBUF} ${LIBUTIL}
+LDADD= -lbsdxml -lcrypto -ll -lsbuf -lutil
YFLAGS+= -v
CLEANFILES= y.tab.c y.tab.h y.output
diff --git a/usr.sbin/ctld/chap.c b/usr.sbin/ctld/chap.c
new file mode 100644
index 0000000..0678a77
--- /dev/null
+++ b/usr.sbin/ctld/chap.c
@@ -0,0 +1,435 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+
+#include "ctld.h"
+
+static void
+chap_compute_md5(const char id, const char *secret,
+ const void *challenge, size_t challenge_len, void *response,
+ size_t response_len)
+{
+ MD5_CTX ctx;
+ int rv;
+
+ assert(response_len == MD5_DIGEST_LENGTH);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, &id, sizeof(id));
+ MD5_Update(&ctx, secret, strlen(secret));
+ MD5_Update(&ctx, challenge, challenge_len);
+ rv = MD5_Final(response, &ctx);
+ if (rv != 1)
+ log_errx(1, "MD5_Final");
+}
+
+static int
+chap_hex2int(const char hex)
+{
+ switch (hex) {
+ case '0':
+ return (0x00);
+ case '1':
+ return (0x01);
+ case '2':
+ return (0x02);
+ case '3':
+ return (0x03);
+ case '4':
+ return (0x04);
+ case '5':
+ return (0x05);
+ case '6':
+ return (0x06);
+ case '7':
+ return (0x07);
+ case '8':
+ return (0x08);
+ case '9':
+ return (0x09);
+ case 'a':
+ case 'A':
+ return (0x0a);
+ case 'b':
+ case 'B':
+ return (0x0b);
+ case 'c':
+ case 'C':
+ return (0x0c);
+ case 'd':
+ case 'D':
+ return (0x0d);
+ case 'e':
+ case 'E':
+ return (0x0e);
+ case 'f':
+ case 'F':
+ return (0x0f);
+ default:
+ return (-1);
+ }
+}
+
+static int
+chap_b642bin(const char *b64, void **binp, size_t *bin_lenp)
+{
+ char *bin;
+ int b64_len, bin_len;
+
+ b64_len = strlen(b64);
+ bin_len = (b64_len + 3) / 4 * 3;
+ bin = calloc(bin_len, 1);
+ if (bin == NULL)
+ log_err(1, "calloc");
+
+ bin_len = b64_pton(b64, bin, bin_len);
+ if (bin_len < 0) {
+ log_warnx("malformed base64 variable");
+ free(bin);
+ return (-1);
+ }
+ *binp = bin;
+ *bin_lenp = bin_len;
+ return (0);
+}
+
+/*
+ * XXX: Review this _carefully_.
+ */
+static int
+chap_hex2bin(const char *hex, void **binp, size_t *bin_lenp)
+{
+ int i, hex_len, nibble;
+ bool lo = true; /* As opposed to 'hi'. */
+ char *bin;
+ size_t bin_off, bin_len;
+
+ if (strncasecmp(hex, "0b", strlen("0b")) == 0)
+ return (chap_b642bin(hex + 2, binp, bin_lenp));
+
+ if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
+ log_warnx("malformed variable, should start with \"0x\""
+ " or \"0b\"");
+ return (-1);
+ }
+
+ hex += strlen("0x");
+ hex_len = strlen(hex);
+ if (hex_len < 1) {
+ log_warnx("malformed variable; doesn't contain anything "
+ "but \"0x\"");
+ return (-1);
+ }
+
+ bin_len = hex_len / 2 + hex_len % 2;
+ bin = calloc(bin_len, 1);
+ if (bin == NULL)
+ log_err(1, "calloc");
+
+ bin_off = bin_len - 1;
+ for (i = hex_len - 1; i >= 0; i--) {
+ nibble = chap_hex2int(hex[i]);
+ if (nibble < 0) {
+ log_warnx("malformed variable, invalid char \"%c\"",
+ hex[i]);
+ free(bin);
+ return (-1);
+ }
+
+ assert(bin_off < bin_len);
+ if (lo) {
+ bin[bin_off] = nibble;
+ lo = false;
+ } else {
+ bin[bin_off] |= nibble << 4;
+ bin_off--;
+ lo = true;
+ }
+ }
+
+ *binp = bin;
+ *bin_lenp = bin_len;
+ return (0);
+}
+
+#ifdef USE_BASE64
+static char *
+chap_bin2hex(const char *bin, size_t bin_len)
+{
+ unsigned char *b64, *tmp;
+ size_t b64_len;
+
+ b64_len = (bin_len + 2) / 3 * 4 + 3; /* +2 for "0b", +1 for '\0'. */
+ b64 = malloc(b64_len);
+ if (b64 == NULL)
+ log_err(1, "malloc");
+
+ tmp = b64;
+ tmp += sprintf(tmp, "0b");
+ b64_ntop(bin, bin_len, tmp, b64_len - 2);
+
+ return (b64);
+}
+#else
+static char *
+chap_bin2hex(const char *bin, size_t bin_len)
+{
+ unsigned char *hex, *tmp, ch;
+ size_t hex_len;
+ size_t i;
+
+ hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
+ hex = malloc(hex_len);
+ if (hex == NULL)
+ log_err(1, "malloc");
+
+ tmp = hex;
+ tmp += sprintf(tmp, "0x");
+ for (i = 0; i < bin_len; i++) {
+ ch = bin[i];
+ tmp += sprintf(tmp, "%02x", ch);
+ }
+
+ return (hex);
+}
+#endif /* !USE_BASE64 */
+
+struct chap *
+chap_new(void)
+{
+ struct chap *chap;
+ int rv;
+
+ chap = calloc(sizeof(*chap), 1);
+ if (chap == NULL)
+ log_err(1, "calloc");
+
+ /*
+ * Generate the challenge.
+ */
+ rv = RAND_bytes(chap->chap_challenge, sizeof(chap->chap_challenge));
+ if (rv != 1) {
+ log_errx(1, "RAND_bytes failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+ rv = RAND_bytes(&chap->chap_id, sizeof(chap->chap_id));
+ if (rv != 1) {
+ log_errx(1, "RAND_bytes failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+
+ return (chap);
+}
+
+char *
+chap_get_id(const struct chap *chap)
+{
+ char *chap_i;
+ int ret;
+
+ ret = asprintf(&chap_i, "%d", chap->chap_id);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ return (chap_i);
+}
+
+char *
+chap_get_challenge(const struct chap *chap)
+{
+ char *chap_c;
+
+ chap_c = chap_bin2hex(chap->chap_challenge,
+ sizeof(chap->chap_challenge));
+
+ return (chap_c);
+}
+
+static int
+chap_receive_bin(struct chap *chap, void *response, size_t response_len)
+{
+
+ if (response_len != sizeof(chap->chap_response)) {
+ log_debugx("got CHAP response with invalid length; "
+ "got %zd, should be %zd",
+ response_len, sizeof(chap->chap_response));
+ return (1);
+ }
+
+ memcpy(chap->chap_response, response, response_len);
+ return (0);
+}
+
+int
+chap_receive(struct chap *chap, const char *response)
+{
+ void *response_bin;
+ size_t response_bin_len;
+ int error;
+
+ error = chap_hex2bin(response, &response_bin, &response_bin_len);
+ if (error != 0) {
+ log_debugx("got incorrectly encoded CHAP response \"%s\"",
+ response);
+ return (1);
+ }
+
+ error = chap_receive_bin(chap, response_bin, response_bin_len);
+ free(response_bin);
+
+ return (error);
+}
+
+int
+chap_authenticate(struct chap *chap, const char *secret)
+{
+ char expected_response[MD5_DIGEST_LENGTH];
+
+ chap_compute_md5(chap->chap_id, secret,
+ chap->chap_challenge, sizeof(chap->chap_challenge),
+ expected_response, sizeof(expected_response));
+
+ if (memcmp(chap->chap_response,
+ expected_response, sizeof(expected_response)) != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+chap_delete(struct chap *chap)
+{
+
+ free(chap);
+}
+
+struct rchap *
+rchap_new(const char *secret)
+{
+ struct rchap *rchap;
+
+ rchap = calloc(sizeof(*rchap), 1);
+ if (rchap == NULL)
+ log_err(1, "calloc");
+
+ rchap->rchap_secret = checked_strdup(secret);
+
+ return (rchap);
+}
+
+static void
+rchap_receive_bin(struct rchap *rchap, const unsigned char id,
+ const void *challenge, size_t challenge_len)
+{
+
+ rchap->rchap_id = id;
+ rchap->rchap_challenge = calloc(challenge_len, 1);
+ if (rchap->rchap_challenge == NULL)
+ log_err(1, "calloc");
+ memcpy(rchap->rchap_challenge, challenge, challenge_len);
+ rchap->rchap_challenge_len = challenge_len;
+}
+
+int
+rchap_receive(struct rchap *rchap, const char *id, const char *challenge)
+{
+ unsigned char id_bin;
+ void *challenge_bin;
+ size_t challenge_bin_len;
+
+ int error;
+
+ id_bin = strtoul(id, NULL, 10);
+
+ error = chap_hex2bin(challenge, &challenge_bin, &challenge_bin_len);
+ if (error != 0) {
+ log_debugx("got incorrectly encoded CHAP challenge \"%s\"",
+ challenge);
+ return (1);
+ }
+
+ rchap_receive_bin(rchap, id_bin, challenge_bin, challenge_bin_len);
+ free(challenge_bin);
+
+ return (0);
+}
+
+static void
+rchap_get_response_bin(struct rchap *rchap,
+ void **responsep, size_t *response_lenp)
+{
+ void *response_bin;
+ size_t response_bin_len = MD5_DIGEST_LENGTH;
+
+ response_bin = calloc(response_bin_len, 1);
+ if (response_bin == NULL)
+ log_err(1, "calloc");
+
+ chap_compute_md5(rchap->rchap_id, rchap->rchap_secret,
+ rchap->rchap_challenge, rchap->rchap_challenge_len,
+ response_bin, response_bin_len);
+
+ *responsep = response_bin;
+ *response_lenp = response_bin_len;
+}
+
+char *
+rchap_get_response(struct rchap *rchap)
+{
+ void *response;
+ size_t response_len;
+ char *chap_r;
+
+ rchap_get_response_bin(rchap, &response, &response_len);
+ chap_r = chap_bin2hex(response, response_len);
+ free(response);
+
+ return (chap_r);
+}
+
+void
+rchap_delete(struct rchap *rchap)
+{
+
+ free(rchap->rchap_secret);
+ free(rchap->rchap_challenge);
+ free(rchap);
+}
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5
index 0c73f64..8e427b1 100644
--- a/usr.sbin/ctld/ctl.conf.5
+++ b/usr.sbin/ctld/ctl.conf.5
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 28, 2014
+.Dd November 9, 2014
.Dt CTL.CONF 5
.Os
.Sh NAME
@@ -46,179 +46,306 @@ The general syntax of the
.Nm
file is:
.Bd -literal -offset indent
-pidfile <path>
+.No pidfile Ar path
-auth-group <name> {
- chap <user> <secret>
- ...
+.No auth-group Ar name No {
+.Dl chap Ar user Ar secret
+.Dl ...
}
-portal-group <name> {
- listen <address>
- listen-iser <address>
- discovery-auth-group <name>
- ...
+.No portal-group Ar name No {
+.Dl listen Ar address
+.\".Dl listen-iser Ar address
+.Dl discovery-auth-group Ar name
+.Dl ...
}
-target <name> {
- auth-group <name>
- portal-group <name>
- lun <number> {
- path <path>
- }
- ...
+.No target Ar name {
+.Dl auth-group Ar name
+.Dl portal-group Ar name
+.Dl lun Ar number No {
+.Dl path Ar path
+.Dl }
+.Dl ...
}
.Ed
-.Ss global level
-The following statements are available at the global level:
+.Ss Global Context
.Bl -tag -width indent
-.It Ic auth-group Aq Ar name
-Opens an auth-group section, defining an authentication group,
+.It Ic auth-group Ar name
+Create an
+.Sy auth-group
+configuration context,
+defining a new auth-group,
which can then be assigned to any number of targets.
-.It Ic debug Aq Ar level
-Specifies debug level.
+.It Ic debug Ar level
+The debug verbosity level.
The default is 0.
-.It Ic maxproc Aq Ar number
-Specifies limit for concurrently running child processes handling
+.It Ic maxproc Ar number
+The limit for concurrently running child processes handling
incoming connections.
The default is 30.
-Setting it to 0 disables the limit.
-.It Ic pidfile Aq Ar path
-Specifies path to pidfile.
+A setting of 0 disables the limit.
+.It Ic pidfile Ar path
+The path to the pidfile.
The default is
.Pa /var/run/ctld.pid .
-.It Ic portal-group Aq Ar name
-Opens a portal-group section, defining a portal group,
+.It Ic portal-group Ar name
+Create a
+.Sy portal-group
+configuration context,
+defining a new portal-group,
which can then be assigned to any number of targets.
-.It Ic target Aq Ar name
-Opens a target configuration section.
-.It Ic timeout Aq Ar seconds
-Specifies timeout for login session, after which the connection
+.It Ic target Ar name
+Create a
+.Sy target
+configuration context, which can contain one or more
+.Sy lun
+contexts.
+.It Ic timeout Ar seconds
+The timeout for login sessions, after which the connection
will be forcibly terminated.
The default is 60.
-Setting it to 0 disables the timeout.
+A setting of 0 disables the timeout.
+.It Ic isns-server Ar address
+An IPv4 or IPv6 address and optionally port of iSNS server to register on.
+.It Ic isns-period Ar seconds
+iSNS registration period.
+Registered Network Entity not updated during this period will be unregistered.
+The default is 900.
+.It Ic isns-timeout Ar seconds
+Timeout for iSNS requests.
+The default is 5.
.El
-.Ss auth-group level
-The following statements are available at the auth-group level:
+.Ss auth-group Context
.Bl -tag -width indent
-.It Ic auth-type Ao Ar type Ac
-Specifies authentication type.
-Type can be either "none", "deny", "chap", or "chap-mutual".
+.It Ic auth-type Ar type
+Sets the authentication type.
+Type can be either
+.Qq Ar none ,
+.Qq Ar deny ,
+.Qq Ar chap ,
+or
+.Qq Ar chap-mutual .
In most cases it is not necessary to set the type using this clause;
-it is usually used to disable authentication for a given auth-group.
-.It Ic chap Ao Ar user Ac Aq Ar secret
-Specifies CHAP authentication credentials.
-.It Ic chap-mutual Ao Ar user Ac Ao Ar secret Ac Ao Ar mutualuser Ac Aq Ar mutualsecret
-Specifies mutual CHAP authentication credentials.
-Note that for any auth-group, configuration may contain either chap,
-or chap-mutual entries; it is an error to mix them.
-.It Ic initiator-name Ao Ar initiator-name Ac
-Specifies iSCSI initiator name.
+it is usually used to disable authentication for a given
+.Sy auth-group .
+.It Ic chap Ar user Ar secret
+A set of CHAP authentication credentials.
+Note that for any
+.Sy auth-group ,
+the configuration may only contain either
+.Sy chap
+or
+.Sy chap-mutual
+entries; it is an error to mix them.
+.It Ic chap-mutual Ar user Ar secret Ar mutualuser Ar mutualsecret
+A set of mutual CHAP authentication credentials.
+Note that for any
+.Sy auth-group ,
+the configuration may only contain either
+.Sy chap
+or
+.Sy chap-mutual
+entries; it is an error to mix them.
+.It Ic initiator-name Ar initiator-name
+An iSCSI initiator name.
+Only initiators with a name matching one of the defined
+names will be allowed to connect.
If not defined, there will be no restrictions based on initiator
name.
-Otherwise, only initiators with names matching one of defined
-ones will be allowed to connect.
-.It Ic initiator-portal Ao Ar address Ac
-Specifies iSCSI initiator portal - IPv4 or IPv6 address or network.
+.It Ic initiator-portal Ar address Ns Op / Ns Ar prefixlen
+An iSCSI initiator portal: an IPv4 or IPv6 address, optionally
+followed by a literal slash and a prefix length.
+Only initiators with an address matching one of the defined
+addresses will be allowed to connect.
If not defined, there will be no restrictions based on initiator
address.
-Otherwise, only initiators with addresses matching one of defined
-ones will be allowed to connect.
.El
-.Ss portal-group level
-The following statements are available at the portal-group level:
+.Ss portal-group Context
.Bl -tag -width indent
-.It Ic discovery-auth-group Aq Ar name
-Assigns previously defined authentication group to the portal group,
+.It Ic discovery-auth-group Ar name
+Assign a previously defined authentication group to the portal group,
to be used for target discovery.
-By default, portal groups that do not specify their own auth settings,
-using clauses such as "chap" or "initiator-name", are assigned
-predefined auth-group "default", which denies discovery.
-Another predefined auth-group, "no-authentication", may be used
+By default, portal groups are assigned predefined
+.Sy auth-group
+.Qq Ar default ,
+which denies discovery.
+Another predefined
+.Sy auth-group ,
+.Qq Ar no-authentication ,
+may be used
to permit discovery without authentication.
-.It Ic listen Aq Ar address
-Specifies IPv4 or IPv6 address and port to listen on for incoming connections.
-.It Ic listen-iser Aq Ar address
-Specifies IPv4 or IPv6 address and port to listen on for incoming connections
-using iSER (iSCSI over RDMA) protocol.
+.It Ic discovery-filter Ar filter
+Determines which targets are returned during discovery.
+Filter can be either
+.Qq Ar none ,
+.Qq Ar portal ,
+.Qq Ar portal-name ,
+or
+.Qq Ar portal-name-auth .
+When set to
+.Qq Ar none ,
+discovery will return all targets assigned to that portal group.
+When set to
+.Qq Ar portal ,
+discovery will not return targets that cannot be accessed by the
+initiator because of their
+.Sy initiator-portal .
+When set to
+.Qq Ar portal-name ,
+the check will include both
+.Sy initiator-portal
+and
+.Sy initiator-name .
+When set to
+.Qq Ar portal-name-auth ,
+the check will include
+.Sy initiator-portal ,
+.Sy initiator-name ,
+and authentication credentials.
+The target is returned if it does not require CHAP authentication,
+or if the CHAP user and secret used during discovery match those
+used by the target.
+Note that when using
+.Qq Ar portal-name-auth ,
+targets that require CHAP authentication will only be returned if
+.Sy discovery-auth-group
+requires CHAP.
+The default is
+.Qq Ar none .
+.It Ic listen Ar address
+An IPv4 or IPv6 address and port to listen on for incoming connections.
+.\".It Ic listen-iser Ar address
+.\"An IPv4 or IPv6 address and port to listen on for incoming connections
+.\"using iSER (iSCSI over RDMA) protocol.
+.It Ic redirect Aq Ar address
+IPv4 or IPv6 address to redirect initiators to.
+When configured, all initiators attempting to connect to portal
+belonging to this
+.Sy portal-group
+will get redirected using "Target moved temporarily" login response.
+Redirection happens before authentication and any
+.Sy initiator-name
+or
+.Sy initiator-portal
+checks are skipped.
.El
-.Ss target level:
-The following statements are available at the target level:
+.Ss target Context
.Bl -tag -width indent
-.It Ic alias Aq Ar text
-Assigns human-readable description to the target.
+.It Ic alias Ar text
+Assign a human-readable description to the target.
There is no default.
-.It Ic auth-group Aq Ar name
-Assigns previously defined authentication group to the target.
+.It Ic auth-group Ar name
+Assign a previously defined authentication group to the target.
By default, targets that do not specify their own auth settings,
-using clauses such as "chap" or "initiator-name", are assigned
-predefined auth-group "default", which denies all access.
-Another predefined auth-group, "no-authentication", may be used to permit access
+using clauses such as
+.Sy chap
+or
+.Sy initiator-name ,
+are assigned
+predefined
+.Sy auth-group
+.Qq Ar default ,
+which denies all access.
+Another predefined
+.Sy auth-group ,
+.Qq Ar no-authentication ,
+may be used to permit access
without authentication.
-.It Ic auth-type Ao Ar type Ac
-Specifies authentication type.
-Type can be either "none", "deny", "chap", or "chap-mutual".
+Note that targets must only use one of
+.Sy auth-group , chap , No or Sy chap-mutual ;
+it is a configuration error to mix multiple types in one target.
+.It Ic auth-type Ar type
+Sets the authentication type.
+Type can be either
+.Qq Ar none ,
+.Qq Ar deny ,
+.Qq Ar chap ,
+or
+.Qq Ar chap-mutual .
In most cases it is not necessary to set the type using this clause;
-it is usually used to disable authentication for a given target.
-This clause is mutually exclusive with auth-group; one cannot use
+it is usually used to disable authentication for a given
+.Sy target .
+This clause is mutually exclusive with
+.Sy auth-group ;
+one cannot use
both in a single target.
-.It Ic chap Ao Ar user Ac Aq Ar secret
-Specifies CHAP authentication credentials.
-Note that targets must use either auth-group, or chap,
-or chap-mutual clauses; it is a configuration error to mix them in one target.
-.It Ic chap-mutual Ao Ar user Ac Ao Ar secret Ac Ao Ar mutualuser Ac Aq Ar mutualsecret
-Specifies mutual CHAP authentication credentials.
-Note that targets must use either auth-group, chap, or
-chap-mutual clauses; it is a configuration error to mix them in one target.
-.It Ic initiator-name Ao Ar initiator-name Ac
-Specifies iSCSI initiator name.
+.It Ic chap Ar user Ar secret
+A set of CHAP authentication credentials.
+Note that targets must only use one of
+.Sy auth-group , chap , No or Sy chap-mutual ;
+it is a configuration error to mix multiple types in one target.
+.It Ic chap-mutual Ar user Ar secret Ar mutualuser Ar mutualsecret
+A set of mutual CHAP authentication credentials.
+Note that targets must only use one of
+.Sy auth-group , chap , No or Sy chap-mutual ;
+it is a configuration error to mix multiple types in one target.
+.It Ic initiator-name Ar initiator-name
+An iSCSI initiator name.
+Only initiators with a name matching one of the defined
+names will be allowed to connect.
If not defined, there will be no restrictions based on initiator
name.
-Otherwise, only initiators with names matching one of defined
-ones will be allowed to connect.
-This clause is mutually exclusive with auth-group; one cannot use
+This clause is mutually exclusive with
+.Sy auth-group ;
+one cannot use
both in a single target.
-.It Ic initiator-portal Ao Ar address Ac
-Specifies iSCSI initiator portal - IPv4 or IPv6 address.
+.It Ic initiator-portal Ar address Ns Op / Ns Ar prefixlen
+An iSCSI initiator portal: an IPv4 or IPv6 address, optionally
+followed by a literal slash and a prefix length.
+Only initiators with an address matching one of the defined
+addresses will be allowed to connect.
If not defined, there will be no restrictions based on initiator
address.
-Otherwise, only initiators with addresses matching one of defined
-ones will be allowed to connect.
-This clause is mutually exclusive with auth-group; one cannot use
+This clause is mutually exclusive with
+.Sy auth-group ;
+one cannot use
both in a single target.
-.It Ic portal-group Aq Ar name
-Assigns previously defined portal group to the target.
-Default portal group is "default", which makes the target available
+.It Ic portal-group Ar name
+Assign a previously defined portal group to the target.
+The default portal group is
+.Qq Ar default ,
+which makes the target available
on TCP port 3260 on all configured IPv4 and IPv6 addresses.
-.It Ic lun Aq Ar number
-Opens a lun configuration section, defining LUN exported by a target.
+.It Ic redirect Aq Ar address
+IPv4 or IPv6 address to redirect initiators to.
+When configured, all initiators attempting to connect to this target
+will get redirected using "Target moved temporarily" login response.
+Redirection happens after successful authentication.
+.It Ic lun Ar number
+Create a
+.Sy lun
+configuration context, defining a LUN exported by the parent target.
.El
-.Ss lun level
-The following statements are available at the lun level:
+.Ss lun Context
.Bl -tag -width indent
-.It Ic backend Ao Ar block | Ar ramdisk Ac
-Specifies the CTL backend to use for a given LUN.
+.It Ic backend Ar block No | Ar ramdisk
+The CTL backend to use for a given LUN.
Valid choices are
-.Dq block
+.Qq Ar block
and
-.Dq ramdisk ;
+.Qq Ar ramdisk ;
block is used for LUNs backed
by files or disk device nodes; ramdisk is a bitsink device, used mostly for
testing.
The default backend is block.
-.It Ic blocksize Aq Ar size
-Specifies blocksize visible to the initiator.
+.It Ic blocksize Ar size
+The blocksize visible to the initiator.
The default blocksize is 512.
-.It Ic device-id Aq Ar string
-Specifies SCSI Device Identification string presented to the initiator.
-.It Ic option Ao Ar name Ac Aq Ar value
-Specifies CTL-specific options passed to the kernel.
-.It Ic path Aq Ar path
-Specifies path to file or device node used to back the LUN.
-.It Ic serial Aq Ar string
-Specifies SCSI serial number presented to the initiator.
-.It Ic size Aq Ar size
-Specifies LUN size, in bytes.
+.It Ic device-id Ar string
+The SCSI Device Identification string presented to the initiator.
+.It Ic option Ar name Ar value
+The CTL-specific options passed to the kernel.
+All CTL-specific options are documented in the
+.Sx OPTIONS
+section of
+.Xr ctladm 8 .
+.It Ic path Ar path
+The path to the file or device node used to back the LUN.
+.It Ic serial Ar string
+The SCSI serial number presented to the initiator.
+.It Ic size Ar size
+The LUN size, in bytes.
.El
.Sh FILES
.Bl -tag -width ".Pa /etc/ctl.conf" -compact
@@ -231,44 +358,52 @@ configuration file.
.Bd -literal
pidfile /var/run/ctld.pid
-auth-group example2 {
+auth-group ag0 {
chap-mutual "user" "secret" "mutualuser" "mutualsecret"
chap-mutual "user2" "secret2" "mutualuser" "mutualsecret"
+ initiator-portal 192.168.1.1/16
+}
+
+auth-group ag1 {
+ auth-type none
+ initiator-name "iqn.2012-06.com.example:initiatorhost1"
+ initiator-name "iqn.2012-06.com.example:initiatorhost2"
+ initiator-portal 192.168.1.1/24
+ initiator-portal [2001:db8::de:ef]
}
-portal-group example2 {
+portal-group pg0 {
discovery-auth-group no-authentication
- listen 127.0.0.1
- listen 0.0.0.0:3261
- listen [::]:3261
- listen [fe80::be:ef]
+ listen 0.0.0.0:3260
+ listen [::]:3260
+ listen [fe80::be:ef]:3261
}
target iqn.2012-06.com.example:target0 {
alias "Example target"
auth-group no-authentication
lun 0 {
- path /dev/zvol/example_0
+ path /dev/zvol/tank/example_0
blocksize 4096
size 4G
}
}
-target iqn.2012-06.com.example:target3 {
+target iqn.2012-06.com.example:target1 {
chap chapuser chapsecret
lun 0 {
- path /dev/zvol/example_3
+ path /dev/zvol/tank/example_1
}
}
target iqn.2012-06.com.example:target2 {
- auth-group example2
- portal-group example2
+ auth-group ag0
+ portal-group pg0
lun 0 {
- path /dev/zvol/example2_0
+ path /dev/zvol/tank/example2_0
}
lun 1 {
- path /dev/zvol/example2_1
+ path /dev/zvol/tank/example2_1
option foo bar
}
}
diff --git a/usr.sbin/ctld/ctld.8 b/usr.sbin/ctld/ctld.8
index 9cff3a8..aa9a414 100644
--- a/usr.sbin/ctld/ctld.8
+++ b/usr.sbin/ctld/ctld.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 20, 2014
+.Dd November 9, 2014
.Dt CTLD 8
.Os
.Sh NAME
@@ -105,6 +105,11 @@ utility exits 0 on success, and >0 if an error occurs.
.Xr ctl 4 ,
.Xr ctl.conf 5 ,
.Xr ctladm 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 10.0 .
.Sh AUTHORS
The
.Nm
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index c14be21..bbf8e7d 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
@@ -48,6 +50,7 @@
#include <unistd.h>
#include "ctld.h"
+#include "isns.h"
bool proxy_mode = false;
@@ -87,7 +90,10 @@ conf_new(void)
TAILQ_INIT(&conf->conf_targets);
TAILQ_INIT(&conf->conf_auth_groups);
TAILQ_INIT(&conf->conf_portal_groups);
+ TAILQ_INIT(&conf->conf_isns);
+ conf->conf_isns_period = 900;
+ conf->conf_isns_timeout = 5;
conf->conf_debug = 0;
conf->conf_timeout = 60;
conf->conf_maxproc = 30;
@@ -101,6 +107,7 @@ conf_delete(struct conf *conf)
struct target *targ, *tmp;
struct auth_group *ag, *cagtmp;
struct portal_group *pg, *cpgtmp;
+ struct isns *is, *istmp;
assert(conf->conf_pidfh == NULL);
@@ -110,6 +117,8 @@ conf_delete(struct conf *conf)
auth_group_delete(ag);
TAILQ_FOREACH_SAFE(pg, &conf->conf_portal_groups, pg_next, cpgtmp)
portal_group_delete(pg);
+ TAILQ_FOREACH_SAFE(is, &conf->conf_isns, i_next, istmp)
+ isns_delete(is);
free(conf->conf_pidfile_path);
free(conf);
}
@@ -253,7 +262,7 @@ auth_new_chap_mutual(struct auth_group *ag, const char *user,
if (ag->ag_name != NULL)
log_warnx("cannot mix \"chap-mutual\" authentication "
"with other types for auth-group \"%s\"",
- ag->ag_name);
+ ag->ag_name);
else
log_warnx("cannot mix \"chap-mutual\" authentication "
"with other types for target \"%s\"",
@@ -316,6 +325,18 @@ auth_name_find(const struct auth_group *ag, const char *name)
return (NULL);
}
+int
+auth_name_check(const struct auth_group *ag, const char *initiator_name)
+{
+ if (!auth_name_defined(ag))
+ return (0);
+
+ if (auth_name_find(ag, initiator_name) == NULL)
+ return (1);
+
+ return (0);
+}
+
const struct auth_portal *
auth_portal_new(struct auth_group *ag, const char *portal)
{
@@ -428,6 +449,19 @@ next:
return (NULL);
}
+int
+auth_portal_check(const struct auth_group *ag, const struct sockaddr_storage *sa)
+{
+
+ if (!auth_portal_defined(ag))
+ return (0);
+
+ if (auth_portal_find(ag, sa) == NULL)
+ return (1);
+
+ return (0);
+}
+
struct auth_group *
auth_group_new(struct conf *conf, const char *name)
{
@@ -488,25 +522,10 @@ auth_group_find(const struct conf *conf, const char *name)
return (NULL);
}
-static int
-auth_group_set_type(struct auth_group *ag, int type)
-{
-
- if (ag->ag_type == AG_TYPE_UNKNOWN) {
- ag->ag_type = type;
- return (0);
- }
-
- if (ag->ag_type == type)
- return (0);
-
- return (1);
-}
-
int
-auth_group_set_type_str(struct auth_group *ag, const char *str)
+auth_group_set_type(struct auth_group *ag, const char *str)
{
- int error, type;
+ int type;
if (strcmp(str, "none") == 0) {
type = AG_TYPE_NO_AUTHENTICATION;
@@ -526,20 +545,22 @@ auth_group_set_type_str(struct auth_group *ag, const char *str)
return (1);
}
- error = auth_group_set_type(ag, type);
- if (error != 0) {
- if (ag->ag_name != NULL)
+ if (ag->ag_type != AG_TYPE_UNKNOWN && ag->ag_type != type) {
+ if (ag->ag_name != NULL) {
log_warnx("cannot set auth-type to \"%s\" for "
"auth-group \"%s\"; already has a different "
"type", str, ag->ag_name);
- else
+ } else {
log_warnx("cannot set auth-type to \"%s\" for target "
"\"%s\"; already has a different type",
str, ag->ag_target->t_name);
+ }
return (1);
}
- return (error);
+ ag->ag_type = type;
+
+ return (0);
}
static struct portal *
@@ -559,8 +580,10 @@ portal_new(struct portal_group *pg)
static void
portal_delete(struct portal *portal)
{
+
TAILQ_REMOVE(&portal->p_portal_group->pg_portals, portal, p_next);
- freeaddrinfo(portal->p_ai);
+ if (portal->p_ai != NULL)
+ freeaddrinfo(portal->p_ai);
free(portal->p_listen);
free(portal);
}
@@ -599,6 +622,7 @@ portal_group_delete(struct portal_group *pg)
TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp)
portal_delete(portal);
free(pg->pg_name);
+ free(pg->pg_redirection);
free(pg);
}
@@ -615,50 +639,28 @@ portal_group_find(const struct conf *conf, const char *name)
return (NULL);
}
-int
-portal_group_add_listen(struct portal_group *pg, const char *value, bool iser)
+static int
+parse_addr_port(char *arg, const char *def_port, struct addrinfo **ai)
{
struct addrinfo hints;
- struct portal *portal;
- char *addr, *ch, *arg;
+ char *addr, *ch;
const char *port;
int error, colons = 0;
- portal = portal_new(pg);
- portal->p_listen = checked_strdup(value);
- portal->p_iser = iser;
-
- arg = portal->p_listen;
- if (arg[0] == '\0') {
- log_warnx("empty listen address");
- free(portal->p_listen);
- free(portal);
- return (1);
- }
if (arg[0] == '[') {
/*
* IPv6 address in square brackets, perhaps with port.
*/
arg++;
addr = strsep(&arg, "]");
- if (arg == NULL) {
- log_warnx("invalid listen address %s",
- portal->p_listen);
- free(portal->p_listen);
- free(portal);
+ if (arg == NULL)
return (1);
- }
if (arg[0] == '\0') {
- port = "3260";
+ port = def_port;
} else if (arg[0] == ':') {
port = arg + 1;
- } else {
- log_warnx("invalid listen address %s",
- portal->p_listen);
- free(portal->p_listen);
- free(portal);
+ } else
return (1);
- }
} else {
/*
* Either IPv6 address without brackets - and without
@@ -670,11 +672,11 @@ portal_group_add_listen(struct portal_group *pg, const char *value, bool iser)
}
if (colons > 1) {
addr = arg;
- port = "3260";
+ port = def_port;
} else {
addr = strsep(&arg, ":");
if (arg == NULL)
- port = "3260";
+ port = def_port;
else
port = arg;
}
@@ -684,13 +686,24 @@ portal_group_add_listen(struct portal_group *pg, const char *value, bool iser)
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
+ error = getaddrinfo(addr, port, &hints, ai);
+ if (error != 0)
+ return (1);
+ return (0);
+}
- error = getaddrinfo(addr, port, &hints, &portal->p_ai);
- if (error != 0) {
- log_warnx("getaddrinfo for %s failed: %s",
- portal->p_listen, gai_strerror(error));
- free(portal->p_listen);
- free(portal);
+int
+portal_group_add_listen(struct portal_group *pg, const char *value, bool iser)
+{
+ struct portal *portal;
+
+ portal = portal_new(pg);
+ portal->p_listen = checked_strdup(value);
+ portal->p_iser = iser;
+
+ if (parse_addr_port(portal->p_listen, "3260", &portal->p_ai)) {
+ log_warnx("invalid listen address %s", portal->p_listen);
+ portal_delete(portal);
return (1);
}
@@ -702,6 +715,308 @@ portal_group_add_listen(struct portal_group *pg, const char *value, bool iser)
return (0);
}
+int
+isns_new(struct conf *conf, const char *addr)
+{
+ struct isns *isns;
+
+ isns = calloc(1, sizeof(*isns));
+ if (isns == NULL)
+ log_err(1, "calloc");
+ isns->i_conf = conf;
+ TAILQ_INSERT_TAIL(&conf->conf_isns, isns, i_next);
+ isns->i_addr = checked_strdup(addr);
+
+ if (parse_addr_port(isns->i_addr, "3205", &isns->i_ai)) {
+ log_warnx("invalid iSNS address %s", isns->i_addr);
+ isns_delete(isns);
+ return (1);
+ }
+
+ /*
+ * XXX: getaddrinfo(3) may return multiple addresses; we should turn
+ * those into multiple servers.
+ */
+
+ return (0);
+}
+
+void
+isns_delete(struct isns *isns)
+{
+
+ TAILQ_REMOVE(&isns->i_conf->conf_isns, isns, i_next);
+ free(isns->i_addr);
+ if (isns->i_ai != NULL)
+ freeaddrinfo(isns->i_ai);
+ free(isns);
+}
+
+static int
+isns_do_connect(struct isns *isns)
+{
+ int s;
+
+ s = socket(isns->i_ai->ai_family, isns->i_ai->ai_socktype,
+ isns->i_ai->ai_protocol);
+ if (s < 0) {
+ log_warn("socket(2) failed for %s", isns->i_addr);
+ return (-1);
+ }
+ if (connect(s, isns->i_ai->ai_addr, isns->i_ai->ai_addrlen)) {
+ log_warn("connect(2) failed for %s", isns->i_addr);
+ close(s);
+ return (-1);
+ }
+ return(s);
+}
+
+static int
+isns_do_register(struct isns *isns, int s, const char *hostname)
+{
+ struct conf *conf = isns->i_conf;
+ struct target *target;
+ struct portal *portal;
+ struct portal_group *pg;
+ struct isns_req *req;
+ int res = 0;
+ uint32_t error;
+
+ req = isns_req_create(ISNS_FUNC_DEVATTRREG, ISNS_FLAG_CLIENT);
+ isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name);
+ isns_req_add_delim(req);
+ isns_req_add_str(req, 1, hostname);
+ isns_req_add_32(req, 2, 2); /* 2 -- iSCSI */
+ isns_req_add_32(req, 6, conf->conf_isns_period);
+ TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
+ if (pg->pg_unassigned)
+ continue;
+ TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
+ isns_req_add_addr(req, 16, portal->p_ai);
+ isns_req_add_port(req, 17, portal->p_ai);
+ }
+ }
+ TAILQ_FOREACH(target, &conf->conf_targets, t_next) {
+ isns_req_add_str(req, 32, target->t_name);
+ isns_req_add_32(req, 33, 1); /* 1 -- Target*/
+ if (target->t_alias != NULL)
+ isns_req_add_str(req, 34, target->t_alias);
+ pg = target->t_portal_group;
+ isns_req_add_32(req, 51, pg->pg_tag);
+ TAILQ_FOREACH(portal, &pg->pg_portals, p_next) {
+ isns_req_add_addr(req, 49, portal->p_ai);
+ isns_req_add_port(req, 50, portal->p_ai);
+ }
+ }
+ res = isns_req_send(s, req);
+ if (res < 0) {
+ log_warn("send(2) failed for %s", isns->i_addr);
+ goto quit;
+ }
+ res = isns_req_receive(s, req);
+ if (res < 0) {
+ log_warn("receive(2) failed for %s", isns->i_addr);
+ goto quit;
+ }
+ error = isns_req_get_status(req);
+ if (error != 0) {
+ log_warnx("iSNS register error %d for %s", error, isns->i_addr);
+ res = -1;
+ }
+quit:
+ isns_req_free(req);
+ return (res);
+}
+
+static int
+isns_do_check(struct isns *isns, int s, const char *hostname)
+{
+ struct conf *conf = isns->i_conf;
+ struct isns_req *req;
+ int res = 0;
+ uint32_t error;
+
+ req = isns_req_create(ISNS_FUNC_DEVATTRQRY, ISNS_FLAG_CLIENT);
+ isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name);
+ isns_req_add_str(req, 1, hostname);
+ isns_req_add_delim(req);
+ isns_req_add(req, 2, 0, NULL);
+ res = isns_req_send(s, req);
+ if (res < 0) {
+ log_warn("send(2) failed for %s", isns->i_addr);
+ goto quit;
+ }
+ res = isns_req_receive(s, req);
+ if (res < 0) {
+ log_warn("receive(2) failed for %s", isns->i_addr);
+ goto quit;
+ }
+ error = isns_req_get_status(req);
+ if (error != 0) {
+ log_warnx("iSNS check error %d for %s", error, isns->i_addr);
+ res = -1;
+ }
+quit:
+ isns_req_free(req);
+ return (res);
+}
+
+static int
+isns_do_deregister(struct isns *isns, int s, const char *hostname)
+{
+ struct conf *conf = isns->i_conf;
+ struct isns_req *req;
+ int res = 0;
+ uint32_t error;
+
+ req = isns_req_create(ISNS_FUNC_DEVDEREG, ISNS_FLAG_CLIENT);
+ isns_req_add_str(req, 32, TAILQ_FIRST(&conf->conf_targets)->t_name);
+ isns_req_add_delim(req);
+ isns_req_add_str(req, 1, hostname);
+ res = isns_req_send(s, req);
+ if (res < 0) {
+ log_warn("send(2) failed for %s", isns->i_addr);
+ goto quit;
+ }
+ res = isns_req_receive(s, req);
+ if (res < 0) {
+ log_warn("receive(2) failed for %s", isns->i_addr);
+ goto quit;
+ }
+ error = isns_req_get_status(req);
+ if (error != 0) {
+ log_warnx("iSNS deregister error %d for %s", error, isns->i_addr);
+ res = -1;
+ }
+quit:
+ isns_req_free(req);
+ return (res);
+}
+
+void
+isns_register(struct isns *isns, struct isns *oldisns)
+{
+ struct conf *conf = isns->i_conf;
+ int s;
+ char hostname[256];
+
+ if (TAILQ_EMPTY(&conf->conf_targets) ||
+ TAILQ_EMPTY(&conf->conf_portal_groups))
+ return;
+ set_timeout(conf->conf_isns_timeout, false);
+ s = isns_do_connect(isns);
+ if (s < 0) {
+ set_timeout(0, false);
+ return;
+ }
+ gethostname(hostname, sizeof(hostname));
+
+ if (oldisns == NULL || TAILQ_EMPTY(&oldisns->i_conf->conf_targets))
+ oldisns = isns;
+ isns_do_deregister(oldisns, s, hostname);
+ isns_do_register(isns, s, hostname);
+ close(s);
+ set_timeout(0, false);
+}
+
+void
+isns_check(struct isns *isns)
+{
+ struct conf *conf = isns->i_conf;
+ int s, res;
+ char hostname[256];
+
+ if (TAILQ_EMPTY(&conf->conf_targets) ||
+ TAILQ_EMPTY(&conf->conf_portal_groups))
+ return;
+ set_timeout(conf->conf_isns_timeout, false);
+ s = isns_do_connect(isns);
+ if (s < 0) {
+ set_timeout(0, false);
+ return;
+ }
+ gethostname(hostname, sizeof(hostname));
+
+ res = isns_do_check(isns, s, hostname);
+ if (res < 0) {
+ isns_do_deregister(isns, s, hostname);
+ isns_do_register(isns, s, hostname);
+ }
+ close(s);
+ set_timeout(0, false);
+}
+
+void
+isns_deregister(struct isns *isns)
+{
+ struct conf *conf = isns->i_conf;
+ int s;
+ char hostname[256];
+
+ if (TAILQ_EMPTY(&conf->conf_targets) ||
+ TAILQ_EMPTY(&conf->conf_portal_groups))
+ return;
+ set_timeout(conf->conf_isns_timeout, false);
+ s = isns_do_connect(isns);
+ if (s < 0)
+ return;
+ gethostname(hostname, sizeof(hostname));
+
+ isns_do_deregister(isns, s, hostname);
+ close(s);
+ set_timeout(0, false);
+}
+
+int
+portal_group_set_filter(struct portal_group *pg, const char *str)
+{
+ int filter;
+
+ if (strcmp(str, "none") == 0) {
+ filter = PG_FILTER_NONE;
+ } else if (strcmp(str, "portal") == 0) {
+ filter = PG_FILTER_PORTAL;
+ } else if (strcmp(str, "portal-name") == 0) {
+ filter = PG_FILTER_PORTAL_NAME;
+ } else if (strcmp(str, "portal-name-auth") == 0) {
+ filter = PG_FILTER_PORTAL_NAME_AUTH;
+ } else {
+ log_warnx("invalid discovery-filter \"%s\" for portal-group "
+ "\"%s\"; valid values are \"none\", \"portal\", "
+ "\"portal-name\", and \"portal-name-auth\"",
+ str, pg->pg_name);
+ return (1);
+ }
+
+ if (pg->pg_discovery_filter != PG_FILTER_UNKNOWN &&
+ pg->pg_discovery_filter != filter) {
+ log_warnx("cannot set discovery-filter to \"%s\" for "
+ "portal-group \"%s\"; already has a different "
+ "value", str, pg->pg_name);
+ return (1);
+ }
+
+ pg->pg_discovery_filter = filter;
+
+ return (0);
+}
+
+int
+portal_group_set_redirection(struct portal_group *pg, const char *addr)
+{
+
+ if (pg->pg_redirection != NULL) {
+ log_warnx("cannot set redirection to \"%s\" for "
+ "portal-group \"%s\"; already defined",
+ addr, pg->pg_name);
+ return (1);
+ }
+
+ pg->pg_redirection = checked_strdup(addr);
+
+ return (0);
+}
+
static bool
valid_hex(const char ch)
{
@@ -754,7 +1069,7 @@ valid_iscsi_name(const char *name)
for (i = strlen("iqn."); name[i] != '\0'; i++) {
/*
* XXX: We should verify UTF-8 normalisation, as defined
- * by 3.2.6.2: iSCSI Name Encoding.
+ * by 3.2.6.2: iSCSI Name Encoding.
*/
if (isalnum(name[i]))
continue;
@@ -846,6 +1161,7 @@ target_delete(struct target *targ)
TAILQ_FOREACH_SAFE(lun, &targ->t_luns, l_next, tmp)
lun_delete(lun);
free(targ->t_name);
+ free(targ->t_redirection);
free(targ);
}
@@ -862,6 +1178,22 @@ target_find(struct conf *conf, const char *name)
return (NULL);
}
+int
+target_set_redirection(struct target *target, const char *addr)
+{
+
+ if (target->t_redirection != NULL) {
+ log_warnx("cannot set redirection to \"%s\" for "
+ "target \"%s\"; already defined",
+ addr, target->t_name);
+ return (1);
+ }
+
+ target->t_redirection = checked_strdup(addr);
+
+ return (0);
+}
+
struct lun *
lun_new(struct target *targ, int lun_id)
{
@@ -1164,7 +1496,7 @@ conf_verify(struct conf *conf)
struct portal_group *pg;
struct target *targ;
struct lun *lun;
- bool found_lun;
+ bool found;
int error;
if (conf->conf_pidfile_path == NULL)
@@ -1181,17 +1513,22 @@ conf_verify(struct conf *conf)
"default");
assert(targ->t_portal_group != NULL);
}
- found_lun = false;
+ found = false;
TAILQ_FOREACH(lun, &targ->t_luns, l_next) {
error = conf_verify_lun(lun);
if (error != 0)
return (error);
- found_lun = true;
+ found = true;
}
- if (!found_lun) {
+ if (!found && targ->t_redirection == NULL) {
log_warnx("no LUNs defined for target \"%s\"",
targ->t_name);
}
+ if (found && targ->t_redirection != NULL) {
+ log_debugx("target \"%s\" contains luns, "
+ " but configured for redirection",
+ targ->t_name);
+ }
}
TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
assert(pg->pg_name != NULL);
@@ -1201,17 +1538,29 @@ conf_verify(struct conf *conf)
assert(pg->pg_discovery_auth_group != NULL);
}
+ if (pg->pg_discovery_filter == PG_FILTER_UNKNOWN)
+ pg->pg_discovery_filter = PG_FILTER_NONE;
+
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
if (targ->t_portal_group == pg)
break;
}
- if (targ == NULL) {
+ if (pg->pg_redirection != NULL) {
+ if (targ != NULL) {
+ log_debugx("portal-group \"%s\" assigned "
+ "to target \"%s\", but configured "
+ "for redirection",
+ pg->pg_name, targ->t_name);
+ }
+ pg->pg_unassigned = false;
+ } else if (targ != NULL) {
+ pg->pg_unassigned = false;
+ } else {
if (strcmp(pg->pg_name, "default") != 0)
log_warnx("portal-group \"%s\" not assigned "
"to any target", pg->pg_name);
pg->pg_unassigned = true;
- } else
- pg->pg_unassigned = false;
+ }
}
TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) {
if (ag->ag_name == NULL)
@@ -1219,11 +1568,20 @@ conf_verify(struct conf *conf)
else
assert(ag->ag_target == NULL);
+ found = false;
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
- if (targ->t_auth_group == ag)
+ if (targ->t_auth_group == ag) {
+ found = true;
break;
+ }
+ }
+ TAILQ_FOREACH(pg, &conf->conf_portal_groups, pg_next) {
+ if (pg->pg_discovery_auth_group == ag) {
+ found = true;
+ break;
+ }
}
- if (targ == NULL && ag->ag_name != NULL &&
+ if (!found && ag->ag_name != NULL &&
strcmp(ag->ag_name, "default") != 0 &&
strcmp(ag->ag_name, "no-authentication") != 0 &&
strcmp(ag->ag_name, "no-access") != 0) {
@@ -1242,6 +1600,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
struct lun *oldlun, *newlun, *tmplun;
struct portal_group *oldpg, *newpg;
struct portal *oldp, *newp;
+ struct isns *oldns, *newns;
pid_t otherpid;
int changed, cumulated_error = 0, error;
int one = 1;
@@ -1279,12 +1638,22 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
}
}
+ /* Deregister on removed iSNS servers. */
+ TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) {
+ TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) {
+ if (strcmp(oldns->i_addr, newns->i_addr) == 0)
+ break;
+ }
+ if (newns == NULL)
+ isns_deregister(oldns);
+ }
+
/*
* XXX: If target or lun removal fails, we should somehow "move"
- * the old lun or target into newconf, so that subsequent
- * conf_apply() would try to remove them again. That would
- * be somewhat hairy, though, and lun deletion failures don't
- * really happen, so leave it as it is for now.
+ * the old lun or target into newconf, so that subsequent
+ * conf_apply() would try to remove them again. That would
+ * be somewhat hairy, though, and lun deletion failures don't
+ * really happen, so leave it as it is for now.
*/
TAILQ_FOREACH_SAFE(oldtarg, &oldconf->conf_targets, t_next, tmptarg) {
/*
@@ -1308,10 +1677,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
oldlun->l_ctl_lun);
cumulated_error++;
}
- lun_delete(oldlun);
}
kernel_port_remove(oldtarg);
- target_delete(oldtarg);
continue;
}
@@ -1334,7 +1701,6 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
oldlun->l_ctl_lun);
cumulated_error++;
}
- lun_delete(oldlun);
continue;
}
@@ -1413,7 +1779,8 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
if (oldtarg != NULL) {
oldlun = lun_find(oldtarg, newlun->l_lun);
if (oldlun != NULL) {
- if (newlun->l_size != oldlun->l_size) {
+ if (newlun->l_size != oldlun->l_size ||
+ newlun->l_size == 0) {
log_debugx("resizing lun %d, "
"target %s, CTL lun %d",
newlun->l_lun,
@@ -1559,6 +1926,19 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
}
}
+ /* (Re-)Register on remaining/new iSNS servers. */
+ TAILQ_FOREACH(newns, &newconf->conf_isns, i_next) {
+ TAILQ_FOREACH(oldns, &oldconf->conf_isns, i_next) {
+ if (strcmp(oldns->i_addr, newns->i_addr) == 0)
+ break;
+ }
+ isns_register(newns, oldns);
+ }
+
+ /* Schedule iSNS update */
+ if (!TAILQ_EMPTY(&newconf->conf_isns))
+ set_timeout((newconf->conf_isns_period + 2) / 3, false);
+
return (cumulated_error);
}
@@ -1570,7 +1950,7 @@ timed_out(void)
}
static void
-sigalrm_handler(int dummy __unused)
+sigalrm_handler_fatal(int dummy __unused)
{
/*
* It would be easiest to just log an error and exit. We can't
@@ -1590,19 +1970,35 @@ sigalrm_handler(int dummy __unused)
}
static void
-set_timeout(const struct conf *conf)
+sigalrm_handler(int dummy __unused)
+{
+
+ sigalrm_received = true;
+}
+
+void
+set_timeout(int timeout, int fatal)
{
struct sigaction sa;
struct itimerval itv;
int error;
- if (conf->conf_timeout <= 0) {
+ if (timeout <= 0) {
log_debugx("session timeout disabled");
+ bzero(&itv, sizeof(itv));
+ error = setitimer(ITIMER_REAL, &itv, NULL);
+ if (error != 0)
+ log_err(1, "setitimer");
+ sigalrm_received = false;
return;
}
+ sigalrm_received = false;
bzero(&sa, sizeof(sa));
- sa.sa_handler = sigalrm_handler;
+ if (fatal)
+ sa.sa_handler = sigalrm_handler_fatal;
+ else
+ sa.sa_handler = sigalrm_handler;
sigfillset(&sa.sa_mask);
error = sigaction(SIGALRM, &sa, NULL);
if (error != 0)
@@ -1612,12 +2008,10 @@ set_timeout(const struct conf *conf)
* First SIGALRM will arive after conf_timeout seconds.
* If we do nothing, another one will arrive a second later.
*/
+ log_debugx("setting session timeout to %d seconds", timeout);
bzero(&itv, sizeof(itv));
itv.it_interval.tv_sec = 1;
- itv.it_value.tv_sec = conf->conf_timeout;
-
- log_debugx("setting session timeout to %d seconds",
- conf->conf_timeout);
+ itv.it_value.tv_sec = timeout;
error = setitimer(ITIMER_REAL, &itv, NULL);
if (error != 0)
log_err(1, "setitimer");
@@ -1703,7 +2097,7 @@ handle_connection(struct portal *portal, int fd,
setproctitle("%s", host);
conn = connection_new(portal, fd, host, client_sa);
- set_timeout(conf);
+ set_timeout(conf->conf_timeout, true);
kernel_capsicate();
login(conn);
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
@@ -1750,7 +2144,7 @@ main_loop(struct conf *conf, bool dont_fork)
pidfile_write(conf->conf_pidfh);
for (;;) {
- if (sighup_received || sigterm_received)
+ if (sighup_received || sigterm_received || timed_out())
return;
#ifdef ICL_KERNEL_PROXY
@@ -1758,9 +2152,7 @@ main_loop(struct conf *conf, bool dont_fork)
client_salen = sizeof(client_sa);
kernel_accept(&connection_id, &portal_id,
(struct sockaddr *)&client_sa, &client_salen);
- if (client_salen < client_sa.ss_len)
- log_errx(1, "salen %u < %u",
- client_salen, client_sa.ss_len);
+ assert(client_salen >= client_sa.ss_len);
log_debugx("incoming connection, id %d, portal id %d",
connection_id, portal_id);
@@ -1804,10 +2196,8 @@ found:
&client_salen);
if (client_fd < 0)
log_err(1, "accept");
- if (client_salen < client_sa.ss_len)
- log_errx(1, "salen %u < %u",
- client_salen,
- client_sa.ss_len);
+ assert(client_salen >= client_sa.ss_len);
+
handle_connection(portal, client_fd,
(struct sockaddr *)&client_sa,
dont_fork);
@@ -1878,6 +2268,7 @@ int
main(int argc, char **argv)
{
struct conf *oldconf, *newconf, *tmpconf;
+ struct isns *newns;
const char *config_path = DEFAULT_CONFIG_PATH;
int debug = 0, ch, error;
bool dont_daemonize = false;
@@ -1937,6 +2328,10 @@ main(int argc, char **argv)
}
}
+ /* Schedule iSNS update */
+ if (!TAILQ_EMPTY(&newconf->conf_isns))
+ set_timeout((newconf->conf_isns_period + 2) / 3, false);
+
for (;;) {
main_loop(newconf, dont_daemonize);
if (sighup_received) {
@@ -1972,12 +2367,25 @@ main(int argc, char **argv)
error = conf_apply(oldconf, newconf);
if (error != 0)
log_warnx("failed to apply configuration");
+ conf_delete(oldconf);
+ oldconf = NULL;
log_warnx("exiting on signal");
exit(0);
} else {
nchildren -= wait_for_children(false);
assert(nchildren >= 0);
+ if (timed_out()) {
+ set_timeout(0, false);
+ TAILQ_FOREACH(newns, &newconf->conf_isns, i_next)
+ isns_check(newns);
+ /* Schedule iSNS update */
+ if (!TAILQ_EMPTY(&newconf->conf_isns)) {
+ set_timeout((newconf->conf_isns_period
+ + 2) / 3,
+ false);
+ }
+ }
}
}
/* NOTREACHED */
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 98d612f..600bd30 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -39,6 +39,7 @@
#include <sys/socket.h>
#include <stdbool.h>
#include <libutil.h>
+#include <openssl/md5.h>
#define DEFAULT_CONFIG_PATH "/etc/ctl.conf"
#define DEFAULT_PIDFILE "/var/run/ctld.pid"
@@ -102,13 +103,21 @@ struct portal {
int p_socket;
};
+#define PG_FILTER_UNKNOWN 0
+#define PG_FILTER_NONE 1
+#define PG_FILTER_PORTAL 2
+#define PG_FILTER_PORTAL_NAME 3
+#define PG_FILTER_PORTAL_NAME_AUTH 4
+
struct portal_group {
TAILQ_ENTRY(portal_group) pg_next;
struct conf *pg_conf;
char *pg_name;
struct auth_group *pg_discovery_auth_group;
+ int pg_discovery_filter;
bool pg_unassigned;
TAILQ_HEAD(, portal) pg_portals;
+ char *pg_redirection;
uint16_t pg_tag;
};
@@ -143,6 +152,14 @@ struct target {
struct portal_group *t_portal_group;
char *t_name;
char *t_alias;
+ char *t_redirection;
+};
+
+struct isns {
+ TAILQ_ENTRY(isns) i_next;
+ struct conf *i_conf;
+ char *i_addr;
+ struct addrinfo *i_ai;
};
struct conf {
@@ -150,6 +167,9 @@ struct conf {
TAILQ_HEAD(, target) conf_targets;
TAILQ_HEAD(, auth_group) conf_auth_groups;
TAILQ_HEAD(, portal_group) conf_portal_groups;
+ TAILQ_HEAD(, isns) conf_isns;
+ int conf_isns_period;
+ int conf_isns_timeout;
int conf_debug;
int conf_timeout;
int conf_maxproc;
@@ -189,6 +209,8 @@ struct connection {
int conn_immediate_data;
int conn_header_digest;
int conn_data_digest;
+ const char *conn_user;
+ struct chap *conn_chap;
};
struct pdu {
@@ -207,6 +229,35 @@ struct keys {
size_t keys_data_len;
};
+#define CHAP_CHALLENGE_LEN 1024
+
+struct chap {
+ unsigned char chap_id;
+ char chap_challenge[CHAP_CHALLENGE_LEN];
+ char chap_response[MD5_DIGEST_LENGTH];
+};
+
+struct rchap {
+ char *rchap_secret;
+ unsigned char rchap_id;
+ void *rchap_challenge;
+ size_t rchap_challenge_len;
+};
+
+struct chap *chap_new(void);
+char *chap_get_id(const struct chap *chap);
+char *chap_get_challenge(const struct chap *chap);
+int chap_receive(struct chap *chap, const char *response);
+int chap_authenticate(struct chap *chap,
+ const char *secret);
+void chap_delete(struct chap *chap);
+
+struct rchap *rchap_new(const char *secret);
+int rchap_receive(struct rchap *rchap,
+ const char *id, const char *challenge);
+char *rchap_get_response(struct rchap *rchap);
+void rchap_delete(struct rchap *rchap);
+
struct conf *conf_new(void);
struct conf *conf_new_from_file(const char *path);
struct conf *conf_new_from_kernel(void);
@@ -217,7 +268,7 @@ struct auth_group *auth_group_new(struct conf *conf, const char *name);
void auth_group_delete(struct auth_group *ag);
struct auth_group *auth_group_find(const struct conf *conf,
const char *name);
-int auth_group_set_type_str(struct auth_group *ag,
+int auth_group_set_type(struct auth_group *ag,
const char *type);
const struct auth *auth_new_chap(struct auth_group *ag,
@@ -233,12 +284,16 @@ const struct auth_name *auth_name_new(struct auth_group *ag,
bool auth_name_defined(const struct auth_group *ag);
const struct auth_name *auth_name_find(const struct auth_group *ag,
const char *initiator_name);
+int auth_name_check(const struct auth_group *ag,
+ const char *initiator_name);
const struct auth_portal *auth_portal_new(struct auth_group *ag,
const char *initiator_portal);
bool auth_portal_defined(const struct auth_group *ag);
const struct auth_portal *auth_portal_find(const struct auth_group *ag,
const struct sockaddr_storage *sa);
+int auth_portal_check(const struct auth_group *ag,
+ const struct sockaddr_storage *sa);
struct portal_group *portal_group_new(struct conf *conf, const char *name);
void portal_group_delete(struct portal_group *pg);
@@ -246,11 +301,23 @@ struct portal_group *portal_group_find(const struct conf *conf,
const char *name);
int portal_group_add_listen(struct portal_group *pg,
const char *listen, bool iser);
+int portal_group_set_filter(struct portal_group *pg,
+ const char *filter);
+int portal_group_set_redirection(struct portal_group *pg,
+ const char *addr);
+
+int isns_new(struct conf *conf, const char *addr);
+void isns_delete(struct isns *is);
+void isns_register(struct isns *isns, struct isns *oldisns);
+void isns_check(struct isns *isns);
+void isns_deregister(struct isns *isns);
struct target *target_new(struct conf *conf, const char *name);
void target_delete(struct target *target);
struct target *target_find(struct conf *conf,
const char *name);
+int target_set_redirection(struct target *target,
+ const char *addr);
struct lun *lun_new(struct target *target, int lun_id);
void lun_delete(struct lun *lun);
@@ -324,6 +391,7 @@ void log_debugx(const char *, ...) __printflike(1, 2);
char *checked_strdup(const char *);
bool valid_iscsi_name(const char *name);
+void set_timeout(int timeout, int fatal);
bool timed_out(void);
#endif /* !CTLD_H */
diff --git a/usr.sbin/ctld/discovery.c b/usr.sbin/ctld/discovery.c
index 9908b96..01c9913 100644
--- a/usr.sbin/ctld/discovery.c
+++ b/usr.sbin/ctld/discovery.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
@@ -158,7 +160,7 @@ logout_new_response(struct pdu *request)
}
static void
-discovery_add_target(struct keys *response_keys, struct target *targ)
+discovery_add_target(struct keys *response_keys, const struct target *targ)
{
struct portal *portal;
char *buf;
@@ -199,14 +201,76 @@ discovery_add_target(struct keys *response_keys, struct target *targ)
}
}
+static bool
+discovery_target_filtered_out(const struct connection *conn,
+ const struct target *targ)
+{
+ const struct auth_group *ag;
+ const struct portal_group *pg;
+ const struct auth *auth;
+ int error;
+
+ ag = targ->t_auth_group;
+ pg = conn->conn_portal->p_portal_group;
+
+ assert(pg->pg_discovery_auth_group != PG_FILTER_UNKNOWN);
+
+ if (pg->pg_discovery_filter >= PG_FILTER_PORTAL &&
+ auth_portal_check(ag, &conn->conn_initiator_sa) != 0) {
+ log_debugx("initiator does not match initiator portals "
+ "allowed for target \"%s\"; skipping", targ->t_name);
+ return (true);
+ }
+
+ if (pg->pg_discovery_filter >= PG_FILTER_PORTAL_NAME &&
+ auth_name_check(ag, conn->conn_initiator_name) != 0) {
+ log_debugx("initiator does not match initiator names "
+ "allowed for target \"%s\"; skipping", targ->t_name);
+ return (true);
+ }
+
+ if (pg->pg_discovery_filter >= PG_FILTER_PORTAL_NAME_AUTH &&
+ ag->ag_type != AG_TYPE_NO_AUTHENTICATION) {
+ if (conn->conn_chap == NULL) {
+ assert(pg->pg_discovery_auth_group->ag_type ==
+ AG_TYPE_NO_AUTHENTICATION);
+
+ log_debugx("initiator didn't authenticate, but target "
+ "\"%s\" requires CHAP; skipping", targ->t_name);
+ return (true);
+ }
+
+ assert(conn->conn_user != NULL);
+ auth = auth_find(ag, conn->conn_user);
+ if (auth == NULL) {
+ log_debugx("CHAP user \"%s\" doesn't match target "
+ "\"%s\"; skipping", conn->conn_user, targ->t_name);
+ return (true);
+ }
+
+ error = chap_authenticate(conn->conn_chap, auth->a_secret);
+ if (error != 0) {
+ log_debugx("password for CHAP user \"%s\" doesn't "
+ "match target \"%s\"; skipping",
+ conn->conn_user, targ->t_name);
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
void
discovery(struct connection *conn)
{
struct pdu *request, *response;
struct keys *request_keys, *response_keys;
- struct target *targ;
+ const struct portal_group *pg;
+ const struct target *targ;
const char *send_targets;
+ pg = conn->conn_portal->p_portal_group;
+
log_debugx("beginning discovery session; waiting for Text PDU");
request = text_receive(conn);
request_keys = keys_new();
@@ -220,26 +284,31 @@ discovery(struct connection *conn)
response_keys = keys_new();
if (strcmp(send_targets, "All") == 0) {
- TAILQ_FOREACH(targ,
- &conn->conn_portal->p_portal_group->pg_conf->conf_targets,
- t_next) {
- if (targ->t_portal_group !=
- conn->conn_portal->p_portal_group) {
+ TAILQ_FOREACH(targ, &pg->pg_conf->conf_targets, t_next) {
+ if (targ->t_portal_group != pg) {
log_debugx("not returning target \"%s\"; "
"belongs to a different portal group",
targ->t_name);
continue;
}
+ if (discovery_target_filtered_out(conn, targ)) {
+ /* Ignore this target. */
+ continue;
+ }
discovery_add_target(response_keys, targ);
}
} else {
- targ = target_find(conn->conn_portal->p_portal_group->pg_conf,
- send_targets);
+ targ = target_find(pg->pg_conf, send_targets);
if (targ == NULL) {
log_debugx("initiator requested information on unknown "
"target \"%s\"; returning nothing", send_targets);
- } else
- discovery_add_target(response_keys, targ);
+ } else {
+ if (discovery_target_filtered_out(conn, targ)) {
+ /* Ignore this target. */
+ } else {
+ discovery_add_target(response_keys, targ);
+ }
+ }
}
keys_save(response_keys, response);
diff --git a/usr.sbin/ctld/isns.c b/usr.sbin/ctld/isns.c
new file mode 100644
index 0000000..2a7bd97
--- /dev/null
+++ b/usr.sbin/ctld/isns.c
@@ -0,0 +1,258 @@
+/*-
+ * Copyright (c) 2014 Alexander Motin <mav@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.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/endian.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ctld.h"
+#include "isns.h"
+
+struct isns_req *
+isns_req_alloc(void)
+{
+ struct isns_req *req;
+
+ req = calloc(sizeof(struct isns_req), 1);
+ if (req == NULL) {
+ log_err(1, "calloc");
+ return (NULL);
+ }
+ req->ir_buflen = sizeof(struct isns_hdr);
+ req->ir_usedlen = 0;
+ req->ir_buf = calloc(req->ir_buflen, 1);
+ if (req == NULL) {
+ free(req);
+ log_err(1, "calloc");
+ return (NULL);
+ }
+ return (req);
+}
+
+struct isns_req *
+isns_req_create(uint16_t func, uint16_t flags)
+{
+ struct isns_req *req;
+ struct isns_hdr *hdr;
+
+ req = isns_req_alloc();
+ req->ir_usedlen = sizeof(struct isns_hdr);
+ hdr = (struct isns_hdr *)req->ir_buf;
+ be16enc(hdr->ih_version, ISNS_VERSION);
+ be16enc(hdr->ih_function, func);
+ be16enc(hdr->ih_flags, flags);
+ return (req);
+}
+
+void
+isns_req_free(struct isns_req *req)
+{
+
+ free(req->ir_buf);
+ free(req);
+}
+
+static int
+isns_req_getspace(struct isns_req *req, uint32_t len)
+{
+ void *newbuf;
+ int newlen;
+
+ if (req->ir_usedlen + len <= req->ir_buflen)
+ return (0);
+ newlen = 1 << flsl(req->ir_usedlen + len);
+ newbuf = realloc(req->ir_buf, newlen);
+ if (newbuf == NULL) {
+ log_err(1, "realloc");
+ return (1);
+ }
+ req->ir_buf = newbuf;
+ req->ir_buflen = newlen;
+ return (0);
+}
+
+void
+isns_req_add(struct isns_req *req, uint32_t tag, uint32_t len,
+ const void *value)
+{
+ struct isns_tlv *tlv;
+ uint32_t vlen;
+
+ vlen = len + ((len & 3) ? (4 - (len & 3)) : 0);
+ isns_req_getspace(req, sizeof(*tlv) + vlen);
+ tlv = (struct isns_tlv *)&req->ir_buf[req->ir_usedlen];
+ be32enc(tlv->it_tag, tag);
+ be32enc(tlv->it_length, vlen);
+ memcpy(tlv->it_value, value, len);
+ if (vlen != len)
+ memset(&tlv->it_value[len], 0, vlen - len);
+ req->ir_usedlen += sizeof(*tlv) + vlen;
+}
+
+void
+isns_req_add_delim(struct isns_req *req)
+{
+
+ isns_req_add(req, 0, 0, NULL);
+}
+
+void
+isns_req_add_str(struct isns_req *req, uint32_t tag, const char *value)
+{
+
+ isns_req_add(req, tag, strlen(value) + 1, value);
+}
+
+void
+isns_req_add_32(struct isns_req *req, uint32_t tag, uint32_t value)
+{
+ uint32_t beval;
+
+ be32enc(&beval, value);
+ isns_req_add(req, tag, sizeof(value), &beval);
+}
+
+void
+isns_req_add_addr(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
+{
+ struct sockaddr_in *in4;
+ struct sockaddr_in6 *in6;
+ uint8_t buf[16];
+
+ switch (ai->ai_addr->sa_family) {
+ case AF_INET:
+ in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
+ memset(buf, 0, 10);
+ buf[10] = 0xff;
+ buf[11] = 0xff;
+ memcpy(&buf[12], &in4->sin_addr, sizeof(in4->sin_addr));
+ isns_req_add(req, tag, sizeof(buf), buf);
+ break;
+ case AF_INET6:
+ in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
+ isns_req_add(req, tag, sizeof(in6->sin6_addr), &in6->sin6_addr);
+ break;
+ default:
+ log_errx(1, "Unsupported address family %d",
+ ai->ai_addr->sa_family);
+ }
+}
+
+void
+isns_req_add_port(struct isns_req *req, uint32_t tag, struct addrinfo *ai)
+{
+ struct sockaddr_in *in4;
+ struct sockaddr_in6 *in6;
+ uint32_t buf;
+
+ switch (ai->ai_addr->sa_family) {
+ case AF_INET:
+ in4 = (struct sockaddr_in *)(void *)ai->ai_addr;
+ be32enc(&buf, ntohs(in4->sin_port));
+ isns_req_add(req, tag, sizeof(buf), &buf);
+ break;
+ case AF_INET6:
+ in6 = (struct sockaddr_in6 *)(void *)ai->ai_addr;
+ be32enc(&buf, ntohs(in6->sin6_port));
+ isns_req_add(req, tag, sizeof(buf), &buf);
+ break;
+ default:
+ log_errx(1, "Unsupported address family %d",
+ ai->ai_addr->sa_family);
+ }
+}
+
+int
+isns_req_send(int s, struct isns_req *req)
+{
+ struct isns_hdr *hdr;
+ int res;
+
+ hdr = (struct isns_hdr *)req->ir_buf;
+ be16enc(hdr->ih_length, req->ir_usedlen - sizeof(*hdr));
+ be16enc(hdr->ih_flags, be16dec(hdr->ih_flags) |
+ ISNS_FLAG_LAST | ISNS_FLAG_FIRST);
+ be16enc(hdr->ih_transaction, 0);
+ be16enc(hdr->ih_sequence, 0);
+
+ res = write(s, req->ir_buf, req->ir_usedlen);
+ return ((res < 0) ? -1 : 0);
+}
+
+int
+isns_req_receive(int s, struct isns_req *req)
+{
+ struct isns_hdr *hdr;
+ ssize_t res, len;
+
+ req->ir_usedlen = 0;
+ isns_req_getspace(req, sizeof(*hdr));
+ res = read(s, req->ir_buf, sizeof(*hdr));
+ if (res < (ssize_t)sizeof(*hdr))
+ return (-1);
+ req->ir_usedlen = sizeof(*hdr);
+ hdr = (struct isns_hdr *)req->ir_buf;
+ if (be16dec(hdr->ih_version) != ISNS_VERSION)
+ return (-1);
+ if ((be16dec(hdr->ih_flags) & (ISNS_FLAG_LAST | ISNS_FLAG_FIRST)) !=
+ (ISNS_FLAG_LAST | ISNS_FLAG_FIRST))
+ return (-1);
+ len = be16dec(hdr->ih_length);
+ isns_req_getspace(req, len);
+ res = read(s, &req->ir_buf[req->ir_usedlen], len);
+ if (res < len)
+ return (-1);
+ req->ir_usedlen += len;
+ return (0);
+}
+
+uint32_t
+isns_req_get_status(struct isns_req *req)
+{
+
+ if (req->ir_usedlen < sizeof(struct isns_hdr) + 4)
+ return (-1);
+ return (be32dec(&req->ir_buf[sizeof(struct isns_hdr)]));
+}
diff --git a/usr.sbin/ctld/isns.h b/usr.sbin/ctld/isns.h
new file mode 100644
index 0000000..00e6b50
--- /dev/null
+++ b/usr.sbin/ctld/isns.h
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2014 Alexander Motin <mav@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$
+ */
+
+#ifndef _ISNS_H
+#define _ISNS_H
+
+#define ISNS_VERSION 0x0001
+
+#define ISNS_FUNC_DEVATTRREG 0x0001
+#define ISNS_FUNC_DEVATTRQRY 0x0002
+#define ISNS_FUNC_DEVGETNEXT 0x0003
+#define ISNS_FUNC_DEVDEREG 0x0004
+#define ISNS_FUNC_SCNREG 0x0005
+#define ISNS_FUNC_SCNDEREG 0x0006
+#define ISNS_FUNC_SCNEVENT 0x0007
+#define ISNS_FUNC_SCN 0x0008
+#define ISNS_FUNC_DDREG 0x0009
+#define ISNS_FUNC_DDDEREG 0x000a
+#define ISNS_FUNC_DDSREG 0x000b
+#define ISNS_FUNC_DDSDEREG 0x000c
+#define ISNS_FUNC_ESI 0x000d
+#define ISNS_FUNC_HEARTBEAT 0x000e
+#define ISNS_FUNC_RESPONSE 0x8000
+
+#define ISNS_FLAG_CLIENT 0x8000
+#define ISNS_FLAG_SERVER 0x4000
+#define ISNS_FLAG_AUTH 0x2000
+#define ISNS_FLAG_REPLACE 0x1000
+#define ISNS_FLAG_LAST 0x0800
+#define ISNS_FLAG_FIRST 0x0400
+
+struct isns_hdr {
+ uint8_t ih_version[2];
+ uint8_t ih_function[2];
+ uint8_t ih_length[2];
+ uint8_t ih_flags[2];
+ uint8_t ih_transaction[2];
+ uint8_t ih_sequence[2];
+};
+
+struct isns_tlv {
+ uint8_t it_tag[4];
+ uint8_t it_length[4];
+ uint8_t it_value[];
+};
+
+struct isns_req {
+ u_int ir_buflen;
+ u_int ir_usedlen;
+ uint8_t *ir_buf;
+};
+
+struct isns_req * isns_req_alloc(void);
+struct isns_req * isns_req_create(uint16_t func, uint16_t flags);
+void isns_req_free(struct isns_req *req);
+void isns_req_add(struct isns_req *req, uint32_t tag, uint32_t len,
+ const void *value);
+void isns_req_add_delim(struct isns_req *req);
+void isns_req_add_str(struct isns_req *req, uint32_t tag, const char *value);
+void isns_req_add_32(struct isns_req *req, uint32_t tag, uint32_t value);
+void isns_req_add_addr(struct isns_req *req, uint32_t tag, struct addrinfo *ai);
+void isns_req_add_port(struct isns_req *req, uint32_t tag, struct addrinfo *ai);
+int isns_req_send(int s, struct isns_req *req);
+int isns_req_receive(int s, struct isns_req *req);
+uint32_t isns_req_get_status(struct isns_req *req);
+
+#endif /* _ISNS_H */
diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c
index 3996e21..219313f 100644
--- a/usr.sbin/ctld/kernel.c
+++ b/usr.sbin/ctld/kernel.c
@@ -32,9 +32,11 @@
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -103,7 +105,7 @@ struct cctl_lun_nv {
};
/*
- * Backend LUN information.
+ * Backend LUN information.
*/
struct cctl_lun {
uint64_t lun_id;
@@ -235,7 +237,7 @@ cctl_end_element(void *user_data, const char *name)
} else if (strcmp(name, "lun") == 0) {
devlist->cur_lun = NULL;
} else if (strcmp(name, "ctllunlist") == 0) {
-
+ /* Nothing. */
} else {
struct cctl_lun_nv *nv;
@@ -340,7 +342,7 @@ cctl_end_pelement(void *user_data, const char *name)
} else if (strcmp(name, "targ_port") == 0) {
devlist->cur_port = NULL;
} else if (strcmp(name, "ctlportlist") == 0) {
-
+ /* Nothing. */
} else {
struct cctl_lun_nv *nv;
@@ -698,20 +700,22 @@ kernel_lun_add(struct lun *lun)
return (1);
}
- if (req.status == CTL_LUN_ERROR) {
- log_warnx("error returned from LUN creation request: %s",
- req.error_str);
+ switch (req.status) {
+ case CTL_LUN_ERROR:
+ log_warnx("LUN creation error: %s", req.error_str);
return (1);
- }
-
- if (req.status != CTL_LUN_OK) {
- log_warnx("unknown LUN creation request status %d",
+ case CTL_LUN_WARNING:
+ log_warnx("LUN creation warning: %s", req.error_str);
+ break;
+ case CTL_LUN_OK:
+ break;
+ default:
+ log_warnx("unknown LUN creation status: %d",
req.status);
return (1);
}
lun_set_ctl_lun(lun, req.reqdata.create.req_lun_id);
-
return (0);
}
@@ -733,14 +737,17 @@ kernel_lun_resize(struct lun *lun)
return (1);
}
- if (req.status == CTL_LUN_ERROR) {
- log_warnx("error returned from LUN modification request: %s",
- req.error_str);
+ switch (req.status) {
+ case CTL_LUN_ERROR:
+ log_warnx("LUN modification error: %s", req.error_str);
return (1);
- }
-
- if (req.status != CTL_LUN_OK) {
- log_warnx("unknown LUN modification request status %d",
+ case CTL_LUN_WARNING:
+ log_warnx("LUN modification warning: %s", req.error_str);
+ break;
+ case CTL_LUN_OK:
+ break;
+ default:
+ log_warnx("unknown LUN modification status: %d",
req.status);
return (1);
}
@@ -765,14 +772,17 @@ kernel_lun_remove(struct lun *lun)
return (1);
}
- if (req.status == CTL_LUN_ERROR) {
- log_warnx("error returned from LUN removal request: %s",
- req.error_str);
+ switch (req.status) {
+ case CTL_LUN_ERROR:
+ log_warnx("LUN removal error: %s", req.error_str);
return (1);
- }
-
- if (req.status != CTL_LUN_OK) {
- log_warnx("unknown LUN removal request status %d", req.status);
+ case CTL_LUN_WARNING:
+ log_warnx("LUN removal warning: %s", req.error_str);
+ break;
+ case CTL_LUN_OK:
+ break;
+ default:
+ log_warnx("unknown LUN removal status: %d", req.status);
return (1);
}
diff --git a/usr.sbin/ctld/keys.c b/usr.sbin/ctld/keys.c
index 1474bd3..6a9ad02 100644
--- a/usr.sbin/ctld/keys.c
+++ b/usr.sbin/ctld/keys.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
@@ -114,7 +116,7 @@ keys_save(struct keys *keys, struct pdu *pdu)
for (i = 0; i < KEYS_MAX; i++) {
if (keys->keys_names[i] == NULL)
break;
- /*
+ /*
* +1 for '=', +1 for '\0'.
*/
len += strlen(keys->keys_names[i]) +
diff --git a/usr.sbin/ctld/log.c b/usr.sbin/ctld/log.c
index 7b8ba71..ac838f3 100644
--- a/usr.sbin/ctld/log.c
+++ b/usr.sbin/ctld/log.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
diff --git a/usr.sbin/ctld/login.c b/usr.sbin/ctld/login.c
index 20ed464..fc41f51 100644
--- a/usr.sbin/ctld/login.c
+++ b/usr.sbin/ctld/login.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
@@ -37,9 +39,6 @@
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
-#include <openssl/err.h>
-#include <openssl/md5.h>
-#include <openssl/rand.h>
#include "ctld.h"
#include "iscsi_proto.h"
@@ -227,150 +226,6 @@ login_list_prefers(const char *list,
return (-1);
}
-static int
-login_hex2int(const char hex)
-{
- switch (hex) {
- case '0':
- return (0x00);
- case '1':
- return (0x01);
- case '2':
- return (0x02);
- case '3':
- return (0x03);
- case '4':
- return (0x04);
- case '5':
- return (0x05);
- case '6':
- return (0x06);
- case '7':
- return (0x07);
- case '8':
- return (0x08);
- case '9':
- return (0x09);
- case 'a':
- case 'A':
- return (0x0a);
- case 'b':
- case 'B':
- return (0x0b);
- case 'c':
- case 'C':
- return (0x0c);
- case 'd':
- case 'D':
- return (0x0d);
- case 'e':
- case 'E':
- return (0x0e);
- case 'f':
- case 'F':
- return (0x0f);
- default:
- return (-1);
- }
-}
-
-/*
- * XXX: Review this _carefully_.
- */
-static int
-login_hex2bin(const char *hex, char **binp, size_t *bin_lenp)
-{
- int i, hex_len, nibble;
- bool lo = true; /* As opposed to 'hi'. */
- char *bin;
- size_t bin_off, bin_len;
-
- if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
- log_warnx("malformed variable, should start with \"0x\"");
- return (-1);
- }
-
- hex += strlen("0x");
- hex_len = strlen(hex);
- if (hex_len < 1) {
- log_warnx("malformed variable; doesn't contain anything "
- "but \"0x\"");
- return (-1);
- }
-
- bin_len = hex_len / 2 + hex_len % 2;
- bin = calloc(bin_len, 1);
- if (bin == NULL)
- log_err(1, "calloc");
-
- bin_off = bin_len - 1;
- for (i = hex_len - 1; i >= 0; i--) {
- nibble = login_hex2int(hex[i]);
- if (nibble < 0) {
- log_warnx("malformed variable, invalid char \"%c\"",
- hex[i]);
- return (-1);
- }
-
- assert(bin_off < bin_len);
- if (lo) {
- bin[bin_off] = nibble;
- lo = false;
- } else {
- bin[bin_off] |= nibble << 4;
- bin_off--;
- lo = true;
- }
- }
-
- *binp = bin;
- *bin_lenp = bin_len;
- return (0);
-}
-
-static char *
-login_bin2hex(const char *bin, size_t bin_len)
-{
- unsigned char *hex, *tmp, ch;
- size_t hex_len;
- size_t i;
-
- hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
- hex = malloc(hex_len);
- if (hex == NULL)
- log_err(1, "malloc");
-
- tmp = hex;
- tmp += sprintf(tmp, "0x");
- for (i = 0; i < bin_len; i++) {
- ch = bin[i];
- tmp += sprintf(tmp, "%02x", ch);
- }
-
- return (hex);
-}
-
-static void
-login_compute_md5(const char id, const char *secret,
- const void *challenge, size_t challenge_len, void *response,
- size_t response_len)
-{
- MD5_CTX ctx;
- int rv;
-
- assert(response_len == MD5_DIGEST_LENGTH);
-
- MD5_Init(&ctx);
- MD5_Update(&ctx, &id, sizeof(id));
- MD5_Update(&ctx, secret, strlen(secret));
- MD5_Update(&ctx, challenge, challenge_len);
- rv = MD5_Final(response, &ctx);
- if (rv != 1)
- log_errx(1, "MD5_Final");
-}
-
-#define LOGIN_CHALLENGE_LEN 1024
-
static struct pdu *
login_receive_chap_a(struct connection *conn)
{
@@ -398,21 +253,21 @@ login_receive_chap_a(struct connection *conn)
}
static void
-login_send_chap_c(struct pdu *request, const unsigned char id,
- const void *challenge, const size_t challenge_len)
+login_send_chap_c(struct pdu *request, struct chap *chap)
{
struct pdu *response;
struct keys *response_keys;
- char *chap_c, chap_i[4];
+ char *chap_c, *chap_i;
- chap_c = login_bin2hex(challenge, challenge_len);
- snprintf(chap_i, sizeof(chap_i), "%d", id);
+ chap_c = chap_get_challenge(chap);
+ chap_i = chap_get_id(chap);
response = login_new_response(request);
response_keys = keys_new();
keys_add(response_keys, "CHAP_A", "5");
keys_add(response_keys, "CHAP_I", chap_i);
keys_add(response_keys, "CHAP_C", chap_c);
+ free(chap_i);
free(chap_c);
keys_save(response_keys, response);
pdu_send(response);
@@ -421,15 +276,12 @@ login_send_chap_c(struct pdu *request, const unsigned char id,
}
static struct pdu *
-login_receive_chap_r(struct connection *conn,
- struct auth_group *ag, const unsigned char id, const void *challenge,
- const size_t challenge_len, const struct auth **cap)
+login_receive_chap_r(struct connection *conn, struct auth_group *ag,
+ struct chap *chap, const struct auth **authp)
{
struct pdu *request;
struct keys *request_keys;
const char *chap_n, *chap_r;
- char *response_bin, expected_response_bin[MD5_DIGEST_LENGTH];
- size_t response_bin_len;
const struct auth *auth;
int error;
@@ -447,7 +299,7 @@ login_receive_chap_r(struct connection *conn,
login_send_error(request, 0x02, 0x07);
log_errx(1, "received CHAP Login PDU without CHAP_R");
}
- error = login_hex2bin(chap_r, &response_bin, &response_bin_len);
+ error = chap_receive(chap, chap_r);
if (error != 0) {
login_send_error(request, 0x02, 0x07);
log_errx(1, "received CHAP Login PDU with malformed CHAP_R");
@@ -467,21 +319,17 @@ login_receive_chap_r(struct connection *conn,
assert(auth->a_secret != NULL);
assert(strlen(auth->a_secret) > 0);
- login_compute_md5(id, auth->a_secret, challenge,
- challenge_len, expected_response_bin,
- sizeof(expected_response_bin));
- if (memcmp(response_bin, expected_response_bin,
- sizeof(expected_response_bin)) != 0) {
+ error = chap_authenticate(chap, auth->a_secret);
+ if (error != 0) {
login_send_error(request, 0x02, 0x01);
log_errx(1, "CHAP authentication failed for user \"%s\"",
auth->a_user);
}
keys_delete(request_keys);
- free(response_bin);
- *cap = auth;
+ *authp = auth;
return (request);
}
@@ -492,10 +340,9 @@ login_send_chap_success(struct pdu *request,
struct pdu *response;
struct keys *request_keys, *response_keys;
struct iscsi_bhs_login_response *bhslr2;
+ struct rchap *rchap;
const char *chap_i, *chap_c;
- char *chap_r, *challenge, response_bin[MD5_DIGEST_LENGTH];
- size_t challenge_len;
- unsigned char id;
+ char *chap_r;
int error;
response = login_new_response(request);
@@ -528,21 +375,18 @@ login_send_chap_success(struct pdu *request,
"is not set", auth->a_user);
}
- id = strtoul(chap_i, NULL, 10);
- error = login_hex2bin(chap_c, &challenge, &challenge_len);
+ log_debugx("performing mutual authentication as user \"%s\"",
+ auth->a_mutual_user);
+
+ rchap = rchap_new(auth->a_mutual_secret);
+ error = rchap_receive(rchap, chap_i, chap_c);
if (error != 0) {
login_send_error(request, 0x02, 0x07);
log_errx(1, "received CHAP Login PDU with malformed "
- "CHAP_C");
+ "CHAP_I or CHAP_C");
}
-
- log_debugx("performing mutual authentication as user \"%s\"",
- auth->a_mutual_user);
- login_compute_md5(id, auth->a_mutual_secret, challenge,
- challenge_len, response_bin, sizeof(response_bin));
-
- chap_r = login_bin2hex(response_bin,
- sizeof(response_bin));
+ chap_r = rchap_get_response(rchap);
+ rchap_delete(rchap);
response_keys = keys_new();
keys_add(response_keys, "CHAP_N", auth->a_mutual_user);
keys_add(response_keys, "CHAP_R", chap_r);
@@ -562,10 +406,8 @@ static void
login_chap(struct connection *conn, struct auth_group *ag)
{
const struct auth *auth;
+ struct chap *chap;
struct pdu *request;
- char challenge_bin[LOGIN_CHALLENGE_LEN];
- unsigned char id;
- int rv;
/*
* Receive CHAP_A PDU.
@@ -576,34 +418,21 @@ login_chap(struct connection *conn, struct auth_group *ag)
/*
* Generate the challenge.
*/
- rv = RAND_bytes(challenge_bin, sizeof(challenge_bin));
- if (rv != 1) {
- login_send_error(request, 0x03, 0x02);
- log_errx(1, "RAND_bytes failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- }
- rv = RAND_bytes(&id, sizeof(id));
- if (rv != 1) {
- login_send_error(request, 0x03, 0x02);
- log_errx(1, "RAND_bytes failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- }
+ chap = chap_new();
/*
* Send the challenge.
*/
log_debugx("sending CHAP_C, binary challenge size is %zd bytes",
- sizeof(challenge_bin));
- login_send_chap_c(request, id, challenge_bin,
- sizeof(challenge_bin));
+ sizeof(chap->chap_challenge));
+ login_send_chap_c(request, chap);
pdu_delete(request);
/*
* Receive CHAP_N/CHAP_R PDU and authenticate.
*/
log_debugx("waiting for CHAP_N/CHAP_R");
- request = login_receive_chap_r(conn, ag, id, challenge_bin,
- sizeof(challenge_bin), &auth);
+ request = login_receive_chap_r(conn, ag, chap, &auth);
/*
* Yay, authentication succeeded!
@@ -612,6 +441,12 @@ login_chap(struct connection *conn, struct auth_group *ag)
"transitioning to Negotiation Phase", auth->a_user);
login_send_chap_success(request, auth);
pdu_delete(request);
+
+ /*
+ * Leave username and CHAP information for discovery().
+ */
+ conn->conn_user = auth->a_user;
+ conn->conn_chap = chap;
}
static void
@@ -718,8 +553,8 @@ login_negotiate_key(struct pdu *request, const char *name,
"MaxRecvDataSegmentLength");
}
if (tmp > MAX_DATA_SEGMENT_LENGTH) {
- log_debugx("capping MaxDataSegmentLength from %d to %d",
- tmp, MAX_DATA_SEGMENT_LENGTH);
+ log_debugx("capping MaxRecvDataSegmentLength "
+ "from %d to %d", tmp, MAX_DATA_SEGMENT_LENGTH);
tmp = MAX_DATA_SEGMENT_LENGTH;
}
conn->conn_max_data_segment_length = tmp;
@@ -778,13 +613,72 @@ login_negotiate_key(struct pdu *request, const char *name,
}
static void
+login_redirect(struct pdu *request, const char *target_address)
+{
+ struct pdu *response;
+ struct iscsi_bhs_login_response *bhslr2;
+ struct keys *response_keys;
+
+ response = login_new_response(request);
+ login_set_csg(response, login_csg(request));
+ bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
+ bhslr2->bhslr_status_class = 0x01;
+ bhslr2->bhslr_status_detail = 0x01;
+
+ response_keys = keys_new();
+ keys_add(response_keys, "TargetAddress", target_address);
+
+ keys_save(response_keys, response);
+ pdu_send(response);
+ pdu_delete(response);
+ keys_delete(response_keys);
+}
+
+static bool
+login_portal_redirect(struct connection *conn, struct pdu *request)
+{
+ const struct portal_group *pg;
+
+ pg = conn->conn_portal->p_portal_group;
+ if (pg->pg_redirection == NULL)
+ return (false);
+
+ log_debugx("portal-group \"%s\" configured to redirect to %s",
+ pg->pg_name, pg->pg_redirection);
+ login_redirect(request, pg->pg_redirection);
+
+ return (true);
+}
+
+static bool
+login_target_redirect(struct connection *conn, struct pdu *request)
+{
+ const char *target_address;
+
+ assert(conn->conn_portal->p_portal_group->pg_redirection == NULL);
+
+ if (conn->conn_target == NULL)
+ return (false);
+
+ target_address = conn->conn_target->t_redirection;
+ if (target_address == NULL)
+ return (false);
+
+ log_debugx("target \"%s\" configured to redirect to %s",
+ conn->conn_target->t_name, target_address);
+ login_redirect(request, target_address);
+
+ return (true);
+}
+
+static void
login_negotiate(struct connection *conn, struct pdu *request)
{
struct pdu *response;
struct iscsi_bhs_login_response *bhslr2;
struct keys *request_keys, *response_keys;
int i;
- bool skipped_security;
+ bool redirected, skipped_security;
if (request == NULL) {
log_debugx("beginning operational parameter negotiation; "
@@ -794,6 +688,18 @@ login_negotiate(struct connection *conn, struct pdu *request)
} else
skipped_security = true;
+ /*
+ * RFC 3720, 10.13.5. Status-Class and Status-Detail, says
+ * the redirection SHOULD be accepted by the initiator before
+ * authentication, but MUST be be accepted afterwards; that's
+ * why we're doing it here and not earlier.
+ */
+ redirected = login_target_redirect(conn, request);
+ if (redirected) {
+ log_debugx("initiator redirected; exiting");
+ exit(0);
+ }
+
request_keys = keys_new();
keys_load(request_keys, request);
@@ -804,6 +710,16 @@ login_negotiate(struct connection *conn, struct pdu *request)
login_set_csg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
login_set_nsg(response, BHSLR_STAGE_FULL_FEATURE_PHASE);
response_keys = keys_new();
+
+ if (skipped_security &&
+ conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
+ if (conn->conn_target->t_alias != NULL)
+ keys_add(response_keys,
+ "TargetAlias", conn->conn_target->t_alias);
+ keys_add_int(response_keys, "TargetPortalGroupTag",
+ conn->conn_portal->p_portal_group->pg_tag);
+ }
+
for (i = 0; i < KEYS_MAX; i++) {
if (request_keys->keys_names[i] == NULL)
break;
@@ -832,10 +748,10 @@ login(struct connection *conn)
struct iscsi_bhs_login_response *bhslr2;
struct keys *request_keys, *response_keys;
struct auth_group *ag;
+ struct portal_group *pg;
const char *initiator_name, *initiator_alias, *session_type,
*target_name, *auth_method;
- char *portal_group_tag;
- int rv;
+ bool redirected;
/*
* Handle the initial Login Request - figure out required authentication
@@ -850,6 +766,8 @@ login(struct connection *conn)
log_errx(1, "received Login PDU with non-zero TSIH");
}
+ pg = conn->conn_portal->p_portal_group;
+
memcpy(conn->conn_initiator_isid, bhslr->bhslr_isid,
sizeof(conn->conn_initiator_isid));
@@ -876,6 +794,12 @@ login(struct connection *conn)
*/
setproctitle("%s (%s)", conn->conn_initiator_addr, conn->conn_initiator_name);
+ redirected = login_portal_redirect(conn, request);
+ if (redirected) {
+ log_debugx("initiator redirected; exiting");
+ exit(0);
+ }
+
initiator_alias = keys_find(request_keys, "InitiatorAlias");
if (initiator_alias != NULL)
conn->conn_initiator_alias = checked_strdup(initiator_alias);
@@ -903,9 +827,7 @@ login(struct connection *conn)
log_errx(1, "received Login PDU without TargetName");
}
- conn->conn_target =
- target_find(conn->conn_portal->p_portal_group->pg_conf,
- target_name);
+ conn->conn_target = target_find(pg->pg_conf, target_name);
if (conn->conn_target == NULL) {
login_send_error(request, 0x02, 0x03);
log_errx(1, "requested target \"%s\" not found",
@@ -922,14 +844,14 @@ login(struct connection *conn)
log_debugx("initiator requests to connect "
"to target \"%s\"; auth-group \"%s\"",
conn->conn_target->t_name,
- conn->conn_target->t_auth_group->ag_name);
+ ag->ag_name);
} else {
log_debugx("initiator requests to connect "
"to target \"%s\"", conn->conn_target->t_name);
}
} else {
assert(conn->conn_session_type == CONN_SESSION_TYPE_DISCOVERY);
- ag = conn->conn_portal->p_portal_group->pg_discovery_auth_group;
+ ag = pg->pg_discovery_auth_group;
if (ag->ag_name != NULL) {
log_debugx("initiator requests "
"discovery session; auth-group \"%s\"", ag->ag_name);
@@ -941,28 +863,15 @@ login(struct connection *conn)
/*
* Enforce initiator-name and initiator-portal.
*/
- if (auth_name_defined(ag)) {
- if (auth_name_find(ag, initiator_name) == NULL) {
- login_send_error(request, 0x02, 0x02);
- log_errx(1, "initiator does not match allowed "
- "initiator names");
- }
- log_debugx("initiator matches allowed initiator names");
- } else {
- log_debugx("auth-group does not define initiator name "
- "restrictions");
+ if (auth_name_check(ag, initiator_name) != 0) {
+ login_send_error(request, 0x02, 0x02);
+ log_errx(1, "initiator does not match allowed initiator names");
}
- if (auth_portal_defined(ag)) {
- if (auth_portal_find(ag, &conn->conn_initiator_sa) == NULL) {
- login_send_error(request, 0x02, 0x02);
- log_errx(1, "initiator does not match allowed "
- "initiator portals");
- }
- log_debugx("initiator matches allowed initiator portals");
- } else {
- log_debugx("auth-group does not define initiator portal "
- "restrictions");
+ if (auth_portal_check(ag, &conn->conn_initiator_sa) != 0) {
+ login_send_error(request, 0x02, 0x02);
+ log_errx(1, "initiator does not match allowed "
+ "initiator portals");
}
/*
@@ -999,8 +908,7 @@ login(struct connection *conn)
response = login_new_response(request);
bhslr2 = (struct iscsi_bhs_login_response *)response->pdu_bhs;
bhslr2->bhslr_flags |= BHSLR_FLAGS_TRANSIT;
- login_set_nsg(response,
- BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
+ login_set_nsg(response, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
response_keys = keys_new();
/*
* Required by Linux initiator.
@@ -1014,13 +922,8 @@ login(struct connection *conn)
if (conn->conn_target->t_alias != NULL)
keys_add(response_keys,
"TargetAlias", conn->conn_target->t_alias);
- rv = asprintf(&portal_group_tag, "%d",
- conn->conn_portal->p_portal_group->pg_tag);
- if (rv <= 0)
- log_err(1, "asprintf");
- keys_add(response_keys,
- "TargetPortalGroupTag", portal_group_tag);
- free(portal_group_tag);
+ keys_add_int(response_keys,
+ "TargetPortalGroupTag", pg->pg_tag);
}
keys_save(response_keys, response);
pdu_send(response);
@@ -1067,16 +970,11 @@ login(struct connection *conn)
response_keys = keys_new();
keys_add(response_keys, "AuthMethod", "CHAP");
if (conn->conn_session_type == CONN_SESSION_TYPE_NORMAL) {
- rv = asprintf(&portal_group_tag, "%d",
- conn->conn_portal->p_portal_group->pg_tag);
- if (rv <= 0)
- log_err(1, "asprintf");
- keys_add(response_keys,
- "TargetPortalGroupTag", portal_group_tag);
- free(portal_group_tag);
if (conn->conn_target->t_alias != NULL)
keys_add(response_keys,
"TargetAlias", conn->conn_target->t_alias);
+ keys_add_int(response_keys,
+ "TargetPortalGroupTag", pg->pg_tag);
}
keys_save(response_keys, response);
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index 645201b..a6519dd 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -58,17 +58,17 @@ extern void yyrestart(FILE *);
%}
%token ALIAS AUTH_GROUP AUTH_TYPE BACKEND BLOCKSIZE CHAP CHAP_MUTUAL
-%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP INITIATOR_NAME
-%token INITIATOR_PORTAL LISTEN LISTEN_ISER LUN MAXPROC NUM OPENING_BRACKET
-%token OPTION PATH PIDFILE PORTAL_GROUP SERIAL SIZE STR TARGET TIMEOUT
+%token CLOSING_BRACKET DEBUG DEVICE_ID DISCOVERY_AUTH_GROUP DISCOVERY_FILTER
+%token INITIATOR_NAME INITIATOR_PORTAL ISNS_SERVER ISNS_PERIOD ISNS_TIMEOUT
+%token LISTEN LISTEN_ISER LUN MAXPROC OPENING_BRACKET OPTION
+%token PATH PIDFILE PORTAL_GROUP REDIRECT SEMICOLON SERIAL SIZE STR
+%token TARGET TIMEOUT
%union
{
- uint64_t num;
char *str;
}
-%token <num> NUM
%token <str> STR
%%
@@ -76,6 +76,8 @@ extern void yyrestart(FILE *);
statements:
|
statements statement
+ |
+ statements statement SEMICOLON
;
statement:
@@ -87,6 +89,12 @@ statement:
|
pidfile
|
+ isns_server
+ |
+ isns_period
+ |
+ isns_timeout
+ |
auth_group
|
portal_group
@@ -94,21 +102,45 @@ statement:
target
;
-debug: DEBUG NUM
+debug: DEBUG STR
{
- conf->conf_debug = $2;
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
+ conf->conf_debug = tmp;
}
;
-timeout: TIMEOUT NUM
+timeout: TIMEOUT STR
{
- conf->conf_timeout = $2;
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
+ conf->conf_timeout = tmp;
}
;
-maxproc: MAXPROC NUM
+maxproc: MAXPROC STR
{
- conf->conf_maxproc = $2;
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
+ conf->conf_maxproc = tmp;
}
;
@@ -123,6 +155,45 @@ pidfile: PIDFILE STR
}
;
+isns_server: ISNS_SERVER STR
+ {
+ int error;
+
+ error = isns_new(conf, $2);
+ free($2);
+ if (error != 0)
+ return (1);
+ }
+ ;
+
+isns_period: ISNS_PERIOD STR
+ {
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
+ conf->conf_isns_period = tmp;
+ }
+ ;
+
+isns_timeout: ISNS_TIMEOUT STR
+ {
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
+ conf->conf_isns_timeout = tmp;
+ }
+ ;
+
auth_group: AUTH_GROUP auth_group_name
OPENING_BRACKET auth_group_entries CLOSING_BRACKET
{
@@ -152,6 +223,8 @@ auth_group_name: STR
auth_group_entries:
|
auth_group_entries auth_group_entry
+ |
+ auth_group_entries auth_group_entry SEMICOLON
;
auth_group_entry:
@@ -170,7 +243,7 @@ auth_group_auth_type: AUTH_TYPE STR
{
int error;
- error = auth_group_set_type_str(auth_group, $2);
+ error = auth_group_set_type(auth_group, $2);
free($2);
if (error != 0)
return (1);
@@ -254,14 +327,20 @@ portal_group_name: STR
portal_group_entries:
|
portal_group_entries portal_group_entry
+ |
+ portal_group_entries portal_group_entry SEMICOLON
;
portal_group_entry:
portal_group_discovery_auth_group
|
+ portal_group_discovery_filter
+ |
portal_group_listen
|
portal_group_listen_iser
+ |
+ portal_group_redirect
;
portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
@@ -284,6 +363,17 @@ portal_group_discovery_auth_group: DISCOVERY_AUTH_GROUP STR
}
;
+portal_group_discovery_filter: DISCOVERY_FILTER STR
+ {
+ int error;
+
+ error = portal_group_set_filter(portal_group, $2);
+ free($2);
+ if (error != 0)
+ return (1);
+ }
+ ;
+
portal_group_listen: LISTEN STR
{
int error;
@@ -306,6 +396,17 @@ portal_group_listen_iser: LISTEN_ISER STR
}
;
+portal_group_redirect: REDIRECT STR
+ {
+ int error;
+
+ error = portal_group_set_redirection(portal_group, $2);
+ free($2);
+ if (error != 0)
+ return (1);
+ }
+ ;
+
target: TARGET target_name
OPENING_BRACKET target_entries CLOSING_BRACKET
{
@@ -325,6 +426,8 @@ target_name: STR
target_entries:
|
target_entries target_entry
+ |
+ target_entries target_entry SEMICOLON
;
target_entry:
@@ -344,6 +447,8 @@ target_entry:
|
target_portal_group
|
+ target_redirect
+ |
target_lun
;
@@ -399,7 +504,7 @@ target_auth_type: AUTH_TYPE STR
}
target->t_auth_group->ag_target = target;
}
- error = auth_group_set_type_str(target->t_auth_group, $2);
+ error = auth_group_set_type(target->t_auth_group, $2);
free($2);
if (error != 0)
return (1);
@@ -546,6 +651,17 @@ target_portal_group: PORTAL_GROUP STR
}
;
+target_redirect: REDIRECT STR
+ {
+ int error;
+
+ error = target_set_redirection(target, $2);
+ free($2);
+ if (error != 0)
+ return (1);
+ }
+ ;
+
target_lun: LUN lun_number
OPENING_BRACKET lun_entries CLOSING_BRACKET
{
@@ -553,9 +669,17 @@ target_lun: LUN lun_number
}
;
-lun_number: NUM
+lun_number: STR
{
- lun = lun_new(target, $1);
+ uint64_t tmp;
+
+ if (expand_number($1, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($1);
+ return (1);
+ }
+
+ lun = lun_new(target, tmp);
if (lun == NULL)
return (1);
}
@@ -564,6 +688,8 @@ lun_number: NUM
lun_entries:
|
lun_entries lun_entry
+ |
+ lun_entries lun_entry SEMICOLON
;
lun_entry:
@@ -596,15 +722,23 @@ lun_backend: BACKEND STR
}
;
-lun_blocksize: BLOCKSIZE NUM
+lun_blocksize: BLOCKSIZE STR
{
+ uint64_t tmp;
+
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
+ return (1);
+ }
+
if (lun->l_blocksize != 0) {
log_warnx("blocksize for lun %d, target \"%s\" "
"specified more than once",
lun->l_lun, target->t_name);
return (1);
}
- lun_set_blocksize(lun, $2);
+ lun_set_blocksize(lun, tmp);
}
;
@@ -625,7 +759,7 @@ lun_device_id: DEVICE_ID STR
lun_option: OPTION STR STR
{
struct lun_option *clo;
-
+
clo = lun_option_new(lun, $2, $3);
free($2);
free($3);
@@ -659,31 +793,26 @@ lun_serial: SERIAL STR
}
lun_set_serial(lun, $2);
free($2);
- } | SERIAL NUM
+ }
+ ;
+
+lun_size: SIZE STR
{
- char *str = NULL;
+ uint64_t tmp;
- if (lun->l_serial != NULL) {
- log_warnx("serial for lun %d, target \"%s\" "
- "specified more than once",
- lun->l_lun, target->t_name);
+ if (expand_number($2, &tmp) != 0) {
+ yyerror("invalid numeric value");
+ free($2);
return (1);
}
- asprintf(&str, "%ju", $2);
- lun_set_serial(lun, str);
- free(str);
- }
- ;
-lun_size: SIZE NUM
- {
if (lun->l_size != 0) {
log_warnx("size for lun %d, target \"%s\" "
"specified more than once",
lun->l_lun, target->t_name);
return (1);
}
- lun_set_size(lun, $2);
+ lun_set_size(lun, tmp);
}
;
%%
diff --git a/usr.sbin/ctld/pdu.c b/usr.sbin/ctld/pdu.c
index 084423c..c3181ac 100644
--- a/usr.sbin/ctld/pdu.c
+++ b/usr.sbin/ctld/pdu.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
diff --git a/usr.sbin/ctld/token.l b/usr.sbin/ctld/token.l
index a47bf9a..d4bf823 100644
--- a/usr.sbin/ctld/token.l
+++ b/usr.sbin/ctld/token.l
@@ -58,6 +58,7 @@ chap-mutual { return CHAP_MUTUAL; }
debug { return DEBUG; }
device-id { return DEVICE_ID; }
discovery-auth-group { return DISCOVERY_AUTH_GROUP; }
+discovery-filter { return DISCOVERY_FILTER; }
initiator-name { return INITIATOR_NAME; }
initiator-portal { return INITIATOR_PORTAL; }
listen { return LISTEN; }
@@ -67,24 +68,24 @@ maxproc { return MAXPROC; }
option { return OPTION; }
path { return PATH; }
pidfile { return PIDFILE; }
+isns-server { return ISNS_SERVER; }
+isns-period { return ISNS_PERIOD; }
+isns-timeout { return ISNS_TIMEOUT; }
portal-group { return PORTAL_GROUP; }
+redirect { return REDIRECT; }
serial { return SERIAL; }
size { return SIZE; }
target { return TARGET; }
timeout { return TIMEOUT; }
-[0-9]+[kKmMgGtTpPeE]? { if (expand_number(yytext, &yylval.num) == 0)
- return NUM;
- else {
- yylval.str = strdup(yytext); return STR;
- }
- }
\"[^"]+\" { yylval.str = strndup(yytext + 1,
strlen(yytext) - 2); return STR; }
[a-zA-Z0-9\.\-_/\:\[\]]+ { yylval.str = strdup(yytext); return STR; }
\{ { return OPENING_BRACKET; }
\} { return CLOSING_BRACKET; }
#.*$ /* ignore comments */;
+\r\n { lineno++; }
\n { lineno++; }
+; { return SEMICOLON; }
[ \t]+ /* ignore whitespace */;
. { yylval.str = strdup(yytext); return STR; }
%%
diff --git a/usr.sbin/editmap/Makefile b/usr.sbin/editmap/Makefile
index 8b4562c..92d8392 100644
--- a/usr.sbin/editmap/Makefile
+++ b/usr.sbin/editmap/Makefile
@@ -33,8 +33,6 @@ DPADD+=${SENDMAIL_DPADD}
LDADD+=${SENDMAIL_LDADD}
LDFLAGS+=${SENDMAIL_LDFLAGS}
-NO_PIE= yes
-
sm_os.h:
ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
diff --git a/usr.sbin/etcupdate/etcupdate.8 b/usr.sbin/etcupdate/etcupdate.8
index 1e722f9..1966179 100644
--- a/usr.sbin/etcupdate/etcupdate.8
+++ b/usr.sbin/etcupdate/etcupdate.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 9, 2013
+.Dd October 29, 2014
.Dt ETCUPDATE 8
.Os
.Sh NAME
@@ -608,12 +608,11 @@ Default log file.
.Sh EXIT STATUS
.Ex -std
.Sh EXAMPLES
-If the source tree matches the currently installed world,
-then the following can be used to bootstrap
-.Nm
-so that it can be used for future upgrades:
+To compare the files in
+.Pa /etc
+with the stock versions:
.Pp
-.Dl "etcupdate extract"
+.Dl "etcupdate diff"
.Pp
To merge changes after an upgrade via the buildworld and installworld process:
.Pp
@@ -622,6 +621,59 @@ To merge changes after an upgrade via the buildworld and installworld process:
To resolve any conflicts generated during a merge:
.Pp
.Dl "etcupdate resolve"
+.Ss Bootstrapping
+The
+.Nm
+utility may need to be bootstrapped before it can be used.
+The
+.Cm diff
+command will fail with an error about a missing reference tree if
+bootstrapping is needed.
+.Pp
+Bootstrapping
+.Nm
+requires a source tree that matches the currently installed world.
+The easiest way to ensure this is to bootstrap
+.Nm
+before updating the source tree to start the next world upgrade cycle.
+First,
+generate a reference tree:
+.Pp
+.Dl "etcupdate extract"
+.Pp
+Second,
+use the
+.Cm diff
+command to compare the reference tree to your current files in
+.Pa /etc .
+Undesired differences should be removed using an editor,
+.Xr patch 1 ,
+or by copying files from the reference tree
+.Po
+located at
+.Pa /var/db/etcupdate/current
+by default
+.Pc
+.
+.Pp
+If the tree at
+.Pa /usr/src
+is already newer than the currently installed world,
+a new tree matching the currently installed world can be checked out to
+a temporary location.
+The reference tree for
+.Nm
+can then be generated via:
+.Pp
+.Dl "etcupdate extract -s /path/to/tree"
+.Pp
+The
+.Cm diff
+command can be used as above to remove undesired differences.
+Afterwards,
+the changes in the tree at
+.Pa /usr/src
+can be merged via a regular merge.
.Sh DIAGNOSTICS
The following warning messages may be generated during a merge.
Note that several of these warnings cover obscure cases that should occur
diff --git a/usr.sbin/fdread/fdutil.c b/usr.sbin/fdread/fdutil.c
index c1f4d8f..c66b0c1 100644
--- a/usr.sbin/fdread/fdutil.c
+++ b/usr.sbin/fdread/fdutil.c
@@ -92,6 +92,7 @@ static struct fd_type fd_types_auto[1] =
static struct fd_type fd_types_288m[] = {
+#ifndef PC98
#if 0
{ FDF_3_2880 },
#endif
@@ -102,30 +103,18 @@ static struct fd_type fd_types_288m[] = {
{ FDF_3_820 },
{ FDF_3_800 },
{ FDF_3_720 },
+#endif /* !PC98 */
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
static struct fd_type fd_types_144m[] = {
#ifdef PC98
-#if 0
- { FDF_3_1722 },
- { FDF_3_1476 },
-#endif
{ FDF_3_1440 },
{ FDF_3_1200 },
-#if 0
- { FDF_3_820 },
- { FDF_3_800 },
-#endif
{ FDF_3_720 },
{ FDF_3_360 },
{ FDF_3_640 },
{ FDF_3_1230 },
-#if 0
- { FDF_3_1280 },
- { FDF_3_1480 },
- { FDF_3_1640 },
-#endif
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
#else
{ FDF_3_1722 },
@@ -142,17 +131,10 @@ static struct fd_type fd_types_144m[] = {
static struct fd_type fd_types_12m[] = {
#ifdef PC98
{ FDF_5_1200 },
-#if 0
- { FDF_5_820 },
- { FDF_5_800 },
-#endif
{ FDF_5_720 },
{ FDF_5_360 },
{ FDF_5_640 },
{ FDF_5_1230 },
-#if 0
- { FDF_5_1280 },
-#endif
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
#else
{ FDF_5_1200 },
@@ -170,13 +152,17 @@ static struct fd_type fd_types_12m[] = {
static struct fd_type fd_types_720k[] =
{
+#ifndef PC98
{ FDF_3_720 },
+#endif
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
static struct fd_type fd_types_360k[] =
{
+#ifndef PC98
{ FDF_5_360 },
+#endif
{ 0,0,0,0,0,0,0,0,0,0,0,0 }
};
diff --git a/usr.sbin/fifolog/fifolog_create/Makefile b/usr.sbin/fifolog/fifolog_create/Makefile
index 38a6623..8b59b25 100644
--- a/usr.sbin/fifolog/fifolog_create/Makefile
+++ b/usr.sbin/fifolog/fifolog_create/Makefile
@@ -12,8 +12,6 @@ MLINKS= fifolog.1 fifolog_create.1 \
fifolog.1 fifolog_reader.1 \
fifolog.1 fifolog_writer.1
-NO_PIE= yes
-
regress:
rm -f /tmp/fifolog.?
./${PROG} /tmp/fifolog.0
diff --git a/usr.sbin/fifolog/fifolog_reader/Makefile b/usr.sbin/fifolog/fifolog_reader/Makefile
index dfbb73f..50575a9 100644
--- a/usr.sbin/fifolog/fifolog_reader/Makefile
+++ b/usr.sbin/fifolog/fifolog_reader/Makefile
@@ -6,10 +6,8 @@ CFLAGS+= -I${.CURDIR}/../lib
MAN=
-DPADD= ${LIBFIFOLOG} ${LIBUTIL} ${LIBZ}
-LDADD= ${LIBFIFOLOG} -lutil -lz
-
-NO_PIE= yes
+DPADD= ${LIBFIFOLOG} ${LIBZ}
+LDADD= ${LIBFIFOLOG} -lz
regress:
./${PROG} /tmp/fifolog.0
diff --git a/usr.sbin/fifolog/fifolog_writer/Makefile b/usr.sbin/fifolog/fifolog_writer/Makefile
index 3e6e377..9806ec7 100644
--- a/usr.sbin/fifolog/fifolog_writer/Makefile
+++ b/usr.sbin/fifolog/fifolog_writer/Makefile
@@ -6,10 +6,8 @@ CFLAGS+= -I${.CURDIR}/../lib
MAN=
-DPADD= ${LIBFIFOLOG} ${LIBUTIL} ${LIBZ}
-LDADD= ${LIBFIFOLOG} -lutil -lz
-
-NO_PIE= yes
+DPADD= ${LIBFIFOLOG} ${LIBZ}
+LDADD= ${LIBFIFOLOG} -lz
regress:
date | ./${PROG} -z 0 /tmp/fifolog.0
diff --git a/usr.sbin/freebsd-update/freebsd-update.sh b/usr.sbin/freebsd-update/freebsd-update.sh
index ee702e3..f586909 100644
--- a/usr.sbin/freebsd-update/freebsd-update.sh
+++ b/usr.sbin/freebsd-update/freebsd-update.sh
@@ -580,6 +580,7 @@ fetchupgrade_check_params () {
_KEYPRINT_z="Key must be given via -k option or configuration file."
_KEYPRINT_bad="Invalid key fingerprint: "
_WORKDIR_bad="Directory does not exist or is not writable: "
+ _WORKDIR_bad2="Directory is not on a persistent filesystem: "
if [ -z "${SERVERNAME}" ]; then
echo -n "`basename $0`: "
@@ -603,6 +604,13 @@ fetchupgrade_check_params () {
echo ${WORKDIR}
exit 1
fi
+ case `df -T ${WORKDIR}` in */dev/md[0-9]* | *tmpfs*)
+ echo -n "`basename $0`: "
+ echo -n "${_WORKDIR_bad2}"
+ echo ${WORKDIR}
+ exit 1
+ ;;
+ esac
chmod 700 ${WORKDIR}
cd ${WORKDIR} || exit 1
diff --git a/usr.sbin/ftp-proxy/Makefile b/usr.sbin/ftp-proxy/Makefile
index 67660c8..7a3ef47 100644
--- a/usr.sbin/ftp-proxy/Makefile
+++ b/usr.sbin/ftp-proxy/Makefile
@@ -1,5 +1,17 @@
# $FreeBSD$
-SUBDIR= libevent ftp-proxy
+.PATH: ${.CURDIR}/../../contrib/pf/ftp-proxy
-.include <bsd.subdir.mk>
+PROG= ftp-proxy
+MAN= ftp-proxy.8
+
+SRCS= ftp-proxy.c filter.c
+
+CFLAGS+=-I${.CURDIR}/../../contrib/pf/libevent
+
+LDADD+= ${LIBEVENT}
+DPADD+= ${LIBEVENT}
+
+WARNS?= 3
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ftp-proxy/Makefile.inc b/usr.sbin/ftp-proxy/Makefile.inc
deleted file mode 100644
index 9043d09..0000000
--- a/usr.sbin/ftp-proxy/Makefile.inc
+++ /dev/null
@@ -1,5 +0,0 @@
-# $FreeBSD$
-
-LIBEVENT= ${.OBJDIR}/../libevent/libevent.a
-
-.include "../Makefile.inc"
diff --git a/usr.sbin/gstat/Makefile b/usr.sbin/gstat/Makefile
index 2a6da40..8aceec0 100644
--- a/usr.sbin/gstat/Makefile
+++ b/usr.sbin/gstat/Makefile
@@ -2,7 +2,7 @@
PROG= gstat
MAN= gstat.8
-DPADD= ${LIBDEVSTAT} ${LIBKVM} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} ${LIBEDIT} ${LIBCURSES}
-LDADD= -ldevstat -lkvm -lgeom -lbsdxml -lsbuf -ledit -lcurses
+DPADD= ${LIBDEVSTAT} ${LIBKVM} ${LIBGEOM} ${LIBBSDXML} ${LIBSBUF} ${LIBEDIT} ${LIBNCURSESW}
+LDADD= -ldevstat -lkvm -lgeom -lbsdxml -lsbuf -ledit -lncursesw
.include <bsd.prog.mk>
diff --git a/usr.sbin/hyperv/Makefile b/usr.sbin/hyperv/Makefile
new file mode 100644
index 0000000..c11b341
--- /dev/null
+++ b/usr.sbin/hyperv/Makefile
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+SUBDIR = tools
+
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/hyperv/Makefile.inc b/usr.sbin/hyperv/Makefile.inc
new file mode 100644
index 0000000..265f86d
--- /dev/null
+++ b/usr.sbin/hyperv/Makefile.inc
@@ -0,0 +1,3 @@
+# $FreeBSD$
+
+.include "../Makefile.inc"
diff --git a/usr.sbin/hyperv/tools/Makefile b/usr.sbin/hyperv/tools/Makefile
new file mode 100644
index 0000000..3cfc001
--- /dev/null
+++ b/usr.sbin/hyperv/tools/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+HV_KVP_DAEMON_DISTDIR?= ${.CURDIR}/../../../contrib/hyperv/tools
+.PATH: ${HV_KVP_DAEMON_DISTDIR}
+
+PROG= hv_kvp_daemon
+MAN= hv_kvp_daemon.8
+
+CFLAGS+= -I${.CURDIR}/../../../sys/dev/hyperv/utilities
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/i2c/i2c.c b/usr.sbin/i2c/i2c.c
index 3a61aa5..920dda2 100644
--- a/usr.sbin/i2c/i2c.c
+++ b/usr.sbin/i2c/i2c.c
@@ -142,6 +142,7 @@ scan_bus(struct iiccmd cmd, char *dev, int skip, char *skip_addr)
if (tokens == NULL) {
fprintf(stderr, "Error allocating tokens "
"buffer\n");
+ error = -1;
goto out;
}
index = skip_get_tokens(skip_addr, tokens,
@@ -150,6 +151,7 @@ scan_bus(struct iiccmd cmd, char *dev, int skip, char *skip_addr)
if (!no_range && (addr_range.start > addr_range.end)) {
fprintf(stderr, "Skip address out of range\n");
+ error = -1;
goto out;
}
}
@@ -409,8 +411,10 @@ i2c_read(char *dev, struct options i2c_opt, char *i2c_buf)
if (i2c_opt.mode == I2C_MODE_STOP_START) {
cmd.slave = i2c_opt.addr;
error = ioctl(fd, I2CSTOP, &cmd);
- if (error == -1)
+ if (error == -1) {
+ err_msg = "error sending stop condtion\n";
goto err2;
+ }
}
}
cmd.slave = i2c_opt.addr;
@@ -432,8 +436,10 @@ i2c_read(char *dev, struct options i2c_opt, char *i2c_buf)
}
}
error = ioctl(fd, I2CSTOP, &cmd);
- if (error == -1)
+ if (error == -1) {
+ err_msg = "error sending stop condtion\n";
goto err2;
+ }
for (i = 0; i < i2c_opt.count; i++) {
error = read(fd, &i2c_buf[i], 1);
diff --git a/usr.sbin/inetd/inetd.c b/usr.sbin/inetd/inetd.c
index eebcfea..c48f33c 100644
--- a/usr.sbin/inetd/inetd.c
+++ b/usr.sbin/inetd/inetd.c
@@ -69,7 +69,7 @@ __FBSDID("$FreeBSD$");
* or name a tcpmux service
* or specify a unix domain socket
* socket type stream/dgram/raw/rdm/seqpacket
- * protocol tcp[4][6][/faith], udp[4][6], unix
+ * protocol tcp[4][6], udp[4][6], unix
* wait/nowait single-threaded/multi-threaded
* user[:group][/login-class] user/group/login-class to run daemon as
* server program full path name
@@ -1305,14 +1305,6 @@ setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
syslog(LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
}
#undef turnon
-#ifdef IPV6_FAITH
- if (sep->se_type == FAITH_TYPE) {
- if (setsockopt(sep->se_fd, IPPROTO_IPV6, IPV6_FAITH, &on,
- sizeof(on)) < 0) {
- syslog(LOG_ERR, "setsockopt (IPV6_FAITH): %m");
- }
- }
-#endif
#ifdef IPSEC
ipsecsetup(sep);
#endif
@@ -1744,15 +1736,15 @@ more:
arg = sskip(&cp);
if (strncmp(arg, "tcp", 3) == 0) {
sep->se_proto = newstr(strsep(&arg, "/"));
- if (arg != NULL) {
- if (strcmp(arg, "faith") == 0)
- sep->se_type = FAITH_TYPE;
+ if (arg != NULL && (strcmp(arg, "faith") == 0)) {
+ syslog(LOG_ERR, "faith has been deprecated");
+ goto more;
}
} else {
if (sep->se_type == NORM_TYPE &&
strncmp(arg, "faith/", 6) == 0) {
- arg += 6;
- sep->se_type = FAITH_TYPE;
+ syslog(LOG_ERR, "faith has been deprecated");
+ goto more;
}
sep->se_proto = newstr(arg);
}
diff --git a/usr.sbin/iscsid/Makefile b/usr.sbin/iscsid/Makefile
index 468b284..784c204 100644
--- a/usr.sbin/iscsid/Makefile
+++ b/usr.sbin/iscsid/Makefile
@@ -1,15 +1,15 @@
# $FreeBSD$
PROG= iscsid
-SRCS= discovery.c iscsid.c keys.c log.c login.c pdu.c
+SRCS= chap.c discovery.c iscsid.c keys.c log.c login.c pdu.c
CFLAGS+= -I${.CURDIR}
CFLAGS+= -I${.CURDIR}/../../sys/cam
CFLAGS+= -I${.CURDIR}/../../sys/dev/iscsi
#CFLAGS+= -DICL_KERNEL_PROXY
MAN= iscsid.8
-DPADD= ${LIBUTIL}
-LDADD= -lcrypto -lssl -lutil
+DPADD= ${LIBCRYPTO} ${LIBUTIL}
+LDADD= -lcrypto -lutil
WARNS= 6
diff --git a/usr.sbin/iscsid/chap.c b/usr.sbin/iscsid/chap.c
new file mode 100644
index 0000000..62e39f5
--- /dev/null
+++ b/usr.sbin/iscsid/chap.c
@@ -0,0 +1,435 @@
+/*-
+ * Copyright (c) 2014 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Edward Tomasz Napierala under sponsorship
+ * from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <assert.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <resolv.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#include <openssl/rand.h>
+
+#include "iscsid.h"
+
+static void
+chap_compute_md5(const char id, const char *secret,
+ const void *challenge, size_t challenge_len, void *response,
+ size_t response_len)
+{
+ MD5_CTX ctx;
+ int rv;
+
+ assert(response_len == MD5_DIGEST_LENGTH);
+
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, &id, sizeof(id));
+ MD5_Update(&ctx, secret, strlen(secret));
+ MD5_Update(&ctx, challenge, challenge_len);
+ rv = MD5_Final(response, &ctx);
+ if (rv != 1)
+ log_errx(1, "MD5_Final");
+}
+
+static int
+chap_hex2int(const char hex)
+{
+ switch (hex) {
+ case '0':
+ return (0x00);
+ case '1':
+ return (0x01);
+ case '2':
+ return (0x02);
+ case '3':
+ return (0x03);
+ case '4':
+ return (0x04);
+ case '5':
+ return (0x05);
+ case '6':
+ return (0x06);
+ case '7':
+ return (0x07);
+ case '8':
+ return (0x08);
+ case '9':
+ return (0x09);
+ case 'a':
+ case 'A':
+ return (0x0a);
+ case 'b':
+ case 'B':
+ return (0x0b);
+ case 'c':
+ case 'C':
+ return (0x0c);
+ case 'd':
+ case 'D':
+ return (0x0d);
+ case 'e':
+ case 'E':
+ return (0x0e);
+ case 'f':
+ case 'F':
+ return (0x0f);
+ default:
+ return (-1);
+ }
+}
+
+static int
+chap_b642bin(const char *b64, void **binp, size_t *bin_lenp)
+{
+ char *bin;
+ int b64_len, bin_len;
+
+ b64_len = strlen(b64);
+ bin_len = (b64_len + 3) / 4 * 3;
+ bin = calloc(bin_len, 1);
+ if (bin == NULL)
+ log_err(1, "calloc");
+
+ bin_len = b64_pton(b64, bin, bin_len);
+ if (bin_len < 0) {
+ log_warnx("malformed base64 variable");
+ free(bin);
+ return (-1);
+ }
+ *binp = bin;
+ *bin_lenp = bin_len;
+ return (0);
+}
+
+/*
+ * XXX: Review this _carefully_.
+ */
+static int
+chap_hex2bin(const char *hex, void **binp, size_t *bin_lenp)
+{
+ int i, hex_len, nibble;
+ bool lo = true; /* As opposed to 'hi'. */
+ char *bin;
+ size_t bin_off, bin_len;
+
+ if (strncasecmp(hex, "0b", strlen("0b")) == 0)
+ return (chap_b642bin(hex + 2, binp, bin_lenp));
+
+ if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
+ log_warnx("malformed variable, should start with \"0x\""
+ " or \"0b\"");
+ return (-1);
+ }
+
+ hex += strlen("0x");
+ hex_len = strlen(hex);
+ if (hex_len < 1) {
+ log_warnx("malformed variable; doesn't contain anything "
+ "but \"0x\"");
+ return (-1);
+ }
+
+ bin_len = hex_len / 2 + hex_len % 2;
+ bin = calloc(bin_len, 1);
+ if (bin == NULL)
+ log_err(1, "calloc");
+
+ bin_off = bin_len - 1;
+ for (i = hex_len - 1; i >= 0; i--) {
+ nibble = chap_hex2int(hex[i]);
+ if (nibble < 0) {
+ log_warnx("malformed variable, invalid char \"%c\"",
+ hex[i]);
+ free(bin);
+ return (-1);
+ }
+
+ assert(bin_off < bin_len);
+ if (lo) {
+ bin[bin_off] = nibble;
+ lo = false;
+ } else {
+ bin[bin_off] |= nibble << 4;
+ bin_off--;
+ lo = true;
+ }
+ }
+
+ *binp = bin;
+ *bin_lenp = bin_len;
+ return (0);
+}
+
+#ifdef USE_BASE64
+static char *
+chap_bin2hex(const char *bin, size_t bin_len)
+{
+ unsigned char *b64, *tmp;
+ size_t b64_len;
+
+ b64_len = (bin_len + 2) / 3 * 4 + 3; /* +2 for "0b", +1 for '\0'. */
+ b64 = malloc(b64_len);
+ if (b64 == NULL)
+ log_err(1, "malloc");
+
+ tmp = b64;
+ tmp += sprintf(tmp, "0b");
+ b64_ntop(bin, bin_len, tmp, b64_len - 2);
+
+ return (b64);
+}
+#else
+static char *
+chap_bin2hex(const char *bin, size_t bin_len)
+{
+ unsigned char *hex, *tmp, ch;
+ size_t hex_len;
+ size_t i;
+
+ hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
+ hex = malloc(hex_len);
+ if (hex == NULL)
+ log_err(1, "malloc");
+
+ tmp = hex;
+ tmp += sprintf(tmp, "0x");
+ for (i = 0; i < bin_len; i++) {
+ ch = bin[i];
+ tmp += sprintf(tmp, "%02x", ch);
+ }
+
+ return (hex);
+}
+#endif /* !USE_BASE64 */
+
+struct chap *
+chap_new(void)
+{
+ struct chap *chap;
+ int rv;
+
+ chap = calloc(sizeof(*chap), 1);
+ if (chap == NULL)
+ log_err(1, "calloc");
+
+ /*
+ * Generate the challenge.
+ */
+ rv = RAND_bytes(chap->chap_challenge, sizeof(chap->chap_challenge));
+ if (rv != 1) {
+ log_errx(1, "RAND_bytes failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+ rv = RAND_bytes(&chap->chap_id, sizeof(chap->chap_id));
+ if (rv != 1) {
+ log_errx(1, "RAND_bytes failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ }
+
+ return (chap);
+}
+
+char *
+chap_get_id(const struct chap *chap)
+{
+ char *chap_i;
+ int ret;
+
+ ret = asprintf(&chap_i, "%d", chap->chap_id);
+ if (ret < 0)
+ log_err(1, "asprintf");
+
+ return (chap_i);
+}
+
+char *
+chap_get_challenge(const struct chap *chap)
+{
+ char *chap_c;
+
+ chap_c = chap_bin2hex(chap->chap_challenge,
+ sizeof(chap->chap_challenge));
+
+ return (chap_c);
+}
+
+static int
+chap_receive_bin(struct chap *chap, void *response, size_t response_len)
+{
+
+ if (response_len != sizeof(chap->chap_response)) {
+ log_debugx("got CHAP response with invalid length; "
+ "got %zd, should be %zd",
+ response_len, sizeof(chap->chap_response));
+ return (1);
+ }
+
+ memcpy(chap->chap_response, response, response_len);
+ return (0);
+}
+
+int
+chap_receive(struct chap *chap, const char *response)
+{
+ void *response_bin;
+ size_t response_bin_len;
+ int error;
+
+ error = chap_hex2bin(response, &response_bin, &response_bin_len);
+ if (error != 0) {
+ log_debugx("got incorrectly encoded CHAP response \"%s\"",
+ response);
+ return (1);
+ }
+
+ error = chap_receive_bin(chap, response_bin, response_bin_len);
+ free(response_bin);
+
+ return (error);
+}
+
+int
+chap_authenticate(struct chap *chap, const char *secret)
+{
+ char expected_response[MD5_DIGEST_LENGTH];
+
+ chap_compute_md5(chap->chap_id, secret,
+ chap->chap_challenge, sizeof(chap->chap_challenge),
+ expected_response, sizeof(expected_response));
+
+ if (memcmp(chap->chap_response,
+ expected_response, sizeof(expected_response)) != 0) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+void
+chap_delete(struct chap *chap)
+{
+
+ free(chap);
+}
+
+struct rchap *
+rchap_new(const char *secret)
+{
+ struct rchap *rchap;
+
+ rchap = calloc(sizeof(*rchap), 1);
+ if (rchap == NULL)
+ log_err(1, "calloc");
+
+ rchap->rchap_secret = checked_strdup(secret);
+
+ return (rchap);
+}
+
+static void
+rchap_receive_bin(struct rchap *rchap, const unsigned char id,
+ const void *challenge, size_t challenge_len)
+{
+
+ rchap->rchap_id = id;
+ rchap->rchap_challenge = calloc(challenge_len, 1);
+ if (rchap->rchap_challenge == NULL)
+ log_err(1, "calloc");
+ memcpy(rchap->rchap_challenge, challenge, challenge_len);
+ rchap->rchap_challenge_len = challenge_len;
+}
+
+int
+rchap_receive(struct rchap *rchap, const char *id, const char *challenge)
+{
+ unsigned char id_bin;
+ void *challenge_bin;
+ size_t challenge_bin_len;
+
+ int error;
+
+ id_bin = strtoul(id, NULL, 10);
+
+ error = chap_hex2bin(challenge, &challenge_bin, &challenge_bin_len);
+ if (error != 0) {
+ log_debugx("got incorrectly encoded CHAP challenge \"%s\"",
+ challenge);
+ return (1);
+ }
+
+ rchap_receive_bin(rchap, id_bin, challenge_bin, challenge_bin_len);
+ free(challenge_bin);
+
+ return (0);
+}
+
+static void
+rchap_get_response_bin(struct rchap *rchap,
+ void **responsep, size_t *response_lenp)
+{
+ void *response_bin;
+ size_t response_bin_len = MD5_DIGEST_LENGTH;
+
+ response_bin = calloc(response_bin_len, 1);
+ if (response_bin == NULL)
+ log_err(1, "calloc");
+
+ chap_compute_md5(rchap->rchap_id, rchap->rchap_secret,
+ rchap->rchap_challenge, rchap->rchap_challenge_len,
+ response_bin, response_bin_len);
+
+ *responsep = response_bin;
+ *response_lenp = response_bin_len;
+}
+
+char *
+rchap_get_response(struct rchap *rchap)
+{
+ void *response;
+ size_t response_len;
+ char *chap_r;
+
+ rchap_get_response_bin(rchap, &response, &response_len);
+ chap_r = chap_bin2hex(response, response_len);
+ free(response);
+
+ return (chap_r);
+}
+
+void
+rchap_delete(struct rchap *rchap)
+{
+
+ free(rchap->rchap_secret);
+ free(rchap->rchap_challenge);
+ free(rchap);
+}
diff --git a/usr.sbin/iscsid/discovery.c b/usr.sbin/iscsid/discovery.c
index 9f0db81..c87d9ff 100644
--- a/usr.sbin/iscsid/discovery.c
+++ b/usr.sbin/iscsid/discovery.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <assert.h>
diff --git a/usr.sbin/iscsid/iscsid.8 b/usr.sbin/iscsid/iscsid.8
index fbfc55d..8517718 100644
--- a/usr.sbin/iscsid/iscsid.8
+++ b/usr.sbin/iscsid/iscsid.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 20, 2012
+.Dd September 12, 2014
.Dt ISCSID 8
.Os
.Sh NAME
@@ -49,12 +49,13 @@ as well as performing SendTargets discovery.
Upon startup, the
.Nm
daemon opens the iSCSI initiator device file and waits for kernel requests.
-It doesn't use any configuration file; all the information it needs it gets
-from the kernel.
+.Nm
+does not use any configuration files.
+All needed information is supplied by the kernel.
.Pp
When the
.Nm
-damon is not running, already established iSCSI connections continue
+daemon is not running, already established iSCSI connections continue
to work.
However, establishing new connections, or recovering existing ones in case
of connection error, is not possible.
@@ -99,6 +100,7 @@ The
.Nm
utility exits 0 on success, and >0 if an error occurs.
.Sh SEE ALSO
+.Xr iscsi 4 ,
.Xr iscsictl 8
.Sh HISTORY
The
@@ -108,6 +110,6 @@ command appeared in
.Sh AUTHORS
The
.Nm
-was developed by
+utility was developed by
.An Edward Tomasz Napierala Aq Mt trasz@FreeBSD.org
under sponsorship from the FreeBSD Foundation.
diff --git a/usr.sbin/iscsid/iscsid.c b/usr.sbin/iscsid/iscsid.c
index 4e85b1c..a7f489e 100644
--- a/usr.sbin/iscsid/iscsid.c
+++ b/usr.sbin/iscsid/iscsid.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
diff --git a/usr.sbin/iscsid/iscsid.h b/usr.sbin/iscsid/iscsid.h
index 9623559..b05c222 100644
--- a/usr.sbin/iscsid/iscsid.h
+++ b/usr.sbin/iscsid/iscsid.h
@@ -34,6 +34,7 @@
#include <stdbool.h>
#include <stdint.h>
+#include <openssl/md5.h>
#include <iscsi_ioctl.h>
@@ -60,8 +61,7 @@ struct connection {
size_t conn_max_data_segment_length;
size_t conn_max_burst_length;
size_t conn_first_burst_length;
- char conn_mutual_challenge[CONN_MUTUAL_CHALLENGE_LEN];
- unsigned char conn_mutual_id;
+ struct chap *conn_mutual_chap;
};
struct pdu {
@@ -80,6 +80,35 @@ struct keys {
size_t keys_data_len;
};
+#define CHAP_CHALLENGE_LEN 1024
+
+struct chap {
+ unsigned char chap_id;
+ char chap_challenge[CHAP_CHALLENGE_LEN];
+ char chap_response[MD5_DIGEST_LENGTH];
+};
+
+struct rchap {
+ char *rchap_secret;
+ unsigned char rchap_id;
+ void *rchap_challenge;
+ size_t rchap_challenge_len;
+};
+
+struct chap *chap_new(void);
+char *chap_get_id(const struct chap *chap);
+char *chap_get_challenge(const struct chap *chap);
+int chap_receive(struct chap *chap, const char *response);
+int chap_authenticate(struct chap *chap,
+ const char *secret);
+void chap_delete(struct chap *chap);
+
+struct rchap *rchap_new(const char *secret);
+int rchap_receive(struct rchap *rchap,
+ const char *id, const char *challenge);
+char *rchap_get_response(struct rchap *rchap);
+void rchap_delete(struct rchap *rchap);
+
struct keys *keys_new(void);
void keys_delete(struct keys *key);
void keys_load(struct keys *keys, const struct pdu *pdu);
diff --git a/usr.sbin/iscsid/keys.c b/usr.sbin/iscsid/keys.c
index 49340e0..bab1ac9 100644
--- a/usr.sbin/iscsid/keys.c
+++ b/usr.sbin/iscsid/keys.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
@@ -115,7 +117,7 @@ keys_save(struct keys *keys, struct pdu *pdu)
for (i = 0; i < KEYS_MAX; i++) {
if (keys->keys_names[i] == NULL)
break;
- /*
+ /*
* +1 for '=', +1 for '\0'.
*/
len += strlen(keys->keys_names[i]) +
diff --git a/usr.sbin/iscsid/log.c b/usr.sbin/iscsid/log.c
index be3aaed..ea7755f 100644
--- a/usr.sbin/iscsid/log.c
+++ b/usr.sbin/iscsid/log.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
diff --git a/usr.sbin/iscsid/login.c b/usr.sbin/iscsid/login.c
index f4fd29f..afe7ebb 100644
--- a/usr.sbin/iscsid/login.c
+++ b/usr.sbin/iscsid/login.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/ioctl.h>
#include <assert.h>
@@ -37,9 +39,6 @@
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
-#include <openssl/err.h>
-#include <openssl/md5.h>
-#include <openssl/rand.h>
#include "iscsid.h"
#include "iscsi_proto.h"
@@ -183,7 +182,7 @@ kernel_modify(const struct connection *conn, const char *target_address)
* be much more complicated: we would need to keep "dependencies"
* for sessions, so that, in case described in draft and using draft
* terminology, we would have three sessions: one for discovery,
- * one for initial target portal, and one for redirect portal.
+ * one for initial target portal, and one for redirect portal.
* This would allow us to "backtrack" on connection failure,
* as described in draft.
*/
@@ -211,6 +210,7 @@ login_handle_redirection(struct connection *conn, struct pdu *response)
log_debugx("received redirection to \"%s\"", target_address);
kernel_modify(conn, target_address);
+ keys_delete(response_keys);
}
static struct pdu *
@@ -326,148 +326,6 @@ login_list_prefers(const char *list,
return (-1);
}
-static int
-login_hex2int(const char hex)
-{
- switch (hex) {
- case '0':
- return (0x00);
- case '1':
- return (0x01);
- case '2':
- return (0x02);
- case '3':
- return (0x03);
- case '4':
- return (0x04);
- case '5':
- return (0x05);
- case '6':
- return (0x06);
- case '7':
- return (0x07);
- case '8':
- return (0x08);
- case '9':
- return (0x09);
- case 'a':
- case 'A':
- return (0x0a);
- case 'b':
- case 'B':
- return (0x0b);
- case 'c':
- case 'C':
- return (0x0c);
- case 'd':
- case 'D':
- return (0x0d);
- case 'e':
- case 'E':
- return (0x0e);
- case 'f':
- case 'F':
- return (0x0f);
- default:
- return (-1);
- }
-}
-
-/*
- * XXX: Review this _carefully_.
- */
-static int
-login_hex2bin(const char *hex, char **binp, size_t *bin_lenp)
-{
- int i, hex_len, nibble;
- bool lo = true; /* As opposed to 'hi'. */
- char *bin;
- size_t bin_off, bin_len;
-
- if (strncasecmp(hex, "0x", strlen("0x")) != 0) {
- log_warnx("malformed variable, should start with \"0x\"");
- return (-1);
- }
-
- hex += strlen("0x");
- hex_len = strlen(hex);
- if (hex_len < 1) {
- log_warnx("malformed variable; doesn't contain anything "
- "but \"0x\"");
- return (-1);
- }
-
- bin_len = hex_len / 2 + hex_len % 2;
- bin = calloc(bin_len, 1);
- if (bin == NULL)
- log_err(1, "calloc");
-
- bin_off = bin_len - 1;
- for (i = hex_len - 1; i >= 0; i--) {
- nibble = login_hex2int(hex[i]);
- if (nibble < 0) {
- log_warnx("malformed variable, invalid char \"%c\"",
- hex[i]);
- return (-1);
- }
-
- assert(bin_off < bin_len);
- if (lo) {
- bin[bin_off] = nibble;
- lo = false;
- } else {
- bin[bin_off] |= nibble << 4;
- bin_off--;
- lo = true;
- }
- }
-
- *binp = bin;
- *bin_lenp = bin_len;
- return (0);
-}
-
-static char *
-login_bin2hex(const char *bin, size_t bin_len)
-{
- unsigned char *hex, *tmp, ch;
- size_t hex_len;
- size_t i;
-
- hex_len = bin_len * 2 + 3; /* +2 for "0x", +1 for '\0'. */
- hex = malloc(hex_len);
- if (hex == NULL)
- log_err(1, "malloc");
-
- tmp = hex;
- tmp += sprintf(tmp, "0x");
- for (i = 0; i < bin_len; i++) {
- ch = bin[i];
- tmp += sprintf(tmp, "%02x", ch);
- }
-
- return (hex);
-}
-
-static void
-login_compute_md5(const char id, const char *secret,
- const void *challenge, size_t challenge_len, void *response,
- size_t response_len)
-{
- MD5_CTX ctx;
- int rv;
-
- assert(response_len == MD5_DIGEST_LENGTH);
-
- MD5_Init(&ctx);
- MD5_Update(&ctx, &id, sizeof(id));
- MD5_Update(&ctx, secret, strlen(secret));
- MD5_Update(&ctx, challenge, challenge_len);
- rv = MD5_Final(response, &ctx);
- if (rv != 1)
- log_errx(1, "MD5_Final");
-}
-
static void
login_negotiate_key(struct connection *conn, const char *name,
const char *value)
@@ -572,7 +430,7 @@ login_negotiate(struct connection *conn)
struct pdu *request, *response;
struct keys *request_keys, *response_keys;
struct iscsi_bhs_login_response *bhslr;
- int i;
+ int i, nrequests = 0;
log_debugx("beginning operational parameter negotiation");
request = login_new_request(conn, BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
@@ -626,19 +484,41 @@ login_negotiate(struct connection *conn)
response_keys->keys_names[i], response_keys->keys_values[i]);
}
- bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
- if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) == 0)
- log_warnx("received final login response "
- "without the \"T\" flag");
- else if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE)
+ keys_delete(response_keys);
+ response_keys = NULL;
+
+ for (;;) {
+ bhslr = (struct iscsi_bhs_login_response *)response->pdu_bhs;
+ if ((bhslr->bhslr_flags & BHSLR_FLAGS_TRANSIT) != 0)
+ break;
+
+ nrequests++;
+ if (nrequests > 5) {
+ log_warnx("received login response "
+ "without the \"T\" flag too many times; giving up");
+ break;
+ }
+
+ log_debugx("received login response "
+ "without the \"T\" flag; sending another request");
+
+ pdu_delete(response);
+
+ request = login_new_request(conn,
+ BHSLR_STAGE_OPERATIONAL_NEGOTIATION);
+ pdu_send(request);
+ pdu_delete(request);
+
+ response = login_receive(conn);
+ }
+
+ if (login_nsg(response) != BHSLR_STAGE_FULL_FEATURE_PHASE)
log_warnx("received final login response with wrong NSG 0x%x",
login_nsg(response));
+ pdu_delete(response);
log_debugx("operational parameter negotiation done; "
"transitioning to Full Feature phase");
-
- keys_delete(response_keys);
- pdu_delete(response);
}
static void
@@ -662,12 +542,11 @@ login_send_chap_r(struct pdu *response)
struct connection *conn;
struct pdu *request;
struct keys *request_keys, *response_keys;
+ struct rchap *rchap;
const char *chap_a, *chap_c, *chap_i;
- char *chap_r, *challenge, response_bin[MD5_DIGEST_LENGTH];
- size_t challenge_len;
- int error, rv;
- unsigned char id;
- char *mutual_chap_c, mutual_chap_i[4];
+ char *chap_r;
+ int error;
+ char *mutual_chap_c, *mutual_chap_i;
/*
* As in the rest of the initiator, 'request' means
@@ -695,17 +574,19 @@ login_send_chap_r(struct pdu *response)
if (chap_i == NULL)
log_errx(1, "received CHAP packet without CHAP_I");
- if (strcmp(chap_a, "5") != 0)
+ if (strcmp(chap_a, "5") != 0) {
log_errx(1, "received CHAP packet "
"with unsupported CHAP_A \"%s\"", chap_a);
- id = strtoul(chap_i, NULL, 10);
- error = login_hex2bin(chap_c, &challenge, &challenge_len);
- if (error != 0)
- log_errx(1, "received CHAP packet with malformed CHAP_C");
- login_compute_md5(id, conn->conn_conf.isc_secret,
- challenge, challenge_len, response_bin, sizeof(response_bin));
- free(challenge);
- chap_r = login_bin2hex(response_bin, sizeof(response_bin));
+ }
+
+ rchap = rchap_new(conn->conn_conf.isc_secret);
+ error = rchap_receive(rchap, chap_i, chap_c);
+ if (error != 0) {
+ log_errx(1, "received CHAP packet "
+ "with malformed CHAP_I or CHAP_C");
+ }
+ chap_r = rchap_get_response(rchap);
+ rchap_delete(rchap);
keys_delete(response_keys);
@@ -722,26 +603,15 @@ login_send_chap_r(struct pdu *response)
if (conn->conn_conf.isc_mutual_user[0] != '\0') {
log_debugx("requesting mutual authentication; "
"binary challenge size is %zd bytes",
- sizeof(conn->conn_mutual_challenge));
+ sizeof(conn->conn_mutual_chap->chap_challenge));
- rv = RAND_bytes(conn->conn_mutual_challenge,
- sizeof(conn->conn_mutual_challenge));
- if (rv != 1) {
- log_errx(1, "RAND_bytes failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- }
- rv = RAND_bytes(&conn->conn_mutual_id,
- sizeof(conn->conn_mutual_id));
- if (rv != 1) {
- log_errx(1, "RAND_bytes failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
- }
- mutual_chap_c = login_bin2hex(conn->conn_mutual_challenge,
- sizeof(conn->conn_mutual_challenge));
- snprintf(mutual_chap_i, sizeof(mutual_chap_i),
- "%d", conn->conn_mutual_id);
+ assert(conn->conn_mutual_chap == NULL);
+ conn->conn_mutual_chap = chap_new();
+ mutual_chap_i = chap_get_id(conn->conn_mutual_chap);
+ mutual_chap_c = chap_get_challenge(conn->conn_mutual_chap);
keys_add(request_keys, "CHAP_I", mutual_chap_i);
keys_add(request_keys, "CHAP_C", mutual_chap_c);
+ free(mutual_chap_i);
free(mutual_chap_c);
}
@@ -757,8 +627,6 @@ login_verify_mutual(const struct pdu *response)
struct connection *conn;
struct keys *response_keys;
const char *chap_n, *chap_r;
- char *response_bin, expected_response_bin[MD5_DIGEST_LENGTH];
- size_t response_bin_len;
int error;
conn = response->pdu_connection;
@@ -772,28 +640,26 @@ login_verify_mutual(const struct pdu *response)
chap_r = keys_find(response_keys, "CHAP_R");
if (chap_r == NULL)
log_errx(1, "received CHAP Response PDU without CHAP_R");
- error = login_hex2bin(chap_r, &response_bin, &response_bin_len);
- if (error != 0)
- log_errx(1, "received CHAP Response PDU with malformed CHAP_R");
+
+ error = chap_receive(conn->conn_mutual_chap, chap_r);
+ if (error != 0)
+ log_errx(1, "received CHAP Response PDU with invalid CHAP_R");
if (strcmp(chap_n, conn->conn_conf.isc_mutual_user) != 0) {
fail(conn, "Mutual CHAP failed");
log_errx(1, "mutual CHAP authentication failed: wrong user");
}
- login_compute_md5(conn->conn_mutual_id,
- conn->conn_conf.isc_mutual_secret, conn->conn_mutual_challenge,
- sizeof(conn->conn_mutual_challenge), expected_response_bin,
- sizeof(expected_response_bin));
-
- if (memcmp(response_bin, expected_response_bin,
- sizeof(expected_response_bin)) != 0) {
+ error = chap_authenticate(conn->conn_mutual_chap,
+ conn->conn_conf.isc_mutual_secret);
+ if (error != 0) {
fail(conn, "Mutual CHAP failed");
log_errx(1, "mutual CHAP authentication failed: wrong secret");
}
- keys_delete(response_keys);
- free(response_bin);
+ keys_delete(response_keys);
+ chap_delete(conn->conn_mutual_chap);
+ conn->conn_mutual_chap = NULL;
log_debugx("mutual CHAP authentication succeeded");
}
@@ -890,8 +756,8 @@ login(struct connection *conn)
* to parse things such as TargetAlias.
*
* XXX: This is somewhat ugly. We should have a way to apply
- * all the keys to the session and use that by default
- * instead of discarding them.
+ * all the keys to the session and use that by default
+ * instead of discarding them.
*/
if (strcmp(response_keys->keys_names[i], "AuthMethod") == 0)
continue;
diff --git a/usr.sbin/iscsid/pdu.c b/usr.sbin/iscsid/pdu.c
index 6b5630e..8f07718 100644
--- a/usr.sbin/iscsid/pdu.c
+++ b/usr.sbin/iscsid/pdu.c
@@ -26,9 +26,11 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $FreeBSD$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
diff --git a/usr.sbin/jail/command.c b/usr.sbin/jail/command.c
index 04a4514..0d1c898 100644
--- a/usr.sbin/jail/command.c
+++ b/usr.sbin/jail/command.c
@@ -268,7 +268,7 @@ run_command(struct cfjail *j)
pid_t pid;
int argc, bg, clean, consfd, down, fib, i, injail, sjuser, timeout;
#if defined(INET) || defined(INET6)
- char *addr;
+ char *addr, *extrap, *p, *val;
#endif
static char *cleanenv;
@@ -317,16 +317,30 @@ run_command(struct cfjail *j)
switch (comparam) {
#ifdef INET
case IP__IP4_IFADDR:
- argv = alloca(8 * sizeof(char *));
+ argc = 0;
+ val = alloca(strlen(comstring->s) + 1);
+ strcpy(val, comstring->s);
+ cs = val;
+ extrap = NULL;
+ while ((p = strchr(cs, ' ')) != NULL && strlen(p) > 1) {
+ if (extrap == NULL) {
+ *p = '\0';
+ extrap = p + 1;
+ }
+ cs = p + 1;
+ argc++;
+ }
+
+ argv = alloca((8 + argc) * sizeof(char *));
*(const char **)&argv[0] = _PATH_IFCONFIG;
- if ((cs = strchr(comstring->s, '|'))) {
- argv[1] = alloca(cs - comstring->s + 1);
- strlcpy(argv[1], comstring->s, cs - comstring->s + 1);
+ if ((cs = strchr(val, '|'))) {
+ argv[1] = alloca(cs - val + 1);
+ strlcpy(argv[1], val, cs - val + 1);
addr = cs + 1;
} else {
*(const char **)&argv[1] =
string_param(j->intparams[IP_INTERFACE]);
- addr = comstring->s;
+ addr = val;
}
*(const char **)&argv[2] = "inet";
if (!(cs = strchr(addr, '/'))) {
@@ -344,6 +358,15 @@ run_command(struct cfjail *j)
argv[3] = addr;
argc = 4;
}
+
+ if (!down) {
+ for (cs = strtok(extrap, " "); cs; cs = strtok(NULL, " ")) {
+ size_t len = strlen(cs) + 1;
+ argv[argc] = alloca(len);
+ strlcpy(argv[argc++], cs, len);
+ }
+ }
+
*(const char **)&argv[argc] = down ? "-alias" : "alias";
argv[argc + 1] = NULL;
break;
@@ -351,16 +374,30 @@ run_command(struct cfjail *j)
#ifdef INET6
case IP__IP6_IFADDR:
- argv = alloca(8 * sizeof(char *));
+ argc = 0;
+ val = alloca(strlen(comstring->s) + 1);
+ strcpy(val, comstring->s);
+ cs = val;
+ extrap = NULL;
+ while ((p = strchr(cs, ' ')) != NULL && strlen(p) > 1) {
+ if (extrap == NULL) {
+ *p = '\0';
+ extrap = p + 1;
+ }
+ cs = p + 1;
+ argc++;
+ }
+
+ argv = alloca((8 + argc) * sizeof(char *));
*(const char **)&argv[0] = _PATH_IFCONFIG;
- if ((cs = strchr(comstring->s, '|'))) {
- argv[1] = alloca(cs - comstring->s + 1);
- strlcpy(argv[1], comstring->s, cs - comstring->s + 1);
+ if ((cs = strchr(val, '|'))) {
+ argv[1] = alloca(cs - val + 1);
+ strlcpy(argv[1], val, cs - val + 1);
addr = cs + 1;
} else {
*(const char **)&argv[1] =
string_param(j->intparams[IP_INTERFACE]);
- addr = comstring->s;
+ addr = val;
}
*(const char **)&argv[2] = "inet6";
argv[3] = addr;
@@ -370,6 +407,15 @@ run_command(struct cfjail *j)
argc = 6;
} else
argc = 4;
+
+ if (!down) {
+ for (cs = strtok(extrap, " "); cs; cs = strtok(NULL, " ")) {
+ size_t len = strlen(cs) + 1;
+ argv[argc] = alloca(len);
+ strlcpy(argv[argc++], cs, len);
+ }
+ }
+
*(const char **)&argv[argc] = down ? "-alias" : "alias";
argv[argc + 1] = NULL;
break;
diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c
index 5796708..cd02a50 100644
--- a/usr.sbin/jail/config.c
+++ b/usr.sbin/jail/config.c
@@ -576,7 +576,9 @@ check_intparams(struct cfjail *j)
/*
* IP addresses may include an interface to set that address on,
- * and a netmask/suffix for that address.
+ * a netmask/suffix for that address and options for ifconfig.
+ * These are copied to an internal command parameter and then stripped
+ * so they won't be passed on to jailparam_set.
*/
defif = string_param(j->intparams[IP_INTERFACE]) != NULL;
#ifdef INET
@@ -601,6 +603,10 @@ check_intparams(struct cfjail *j)
*cs = '\0';
s->len = cs - s->s;
}
+ if ((cs = strchr(s->s, ' ')) != NULL) {
+ *cs = '\0';
+ s->len = cs - s->s;
+ }
}
}
#endif
@@ -625,6 +631,10 @@ check_intparams(struct cfjail *j)
*cs = '\0';
s->len = cs - s->s;
}
+ if ((cs = strchr(s->s, ' ')) != NULL) {
+ *cs = '\0';
+ s->len = cs - s->s;
+ }
}
}
#endif
diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
index e43928a..927e2bb 100644
--- a/usr.sbin/jail/jail.8
+++ b/usr.sbin/jail/jail.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 10, 2014
+.Dd August 4, 2014
.Dt JAIL 8
.Os
.Sh NAME
@@ -687,18 +687,24 @@ jail is created, and will be removed from the interface after the
jail is removed.
.It Va ip4.addr
In addition to the IP addresses that are passed to the kernel, an
-interface and/or a netmask may also be specified, in the form
-.Dq Ar interface Ns | Ns Ar ip-address Ns / Ns Ar netmask .
+interface, netmask and additional paramters (as supported by
+.Xr ifconfig 8 Ns )
+may also be specified, in the form
+.Dq Ar interface Ns | Ns Ar ip-address Ns / Ns Ar netmask param ... .
If an interface is given before the IP address, an alias for the address
will be added to that interface, as it is with the
.Va interface
parameter.
If a netmask in either dotted-quad or CIDR form is given
after an IP address, it will be used when adding the IP alias.
+If additional parameters are specified then they will also be used when
+adding the IP alias.
.It Va ip6.addr
In addition to the IP addresses that are passed to the kernel,
-an interface and/or a prefix may also be specified, in the form
-.Dq Ar interface Ns | Ns Ar ip-address Ns / Ns Ar prefix .
+an interface, prefix and additional parameters (as supported by
+.Xr ifconfig 8 Ns )
+may also be specified, in the form
+.Dq Ar interface Ns | Ns Ar ip-address Ns / Ns Ar prefix param ... .
.It Va vnet.interface
A network interface to give to a vnet-enabled jail after is it created.
The interface will automatically be released when the jail is removed.
@@ -1177,6 +1183,7 @@ environment of the first jail.
.Xr pkill 1 ,
.Xr ps 1 ,
.Xr quota 1 ,
+.Xr ifconfig 8 ,
.Xr jail_set 2 ,
.Xr devfs 5 ,
.Xr fdescfs 5 ,
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.1 b/usr.sbin/kbdcontrol/kbdcontrol.1
index 3ffa270..cc37309 100644
--- a/usr.sbin/kbdcontrol/kbdcontrol.1
+++ b/usr.sbin/kbdcontrol/kbdcontrol.1
@@ -1,5 +1,5 @@
.\"
-.\" kbdcontrol - a utility for manipulating the syscons keyboard driver section
+.\" kbdcontrol - a utility for manipulating the syscons or vt keyboard driver section
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -41,6 +41,8 @@ The
.Nm
command is used to set various keyboard related options for the
.Xr syscons 4
+or
+.Xr vt 4
console driver and the keyboard drivers,
such as key map, keyboard repeat and delay rates, bell
characteristics etc.
@@ -213,7 +215,9 @@ for details.
.Sh FILES
.Bl -tag -width /usr/share/syscons/keymaps/foo_bar -compact
.It Pa /usr/share/syscons/keymaps/*
-keyboard map files
+keyboard map files for syscons
+.It Pa /usr/share/vt/keymaps/*
+keyboard map files for vt
.El
.Sh EXAMPLES
The following command will load the keyboard map file
@@ -222,9 +226,19 @@ The following command will load the keyboard map file
.Dl kbdcontrol -l /usr/share/syscons/keymaps/ru.koi8-r.kbd
.Pp
So long as the keyboard map file resides in
-.Pa /usr/share/syscons/keymaps ,
+.Pa /usr/share/syscons/keymaps
+(if using
+.Xr syscons 4 ) or
+.Pa /usr/share/vt/keymaps
+(if using
+.Xr vt 4 ) ,
you may abbreviate the file name as
.Pa ru.koi8-r .
+Since
+.Xr vt 4
+uses Unicode, the corresponding keyboard file names omit the encoding
+and typically are just a country code, e.g.\&
+.Pa ru .
.Pp
.Dl kbdcontrol -l ru.koi8-r
.Pp
@@ -268,6 +282,7 @@ kbdcontrol -k /dev/kbdmux0 < /dev/console
.Xr screen 4 ,
.Xr syscons 4 ,
.Xr ukbd 4 ,
+.Xr vt 4 ,
.Xr kbdmap 5 ,
.Xr rc.conf 5
.Sh AUTHORS
diff --git a/usr.sbin/kbdcontrol/kbdcontrol.c b/usr.sbin/kbdcontrol/kbdcontrol.c
index 241e10d..0f927ef 100644
--- a/usr.sbin/kbdcontrol/kbdcontrol.c
+++ b/usr.sbin/kbdcontrol/kbdcontrol.c
@@ -800,7 +800,7 @@ load_keymap(char *opt, int dumponly)
char *name, *cp;
char blank[] = "", keymap_path[] = KEYMAP_PATH;
char vt_keymap_path[] = VT_KEYMAP_PATH, dotkbd[] = ".kbd";
- char *prefix[] = {blank, blank, blank, keymap_path, NULL};
+ char *prefix[] = {blank, blank, keymap_path, NULL};
char *postfix[] = {blank, dotkbd, NULL};
if (is_vt4())
diff --git a/usr.sbin/kbdcontrol/kbdmap.5 b/usr.sbin/kbdcontrol/kbdmap.5
index 4c4cd86..c7f437a 100644
--- a/usr.sbin/kbdcontrol/kbdmap.5
+++ b/usr.sbin/kbdcontrol/kbdmap.5
@@ -313,13 +313,16 @@ for that vowel with a grave accent.
.Sh FILES
.Bl -tag -width /usr/share/syscons/keymaps/* -compact
.It Pa /usr/share/syscons/keymaps/*
-standard keyboard map files
+standard keyboard map files for syscons
+.It Pa /usr/share/vt/keymaps/*
+standard keyboard map files for vt
.El
.Sh SEE ALSO
.Xr kbdcontrol 1 ,
.Xr kbdmap 1 ,
.Xr keyboard 4 ,
.Xr syscons 4 ,
+.Xr vt 4 ,
.Xr ascii 7
.Sh HISTORY
This manual page first appeared in
diff --git a/usr.sbin/kbdmap/kbdmap.1 b/usr.sbin/kbdmap/kbdmap.1
index 6769c30..5d4cf0e 100644
--- a/usr.sbin/kbdmap/kbdmap.1
+++ b/usr.sbin/kbdmap/kbdmap.1
@@ -29,7 +29,7 @@
.Sh NAME
.Nm kbdmap ,
.Nm vidfont
-.Nd front end for syscons
+.Nd front end for syscons and vt
.Sh SYNOPSIS
.Nm
.Op Fl K
@@ -106,8 +106,10 @@ preferred language
.Sh FILES
.Bl -tag -width ".Pa /usr/share/syscons/keymaps/INDEX.keymaps" -compact
.It Pa /usr/share/syscons/keymaps/INDEX.keymaps
+.It Pa /usr/share/vt/keymaps/INDEX.keymaps
database for keymaps
.It Pa /usr/share/syscons/fonts/INDEX.fonts
+.It Pa /usr/share/vt/fonts/INDEX.fonts
database for fonts
.It Pa /etc/rc.conf
default font
@@ -120,6 +122,8 @@ values
.Xr dialog 1 ,
.Xr kbdcontrol 1 ,
.Xr vidcontrol 1 ,
+.Xr syscons 4 ,
+.Xr vt 4 ,
.Xr kbdmap 5 ,
.Xr rc.conf 5
.Sh HISTORY
diff --git a/usr.sbin/kbdmap/kbdmap.c b/usr.sbin/kbdmap/kbdmap.c
index 7d5a0d1..bf2aa81 100644
--- a/usr.sbin/kbdmap/kbdmap.c
+++ b/usr.sbin/kbdmap/kbdmap.c
@@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/sysctl.h>
#include <assert.h>
#include <ctype.h>
@@ -47,10 +48,10 @@ static const char *lang_default = DEFAULT_LANG;
static const char *font;
static const char *lang;
static const char *program;
-static const char *keymapdir = DEFAULT_KEYMAP_DIR;
-static const char *fontdir = DEFAULT_FONT_DIR;
+static const char *keymapdir = DEFAULT_VT_KEYMAP_DIR;
+static const char *fontdir = DEFAULT_VT_FONT_DIR;
+static const char *font_default = DEFAULT_VT_FONT;
static const char *sysconfig = DEFAULT_SYSCONFIG;
-static const char *font_default = DEFAULT_FONT;
static const char *font_current;
static const char *dir;
static const char *menu = "";
@@ -146,6 +147,22 @@ add_keymap(const char *desc, int mark, const char *keym)
}
/*
+ * Return 0 if syscons is in use (to select legacy defaults).
+ */
+static int
+check_newcons(void)
+{
+ size_t len;
+ char term[3];
+
+ len = 3;
+ if (sysctlbyname("kern.vty", &term, &len, NULL, 0) != 0 ||
+ strcmp(term, "vt") != 0)
+ return 0;
+ return -1;
+}
+
+/*
* Figure out the default language to use.
*/
static const char *
@@ -815,6 +832,12 @@ main(int argc, char **argv)
sleep(2);
}
+ if (check_newcons() == 0) {
+ keymapdir = DEFAULT_SC_KEYMAP_DIR;
+ fontdir = DEFAULT_SC_FONT_DIR;
+ font_default = DEFAULT_SC_FONT;
+ }
+
SLIST_INIT(&head);
lang = get_locale();
diff --git a/usr.sbin/kbdmap/kbdmap.h b/usr.sbin/kbdmap/kbdmap.h
index e57fa8c..89d27b1 100644
--- a/usr.sbin/kbdmap/kbdmap.h
+++ b/usr.sbin/kbdmap/kbdmap.h
@@ -28,7 +28,12 @@
#define DEFAULT_LANG "en"
-#define DEFAULT_KEYMAP_DIR "/usr/share/syscons/keymaps"
-#define DEFAULT_FONT_DIR "/usr/share/syscons/fonts"
#define DEFAULT_SYSCONFIG "/etc/rc.conf"
-#define DEFAULT_FONT "cp437-8x16.fnt"
+
+#define DEFAULT_SC_KEYMAP_DIR "/usr/share/syscons/keymaps"
+#define DEFAULT_SC_FONT_DIR "/usr/share/syscons/fonts"
+#define DEFAULT_SC_FONT "cp437-8x16.fnt"
+
+#define DEFAULT_VT_KEYMAP_DIR "/usr/share/vt/keymaps"
+#define DEFAULT_VT_FONT_DIR "/usr/share/vt/fonts"
+#define DEFAULT_VT_FONT "vgarom-thin-8x16.fnt"
diff --git a/usr.sbin/lpr/chkprintcap/Makefile b/usr.sbin/lpr/chkprintcap/Makefile
index 1ea2254..ffffffb 100644
--- a/usr.sbin/lpr/chkprintcap/Makefile
+++ b/usr.sbin/lpr/chkprintcap/Makefile
@@ -11,6 +11,4 @@ CFLAGS+= -I${.CURDIR}/../common_source
DPADD= ${LIBLPR}
LDADD= ${LIBLPR}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpc/Makefile b/usr.sbin/lpr/lpc/Makefile
index 7f228d6..92ca9e8 100644
--- a/usr.sbin/lpr/lpc/Makefile
+++ b/usr.sbin/lpr/lpc/Makefile
@@ -16,6 +16,4 @@ WARNS?= 0
DPADD= ${LIBLPR} ${LIBEDIT} ${LIBTERMCAPW}
LDADD= ${LIBLPR} -ledit -ltermcapw
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpd/Makefile b/usr.sbin/lpr/lpd/Makefile
index bd3e25a..0d7d93e 100644
--- a/usr.sbin/lpr/lpd/Makefile
+++ b/usr.sbin/lpr/lpd/Makefile
@@ -12,6 +12,4 @@ WARNS?= 1
DPADD= ${LIBLPR}
LDADD= ${LIBLPR}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpd/printjob.c b/usr.sbin/lpr/lpd/printjob.c
index 9771498..06ea1b0 100644
--- a/usr.sbin/lpr/lpd/printjob.c
+++ b/usr.sbin/lpr/lpd/printjob.c
@@ -176,7 +176,7 @@ printjob(struct printer *pp)
}
if(setgid(getegid()) != 0) err(1, "setgid() failed");
printpid = getpid(); /* for use with lprm */
- setpgrp(0, printpid);
+ setpgid((pid_t)0, printpid);
/*
* At initial lpd startup, printjob may be called with various
diff --git a/usr.sbin/lpr/lpq/Makefile b/usr.sbin/lpr/lpq/Makefile
index 1c2504b..4df437e 100644
--- a/usr.sbin/lpr/lpq/Makefile
+++ b/usr.sbin/lpr/lpq/Makefile
@@ -13,6 +13,4 @@ CFLAGS+= -I${.CURDIR}/../common_source
DPADD= ${LIBLPR}
LDADD= ${LIBLPR}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lpr/Makefile b/usr.sbin/lpr/lpr/Makefile
index cfeebb0..1894b00 100644
--- a/usr.sbin/lpr/lpr/Makefile
+++ b/usr.sbin/lpr/lpr/Makefile
@@ -18,6 +18,4 @@ WARNS?= 2
DPADD= ${LIBLPR}
LDADD= ${LIBLPR}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/lprm/Makefile b/usr.sbin/lpr/lprm/Makefile
index bd7e321..44bc93a 100644
--- a/usr.sbin/lpr/lprm/Makefile
+++ b/usr.sbin/lpr/lprm/Makefile
@@ -15,6 +15,4 @@ CFLAGS+= -I${.CURDIR}/../common_source
DPADD= ${LIBLPR}
LDADD= ${LIBLPR}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/lpr/pac/Makefile b/usr.sbin/lpr/pac/Makefile
index 3a157c9..bd895a7 100644
--- a/usr.sbin/lpr/pac/Makefile
+++ b/usr.sbin/lpr/pac/Makefile
@@ -11,6 +11,4 @@ CFLAGS+= -I${.CURDIR}/../common_source
DPADD= ${LIBLPR}
LDADD= ${LIBLPR}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/mailstats/Makefile b/usr.sbin/mailstats/Makefile
index a3cd562..bd72fc6 100644
--- a/usr.sbin/mailstats/Makefile
+++ b/usr.sbin/mailstats/Makefile
@@ -31,8 +31,6 @@ DPADD+= ${SENDMAIL_DPADD}
LDADD+= ${SENDMAIL_LDADD}
LDFLAGS+= ${SENDMAIL_LDFLAGS}
-NO_PIE= yes
-
sm_os.h:
ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
diff --git a/usr.sbin/mailwrapper/mailwrapper.8 b/usr.sbin/mailwrapper/mailwrapper.8
index 11bfe95..b382d77 100644
--- a/usr.sbin/mailwrapper/mailwrapper.8
+++ b/usr.sbin/mailwrapper/mailwrapper.8
@@ -31,7 +31,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd August 7, 2006
+.Dd August 27, 2014
.Dt MAILWRAPPER 8
.Os
.Sh NAME
@@ -109,6 +109,8 @@ utility is designed to replace
and to invoke an appropriate MTA instead of
.Xr sendmail 8
based on configuration information placed in
+.Pa ${LOCALBASE}/etc/mail/mailer.conf
+falling back on
.Pa /etc/mail/mailer.conf .
This permits the administrator to configure which MTA is to be invoked on
the system at run time.
@@ -126,6 +128,8 @@ should be turned off in
Configuration for
.Nm
is kept in
+.Pa ${LOCALBASE}/etc/mail/mailer.conf
+or
.Pa /etc/mail/mailer.conf .
.Pa /usr/sbin/sendmail
is typically set up as a symbolic link to
diff --git a/usr.sbin/mailwrapper/mailwrapper.c b/usr.sbin/mailwrapper/mailwrapper.c
index 1b52a64..96c9190 100644
--- a/usr.sbin/mailwrapper/mailwrapper.c
+++ b/usr.sbin/mailwrapper/mailwrapper.c
@@ -35,6 +35,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include <sys/param.h>
+
#include <err.h>
#include <stdio.h>
#include <string.h>
@@ -87,6 +89,8 @@ main(int argc, char *argv[], char *envp[])
FILE *config;
char *line, *cp, *from, *to, *ap;
const char *progname;
+ char localmailerconf[MAXPATHLEN];
+ const char *mailerconf;
size_t len, lineno = 0;
int i;
struct arglist al;
@@ -98,11 +102,18 @@ main(int argc, char *argv[], char *envp[])
initarg(&al);
addarg(&al, argv[0]);
- if ((config = fopen(_PATH_MAILERCONF, "r")) == NULL) {
+ snprintf(localmailerconf, MAXPATHLEN, "%s/etc/mail/mailer.conf",
+ getenv("LOCALBASE") ? getenv("LOCALBASE") : "/usr/local");
+
+ mailerconf = localmailerconf;
+ if ((config = fopen(localmailerconf, "r")) == NULL)
+ mailerconf = _PATH_MAILERCONF;
+
+ if (config == NULL && ((config = fopen(mailerconf, "r")) == NULL)) {
addarg(&al, NULL);
openlog(getprogname(), LOG_PID, LOG_MAIL);
syslog(LOG_INFO, "cannot open %s, using %s as default MTA",
- _PATH_MAILERCONF, _PATH_DEFAULTMTA);
+ mailerconf, _PATH_DEFAULTMTA);
closelog();
execve(_PATH_DEFAULTMTA, al.argv, envp);
err(EX_OSERR, "cannot exec %s", _PATH_DEFAULTMTA);
@@ -112,7 +123,7 @@ main(int argc, char *argv[], char *envp[])
for (;;) {
if ((line = fparseln(config, &len, &lineno, NULL, 0)) == NULL) {
if (feof(config))
- errx(EX_CONFIG, "no mapping in %s", _PATH_MAILERCONF);
+ errx(EX_CONFIG, "no mapping in %s", mailerconf);
err(EX_CONFIG, "cannot parse line %lu", (u_long)lineno);
}
@@ -157,6 +168,6 @@ main(int argc, char *argv[], char *envp[])
/*NOTREACHED*/
parse_error:
errx(EX_CONFIG, "parse error in %s at line %lu",
- _PATH_MAILERCONF, (u_long)lineno);
+ mailerconf, (u_long)lineno);
/*NOTREACHED*/
}
diff --git a/usr.sbin/makefs/Makefile b/usr.sbin/makefs/Makefile
index 0e03fd3..6253148 100644
--- a/usr.sbin/makefs/Makefile
+++ b/usr.sbin/makefs/Makefile
@@ -38,6 +38,4 @@ LDADD+= ${LIBNETBSD}
DPADD+= ${LIBSBUF} ${LIBUTIL}
LDADD+= -lsbuf -lutil
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index 92d5508..9fd87ae 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -361,7 +361,8 @@ ffs_validate(const char *dir, fsnode *root, fsinfo_t *fsopts)
if (ffs_opts->avgfpdir == -1)
ffs_opts->avgfpdir = AFPDIR;
- if (roundup(fsopts->minsize, ffs_opts->bsize) > fsopts->maxsize)
+ if (fsopts->maxsize > 0 &&
+ roundup(fsopts->minsize, ffs_opts->bsize) > fsopts->maxsize)
errx(1, "`%s' minsize of %lld rounded up to ffs bsize of %d "
"exceeds maxsize %lld. Lower bsize, or round the minimum "
"and maximum sizes to bsize.", dir,
diff --git a/usr.sbin/makemap/Makefile b/usr.sbin/makemap/Makefile
index 2c2eef5..80cafcb 100644
--- a/usr.sbin/makemap/Makefile
+++ b/usr.sbin/makemap/Makefile
@@ -34,8 +34,6 @@ DPADD+=${SENDMAIL_DPADD}
LDADD+=${SENDMAIL_LDADD}
LDFLAGS+=${SENDMAIL_LDFLAGS}
-NO_PIE= yes
-
sm_os.h:
ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
diff --git a/usr.sbin/mfiutil/mfi_properties.c b/usr.sbin/mfiutil/mfi_properties.c
index c9c9204..b03d522 100644
--- a/usr.sbin/mfiutil/mfi_properties.c
+++ b/usr.sbin/mfiutil/mfi_properties.c
@@ -68,7 +68,7 @@ mfi_ctrl_set_properties(int fd, struct mfi_ctrl_props *info)
static int
mfi_ctrl_rebuild_rate(int ac, char **av)
{
- int error, fd;
+ int error, fd;
struct mfi_ctrl_props ctrl_props;
if (ac > 2) {
@@ -76,40 +76,40 @@ mfi_ctrl_rebuild_rate(int ac, char **av)
return(-1);
}
- fd = mfi_open(mfi_unit, O_RDWR);
- if (fd < 0) {
- error = errno;
- warn("mfi_open");
- return (error);
- }
+ fd = mfi_open(mfi_unit, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
error = mfi_ctrl_get_properties(fd, &ctrl_props);
- if ( error < 0) {
- error = errno;
- warn("Failed to get controller properties");
- close(fd);
- return (error);
- }
+ if ( error < 0) {
+ error = errno;
+ warn("Failed to get controller properties");
+ close(fd);
+ return (error);
+ }
/*
* User requested a change to the rebuild rate
*/
if (ac > 1) {
ctrl_props.rebuild_rate = atoi(av[ac - 1]);
error = mfi_ctrl_set_properties(fd, &ctrl_props);
- if ( error < 0) {
- error = errno;
- warn("Failed to set controller properties");
- close(fd);
- return (error);
- }
+ if ( error < 0) {
+ error = errno;
+ warn("Failed to set controller properties");
+ close(fd);
+ return (error);
+ }
error = mfi_ctrl_get_properties(fd, &ctrl_props);
- if ( error < 0) {
- error = errno;
- warn("Failed to get controller properties");
- close(fd);
- return (error);
- }
+ if ( error < 0) {
+ error = errno;
+ warn("Failed to get controller properties");
+ close(fd);
+ return (error);
+ }
}
printf ("controller rebuild rate: %%%u \n",
ctrl_props.rebuild_rate);
@@ -120,7 +120,7 @@ MFI_COMMAND(ctrlprop, rebuild, mfi_ctrl_rebuild_rate);
static int
mfi_ctrl_alarm_enable(int ac, char **av)
{
- int error, fd;
+ int error, fd;
struct mfi_ctrl_props ctrl_props;
if (ac > 2) {
@@ -128,40 +128,40 @@ mfi_ctrl_alarm_enable(int ac, char **av)
return(-1);
}
- fd = mfi_open(mfi_unit, O_RDWR);
- if (fd < 0) {
- error = errno;
- warn("mfi_open");
- return (error);
- }
+ fd = mfi_open(mfi_unit, O_RDWR);
+ if (fd < 0) {
+ error = errno;
+ warn("mfi_open");
+ return (error);
+ }
error = mfi_ctrl_get_properties(fd, &ctrl_props);
- if ( error < 0) {
- error = errno;
- warn("Failed to get controller properties");
- close(fd);
- return (error);
- }
+ if ( error < 0) {
+ error = errno;
+ warn("Failed to get controller properties");
+ close(fd);
+ return (error);
+ }
printf ("controller alarm was : %s\n",
(ctrl_props.alarm_enable ? "enabled" : "disabled"));
if (ac > 1) {
ctrl_props.alarm_enable = atoi(av[ac - 1]);
error = mfi_ctrl_set_properties(fd, &ctrl_props);
- if ( error < 0) {
- error = errno;
- warn("Failed to set controller properties");
- close(fd);
- return (error);
- }
+ if ( error < 0) {
+ error = errno;
+ warn("Failed to set controller properties");
+ close(fd);
+ return (error);
+ }
error = mfi_ctrl_get_properties(fd, &ctrl_props);
- if ( error < 0) {
- error = errno;
- warn("Failed to get controller properties");
- close(fd);
- return (error);
- }
+ if ( error < 0) {
+ error = errno;
+ warn("Failed to get controller properties");
+ close(fd);
+ return (error);
+ }
}
printf ("controller alarm was : %s\n",
(ctrl_props.alarm_enable ? "enabled" : "disabled"));
diff --git a/usr.sbin/mountd/exports.5 b/usr.sbin/mountd/exports.5
index 1293524..88e2219 100644
--- a/usr.sbin/mountd/exports.5
+++ b/usr.sbin/mountd/exports.5
@@ -28,7 +28,7 @@
.\" @(#)exports.5 8.3 (Berkeley) 3/29/95
.\" $FreeBSD$
.\"
-.Dd December 23, 2012
+.Dd August 14, 2014
.Dt EXPORTS 5
.Os
.Sh NAME
@@ -91,10 +91,10 @@ option is used on
Because NFSv4 does not use the mount protocol,
the
.Dq administrative controls
-are not applied.
-Thus, all the above export line(s) should be considered to have the
+are not applied and all directories within this server
+file system are mountable via NFSv4 even if the
.Fl alldirs
-flag, even if the line is specified without it.
+flag has not been specified.
The third form has the string ``V4:'' followed by a single absolute path
name, to specify the NFSv4 tree root.
This line does not export any file system, but simply marks where the root
@@ -310,7 +310,8 @@ interface.
For the third form which specifies the NFSv4 tree root, the directory path
specifies the location within the server's file system tree which is the
root of the NFSv4 tree.
-All entries of this form must specify the same directory path.
+There can only be one NFSv4 root directory per server.
+As such, all entries of this form must specify the same directory path.
For file systems other than ZFS,
this location can be any directory and does not
need to be within an exported file system. If it is not in an exported
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index 1913410..6e4085c 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -1744,6 +1744,7 @@ get_exportlist(void)
iov[3].iov_len = strlen(fsp->f_mntonname) + 1;
iov[5].iov_base = fsp->f_mntfromname;
iov[5].iov_len = strlen(fsp->f_mntfromname) + 1;
+ errmsg[0] = '\0';
if (nmount(iov, iovlen, fsp->f_flags) < 0 &&
errno != ENOENT && errno != ENOTSUP) {
@@ -2501,6 +2502,7 @@ do_mount(struct exportlist *ep, struct grouplist *grp, int exflags,
iov[3].iov_len = strlen(fsb->f_mntonname) + 1;
iov[5].iov_base = fsb->f_mntfromname; /* "from" */
iov[5].iov_len = strlen(fsb->f_mntfromname) + 1;
+ errmsg[0] = '\0';
while (nmount(iov, iovlen, fsb->f_flags) < 0) {
if (cp)
diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/mtree/Makefile
index e73815a..1ceb52e 100644
--- a/usr.sbin/mtree/Makefile
+++ b/usr.sbin/mtree/Makefile
@@ -17,6 +17,6 @@ LDADD= -lmd
CLEANFILES+= fmtree.8
fmtree.8: mtree.8
- cp ${.ALLSRC} ${.TARGET}
+ cp -f ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/newsyslog/newsyslog.8 b/usr.sbin/newsyslog/newsyslog.8
index e6d79a4..ba3db8a 100644
--- a/usr.sbin/newsyslog/newsyslog.8
+++ b/usr.sbin/newsyslog/newsyslog.8
@@ -17,7 +17,7 @@
.\" the suitability of this software for any purpose. It is
.\" provided "as is" without express or implied warranty.
.\"
-.Dd May 19, 2014
+.Dd September 23, 2014
.Dt NEWSYSLOG 8
.Os
.Sh NAME
@@ -156,6 +156,7 @@ will create the
.Dq rotated
logfiles using the specified time format instead of the default
sequential filenames.
+The filename used will be kept until it is deleted.
The time format is described in the
.Xr strftime 3
manual page.
diff --git a/usr.sbin/newsyslog/newsyslog.c b/usr.sbin/newsyslog/newsyslog.c
index ff9e937..b63234b 100644
--- a/usr.sbin/newsyslog/newsyslog.c
+++ b/usr.sbin/newsyslog/newsyslog.c
@@ -1968,8 +1968,8 @@ do_sigwork(struct sigwork_entry *swork)
*/
if (errno != ESRCH)
swork->sw_pidok = 0;
- warn("can't notify %s, pid %d", swork->sw_pidtype,
- (int)swork->sw_pid);
+ warn("can't notify %s, pid %d = %s", swork->sw_pidtype,
+ (int)swork->sw_pid, swork->sw_fname);
} else {
if (verbose)
printf("Notified %s pid %d = %s\n", swork->sw_pidtype,
diff --git a/usr.sbin/nfsd/nfsd.8 b/usr.sbin/nfsd/nfsd.8
index d865d7e..660e5e8 100644
--- a/usr.sbin/nfsd/nfsd.8
+++ b/usr.sbin/nfsd/nfsd.8
@@ -28,7 +28,7 @@
.\" @(#)nfsd.8 8.4 (Berkeley) 3/29/95
.\" $FreeBSD$
.\"
-.Dd July 18, 2014
+.Dd August 10, 2014
.Dt NFSD 8
.Os
.Sh NAME
@@ -175,6 +175,24 @@ utility
would then be used to block nfs-related packets that come in on the outside
interface.
.Pp
+If the server has stopped servicing clients and has generated a console message
+like
+.Dq Li "nfsd server cache flooded..." ,
+the value for vfs.nfsd.tcphighwater needs to be increased.
+This should allow the server to again handle requests without a reboot.
+Also, you may want to consider decreasing the value for
+vfs.nfsd.tcpcachetimeo to several minutes (in seconds) instead of 12 hours
+when this occurs.
+.Pp
+Unfortunately making vfs.nfsd.tcphighwater too large can result in the mbuf
+limit being reached, as indicated by a console message
+like
+.Dq Li "kern.ipc.nmbufs limit reached" .
+If you cannot find values of the above
+.Nm sysctl
+values that work, you can disable the DRC cache for TCP by setting
+vfs.nfsd.cachetcp to 0.
+.Pp
The
.Nm
utility has to be terminated with
diff --git a/usr.sbin/nmtree/Makefile b/usr.sbin/nmtree/Makefile
index e09f3c4..5789ad8 100644
--- a/usr.sbin/nmtree/Makefile
+++ b/usr.sbin/nmtree/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-.include <bsd.own.mk>
+.include <src.opts.mk>
.PATH: ${.CURDIR}/../../contrib/mtree
@@ -8,6 +8,7 @@ PROG= mtree
MAN= mtree.5 mtree.8
SRCS= compare.c crc.c create.c excludes.c getid.c misc.c mtree.c \
only.c spec.c specspec.c verify.c
+DPADD+= ${LIBMD} ${LIBUTIL}
LDADD+= -lmd -lutil
CFLAGS+= -I${.CURDIR}/../../contrib/mknod
@@ -23,6 +24,8 @@ LDADD+= ${LIBNETBSD}
LINKS= ${BINDIR}/mtree ${BINDIR}/nmtree
MLINKS= mtree.8 nmtree.8
-NO_PIE= yes
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
.include <bsd.prog.mk>
diff --git a/usr.sbin/nmtree/tests/Makefile b/usr.sbin/nmtree/tests/Makefile
new file mode 100644
index 0000000..1df81d0
--- /dev/null
+++ b/usr.sbin/nmtree/tests/Makefile
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+TESTSRC= ${.CURDIR}/../../../contrib/netbsd-tests/usr.sbin/mtree
+.PATH: ${TESTSRC}
+
+TESTSDIR= ${TESTSBASE}/usr.sbin/nmtree
+
+ATF_TESTS_SH= nmtree_test
+ATF_TESTS_SH_SRC_nmtree_test= t_mtree.sh
+
+FILESDIR= ${TESTSDIR}
+
+# NOTE: the output from FreeBSD's nmtree displays sha256digest instead of
+# sha256; we need to mangle the specfiles to reflect this.
+.for f in mtree_d_create.out netbsd6_d_create.out
+CLEANFILES+= $f $f.tmp
+FILES+= $f
+$f: ${TESTSRC}/$f
+ sed -e 's/sha256/sha256digest/g' < ${.ALLSRC} > ${.TARGET}.tmp
+ mv ${.TARGET}.tmp ${.TARGET}
+.endfor
+
+FILES+= d_convert.in
+FILES+= d_convert_C.out
+FILES+= d_convert_C_S.out
+FILES+= d_convert_D.out
+FILES+= d_convert_D_S.out
+FILES+= d_merge.in
+FILES+= d_merge_C_M.out
+FILES+= d_merge_C_M_S.out
+
+.include <bsd.test.mk>
diff --git a/usr.sbin/nscd/query.c b/usr.sbin/nscd/query.c
index c233e19..270992e 100644
--- a/usr.sbin/nscd/query.c
+++ b/usr.sbin/nscd/query.c
@@ -1253,8 +1253,8 @@ init_query_state(int sockfd, size_t kevent_watermark, uid_t euid, gid_t egid)
retval->read_func = query_socket_read;
get_time_func(&retval->creation_time);
- memcpy(&retval->timeout, &s_configuration->query_timeout,
- sizeof(struct timeval));
+ retval->timeout.tv_sec = s_configuration->query_timeout;
+ retval->timeout.tv_usec = 0;
TRACE_OUT(init_query_state);
return (retval);
diff --git a/usr.sbin/ntp/ntp-keygen/Makefile b/usr.sbin/ntp/ntp-keygen/Makefile
index 5075350..78308fa 100644
--- a/usr.sbin/ntp/ntp-keygen/Makefile
+++ b/usr.sbin/ntp/ntp-keygen/Makefile
@@ -21,6 +21,4 @@ DPADD+= ${LIBMD} ${LIBCRYPTO}
LDADD+= -lmd -lcrypto
.endif
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/ntp/ntpd/Makefile b/usr.sbin/ntp/ntpd/Makefile
index 3422ad2..87b2d72 100644
--- a/usr.sbin/ntp/ntpd/Makefile
+++ b/usr.sbin/ntp/ntpd/Makefile
@@ -4,8 +4,6 @@ MAN=
.include <src.opts.mk>
-NO_PIE= yes
-
.PATH: ${.CURDIR}/../../../contrib/ntp/ntpd
PROG= ntpd
diff --git a/usr.sbin/ntp/ntpdate/Makefile b/usr.sbin/ntp/ntpdate/Makefile
index ea0fe1e..f55ec92 100644
--- a/usr.sbin/ntp/ntpdate/Makefile
+++ b/usr.sbin/ntp/ntpdate/Makefile
@@ -13,8 +13,6 @@ LDADD= ${LIBNTP} -lm -lmd -lrt
CLEANFILES+= .version version.c
-NO_PIE= yes
-
version.c:
sh -e ${.CURDIR}/../scripts/mkver ntpdate
diff --git a/usr.sbin/ntp/ntpdc/Makefile b/usr.sbin/ntp/ntpdc/Makefile
index e4e8960..d3c37e1 100644
--- a/usr.sbin/ntp/ntpdc/Makefile
+++ b/usr.sbin/ntp/ntpdc/Makefile
@@ -22,8 +22,6 @@ CFLAGS+= -DHAVE_LIBEDIT -DHAVE_READLINE_READLINE_H \
CLEANFILES+= .version version.c
-NO_PIE= yes
-
version.c:
sh -e ${.CURDIR}/../scripts/mkver ntpdc
diff --git a/usr.sbin/ntp/ntpq/Makefile b/usr.sbin/ntp/ntpq/Makefile
index a1ddcd4..369bd58 100644
--- a/usr.sbin/ntp/ntpq/Makefile
+++ b/usr.sbin/ntp/ntpq/Makefile
@@ -24,8 +24,6 @@ CFLAGS+= -DHAVE_LIBEDIT -DHAVE_READLINE_READLINE_H \
CLEANFILES+= .version version.c
-NO_PIE= yes
-
version.c:
sh -e ${.CURDIR}/../scripts/mkver ntpq
diff --git a/usr.sbin/ntp/ntptime/Makefile b/usr.sbin/ntp/ntptime/Makefile
index af3f905..d3bf7a7 100644
--- a/usr.sbin/ntp/ntptime/Makefile
+++ b/usr.sbin/ntp/ntptime/Makefile
@@ -10,6 +10,4 @@ CFLAGS+= -I${.CURDIR}/../../../contrib/ntp/include -I${.CURDIR}/../
DPADD= ${LIBNTP}
LDADD= ${LIBNTP}
-NO_PIE= yes
-
.include <bsd.prog.mk>
diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c
index 12e83ec..22bb61d 100644
--- a/usr.sbin/pciconf/pciconf.c
+++ b/usr.sbin/pciconf/pciconf.c
@@ -662,16 +662,16 @@ getdevice(const char *name)
* find the start of the unit.
*/
if (name[0] == '\0')
- err(1, "Empty device name");
+ errx(1, "Empty device name");
cp = strchr(name, '\0');
assert(cp != NULL && cp != name);
cp--;
while (cp != name && isdigit(cp[-1]))
cp--;
- if (cp == name)
+ if (cp == name || !isdigit(*cp))
errx(1, "Invalid device name");
if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name))
- errx(1, "Device name i2s too long");
+ errx(1, "Device name is too long");
memcpy(patterns[0].pd_name, name, cp - name);
patterns[0].pd_unit = strtol(cp, &cp, 10);
assert(*cp == '\0');
diff --git a/usr.sbin/pkg/Makefile b/usr.sbin/pkg/Makefile
index 3892ecc5..c372a3c 100644
--- a/usr.sbin/pkg/Makefile
+++ b/usr.sbin/pkg/Makefile
@@ -6,9 +6,9 @@ MAN= pkg.7
CFLAGS+=-I${.CURDIR}/../../contrib/libucl/include
.PATH: ${.CURDIR}/../../contrib/libucl/include
-DPADD= ${LIBARCHIVE} ${LIBELF} ${LIBFETCH} ${LIBUCL} ${LIBSBUF} ${LIBSSL} \
+DPADD= ${LIBARCHIVE} ${LIBFETCH} ${LIBUCL} ${LIBSBUF} ${LIBSSL} \
${LIBCRYPTO} ${LIBM}
-LDADD= -larchive -lelf -lfetch -lucl -lsbuf -lssl -lcrypto -lm
+LDADD= -larchive -lfetch ${LDUCL} -lsbuf -lssl -lcrypto -lm
USEPRIVATELIB= ucl
.include <bsd.prog.mk>
diff --git a/usr.sbin/pkg/config.c b/usr.sbin/pkg/config.c
index fded95e..3a1f18d 100644
--- a/usr.sbin/pkg/config.c
+++ b/usr.sbin/pkg/config.c
@@ -31,9 +31,9 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/sbuf.h>
-#include <sys/elf_common.h>
-#include <sys/endian.h>
#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/sysctl.h>
#include <assert.h>
#include <dirent.h>
@@ -42,14 +42,12 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <fcntl.h>
-#include <gelf.h>
#include <inttypes.h>
#include <paths.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
-#include "elf_tables.h"
#include "config.h"
#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
@@ -135,349 +133,32 @@ static struct config_entry c[] = {
},
};
-static const char *
-elf_corres_to_string(struct _elf_corres *m, int e)
-{
- int i;
-
- for (i = 0; m[i].string != NULL; i++)
- if (m[i].elf_nb == e)
- return (m[i].string);
-
- return ("unknown");
-}
-
-static const char *
-aeabi_parse_arm_attributes(void *data, size_t length)
-{
- uint32_t sect_len;
- uint8_t *section = data;
-
-#define MOVE(len) do { \
- assert(length >= (len)); \
- section += (len); \
- length -= (len); \
-} while (0)
-
- if (length == 0 || *section != 'A')
- return (NULL);
-
- MOVE(1);
-
- /* Read the section length */
- if (length < sizeof(sect_len))
- return (NULL);
-
- memcpy(&sect_len, section, sizeof(sect_len));
-
- /*
- * The section length should be no longer than the section it is within
- */
- if (sect_len > length)
- return (NULL);
-
- MOVE(sizeof(sect_len));
-
- /* Skip the vendor name */
- while (length != 0) {
- if (*section == '\0')
- break;
- MOVE(1);
- }
- if (length == 0)
- return (NULL);
- MOVE(1);
-
- while (length != 0) {
- uint32_t tag_length;
-
- switch(*section) {
- case 1: /* Tag_File */
- MOVE(1);
- if (length < sizeof(tag_length))
- return (NULL);
- memcpy(&tag_length, section, sizeof(tag_length));
- break;
- case 2: /* Tag_Section */
- case 3: /* Tag_Symbol */
- default:
- return (NULL);
- }
- /* At least space for the tag and size */
- if (tag_length <= 5)
- return (NULL);
- tag_length--;
- /* Check the tag fits */
- if (tag_length > length)
- return (NULL);
-
-#define MOVE_TAG(len) do { \
- assert(tag_length >= (len)); \
- MOVE(len); \
- tag_length -= (len); \
-} while(0)
-
- MOVE(sizeof(tag_length));
- tag_length -= sizeof(tag_length);
-
- while (tag_length != 0) {
- uint8_t tag;
-
- assert(tag_length >= length);
-
- tag = *section;
- MOVE_TAG(1);
-
- /*
- * These tag values come from:
- *
- * Addenda to, and Errata in, the ABI for the
- * ARM Architecture. Release 2.08, section 2.3.
- */
- if (tag == 6) { /* == Tag_CPU_arch */
- uint8_t val;
-
- val = *section;
- /*
- * We don't support values that require
- * more than one byte.
- */
- if (val & (1 << 7))
- return (NULL);
-
- /* We have an ARMv4 or ARMv5 */
- if (val <= 5)
- return ("arm");
- else /* We have an ARMv6+ */
- return ("armv6");
- } else if (tag == 4 || tag == 5 || tag == 32 ||
- tag == 65 || tag == 67) {
- while (*section != '\0' && length != 0)
- MOVE_TAG(1);
- if (tag_length == 0)
- return (NULL);
- /* Skip the last byte */
- MOVE_TAG(1);
- } else if ((tag >= 7 && tag <= 31) || tag == 34 ||
- tag == 36 || tag == 38 || tag == 42 || tag == 44 ||
- tag == 64 || tag == 66 || tag == 68 || tag == 70) {
- /* Skip the uleb128 data */
- while (*section & (1 << 7) && length != 0)
- MOVE_TAG(1);
- if (tag_length == 0)
- return (NULL);
- /* Skip the last byte */
- MOVE_TAG(1);
- } else
- return (NULL);
-#undef MOVE_TAG
- }
-
- break;
- }
- return (NULL);
-#undef MOVE
-}
-
static int
pkg_get_myabi(char *dest, size_t sz)
{
- Elf *elf;
- Elf_Data *data;
- Elf_Note note;
- Elf_Scn *scn;
- char *src, *osname;
- const char *arch, *abi, *fpu, *endian_corres_str;
- const char *wordsize_corres_str;
- GElf_Ehdr elfhdr;
- GElf_Shdr shdr;
- int fd, i, ret;
- uint32_t version;
-
- version = 0;
- ret = -1;
- scn = NULL;
- abi = NULL;
-
- if (elf_version(EV_CURRENT) == EV_NONE) {
- warnx("ELF library initialization failed: %s",
- elf_errmsg(-1));
- return (-1);
- }
-
- if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) {
- warn("open()");
- return (-1);
- }
+ struct utsname uts;
+ char machine_arch[255];
+ size_t len;
+ int error;
- if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
- ret = -1;
- warnx("elf_begin() failed: %s.", elf_errmsg(-1));
- goto cleanup;
- }
+ error = uname(&uts);
+ if (error)
+ return (errno);
- if (gelf_getehdr(elf, &elfhdr) == NULL) {
- ret = -1;
- warn("getehdr() failed: %s.", elf_errmsg(-1));
- goto cleanup;
- }
- while ((scn = elf_nextscn(elf, scn)) != NULL) {
- if (gelf_getshdr(scn, &shdr) != &shdr) {
- ret = -1;
- warn("getshdr() failed: %s.", elf_errmsg(-1));
- goto cleanup;
- }
+ len = sizeof(machine_arch);
+ error = sysctlbyname("hw.machine_arch", machine_arch, &len, NULL, 0);
+ if (error)
+ return (errno);
+ machine_arch[len] = '\0';
- if (shdr.sh_type == SHT_NOTE)
- break;
- }
-
- if (scn == NULL) {
- ret = -1;
- warn("failed to get the note section");
- goto cleanup;
- }
-
- data = elf_getdata(scn, NULL);
- src = data->d_buf;
- for (;;) {
- memcpy(&note, src, sizeof(Elf_Note));
- src += sizeof(Elf_Note);
- if (note.n_type == NT_VERSION)
- break;
- src += note.n_namesz + note.n_descsz;
- }
- osname = src;
- src += roundup2(note.n_namesz, 4);
- if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
- version = be32dec(src);
- else
- version = le32dec(src);
-
- for (i = 0; osname[i] != '\0'; i++)
- osname[i] = (char)tolower(osname[i]);
-
- wordsize_corres_str = elf_corres_to_string(wordsize_corres,
- (int)elfhdr.e_ident[EI_CLASS]);
-
- arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine);
-
- snprintf(dest, sz, "%s:%d",
- osname, version / 100000);
-
- ret = 0;
-
- switch (elfhdr.e_machine) {
- case EM_ARM:
- endian_corres_str = elf_corres_to_string(endian_corres,
- (int)elfhdr.e_ident[EI_DATA]);
-
- /* FreeBSD doesn't support the hard-float ABI yet */
- fpu = "softfp";
- if ((elfhdr.e_flags & 0xFF000000) != 0) {
- const char *sh_name = NULL;
- size_t shstrndx;
-
- /* This is an EABI file, the conformance level is set */
- abi = "eabi";
- /* Find which TARGET_ARCH we are building for. */
- elf_getshdrstrndx(elf, &shstrndx);
- while ((scn = elf_nextscn(elf, scn)) != NULL) {
- sh_name = NULL;
- if (gelf_getshdr(scn, &shdr) != &shdr) {
- scn = NULL;
- break;
- }
-
- sh_name = elf_strptr(elf, shstrndx,
- shdr.sh_name);
- if (sh_name == NULL)
- continue;
- if (strcmp(".ARM.attributes", sh_name) == 0)
- break;
- }
- if (scn != NULL && sh_name != NULL) {
- data = elf_getdata(scn, NULL);
- /*
- * Prior to FreeBSD 10.0 libelf would return
- * NULL from elf_getdata on the .ARM.attributes
- * section. As this was the first release to
- * get armv6 support assume a NULL value means
- * arm.
- *
- * This assumption can be removed when 9.x
- * is unsupported.
- */
- if (data != NULL) {
- arch = aeabi_parse_arm_attributes(
- data->d_buf, data->d_size);
- if (arch == NULL) {
- ret = 1;
- warn("unknown ARM ARCH");
- goto cleanup;
- }
- }
- } else {
- ret = 1;
- warn("Unable to find the .ARM.attributes "
- "section");
- goto cleanup;
- }
- } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) {
- /*
- * EABI executables all have this field set to
- * ELFOSABI_NONE, therefore it must be an oabi file.
- */
- abi = "oabi";
- } else {
- ret = 1;
- warn("unknown ARM ABI");
- goto cleanup;
- }
- snprintf(dest + strlen(dest), sz - strlen(dest),
- ":%s:%s:%s:%s:%s", arch, wordsize_corres_str,
- endian_corres_str, abi, fpu);
- break;
- case EM_MIPS:
- /*
- * this is taken from binutils sources:
- * include/elf/mips.h
- * mapping is figured out from binutils:
- * gas/config/tc-mips.c
- */
- switch (elfhdr.e_flags & EF_MIPS_ABI) {
- case E_MIPS_ABI_O32:
- abi = "o32";
- break;
- case E_MIPS_ABI_N32:
- abi = "n32";
- break;
- default:
- if (elfhdr.e_ident[EI_DATA] ==
- ELFCLASS32)
- abi = "o32";
- else if (elfhdr.e_ident[EI_DATA] ==
- ELFCLASS64)
- abi = "n64";
- break;
- }
- endian_corres_str = elf_corres_to_string(endian_corres,
- (int)elfhdr.e_ident[EI_DATA]);
-
- snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s",
- arch, wordsize_corres_str, endian_corres_str, abi);
- break;
- default:
- snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s",
- arch, wordsize_corres_str);
- }
-
-cleanup:
- if (elf != NULL)
- elf_end(elf);
+ /*
+ * Use __FreeBSD_version rather than kernel version (uts.release) for
+ * use in jails. This is equivalent to the value of uname -U.
+ */
+ snprintf(dest, sz, "%s:%d:%s", uts.sysname, __FreeBSD_version/100000,
+ machine_arch);
- close(fd);
- return (ret);
+ return (error);
}
static void
diff --git a/usr.sbin/pmcstat/pmcstat.8 b/usr.sbin/pmcstat/pmcstat.8
index 6662d43..d34cb6b 100644
--- a/usr.sbin/pmcstat/pmcstat.8
+++ b/usr.sbin/pmcstat/pmcstat.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 16, 2014
+.Dd Oct 27, 2014
.Dt PMCSTAT 8
.Os
.Sh NAME
@@ -235,7 +235,7 @@ lookup information is available.
This option requires the
.Fl R
option to read in samples that were previously collected and
-saved with the
+saved with the
.Fl o
option.
.It Fl c Ar cpu-spec
@@ -254,6 +254,12 @@ Toggle between process mode PMCs measuring events for the target
process' current and future children or only measuring events for
the target process.
The default is to measure events for the target process alone.
+(it has to be passed in the command line prior to
+.Fl p ,
+.Fl s ,
+.Fl P ,
+or
+.Fl S ) .
.It Fl f Ar pluginopt
Pass option string to the active plugin.
.br
diff --git a/usr.sbin/ppp/Makefile b/usr.sbin/ppp/Makefile
index beea0ab..dda493e 100644
--- a/usr.sbin/ppp/Makefile
+++ b/usr.sbin/ppp/Makefile
@@ -33,9 +33,9 @@ PPP_NO_PAM=
.endif
.if defined(PPP_NO_SUID)
-BINMODE=550
+BINMODE=554
.else
-BINMODE=4550
+BINMODE=4554
BINOWN= root
.endif
BINGRP= network
diff --git a/usr.sbin/praliases/Makefile b/usr.sbin/praliases/Makefile
index e1a9a2a..120028d 100644
--- a/usr.sbin/praliases/Makefile
+++ b/usr.sbin/praliases/Makefile
@@ -34,8 +34,6 @@ LDFLAGS+=${SENDMAIL_LDFLAGS}
DPADD+= ${SENDMAIL_DPADD}
LDADD+= ${SENDMAIL_LDADD}
-NO_PIE= yes
-
sm_os.h:
ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
diff --git a/usr.sbin/pstat/pstat.8 b/usr.sbin/pstat/pstat.8
index 5e3760c..cd13994 100644
--- a/usr.sbin/pstat/pstat.8
+++ b/usr.sbin/pstat/pstat.8
@@ -35,7 +35,7 @@
.\" @(#)pstat.8 8.5 (Berkeley) 5/13/94
.\" $FreeBSD$
.\"
-.Dd August 20, 2008
+.Dd October 11, 2014
.Dt PSTAT 8
.Os
.Sh NAME
@@ -170,7 +170,7 @@ Low water mark for output.
.It COL
Calculated column position of terminal.
.It SESS
-Kernel address of the session structure.
+Process ID of the session leader.
.It PGID
Process group for which this is the controlling terminal.
.It STATE
diff --git a/usr.sbin/pw/Makefile b/usr.sbin/pw/Makefile
index eae0b87..8c5acf9 100644
--- a/usr.sbin/pw/Makefile
+++ b/usr.sbin/pw/Makefile
@@ -11,4 +11,10 @@ WARNS?= 2
DPADD= ${LIBCRYPT} ${LIBUTIL}
LDADD= -lcrypt -lutil
+.include <src.opts.mk>
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/pw/pw.c b/usr.sbin/pw/pw.c
index b0ac728..ff48db7 100644
--- a/usr.sbin/pw/pw.c
+++ b/usr.sbin/pw/pw.c
@@ -98,6 +98,7 @@ main(int argc, char *argv[])
int which = -1;
char *config = NULL;
struct userconf *cnf;
+ struct stat st;
static const char *opts[W_NUM][M_NUM] =
{
@@ -143,6 +144,13 @@ main(int argc, char *argv[])
if (argv[1][1] == 'V') {
optarg = &argv[1][2];
if (*optarg == '\0') {
+ if (stat(argv[2], &st) != 0)
+ errx(EX_OSFILE, \
+ "no such directory `%s'",
+ argv[2]);
+ if (!S_ISDIR(st.st_mode))
+ errx(EX_OSFILE, "`%s' not a "
+ "directory", argv[2]);
optarg = argv[2];
++argv;
--argc;
diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c
index 391e477..b20ce88 100644
--- a/usr.sbin/pw/pw_group.c
+++ b/usr.sbin/pw/pw_group.c
@@ -51,6 +51,7 @@ int
pw_group(struct userconf * cnf, int mode, struct cargs * args)
{
int rc;
+ struct carg *a_newname = getarg(args, 'l');
struct carg *a_name = getarg(args, 'n');
struct carg *a_gid = getarg(args, 'g');
struct carg *arg;
@@ -66,6 +67,11 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
NULL
};
+ if (a_gid != NULL) {
+ if (strspn(a_gid->val, "0123456789") != strlen(a_gid->val))
+ errx(EX_USAGE, "-g expects a number");
+ }
+
if (mode == M_LOCK || mode == M_UNLOCK)
errx(EX_USAGE, "'lock' command is not available for groups");
@@ -140,8 +146,8 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
if (a_gid)
grp->gr_gid = (gid_t) atoi(a_gid->val);
- if ((arg = getarg(args, 'l')) != NULL)
- grp->gr_name = pw_checkname((u_char *)arg->val, 0);
+ if (a_newname != NULL)
+ grp->gr_name = pw_checkname((u_char *)a_newname->val, 0);
} else {
if (a_name == NULL) /* Required */
errx(EX_DATAERR, "group name required");
@@ -270,8 +276,10 @@ pw_group(struct userconf * cnf, int mode, struct cargs * args)
warn("group update");
return EX_IOERR;
}
+
+ arg = a_newname != NULL ? a_newname : a_name;
/* grp may have been invalidated */
- if ((grp = GETGRNAM(a_name->val)) == NULL)
+ if ((grp = GETGRNAM(arg->val)) == NULL)
errx(EX_SOFTWARE, "group disappeared during update");
pw_log(cnf, mode, W_GROUP, "%s(%ld)", grp->gr_name, (long) grp->gr_gid);
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
index 36c5d9d..483148a 100644
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -321,6 +321,9 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
(a_uid = a_name)->ch = 'u';
a_name = NULL;
}
+ } else {
+ if (strspn(a_uid->val, "0123456789") != strlen(a_uid->val))
+ errx(EX_USAGE, "-u expects a number");
}
/*
@@ -615,7 +618,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
pwd->pw_dir = pw_homepolicy(cnf, args, pwd->pw_name);
pwd->pw_shell = pw_shellpolicy(cnf, args, NULL);
lc = login_getpwclass(pwd);
- if (lc == NULL || login_setcryptfmt(lc, "md5", NULL) == NULL)
+ if (lc == NULL || login_setcryptfmt(lc, "sha512", NULL) == NULL)
warn("setting crypt(3) format");
login_close(lc);
pwd->pw_passwd = pw_password(cnf, args, pwd->pw_name);
@@ -690,7 +693,7 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
} else {
lc = login_getpwclass(pwd);
if (lc == NULL ||
- login_setcryptfmt(lc, "md5", NULL) == NULL)
+ login_setcryptfmt(lc, "sha512", NULL) == NULL)
warn("setting crypt(3) format");
login_close(lc);
pwd->pw_passwd = pw_pwcrypt(line);
@@ -751,7 +754,25 @@ pw_user(struct userconf * cnf, int mode, struct cargs * args)
*/
if (mode == M_ADD || getarg(args, 'G') != NULL) {
- int i;
+ int i, j;
+ /* First remove the user from all group */
+ SETGRENT();
+ while ((grp = GETGRENT()) != NULL) {
+ char group[MAXLOGNAME];
+ if (grp->gr_mem == NULL)
+ continue;
+ for (i = 0; grp->gr_mem[i] != NULL; i++) {
+ if (strcmp(grp->gr_mem[i] , pwd->pw_name) != 0)
+ continue;
+ for (j = i; grp->gr_mem[j] != NULL ; j++)
+ grp->gr_mem[j] = grp->gr_mem[j+1];
+ strlcpy(group, grp->gr_name, MAXLOGNAME);
+ chggrent(group, grp);
+ }
+ }
+ ENDGRENT();
+
+ /* now add to group where needed */
for (i = 0; cnf->groups[i] != NULL; i++) {
grp = GETGRNAM(cnf->groups[i]);
grp = gr_add(grp, pwd->pw_name);
diff --git a/usr.sbin/pw/tests/Makefile b/usr.sbin/pw/tests/Makefile
new file mode 100644
index 0000000..6bc9433
--- /dev/null
+++ b/usr.sbin/pw/tests/Makefile
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+TESTSRC= ${.CURDIR}/../../../contrib/netbsd-tests/usr.sbin/useradd
+.PATH: ${TESTSRC}
+
+TESTSDIR= ${TESTSBASE}/usr.sbin/pw
+
+ATF_TESTS_SH= pw_delete pw_lock pw_modify pw_etcdir
+
+TEST_METADATA.pw_delete+= required_user="root"
+TEST_METADATA.pw_modify+= required_user="root"
+
+FILES= group helper_functions.shin master.passwd
+FILESDIR= ${TESTSDIR}
+
+ATF_TESTS_SH+= pw_test
+# - user{add,del} does not exist on FreeBSD; use pw user{add,del} instead
+# - The command passes on FreeBSD
+ATF_TESTS_SH_SED_pw_test= -e 's/useradd /pw useradd /'
+ATF_TESTS_SH_SED_pw_test+= -e 's/userdel /pw userdel /'
+ATF_TESTS_SH_SED_pw_test+= -e '/atf_expect_fail "PR bin\/39546"/d'
+ATF_TESTS_SH_SRC_pw_test= t_useradd.sh
+
+.include <bsd.test.mk>
diff --git a/usr.sbin/pw/tests/group b/usr.sbin/pw/tests/group
new file mode 100644
index 0000000..620c588
--- /dev/null
+++ b/usr.sbin/pw/tests/group
@@ -0,0 +1,3 @@
+# $FreeBSD$
+#
+wheel:*:0:root
diff --git a/usr.sbin/pw/tests/helper_functions.shin b/usr.sbin/pw/tests/helper_functions.shin
new file mode 100755
index 0000000..f87b1e7
--- /dev/null
+++ b/usr.sbin/pw/tests/helper_functions.shin
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+# Workdir to run tests in
+TESTDIR=$(atf_get_srcdir)
+
+# Populate the files pw needs to use into $HOME/etc
+populate_etc_skel() {
+ cp ${TESTDIR}/master.passwd ${HOME} || \
+ atf_fail "Populating master.passwd in ${HOME}"
+ cp ${TESTDIR}/group ${HOME} || atf_fail "Populating group in ${HOME}"
+
+ # Generate the passwd file
+ pwd_mkdb -p -d ${HOME} ${HOME}/master.passwd || \
+ atf_fail "generate passwd from master.passwd"
+}
diff --git a/usr.sbin/pw/tests/master.passwd b/usr.sbin/pw/tests/master.passwd
new file mode 100644
index 0000000..f7dc837
--- /dev/null
+++ b/usr.sbin/pw/tests/master.passwd
@@ -0,0 +1,4 @@
+# $FreeBSD$
+#
+root:*:0:0::0:0:Charlie &:/root:/bin/csh
+toor:*:0:0::0:0:Bourne-again Superuser:/root:
diff --git a/usr.sbin/pw/tests/pw_delete.sh b/usr.sbin/pw/tests/pw_delete.sh
new file mode 100755
index 0000000..02a9ade
--- /dev/null
+++ b/usr.sbin/pw/tests/pw_delete.sh
@@ -0,0 +1,47 @@
+# $FreeBSD$
+
+# Import helper functions
+. $(atf_get_srcdir)/helper_functions.shin
+
+# Test that a user can be deleted when another user is part of this
+# user's default group and does not go into an infinate loop.
+# PR: 191427
+atf_test_case rmuser_seperate_group cleanup
+rmuser_seperate_group_head() {
+ atf_set "timeout" "30"
+}
+rmuser_seperate_group_body() {
+ populate_etc_skel
+ pw -V ${HOME} useradd test || atf_fail "Creating test user"
+ pw -V ${HOME} groupmod test -M 'test,root' || \
+ atf_fail "Modifying the group"
+ pw -V ${HOME} userdel test || atf_fail "Delete the test user"
+}
+
+atf_test_case group_do_not_delete_wheel_if_group_unknown
+group_do_not_delete_wheel_if_group_unknown_head() {
+ atf_set "descr" "Make sure we do not consider gid 0 an unknown group"
+}
+
+group_do_not_delete_wheel_if_group_unknown_body() {
+ populate_etc_skel
+ atf_check -s exit:0 -o inline:"wheel:*:0:root\n" -x pw -V ${HOME} groupshow wheel
+ atf_check -e inline:"pw: -g expects a number\n" -s exit:64 -x pw -V ${HOME} groupdel -g I_do_not_exist
+ atf_check -s exit:0 -o inline:"wheel:*:0:root\n" -x pw -V ${HOME} groupshow wheel
+}
+
+atf_test_case user_do_not_try_to_delete_root_if_user_unknown
+user_do_not_try_to_delete_root_if_user_unknown_head() {
+ atf_set "descr" "Make sure not to try to remove root if deleting an unknown user"
+}
+
+user_do_not_try_to_delete_root_if_user_unknown_body() {
+ populate_etc_skel
+ atf_check -e inline:"pw: -u expects a number\n" -s exit:64 -x pw -V ${HOME} userdel -u plop
+}
+
+atf_init_test_cases() {
+ atf_add_test_case rmuser_seperate_group
+ atf_add_test_case group_do_not_delete_wheel_if_group_unknown
+ atf_add_test_case user_do_not_try_to_delete_root_if_user_unknown
+}
diff --git a/usr.sbin/pw/tests/pw_etcdir.sh b/usr.sbin/pw/tests/pw_etcdir.sh
new file mode 100755
index 0000000..b237789
--- /dev/null
+++ b/usr.sbin/pw/tests/pw_etcdir.sh
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+# When the '-V directory' option is provided, the directory must exist
+atf_test_case etcdir_must_exist
+etcdir_must_exist_head() {
+ atf_set "descr" "When the '-V directory' option is provided, the directory must exist"
+}
+
+etcdir_must_exist_body() {
+ local fakedir="/this_directory_does_not_exist"
+ atf_check -e inline:"pw: no such directory \`$fakedir'\n" \
+ -s exit:72 -x pw -V ${fakedir} usershow root
+}
+
+atf_init_test_cases() {
+ atf_add_test_case etcdir_must_exist
+}
+
diff --git a/usr.sbin/pw/tests/pw_lock.sh b/usr.sbin/pw/tests/pw_lock.sh
new file mode 100755
index 0000000..070a6f9
--- /dev/null
+++ b/usr.sbin/pw/tests/pw_lock.sh
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+# Import helper functions
+. $(atf_get_srcdir)/helper_functions.shin
+
+# Test locking and unlocking a user account
+atf_test_case user_locking cleanup
+user_locking_body() {
+ populate_etc_skel
+ pw -V ${HOME} useradd test || atf_fail "Creating test user"
+ pw -V ${HOME} lock test || atf_fail "Locking the user"
+ atf_check -s exit:0 -o match:"^test:\*LOCKED\*\*:1001:" \
+ grep "^test:\*LOCKED\*\*:1001:" $HOME/master.passwd
+ pw -V ${HOME} unlock test || atf_fail "Locking the user"
+ atf_check -s exit:0 -o match:"^test:\*:1001:" \
+ grep "^test:\*:1001:" $HOME/master.passwd
+}
+
+
+atf_init_test_cases() {
+ atf_add_test_case user_locking
+}
diff --git a/usr.sbin/pw/tests/pw_modify.sh b/usr.sbin/pw/tests/pw_modify.sh
new file mode 100755
index 0000000..b81f105
--- /dev/null
+++ b/usr.sbin/pw/tests/pw_modify.sh
@@ -0,0 +1,80 @@
+# $FreeBSD$
+
+# Import helper functions
+. $(atf_get_srcdir)/helper_functions.shin
+
+
+# Test adding & removing a user from a group
+atf_test_case groupmod_user
+groupmod_user_body() {
+ populate_etc_skel
+ atf_check -s exit:0 pw -V ${HOME} addgroup test
+ atf_check -s exit:0 pw -V ${HOME} groupmod test -m root
+ atf_check -s exit:0 -o match:"^test:\*:1001:root$" \
+ grep "^test:\*:.*:root$" $HOME/group
+ atf_check -s exit:0 pw -V ${HOME} groupmod test -d root
+ atf_check -s exit:0 -o match:"^test:\*:1001:$" \
+ grep "^test:\*:.*:$" $HOME/group
+}
+
+
+# Test adding and removing a user that does not exist
+atf_test_case groupmod_invalid_user
+groupmod_invalid_user_body() {
+ populate_etc_skel
+ atf_check -s exit:0 pw -V ${HOME} addgroup test
+ atf_check -s exit:67 -e match:"does not exist" pw -V ${HOME} groupmod test -m foo
+ atf_check -s exit:0 pw -V ${HOME} groupmod test -d foo
+}
+
+atf_test_case groupmod_bug_193704
+groupmod_bug_193704_head() {
+ atf_set "descr" "Regression test for the #193704 bug"
+}
+groupmod_bug_193704_body() {
+ populate_etc_skel
+ atf_check -s exit:0 -x pw -V ${HOME} groupadd test
+ atf_check -s exit:0 -x pw -V ${HOME} groupmod test -l newgroupname
+ atf_check -s exit:65 -e match:"^pw: unknown group" -x pw -V ${HOME} groupshow test
+}
+
+atf_test_case usermod_bug_185666
+usermod_bug_185666_head() {
+ atf_set "descr" "Regression test for the #185666 bug"
+}
+
+usermod_bug_185666_body() {
+ populate_etc_skel
+ atf_check -s exit:0 -x pw -V ${HOME} useradd testuser
+ atf_check -s exit:0 -x pw -V ${HOME} groupadd testgroup
+ atf_check -s exit:0 -x pw -V ${HOME} groupadd testgroup2
+ atf_check -s exit:0 -x pw -V ${HOME} usermod testuser -G testgroup
+ atf_check -o inline:"testuser:*:1001:\n" -x pw -V${HOME} groupshow testuser
+ atf_check -o inline:"testgroup:*:1002:testuser\n" -x pw -V ${HOME} groupshow testgroup
+ atf_check -o inline:"testgroup2:*:1003:\n" -x pw -V${HOME} groupshow testgroup2
+ atf_check -s exit:0 -x pw -V ${HOME} usermod testuser -G testgroup2
+ atf_check -o inline:"testuser:*:1001:\n" -x pw -V ${HOME} groupshow testuser
+ atf_check -o inline:"testgroup:*:1002:\n" -x pw -V ${HOME} groupshow testgroup
+ atf_check -o inline:"testgroup2:*:1003:testuser\n" -x pw -V ${HOME} groupshow testgroup2
+}
+
+atf_test_case do_not_duplicate_group_on_gid_change
+do_not_duplicate_group_on_gid_change_head() {
+ atf_set "descr" "Do not duplicate group on gid change"
+}
+
+do_not_duplicate_group_on_gid_change_body() {
+ populate_etc_skel
+ atf_check -s exit:0 -x pw -V ${HOME} groupadd testgroup
+ atf_check -s exit:0 -x pw -V ${HOME} groupmod testgroup -g 12345
+ # use grep to see if the entry has not be duplicated
+ atf_check -o inline:"testgroup:*:12345:\n" -s exit:0 -x grep "^testgroup" ${HOME}/group
+}
+
+atf_init_test_cases() {
+ atf_add_test_case groupmod_user
+ atf_add_test_case groupmod_invalid_user
+ atf_add_test_case groupmod_bug_193704
+ atf_add_test_case usermod_bug_185666
+ atf_add_test_case do_not_duplicate_group_on_gid_change
+}
diff --git a/usr.sbin/route6d/route6d.c b/usr.sbin/route6d/route6d.c
index fc45615..258219b 100644
--- a/usr.sbin/route6d/route6d.c
+++ b/usr.sbin/route6d/route6d.c
@@ -2835,6 +2835,8 @@ addroute(struct riprt *rrt,
sin6->sin6_len = sizeof(struct sockaddr_in6);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr = *gw;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ sin6->sin6_scope_id = ifcp->ifc_index;
sin6 = (struct sockaddr_in6 *)((char *)sin6 + ROUNDUP(sin6->sin6_len));
/* Netmask */
sin6->sin6_len = sizeof(struct sockaddr_in6);
diff --git a/usr.sbin/rpcbind/Makefile b/usr.sbin/rpcbind/Makefile
index 2780001..44a030e 100644
--- a/usr.sbin/rpcbind/Makefile
+++ b/usr.sbin/rpcbind/Makefile
@@ -16,7 +16,7 @@ CFLAGS+= -DINET6
WARNS?= 1
-DPADD= ${LIBWRAP} ${LIBUTIL}
-LDADD= -lwrap -lutil
+DPADD= ${LIBWRAP}
+LDADD= -lwrap
.include <bsd.prog.mk>
diff --git a/usr.sbin/rtadvd/advcap.c b/usr.sbin/rtadvd/advcap.c
index 7280f40..542e066 100644
--- a/usr.sbin/rtadvd/advcap.c
+++ b/usr.sbin/rtadvd/advcap.c
@@ -149,9 +149,9 @@ getent(char *bp, char *name, const char *cfile)
}
break;
}
- if (cp >= bp + BUFSIZ) {
+ if (cp >= bp + BUFSIZ - 1) {
write(STDERR_FILENO, "Remcap entry too long\n",
- 23);
+ 22);
break;
} else
*cp++ = c;
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index f0e11a3..5c9d778 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -77,10 +77,10 @@ static time_t prefix_timo = (60 * 120); /* 2 hours.
static struct rtadvd_timer *prefix_timeout(void *);
static void makeentry(char *, size_t, int, const char *);
-static size_t dname_labelenc(char *, const char *);
+static ssize_t dname_labelenc(char *, const char *);
/* Encode domain name label encoding in RFC 1035 Section 3.1 */
-static size_t
+static ssize_t
dname_labelenc(char *dst, const char *src)
{
char *dst_origin;
@@ -90,6 +90,8 @@ dname_labelenc(char *dst, const char *src)
dst_origin = dst;
len = strlen(src);
+ if (len + len / 64 + 1 + 1 > DNAME_LABELENC_MAXLEN)
+ return (-1);
/* Length fields per 63 octets + '\0' (<= DNAME_LABELENC_MAXLEN) */
memset(dst, 0, len + len / 64 + 1 + 1);
@@ -98,9 +100,13 @@ dname_labelenc(char *dst, const char *src)
/* Put a length field with 63 octet limitation first. */
p = strchr(src, '.');
if (p == NULL)
- *dst++ = len = MIN(63, len);
+ *dst = len = MIN(63, len);
+ else
+ *dst = len = MIN(63, p - src);
+ if (dst + 1 + len < dst_origin + DNAME_LABELENC_MAXLEN)
+ dst++;
else
- *dst++ = len = MIN(63, p - src);
+ return (-1);
/* Copy 63 octets at most. */
memcpy(dst, src, len);
dst += len;
@@ -866,6 +872,11 @@ getconfig_free_rdn:
abuf[c] = '\0';
ELM_MALLOC(dnsa, goto getconfig_free_dns);
dnsa->da_len = dname_labelenc(dnsa->da_dom, abuf);
+ if (dnsa->da_len < 0) {
+ syslog(LOG_ERR, "Invalid dnssl entry: %s",
+ abuf);
+ goto getconfig_free_dns;
+ }
syslog(LOG_DEBUG, "<%s>: dnsa->da_len = %d", __func__,
dnsa->da_len);
TAILQ_INSERT_TAIL(&dns->dn_list, dnsa, da_next);
diff --git a/usr.sbin/rtsold/rtsol.c b/usr.sbin/rtsold/rtsol.c
index c9b3d44..118206a 100644
--- a/usr.sbin/rtsold/rtsol.c
+++ b/usr.sbin/rtsold/rtsol.c
@@ -933,7 +933,8 @@ dname_labeldec(char *dst, size_t dlen, const char *src)
dst_origin = dst;
memset(dst, '\0', dlen);
while (src && (len = (uint8_t)(*src++) & 0x3f) &&
- (src + len) <= src_last) {
+ (src + len) <= src_last &&
+ (dst - dst_origin < (ssize_t)dlen)) {
if (dst != dst_origin)
*dst++ = '.';
warnmsg(LOG_DEBUG, __func__, "labellen = %zd", len);
diff --git a/usr.sbin/sendmail/Makefile b/usr.sbin/sendmail/Makefile
index ffd22bd..893b6fd 100644
--- a/usr.sbin/sendmail/Makefile
+++ b/usr.sbin/sendmail/Makefile
@@ -7,8 +7,6 @@ SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
SMDIR= ${SENDMAIL_DIR}/src
.PATH: ${SMDIR}
-NO_PIE= yes
-
BINDIR= /usr/libexec/sendmail
PROG= sendmail
diff --git a/usr.sbin/smbmsg/smbmsg.8 b/usr.sbin/smbmsg/smbmsg.8
index 39caa67..faa5bb0 100644
--- a/usr.sbin/smbmsg/smbmsg.8
+++ b/usr.sbin/smbmsg/smbmsg.8
@@ -59,7 +59,7 @@ The first form shown in the synopsis can be used to
the devices on the SMBus.
This is done by sending each valid device address one
receive byte, and one quick read message, respectively.
-Devices that respond to these requests will by displayed
+Devices that respond to these requests will be displayed
by their device address, followed by the strings
.Ql r ,
.Ql w ,
diff --git a/usr.sbin/sysrc/sysrc b/usr.sbin/sysrc/sysrc
index f37a496..8a1a863 100644
--- a/usr.sbin/sysrc/sysrc
+++ b/usr.sbin/sysrc/sysrc
@@ -40,7 +40,7 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
#
# Version information
#
-SYSRC_VERSION="6.1 Jul-18,2014"
+SYSRC_VERSION="6.2 Nov-3,2014"
#
# Options
@@ -80,7 +80,7 @@ die()
#
usage()
{
- f_err "Usage: %s [OPTIONS] name[=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] name[[+]=value] ...\n" "$pgm"
f_err "Try \`%s --help' for more information.\n" "$pgm"
die
}
@@ -94,7 +94,7 @@ help()
local optfmt="\t%-11s%s\n"
local envfmt="\t%-17s%s\n"
- f_err "Usage: %s [OPTIONS] name[=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] name[[+]=value] ...\n" "$pgm"
f_err "OPTIONS:\n"
f_err "$optfmt" "-a" \
@@ -529,6 +529,11 @@ status=$SUCCESS
while [ $# -gt 0 ]; do
NAME="${1%%=*}"
+ case "$NAME" in
+ *+) mode=APPEND NAME="${NAME%+}" ;;
+ *) mode=ASSIGN
+ esac
+
[ "$DESCRIBE" ] && \
echo "$NAME: $( f_sysrc_desc "$NAME" )"
@@ -593,14 +598,25 @@ while [ $# -gt 0 ]; do
#
if [ ! "$SHOW_VALUE" ]; then
echo "$NAME"
- f_sysrc_set "$NAME" "${1#*}"
+ case "$mode" in
+ APPEND)
+ before=$( f_sysrc_get "$NAME" )
+ f_sysrc_set "$NAME" "$before${1#*=}"
+ ;;
+ *)
+ f_sysrc_set "$NAME" "${1#*=}"
+ esac
else
if [ "$SHOW_FILE" ]; then
before=$( f_sysrc_find "$NAME" )
else
before=$( f_sysrc_get "$NAME" )
fi
- if f_sysrc_set "$NAME" "${1#*=}"; then
+ if case "$mode" in
+ APPEND) f_sysrc_set "$NAME" "$before${1#*=}" ;;
+ *) f_sysrc_set "$NAME" "${1#*=}"
+ esac
+ then
if [ "$SHOW_FILE" ]; then
after=$( f_sysrc_find "$NAME" )
else
diff --git a/usr.sbin/sysrc/sysrc.8 b/usr.sbin/sysrc/sysrc.8
index 28d8de6..cba481f 100644
--- a/usr.sbin/sysrc/sysrc.8
+++ b/usr.sbin/sysrc/sysrc.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd Jul 18, 2014
+.Dd November 4, 2014
.Dt SYSRC 8
.Os
.Sh NAME
@@ -35,7 +35,7 @@
.Op Fl cdDeFhinNqvx
.Op Fl f Ar file
.Op Fl j Ar jail | Fl R Ar dir
-.Ar name Ns Op = Ns Ar value
+.Ar name Ns Op Ns Oo + Oc Ns = Ns Ar value
.Ar ...
.Nm
.Op Fl cdDeFhinNqvx
@@ -135,6 +135,10 @@ It shares the `-e' and `-n' options
and also has the same
.Ql name[=value]
syntax for making queries/assignments.
+In addition
+.Pq unlike Xr sysctl 8 ,
+.Ql name+=value
+is supported for appending values.
.Pp
However, while
.Xr sysctl 8
@@ -243,6 +247,12 @@ Working on other files, such as
-f /etc/crontab MAILTO
.Dl returns the value of the MAILTO setting Pq if configured .
.Pp
+Appending to existing values:
+.Pp
+.Nm
+\&cloned_interfaces+=" gif0"
+.Dl appends Qo \ gif0 Qc to $cloned_interfaces .
+.Pp
In addition to the above syntax,
.Nm
also supports inline
diff --git a/usr.sbin/timed/timedc/timedc.c b/usr.sbin/timed/timedc/timedc.c
index f81da89..2f3e508 100644
--- a/usr.sbin/timed/timedc/timedc.c
+++ b/usr.sbin/timed/timedc/timedc.c
@@ -66,7 +66,7 @@ main(int argc, char *argv[])
{
register struct cmd *c;
- openlog("timedc", LOG_ODELAY, LOG_AUTH);
+ openlog("timedc", 0, LOG_AUTH);
/*
* security dictates!
diff --git a/usr.sbin/traceroute/Makefile b/usr.sbin/traceroute/Makefile
index 103d206..12f9a0b 100644
--- a/usr.sbin/traceroute/Makefile
+++ b/usr.sbin/traceroute/Makefile
@@ -13,7 +13,7 @@ CLEANFILES= version.c
CFLAGS+= -DHAVE_SYS_SELECT_H=1 -DHAVE_SYS_SOCKIO_H=1 \
-DHAVE_NET_ROUTE_H=1 -DHAVE_NET_IF_DL_H=1 \
-DHAVE_STRERROR=1 -DHAVE_USLEEP=1 \
- -DHAVE_SYS_SYSCTL_H=1 \
+ -DHAVE_SYS_SYSCTL_H=1 -DBYTESWAP_IP_HDR=1 \
-DHAVE_SETLINEBUF=1 -DHAVE_RAW_OPTIONS=1 \
-DHAVE_SOCKADDR_SA_LEN=1 -DHAVE_ICMP_NEXTMTU=1
.if !defined(TRACEROUTE_NO_IPSEC)
diff --git a/usr.sbin/tzsetup/tzsetup.c b/usr.sbin/tzsetup/tzsetup.c
index cea8533..71ba63b 100644
--- a/usr.sbin/tzsetup/tzsetup.c
+++ b/usr.sbin/tzsetup/tzsetup.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/stat.h>
+#include <sys/sysctl.h>
#include <dialog.h>
@@ -910,8 +911,16 @@ main(int argc, char **argv)
{
char title[64], prompt[128];
int c, fd, rv, skiputc;
+ char vm_guest[16] = "";
+ size_t len = sizeof(vm_guest);
skiputc = 0;
+
+ /* Default skiputc to 1 for VM guests */
+ if (sysctlbyname("kern.vm_guest", vm_guest, &len, NULL, 0) == 0 &&
+ strcmp(vm_guest, "none") != 0)
+ skiputc = 1;
+
while ((c = getopt(argc, argv, "C:nrs")) != -1) {
switch(c) {
case 'C':
diff --git a/usr.sbin/unbound/anchor/Makefile b/usr.sbin/unbound/anchor/Makefile
index 1404766..970fb70 100644
--- a/usr.sbin/unbound/anchor/Makefile
+++ b/usr.sbin/unbound/anchor/Makefile
@@ -11,7 +11,7 @@ PROG= unbound-anchor
SRCS= unbound-anchor.c
CFLAGS= -I${UNBOUNDDIR} -I${LDNSDIR} -I${EXPATDIR}/lib
DPADD= ${LIBUNBOUND} ${LIBLDNS} ${LIBUTIL} ${LIBBSDXML} ${LIBSSL} ${LIBCRYPTO} ${LIBPTHREAD}
-LDADD= -lunbound -lldns -lutil -lbsdxml -lssl -lcrypto -lpthread
+LDADD= ${LDUNBOUND} ${LDLDNS} -lutil -lbsdxml -lssl -lcrypto -lpthread
USEPRIVATELIB= ldns
MAN= unbound-anchor.8
diff --git a/usr.sbin/unbound/checkconf/Makefile b/usr.sbin/unbound/checkconf/Makefile
index 6a58806..0993d3d 100644
--- a/usr.sbin/unbound/checkconf/Makefile
+++ b/usr.sbin/unbound/checkconf/Makefile
@@ -10,7 +10,7 @@ PROG= unbound-checkconf
SRCS= unbound-checkconf.c worker_cb.c
CFLAGS= -I${UNBOUNDDIR} -I${LDNSDIR}
DPADD= ${LIBUNBOUND} ${LIBLDNS} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBPTHREAD}
-LDADD= -lunbound -lldns -lutil -lssl -lcrypto -lpthread
+LDADD= ${LDUNBOUND} ${LDLDNS} -lutil -lssl -lcrypto -lpthread
USEPRIVATELIB= ldns
MAN= unbound-checkconf.8
diff --git a/usr.sbin/unbound/control/Makefile b/usr.sbin/unbound/control/Makefile
index 7056a9e..2989e73 100644
--- a/usr.sbin/unbound/control/Makefile
+++ b/usr.sbin/unbound/control/Makefile
@@ -11,7 +11,7 @@ SCRIPTS= unbound-control-setup.sh
SRCS= unbound-control.c worker_cb.c
CFLAGS= -I${UNBOUNDDIR} -I${LDNSDIR}
DPADD= ${LIBUNBOUND} ${LIBLDNS} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBPTHREAD}
-LDADD= -lunbound -lldns -lutil -lssl -lcrypto -lpthread
+LDADD= ${LDUNBOUND} ${LDLDNS} -lutil -lssl -lcrypto -lpthread
USEPRIVATELIB= ldns
MAN= unbound-control.8
diff --git a/usr.sbin/unbound/daemon/Makefile b/usr.sbin/unbound/daemon/Makefile
index 0f9044f..a8b1bb2 100644
--- a/usr.sbin/unbound/daemon/Makefile
+++ b/usr.sbin/unbound/daemon/Makefile
@@ -10,7 +10,7 @@ PROG= unbound
SRCS= acl_list.c cachedump.c daemon.c remote.c stats.c unbound.c worker.c
CFLAGS= -I${UNBOUNDDIR} -I${LDNSDIR}
DPADD= ${LIBUNBOUND} ${LIBLDNS} ${LIBUTIL} ${LIBSSL} ${LIBCRYPTO} ${LIBPTHREAD}
-LDADD= -lunbound -lldns -lutil -lssl -lcrypto -lpthread
+LDADD= ${LDUNBOUND} ${LDLDNS} -lutil -lssl -lcrypto -lpthread
USEPRIVATELIB= ldns
MAN= unbound.8 unbound.conf.5
diff --git a/usr.sbin/unbound/local-setup/local-unbound-setup.sh b/usr.sbin/unbound/local-setup/local-unbound-setup.sh
index 837cf9a..a16e6d0 100755
--- a/usr.sbin/unbound/local-setup/local-unbound-setup.sh
+++ b/usr.sbin/unbound/local-setup/local-unbound-setup.sh
@@ -178,7 +178,7 @@ gen_forward_conf() {
echo "forward-zone:"
echo " name: ."
for forwarder ; do
- if expr "${forwarder}" : "^[0-9:.]\{1,\}$" >/dev/null ; then
+ if expr "${forwarder}" : "^[0-9A-Fa-f:.]\{1,\}$" >/dev/null ; then
echo " forward-addr: ${forwarder}"
else
echo " forward-host: ${forwarder}"
diff --git a/usr.sbin/usbconfig/dump.c b/usr.sbin/usbconfig/dump.c
index 52dd132..df5cde0 100644
--- a/usr.sbin/usbconfig/dump.c
+++ b/usr.sbin/usbconfig/dump.c
@@ -110,7 +110,6 @@ dump_field(struct libusb20_device *pdev, const char *plevel,
printf(" <OUT>\n");
return;
}
-
if (strcmp(field, "bmAttributes") == 0) {
switch (value & 0x03) {
case 0:
@@ -142,7 +141,6 @@ dump_field(struct libusb20_device *pdev, const char *plevel,
return;
}
}
-
if ((field[0] == 'i') && (field[1] != 'd')) {
/* Indirect String Descriptor */
if (value == 0) {
@@ -157,7 +155,84 @@ dump_field(struct libusb20_device *pdev, const char *plevel,
printf(" <%s>\n", temp_string);
return;
}
+ if (strlen(plevel) == 2 || strlen(plevel) == 6) {
+
+ /* Device and Interface Descriptor class codes */
+
+ if (strcmp(field, "bInterfaceClass") == 0 ||
+ strcmp(field, "bDeviceClass") == 0) {
+ switch (value) {
+ case 0x00:
+ printf(" <Probed by interface class>\n");
+ break;
+ case 0x01:
+ printf(" <Audio device>\n");
+ break;
+ case 0x02:
+ printf(" <Communication device>\n");
+ break;
+ case 0x03:
+ printf(" <HID device>\n");
+ break;
+ case 0x05:
+ printf(" <Physical device>\n");
+ break;
+ case 0x06:
+ printf(" <Still imaging>\n");
+ break;
+ case 0x07:
+ printf(" <Printer device>\n");
+ break;
+ case 0x08:
+ printf(" <Mass storage>\n");
+ break;
+ case 0x09:
+ printf(" <HUB>\n");
+ break;
+ case 0x0A:
+ printf(" <CDC-data>\n");
+ break;
+ case 0x0B:
+ printf(" <Smart card>\n");
+ break;
+ case 0x0D:
+ printf(" <Content security>\n");
+ break;
+ case 0x0E:
+ printf(" <Video device>\n");
+ break;
+ case 0x0F:
+ printf(" <Personal healthcare>\n");
+ break;
+ case 0x10:
+ printf(" <Audio and video device>\n");
+ break;
+ case 0x11:
+ printf(" <Billboard device>\n");
+ break;
+ case 0xDC:
+ printf(" <Diagnostic device>\n");
+ break;
+ case 0xE0:
+ printf(" <Wireless controller>\n");
+ break;
+ case 0xEF:
+ printf(" <Miscellaneous device>\n");
+ break;
+ case 0xFE:
+ printf(" <Application specific>\n");
+ break;
+ case 0xFF:
+ printf(" <Vendor specific>\n");
+ break;
+ default:
+ printf(" <Unknown>\n");
+ break;
+ }
+ return;
+ }
+ }
/* No additional information */
printf("\n");
}
@@ -390,8 +465,8 @@ dump_string_by_index(struct libusb20_device *pdev, uint8_t str_index)
printf("STRING_0x%02x = ", str_index);
len = (uint8_t)pbuf[0];
for (n = 0; n != len; n++) {
- printf("0x%02x%s", (uint8_t)pbuf[n],
- (n != (len-1)) ? ", " : "");
+ printf("0x%02x%s", (uint8_t)pbuf[n],
+ (n != (len - 1)) ? ", " : "");
}
printf("\n");
}
diff --git a/usr.sbin/vidcontrol/vidcontrol.1 b/usr.sbin/vidcontrol/vidcontrol.1
index d46bd6d..d722628 100644
--- a/usr.sbin/vidcontrol/vidcontrol.1
+++ b/usr.sbin/vidcontrol/vidcontrol.1
@@ -1,5 +1,5 @@
.\"
-.\" vidcontrol - a utility for manipulating the syscons video driver
+.\" vidcontrol - a utility for manipulating the syscons or vt video driver
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -26,9 +26,11 @@
.Op Fl c Ar appearance
.Oo
.Fl f
+.Oo
.Op Ar size
.Ar file
.Oc
+.Oc
.Op Fl g Ar geometry
.Op Fl h Ar size
.Op Fl i Cm adapter | mode
@@ -48,9 +50,15 @@ The
.Nm
utility is used to set various options for the
.Xr syscons 4
+or
+.Xr vt 4
console driver,
such as video mode, colors, cursor shape, screen output map, font and screen
saver timeout.
+Only a small subset of options is supported by
+.Xr vt 4 .
+Unsupported options lead to error messages, typically including
+the text "Inappropriate ioctl for device".
.Pp
The following command line options are supported:
.Bl -tag -width indent
@@ -130,8 +138,10 @@ The latter is actually a simulation.
Print out current output screen map.
.It Xo
.Fl f
+.Oo
.Op Ar size
.Ar file
+.Oc
.Xc
Load font
.Ar file
@@ -152,14 +162,25 @@ may be omitted, in this case
.Nm
will try to guess it from the size of font file.
.Pp
+When using
+.Xr vt 4
+both
+.Ar size
+and
+.Ar font
+can be omitted, and the default font will be loaded.
+.Pp
Note that older video cards, such as MDA and CGA, do not support
software font.
See also
.Sx Video Mode Support
and
.Sx EXAMPLES
-below and the man page for
-.Xr syscons 4 .
+below and the man page for either
+.Xr syscons 4
+or
+.Xr vt 4
+(depending on which driver you use).
.It Fl g Ar geometry
Set the
.Ar geometry
@@ -185,7 +206,10 @@ Shows the possible video modes with the current video hardware.
Install screen output map file from
.Ar screen_map .
See also
-.Xr syscons 4 .
+.Xr syscons 4
+or
+.Xr vt 4
+(depending on which driver you use).
.It Fl L
Install default screen output map.
.It Fl M Ar char
@@ -307,12 +331,18 @@ kernel with the
option.
See
.Xr syscons 4
+or
+.Xr vt 4
+(depending on which driver you use)
for more details on this kernel option.
.Ss Format of Video Buffer Dump
The
.Nm
utility uses the
.Xr syscons 4
+.\" is it supported on vt(4)???
+or
+.Xr vt 4
.Dv CONS_SCRSHOT
.Xr ioctl 2
to capture the current contents of the video buffer.
@@ -453,9 +483,12 @@ for details.
.Sh FILES
.Bl -tag -width /usr/share/syscons/scrnmaps/foo-bar -compact
.It Pa /usr/share/syscons/fonts/*
+.It Pa /usr/share/vt/fonts/*
font files.
.It Pa /usr/share/syscons/scrnmaps/*
-screen output map files.
+screen output map files (relevant for
+.Xr syscons 4
+only).
.El
.Sh EXAMPLES
If you want to load
@@ -467,7 +500,10 @@ as:
.Dl vidcontrol -f 8x16 /usr/share/syscons/fonts/iso-8x16.fnt
.Pp
So long as the font file is in
-.Pa /usr/share/syscons/fonts ,
+.Pa /usr/share/syscons/fonts
+(if using syscons) or
+.Pa /usr/share/vt/fonts
+(if using vt),
you may abbreviate the file name as
.Pa iso-8x16 :
.Pp
@@ -521,6 +557,7 @@ to the standard output in the human readable format:
.Xr screen 4 ,
.Xr syscons 4 ,
.Xr vga 4 ,
+.Xr vt 4 ,
.Xr rc.conf 5 ,
.Xr kldload 8 ,
.Xr moused 8 ,
diff --git a/usr.sbin/vidcontrol/vidcontrol.c b/usr.sbin/vidcontrol/vidcontrol.c
index 32e4de6..3001f69 100644
--- a/usr.sbin/vidcontrol/vidcontrol.c
+++ b/usr.sbin/vidcontrol/vidcontrol.c
@@ -197,7 +197,7 @@ usage(void)
{
if (vt4_mode)
fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
-"usage: vidcontrol [-CHPpx] [-b color] [-c appearance] [-f [size] file]",
+"usage: vidcontrol [-CHPpx] [-b color] [-c appearance] [-f [[size] file]]",
" [-g geometry] [-h size] [-i adapter | mode]",
" [-M char] [-m on | off] [-r foreground background]",
" [-S on | off] [-s number] [-T xterm | cons25] [-t N | off]",
@@ -409,6 +409,19 @@ load_vt4mappingtable(unsigned int nmappings, FILE *f)
return (t);
}
+/*
+ * Set the default vt font.
+ */
+
+static void
+load_default_vt4font(void)
+{
+ if (ioctl(0, PIO_VFONT_DEFAULT) == -1) {
+ revert();
+ errc(1, errno, "loading default vt font");
+ }
+}
+
static int
load_vt4font(FILE *f)
{
@@ -1328,7 +1341,7 @@ main(int argc, char **argv)
dumpopt = DUMP_FBF;
termmode = NULL;
if (vt4_mode)
- opts = "b:Cc:f:g:h:Hi:M:m:pPr:S:s:T:t:x";
+ opts = "b:Cc:fg:h:Hi:M:m:pPr:S:s:T:t:x";
else
opts = "b:Cc:df:g:h:Hi:l:LM:m:pPr:S:s:T:t:x";
@@ -1349,15 +1362,23 @@ main(int argc, char **argv)
print_scrnmap();
break;
case 'f':
- type = optarg;
- font = nextarg(argc, argv, &optind, 'f', 0);
+ optarg = nextarg(argc, argv, &optind, 'f', 0);
+ if (optarg != NULL) {
+ font = nextarg(argc, argv, &optind, 'f', 0);
- if (font == NULL) {
- type = NULL;
- font = optarg;
- }
+ if (font == NULL) {
+ type = NULL;
+ font = optarg;
+ } else
+ type = optarg;
- load_font(type, font);
+ load_font(type, font);
+ } else {
+ if (!vt4_mode)
+ usage(); /* Switch syscons to ROM? */
+
+ load_default_vt4font();
+ }
break;
case 'g':
if (sscanf(optarg, "%dx%d",
diff --git a/usr.sbin/watchdogd/watchdog.8 b/usr.sbin/watchdogd/watchdog.8
index a82f6e3..9d041f5 100644
--- a/usr.sbin/watchdogd/watchdog.8
+++ b/usr.sbin/watchdogd/watchdog.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 2, 2006
+.Dd October 18, 2014
.Dt WATCHDOG 8
.Os
.Sh NAME
@@ -50,7 +50,7 @@ The
option
specifies the desired timeout period in seconds, a value of
zero will disable the watchdog.
-The default timeout is 16 seconds.
+The default timeout is 128 seconds.
.Sh SEE ALSO
.Xr watchdog 4 ,
.Xr watchdogd 8 ,
diff --git a/usr.sbin/watchdogd/watchdogd.8 b/usr.sbin/watchdogd/watchdogd.8
index 1d76eee..e60f42d 100644
--- a/usr.sbin/watchdogd/watchdogd.8
+++ b/usr.sbin/watchdogd/watchdogd.8
@@ -27,7 +27,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 27, 2013
+.Dd November 16, 2014
.Dt WATCHDOGD 8
.Os
.Sh NAME
@@ -79,12 +79,12 @@ reboot if there are problems with the script.
The
.Fl s Ar sleep
argument can be used to control the sleep period between each execution
-of the check and defaults to one second.
+of the check and defaults to 10 seconds.
.Pp
The
.Fl t Ar timeout
specifies the desired timeout period in seconds.
-The default timeout is 16 seconds.
+The default timeout is 128 seconds.
.Pp
One possible circumstance which will cause a watchdog timeout is an interrupt
storm.
diff --git a/usr.sbin/watchdogd/watchdogd.c b/usr.sbin/watchdogd/watchdogd.c
index 5fd16f5..767aa8e 100644
--- a/usr.sbin/watchdogd/watchdogd.c
+++ b/usr.sbin/watchdogd/watchdogd.c
@@ -87,7 +87,7 @@ static int is_dry_run = 0; /* do not arm the watchdog, only
static int do_timedog = 0;
static int do_syslog = 1;
static int fd = -1;
-static int nap = 1;
+static int nap = 10;
static int carp_thresh_seconds = -1;
static char *test_cmd = NULL;
diff --git a/usr.sbin/wlandebug/wlandebug.c b/usr.sbin/wlandebug/wlandebug.c
index f0e325c..9bec123 100644
--- a/usr.sbin/wlandebug/wlandebug.c
+++ b/usr.sbin/wlandebug/wlandebug.c
@@ -177,7 +177,7 @@ main(int argc, char *argv[])
setoid(oid, sizeof(oid), NULL);
argc -= 1, argv += 1;
} else if (strcmp(argv[1], "-i") == 0) {
- if (argc < 2)
+ if (argc <= 2)
errx(1, "missing interface name for -i option");
if (strncmp(argv[2], "wlan", 4) != 0)
errx(1, "expecting a wlan interface name");
diff --git a/usr.sbin/wpa/wpa_cli/Makefile b/usr.sbin/wpa/wpa_cli/Makefile
index 93a1ba7..9530b73 100644
--- a/usr.sbin/wpa/wpa_cli/Makefile
+++ b/usr.sbin/wpa/wpa_cli/Makefile
@@ -14,8 +14,8 @@ CFLAGS+= -DCONFIG_CTRL_IFACE_UNIX
# enable use of d_type to identify unix domain sockets
CFLAGS+= -D_DIRENT_HAVE_D_TYPE
-CFLAGS+= -DCONFIG_READLINE -I${DESTDIR}/${INCLUDEDIR}/edit
-LDADD+= -ledit -ltermcapw -lutil
-DPADD+= ${LIBEDIT} ${LIBTERMCAPW} ${LIBUTIL}
+CFLAGS+= -DCONFIG_WPA_CLI_EDIT=y
+LDADD+= -lutil
+DPADD+= ${LIBUTIL}
.include <bsd.prog.mk>
OpenPOWER on IntegriCloud