summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/Makefile353
-rw-r--r--usr.sbin/Makefile.amd641
-rw-r--r--usr.sbin/Makefile.arm2
-rw-r--r--usr.sbin/Makefile.arm643
-rw-r--r--usr.sbin/Makefile.i3861
-rw-r--r--usr.sbin/Makefile.mips4
-rw-r--r--usr.sbin/Makefile.powerpc1
-rw-r--r--usr.sbin/Makefile.sparc641
-rw-r--r--usr.sbin/acpi/iasl/Makefile6
-rw-r--r--usr.sbin/amd/include/Makefile.depend1
-rw-r--r--usr.sbin/asf/Makefile.depend1
-rw-r--r--usr.sbin/auditdistd/Makefile.depend31
-rw-r--r--usr.sbin/autofs/Makefile.depend21
-rw-r--r--usr.sbin/bhyve/bhyverun.c12
-rw-r--r--usr.sbin/bhyve/pci_emul.c5
-rw-r--r--usr.sbin/bhyvectl/Makefile.depend20
-rw-r--r--usr.sbin/bhyveload/Makefile.depend20
-rw-r--r--usr.sbin/binmiscctl/Makefile.depend18
-rw-r--r--usr.sbin/bluetooth/bthidd/kbd.c4
-rw-r--r--usr.sbin/bluetooth/sdpcontrol/search.c52
-rw-r--r--usr.sbin/boot0cfg/boot0cfg.c2
-rw-r--r--usr.sbin/bootparamd/bootparamd/main.c7
-rw-r--r--usr.sbin/bsdconfig/Makefile.depend11
-rwxr-xr-xusr.sbin/bsdconfig/bsdconfig2
-rw-r--r--usr.sbin/bsdconfig/console/Makefile2
-rw-r--r--usr.sbin/bsdconfig/console/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/console/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/console/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/Makefile2
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/diskmgmt/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/docsinstall/Makefile2
-rw-r--r--usr.sbin/bsdconfig/docsinstall/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/docsinstall/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/docsinstall/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/dot/Makefile2
-rw-r--r--usr.sbin/bsdconfig/dot/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/dot/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/dot/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/examples/Makefile2
-rw-r--r--usr.sbin/bsdconfig/examples/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/includes/Makefile4
-rw-r--r--usr.sbin/bsdconfig/includes/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/includes/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/includes/include/Makefile.depend11
-rwxr-xr-xusr.sbin/bsdconfig/includes/includes.sh (renamed from usr.sbin/bsdconfig/includes/includes)0
-rw-r--r--usr.sbin/bsdconfig/mouse/Makefile2
-rw-r--r--usr.sbin/bsdconfig/mouse/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/mouse/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/mouse/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/networking/Makefile2
-rw-r--r--usr.sbin/bsdconfig/networking/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/networking/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/networking/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/networking/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/networking/share/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/packages/Makefile2
-rw-r--r--usr.sbin/bsdconfig/packages/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/password/Makefile2
-rw-r--r--usr.sbin/bsdconfig/password/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/password/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/password/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/password/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/password/share/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/security/Makefile2
-rw-r--r--usr.sbin/bsdconfig/security/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/security/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/security/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/share/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/share/media/Makefile2
-rw-r--r--usr.sbin/bsdconfig/share/media/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/share/packages/Makefile2
-rw-r--r--usr.sbin/bsdconfig/share/sysrc.subr96
-rw-r--r--usr.sbin/bsdconfig/startup/Makefile2
-rw-r--r--usr.sbin/bsdconfig/startup/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/startup/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/startup/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/startup/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/startup/share/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/timezone/Makefile2
-rw-r--r--usr.sbin/bsdconfig/timezone/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/timezone/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/timezone/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/timezone/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/timezone/share/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/ttys/Makefile2
-rw-r--r--usr.sbin/bsdconfig/ttys/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/ttys/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/ttys/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/usermgmt/Makefile2
-rw-r--r--usr.sbin/bsdconfig/usermgmt/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/Makefile2
-rw-r--r--usr.sbin/bsdconfig/usermgmt/include/Makefile.depend11
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/Makefile2
-rw-r--r--usr.sbin/bsdconfig/usermgmt/share/Makefile.depend11
-rw-r--r--usr.sbin/bsdinstall/distextract/Makefile2
-rw-r--r--usr.sbin/bsdinstall/distfetch/Makefile2
-rw-r--r--usr.sbin/bsdinstall/distfetch/distfetch.c2
-rw-r--r--usr.sbin/bsdinstall/partedit/Makefile2
-rw-r--r--usr.sbin/bsdinstall/scripts/Makefile2
-rwxr-xr-xusr.sbin/bsdinstall/scripts/entropy7
-rwxr-xr-xusr.sbin/bsdinstall/scripts/netconfig21
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_atm/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_bridge/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hast/Makefile.depend2
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_lm75/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_mibII/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_pf/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_target/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_usm/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_vacm/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_wlan/Makefile.depend1
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/Makefile.depend1
-rw-r--r--usr.sbin/camdd/Makefile10
-rw-r--r--usr.sbin/camdd/Makefile.depend25
-rw-r--r--usr.sbin/camdd/camdd.8283
-rw-r--r--usr.sbin/camdd/camdd.c3423
-rw-r--r--usr.sbin/config/config.h2
-rw-r--r--usr.sbin/cron/cron/do_command.c6
-rw-r--r--usr.sbin/cron/cron/popen.c3
-rw-r--r--usr.sbin/cron/crontab/crontab.c2
-rw-r--r--usr.sbin/crunch/crunchide/exec_elf32.c4
-rw-r--r--usr.sbin/ctld/Makefile.depend31
-rw-r--r--usr.sbin/ctld/ctl.conf.54
-rw-r--r--usr.sbin/ctld/ctld.c73
-rw-r--r--usr.sbin/ctld/ctld.h24
-rw-r--r--usr.sbin/ctld/kernel.c79
-rw-r--r--usr.sbin/ctld/keys.c3
-rw-r--r--usr.sbin/ctld/parse.y20
-rw-r--r--usr.sbin/ctm/ctm/ctm.113
-rw-r--r--usr.sbin/dconschat/Makefile.depend1
-rw-r--r--usr.sbin/devctl/Makefile.depend19
-rw-r--r--usr.sbin/editmap/Makefile4
-rw-r--r--usr.sbin/editmap/Makefile.depend1
-rw-r--r--usr.sbin/fifolog/lib/Makefile1
-rw-r--r--usr.sbin/fmtree/Makefile (renamed from usr.sbin/mtree/Makefile)0
-rw-r--r--usr.sbin/fmtree/Makefile.depend (renamed from usr.sbin/mtree/Makefile.depend)0
-rw-r--r--usr.sbin/fmtree/compare.c (renamed from usr.sbin/mtree/compare.c)0
-rw-r--r--usr.sbin/fmtree/create.c (renamed from usr.sbin/mtree/create.c)0
-rw-r--r--usr.sbin/fmtree/excludes.c (renamed from usr.sbin/mtree/excludes.c)0
-rw-r--r--usr.sbin/fmtree/extern.h (renamed from usr.sbin/mtree/extern.h)0
-rw-r--r--usr.sbin/fmtree/misc.c (renamed from usr.sbin/mtree/misc.c)0
-rw-r--r--usr.sbin/fmtree/mtree.8 (renamed from usr.sbin/mtree/mtree.8)0
-rw-r--r--usr.sbin/fmtree/mtree.c (renamed from usr.sbin/mtree/mtree.c)0
-rw-r--r--usr.sbin/fmtree/mtree.h (renamed from usr.sbin/mtree/mtree.h)0
-rw-r--r--usr.sbin/fmtree/spec.c (renamed from usr.sbin/mtree/spec.c)0
-rw-r--r--usr.sbin/fmtree/specspec.c (renamed from usr.sbin/mtree/specspec.c)0
-rw-r--r--usr.sbin/fmtree/test/test00.sh (renamed from usr.sbin/mtree/test/test00.sh)0
-rw-r--r--usr.sbin/fmtree/test/test01.sh (renamed from usr.sbin/mtree/test/test01.sh)0
-rw-r--r--usr.sbin/fmtree/test/test02.sh (renamed from usr.sbin/mtree/test/test02.sh)0
-rw-r--r--usr.sbin/fmtree/test/test03.sh (renamed from usr.sbin/mtree/test/test03.sh)0
-rw-r--r--usr.sbin/fmtree/test/test04.sh (renamed from usr.sbin/mtree/test/test04.sh)0
-rw-r--r--usr.sbin/fmtree/test/test05.sh (renamed from usr.sbin/mtree/test/test05.sh)0
-rw-r--r--usr.sbin/fmtree/verify.c (renamed from usr.sbin/mtree/verify.c)0
-rw-r--r--usr.sbin/fstyp/Makefile10
-rw-r--r--usr.sbin/fstyp/Makefile.depend32
-rw-r--r--usr.sbin/fstyp/fstyp.c1
-rw-r--r--usr.sbin/fstyp/geli.c2
-rw-r--r--usr.sbin/fstyp/zfs.c3
-rw-r--r--usr.sbin/ftp-proxy/Makefile.depend20
-rw-r--r--usr.sbin/fwcontrol/fwmpegts.c2
-rw-r--r--usr.sbin/gssd/gssd.c2
-rw-r--r--usr.sbin/gstat/Makefile.depend1
-rw-r--r--usr.sbin/hyperv/tools/Makefile.depend19
-rw-r--r--usr.sbin/iostat/Makefile.depend1
-rw-r--r--usr.sbin/iostat/iostat.c59
-rw-r--r--usr.sbin/iovctl/Makefile.depend21
-rw-r--r--usr.sbin/iscsid/Makefile.depend21
-rw-r--r--usr.sbin/iscsid/keys.c1
-rw-r--r--usr.sbin/iscsid/pdu.c1
-rw-r--r--usr.sbin/jail/Makefile.depend1
-rw-r--r--usr.sbin/jail/command.c2
-rw-r--r--usr.sbin/jail/jailp.h2
-rw-r--r--usr.sbin/jail/jailparse.y2
-rw-r--r--usr.sbin/jls/Makefile2
-rw-r--r--usr.sbin/jls/jls.814
-rw-r--r--usr.sbin/jls/jls.c177
-rw-r--r--usr.sbin/kbdcontrol/kbdmap.514
-rw-r--r--usr.sbin/kbdmap/kbdmap.c20
-rw-r--r--usr.sbin/kgmon/Makefile.depend1
-rw-r--r--usr.sbin/kldxref/kldxref.c347
-rw-r--r--usr.sbin/lpr/filters/Makefile2
-rw-r--r--usr.sbin/mailstats/Makefile4
-rw-r--r--usr.sbin/mailstats/Makefile.depend1
-rw-r--r--usr.sbin/makefs/Makefile6
-rw-r--r--usr.sbin/makefs/cd9660.c11
-rw-r--r--usr.sbin/makefs/cd9660/cd9660_write.c6
-rw-r--r--usr.sbin/makefs/cd9660/iso9660_rrip.c9
-rw-r--r--usr.sbin/makefs/ffs/ffs_bswap.c8
-rw-r--r--usr.sbin/makefs/ffs/newfs_extern.h7
-rw-r--r--usr.sbin/makefs/makefs.877
-rw-r--r--usr.sbin/makefs/makefs.c17
-rw-r--r--usr.sbin/makefs/tests/Makefile15
-rwxr-xr-xusr.sbin/makefs/tests/makefs_cd9660_tests.sh373
-rwxr-xr-xusr.sbin/makefs/tests/makefs_ffs_tests.sh237
-rwxr-xr-xusr.sbin/makefs/tests/makefs_tests_common.sh152
-rw-r--r--usr.sbin/makemap/Makefile4
-rw-r--r--usr.sbin/makemap/Makefile.depend1
-rw-r--r--usr.sbin/mfiutil/mfiutil.88
-rw-r--r--usr.sbin/mount_smbfs/Makefile.depend3
-rw-r--r--usr.sbin/mountd/mountd.c2
-rw-r--r--usr.sbin/mpsutil/Makefile22
-rw-r--r--usr.sbin/mpsutil/Makefile.depend18
-rw-r--r--usr.sbin/mpsutil/mpr_ioctl.h388
-rw-r--r--usr.sbin/mpsutil/mps_cmd.c731
-rw-r--r--usr.sbin/mpsutil/mps_flash.c237
-rw-r--r--usr.sbin/mpsutil/mps_ioctl.h387
-rw-r--r--usr.sbin/mpsutil/mps_show.c772
-rw-r--r--usr.sbin/mpsutil/mpsutil.8165
-rw-r--r--usr.sbin/mpsutil/mpsutil.c207
-rw-r--r--usr.sbin/mpsutil/mpsutil.h147
-rw-r--r--usr.sbin/mptable/mptable.c3
-rw-r--r--usr.sbin/nandsim/Makefile.depend18
-rw-r--r--usr.sbin/nandsim/nandsim.82
-rw-r--r--usr.sbin/nandsim/nandsim.c2
-rw-r--r--usr.sbin/nandsim/nandsim_cfgparse.c4
-rw-r--r--usr.sbin/nandtool/Makefile.depend21
-rw-r--r--usr.sbin/ndiscvt/Makefile3
-rw-r--r--usr.sbin/ndp/ndp.c80
-rw-r--r--usr.sbin/newsyslog/newsyslog.c61
-rw-r--r--usr.sbin/newsyslog/newsyslog.conf.519
-rw-r--r--usr.sbin/nfsuserd/nfsuserd.820
-rw-r--r--usr.sbin/nfsuserd/nfsuserd.c60
-rw-r--r--usr.sbin/ntp/config.h10
-rw-r--r--usr.sbin/ntp/doc/drivers/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/drivers/icons/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/drivers/scripts/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/hints/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/icons/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/ntp-keygen.84
-rw-r--r--usr.sbin/ntp/doc/ntp.conf.554
-rw-r--r--usr.sbin/ntp/doc/ntp.keys.56
-rw-r--r--usr.sbin/ntp/doc/ntpd.827
-rw-r--r--usr.sbin/ntp/doc/ntpdc.84
-rw-r--r--usr.sbin/ntp/doc/ntpq.816
-rw-r--r--usr.sbin/ntp/doc/pic/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/scripts/Makefile.depend11
-rw-r--r--usr.sbin/ntp/doc/sntp.87
-rwxr-xr-xusr.sbin/ntp/scripts/mkver2
-rw-r--r--usr.sbin/ofwdump/Makefile.depend3
-rw-r--r--usr.sbin/pciconf/cap.c4
-rw-r--r--usr.sbin/pciconf/pciconf.842
-rw-r--r--usr.sbin/pciconf/pciconf.c212
-rw-r--r--usr.sbin/pmcstat/pmcpl_gprof.c54
-rw-r--r--usr.sbin/pmcstat/pmcstat.89
-rw-r--r--usr.sbin/pmcstat/pmcstat.c32
-rw-r--r--usr.sbin/pmcstat/pmcstat.h1
-rw-r--r--usr.sbin/pmcstudy/eval_expr.c2
-rw-r--r--usr.sbin/pmcstudy/pmcstudy.88
-rw-r--r--usr.sbin/pmcstudy/pmcstudy.c712
-rw-r--r--usr.sbin/ppp/ip.c2
-rw-r--r--usr.sbin/ppp/ppp.84
-rw-r--r--usr.sbin/praliases/Makefile4
-rw-r--r--usr.sbin/praliases/Makefile.depend1
-rw-r--r--usr.sbin/pstat/Makefile.depend1
-rw-r--r--usr.sbin/pw/pw_conf.c2
-rw-r--r--usr.sbin/pw/pw_group.c7
-rw-r--r--usr.sbin/pw/pw_user.c27
-rw-r--r--usr.sbin/pw/pw_vpw.c2
-rwxr-xr-xusr.sbin/pw/tests/pw_lock.sh20
-rw-r--r--usr.sbin/pwd_mkdb/pwd_mkdb.c2
-rw-r--r--usr.sbin/rpc.lockd/lockd.c2
-rw-r--r--usr.sbin/rpc.statd/statd.c2
-rw-r--r--usr.sbin/rpc.yppasswdd/Makefile2
-rw-r--r--usr.sbin/rtadvd/config.c5
-rw-r--r--usr.sbin/rtadvd/if.c3
-rw-r--r--usr.sbin/rtsold/rtsold.c14
-rw-r--r--usr.sbin/rtsold/rtsold.h2
-rw-r--r--usr.sbin/sendmail/Makefile6
-rw-r--r--usr.sbin/sesutil/Makefile2
-rw-r--r--usr.sbin/sesutil/eltsub.c75
-rw-r--r--usr.sbin/sesutil/eltsub.h5
-rw-r--r--usr.sbin/sesutil/sesutil.c28
-rw-r--r--usr.sbin/syslogd/syslogd.c26
-rw-r--r--usr.sbin/sysrc/Makefile.depend11
-rw-r--r--usr.sbin/sysrc/sysrc181
-rw-r--r--usr.sbin/sysrc/sysrc.869
-rw-r--r--usr.sbin/tcpdchk/Makefile2
-rw-r--r--usr.sbin/tcpdmatch/Makefile2
-rw-r--r--usr.sbin/tzsetup/tzsetup.c26
-rw-r--r--usr.sbin/uathload/Makefile10
-rw-r--r--usr.sbin/uefisign/Makefile.depend19
-rw-r--r--usr.sbin/uefisign/magic.h2
-rw-r--r--usr.sbin/uefisign/pe.c2
-rw-r--r--usr.sbin/uhsoctl/uhsoctl.c1
-rw-r--r--usr.sbin/unbound/anchor/Makefile.depend24
-rw-r--r--usr.sbin/unbound/checkconf/Makefile.depend23
-rw-r--r--usr.sbin/unbound/control/Makefile.depend23
-rw-r--r--usr.sbin/unbound/daemon/Makefile.depend24
-rw-r--r--usr.sbin/unbound/local-setup/Makefile.depend11
-rw-r--r--usr.sbin/vigr/Makefile.depend11
-rw-r--r--usr.sbin/wpa/Makefile.crypto3
-rw-r--r--usr.sbin/wpa/hostapd/Makefile1
-rw-r--r--usr.sbin/wpa/wpa_supplicant/Makefile4
-rw-r--r--usr.sbin/ypbind/ypbind.c8
-rw-r--r--usr.sbin/ypldap/Makefile20
-rw-r--r--usr.sbin/ypldap/aldap.c1272
-rw-r--r--usr.sbin/ypldap/aldap.h221
-rw-r--r--usr.sbin/ypldap/ber.c1268
-rw-r--r--usr.sbin/ypldap/ber.h129
-rw-r--r--usr.sbin/ypldap/entries.c149
-rw-r--r--usr.sbin/ypldap/ldapclient.c705
-rw-r--r--usr.sbin/ypldap/log.c162
-rw-r--r--usr.sbin/ypldap/parse.y838
-rw-r--r--usr.sbin/ypldap/yp.c652
-rw-r--r--usr.sbin/ypldap/ypldap.882
-rw-r--r--usr.sbin/ypldap/ypldap.c651
-rw-r--r--usr.sbin/ypldap/ypldap.conf.5167
-rw-r--r--usr.sbin/ypldap/ypldap.h222
-rw-r--r--usr.sbin/ypldap/ypldap_dns.c254
-rw-r--r--usr.sbin/ypserv/Makefile.yp32
-rw-r--r--usr.sbin/ypserv/yp_access.c4
-rw-r--r--usr.sbin/ypserv/yp_dblookup.c4
-rw-r--r--usr.sbin/ypserv/yp_dnslookup.c2
-rw-r--r--usr.sbin/ypserv/ypinit.sh2
-rw-r--r--usr.sbin/zic/zdump/Makefile2
-rw-r--r--usr.sbin/zic/zic/Makefile2
323 files changed, 18095 insertions, 1041 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index 03f69c1..16feb68 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -7,6 +7,7 @@ SUBDIR= adduser \
arp \
binmiscctl \
bsdconfig \
+ camdd \
cdcontrol \
chkgrp \
chown \
@@ -45,9 +46,10 @@ SUBDIR= adduser \
mixer \
mlxcontrol \
mountd \
+ mount_smbfs \
+ mpsutil \
mptutil \
mtest \
- ${_mtree} \
newsyslog \
nfscbd \
nfsd \
@@ -56,7 +58,6 @@ SUBDIR= adduser \
nfsuserd \
nmtree \
nologin \
- ${_pc_sysinstall} \
pciconf \
periodic \
powerd \
@@ -99,254 +100,112 @@ SUBDIR= adduser \
# NB: keep these sorted by MK_* knobs
-.if ${MK_ACCT} != "no"
-SUBDIR+= accton
-SUBDIR+= sa
-.endif
-
-.if ${MK_AMD} != "no"
-SUBDIR+= amd
-.endif
-
-.if ${MK_AUDIT} != "no"
-SUBDIR+= audit
-SUBDIR+= auditd
+SUBDIR.${MK_ACCT}+= accton
+SUBDIR.${MK_ACCT}+= sa
+SUBDIR.${MK_AMD}+= amd
+SUBDIR.${MK_AUDIT}+= audit
+SUBDIR.${MK_AUDIT}+= auditd
.if ${MK_OPENSSL} != "no"
-SUBDIR+= auditdistd
-.endif
-SUBDIR+= auditreduce
-SUBDIR+= praudit
-.endif
-
-.if ${MK_AUTHPF} != "no"
-SUBDIR+= authpf
-.endif
-
-.if ${MK_AUTOFS} != "no"
-SUBDIR+= autofs
-.endif
-
-.if ${MK_BLUETOOTH} != "no"
-SUBDIR+= bluetooth
-.endif
-
-.if ${MK_BOOTPARAMD} != "no"
-SUBDIR+= bootparamd
-.endif
-
-.if ${MK_BSDINSTALL} != "no"
-SUBDIR+= bsdinstall
-.endif
-
-.if ${MK_BSNMP} != "no"
-SUBDIR+= bsnmpd
-.endif
-
-.if ${MK_CTM} != "no"
-SUBDIR+= ctm
-.endif
-
-.if ${MK_FLOPPY} != "no"
-SUBDIR+= fdcontrol
-SUBDIR+= fdformat
-SUBDIR+= fdread
-SUBDIR+= fdwrite
-.endif
-
-.if ${MK_FMTREE} != "no"
-SUBDIR+= mtree
-.endif
-
-.if ${MK_FREEBSD_UPDATE} != "no"
-SUBDIR+= freebsd-update
-.endif
-
-.if ${MK_GSSAPI} != "no"
-SUBDIR+= gssd
-.endif
-
-.if ${MK_GPIO} != "no"
-SUBDIR+= gpioctl
-.endif
-
-.if ${MK_INET6} != "no"
-SUBDIR+= ip6addrctl
-SUBDIR+= mld6query
-SUBDIR+= ndp
-SUBDIR+= rip6query
-SUBDIR+= route6d
-SUBDIR+= rrenumd
-SUBDIR+= rtadvctl
-SUBDIR+= rtadvd
-SUBDIR+= rtsold
-SUBDIR+= traceroute6
-.endif
-
-.if ${MK_INETD} != "no"
-SUBDIR+= inetd
-.endif
-
-.if ${MK_IPFW} != "no"
-SUBDIR+= ipfwpcap
-.endif
-
-.if ${MK_ISCSI} != "no"
-SUBDIR+= iscsid
-.endif
-
-.if ${MK_JAIL} != "no"
-SUBDIR+= jail
-SUBDIR+= jexec
-SUBDIR+= jls
-.endif
-
+SUBDIR.${MK_AUDIT}+= auditdistd
+.endif
+SUBDIR.${MK_AUDIT}+= auditreduce
+SUBDIR.${MK_AUDIT}+= praudit
+SUBDIR.${MK_AUTHPF}+= authpf
+SUBDIR.${MK_AUTOFS}+= autofs
+SUBDIR.${MK_BLUETOOTH}+= bluetooth
+SUBDIR.${MK_BOOTPARAMD}+= bootparamd
+SUBDIR.${MK_BSDINSTALL}+= bsdinstall
+SUBDIR.${MK_BSNMP}+= bsnmpd
+SUBDIR.${MK_CTM}+= ctm
+SUBDIR.${MK_FLOPPY}+= fdcontrol
+SUBDIR.${MK_FLOPPY}+= fdformat
+SUBDIR.${MK_FLOPPY}+= fdread
+SUBDIR.${MK_FLOPPY}+= fdwrite
+SUBDIR.${MK_FMTREE}+= fmtree
+SUBDIR.${MK_FREEBSD_UPDATE}+= freebsd-update
+SUBDIR.${MK_GSSAPI}+= gssd
+SUBDIR.${MK_GPIO}+= gpioctl
+SUBDIR.${MK_INET6}+= ip6addrctl
+SUBDIR.${MK_INET6}+= mld6query
+SUBDIR.${MK_INET6}+= ndp
+SUBDIR.${MK_INET6}+= rip6query
+SUBDIR.${MK_INET6}+= route6d
+SUBDIR.${MK_INET6}+= rrenumd
+SUBDIR.${MK_INET6}+= rtadvctl
+SUBDIR.${MK_INET6}+= rtadvd
+SUBDIR.${MK_INET6}+= rtsold
+SUBDIR.${MK_INET6}+= traceroute6
+SUBDIR.${MK_INETD}+= inetd
+SUBDIR.${MK_IPFW}+= ipfwpcap
+SUBDIR.${MK_ISCSI}+= iscsid
+SUBDIR.${MK_JAIL}+= jail
+SUBDIR.${MK_JAIL}+= jexec
+SUBDIR.${MK_JAIL}+= jls
# XXX MK_SYSCONS
-.if ${MK_LEGACY_CONSOLE} != "no"
-SUBDIR+= kbdcontrol
-SUBDIR+= kbdmap
-SUBDIR+= moused
-SUBDIR+= vidcontrol
-.endif
-
+SUBDIR.${MK_LEGACY_CONSOLE}+= kbdcontrol
+SUBDIR.${MK_LEGACY_CONSOLE}+= kbdmap
+SUBDIR.${MK_LEGACY_CONSOLE}+= moused
+SUBDIR.${MK_LEGACY_CONSOLE}+= vidcontrol
.if ${MK_LIBTHR} != "no" || ${MK_LIBPTHREAD} != "no"
-.if ${MK_PPP} != "no"
-SUBDIR+= pppctl
-.endif
-.if ${MK_NS_CACHING} != "no"
-SUBDIR+= nscd
-.endif
-.endif
-
-.if ${MK_LPR} != "no"
-SUBDIR+= lpr
-.endif
-
-.if ${MK_MAN_UTILS} != "no"
-SUBDIR+= manctl
-.endif
-
-.if ${MK_NAND} != "no"
-SUBDIR+= nandsim
-SUBDIR+= nandtool
-.endif
-
-.if ${MK_NETGRAPH} != "no"
-SUBDIR+= flowctl
-SUBDIR+= lmcconfig
-SUBDIR+= ngctl
-SUBDIR+= nghook
-.endif
-
-.if ${MK_NIS} != "no"
-SUBDIR+= rpc.yppasswdd
-SUBDIR+= rpc.ypupdated
-SUBDIR+= rpc.ypxfrd
-SUBDIR+= ypbind
-SUBDIR+= yp_mkdb
-SUBDIR+= yppoll
-SUBDIR+= yppush
-SUBDIR+= ypserv
-SUBDIR+= ypset
-.endif
-
-.if ${MK_NTP} != "no"
-SUBDIR+= ntp
-.endif
-
-.if ${MK_OPENSSL} != "no"
-SUBDIR+= keyserv
-.endif
-
-.if ${MK_PC_SYSINSTALL} != "no"
-_pc_sysinstall= pc-sysinstall
-.endif
-
-.if ${MK_PF} != "no"
-SUBDIR+= ftp-proxy
-.endif
-
-.if ${MK_PKGBOOTSTRAP} != "no"
-SUBDIR+= pkg
-.endif
-
-# XXX MK_TOOLCHAIN?
-.if ${MK_PMC} != "no"
-SUBDIR+= pmcannotate
-SUBDIR+= pmccontrol
-SUBDIR+= pmcstat
-SUBDIR+= pmcstudy
-.endif
-
-.if ${MK_PORTSNAP} != "no"
-SUBDIR+= portsnap
-.endif
-
-.if ${MK_PPP} != "no"
-SUBDIR+= ppp
-.endif
-
-.if ${MK_QUOTAS} != "no"
-SUBDIR+= edquota
-SUBDIR+= quotaon
-SUBDIR+= repquota
-.endif
-
-.if ${MK_RCMDS} != "no"
-SUBDIR+= rwhod
-.endif
-
-.if ${MK_RCS} != "no"
-SUBDIR+= etcupdate
-.endif
-
-.if ${MK_SENDMAIL} != "no"
-SUBDIR+= editmap
-SUBDIR+= mailstats
-SUBDIR+= makemap
-SUBDIR+= praliases
-SUBDIR+= sendmail
-.endif
-
-.if ${MK_TCP_WRAPPERS} != "no"
-SUBDIR+= tcpdchk
-SUBDIR+= tcpdmatch
-.endif
-
-.if ${MK_TESTS} != "no"
-SUBDIR+= tests
-.endif
-
-.if ${MK_TIMED} != "no"
-SUBDIR+= timed
-.endif
-
-.if ${MK_TOOLCHAIN} != "no"
-SUBDIR+= config
-SUBDIR+= crunch
-.endif
-
-.if ${MK_UNBOUND} != "no"
-SUBDIR+= unbound
-.endif
-
-.if ${MK_USB} != "no"
-SUBDIR+= uathload
-SUBDIR+= uhsoctl
-SUBDIR+= usbconfig
-SUBDIR+= usbdump
-.endif
-
-.if ${MK_UTMPX} != "no"
-SUBDIR+= ac
-SUBDIR+= lastlogin
-SUBDIR+= utx
-.endif
-
-.if ${MK_WIRELESS} != "no"
-SUBDIR+= ancontrol
-SUBDIR+= wlandebug
-SUBDIR+= wpa
-.endif
+SUBDIR.${MK_PPP}+= pppctl
+SUBDIR.${MK_NS_CACHING}+= nscd
+.endif
+SUBDIR.${MK_LPR}+= lpr
+SUBDIR.${MK_MAN_UTILS}+= manctl
+SUBDIR.${MK_NAND}+= nandsim
+SUBDIR.${MK_NAND}+= nandtool
+SUBDIR.${MK_NETGRAPH}+= flowctl
+SUBDIR.${MK_NETGRAPH}+= lmcconfig
+SUBDIR.${MK_NETGRAPH}+= ngctl
+SUBDIR.${MK_NETGRAPH}+= nghook
+SUBDIR.${MK_NIS}+= rpc.yppasswdd
+SUBDIR.${MK_NIS}+= rpc.ypupdated
+SUBDIR.${MK_NIS}+= rpc.ypxfrd
+SUBDIR.${MK_NIS}+= ypbind
+SUBDIR.${MK_NIS}+= ypldap
+SUBDIR.${MK_NIS}+= yp_mkdb
+SUBDIR.${MK_NIS}+= yppoll
+SUBDIR.${MK_NIS}+= yppush
+SUBDIR.${MK_NIS}+= ypserv
+SUBDIR.${MK_NIS}+= ypset
+SUBDIR.${MK_NTP}+= ntp
+SUBDIR.${MK_OPENSSL}+= keyserv
+SUBDIR.${MK_PC_SYSINSTALL}+= pc-sysinstall
+SUBDIR.${MK_PF}+= ftp-proxy
+SUBDIR.${MK_PKGBOOTSTRAP}+= pkg
+SUBDIR.${MK_PMC}+= pmcannotate
+SUBDIR.${MK_PMC}+= pmccontrol
+SUBDIR.${MK_PMC}+= pmcstat
+SUBDIR.${MK_PORTSNAP}+= portsnap
+SUBDIR.${MK_PPP}+= ppp
+SUBDIR.${MK_QUOTAS}+= edquota
+SUBDIR.${MK_QUOTAS}+= quotaon
+SUBDIR.${MK_QUOTAS}+= repquota
+SUBDIR.${MK_RCMDS}+= rwhod
+SUBDIR.${MK_RCS}+= etcupdate
+SUBDIR.${MK_SENDMAIL}+= editmap
+SUBDIR.${MK_SENDMAIL}+= mailstats
+SUBDIR.${MK_SENDMAIL}+= makemap
+SUBDIR.${MK_SENDMAIL}+= praliases
+SUBDIR.${MK_SENDMAIL}+= sendmail
+SUBDIR.${MK_TCP_WRAPPERS}+= tcpdchk
+SUBDIR.${MK_TCP_WRAPPERS}+= tcpdmatch
+SUBDIR.${MK_TIMED}+= timed
+SUBDIR.${MK_TOOLCHAIN}+= config
+SUBDIR.${MK_TOOLCHAIN}+= crunch
+SUBDIR.${MK_UNBOUND}+= unbound
+SUBDIR.${MK_USB}+= uathload
+SUBDIR.${MK_USB}+= uhsoctl
+SUBDIR.${MK_USB}+= usbconfig
+SUBDIR.${MK_USB}+= usbdump
+SUBDIR.${MK_UTMPX}+= ac
+SUBDIR.${MK_UTMPX}+= lastlogin
+SUBDIR.${MK_UTMPX}+= utx
+SUBDIR.${MK_WIRELESS}+= ancontrol
+SUBDIR.${MK_WIRELESS}+= wlandebug
+SUBDIR.${MK_WIRELESS}+= wpa
+
+SUBDIR.${MK_TESTS}+= tests
.include <bsd.arch.inc.mk>
diff --git a/usr.sbin/Makefile.amd64 b/usr.sbin/Makefile.amd64
index 3f40974..0fdccaf 100644
--- a/usr.sbin/Makefile.amd64
+++ b/usr.sbin/Makefile.amd64
@@ -25,7 +25,6 @@ SUBDIR+= hyperv
.endif
SUBDIR+= kgmon
SUBDIR+= lptcontrol
-SUBDIR+= mount_smbfs
SUBDIR+= mptable
.if ${MK_NDIS} != "no"
SUBDIR+= ndiscvt
diff --git a/usr.sbin/Makefile.arm b/usr.sbin/Makefile.arm
index b21bc52..84cff4a 100644
--- a/usr.sbin/Makefile.arm
+++ b/usr.sbin/Makefile.arm
@@ -1,4 +1,4 @@
# $FreeBSD$
-SUBDIR+= ofwdump
SUBDIR+= kgmon
+SUBDIR+= ofwdump
diff --git a/usr.sbin/Makefile.arm64 b/usr.sbin/Makefile.arm64
index 8987110..c2d5f36 100644
--- a/usr.sbin/Makefile.arm64
+++ b/usr.sbin/Makefile.arm64
@@ -1,3 +1,6 @@
# $FreeBSD$
+.if ${MK_ACPI} != "no"
+SUBDIR+= acpi
+.endif
SUBDIR+= ofwdump
diff --git a/usr.sbin/Makefile.i386 b/usr.sbin/Makefile.i386
index 772c11d..6c99daf 100644
--- a/usr.sbin/Makefile.i386
+++ b/usr.sbin/Makefile.i386
@@ -12,7 +12,6 @@ SUBDIR+= cpucontrol
SUBDIR+= kgmon
SUBDIR+= kgzip
SUBDIR+= lptcontrol
-SUBDIR+= mount_smbfs
SUBDIR+= mptable
.if ${MK_NDIS} != "no"
SUBDIR+= ndiscvt
diff --git a/usr.sbin/Makefile.mips b/usr.sbin/Makefile.mips
index b56992b..8987110 100644
--- a/usr.sbin/Makefile.mips
+++ b/usr.sbin/Makefile.mips
@@ -1,7 +1,3 @@
# $FreeBSD$
SUBDIR+= ofwdump
-# uathload broken for n32 and n64 due to toolchain issues, only build for o32
-.if ${MACHINE_ARCH} != "mips" && ${MACHINE_ARCH} != "mipsel"
-SUBDIR:= ${SUBDIR:Nuathload}
-.endif
diff --git a/usr.sbin/Makefile.powerpc b/usr.sbin/Makefile.powerpc
index 8833a27..131eb57 100644
--- a/usr.sbin/Makefile.powerpc
+++ b/usr.sbin/Makefile.powerpc
@@ -1,5 +1,4 @@
# $FreeBSD$
-SUBDIR+= mount_smbfs
SUBDIR+= nvram
SUBDIR+= ofwdump
diff --git a/usr.sbin/Makefile.sparc64 b/usr.sbin/Makefile.sparc64
index 632b3a8..81f7a9b 100644
--- a/usr.sbin/Makefile.sparc64
+++ b/usr.sbin/Makefile.sparc64
@@ -1,5 +1,4 @@
# $FreeBSD$
SUBDIR+= eeprom
-SUBDIR+= mount_smbfs
SUBDIR+= ofwdump
diff --git a/usr.sbin/acpi/iasl/Makefile b/usr.sbin/acpi/iasl/Makefile
index 210b31a..b4385c7 100644
--- a/usr.sbin/acpi/iasl/Makefile
+++ b/usr.sbin/acpi/iasl/Makefile
@@ -95,7 +95,7 @@ aslcompiler.y: aslparser.y aslrules.y aslsupport.y asltokens.y asltypes.y
aslcompilerparse.c aslcompilerparse.h: aslcompiler.y
${YACC} ${YFLAGS} -pAslCompiler -oaslcompilerparse.c ${.ALLSRC}
-aslcompiler.y.h: aslcompilerparse.h
+aslcompiler.y.h: aslcompilerparse.h .NOMETA
ln -f ${.ALLSRC} ${.TARGET}
dtparserlex.c: dtparser.l
@@ -105,7 +105,7 @@ dtparserlex.c: dtparser.l
dtparserparse.c dtparserparse.h: dtparser.y
${YACC} ${YFLAGS} -pDtParser -odtparserparse.c ${.ALLSRC}
-dtparser.y.h: dtparserparse.h
+dtparser.y.h: dtparserparse.h .NOMETA
ln -f ${.ALLSRC} ${.TARGET}
prparserlex.c: prparser.l
@@ -115,7 +115,7 @@ prparserlex.c: prparser.l
prparserparse.c prparserparse.h: prparser.y
${YACC} ${YFLAGS} -pPrParser -oprparserparse.c ${.ALLSRC}
-prparser.y.h: prparserparse.h
+prparser.y.h: prparserparse.h .NOMETA
ln -f ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/amd/include/Makefile.depend b/usr.sbin/amd/include/Makefile.depend
index 50936ca..f80275d 100644
--- a/usr.sbin/amd/include/Makefile.depend
+++ b/usr.sbin/amd/include/Makefile.depend
@@ -2,7 +2,6 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
- bin/cat.host \
.include <dirdeps.mk>
diff --git a/usr.sbin/asf/Makefile.depend b/usr.sbin/asf/Makefile.depend
index a1ac545..34582cd 100644
--- a/usr.sbin/asf/Makefile.depend
+++ b/usr.sbin/asf/Makefile.depend
@@ -9,6 +9,7 @@ DIRDEPS = \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
+ lib/libelf \
lib/libkvm \
diff --git a/usr.sbin/auditdistd/Makefile.depend b/usr.sbin/auditdistd/Makefile.depend
new file mode 100644
index 0000000..b939d66
--- /dev/null
+++ b/usr.sbin/auditdistd/Makefile.depend
@@ -0,0 +1,31 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libthr \
+ lib/libutil \
+ secure/lib/libcrypto \
+ secure/lib/libssl \
+ usr.bin/lex/lib \
+ usr.bin/yacc.host \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+parse.o: parse.c
+parse.po: parse.c
+token.o: parse.h
+token.o: token.c
+token.po: parse.h
+token.po: token.c
+.endif
diff --git a/usr.sbin/autofs/Makefile.depend b/usr.sbin/autofs/Makefile.depend
new file mode 100644
index 0000000..61f3b2b
--- /dev/null
+++ b/usr.sbin/autofs/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+token.o: token.c
+token.po: token.c
+.endif
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index bc49c57..bfa135b 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -261,7 +261,8 @@ fbsdrun_addcpu(struct vmctx *ctx, int fromcpu, int newcpu, uint64_t rip)
* with vm_suspend().
*/
error = vm_activate_cpu(ctx, newcpu);
- assert(error == 0);
+ if (error != 0)
+ err(EX_OSERR, "could not activate CPU %d", newcpu);
CPU_SET_ATOMIC(newcpu, &cpumask);
@@ -309,14 +310,13 @@ static int
vmexit_inout(struct vmctx *ctx, struct vm_exit *vme, int *pvcpu)
{
int error;
- int bytes, port, in, out, string;
+ int bytes, port, in, out;
int vcpu;
vcpu = *pvcpu;
port = vme->u.inout.port;
bytes = vme->u.inout.bytes;
- string = vme->u.inout.string;
in = vme->u.inout.in;
out = !in;
@@ -598,7 +598,7 @@ static vmexit_handler_t handler[VM_EXITCODE_MAX] = {
static void
vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip)
{
- int error, rc, prevcpu;
+ int error, rc;
enum vm_exitcode exitcode;
cpuset_t active_cpus;
@@ -619,8 +619,6 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip)
if (error != 0)
break;
- prevcpu = vcpu;
-
exitcode = vmexit[vcpu].exitcode;
if (exitcode >= VM_EXITCODE_MAX || handler[exitcode] == NULL) {
fprintf(stderr, "vm_loop: unexpected exitcode 0x%x\n",
@@ -628,7 +626,7 @@ vm_loop(struct vmctx *ctx, int vcpu, uint64_t startrip)
exit(1);
}
- rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu);
+ rc = (*handler[exitcode])(ctx, &vmexit[vcpu], &vcpu);
switch (rc) {
case VMEXIT_CONTINUE:
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 03ff0c0..c6763c9 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -295,7 +295,7 @@ pci_emul_msix_tread(struct pci_devinst *pi, uint64_t offset, int size)
/*
* The PCI standard only allows 4 and 8 byte accesses to the MSI-X
- * table but we also allow 1 byte access to accomodate reads from
+ * table but we also allow 1 byte access to accommodate reads from
* ddb.
*/
if (size != 1 && size != 4 && size != 8)
@@ -863,10 +863,9 @@ msixcap_cfgwrite(struct pci_devinst *pi, int capoff, int offset,
int bytes, uint32_t val)
{
uint16_t msgctrl, rwmask;
- int off, table_bar;
+ int off;
off = offset - capoff;
- table_bar = pi->pi_msix.table_bar;
/* Message Control Register */
if (off == 2 && bytes == 2) {
rwmask = PCIM_MSIXCTRL_MSIX_ENABLE | PCIM_MSIXCTRL_FUNCTION_MASK;
diff --git a/usr.sbin/bhyvectl/Makefile.depend b/usr.sbin/bhyvectl/Makefile.depend
new file mode 100644
index 0000000..2d0f324
--- /dev/null
+++ b/usr.sbin/bhyvectl/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libutil \
+ lib/libvmmapi \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bhyveload/Makefile.depend b/usr.sbin/bhyveload/Makefile.depend
new file mode 100644
index 0000000..2d0f324
--- /dev/null
+++ b/usr.sbin/bhyveload/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libutil \
+ lib/libvmmapi \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/binmiscctl/Makefile.depend b/usr.sbin/binmiscctl/Makefile.depend
new file mode 100644
index 0000000..3646e2e
--- /dev/null
+++ b/usr.sbin/binmiscctl/Makefile.depend
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bluetooth/bthidd/kbd.c b/usr.sbin/bluetooth/bthidd/kbd.c
index e570b80..cd9f70b 100644
--- a/usr.sbin/bluetooth/bthidd/kbd.c
+++ b/usr.sbin/bluetooth/bthidd/kbd.c
@@ -226,8 +226,8 @@ static int32_t const x[] =
/* Keyboard Int'l 7 8D */ -1, /* Unassigned */
/* Keyboard Int'l 8 8E */ -1, /* Unassigned */
/* Keyboard Int'l 9 8F */ -1, /* Unassigned */
-/* Keyboard Lang 1 90 */ 0x71, /* eisu */
-/* Keyboard Lang 2 91 */ 0x72, /* kana */
+/* Keyboard Lang 1 90 */ 0x71, /* Kana */
+/* Keyboard Lang 2 91 */ 0x72, /* Eisu */
/* Keyboard Lang 3 92 */ 0x78, /* F8 */
/* Keyboard Lang 4 93 */ 0x77, /* F7 */
/* Keyboard Lang 5 94 */ 0x76, /* F6 */
diff --git a/usr.sbin/bluetooth/sdpcontrol/search.c b/usr.sbin/bluetooth/sdpcontrol/search.c
index acc8c16..6a2808c 100644
--- a/usr.sbin/bluetooth/sdpcontrol/search.c
+++ b/usr.sbin/bluetooth/sdpcontrol/search.c
@@ -103,6 +103,12 @@ print_service_class_id_list(uint8_t const *start, uint8_t const *end)
/* NOT REACHED */
}
+ if (len > (end - start)) {
+ fprintf(stderr, "Invalid Service Class ID List. " \
+ "Too long len=%d\n", len);
+ return;
+ }
+
while (start < end) {
SDP_GET8(type, start);
switch (type) {
@@ -259,28 +265,31 @@ print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
case SDP_DATA_STR8:
case SDP_DATA_URL8:
SDP_GET8(len, start);
- fprintf(stdout, "%*.*s\n", len, len, (char *) start);
- start += len;
+ for (; start < end && len > 0; start ++, len --)
+ fprintf(stdout, "%c", *start);
+ fprintf(stdout, "\n");
break;
case SDP_DATA_STR16:
case SDP_DATA_URL16:
SDP_GET16(len, start);
- fprintf(stdout, "%*.*s\n", len, len, (char *) start);
- start += len;
+ for (; start < end && len > 0; start ++, len --)
+ fprintf(stdout, "%c", *start);
+ fprintf(stdout, "\n");
break;
case SDP_DATA_STR32:
case SDP_DATA_URL32:
SDP_GET32(len, start);
- fprintf(stdout, "%*.*s\n", len, len, (char *) start);
- start += len;
+ for (; start < end && len > 0; start ++, len --)
+ fprintf(stdout, "%c", *start);
+ fprintf(stdout, "\n");
break;
case SDP_DATA_SEQ8:
case SDP_DATA_ALT8:
SDP_GET8(len, start);
- for (; len > 0; start ++, len --)
+ for (; start < end && len > 0; start ++, len --)
fprintf(stdout, "%#2.2x ", *start);
fprintf(stdout, "\n");
break;
@@ -288,7 +297,7 @@ print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
case SDP_DATA_SEQ16:
case SDP_DATA_ALT16:
SDP_GET16(len, start);
- for (; len > 0; start ++, len --)
+ for (; start < end && len > 0; start ++, len --)
fprintf(stdout, "%#2.2x ", *start);
fprintf(stdout, "\n");
break;
@@ -296,7 +305,7 @@ print_protocol_descriptor(uint8_t const *start, uint8_t const *end)
case SDP_DATA_SEQ32:
case SDP_DATA_ALT32:
SDP_GET32(len, start);
- for (; len > 0; start ++, len --)
+ for (; start < end && len > 0; start ++, len --)
fprintf(stdout, "%#2.2x ", *start);
fprintf(stdout, "\n");
break;
@@ -342,6 +351,12 @@ print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
/* NOT REACHED */
}
+ if (len > (end - start)) {
+ fprintf(stderr, "Invalid Protocol Descriptor List. " \
+ "Too long, len=%d\n", len);
+ return;
+ }
+
while (start < end) {
SDP_GET8(type, start);
switch (type) {
@@ -364,6 +379,12 @@ print_protocol_descriptor_list(uint8_t const *start, uint8_t const *end)
/* NOT REACHED */
}
+ if (len > (end - start)) {
+ fprintf(stderr, "Invalid Protocol Descriptor List. " \
+ "Too long, len=%d\n", len);
+ return;
+ }
+
print_protocol_descriptor(start, start + len);
start += len;
}
@@ -416,6 +437,12 @@ print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end
/* NOT REACHED */
}
+ if (len > (end - start)) {
+ fprintf(stderr, "Invalid Bluetooth Profile Descriptor List. " \
+ "Too long, len=%d\n", len);
+ return;
+ }
+
while (start < end) {
SDP_GET8(type, start);
switch (type) {
@@ -439,6 +466,13 @@ print_bluetooth_profile_descriptor_list(uint8_t const *start, uint8_t const *end
/* NOT REACHED */
}
+ if (len > (end - start)) {
+ fprintf(stderr, "Invalid Bluetooth Profile " \
+ "Descriptor List. " \
+ "Too long, len=%d\n", len);
+ return;
+ }
+
/* Get UUID */
SDP_GET8(type, start);
switch (type) {
diff --git a/usr.sbin/boot0cfg/boot0cfg.c b/usr.sbin/boot0cfg/boot0cfg.c
index 2602e50..f2cbf67 100644
--- a/usr.sbin/boot0cfg/boot0cfg.c
+++ b/usr.sbin/boot0cfg/boot0cfg.c
@@ -337,6 +337,8 @@ read_mbr(const char *disk, u_int8_t **mbr, int check_version)
return (mbr_size);
}
*mbr = malloc(sizeof(buf));
+ if (*mbr == NULL)
+ errx(1, "%s: unable to allocate MBR buffer", disk);
memcpy(*mbr, buf, sizeof(buf));
close(fd);
diff --git a/usr.sbin/bootparamd/bootparamd/main.c b/usr.sbin/bootparamd/bootparamd/main.c
index 85a1fca..04f5cef 100644
--- a/usr.sbin/bootparamd/bootparamd/main.c
+++ b/usr.sbin/bootparamd/bootparamd/main.c
@@ -36,13 +36,10 @@ in_addr_t route_addr = -1;
struct sockaddr_in my_addr;
char *bootpfile = "/etc/bootparams";
-extern void bootparamprog_1();
static void usage(void);
int
-main(argc, argv)
-int argc;
-char **argv;
+main(int argc, char **argv)
{
SVCXPRT *transp;
struct hostent *he;
@@ -110,7 +107,7 @@ char **argv;
}
static void
-usage()
+usage(void)
{
fprintf(stderr,
"usage: bootparamd [-d] [-s] [-r router] [-f bootparmsfile]\n");
diff --git a/usr.sbin/bsdconfig/Makefile.depend b/usr.sbin/bsdconfig/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/bsdconfig b/usr.sbin/bsdconfig/bsdconfig
index 62699f2..993865c 100755
--- a/usr.sbin/bsdconfig/bsdconfig
+++ b/usr.sbin/bsdconfig/bsdconfig
@@ -131,7 +131,7 @@ usage()
# determine if we can use more than one column to display commands.
#
local x=$longest_cmd ncols=1
- x=$(( $x + 8 )) # Accomodate leading tab character
+ x=$(( $x + 8 )) # Accommodate leading tab character
x=$(( $x + 3 + $longest_cmd )) # Preload end of next column
while [ $x -lt $max_width ]; do
ncols=$(( $ncols + 1 ))
diff --git a/usr.sbin/bsdconfig/console/Makefile b/usr.sbin/bsdconfig/console/Makefile
index c765a33..bcb2ebd 100644
--- a/usr.sbin/bsdconfig/console/Makefile
+++ b/usr.sbin/bsdconfig/console/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/080.console
diff --git a/usr.sbin/bsdconfig/console/Makefile.depend b/usr.sbin/bsdconfig/console/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/console/include/Makefile b/usr.sbin/bsdconfig/console/include/Makefile
index d2a17a0..52cb0be 100644
--- a/usr.sbin/bsdconfig/console/include/Makefile
+++ b/usr.sbin/bsdconfig/console/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/080.console/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/console/include/Makefile.depend b/usr.sbin/bsdconfig/console/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/console/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/diskmgmt/Makefile b/usr.sbin/bsdconfig/diskmgmt/Makefile
index fc659f8..16a8900 100644
--- a/usr.sbin/bsdconfig/diskmgmt/Makefile
+++ b/usr.sbin/bsdconfig/diskmgmt/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/050.diskmgmt
diff --git a/usr.sbin/bsdconfig/diskmgmt/Makefile.depend b/usr.sbin/bsdconfig/diskmgmt/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/diskmgmt/include/Makefile b/usr.sbin/bsdconfig/diskmgmt/include/Makefile
index 33b93e0..c927153 100644
--- a/usr.sbin/bsdconfig/diskmgmt/include/Makefile
+++ b/usr.sbin/bsdconfig/diskmgmt/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/050.diskmgmt/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/diskmgmt/include/Makefile.depend b/usr.sbin/bsdconfig/diskmgmt/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/diskmgmt/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/docsinstall/Makefile b/usr.sbin/bsdconfig/docsinstall/Makefile
index 4b67834..2ab3a68 100644
--- a/usr.sbin/bsdconfig/docsinstall/Makefile
+++ b/usr.sbin/bsdconfig/docsinstall/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/020.docsinstall
diff --git a/usr.sbin/bsdconfig/docsinstall/Makefile.depend b/usr.sbin/bsdconfig/docsinstall/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/docsinstall/include/Makefile b/usr.sbin/bsdconfig/docsinstall/include/Makefile
index b86091a..a3ca529 100644
--- a/usr.sbin/bsdconfig/docsinstall/include/Makefile
+++ b/usr.sbin/bsdconfig/docsinstall/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/020.docsinstall/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/docsinstall/include/Makefile.depend b/usr.sbin/bsdconfig/docsinstall/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/docsinstall/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/dot/Makefile b/usr.sbin/bsdconfig/dot/Makefile
index 0f11518..ccd10b4 100644
--- a/usr.sbin/bsdconfig/dot/Makefile
+++ b/usr.sbin/bsdconfig/dot/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/dot
diff --git a/usr.sbin/bsdconfig/dot/Makefile.depend b/usr.sbin/bsdconfig/dot/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/dot/include/Makefile b/usr.sbin/bsdconfig/dot/include/Makefile
index 891279f..b687b88 100644
--- a/usr.sbin/bsdconfig/dot/include/Makefile
+++ b/usr.sbin/bsdconfig/dot/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/dot/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/dot/include/Makefile.depend b/usr.sbin/bsdconfig/dot/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/dot/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/examples/Makefile b/usr.sbin/bsdconfig/examples/Makefile
index 33899d8..f66c2b1 100644
--- a/usr.sbin/bsdconfig/examples/Makefile
+++ b/usr.sbin/bsdconfig/examples/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/examples/bsdconfig
FILES= add_some_packages.sh browse_packages_http.sh bsdconfigrc
diff --git a/usr.sbin/bsdconfig/examples/Makefile.depend b/usr.sbin/bsdconfig/examples/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/examples/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/include/Makefile b/usr.sbin/bsdconfig/include/Makefile
index 50bef4c..913481c 100644
--- a/usr.sbin/bsdconfig/include/Makefile
+++ b/usr.sbin/bsdconfig/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/include
FILES= bsdconfig.hlp media.hlp messages.subr network_device.hlp \
options.hlp tcp.hlp usage.hlp
diff --git a/usr.sbin/bsdconfig/include/Makefile.depend b/usr.sbin/bsdconfig/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/includes/Makefile b/usr.sbin/bsdconfig/includes/Makefile
index 4717d34..367776c 100644
--- a/usr.sbin/bsdconfig/includes/Makefile
+++ b/usr.sbin/bsdconfig/includes/Makefile
@@ -1,13 +1,11 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/includes
FILES= INDEX USAGE
SCRIPTSDIR= ${FILESDIR}
-SCRIPTS= includes
+SCRIPTS= includes.sh
.include <bsd.prog.mk>
diff --git a/usr.sbin/bsdconfig/includes/Makefile.depend b/usr.sbin/bsdconfig/includes/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/includes/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/includes/include/Makefile b/usr.sbin/bsdconfig/includes/include/Makefile
index 21d55a1..3b8b3ec 100644
--- a/usr.sbin/bsdconfig/includes/include/Makefile
+++ b/usr.sbin/bsdconfig/includes/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/includes/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/includes/include/Makefile.depend b/usr.sbin/bsdconfig/includes/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/includes/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/includes/includes b/usr.sbin/bsdconfig/includes/includes.sh
index 6e9906f..6e9906f 100755
--- a/usr.sbin/bsdconfig/includes/includes
+++ b/usr.sbin/bsdconfig/includes/includes.sh
diff --git a/usr.sbin/bsdconfig/mouse/Makefile b/usr.sbin/bsdconfig/mouse/Makefile
index b054c8b..97fa52b 100644
--- a/usr.sbin/bsdconfig/mouse/Makefile
+++ b/usr.sbin/bsdconfig/mouse/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/110.mouse
diff --git a/usr.sbin/bsdconfig/mouse/Makefile.depend b/usr.sbin/bsdconfig/mouse/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/mouse/include/Makefile b/usr.sbin/bsdconfig/mouse/include/Makefile
index 5071db8..2cc852f 100644
--- a/usr.sbin/bsdconfig/mouse/include/Makefile
+++ b/usr.sbin/bsdconfig/mouse/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/110.mouse/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/mouse/include/Makefile.depend b/usr.sbin/bsdconfig/mouse/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/mouse/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/networking/Makefile b/usr.sbin/bsdconfig/networking/Makefile
index fcd8421..8a88067 100644
--- a/usr.sbin/bsdconfig/networking/Makefile
+++ b/usr.sbin/bsdconfig/networking/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include share
FILESDIR= ${LIBEXECDIR}/bsdconfig/120.networking
diff --git a/usr.sbin/bsdconfig/networking/Makefile.depend b/usr.sbin/bsdconfig/networking/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/networking/include/Makefile b/usr.sbin/bsdconfig/networking/include/Makefile
index b76349a..54f66e1 100644
--- a/usr.sbin/bsdconfig/networking/include/Makefile
+++ b/usr.sbin/bsdconfig/networking/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/120.networking/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/networking/include/Makefile.depend b/usr.sbin/bsdconfig/networking/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/networking/share/Makefile b/usr.sbin/bsdconfig/networking/share/Makefile
index 3cb2d4e..6d77f25 100644
--- a/usr.sbin/bsdconfig/networking/share/Makefile
+++ b/usr.sbin/bsdconfig/networking/share/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/networking
FILES= common.subr device.subr hostname.subr ipaddr.subr media.subr \
netmask.subr resolv.subr routing.subr services.subr
diff --git a/usr.sbin/bsdconfig/networking/share/Makefile.depend b/usr.sbin/bsdconfig/networking/share/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/networking/share/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/packages/Makefile b/usr.sbin/bsdconfig/packages/Makefile
index 6450e06..fa5bd30 100644
--- a/usr.sbin/bsdconfig/packages/Makefile
+++ b/usr.sbin/bsdconfig/packages/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/030.packages
diff --git a/usr.sbin/bsdconfig/packages/include/Makefile b/usr.sbin/bsdconfig/packages/include/Makefile
index 0c72bd4..3d30fd2 100644
--- a/usr.sbin/bsdconfig/packages/include/Makefile
+++ b/usr.sbin/bsdconfig/packages/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/030.packages/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/password/Makefile b/usr.sbin/bsdconfig/password/Makefile
index 0c4851f..d660e45 100644
--- a/usr.sbin/bsdconfig/password/Makefile
+++ b/usr.sbin/bsdconfig/password/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include share
FILESDIR= ${LIBEXECDIR}/bsdconfig/040.password
diff --git a/usr.sbin/bsdconfig/password/Makefile.depend b/usr.sbin/bsdconfig/password/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/password/include/Makefile b/usr.sbin/bsdconfig/password/include/Makefile
index dba8f19..a146eb2 100644
--- a/usr.sbin/bsdconfig/password/include/Makefile
+++ b/usr.sbin/bsdconfig/password/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/040.password/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/password/include/Makefile.depend b/usr.sbin/bsdconfig/password/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/password/share/Makefile b/usr.sbin/bsdconfig/password/share/Makefile
index af707b3..65f9e8c 100644
--- a/usr.sbin/bsdconfig/password/share/Makefile
+++ b/usr.sbin/bsdconfig/password/share/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/password
FILES= password.subr
diff --git a/usr.sbin/bsdconfig/password/share/Makefile.depend b/usr.sbin/bsdconfig/password/share/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/password/share/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/security/Makefile b/usr.sbin/bsdconfig/security/Makefile
index 4caa6ae..af83cee 100644
--- a/usr.sbin/bsdconfig/security/Makefile
+++ b/usr.sbin/bsdconfig/security/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/130.security
diff --git a/usr.sbin/bsdconfig/security/Makefile.depend b/usr.sbin/bsdconfig/security/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/security/include/Makefile b/usr.sbin/bsdconfig/security/include/Makefile
index 8b49a81..2efcc0f 100644
--- a/usr.sbin/bsdconfig/security/include/Makefile
+++ b/usr.sbin/bsdconfig/security/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/130.security/include
FILES= messages.subr securelevel.hlp
diff --git a/usr.sbin/bsdconfig/security/include/Makefile.depend b/usr.sbin/bsdconfig/security/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/security/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/share/Makefile b/usr.sbin/bsdconfig/share/Makefile
index 400cc11..a09697a 100644
--- a/usr.sbin/bsdconfig/share/Makefile
+++ b/usr.sbin/bsdconfig/share/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= media packages
FILESDIR= ${SHAREDIR}/bsdconfig
diff --git a/usr.sbin/bsdconfig/share/Makefile.depend b/usr.sbin/bsdconfig/share/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/share/media/Makefile b/usr.sbin/bsdconfig/share/media/Makefile
index 7be059b..135515b 100644
--- a/usr.sbin/bsdconfig/share/media/Makefile
+++ b/usr.sbin/bsdconfig/share/media/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/media
FILES= any.subr cdrom.subr common.subr directory.subr dos.subr \
floppy.subr ftp.subr http.subr httpproxy.subr network.subr \
diff --git a/usr.sbin/bsdconfig/share/media/Makefile.depend b/usr.sbin/bsdconfig/share/media/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/share/media/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/share/packages/Makefile b/usr.sbin/bsdconfig/share/packages/Makefile
index 8146346..bc0e59a 100644
--- a/usr.sbin/bsdconfig/share/packages/Makefile
+++ b/usr.sbin/bsdconfig/share/packages/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/packages
FILES= categories.subr index.subr musthavepkg.subr packages.subr
diff --git a/usr.sbin/bsdconfig/share/sysrc.subr b/usr.sbin/bsdconfig/share/sysrc.subr
index d863ba0..346bf10 100644
--- a/usr.sbin/bsdconfig/share/sysrc.subr
+++ b/usr.sbin/bsdconfig/share/sysrc.subr
@@ -1,6 +1,6 @@
if [ ! "$_SYSRC_SUBR" ]; then _SYSRC_SUBR=1
#
-# Copyright (c) 2006-2012 Devin Teske
+# Copyright (c) 2006-2015 Devin Teske
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -204,6 +204,100 @@ f_sysrc_get()
)
}
+# f_sysrc_service_configs [-a|-p] $name [$var_to_set]
+#
+# Get a list of optional `rc.conf.d' entries sourced by system `rc.d' script
+# $name (see rc.subr(8) for additional information on `rc.conf.d'). If $name
+# exists in `/etc/rc.d' or $local_startup directories and is an rc(8) script
+# the result is a space separated list of `rc.conf.d' entries sourced by the
+# $name `rc.d' script. Otherwise, if $name exists as a binary `rc.d' script,
+# the result is ``/etc/rc.conf.d/$name /usr/local/etc/rc.conf.d/$name''. The
+# result is NULL if $name does not exist.
+#
+# If $var_to_set is missing or NULL, output is to standard out. Returns success
+# if $name was found, failure otherwise.
+#
+# If `-a' flag is given and $var_to_set is non-NULL, append result to value of
+# $var_to_set rather than overwriting current contents.
+#
+# If `-p' flag is given and $var_to_set is non-NULL, prepend result to value of
+# $var_to_set rather than overwriting current contents.
+#
+# NB: The `-a' and `-p' option flags are mutually exclusive.
+#
+f_sysrc_service_configs()
+{
+ local OPTIND=1 OPTARG __flag __append= __prepend=
+ local __local_startup __dir __spath __stype __names=
+
+ while getopts ap __flag; do
+ case "$__flag" in
+ a) __append=1 __prepend= ;;
+ p) __prepend=1 __append= ;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
+
+ [ $# -gt 0 ] || return $FAILURE
+ local __sname="$1" __var_to_set="$2"
+
+ __local_startup=$( f_sysrc_get local_startup )
+ for __dir in /etc/rc.d $__local_startup; do
+ __spath="$__dir/$__sname"
+ [ -f "$__spath" -a -x "$__spath" ] || __spath= continue
+ break
+ done
+ [ "$__spath" ] || return $FAILURE
+
+ __stype=$( file -b "$__spath" 2> /dev/null )
+ case "$__stype" in
+ *"shell script"*)
+ __names=$( exec 9<&1 1>&- 2>&-
+ last_name=
+ print_name() {
+ local name="$1"
+ [ "$name" = "$last_name" ] && return
+ echo "$name" >&9
+ last_name="$name"
+ }
+ eval "$( awk '{
+ gsub(/load_rc_config /, "print_name ")
+ gsub(/run_rc_command /, ": ")
+ print
+ }' "$__spath" )"
+ ) ;;
+ *)
+ __names="$__sname"
+ esac
+
+ local __name __test_path __configs=
+ for __name in $__names; do
+ for __dir in /etc/rc.d $__local_startup; do
+ __test_path="${__dir%/rc.d}/rc.conf.d/$__name"
+ [ -d "$__test_path" ] ||
+ __configs="$__configs $__test_path" continue
+ for __test_path in "$__test_path"/*; do
+ [ -f "$__test_path" ] || continue
+ __configs="$__configs $__test_path"
+ done
+ done
+ done
+ __configs="${__configs# }"
+
+ if [ "$__var_to_set" ]; then
+ local __cur=
+ [ "$__append" -o "$__prepend" ] &&
+ f_getvar "$__var_to_set" __cur
+ [ "$__append" ] && __configs="$__cur{$__cur:+ }$__configs"
+ [ "$__prepend" ] && __configs="$__configs${__cur:+ }$__cur"
+ setvar "$__var_to_set" "$__configs"
+ else
+ echo "$__configs"
+ fi
+
+ return $SUCCESS
+}
+
# f_sysrc_get_default $varname
#
# Get a system configuration default setting from the default rc.conf(5) file
diff --git a/usr.sbin/bsdconfig/startup/Makefile b/usr.sbin/bsdconfig/startup/Makefile
index afab7b1..62a9e71 100644
--- a/usr.sbin/bsdconfig/startup/Makefile
+++ b/usr.sbin/bsdconfig/startup/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include share
FILESDIR= ${LIBEXECDIR}/bsdconfig/140.startup
diff --git a/usr.sbin/bsdconfig/startup/Makefile.depend b/usr.sbin/bsdconfig/startup/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/startup/include/Makefile b/usr.sbin/bsdconfig/startup/include/Makefile
index 40a6539..aab9842 100644
--- a/usr.sbin/bsdconfig/startup/include/Makefile
+++ b/usr.sbin/bsdconfig/startup/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/140.startup/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/startup/include/Makefile.depend b/usr.sbin/bsdconfig/startup/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/startup/share/Makefile b/usr.sbin/bsdconfig/startup/share/Makefile
index 221c38b..134914c 100644
--- a/usr.sbin/bsdconfig/startup/share/Makefile
+++ b/usr.sbin/bsdconfig/startup/share/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/startup
FILES= rcconf.subr rcedit.subr rcvar.subr
diff --git a/usr.sbin/bsdconfig/startup/share/Makefile.depend b/usr.sbin/bsdconfig/startup/share/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/startup/share/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/timezone/Makefile b/usr.sbin/bsdconfig/timezone/Makefile
index ea6a6a6..1569e7e 100644
--- a/usr.sbin/bsdconfig/timezone/Makefile
+++ b/usr.sbin/bsdconfig/timezone/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include share
FILESDIR= ${LIBEXECDIR}/bsdconfig/090.timezone
diff --git a/usr.sbin/bsdconfig/timezone/Makefile.depend b/usr.sbin/bsdconfig/timezone/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/timezone/include/Makefile b/usr.sbin/bsdconfig/timezone/include/Makefile
index 82787e1..8fc6dfc 100644
--- a/usr.sbin/bsdconfig/timezone/include/Makefile
+++ b/usr.sbin/bsdconfig/timezone/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/090.timezone/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/timezone/include/Makefile.depend b/usr.sbin/bsdconfig/timezone/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/timezone/share/Makefile b/usr.sbin/bsdconfig/timezone/share/Makefile
index bd67741..166fb10 100644
--- a/usr.sbin/bsdconfig/timezone/share/Makefile
+++ b/usr.sbin/bsdconfig/timezone/share/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/timezone
FILES= continents.subr countries.subr iso3166.subr menus.subr \
zones.subr
diff --git a/usr.sbin/bsdconfig/timezone/share/Makefile.depend b/usr.sbin/bsdconfig/timezone/share/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/timezone/share/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/ttys/Makefile b/usr.sbin/bsdconfig/ttys/Makefile
index d53314c..044fdcf 100644
--- a/usr.sbin/bsdconfig/ttys/Makefile
+++ b/usr.sbin/bsdconfig/ttys/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include
FILESDIR= ${LIBEXECDIR}/bsdconfig/150.ttys
diff --git a/usr.sbin/bsdconfig/ttys/Makefile.depend b/usr.sbin/bsdconfig/ttys/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/ttys/include/Makefile b/usr.sbin/bsdconfig/ttys/include/Makefile
index 2f32175..45c72ad 100644
--- a/usr.sbin/bsdconfig/ttys/include/Makefile
+++ b/usr.sbin/bsdconfig/ttys/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/150.ttys/include
FILES= messages.subr
diff --git a/usr.sbin/bsdconfig/ttys/include/Makefile.depend b/usr.sbin/bsdconfig/ttys/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/ttys/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/usermgmt/Makefile b/usr.sbin/bsdconfig/usermgmt/Makefile
index d82f6d6..127c874 100644
--- a/usr.sbin/bsdconfig/usermgmt/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
SUBDIR= include share
FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt
diff --git a/usr.sbin/bsdconfig/usermgmt/Makefile.depend b/usr.sbin/bsdconfig/usermgmt/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/usermgmt/include/Makefile b/usr.sbin/bsdconfig/usermgmt/include/Makefile
index a63b1fe..4839654 100644
--- a/usr.sbin/bsdconfig/usermgmt/include/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/include/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${LIBEXECDIR}/bsdconfig/070.usermgmt/include
FILES= messages.subr usermgmt.hlp
diff --git a/usr.sbin/bsdconfig/usermgmt/include/Makefile.depend b/usr.sbin/bsdconfig/usermgmt/include/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/include/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdconfig/usermgmt/share/Makefile b/usr.sbin/bsdconfig/usermgmt/share/Makefile
index a13c200..eba7c1c 100644
--- a/usr.sbin/bsdconfig/usermgmt/share/Makefile
+++ b/usr.sbin/bsdconfig/usermgmt/share/Makefile
@@ -1,7 +1,5 @@
# $FreeBSD$
-NO_OBJ=
-
FILESDIR= ${SHAREDIR}/bsdconfig/usermgmt
FILES= group.subr group_input.subr user.subr user_input.subr
diff --git a/usr.sbin/bsdconfig/usermgmt/share/Makefile.depend b/usr.sbin/bsdconfig/usermgmt/share/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/bsdconfig/usermgmt/share/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/bsdinstall/distextract/Makefile b/usr.sbin/bsdinstall/distextract/Makefile
index 313ec00..d3008f6 100644
--- a/usr.sbin/bsdinstall/distextract/Makefile
+++ b/usr.sbin/bsdinstall/distextract/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-BINDIR= /usr/libexec/bsdinstall
+BINDIR= ${LIBEXECDIR}/bsdinstall
PROG= distextract
LIBADD= archive dpv figpar ncursesw dialog m
diff --git a/usr.sbin/bsdinstall/distfetch/Makefile b/usr.sbin/bsdinstall/distfetch/Makefile
index 5c0f6e8..1620c9b 100644
--- a/usr.sbin/bsdinstall/distfetch/Makefile
+++ b/usr.sbin/bsdinstall/distfetch/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-BINDIR= /usr/libexec/bsdinstall
+BINDIR= ${LIBEXECDIR}/bsdinstall
PROG= distfetch
LIBADD= fetch ncursesw dialog m
diff --git a/usr.sbin/bsdinstall/distfetch/distfetch.c b/usr.sbin/bsdinstall/distfetch/distfetch.c
index 4e870c8..219847d 100644
--- a/usr.sbin/bsdinstall/distfetch/distfetch.c
+++ b/usr.sbin/bsdinstall/distfetch/distfetch.c
@@ -78,7 +78,7 @@ main(void)
if (chdir(getenv("BSDINSTALL_DISTDIR")) != 0) {
snprintf(error, sizeof(error),
- "Could could change to directory %s: %s\n",
+ "Could not change to directory %s: %s\n",
getenv("BSDINSTALL_DISTDIR"), strerror(errno));
dialog_msgbox("Error", error, 0, 0, TRUE);
end_dialog();
diff --git a/usr.sbin/bsdinstall/partedit/Makefile b/usr.sbin/bsdinstall/partedit/Makefile
index d48f777..21d842e 100644
--- a/usr.sbin/bsdinstall/partedit/Makefile
+++ b/usr.sbin/bsdinstall/partedit/Makefile
@@ -1,6 +1,6 @@
# $FreeBSD$
-BINDIR= /usr/libexec/bsdinstall
+BINDIR= ${LIBEXECDIR}/bsdinstall
PROG= partedit
LINKS= ${BINDIR}/partedit ${BINDIR}/autopart \
${BINDIR}/partedit ${BINDIR}/scriptedpart
diff --git a/usr.sbin/bsdinstall/scripts/Makefile b/usr.sbin/bsdinstall/scripts/Makefile
index efe9700..c0d6ac2 100644
--- a/usr.sbin/bsdinstall/scripts/Makefile
+++ b/usr.sbin/bsdinstall/scripts/Makefile
@@ -3,7 +3,7 @@
SCRIPTS= auto adduser checksum config docsinstall entropy hostname jail \
keymap mirrorselect mount netconfig netconfig_ipv4 netconfig_ipv6 \
rootpass script services time umount wlanconfig zfsboot
-BINDIR= /usr/libexec/bsdinstall
+BINDIR= ${LIBEXECDIR}/bsdinstall
MAN=
diff --git a/usr.sbin/bsdinstall/scripts/entropy b/usr.sbin/bsdinstall/scripts/entropy
index add6f30..d3938f1 100755
--- a/usr.sbin/bsdinstall/scripts/entropy
+++ b/usr.sbin/bsdinstall/scripts/entropy
@@ -26,4 +26,9 @@
#
# $FreeBSD$
-dd if=/dev/random of=$BSDINSTALL_CHROOT/entropy bs=4096 count=1
+umask 077
+for i in /entropy /boot/entropy; do
+ i="$BSDINSTALL_CHROOT/$i"
+ dd if=/dev/random of="$i" bs=4096 count=1
+ chown 0:0 "$i"
+done
diff --git a/usr.sbin/bsdinstall/scripts/netconfig b/usr.sbin/bsdinstall/scripts/netconfig
index d5a14ce..f9913c3 100755
--- a/usr.sbin/bsdinstall/scripts/netconfig
+++ b/usr.sbin/bsdinstall/scripts/netconfig
@@ -41,19 +41,24 @@ DIALOG_TAGS=""
: ${DIALOG_ITEM_HELP=4}
: ${DIALOG_ESC=255}
-# Do a dirty check to see if this a wireless interface -- there should be a
-# better way
-is_wireless_if() {
- ifconfig $1 | grep -q 'media: IEEE 802.11 Wireless'
-}
-
for IF in `ifconfig -l`; do
test "$IF" = "lo0" && continue
(ifconfig -g wlan | egrep -wq $IF) && continue
INTERFACES="$INTERFACES $IF"
+done
+
+INTERFACES="$INTERFACES $(sysctl -in net.wlan.devices)"
+is_wireless_if() {
+ for IF in $(sysctl -in net.wlan.devices); do
+ if [ $IF = $1 ]; then
+ return 0
+ fi
+ done
+ return 1
+}
+
+for IF in $INTERFACES; do
DESC=`sysctl -n dev.$(echo $IF | sed -E 's/([[:alpha:]]*)([[:digit:]]*)/\1.\2/g').%desc`
- is_wireless_if $IF && echo $DESC |
- grep -iqv wireless && DESC="Wireless $DESC"
DIALOG_TAGS="$DIALOG_TAGS $IF \"$DESC\""
done
diff --git a/usr.sbin/bsnmpd/modules/snmp_atm/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_atm/Makefile.depend
index 06b5e37..aecafbc 100644
--- a/usr.sbin/bsnmpd/modules/snmp_atm/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_atm/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
usr.sbin/bsnmpd/modules/snmp_mibII \
usr.sbin/bsnmpd/modules/snmp_netgraph \
diff --git a/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile.depend
index 7d1ccb6..f391300 100644
--- a/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_bridge/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
usr.sbin/bsnmpd/modules/snmp_mibII \
diff --git a/usr.sbin/bsnmpd/modules/snmp_hast/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_hast/Makefile.depend
index ccb3d83..140fffb 100644
--- a/usr.sbin/bsnmpd/modules/snmp_hast/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_hast/Makefile.depend
@@ -2,6 +2,7 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
+ gnu/lib/csu \
gnu/lib/libgcc \
include \
include/arpa \
@@ -11,6 +12,7 @@ DIRDEPS = \
lib/libc \
lib/libcompiler_rt \
lib/libutil \
+ usr.bin/yacc.host \
usr.sbin/bsnmpd/modules \
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile.depend
index 64bb2df..a492080 100644
--- a/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/Makefile.depend
@@ -15,7 +15,6 @@ DIRDEPS = \
lib/libkvm \
lib/libmemstat \
lib/msun \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
usr.sbin/bsnmpd/modules/snmp_mibII \
diff --git a/usr.sbin/bsnmpd/modules/snmp_lm75/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_lm75/Makefile.depend
index ea1a0a5..e3d0506 100644
--- a/usr.sbin/bsnmpd/modules/snmp_lm75/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_lm75/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
diff --git a/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile.depend
index 8e546b0..32018d0 100644
--- a/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_mibII/Makefile.depend
@@ -11,7 +11,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
.include <dirdeps.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile.depend
index 19bbcd5..cad32c9 100644
--- a/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_netgraph/Makefile.depend
@@ -11,7 +11,6 @@ DIRDEPS = \
lib/libc \
lib/libcompiler_rt \
lib/libnetgraph \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
diff --git a/usr.sbin/bsnmpd/modules/snmp_pf/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_pf/Makefile.depend
index 6843d75..855779d 100644
--- a/usr.sbin/bsnmpd/modules/snmp_pf/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_pf/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
diff --git a/usr.sbin/bsnmpd/modules/snmp_target/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_target/Makefile.depend
index c8536c4..66ec571 100644
--- a/usr.sbin/bsnmpd/modules/snmp_target/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_target/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
.include <dirdeps.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_usm/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_usm/Makefile.depend
index 2e9a3fe..a7180f9 100644
--- a/usr.sbin/bsnmpd/modules/snmp_usm/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_usm/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
.include <dirdeps.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile.depend
index 25501c8..89b4f2b 100644
--- a/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
.include <dirdeps.mk>
diff --git a/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile.depend b/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile.depend
index 80b1aea..329da3d 100644
--- a/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile.depend
+++ b/usr.sbin/bsnmpd/modules/snmp_wlan/Makefile.depend
@@ -10,7 +10,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
usr.sbin/bsnmpd/modules \
usr.sbin/bsnmpd/modules/snmp_mibII \
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile.depend b/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile.depend
index 06abcea..fc79573 100644
--- a/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile.depend
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/Makefile.depend
@@ -11,7 +11,6 @@ DIRDEPS = \
lib/libbsnmp/libbsnmp \
lib/libc \
lib/libcompiler_rt \
- usr.bin/xinstall.host \
.include <dirdeps.mk>
diff --git a/usr.sbin/camdd/Makefile b/usr.sbin/camdd/Makefile
new file mode 100644
index 0000000..64ee61b
--- /dev/null
+++ b/usr.sbin/camdd/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+PROG= camdd
+SRCS= camdd.c
+SDIR= ${.CURDIR}/../../sys
+LIBADD= cam mt util pthread
+NO_WTHREAD_SAFETY= 1
+MAN= camdd.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/camdd/Makefile.depend b/usr.sbin/camdd/Makefile.depend
new file mode 100644
index 0000000..17ca2bc
--- /dev/null
+++ b/usr.sbin/camdd/Makefile.depend
@@ -0,0 +1,25 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcam \
+ lib/libcompiler_rt \
+ lib/libexpat \
+ lib/libmt \
+ lib/libsbuf \
+ lib/libthr \
+ lib/libutil \
+ lib/libz \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/camdd/camdd.8 b/usr.sbin/camdd/camdd.8
new file mode 100644
index 0000000..af556bb
--- /dev/null
+++ b/usr.sbin/camdd/camdd.8
@@ -0,0 +1,283 @@
+.\"
+.\" Copyright (c) 2015 Spectra Logic Corporation
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions, and the following disclaimer,
+.\" without modification.
+.\" 2. Redistributions in binary form must reproduce at minimum a disclaimer
+.\" substantially similar to the "NO WARRANTY" disclaimer below
+.\" ("Disclaimer") and any redistribution must be conditioned upon
+.\" including a substantially similar Disclaimer requirement for further
+.\" binary redistribution.
+.\"
+.\" NO WARRANTY
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+.\" "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+.\" A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+.\" HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGES.
+.\"
+.\" Authors: Ken Merry (Spectra Logic Corporation)
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 11, 2015
+.Dt CAMDD 8
+.Os
+.Sh NAME
+.Nm camdd
+.Nd CAM data transfer utility
+.Sh SYNOPSIS
+.Nm
+.Aq Fl i|o Ar pass=pass_dev|file=filename,bs=blocksize,[...]
+.Op Fl C Ar retry_count
+.Op Fl E
+.Op Fl m Ar max_io
+.Op Fl t Ar timeout
+.Op Fl v
+.Op Fl h
+.Sh DESCRIPTION
+The
+.Nm
+utility is a sequential data transfer utility that offers standard
+.Xr read 2
+and
+.Xr write 2
+operation in addition to a mode that uses the asynchronous
+.Xr pass 4
+API.
+The asynchronous
+.Xr pass 4
+API allows multiple requests to be queued to a device simultaneously.
+.Pp
+.Nm
+collects performance information and will display it when the transfer
+completes, when
+.Nm
+is terminated or when it receives a SIGINFO signal.
+.Pp
+The following options are available:
+.Bl -tag -width 12n
+.It Fl i | o Ar args
+Specify the input and output device or file.
+Both
+.Fl i
+and
+.Fl o
+must be specified.
+There are a number of parameters that can be specified.
+One of the first two (file or pass) MUST be specified to indicate which I/O
+method to use on the device in question.
+.Bl -tag -width 9n
+.It pass=dev
+Specify a
+.Xr pass 4
+device to operate on.
+This requests that
+.Nm
+access the device in question be accessed via the asynchronous
+.Xr pass 4
+interface.
+.Pp
+The device name can be a
+.Xr pass 4
+name and unit number, for instance
+.Dq pass0 ,
+or a regular peripheral driver name and unit number, for instance
+.Dq da5 .
+It can also be the path of a
+.Xr pass 4
+or other disk device, like
+.Dq /dev/da5 .
+It may also be a bus:target:lun, for example:
+.Dq 0:5:0 .
+.Pp
+Only
+.Xr pass 4
+devices for
+.Tn SCSI
+disk-like devices are supported.
+.Tn ATA
+devices are not currently supported, but support could be added later.
+Specifically,
+.Tn SCSI
+Direct Access (type 0), WORM (type 4), CDROM (type 5), and RBC (Reduced
+Block Command, type 14) devices are supported.
+Tape drives, medium changers, enclosures etc. are not supported.
+.It file=path
+Specify a file or device to operate on.
+This requests that the file or device in question be accessed using the
+standard
+.Xr read 2
+and
+.Xr write 2
+system calls.
+The file interface does not support queueing multiple commands at a time.
+It does support probing disk sector size and capacity information, and tape
+blocksize and maximum transfer size information.
+The file interface supports standard files, disks, tape drives, special
+devices, pipes and standard input and output.
+If the file is specified as a
+.Dq - ,
+standard input or standard output are used.
+For tape devices, the specified blocksize will be the size that
+.Nm
+attempts to use to write to or read from the tape.
+When writing to a tape device, the blocksize is treated like a disk sector
+size.
+So, that means
+.Nm
+will not write anything smaller than the sector size.
+At the end of a transfer, if there isn't sufficient data from the reader
+to yield a full block,
+.Nm
+will add zeros on the end of the data from the reader to make up a full
+block.
+.It bs=N
+Specify the blocksize to use for transfers.
+.Nm
+will attempt to read or write using the requested blocksize.
+.Pp
+Note that the blocksize given only applies to either the input or the
+output path.
+To use the same blocksize for the input and output transfers, you must
+specify that blocksize with both the
+.Fl i
+and
+.Fl o
+arguments.
+.Pp
+The blocksize may be specified in bytes, or using any suffix (e.g. k, M, G)
+supported by
+.Xr expand_number 3 .
+.It offset=N
+Specify the starting offset for the input or output device or file.
+The offset may be specified in bytes, or by using any suffix (e.g. k, M, G)
+supported by
+.Xr expand_number 3 .
+.It depth=N
+Specify a desired queue depth for the input or output path.
+.Nm
+will attempt to keep the requested number of requests of the specified
+blocksize queued to the input or output device.
+Queue depths greater than 1 are only supported for the asynchronous
+.Xr pass 4
+output method.
+The queue depth is maintained on a best effort basis, and may not be
+possible to maintain for especially fast devices.
+For writes, maintaining the queue depth also depends on a sufficiently
+fast reading device.
+.It mcs=N
+Specify the minimum command size to use for
+.Xr pass 4
+devices.
+Some devices do not support 6 byte
+.Tn SCSI
+commands.
+The
+.Xr da 4
+device handles this restriction automatically, but the
+.Xr pass 4
+device allows the user to specify the
+.Tn SCSI
+command used.
+If a device does not accept 6 byte
+.Tn SCSI
+READ/WRITE commands (which is the default at lower LBAs), it will generally
+accept 10 byte
+.Tn SCSI
+commands instead.
+.It debug=N
+Specify the debug level for this device.
+There is currently only one debug level setting, so setting this to any
+non-zero value will turn on debugging.
+The debug facility may be expanded in the future.
+.El
+.It Fl C Ar count
+Specify the retry count for commands sent via the asynchronous
+.Xr pass 4
+interface.
+This does not apply to commands sent via the file interface.
+.It Fl E
+Enable kernel error recovery for the
+.Xr pass 4
+driver.
+If error recovery is not enabled, unit attention conditions and other
+transient failures may cause the transfer to fail.
+.It Fl m Ar size
+Specify the maximum amount of data to be transferred.
+This may be specified in bytes, or by using any suffix (e.g. K, M, G)
+supported by
+.Xr expand_number 3 .
+.It Fl t Ar timeout
+Specify the command timeout in seconds to use for commands sent via the
+.Xr pass 4
+driver.
+.It Fl v
+Enable verbose reporting of errors.
+This is recommended to aid in debugging any
+.Tn SCSI
+issues that come up.
+.It Fl h
+Display the
+.Nm
+usage message.
+.El
+.Pp
+If
+.Nm
+receives a SIGINFO signal, it will print the current input and output byte
+counts, elapsed runtime and average throughput.
+If
+.Nm
+receives a SIGINT signal, it will print the current input and output byte
+counts, elapsed runtime and average throughput and then exit.
+.Sh EXAMPLES
+.Dl camdd -i pass=da8,bs=512k,depth=4 -o pass=da3,bs=512k,depth=4
+.Pp
+Copy all data from da8 to da3 using a blocksize of 512k for both drives,
+and attempt to maintain a queue depth of 4 on both the input and output
+devices.
+The transfer will stop when the end of either device is reached.
+.Pp
+.Dl camdd -i file=/dev/zero,bs=1M -o pass=da5,bs=1M,depth=4 -m 100M
+.Pp
+Read 1MB blocks of zeros from /dev/zero, and write them to da5 with a
+desired queue depth of 4.
+Stop the transfer after 100MB has been written.
+.Pp
+.Dl camdd -i pass=da8,bs=1M,depth=3 -o file=disk.img
+.Pp
+Copy disk da8 using a 1MB blocksize and desired queue depth of 3 to the
+file disk.img.
+.Pp
+.Dl camdd -i file=/etc/rc -o file=-
+.Pp
+Read the file /etc/rc and write it to standard output.
+.Pp
+.Dl camdd -i pass=da10,bs=64k,depth=16 -o file=/dev/nsa0,bs=128k
+.Pp
+Copy 64K blocks from the disk da10 with a queue depth of 16, and write
+to the tape drive sa0 with a 128k blocksize.
+The copy will stop when either the end of the disk or tape is reached.
+.Sh SEE ALSO
+.Xr cam 3 ,
+.Xr cam 4 ,
+.Xr pass 4 ,
+.Xr camcontrol 8
+.Sh HISTORY
+.Nm
+first appeared in
+.Fx 10.2
+.Sh AUTHORS
+.An Kenneth Merry Aq Mt ken@FreeBSD.org
diff --git a/usr.sbin/camdd/camdd.c b/usr.sbin/camdd/camdd.c
new file mode 100644
index 0000000..9284eb5
--- /dev/null
+++ b/usr.sbin/camdd/camdd.c
@@ -0,0 +1,3423 @@
+/*-
+ * Copyright (c) 1997-2007 Kenneth D. Merry
+ * Copyright (c) 2013, 2014, 2015 Spectra Logic Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * Authors: Ken Merry (Spectra Logic Corporation)
+ */
+
+/*
+ * This is eventually intended to be:
+ * - A basic data transfer/copy utility
+ * - A simple benchmark utility
+ * - An example of how to use the asynchronous pass(4) driver interface.
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/ioctl.h>
+#include <sys/stdint.h>
+#include <sys/types.h>
+#include <sys/endian.h>
+#include <sys/param.h>
+#include <sys/sbuf.h>
+#include <sys/stat.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <vm/vm.h>
+#include <machine/bus.h>
+#include <sys/bus.h>
+#include <sys/bus_dma.h>
+#include <sys/mtio.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <semaphore.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <libutil.h>
+#include <pthread.h>
+#include <assert.h>
+#include <bsdxml.h>
+
+#include <cam/cam.h>
+#include <cam/cam_debug.h>
+#include <cam/cam_ccb.h>
+#include <cam/scsi/scsi_all.h>
+#include <cam/scsi/scsi_da.h>
+#include <cam/scsi/scsi_pass.h>
+#include <cam/scsi/scsi_message.h>
+#include <cam/scsi/smp_all.h>
+#include <camlib.h>
+#include <mtlib.h>
+#include <zlib.h>
+
+typedef enum {
+ CAMDD_CMD_NONE = 0x00000000,
+ CAMDD_CMD_HELP = 0x00000001,
+ CAMDD_CMD_WRITE = 0x00000002,
+ CAMDD_CMD_READ = 0x00000003
+} camdd_cmdmask;
+
+typedef enum {
+ CAMDD_ARG_NONE = 0x00000000,
+ CAMDD_ARG_VERBOSE = 0x00000001,
+ CAMDD_ARG_DEVICE = 0x00000002,
+ CAMDD_ARG_BUS = 0x00000004,
+ CAMDD_ARG_TARGET = 0x00000008,
+ CAMDD_ARG_LUN = 0x00000010,
+ CAMDD_ARG_UNIT = 0x00000020,
+ CAMDD_ARG_TIMEOUT = 0x00000040,
+ CAMDD_ARG_ERR_RECOVER = 0x00000080,
+ CAMDD_ARG_RETRIES = 0x00000100
+} camdd_argmask;
+
+typedef enum {
+ CAMDD_DEV_NONE = 0x00,
+ CAMDD_DEV_PASS = 0x01,
+ CAMDD_DEV_FILE = 0x02
+} camdd_dev_type;
+
+struct camdd_io_opts {
+ camdd_dev_type dev_type;
+ char *dev_name;
+ uint64_t blocksize;
+ uint64_t queue_depth;
+ uint64_t offset;
+ int min_cmd_size;
+ int write_dev;
+ uint64_t debug;
+};
+
+typedef enum {
+ CAMDD_BUF_NONE,
+ CAMDD_BUF_DATA,
+ CAMDD_BUF_INDIRECT
+} camdd_buf_type;
+
+struct camdd_buf_indirect {
+ /*
+ * Pointer to the source buffer.
+ */
+ struct camdd_buf *src_buf;
+
+ /*
+ * Offset into the source buffer, in bytes.
+ */
+ uint64_t offset;
+ /*
+ * Pointer to the starting point in the source buffer.
+ */
+ uint8_t *start_ptr;
+
+ /*
+ * Length of this chunk in bytes.
+ */
+ size_t len;
+};
+
+struct camdd_buf_data {
+ /*
+ * Buffer allocated when we allocate this camdd_buf. This should
+ * be the size of the blocksize for this device.
+ */
+ uint8_t *buf;
+
+ /*
+ * The amount of backing store allocated in buf. Generally this
+ * will be the blocksize of the device.
+ */
+ uint32_t alloc_len;
+
+ /*
+ * The amount of data that was put into the buffer (on reads) or
+ * the amount of data we have put onto the src_list so far (on
+ * writes).
+ */
+ uint32_t fill_len;
+
+ /*
+ * The amount of data that was not transferred.
+ */
+ uint32_t resid;
+
+ /*
+ * Starting byte offset on the reader.
+ */
+ uint64_t src_start_offset;
+
+ /*
+ * CCB used for pass(4) device targets.
+ */
+ union ccb ccb;
+
+ /*
+ * Number of scatter/gather segments.
+ */
+ int sg_count;
+
+ /*
+ * Set if we had to tack on an extra buffer to round the transfer
+ * up to a sector size.
+ */
+ int extra_buf;
+
+ /*
+ * Scatter/gather list used generally when we're the writer for a
+ * pass(4) device.
+ */
+ bus_dma_segment_t *segs;
+
+ /*
+ * Scatter/gather list used generally when we're the writer for a
+ * file or block device;
+ */
+ struct iovec *iovec;
+};
+
+union camdd_buf_types {
+ struct camdd_buf_indirect indirect;
+ struct camdd_buf_data data;
+};
+
+typedef enum {
+ CAMDD_STATUS_NONE,
+ CAMDD_STATUS_OK,
+ CAMDD_STATUS_SHORT_IO,
+ CAMDD_STATUS_EOF,
+ CAMDD_STATUS_ERROR
+} camdd_buf_status;
+
+struct camdd_buf {
+ camdd_buf_type buf_type;
+ union camdd_buf_types buf_type_spec;
+
+ camdd_buf_status status;
+
+ uint64_t lba;
+ size_t len;
+
+ /*
+ * A reference count of how many indirect buffers point to this
+ * buffer.
+ */
+ int refcount;
+
+ /*
+ * A link back to our parent device.
+ */
+ struct camdd_dev *dev;
+ STAILQ_ENTRY(camdd_buf) links;
+ STAILQ_ENTRY(camdd_buf) work_links;
+
+ /*
+ * A count of the buffers on the src_list.
+ */
+ int src_count;
+
+ /*
+ * List of buffers from our partner thread that are the components
+ * of this buffer for the I/O. Uses src_links.
+ */
+ STAILQ_HEAD(,camdd_buf) src_list;
+ STAILQ_ENTRY(camdd_buf) src_links;
+};
+
+#define NUM_DEV_TYPES 2
+
+struct camdd_dev_pass {
+ int scsi_dev_type;
+ struct cam_device *dev;
+ uint64_t max_sector;
+ uint32_t block_len;
+ uint32_t cpi_maxio;
+};
+
+typedef enum {
+ CAMDD_FILE_NONE,
+ CAMDD_FILE_REG,
+ CAMDD_FILE_STD,
+ CAMDD_FILE_PIPE,
+ CAMDD_FILE_DISK,
+ CAMDD_FILE_TAPE,
+ CAMDD_FILE_TTY,
+ CAMDD_FILE_MEM
+} camdd_file_type;
+
+typedef enum {
+ CAMDD_FF_NONE = 0x00,
+ CAMDD_FF_CAN_SEEK = 0x01
+} camdd_file_flags;
+
+struct camdd_dev_file {
+ int fd;
+ struct stat sb;
+ char filename[MAXPATHLEN + 1];
+ camdd_file_type file_type;
+ camdd_file_flags file_flags;
+ uint8_t *tmp_buf;
+};
+
+struct camdd_dev_block {
+ int fd;
+ uint64_t size_bytes;
+ uint32_t block_len;
+};
+
+union camdd_dev_spec {
+ struct camdd_dev_pass pass;
+ struct camdd_dev_file file;
+ struct camdd_dev_block block;
+};
+
+typedef enum {
+ CAMDD_DEV_FLAG_NONE = 0x00,
+ CAMDD_DEV_FLAG_EOF = 0x01,
+ CAMDD_DEV_FLAG_PEER_EOF = 0x02,
+ CAMDD_DEV_FLAG_ACTIVE = 0x04,
+ CAMDD_DEV_FLAG_EOF_SENT = 0x08,
+ CAMDD_DEV_FLAG_EOF_QUEUED = 0x10
+} camdd_dev_flags;
+
+struct camdd_dev {
+ camdd_dev_type dev_type;
+ union camdd_dev_spec dev_spec;
+ camdd_dev_flags flags;
+ char device_name[MAXPATHLEN+1];
+ uint32_t blocksize;
+ uint32_t sector_size;
+ uint64_t max_sector;
+ uint64_t sector_io_limit;
+ int min_cmd_size;
+ int write_dev;
+ int retry_count;
+ int io_timeout;
+ int debug;
+ uint64_t start_offset_bytes;
+ uint64_t next_io_pos_bytes;
+ uint64_t next_peer_pos_bytes;
+ uint64_t next_completion_pos_bytes;
+ uint64_t peer_bytes_queued;
+ uint64_t bytes_transferred;
+ uint32_t target_queue_depth;
+ uint32_t cur_active_io;
+ uint8_t *extra_buf;
+ uint32_t extra_buf_len;
+ struct camdd_dev *peer_dev;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int kq;
+
+ int (*run)(struct camdd_dev *dev);
+ int (*fetch)(struct camdd_dev *dev);
+
+ /*
+ * Buffers that are available for I/O. Uses links.
+ */
+ STAILQ_HEAD(,camdd_buf) free_queue;
+
+ /*
+ * Free indirect buffers. These are used for breaking a large
+ * buffer into multiple pieces.
+ */
+ STAILQ_HEAD(,camdd_buf) free_indirect_queue;
+
+ /*
+ * Buffers that have been queued to the kernel. Uses links.
+ */
+ STAILQ_HEAD(,camdd_buf) active_queue;
+
+ /*
+ * Will generally contain one of our buffers that is waiting for enough
+ * I/O from our partner thread to be able to execute. This will
+ * generally happen when our per-I/O-size is larger than the
+ * partner thread's per-I/O-size. Uses links.
+ */
+ STAILQ_HEAD(,camdd_buf) pending_queue;
+
+ /*
+ * Number of buffers on the pending queue
+ */
+ int num_pending_queue;
+
+ /*
+ * Buffers that are filled and ready to execute. This is used when
+ * our partner (reader) thread sends us blocks that are larger than
+ * our blocksize, and so we have to split them into multiple pieces.
+ */
+ STAILQ_HEAD(,camdd_buf) run_queue;
+
+ /*
+ * Number of buffers on the run queue.
+ */
+ int num_run_queue;
+
+ STAILQ_HEAD(,camdd_buf) reorder_queue;
+
+ int num_reorder_queue;
+
+ /*
+ * Buffers that have been queued to us by our partner thread
+ * (generally the reader thread) to be written out. Uses
+ * work_links.
+ */
+ STAILQ_HEAD(,camdd_buf) work_queue;
+
+ /*
+ * Buffers that have been completed by our partner thread. Uses
+ * work_links.
+ */
+ STAILQ_HEAD(,camdd_buf) peer_done_queue;
+
+ /*
+ * Number of buffers on the peer done queue.
+ */
+ uint32_t num_peer_done_queue;
+
+ /*
+ * A list of buffers that we have queued to our peer thread. Uses
+ * links.
+ */
+ STAILQ_HEAD(,camdd_buf) peer_work_queue;
+
+ /*
+ * Number of buffers on the peer work queue.
+ */
+ uint32_t num_peer_work_queue;
+};
+
+static sem_t camdd_sem;
+static int need_exit = 0;
+static int error_exit = 0;
+static int need_status = 0;
+
+#ifndef min
+#define min(a, b) (a < b) ? a : b
+#endif
+
+/*
+ * XXX KDM private copy of timespecsub(). This is normally defined in
+ * sys/time.h, but is only enabled in the kernel. If that definition is
+ * enabled in userland, it breaks the build of libnetbsd.
+ */
+#ifndef timespecsub
+#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)
+#endif
+
+
+/* Generically usefull offsets into the peripheral private area */
+#define ppriv_ptr0 periph_priv.entries[0].ptr
+#define ppriv_ptr1 periph_priv.entries[1].ptr
+#define ppriv_field0 periph_priv.entries[0].field
+#define ppriv_field1 periph_priv.entries[1].field
+
+#define ccb_buf ppriv_ptr0
+
+#define CAMDD_FILE_DEFAULT_BLOCK 524288
+#define CAMDD_FILE_DEFAULT_DEPTH 1
+#define CAMDD_PASS_MAX_BLOCK 1048576
+#define CAMDD_PASS_DEFAULT_DEPTH 6
+#define CAMDD_PASS_RW_TIMEOUT 60 * 1000
+
+static int parse_btl(char *tstr, int *bus, int *target, int *lun,
+ camdd_argmask *arglst);
+void camdd_free_dev(struct camdd_dev *dev);
+struct camdd_dev *camdd_alloc_dev(camdd_dev_type dev_type,
+ struct kevent *new_ke, int num_ke,
+ int retry_count, int timeout);
+static struct camdd_buf *camdd_alloc_buf(struct camdd_dev *dev,
+ camdd_buf_type buf_type);
+void camdd_release_buf(struct camdd_buf *buf);
+struct camdd_buf *camdd_get_buf(struct camdd_dev *dev, camdd_buf_type buf_type);
+int camdd_buf_sg_create(struct camdd_buf *buf, int iovec,
+ uint32_t sector_size, uint32_t *num_sectors_used,
+ int *double_buf_needed);
+uint32_t camdd_buf_get_len(struct camdd_buf *buf);
+void camdd_buf_add_child(struct camdd_buf *buf, struct camdd_buf *child_buf);
+int camdd_probe_tape(int fd, char *filename, uint64_t *max_iosize,
+ uint64_t *max_blk, uint64_t *min_blk, uint64_t *blk_gran);
+struct camdd_dev *camdd_probe_file(int fd, struct camdd_io_opts *io_opts,
+ int retry_count, int timeout);
+struct camdd_dev *camdd_probe_pass(struct cam_device *cam_dev,
+ struct camdd_io_opts *io_opts,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, int io_retry_count,
+ int io_timeout);
+void *camdd_file_worker(void *arg);
+camdd_buf_status camdd_ccb_status(union ccb *ccb);
+int camdd_queue_peer_buf(struct camdd_dev *dev, struct camdd_buf *buf);
+int camdd_complete_peer_buf(struct camdd_dev *dev, struct camdd_buf *peer_buf);
+void camdd_peer_done(struct camdd_buf *buf);
+void camdd_complete_buf(struct camdd_dev *dev, struct camdd_buf *buf,
+ int *error_count);
+int camdd_pass_fetch(struct camdd_dev *dev);
+int camdd_file_run(struct camdd_dev *dev);
+int camdd_pass_run(struct camdd_dev *dev);
+int camdd_get_next_lba_len(struct camdd_dev *dev, uint64_t *lba, ssize_t *len);
+int camdd_queue(struct camdd_dev *dev, struct camdd_buf *read_buf);
+void camdd_get_depth(struct camdd_dev *dev, uint32_t *our_depth,
+ uint32_t *peer_depth, uint32_t *our_bytes,
+ uint32_t *peer_bytes);
+void *camdd_worker(void *arg);
+void camdd_sig_handler(int sig);
+void camdd_print_status(struct camdd_dev *camdd_dev,
+ struct camdd_dev *other_dev,
+ struct timespec *start_time);
+int camdd_rw(struct camdd_io_opts *io_opts, int num_io_opts,
+ uint64_t max_io, int retry_count, int timeout);
+int camdd_parse_io_opts(char *args, int is_write,
+ struct camdd_io_opts *io_opts);
+void usage(void);
+
+/*
+ * Parse out a bus, or a bus, target and lun in the following
+ * format:
+ * bus
+ * bus:target
+ * bus:target:lun
+ *
+ * Returns the number of parsed components, or 0.
+ */
+static int
+parse_btl(char *tstr, int *bus, int *target, int *lun, camdd_argmask *arglst)
+{
+ char *tmpstr;
+ int convs = 0;
+
+ while (isspace(*tstr) && (*tstr != '\0'))
+ tstr++;
+
+ tmpstr = (char *)strtok(tstr, ":");
+ if ((tmpstr != NULL) && (*tmpstr != '\0')) {
+ *bus = strtol(tmpstr, NULL, 0);
+ *arglst |= CAMDD_ARG_BUS;
+ convs++;
+ tmpstr = (char *)strtok(NULL, ":");
+ if ((tmpstr != NULL) && (*tmpstr != '\0')) {
+ *target = strtol(tmpstr, NULL, 0);
+ *arglst |= CAMDD_ARG_TARGET;
+ convs++;
+ tmpstr = (char *)strtok(NULL, ":");
+ if ((tmpstr != NULL) && (*tmpstr != '\0')) {
+ *lun = strtol(tmpstr, NULL, 0);
+ *arglst |= CAMDD_ARG_LUN;
+ convs++;
+ }
+ }
+ }
+
+ return convs;
+}
+
+/*
+ * XXX KDM clean up and free all of the buffers on the queue!
+ */
+void
+camdd_free_dev(struct camdd_dev *dev)
+{
+ if (dev == NULL)
+ return;
+
+ switch (dev->dev_type) {
+ case CAMDD_DEV_FILE: {
+ struct camdd_dev_file *file_dev = &dev->dev_spec.file;
+
+ if (file_dev->fd != -1)
+ close(file_dev->fd);
+ free(file_dev->tmp_buf);
+ break;
+ }
+ case CAMDD_DEV_PASS: {
+ struct camdd_dev_pass *pass_dev = &dev->dev_spec.pass;
+
+ if (pass_dev->dev != NULL)
+ cam_close_device(pass_dev->dev);
+ break;
+ }
+ default:
+ break;
+ }
+
+ free(dev);
+}
+
+struct camdd_dev *
+camdd_alloc_dev(camdd_dev_type dev_type, struct kevent *new_ke, int num_ke,
+ int retry_count, int timeout)
+{
+ struct camdd_dev *dev = NULL;
+ struct kevent *ke;
+ size_t ke_size;
+ int retval = 0;
+
+ dev = malloc(sizeof(*dev));
+ if (dev == NULL) {
+ warn("%s: unable to malloc %zu bytes", __func__, sizeof(*dev));
+ goto bailout;
+ }
+
+ bzero(dev, sizeof(*dev));
+
+ dev->dev_type = dev_type;
+ dev->io_timeout = timeout;
+ dev->retry_count = retry_count;
+ STAILQ_INIT(&dev->free_queue);
+ STAILQ_INIT(&dev->free_indirect_queue);
+ STAILQ_INIT(&dev->active_queue);
+ STAILQ_INIT(&dev->pending_queue);
+ STAILQ_INIT(&dev->run_queue);
+ STAILQ_INIT(&dev->reorder_queue);
+ STAILQ_INIT(&dev->work_queue);
+ STAILQ_INIT(&dev->peer_done_queue);
+ STAILQ_INIT(&dev->peer_work_queue);
+ retval = pthread_mutex_init(&dev->mutex, NULL);
+ if (retval != 0) {
+ warnc(retval, "%s: failed to initialize mutex", __func__);
+ goto bailout;
+ }
+
+ retval = pthread_cond_init(&dev->cond, NULL);
+ if (retval != 0) {
+ warnc(retval, "%s: failed to initialize condition variable",
+ __func__);
+ goto bailout;
+ }
+
+ dev->kq = kqueue();
+ if (dev->kq == -1) {
+ warn("%s: Unable to create kqueue", __func__);
+ goto bailout;
+ }
+
+ ke_size = sizeof(struct kevent) * (num_ke + 4);
+ ke = malloc(ke_size);
+ if (ke == NULL) {
+ warn("%s: unable to malloc %zu bytes", __func__, ke_size);
+ goto bailout;
+ }
+ bzero(ke, ke_size);
+ if (num_ke > 0)
+ bcopy(new_ke, ke, num_ke * sizeof(struct kevent));
+
+ EV_SET(&ke[num_ke++], (uintptr_t)&dev->work_queue, EVFILT_USER,
+ EV_ADD|EV_ENABLE|EV_CLEAR, 0,0, 0);
+ EV_SET(&ke[num_ke++], (uintptr_t)&dev->peer_done_queue, EVFILT_USER,
+ EV_ADD|EV_ENABLE|EV_CLEAR, 0,0, 0);
+ EV_SET(&ke[num_ke++], SIGINFO, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0,0,0);
+ EV_SET(&ke[num_ke++], SIGINT, EVFILT_SIGNAL, EV_ADD|EV_ENABLE, 0,0,0);
+
+ retval = kevent(dev->kq, ke, num_ke, NULL, 0, NULL);
+ if (retval == -1) {
+ warn("%s: Unable to register kevents", __func__);
+ goto bailout;
+ }
+
+
+ return (dev);
+
+bailout:
+ free(dev);
+
+ return (NULL);
+}
+
+static struct camdd_buf *
+camdd_alloc_buf(struct camdd_dev *dev, camdd_buf_type buf_type)
+{
+ struct camdd_buf *buf = NULL;
+ uint8_t *data_ptr = NULL;
+
+ /*
+ * We only need to allocate data space for data buffers.
+ */
+ switch (buf_type) {
+ case CAMDD_BUF_DATA:
+ data_ptr = malloc(dev->blocksize);
+ if (data_ptr == NULL) {
+ warn("unable to allocate %u bytes", dev->blocksize);
+ goto bailout_error;
+ }
+ break;
+ default:
+ break;
+ }
+
+ buf = malloc(sizeof(*buf));
+ if (buf == NULL) {
+ warn("unable to allocate %zu bytes", sizeof(*buf));
+ goto bailout_error;
+ }
+
+ bzero(buf, sizeof(*buf));
+ buf->buf_type = buf_type;
+ buf->dev = dev;
+ switch (buf_type) {
+ case CAMDD_BUF_DATA: {
+ struct camdd_buf_data *data;
+
+ data = &buf->buf_type_spec.data;
+
+ data->alloc_len = dev->blocksize;
+ data->buf = data_ptr;
+ break;
+ }
+ case CAMDD_BUF_INDIRECT:
+ break;
+ default:
+ break;
+ }
+ STAILQ_INIT(&buf->src_list);
+
+ return (buf);
+
+bailout_error:
+ if (data_ptr != NULL)
+ free(data_ptr);
+
+ if (buf != NULL)
+ free(buf);
+
+ return (NULL);
+}
+
+void
+camdd_release_buf(struct camdd_buf *buf)
+{
+ struct camdd_dev *dev;
+
+ dev = buf->dev;
+
+ switch (buf->buf_type) {
+ case CAMDD_BUF_DATA: {
+ struct camdd_buf_data *data;
+
+ data = &buf->buf_type_spec.data;
+
+ if (data->segs != NULL) {
+ if (data->extra_buf != 0) {
+ void *extra_buf;
+
+ extra_buf = (void *)
+ data->segs[data->sg_count - 1].ds_addr;
+ free(extra_buf);
+ data->extra_buf = 0;
+ }
+ free(data->segs);
+ data->segs = NULL;
+ data->sg_count = 0;
+ } else if (data->iovec != NULL) {
+ if (data->extra_buf != 0) {
+ free(data->iovec[data->sg_count - 1].iov_base);
+ data->extra_buf = 0;
+ }
+ free(data->iovec);
+ data->iovec = NULL;
+ data->sg_count = 0;
+ }
+ STAILQ_INSERT_TAIL(&dev->free_queue, buf, links);
+ break;
+ }
+ case CAMDD_BUF_INDIRECT:
+ STAILQ_INSERT_TAIL(&dev->free_indirect_queue, buf, links);
+ break;
+ default:
+ err(1, "%s: Invalid buffer type %d for released buffer",
+ __func__, buf->buf_type);
+ break;
+ }
+}
+
+struct camdd_buf *
+camdd_get_buf(struct camdd_dev *dev, camdd_buf_type buf_type)
+{
+ struct camdd_buf *buf = NULL;
+
+ switch (buf_type) {
+ case CAMDD_BUF_DATA:
+ buf = STAILQ_FIRST(&dev->free_queue);
+ if (buf != NULL) {
+ struct camdd_buf_data *data;
+ uint8_t *data_ptr;
+ uint32_t alloc_len;
+
+ STAILQ_REMOVE_HEAD(&dev->free_queue, links);
+ data = &buf->buf_type_spec.data;
+ data_ptr = data->buf;
+ alloc_len = data->alloc_len;
+ bzero(buf, sizeof(*buf));
+ data->buf = data_ptr;
+ data->alloc_len = alloc_len;
+ }
+ break;
+ case CAMDD_BUF_INDIRECT:
+ buf = STAILQ_FIRST(&dev->free_indirect_queue);
+ if (buf != NULL) {
+ STAILQ_REMOVE_HEAD(&dev->free_indirect_queue, links);
+
+ bzero(buf, sizeof(*buf));
+ }
+ break;
+ default:
+ warnx("Unknown buffer type %d requested", buf_type);
+ break;
+ }
+
+
+ if (buf == NULL)
+ return (camdd_alloc_buf(dev, buf_type));
+ else {
+ STAILQ_INIT(&buf->src_list);
+ buf->dev = dev;
+ buf->buf_type = buf_type;
+
+ return (buf);
+ }
+}
+
+int
+camdd_buf_sg_create(struct camdd_buf *buf, int iovec, uint32_t sector_size,
+ uint32_t *num_sectors_used, int *double_buf_needed)
+{
+ struct camdd_buf *tmp_buf;
+ struct camdd_buf_data *data;
+ uint8_t *extra_buf = NULL;
+ size_t extra_buf_len = 0;
+ int i, retval = 0;
+
+ data = &buf->buf_type_spec.data;
+
+ data->sg_count = buf->src_count;
+ /*
+ * Compose a scatter/gather list from all of the buffers in the list.
+ * If the length of the buffer isn't a multiple of the sector size,
+ * we'll have to add an extra buffer. This should only happen
+ * at the end of a transfer.
+ */
+ if ((data->fill_len % sector_size) != 0) {
+ extra_buf_len = sector_size - (data->fill_len % sector_size);
+ extra_buf = calloc(extra_buf_len, 1);
+ if (extra_buf == NULL) {
+ warn("%s: unable to allocate %zu bytes for extra "
+ "buffer space", __func__, extra_buf_len);
+ retval = 1;
+ goto bailout;
+ }
+ data->extra_buf = 1;
+ data->sg_count++;
+ }
+ if (iovec == 0) {
+ data->segs = calloc(data->sg_count, sizeof(bus_dma_segment_t));
+ if (data->segs == NULL) {
+ warn("%s: unable to allocate %zu bytes for S/G list",
+ __func__, sizeof(bus_dma_segment_t) *
+ data->sg_count);
+ retval = 1;
+ goto bailout;
+ }
+
+ } else {
+ data->iovec = calloc(data->sg_count, sizeof(struct iovec));
+ if (data->iovec == NULL) {
+ warn("%s: unable to allocate %zu bytes for S/G list",
+ __func__, sizeof(struct iovec) * data->sg_count);
+ retval = 1;
+ goto bailout;
+ }
+ }
+
+ for (i = 0, tmp_buf = STAILQ_FIRST(&buf->src_list);
+ i < buf->src_count && tmp_buf != NULL; i++,
+ tmp_buf = STAILQ_NEXT(tmp_buf, src_links)) {
+
+ if (tmp_buf->buf_type == CAMDD_BUF_DATA) {
+ struct camdd_buf_data *tmp_data;
+
+ tmp_data = &tmp_buf->buf_type_spec.data;
+ if (iovec == 0) {
+ data->segs[i].ds_addr =
+ (bus_addr_t) tmp_data->buf;
+ data->segs[i].ds_len = tmp_data->fill_len -
+ tmp_data->resid;
+ } else {
+ data->iovec[i].iov_base = tmp_data->buf;
+ data->iovec[i].iov_len = tmp_data->fill_len -
+ tmp_data->resid;
+ }
+ if (((tmp_data->fill_len - tmp_data->resid) %
+ sector_size) != 0)
+ *double_buf_needed = 1;
+ } else {
+ struct camdd_buf_indirect *tmp_ind;
+
+ tmp_ind = &tmp_buf->buf_type_spec.indirect;
+ if (iovec == 0) {
+ data->segs[i].ds_addr =
+ (bus_addr_t)tmp_ind->start_ptr;
+ data->segs[i].ds_len = tmp_ind->len;
+ } else {
+ data->iovec[i].iov_base = tmp_ind->start_ptr;
+ data->iovec[i].iov_len = tmp_ind->len;
+ }
+ if ((tmp_ind->len % sector_size) != 0)
+ *double_buf_needed = 1;
+ }
+ }
+
+ if (extra_buf != NULL) {
+ if (iovec == 0) {
+ data->segs[i].ds_addr = (bus_addr_t)extra_buf;
+ data->segs[i].ds_len = extra_buf_len;
+ } else {
+ data->iovec[i].iov_base = extra_buf;
+ data->iovec[i].iov_len = extra_buf_len;
+ }
+ i++;
+ }
+ if ((tmp_buf != NULL) || (i != data->sg_count)) {
+ warnx("buffer source count does not match "
+ "number of buffers in list!");
+ retval = 1;
+ goto bailout;
+ }
+
+bailout:
+ if (retval == 0) {
+ *num_sectors_used = (data->fill_len + extra_buf_len) /
+ sector_size;
+ }
+ return (retval);
+}
+
+uint32_t
+camdd_buf_get_len(struct camdd_buf *buf)
+{
+ uint32_t len = 0;
+
+ if (buf->buf_type != CAMDD_BUF_DATA) {
+ struct camdd_buf_indirect *indirect;
+
+ indirect = &buf->buf_type_spec.indirect;
+ len = indirect->len;
+ } else {
+ struct camdd_buf_data *data;
+
+ data = &buf->buf_type_spec.data;
+ len = data->fill_len;
+ }
+
+ return (len);
+}
+
+void
+camdd_buf_add_child(struct camdd_buf *buf, struct camdd_buf *child_buf)
+{
+ struct camdd_buf_data *data;
+
+ assert(buf->buf_type == CAMDD_BUF_DATA);
+
+ data = &buf->buf_type_spec.data;
+
+ STAILQ_INSERT_TAIL(&buf->src_list, child_buf, src_links);
+ buf->src_count++;
+
+ data->fill_len += camdd_buf_get_len(child_buf);
+}
+
+typedef enum {
+ CAMDD_TS_MAX_BLK,
+ CAMDD_TS_MIN_BLK,
+ CAMDD_TS_BLK_GRAN,
+ CAMDD_TS_EFF_IOSIZE
+} camdd_status_item_index;
+
+static struct camdd_status_items {
+ const char *name;
+ struct mt_status_entry *entry;
+} req_status_items[] = {
+ { "max_blk", NULL },
+ { "min_blk", NULL },
+ { "blk_gran", NULL },
+ { "max_effective_iosize", NULL }
+};
+
+int
+camdd_probe_tape(int fd, char *filename, uint64_t *max_iosize,
+ uint64_t *max_blk, uint64_t *min_blk, uint64_t *blk_gran)
+{
+ struct mt_status_data status_data;
+ char *xml_str = NULL;
+ unsigned int i;
+ int retval = 0;
+
+ retval = mt_get_xml_str(fd, MTIOCEXTGET, &xml_str);
+ if (retval != 0)
+ err(1, "Couldn't get XML string from %s", filename);
+
+ retval = mt_get_status(xml_str, &status_data);
+ if (retval != XML_STATUS_OK) {
+ warn("couldn't get status for %s", filename);
+ retval = 1;
+ goto bailout;
+ } else
+ retval = 0;
+
+ if (status_data.error != 0) {
+ warnx("%s", status_data.error_str);
+ retval = 1;
+ goto bailout;
+ }
+
+ for (i = 0; i < sizeof(req_status_items) /
+ sizeof(req_status_items[0]); i++) {
+ char *name;
+
+ name = __DECONST(char *, req_status_items[i].name);
+ req_status_items[i].entry = mt_status_entry_find(&status_data,
+ name);
+ if (req_status_items[i].entry == NULL) {
+ errx(1, "Cannot find status entry %s",
+ req_status_items[i].name);
+ }
+ }
+
+ *max_iosize = req_status_items[CAMDD_TS_EFF_IOSIZE].entry->value_unsigned;
+ *max_blk= req_status_items[CAMDD_TS_MAX_BLK].entry->value_unsigned;
+ *min_blk= req_status_items[CAMDD_TS_MIN_BLK].entry->value_unsigned;
+ *blk_gran = req_status_items[CAMDD_TS_BLK_GRAN].entry->value_unsigned;
+bailout:
+
+ free(xml_str);
+ mt_status_free(&status_data);
+
+ return (retval);
+}
+
+struct camdd_dev *
+camdd_probe_file(int fd, struct camdd_io_opts *io_opts, int retry_count,
+ int timeout)
+{
+ struct camdd_dev *dev = NULL;
+ struct camdd_dev_file *file_dev;
+ uint64_t blocksize = io_opts->blocksize;
+
+ dev = camdd_alloc_dev(CAMDD_DEV_FILE, NULL, 0, retry_count, timeout);
+ if (dev == NULL)
+ goto bailout;
+
+ file_dev = &dev->dev_spec.file;
+ file_dev->fd = fd;
+ strlcpy(file_dev->filename, io_opts->dev_name,
+ sizeof(file_dev->filename));
+ strlcpy(dev->device_name, io_opts->dev_name, sizeof(dev->device_name));
+ if (blocksize == 0)
+ dev->blocksize = CAMDD_FILE_DEFAULT_BLOCK;
+ else
+ dev->blocksize = blocksize;
+
+ if ((io_opts->queue_depth != 0)
+ && (io_opts->queue_depth != 1)) {
+ warnx("Queue depth %ju for %s ignored, only 1 outstanding "
+ "command supported", (uintmax_t)io_opts->queue_depth,
+ io_opts->dev_name);
+ }
+ dev->target_queue_depth = CAMDD_FILE_DEFAULT_DEPTH;
+ dev->run = camdd_file_run;
+ dev->fetch = NULL;
+
+ /*
+ * We can effectively access files on byte boundaries. We'll reset
+ * this for devices like disks that can be accessed on sector
+ * boundaries.
+ */
+ dev->sector_size = 1;
+
+ if ((fd != STDIN_FILENO)
+ && (fd != STDOUT_FILENO)) {
+ int retval;
+
+ retval = fstat(fd, &file_dev->sb);
+ if (retval != 0) {
+ warn("Cannot stat %s", dev->device_name);
+ goto bailout;
+ camdd_free_dev(dev);
+ dev = NULL;
+ }
+ if (S_ISREG(file_dev->sb.st_mode)) {
+ file_dev->file_type = CAMDD_FILE_REG;
+ } else if (S_ISCHR(file_dev->sb.st_mode)) {
+ int type;
+
+ if (ioctl(fd, FIODTYPE, &type) == -1)
+ err(1, "FIODTYPE ioctl failed on %s",
+ dev->device_name);
+ else {
+ if (type & D_TAPE)
+ file_dev->file_type = CAMDD_FILE_TAPE;
+ else if (type & D_DISK)
+ file_dev->file_type = CAMDD_FILE_DISK;
+ else if (type & D_MEM)
+ file_dev->file_type = CAMDD_FILE_MEM;
+ else if (type & D_TTY)
+ file_dev->file_type = CAMDD_FILE_TTY;
+ }
+ } else if (S_ISDIR(file_dev->sb.st_mode)) {
+ errx(1, "cannot operate on directory %s",
+ dev->device_name);
+ } else if (S_ISFIFO(file_dev->sb.st_mode)) {
+ file_dev->file_type = CAMDD_FILE_PIPE;
+ } else
+ errx(1, "Cannot determine file type for %s",
+ dev->device_name);
+
+ switch (file_dev->file_type) {
+ case CAMDD_FILE_REG:
+ if (file_dev->sb.st_size != 0)
+ dev->max_sector = file_dev->sb.st_size - 1;
+ else
+ dev->max_sector = 0;
+ file_dev->file_flags |= CAMDD_FF_CAN_SEEK;
+ break;
+ case CAMDD_FILE_TAPE: {
+ uint64_t max_iosize, max_blk, min_blk, blk_gran;
+ /*
+ * Check block limits and maximum effective iosize.
+ * Make sure the blocksize is within the block
+ * limits (and a multiple of the minimum blocksize)
+ * and that the blocksize is <= maximum effective
+ * iosize.
+ */
+ retval = camdd_probe_tape(fd, dev->device_name,
+ &max_iosize, &max_blk, &min_blk, &blk_gran);
+ if (retval != 0)
+ errx(1, "Unable to probe tape %s",
+ dev->device_name);
+
+ /*
+ * The blocksize needs to be <= the maximum
+ * effective I/O size of the tape device. Note
+ * that this also takes into account the maximum
+ * blocksize reported by READ BLOCK LIMITS.
+ */
+ if (dev->blocksize > max_iosize) {
+ warnx("Blocksize %u too big for %s, limiting "
+ "to %ju", dev->blocksize, dev->device_name,
+ max_iosize);
+ dev->blocksize = max_iosize;
+ }
+
+ /*
+ * The blocksize needs to be at least min_blk;
+ */
+ if (dev->blocksize < min_blk) {
+ warnx("Blocksize %u too small for %s, "
+ "increasing to %ju", dev->blocksize,
+ dev->device_name, min_blk);
+ dev->blocksize = min_blk;
+ }
+
+ /*
+ * And the blocksize needs to be a multiple of
+ * the block granularity.
+ */
+ if ((blk_gran != 0)
+ && (dev->blocksize % (1 << blk_gran))) {
+ warnx("Blocksize %u for %s not a multiple of "
+ "%d, adjusting to %d", dev->blocksize,
+ dev->device_name, (1 << blk_gran),
+ dev->blocksize & ~((1 << blk_gran) - 1));
+ dev->blocksize &= ~((1 << blk_gran) - 1);
+ }
+
+ if (dev->blocksize == 0) {
+ errx(1, "Unable to derive valid blocksize for "
+ "%s", dev->device_name);
+ }
+
+ /*
+ * For tape drives, set the sector size to the
+ * blocksize so that we make sure not to write
+ * less than the blocksize out to the drive.
+ */
+ dev->sector_size = dev->blocksize;
+ break;
+ }
+ case CAMDD_FILE_DISK: {
+ off_t media_size;
+ unsigned int sector_size;
+
+ file_dev->file_flags |= CAMDD_FF_CAN_SEEK;
+
+ if (ioctl(fd, DIOCGSECTORSIZE, &sector_size) == -1) {
+ err(1, "DIOCGSECTORSIZE ioctl failed on %s",
+ dev->device_name);
+ }
+
+ if (sector_size == 0) {
+ errx(1, "DIOCGSECTORSIZE ioctl returned "
+ "invalid sector size %u for %s",
+ sector_size, dev->device_name);
+ }
+
+ if (ioctl(fd, DIOCGMEDIASIZE, &media_size) == -1) {
+ err(1, "DIOCGMEDIASIZE ioctl failed on %s",
+ dev->device_name);
+ }
+
+ if (media_size == 0) {
+ errx(1, "DIOCGMEDIASIZE ioctl returned "
+ "invalid media size %ju for %s",
+ (uintmax_t)media_size, dev->device_name);
+ }
+
+ if (dev->blocksize % sector_size) {
+ errx(1, "%s blocksize %u not a multiple of "
+ "sector size %u", dev->device_name,
+ dev->blocksize, sector_size);
+ }
+
+ dev->sector_size = sector_size;
+ dev->max_sector = (media_size / sector_size) - 1;
+ break;
+ }
+ case CAMDD_FILE_MEM:
+ file_dev->file_flags |= CAMDD_FF_CAN_SEEK;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ((io_opts->offset != 0)
+ && ((file_dev->file_flags & CAMDD_FF_CAN_SEEK) == 0)) {
+ warnx("Offset %ju specified for %s, but we cannot seek on %s",
+ io_opts->offset, io_opts->dev_name, io_opts->dev_name);
+ goto bailout_error;
+ }
+#if 0
+ else if ((io_opts->offset != 0)
+ && ((io_opts->offset % dev->sector_size) != 0)) {
+ warnx("Offset %ju for %s is not a multiple of the "
+ "sector size %u", io_opts->offset,
+ io_opts->dev_name, dev->sector_size);
+ goto bailout_error;
+ } else {
+ dev->start_offset_bytes = io_opts->offset;
+ }
+#endif
+
+bailout:
+ return (dev);
+
+bailout_error:
+ camdd_free_dev(dev);
+ return (NULL);
+}
+
+/*
+ * Need to implement this. Do a basic probe:
+ * - Check the inquiry data, make sure we're talking to a device that we
+ * can reasonably expect to talk to -- direct, RBC, CD, WORM.
+ * - Send a test unit ready, make sure the device is available.
+ * - Get the capacity and block size.
+ */
+struct camdd_dev *
+camdd_probe_pass(struct cam_device *cam_dev, struct camdd_io_opts *io_opts,
+ camdd_argmask arglist, int probe_retry_count,
+ int probe_timeout, int io_retry_count, int io_timeout)
+{
+ union ccb *ccb;
+ uint64_t maxsector;
+ uint32_t cpi_maxio, max_iosize, pass_numblocks;
+ uint32_t block_len;
+ struct scsi_read_capacity_data rcap;
+ struct scsi_read_capacity_data_long rcaplong;
+ struct camdd_dev *dev;
+ struct camdd_dev_pass *pass_dev;
+ struct kevent ke;
+ int scsi_dev_type;
+
+ dev = NULL;
+
+ scsi_dev_type = SID_TYPE(&cam_dev->inq_data);
+ maxsector = 0;
+ block_len = 0;
+
+ /*
+ * For devices that support READ CAPACITY, we'll attempt to get the
+ * capacity. Otherwise, we really don't support tape or other
+ * devices via SCSI passthrough, so just return an error in that case.
+ */
+ switch (scsi_dev_type) {
+ case T_DIRECT:
+ case T_WORM:
+ case T_CDROM:
+ case T_OPTICAL:
+ case T_RBC:
+ break;
+ default:
+ errx(1, "Unsupported SCSI device type %d", scsi_dev_type);
+ break; /*NOTREACHED*/
+ }
+
+ ccb = cam_getccb(cam_dev);
+
+ if (ccb == NULL) {
+ warnx("%s: error allocating ccb", __func__);
+ goto bailout;
+ }
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+
+ scsi_read_capacity(&ccb->csio,
+ /*retries*/ probe_retry_count,
+ /*cbfcnp*/ NULL,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ &rcap,
+ SSD_FULL_SIZE,
+ /*timeout*/ probe_timeout ? probe_timeout : 5000);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+ if (arglist & CAMDD_ARG_ERR_RECOVER)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+ if (cam_send_ccb(cam_dev, ccb) < 0) {
+ warn("error sending READ CAPACITY command");
+
+ cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+
+ goto bailout;
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+ goto bailout;
+ }
+
+ maxsector = scsi_4btoul(rcap.addr);
+ block_len = scsi_4btoul(rcap.length);
+
+ /*
+ * A last block of 2^32-1 means that the true capacity is over 2TB,
+ * and we need to issue the long READ CAPACITY to get the real
+ * capacity. Otherwise, we're all set.
+ */
+ if (maxsector != 0xffffffff)
+ goto rcap_done;
+
+ scsi_read_capacity_16(&ccb->csio,
+ /*retries*/ probe_retry_count,
+ /*cbfcnp*/ NULL,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*lba*/ 0,
+ /*reladdr*/ 0,
+ /*pmi*/ 0,
+ (uint8_t *)&rcaplong,
+ sizeof(rcaplong),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ probe_timeout ? probe_timeout : 5000);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+ if (arglist & CAMDD_ARG_ERR_RECOVER)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+ if (cam_send_ccb(cam_dev, ccb) < 0) {
+ warn("error sending READ CAPACITY (16) command");
+ cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ goto bailout;
+ }
+
+ if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
+ cam_error_print(cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr);
+ goto bailout;
+ }
+
+ maxsector = scsi_8btou64(rcaplong.addr);
+ block_len = scsi_4btoul(rcaplong.length);
+
+rcap_done:
+
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+
+ ccb->ccb_h.func_code = XPT_PATH_INQ;
+ ccb->ccb_h.flags = CAM_DIR_NONE;
+ ccb->ccb_h.retry_count = 1;
+
+ if (cam_send_ccb(cam_dev, ccb) < 0) {
+ warn("error sending XPT_PATH_INQ CCB");
+
+ cam_error_print(cam_dev, ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ goto bailout;
+ }
+
+ EV_SET(&ke, cam_dev->fd, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, 0);
+
+ dev = camdd_alloc_dev(CAMDD_DEV_PASS, &ke, 1, io_retry_count,
+ io_timeout);
+ if (dev == NULL)
+ goto bailout;
+
+ pass_dev = &dev->dev_spec.pass;
+ pass_dev->scsi_dev_type = scsi_dev_type;
+ pass_dev->dev = cam_dev;
+ pass_dev->max_sector = maxsector;
+ pass_dev->block_len = block_len;
+ pass_dev->cpi_maxio = ccb->cpi.maxio;
+ snprintf(dev->device_name, sizeof(dev->device_name), "%s%u",
+ pass_dev->dev->device_name, pass_dev->dev->dev_unit_num);
+ dev->sector_size = block_len;
+ dev->max_sector = maxsector;
+
+
+ /*
+ * Determine the optimal blocksize to use for this device.
+ */
+
+ /*
+ * If the controller has not specified a maximum I/O size,
+ * just go with 128K as a somewhat conservative value.
+ */
+ if (pass_dev->cpi_maxio == 0)
+ cpi_maxio = 131072;
+ else
+ cpi_maxio = pass_dev->cpi_maxio;
+
+ /*
+ * If the controller has a large maximum I/O size, limit it
+ * to something smaller so that the kernel doesn't have trouble
+ * allocating buffers to copy data in and out for us.
+ * XXX KDM this is until we have unmapped I/O support in the kernel.
+ */
+ max_iosize = min(cpi_maxio, CAMDD_PASS_MAX_BLOCK);
+
+ /*
+ * If we weren't able to get a block size for some reason,
+ * default to 512 bytes.
+ */
+ block_len = pass_dev->block_len;
+ if (block_len == 0)
+ block_len = 512;
+
+ /*
+ * Figure out how many blocksize chunks will fit in the
+ * maximum I/O size.
+ */
+ pass_numblocks = max_iosize / block_len;
+
+ /*
+ * And finally, multiple the number of blocks by the LBA
+ * length to get our maximum block size;
+ */
+ dev->blocksize = pass_numblocks * block_len;
+
+ if (io_opts->blocksize != 0) {
+ if ((io_opts->blocksize % dev->sector_size) != 0) {
+ warnx("Blocksize %ju for %s is not a multiple of "
+ "sector size %u", (uintmax_t)io_opts->blocksize,
+ dev->device_name, dev->sector_size);
+ goto bailout_error;
+ }
+ dev->blocksize = io_opts->blocksize;
+ }
+ dev->target_queue_depth = CAMDD_PASS_DEFAULT_DEPTH;
+ if (io_opts->queue_depth != 0)
+ dev->target_queue_depth = io_opts->queue_depth;
+
+ if (io_opts->offset != 0) {
+ if (io_opts->offset > (dev->max_sector * dev->sector_size)) {
+ warnx("Offset %ju is past the end of device %s",
+ io_opts->offset, dev->device_name);
+ goto bailout_error;
+ }
+#if 0
+ else if ((io_opts->offset % dev->sector_size) != 0) {
+ warnx("Offset %ju for %s is not a multiple of the "
+ "sector size %u", io_opts->offset,
+ dev->device_name, dev->sector_size);
+ goto bailout_error;
+ }
+ dev->start_offset_bytes = io_opts->offset;
+#endif
+ }
+
+ dev->min_cmd_size = io_opts->min_cmd_size;
+
+ dev->run = camdd_pass_run;
+ dev->fetch = camdd_pass_fetch;
+
+bailout:
+ cam_freeccb(ccb);
+
+ return (dev);
+
+bailout_error:
+ cam_freeccb(ccb);
+
+ camdd_free_dev(dev);
+
+ return (NULL);
+}
+
+void *
+camdd_worker(void *arg)
+{
+ struct camdd_dev *dev = arg;
+ struct camdd_buf *buf;
+ struct timespec ts, *kq_ts;
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ pthread_mutex_lock(&dev->mutex);
+
+ dev->flags |= CAMDD_DEV_FLAG_ACTIVE;
+
+ for (;;) {
+ struct kevent ke;
+ int retval = 0;
+
+ /*
+ * XXX KDM check the reorder queue depth?
+ */
+ if (dev->write_dev == 0) {
+ uint32_t our_depth, peer_depth, peer_bytes, our_bytes;
+ uint32_t target_depth = dev->target_queue_depth;
+ uint32_t peer_target_depth =
+ dev->peer_dev->target_queue_depth;
+ uint32_t peer_blocksize = dev->peer_dev->blocksize;
+
+ camdd_get_depth(dev, &our_depth, &peer_depth,
+ &our_bytes, &peer_bytes);
+
+#if 0
+ while (((our_depth < target_depth)
+ && (peer_depth < peer_target_depth))
+ || ((peer_bytes + our_bytes) <
+ (peer_blocksize * 2))) {
+#endif
+ while (((our_depth + peer_depth) <
+ (target_depth + peer_target_depth))
+ || ((peer_bytes + our_bytes) <
+ (peer_blocksize * 3))) {
+
+ retval = camdd_queue(dev, NULL);
+ if (retval == 1)
+ break;
+ else if (retval != 0) {
+ error_exit = 1;
+ goto bailout;
+ }
+
+ camdd_get_depth(dev, &our_depth, &peer_depth,
+ &our_bytes, &peer_bytes);
+ }
+ }
+ /*
+ * See if we have any I/O that is ready to execute.
+ */
+ buf = STAILQ_FIRST(&dev->run_queue);
+ if (buf != NULL) {
+ while (dev->target_queue_depth > dev->cur_active_io) {
+ retval = dev->run(dev);
+ if (retval == -1) {
+ dev->flags |= CAMDD_DEV_FLAG_EOF;
+ error_exit = 1;
+ break;
+ } else if (retval != 0) {
+ break;
+ }
+ }
+ }
+
+ /*
+ * We've reached EOF, or our partner has reached EOF.
+ */
+ if ((dev->flags & CAMDD_DEV_FLAG_EOF)
+ || (dev->flags & CAMDD_DEV_FLAG_PEER_EOF)) {
+ if (dev->write_dev != 0) {
+ if ((STAILQ_EMPTY(&dev->work_queue))
+ && (dev->num_run_queue == 0)
+ && (dev->cur_active_io == 0)) {
+ goto bailout;
+ }
+ } else {
+ /*
+ * If we're the reader, and the writer
+ * got EOF, he is already done. If we got
+ * the EOF, then we need to wait until
+ * everything is flushed out for the writer.
+ */
+ if (dev->flags & CAMDD_DEV_FLAG_PEER_EOF) {
+ goto bailout;
+ } else if ((dev->num_peer_work_queue == 0)
+ && (dev->num_peer_done_queue == 0)
+ && (dev->cur_active_io == 0)
+ && (dev->num_run_queue == 0)) {
+ goto bailout;
+ }
+ }
+ /*
+ * XXX KDM need to do something about the pending
+ * queue and cleanup resources.
+ */
+ }
+
+ if ((dev->write_dev == 0)
+ && (dev->cur_active_io == 0)
+ && (dev->peer_bytes_queued < dev->peer_dev->blocksize))
+ kq_ts = &ts;
+ else
+ kq_ts = NULL;
+
+ /*
+ * Run kevent to see if there are events to process.
+ */
+ pthread_mutex_unlock(&dev->mutex);
+ retval = kevent(dev->kq, NULL, 0, &ke, 1, kq_ts);
+ pthread_mutex_lock(&dev->mutex);
+ if (retval == -1) {
+ warn("%s: error returned from kevent",__func__);
+ goto bailout;
+ } else if (retval != 0) {
+ switch (ke.filter) {
+ case EVFILT_READ:
+ if (dev->fetch != NULL) {
+ retval = dev->fetch(dev);
+ if (retval == -1) {
+ error_exit = 1;
+ goto bailout;
+ }
+ }
+ break;
+ case EVFILT_SIGNAL:
+ /*
+ * We register for this so we don't get
+ * an error as a result of a SIGINFO or a
+ * SIGINT. It will actually get handled
+ * by the signal handler. If we get a
+ * SIGINT, bail out without printing an
+ * error message. Any other signals
+ * will result in the error message above.
+ */
+ if (ke.ident == SIGINT)
+ goto bailout;
+ break;
+ case EVFILT_USER:
+ retval = 0;
+ /*
+ * Check to see if the other thread has
+ * queued any I/O for us to do. (In this
+ * case we're the writer.)
+ */
+ for (buf = STAILQ_FIRST(&dev->work_queue);
+ buf != NULL;
+ buf = STAILQ_FIRST(&dev->work_queue)) {
+ STAILQ_REMOVE_HEAD(&dev->work_queue,
+ work_links);
+ retval = camdd_queue(dev, buf);
+ /*
+ * We keep going unless we get an
+ * actual error. If we get EOF, we
+ * still want to remove the buffers
+ * from the queue and send the back
+ * to the reader thread.
+ */
+ if (retval == -1) {
+ error_exit = 1;
+ goto bailout;
+ } else
+ retval = 0;
+ }
+
+ /*
+ * Next check to see if the other thread has
+ * queued any completed buffers back to us.
+ * (In this case we're the reader.)
+ */
+ for (buf = STAILQ_FIRST(&dev->peer_done_queue);
+ buf != NULL;
+ buf = STAILQ_FIRST(&dev->peer_done_queue)){
+ STAILQ_REMOVE_HEAD(
+ &dev->peer_done_queue, work_links);
+ dev->num_peer_done_queue--;
+ camdd_peer_done(buf);
+ }
+ break;
+ default:
+ warnx("%s: unknown kevent filter %d",
+ __func__, ke.filter);
+ break;
+ }
+ }
+ }
+
+bailout:
+
+ dev->flags &= ~CAMDD_DEV_FLAG_ACTIVE;
+
+ /* XXX KDM cleanup resources here? */
+
+ pthread_mutex_unlock(&dev->mutex);
+
+ need_exit = 1;
+ sem_post(&camdd_sem);
+
+ return (NULL);
+}
+
+/*
+ * Simplistic translation of CCB status to our local status.
+ */
+camdd_buf_status
+camdd_ccb_status(union ccb *ccb)
+{
+ camdd_buf_status status = CAMDD_STATUS_NONE;
+ cam_status ccb_status;
+
+ ccb_status = ccb->ccb_h.status & CAM_STATUS_MASK;
+
+ switch (ccb_status) {
+ case CAM_REQ_CMP: {
+ if (ccb->csio.resid == 0) {
+ status = CAMDD_STATUS_OK;
+ } else if (ccb->csio.dxfer_len > ccb->csio.resid) {
+ status = CAMDD_STATUS_SHORT_IO;
+ } else {
+ status = CAMDD_STATUS_EOF;
+ }
+ break;
+ }
+ case CAM_SCSI_STATUS_ERROR: {
+ switch (ccb->csio.scsi_status) {
+ case SCSI_STATUS_OK:
+ case SCSI_STATUS_COND_MET:
+ case SCSI_STATUS_INTERMED:
+ case SCSI_STATUS_INTERMED_COND_MET:
+ status = CAMDD_STATUS_OK;
+ break;
+ case SCSI_STATUS_CMD_TERMINATED:
+ case SCSI_STATUS_CHECK_COND:
+ case SCSI_STATUS_QUEUE_FULL:
+ case SCSI_STATUS_BUSY:
+ case SCSI_STATUS_RESERV_CONFLICT:
+ default:
+ status = CAMDD_STATUS_ERROR;
+ break;
+ }
+ break;
+ }
+ default:
+ status = CAMDD_STATUS_ERROR;
+ break;
+ }
+
+ return (status);
+}
+
+/*
+ * Queue a buffer to our peer's work thread for writing.
+ *
+ * Returns 0 for success, -1 for failure, 1 if the other thread exited.
+ */
+int
+camdd_queue_peer_buf(struct camdd_dev *dev, struct camdd_buf *buf)
+{
+ struct kevent ke;
+ STAILQ_HEAD(, camdd_buf) local_queue;
+ struct camdd_buf *buf1, *buf2;
+ struct camdd_buf_data *data = NULL;
+ uint64_t peer_bytes_queued = 0;
+ int active = 1;
+ int retval = 0;
+
+ STAILQ_INIT(&local_queue);
+
+ /*
+ * Since we're the reader, we need to queue our I/O to the writer
+ * in sequential order in order to make sure it gets written out
+ * in sequential order.
+ *
+ * Check the next expected I/O starting offset. If this doesn't
+ * match, put it on the reorder queue.
+ */
+ if ((buf->lba * dev->sector_size) != dev->next_completion_pos_bytes) {
+
+ /*
+ * If there is nothing on the queue, there is no sorting
+ * needed.
+ */
+ if (STAILQ_EMPTY(&dev->reorder_queue)) {
+ STAILQ_INSERT_TAIL(&dev->reorder_queue, buf, links);
+ dev->num_reorder_queue++;
+ goto bailout;
+ }
+
+ /*
+ * Sort in ascending order by starting LBA. There should
+ * be no identical LBAs.
+ */
+ for (buf1 = STAILQ_FIRST(&dev->reorder_queue); buf1 != NULL;
+ buf1 = buf2) {
+ buf2 = STAILQ_NEXT(buf1, links);
+ if (buf->lba < buf1->lba) {
+ /*
+ * If we're less than the first one, then
+ * we insert at the head of the list
+ * because this has to be the first element
+ * on the list.
+ */
+ STAILQ_INSERT_HEAD(&dev->reorder_queue,
+ buf, links);
+ dev->num_reorder_queue++;
+ break;
+ } else if (buf->lba > buf1->lba) {
+ if (buf2 == NULL) {
+ STAILQ_INSERT_TAIL(&dev->reorder_queue,
+ buf, links);
+ dev->num_reorder_queue++;
+ break;
+ } else if (buf->lba < buf2->lba) {
+ STAILQ_INSERT_AFTER(&dev->reorder_queue,
+ buf1, buf, links);
+ dev->num_reorder_queue++;
+ break;
+ }
+ } else {
+ errx(1, "Found buffers with duplicate LBA %ju!",
+ buf->lba);
+ }
+ }
+ goto bailout;
+ } else {
+
+ /*
+ * We're the next expected I/O completion, so put ourselves
+ * on the local queue to be sent to the writer. We use
+ * work_links here so that we can queue this to the
+ * peer_work_queue before taking the buffer off of the
+ * local_queue.
+ */
+ dev->next_completion_pos_bytes += buf->len;
+ STAILQ_INSERT_TAIL(&local_queue, buf, work_links);
+
+ /*
+ * Go through the reorder queue looking for more sequential
+ * I/O and add it to the local queue.
+ */
+ for (buf1 = STAILQ_FIRST(&dev->reorder_queue); buf1 != NULL;
+ buf1 = STAILQ_FIRST(&dev->reorder_queue)) {
+ /*
+ * As soon as we see an I/O that is out of sequence,
+ * we're done.
+ */
+ if ((buf1->lba * dev->sector_size) !=
+ dev->next_completion_pos_bytes)
+ break;
+
+ STAILQ_REMOVE_HEAD(&dev->reorder_queue, links);
+ dev->num_reorder_queue--;
+ STAILQ_INSERT_TAIL(&local_queue, buf1, work_links);
+ dev->next_completion_pos_bytes += buf1->len;
+ }
+ }
+
+ /*
+ * Setup the event to let the other thread know that it has work
+ * pending.
+ */
+ EV_SET(&ke, (uintptr_t)&dev->peer_dev->work_queue, EVFILT_USER, 0,
+ NOTE_TRIGGER, 0, NULL);
+
+ /*
+ * Put this on our shadow queue so that we know what we've queued
+ * to the other thread.
+ */
+ STAILQ_FOREACH_SAFE(buf1, &local_queue, work_links, buf2) {
+ if (buf1->buf_type != CAMDD_BUF_DATA) {
+ errx(1, "%s: should have a data buffer, not an "
+ "indirect buffer", __func__);
+ }
+ data = &buf1->buf_type_spec.data;
+
+ /*
+ * We only need to send one EOF to the writer, and don't
+ * need to continue sending EOFs after that.
+ */
+ if (buf1->status == CAMDD_STATUS_EOF) {
+ if (dev->flags & CAMDD_DEV_FLAG_EOF_SENT) {
+ STAILQ_REMOVE(&local_queue, buf1, camdd_buf,
+ work_links);
+ camdd_release_buf(buf1);
+ retval = 1;
+ continue;
+ }
+ dev->flags |= CAMDD_DEV_FLAG_EOF_SENT;
+ }
+
+
+ STAILQ_INSERT_TAIL(&dev->peer_work_queue, buf1, links);
+ peer_bytes_queued += (data->fill_len - data->resid);
+ dev->peer_bytes_queued += (data->fill_len - data->resid);
+ dev->num_peer_work_queue++;
+ }
+
+ if (STAILQ_FIRST(&local_queue) == NULL)
+ goto bailout;
+
+ /*
+ * Drop our mutex and pick up the other thread's mutex. We need to
+ * do this to avoid deadlocks.
+ */
+ pthread_mutex_unlock(&dev->mutex);
+ pthread_mutex_lock(&dev->peer_dev->mutex);
+
+ if (dev->peer_dev->flags & CAMDD_DEV_FLAG_ACTIVE) {
+ /*
+ * Put the buffers on the other thread's incoming work queue.
+ */
+ for (buf1 = STAILQ_FIRST(&local_queue); buf1 != NULL;
+ buf1 = STAILQ_FIRST(&local_queue)) {
+ STAILQ_REMOVE_HEAD(&local_queue, work_links);
+ STAILQ_INSERT_TAIL(&dev->peer_dev->work_queue, buf1,
+ work_links);
+ }
+ /*
+ * Send an event to the other thread's kqueue to let it know
+ * that there is something on the work queue.
+ */
+ retval = kevent(dev->peer_dev->kq, &ke, 1, NULL, 0, NULL);
+ if (retval == -1)
+ warn("%s: unable to add peer work_queue kevent",
+ __func__);
+ else
+ retval = 0;
+ } else
+ active = 0;
+
+ pthread_mutex_unlock(&dev->peer_dev->mutex);
+ pthread_mutex_lock(&dev->mutex);
+
+ /*
+ * If the other side isn't active, run through the queue and
+ * release all of the buffers.
+ */
+ if (active == 0) {
+ for (buf1 = STAILQ_FIRST(&local_queue); buf1 != NULL;
+ buf1 = STAILQ_FIRST(&local_queue)) {
+ STAILQ_REMOVE_HEAD(&local_queue, work_links);
+ STAILQ_REMOVE(&dev->peer_work_queue, buf1, camdd_buf,
+ links);
+ dev->num_peer_work_queue--;
+ camdd_release_buf(buf1);
+ }
+ dev->peer_bytes_queued -= peer_bytes_queued;
+ retval = 1;
+ }
+
+bailout:
+ return (retval);
+}
+
+/*
+ * Return a buffer to the reader thread when we have completed writing it.
+ */
+int
+camdd_complete_peer_buf(struct camdd_dev *dev, struct camdd_buf *peer_buf)
+{
+ struct kevent ke;
+ int retval = 0;
+
+ /*
+ * Setup the event to let the other thread know that we have
+ * completed a buffer.
+ */
+ EV_SET(&ke, (uintptr_t)&dev->peer_dev->peer_done_queue, EVFILT_USER, 0,
+ NOTE_TRIGGER, 0, NULL);
+
+ /*
+ * Drop our lock and acquire the other thread's lock before
+ * manipulating
+ */
+ pthread_mutex_unlock(&dev->mutex);
+ pthread_mutex_lock(&dev->peer_dev->mutex);
+
+ /*
+ * Put the buffer on the reader thread's peer done queue now that
+ * we have completed it.
+ */
+ STAILQ_INSERT_TAIL(&dev->peer_dev->peer_done_queue, peer_buf,
+ work_links);
+ dev->peer_dev->num_peer_done_queue++;
+
+ /*
+ * Send an event to the peer thread to let it know that we've added
+ * something to its peer done queue.
+ */
+ retval = kevent(dev->peer_dev->kq, &ke, 1, NULL, 0, NULL);
+ if (retval == -1)
+ warn("%s: unable to add peer_done_queue kevent", __func__);
+ else
+ retval = 0;
+
+ /*
+ * Drop the other thread's lock and reacquire ours.
+ */
+ pthread_mutex_unlock(&dev->peer_dev->mutex);
+ pthread_mutex_lock(&dev->mutex);
+
+ return (retval);
+}
+
+/*
+ * Free a buffer that was written out by the writer thread and returned to
+ * the reader thread.
+ */
+void
+camdd_peer_done(struct camdd_buf *buf)
+{
+ struct camdd_dev *dev;
+ struct camdd_buf_data *data;
+
+ dev = buf->dev;
+ if (buf->buf_type != CAMDD_BUF_DATA) {
+ errx(1, "%s: should have a data buffer, not an "
+ "indirect buffer", __func__);
+ }
+
+ data = &buf->buf_type_spec.data;
+
+ STAILQ_REMOVE(&dev->peer_work_queue, buf, camdd_buf, links);
+ dev->num_peer_work_queue--;
+ dev->peer_bytes_queued -= (data->fill_len - data->resid);
+
+ if (buf->status == CAMDD_STATUS_EOF)
+ dev->flags |= CAMDD_DEV_FLAG_PEER_EOF;
+
+ STAILQ_INSERT_TAIL(&dev->free_queue, buf, links);
+}
+
+/*
+ * Assumes caller holds the lock for this device.
+ */
+void
+camdd_complete_buf(struct camdd_dev *dev, struct camdd_buf *buf,
+ int *error_count)
+{
+ int retval = 0;
+
+ /*
+ * If we're the reader, we need to send the completed I/O
+ * to the writer. If we're the writer, we need to just
+ * free up resources, or let the reader know if we've
+ * encountered an error.
+ */
+ if (dev->write_dev == 0) {
+ retval = camdd_queue_peer_buf(dev, buf);
+ if (retval != 0)
+ (*error_count)++;
+ } else {
+ struct camdd_buf *tmp_buf, *next_buf;
+
+ STAILQ_FOREACH_SAFE(tmp_buf, &buf->src_list, src_links,
+ next_buf) {
+ struct camdd_buf *src_buf;
+ struct camdd_buf_indirect *indirect;
+
+ STAILQ_REMOVE(&buf->src_list, tmp_buf,
+ camdd_buf, src_links);
+
+ tmp_buf->status = buf->status;
+
+ if (tmp_buf->buf_type == CAMDD_BUF_DATA) {
+ camdd_complete_peer_buf(dev, tmp_buf);
+ continue;
+ }
+
+ indirect = &tmp_buf->buf_type_spec.indirect;
+ src_buf = indirect->src_buf;
+ src_buf->refcount--;
+ /*
+ * XXX KDM we probably need to account for
+ * exactly how many bytes we were able to
+ * write. Allocate the residual to the
+ * first N buffers? Or just track the
+ * number of bytes written? Right now the reader
+ * doesn't do anything with a residual.
+ */
+ src_buf->status = buf->status;
+ if (src_buf->refcount <= 0)
+ camdd_complete_peer_buf(dev, src_buf);
+ STAILQ_INSERT_TAIL(&dev->free_indirect_queue,
+ tmp_buf, links);
+ }
+
+ STAILQ_INSERT_TAIL(&dev->free_queue, buf, links);
+ }
+}
+
+/*
+ * Fetch all completed commands from the pass(4) device.
+ *
+ * Returns the number of commands received, or -1 if any of the commands
+ * completed with an error. Returns 0 if no commands are available.
+ */
+int
+camdd_pass_fetch(struct camdd_dev *dev)
+{
+ struct camdd_dev_pass *pass_dev = &dev->dev_spec.pass;
+ union ccb ccb;
+ int retval = 0, num_fetched = 0, error_count = 0;
+
+ pthread_mutex_unlock(&dev->mutex);
+ /*
+ * XXX KDM we don't distinguish between EFAULT and ENOENT.
+ */
+ while ((retval = ioctl(pass_dev->dev->fd, CAMIOGET, &ccb)) != -1) {
+ struct camdd_buf *buf;
+ struct camdd_buf_data *data;
+ cam_status ccb_status;
+ union ccb *buf_ccb;
+
+ buf = ccb.ccb_h.ccb_buf;
+ data = &buf->buf_type_spec.data;
+ buf_ccb = &data->ccb;
+
+ num_fetched++;
+
+ /*
+ * Copy the CCB back out so we get status, sense data, etc.
+ */
+ bcopy(&ccb, buf_ccb, sizeof(ccb));
+
+ pthread_mutex_lock(&dev->mutex);
+
+ /*
+ * We're now done, so take this off the active queue.
+ */
+ STAILQ_REMOVE(&dev->active_queue, buf, camdd_buf, links);
+ dev->cur_active_io--;
+
+ ccb_status = ccb.ccb_h.status & CAM_STATUS_MASK;
+ if (ccb_status != CAM_REQ_CMP) {
+ cam_error_print(pass_dev->dev, &ccb, CAM_ESF_ALL,
+ CAM_EPF_ALL, stderr);
+ }
+
+ data->resid = ccb.csio.resid;
+ dev->bytes_transferred += (ccb.csio.dxfer_len - ccb.csio.resid);
+
+ if (buf->status == CAMDD_STATUS_NONE)
+ buf->status = camdd_ccb_status(&ccb);
+ if (buf->status == CAMDD_STATUS_ERROR)
+ error_count++;
+ else if (buf->status == CAMDD_STATUS_EOF) {
+ /*
+ * Once we queue this buffer to our partner thread,
+ * he will know that we've hit EOF.
+ */
+ dev->flags |= CAMDD_DEV_FLAG_EOF;
+ }
+
+ camdd_complete_buf(dev, buf, &error_count);
+
+ /*
+ * Unlock in preparation for the ioctl call.
+ */
+ pthread_mutex_unlock(&dev->mutex);
+ }
+
+ pthread_mutex_lock(&dev->mutex);
+
+ if (error_count > 0)
+ return (-1);
+ else
+ return (num_fetched);
+}
+
+/*
+ * Returns -1 for error, 0 for success/continue, and 1 for resource
+ * shortage/stop processing.
+ */
+int
+camdd_file_run(struct camdd_dev *dev)
+{
+ struct camdd_dev_file *file_dev = &dev->dev_spec.file;
+ struct camdd_buf_data *data;
+ struct camdd_buf *buf;
+ off_t io_offset;
+ int retval = 0, write_dev = dev->write_dev;
+ int error_count = 0, no_resources = 0, double_buf_needed = 0;
+ uint32_t num_sectors = 0, db_len = 0;
+
+ buf = STAILQ_FIRST(&dev->run_queue);
+ if (buf == NULL) {
+ no_resources = 1;
+ goto bailout;
+ } else if ((dev->write_dev == 0)
+ && (dev->flags & (CAMDD_DEV_FLAG_EOF |
+ CAMDD_DEV_FLAG_EOF_SENT))) {
+ STAILQ_REMOVE(&dev->run_queue, buf, camdd_buf, links);
+ dev->num_run_queue--;
+ buf->status = CAMDD_STATUS_EOF;
+ error_count++;
+ goto bailout;
+ }
+
+ /*
+ * If we're writing, we need to go through the source buffer list
+ * and create an S/G list.
+ */
+ if (write_dev != 0) {
+ retval = camdd_buf_sg_create(buf, /*iovec*/ 1,
+ dev->sector_size, &num_sectors, &double_buf_needed);
+ if (retval != 0) {
+ no_resources = 1;
+ goto bailout;
+ }
+ }
+
+ STAILQ_REMOVE(&dev->run_queue, buf, camdd_buf, links);
+ dev->num_run_queue--;
+
+ data = &buf->buf_type_spec.data;
+
+ /*
+ * pread(2) and pwrite(2) offsets are byte offsets.
+ */
+ io_offset = buf->lba * dev->sector_size;
+
+ /*
+ * Unlock the mutex while we read or write.
+ */
+ pthread_mutex_unlock(&dev->mutex);
+
+ /*
+ * Note that we don't need to double buffer if we're the reader
+ * because in that case, we have allocated a single buffer of
+ * sufficient size to do the read. This copy is necessary on
+ * writes because if one of the components of the S/G list is not
+ * a sector size multiple, the kernel will reject the write. This
+ * is unfortunate but not surprising. So this will make sure that
+ * we're using a single buffer that is a multiple of the sector size.
+ */
+ if ((double_buf_needed != 0)
+ && (data->sg_count > 1)
+ && (write_dev != 0)) {
+ uint32_t cur_offset;
+ int i;
+
+ if (file_dev->tmp_buf == NULL)
+ file_dev->tmp_buf = calloc(dev->blocksize, 1);
+ if (file_dev->tmp_buf == NULL) {
+ buf->status = CAMDD_STATUS_ERROR;
+ error_count++;
+ goto bailout;
+ }
+ for (i = 0, cur_offset = 0; i < data->sg_count; i++) {
+ bcopy(data->iovec[i].iov_base,
+ &file_dev->tmp_buf[cur_offset],
+ data->iovec[i].iov_len);
+ cur_offset += data->iovec[i].iov_len;
+ }
+ db_len = cur_offset;
+ }
+
+ if (file_dev->file_flags & CAMDD_FF_CAN_SEEK) {
+ if (write_dev == 0) {
+ /*
+ * XXX KDM is there any way we would need a S/G
+ * list here?
+ */
+ retval = pread(file_dev->fd, data->buf,
+ buf->len, io_offset);
+ } else {
+ if (double_buf_needed != 0) {
+ retval = pwrite(file_dev->fd, file_dev->tmp_buf,
+ db_len, io_offset);
+ } else if (data->sg_count == 0) {
+ retval = pwrite(file_dev->fd, data->buf,
+ data->fill_len, io_offset);
+ } else {
+ retval = pwritev(file_dev->fd, data->iovec,
+ data->sg_count, io_offset);
+ }
+ }
+ } else {
+ if (write_dev == 0) {
+ /*
+ * XXX KDM is there any way we would need a S/G
+ * list here?
+ */
+ retval = read(file_dev->fd, data->buf, buf->len);
+ } else {
+ if (double_buf_needed != 0) {
+ retval = write(file_dev->fd, file_dev->tmp_buf,
+ db_len);
+ } else if (data->sg_count == 0) {
+ retval = write(file_dev->fd, data->buf,
+ data->fill_len);
+ } else {
+ retval = writev(file_dev->fd, data->iovec,
+ data->sg_count);
+ }
+ }
+ }
+
+ /* We're done, re-acquire the lock */
+ pthread_mutex_lock(&dev->mutex);
+
+ if (retval >= (ssize_t)data->fill_len) {
+ /*
+ * If the bytes transferred is more than the request size,
+ * that indicates an overrun, which should only happen at
+ * the end of a transfer if we have to round up to a sector
+ * boundary.
+ */
+ if (buf->status == CAMDD_STATUS_NONE)
+ buf->status = CAMDD_STATUS_OK;
+ data->resid = 0;
+ dev->bytes_transferred += retval;
+ } else if (retval == -1) {
+ warn("Error %s %s", (write_dev) ? "writing to" :
+ "reading from", file_dev->filename);
+
+ buf->status = CAMDD_STATUS_ERROR;
+ data->resid = data->fill_len;
+ error_count++;
+
+ if (dev->debug == 0)
+ goto bailout;
+
+ if ((double_buf_needed != 0)
+ && (write_dev != 0)) {
+ fprintf(stderr, "%s: fd %d, DB buf %p, len %u lba %ju "
+ "offset %ju\n", __func__, file_dev->fd,
+ file_dev->tmp_buf, db_len, (uintmax_t)buf->lba,
+ (uintmax_t)io_offset);
+ } else if (data->sg_count == 0) {
+ fprintf(stderr, "%s: fd %d, buf %p, len %u, lba %ju "
+ "offset %ju\n", __func__, file_dev->fd, data->buf,
+ data->fill_len, (uintmax_t)buf->lba,
+ (uintmax_t)io_offset);
+ } else {
+ int i;
+
+ fprintf(stderr, "%s: fd %d, len %u, lba %ju "
+ "offset %ju\n", __func__, file_dev->fd,
+ data->fill_len, (uintmax_t)buf->lba,
+ (uintmax_t)io_offset);
+
+ for (i = 0; i < data->sg_count; i++) {
+ fprintf(stderr, "index %d ptr %p len %zu\n",
+ i, data->iovec[i].iov_base,
+ data->iovec[i].iov_len);
+ }
+ }
+ } else if (retval == 0) {
+ buf->status = CAMDD_STATUS_EOF;
+ if (dev->debug != 0)
+ printf("%s: got EOF from %s!\n", __func__,
+ file_dev->filename);
+ data->resid = data->fill_len;
+ error_count++;
+ } else if (retval < (ssize_t)data->fill_len) {
+ if (buf->status == CAMDD_STATUS_NONE)
+ buf->status = CAMDD_STATUS_SHORT_IO;
+ data->resid = data->fill_len - retval;
+ dev->bytes_transferred += retval;
+ }
+
+bailout:
+ if (buf != NULL) {
+ if (buf->status == CAMDD_STATUS_EOF) {
+ struct camdd_buf *buf2;
+ dev->flags |= CAMDD_DEV_FLAG_EOF;
+ STAILQ_FOREACH(buf2, &dev->run_queue, links)
+ buf2->status = CAMDD_STATUS_EOF;
+ }
+
+ camdd_complete_buf(dev, buf, &error_count);
+ }
+
+ if (error_count != 0)
+ return (-1);
+ else if (no_resources != 0)
+ return (1);
+ else
+ return (0);
+}
+
+/*
+ * Execute one command from the run queue. Returns 0 for success, 1 for
+ * stop processing, and -1 for error.
+ */
+int
+camdd_pass_run(struct camdd_dev *dev)
+{
+ struct camdd_buf *buf = NULL;
+ struct camdd_dev_pass *pass_dev = &dev->dev_spec.pass;
+ struct camdd_buf_data *data;
+ uint32_t num_blocks, sectors_used = 0;
+ union ccb *ccb;
+ int retval = 0, is_write = dev->write_dev;
+ int double_buf_needed = 0;
+
+ buf = STAILQ_FIRST(&dev->run_queue);
+ if (buf == NULL) {
+ retval = 1;
+ goto bailout;
+ }
+
+ /*
+ * If we're writing, we need to go through the source buffer list
+ * and create an S/G list.
+ */
+ if (is_write != 0) {
+ retval = camdd_buf_sg_create(buf, /*iovec*/ 0,dev->sector_size,
+ &sectors_used, &double_buf_needed);
+ if (retval != 0) {
+ retval = -1;
+ goto bailout;
+ }
+ }
+
+ STAILQ_REMOVE(&dev->run_queue, buf, camdd_buf, links);
+ dev->num_run_queue--;
+
+ data = &buf->buf_type_spec.data;
+
+ ccb = &data->ccb;
+ bzero(&(&ccb->ccb_h)[1],
+ sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr));
+
+ /*
+ * In almost every case the number of blocks should be the device
+ * block size. The exception may be at the end of an I/O stream
+ * for a partial block or at the end of a device.
+ */
+ if (is_write != 0)
+ num_blocks = sectors_used;
+ else
+ num_blocks = data->fill_len / pass_dev->block_len;
+
+ scsi_read_write(&ccb->csio,
+ /*retries*/ dev->retry_count,
+ /*cbfcnp*/ NULL,
+ /*tag_action*/ MSG_SIMPLE_Q_TAG,
+ /*readop*/ (dev->write_dev == 0) ? SCSI_RW_READ :
+ SCSI_RW_WRITE,
+ /*byte2*/ 0,
+ /*minimum_cmd_size*/ dev->min_cmd_size,
+ /*lba*/ buf->lba,
+ /*block_count*/ num_blocks,
+ /*data_ptr*/ (data->sg_count != 0) ?
+ (uint8_t *)data->segs : data->buf,
+ /*dxfer_len*/ (num_blocks * pass_dev->block_len),
+ /*sense_len*/ SSD_FULL_SIZE,
+ /*timeout*/ dev->io_timeout);
+
+ /* Disable freezing the device queue */
+ ccb->ccb_h.flags |= CAM_DEV_QFRZDIS;
+
+ if (dev->retry_count != 0)
+ ccb->ccb_h.flags |= CAM_PASS_ERR_RECOVER;
+
+ if (data->sg_count != 0) {
+ ccb->csio.sglist_cnt = data->sg_count;
+ ccb->ccb_h.flags |= CAM_DATA_SG;
+ }
+
+ /*
+ * Store a pointer to the buffer in the CCB. The kernel will
+ * restore this when we get it back, and we'll use it to identify
+ * the buffer this CCB came from.
+ */
+ ccb->ccb_h.ccb_buf = buf;
+
+ /*
+ * Unlock our mutex in preparation for issuing the ioctl.
+ */
+ pthread_mutex_unlock(&dev->mutex);
+ /*
+ * Queue the CCB to the pass(4) driver.
+ */
+ if (ioctl(pass_dev->dev->fd, CAMIOQUEUE, ccb) == -1) {
+ pthread_mutex_lock(&dev->mutex);
+
+ warn("%s: error sending CAMIOQUEUE ioctl to %s%u", __func__,
+ pass_dev->dev->device_name, pass_dev->dev->dev_unit_num);
+ warn("%s: CCB address is %p", __func__, ccb);
+ retval = -1;
+
+ STAILQ_INSERT_TAIL(&dev->free_queue, buf, links);
+ } else {
+ pthread_mutex_lock(&dev->mutex);
+
+ dev->cur_active_io++;
+ STAILQ_INSERT_TAIL(&dev->active_queue, buf, links);
+ }
+
+bailout:
+ return (retval);
+}
+
+int
+camdd_get_next_lba_len(struct camdd_dev *dev, uint64_t *lba, ssize_t *len)
+{
+ struct camdd_dev_pass *pass_dev;
+ uint32_t num_blocks;
+ int retval = 0;
+
+ pass_dev = &dev->dev_spec.pass;
+
+ *lba = dev->next_io_pos_bytes / dev->sector_size;
+ *len = dev->blocksize;
+ num_blocks = *len / dev->sector_size;
+
+ /*
+ * If max_sector is 0, then we have no set limit. This can happen
+ * if we're writing to a file in a filesystem, or reading from
+ * something like /dev/zero.
+ */
+ if ((dev->max_sector != 0)
+ || (dev->sector_io_limit != 0)) {
+ uint64_t max_sector;
+
+ if ((dev->max_sector != 0)
+ && (dev->sector_io_limit != 0))
+ max_sector = min(dev->sector_io_limit, dev->max_sector);
+ else if (dev->max_sector != 0)
+ max_sector = dev->max_sector;
+ else
+ max_sector = dev->sector_io_limit;
+
+
+ /*
+ * Check to see whether we're starting off past the end of
+ * the device. If so, we need to just send an EOF
+ * notification to the writer.
+ */
+ if (*lba > max_sector) {
+ *len = 0;
+ retval = 1;
+ } else if (((*lba + num_blocks) > max_sector + 1)
+ || ((*lba + num_blocks) < *lba)) {
+ /*
+ * If we get here (but pass the first check), we
+ * can trim the request length down to go to the
+ * end of the device.
+ */
+ num_blocks = (max_sector + 1) - *lba;
+ *len = num_blocks * dev->sector_size;
+ retval = 1;
+ }
+ }
+
+ dev->next_io_pos_bytes += *len;
+
+ return (retval);
+}
+
+/*
+ * Returns 0 for success, 1 for EOF detected, and -1 for failure.
+ */
+int
+camdd_queue(struct camdd_dev *dev, struct camdd_buf *read_buf)
+{
+ struct camdd_buf *buf = NULL;
+ struct camdd_buf_data *data;
+ struct camdd_dev_pass *pass_dev;
+ size_t new_len;
+ struct camdd_buf_data *rb_data;
+ int is_write = dev->write_dev;
+ int eof_flush_needed = 0;
+ int retval = 0;
+ int error;
+
+ pass_dev = &dev->dev_spec.pass;
+
+ /*
+ * If we've gotten EOF or our partner has, we should not continue
+ * queueing I/O. If we're a writer, though, we should continue
+ * to write any buffers that don't have EOF status.
+ */
+ if ((dev->flags & CAMDD_DEV_FLAG_EOF)
+ || ((dev->flags & CAMDD_DEV_FLAG_PEER_EOF)
+ && (is_write == 0))) {
+ /*
+ * Tell the worker thread that we have seen EOF.
+ */
+ retval = 1;
+
+ /*
+ * If we're the writer, send the buffer back with EOF status.
+ */
+ if (is_write) {
+ read_buf->status = CAMDD_STATUS_EOF;
+
+ error = camdd_complete_peer_buf(dev, read_buf);
+ }
+ goto bailout;
+ }
+
+ if (is_write == 0) {
+ buf = camdd_get_buf(dev, CAMDD_BUF_DATA);
+ if (buf == NULL) {
+ retval = -1;
+ goto bailout;
+ }
+ data = &buf->buf_type_spec.data;
+
+ retval = camdd_get_next_lba_len(dev, &buf->lba, &buf->len);
+ if (retval != 0) {
+ buf->status = CAMDD_STATUS_EOF;
+
+ if ((buf->len == 0)
+ && ((dev->flags & (CAMDD_DEV_FLAG_EOF_SENT |
+ CAMDD_DEV_FLAG_EOF_QUEUED)) != 0)) {
+ camdd_release_buf(buf);
+ goto bailout;
+ }
+ dev->flags |= CAMDD_DEV_FLAG_EOF_QUEUED;
+ }
+
+ data->fill_len = buf->len;
+ data->src_start_offset = buf->lba * dev->sector_size;
+
+ /*
+ * Put this on the run queue.
+ */
+ STAILQ_INSERT_TAIL(&dev->run_queue, buf, links);
+ dev->num_run_queue++;
+
+ /* We're done. */
+ goto bailout;
+ }
+
+ /*
+ * Check for new EOF status from the reader.
+ */
+ if ((read_buf->status == CAMDD_STATUS_EOF)
+ || (read_buf->status == CAMDD_STATUS_ERROR)) {
+ dev->flags |= CAMDD_DEV_FLAG_PEER_EOF;
+ if ((STAILQ_FIRST(&dev->pending_queue) == NULL)
+ && (read_buf->len == 0)) {
+ camdd_complete_peer_buf(dev, read_buf);
+ retval = 1;
+ goto bailout;
+ } else
+ eof_flush_needed = 1;
+ }
+
+ /*
+ * See if we have a buffer we're composing with pieces from our
+ * partner thread.
+ */
+ buf = STAILQ_FIRST(&dev->pending_queue);
+ if (buf == NULL) {
+ uint64_t lba;
+ ssize_t len;
+
+ retval = camdd_get_next_lba_len(dev, &lba, &len);
+ if (retval != 0) {
+ read_buf->status = CAMDD_STATUS_EOF;
+
+ if (len == 0) {
+ dev->flags |= CAMDD_DEV_FLAG_EOF;
+ error = camdd_complete_peer_buf(dev, read_buf);
+ goto bailout;
+ }
+ }
+
+ /*
+ * If we don't have a pending buffer, we need to grab a new
+ * one from the free list or allocate another one.
+ */
+ buf = camdd_get_buf(dev, CAMDD_BUF_DATA);
+ if (buf == NULL) {
+ retval = 1;
+ goto bailout;
+ }
+
+ buf->lba = lba;
+ buf->len = len;
+
+ STAILQ_INSERT_TAIL(&dev->pending_queue, buf, links);
+ dev->num_pending_queue++;
+ }
+
+ data = &buf->buf_type_spec.data;
+
+ rb_data = &read_buf->buf_type_spec.data;
+
+ if ((rb_data->src_start_offset != dev->next_peer_pos_bytes)
+ && (dev->debug != 0)) {
+ printf("%s: WARNING: reader offset %#jx != expected offset "
+ "%#jx\n", __func__, (uintmax_t)rb_data->src_start_offset,
+ (uintmax_t)dev->next_peer_pos_bytes);
+ }
+ dev->next_peer_pos_bytes = rb_data->src_start_offset +
+ (rb_data->fill_len - rb_data->resid);
+
+ new_len = (rb_data->fill_len - rb_data->resid) + data->fill_len;
+ if (new_len < buf->len) {
+ /*
+ * There are three cases here:
+ * 1. We need more data to fill up a block, so we put
+ * this I/O on the queue and wait for more I/O.
+ * 2. We have a pending buffer in the queue that is
+ * smaller than our blocksize, but we got an EOF. So we
+ * need to go ahead and flush the write out.
+ * 3. We got an error.
+ */
+
+ /*
+ * Increment our fill length.
+ */
+ data->fill_len += (rb_data->fill_len - rb_data->resid);
+
+ /*
+ * Add the new read buffer to the list for writing.
+ */
+ STAILQ_INSERT_TAIL(&buf->src_list, read_buf, src_links);
+
+ /* Increment the count */
+ buf->src_count++;
+
+ if (eof_flush_needed == 0) {
+ /*
+ * We need to exit, because we don't have enough
+ * data yet.
+ */
+ goto bailout;
+ } else {
+ /*
+ * Take the buffer off of the pending queue.
+ */
+ STAILQ_REMOVE(&dev->pending_queue, buf, camdd_buf,
+ links);
+ dev->num_pending_queue--;
+
+ /*
+ * If we need an EOF flush, but there is no data
+ * to flush, go ahead and return this buffer.
+ */
+ if (data->fill_len == 0) {
+ camdd_complete_buf(dev, buf, /*error_count*/0);
+ retval = 1;
+ goto bailout;
+ }
+
+ /*
+ * Put this on the next queue for execution.
+ */
+ STAILQ_INSERT_TAIL(&dev->run_queue, buf, links);
+ dev->num_run_queue++;
+ }
+ } else if (new_len == buf->len) {
+ /*
+ * We have enough data to completey fill one block,
+ * so we're ready to issue the I/O.
+ */
+
+ /*
+ * Take the buffer off of the pending queue.
+ */
+ STAILQ_REMOVE(&dev->pending_queue, buf, camdd_buf, links);
+ dev->num_pending_queue--;
+
+ /*
+ * Add the new read buffer to the list for writing.
+ */
+ STAILQ_INSERT_TAIL(&buf->src_list, read_buf, src_links);
+
+ /* Increment the count */
+ buf->src_count++;
+
+ /*
+ * Increment our fill length.
+ */
+ data->fill_len += (rb_data->fill_len - rb_data->resid);
+
+ /*
+ * Put this on the next queue for execution.
+ */
+ STAILQ_INSERT_TAIL(&dev->run_queue, buf, links);
+ dev->num_run_queue++;
+ } else {
+ struct camdd_buf *idb;
+ struct camdd_buf_indirect *indirect;
+ uint32_t len_to_go, cur_offset;
+
+
+ idb = camdd_get_buf(dev, CAMDD_BUF_INDIRECT);
+ if (idb == NULL) {
+ retval = 1;
+ goto bailout;
+ }
+ indirect = &idb->buf_type_spec.indirect;
+ indirect->src_buf = read_buf;
+ read_buf->refcount++;
+ indirect->offset = 0;
+ indirect->start_ptr = rb_data->buf;
+ /*
+ * We've already established that there is more
+ * data in read_buf than we have room for in our
+ * current write request. So this particular chunk
+ * of the request should just be the remainder
+ * needed to fill up a block.
+ */
+ indirect->len = buf->len - (data->fill_len - data->resid);
+
+ camdd_buf_add_child(buf, idb);
+
+ /*
+ * This buffer is ready to execute, so we can take
+ * it off the pending queue and put it on the run
+ * queue.
+ */
+ STAILQ_REMOVE(&dev->pending_queue, buf, camdd_buf,
+ links);
+ dev->num_pending_queue--;
+ STAILQ_INSERT_TAIL(&dev->run_queue, buf, links);
+ dev->num_run_queue++;
+
+ cur_offset = indirect->offset + indirect->len;
+
+ /*
+ * The resulting I/O would be too large to fit in
+ * one block. We need to split this I/O into
+ * multiple pieces. Allocate as many buffers as needed.
+ */
+ for (len_to_go = rb_data->fill_len - rb_data->resid -
+ indirect->len; len_to_go > 0;) {
+ struct camdd_buf *new_buf;
+ struct camdd_buf_data *new_data;
+ uint64_t lba;
+ ssize_t len;
+
+ retval = camdd_get_next_lba_len(dev, &lba, &len);
+ if ((retval != 0)
+ && (len == 0)) {
+ /*
+ * The device has already been marked
+ * as EOF, and there is no space left.
+ */
+ goto bailout;
+ }
+
+ new_buf = camdd_get_buf(dev, CAMDD_BUF_DATA);
+ if (new_buf == NULL) {
+ retval = 1;
+ goto bailout;
+ }
+
+ new_buf->lba = lba;
+ new_buf->len = len;
+
+ idb = camdd_get_buf(dev, CAMDD_BUF_INDIRECT);
+ if (idb == NULL) {
+ retval = 1;
+ goto bailout;
+ }
+
+ indirect = &idb->buf_type_spec.indirect;
+
+ indirect->src_buf = read_buf;
+ read_buf->refcount++;
+ indirect->offset = cur_offset;
+ indirect->start_ptr = rb_data->buf + cur_offset;
+ indirect->len = min(len_to_go, new_buf->len);
+#if 0
+ if (((indirect->len % dev->sector_size) != 0)
+ || ((indirect->offset % dev->sector_size) != 0)) {
+ warnx("offset %ju len %ju not aligned with "
+ "sector size %u", indirect->offset,
+ (uintmax_t)indirect->len, dev->sector_size);
+ }
+#endif
+ cur_offset += indirect->len;
+ len_to_go -= indirect->len;
+
+ camdd_buf_add_child(new_buf, idb);
+
+ new_data = &new_buf->buf_type_spec.data;
+
+ if ((new_data->fill_len == new_buf->len)
+ || (eof_flush_needed != 0)) {
+ STAILQ_INSERT_TAIL(&dev->run_queue,
+ new_buf, links);
+ dev->num_run_queue++;
+ } else if (new_data->fill_len < buf->len) {
+ STAILQ_INSERT_TAIL(&dev->pending_queue,
+ new_buf, links);
+ dev->num_pending_queue++;
+ } else {
+ warnx("%s: too much data in new "
+ "buffer!", __func__);
+ retval = 1;
+ goto bailout;
+ }
+ }
+ }
+
+bailout:
+ return (retval);
+}
+
+void
+camdd_get_depth(struct camdd_dev *dev, uint32_t *our_depth,
+ uint32_t *peer_depth, uint32_t *our_bytes, uint32_t *peer_bytes)
+{
+ *our_depth = dev->cur_active_io + dev->num_run_queue;
+ if (dev->num_peer_work_queue >
+ dev->num_peer_done_queue)
+ *peer_depth = dev->num_peer_work_queue -
+ dev->num_peer_done_queue;
+ else
+ *peer_depth = 0;
+ *our_bytes = *our_depth * dev->blocksize;
+ *peer_bytes = dev->peer_bytes_queued;
+}
+
+void
+camdd_sig_handler(int sig)
+{
+ if (sig == SIGINFO)
+ need_status = 1;
+ else {
+ need_exit = 1;
+ error_exit = 1;
+ }
+
+ sem_post(&camdd_sem);
+}
+
+void
+camdd_print_status(struct camdd_dev *camdd_dev, struct camdd_dev *other_dev,
+ struct timespec *start_time)
+{
+ struct timespec done_time;
+ uint64_t total_ns;
+ long double mb_sec, total_sec;
+ int error = 0;
+
+ error = clock_gettime(CLOCK_MONOTONIC_PRECISE, &done_time);
+ if (error != 0) {
+ warn("Unable to get done time");
+ return;
+ }
+
+ timespecsub(&done_time, start_time);
+
+ total_ns = done_time.tv_nsec + (done_time.tv_sec * 1000000000);
+ total_sec = total_ns;
+ total_sec /= 1000000000;
+
+ fprintf(stderr, "%ju bytes %s %s\n%ju bytes %s %s\n"
+ "%.4Lf seconds elapsed\n",
+ (uintmax_t)camdd_dev->bytes_transferred,
+ (camdd_dev->write_dev == 0) ? "read from" : "written to",
+ camdd_dev->device_name,
+ (uintmax_t)other_dev->bytes_transferred,
+ (other_dev->write_dev == 0) ? "read from" : "written to",
+ other_dev->device_name, total_sec);
+
+ mb_sec = min(other_dev->bytes_transferred,camdd_dev->bytes_transferred);
+ mb_sec /= 1024 * 1024;
+ mb_sec *= 1000000000;
+ mb_sec /= total_ns;
+ fprintf(stderr, "%.2Lf MB/sec\n", mb_sec);
+}
+
+int
+camdd_rw(struct camdd_io_opts *io_opts, int num_io_opts, uint64_t max_io,
+ int retry_count, int timeout)
+{
+ char *device = NULL;
+ struct cam_device *new_cam_dev = NULL;
+ struct camdd_dev *devs[2];
+ struct timespec start_time;
+ pthread_t threads[2];
+ int unit = 0;
+ int error = 0;
+ int i;
+
+ if (num_io_opts != 2) {
+ warnx("Must have one input and one output path");
+ error = 1;
+ goto bailout;
+ }
+
+ bzero(devs, sizeof(devs));
+
+ for (i = 0; i < num_io_opts; i++) {
+ switch (io_opts[i].dev_type) {
+ case CAMDD_DEV_PASS: {
+ camdd_argmask new_arglist = CAMDD_ARG_NONE;
+ int bus = 0, target = 0, lun = 0;
+ char name[30];
+ int rv;
+
+ if (isdigit(io_opts[i].dev_name[0])) {
+ /* device specified as bus:target[:lun] */
+ rv = parse_btl(io_opts[i].dev_name, &bus,
+ &target, &lun, &new_arglist);
+ if (rv < 2) {
+ warnx("numeric device specification "
+ "must be either bus:target, or "
+ "bus:target:lun");
+ error = 1;
+ goto bailout;
+ }
+ /* default to 0 if lun was not specified */
+ if ((new_arglist & CAMDD_ARG_LUN) == 0) {
+ lun = 0;
+ new_arglist |= CAMDD_ARG_LUN;
+ }
+ } else {
+ if (cam_get_device(io_opts[i].dev_name, name,
+ sizeof name, &unit) == -1) {
+ warnx("%s", cam_errbuf);
+ error = 1;
+ goto bailout;
+ }
+ device = strdup(name);
+ new_arglist |= CAMDD_ARG_DEVICE |CAMDD_ARG_UNIT;
+ }
+
+ if (new_arglist & (CAMDD_ARG_BUS | CAMDD_ARG_TARGET))
+ new_cam_dev = cam_open_btl(bus, target, lun,
+ O_RDWR, NULL);
+ else
+ new_cam_dev = cam_open_spec_device(device, unit,
+ O_RDWR, NULL);
+ if (new_cam_dev == NULL) {
+ warnx("%s", cam_errbuf);
+ error = 1;
+ goto bailout;
+ }
+
+ devs[i] = camdd_probe_pass(new_cam_dev,
+ /*io_opts*/ &io_opts[i],
+ CAMDD_ARG_ERR_RECOVER,
+ /*probe_retry_count*/ 3,
+ /*probe_timeout*/ 5000,
+ /*io_retry_count*/ retry_count,
+ /*io_timeout*/ timeout);
+ if (devs[i] == NULL) {
+ warn("Unable to probe device %s%u",
+ new_cam_dev->device_name,
+ new_cam_dev->dev_unit_num);
+ error = 1;
+ goto bailout;
+ }
+ break;
+ }
+ case CAMDD_DEV_FILE: {
+ int fd = -1;
+
+ if (io_opts[i].dev_name[0] == '-') {
+ if (io_opts[i].write_dev != 0)
+ fd = STDOUT_FILENO;
+ else
+ fd = STDIN_FILENO;
+ } else {
+ if (io_opts[i].write_dev != 0) {
+ fd = open(io_opts[i].dev_name,
+ O_RDWR | O_CREAT, S_IWUSR |S_IRUSR);
+ } else {
+ fd = open(io_opts[i].dev_name,
+ O_RDONLY);
+ }
+ }
+ if (fd == -1) {
+ warn("error opening file %s",
+ io_opts[i].dev_name);
+ error = 1;
+ goto bailout;
+ }
+
+ devs[i] = camdd_probe_file(fd, &io_opts[i],
+ retry_count, timeout);
+ if (devs[i] == NULL) {
+ error = 1;
+ goto bailout;
+ }
+
+ break;
+ }
+ default:
+ warnx("Unknown device type %d (%s)",
+ io_opts[i].dev_type, io_opts[i].dev_name);
+ error = 1;
+ goto bailout;
+ break; /*NOTREACHED */
+ }
+
+ devs[i]->write_dev = io_opts[i].write_dev;
+
+ devs[i]->start_offset_bytes = io_opts[i].offset;
+
+ if (max_io != 0) {
+ devs[i]->sector_io_limit =
+ (devs[i]->start_offset_bytes /
+ devs[i]->sector_size) +
+ (max_io / devs[i]->sector_size) - 1;
+ devs[i]->sector_io_limit =
+ (devs[i]->start_offset_bytes /
+ devs[i]->sector_size) +
+ (max_io / devs[i]->sector_size) - 1;
+ }
+
+ devs[i]->next_io_pos_bytes = devs[i]->start_offset_bytes;
+ devs[i]->next_completion_pos_bytes =devs[i]->start_offset_bytes;
+ }
+
+ devs[0]->peer_dev = devs[1];
+ devs[1]->peer_dev = devs[0];
+ devs[0]->next_peer_pos_bytes = devs[0]->peer_dev->next_io_pos_bytes;
+ devs[1]->next_peer_pos_bytes = devs[1]->peer_dev->next_io_pos_bytes;
+
+ sem_init(&camdd_sem, /*pshared*/ 0, 0);
+
+ signal(SIGINFO, camdd_sig_handler);
+ signal(SIGINT, camdd_sig_handler);
+
+ error = clock_gettime(CLOCK_MONOTONIC_PRECISE, &start_time);
+ if (error != 0) {
+ warn("Unable to get start time");
+ goto bailout;
+ }
+
+ for (i = 0; i < num_io_opts; i++) {
+ error = pthread_create(&threads[i], NULL, camdd_worker,
+ (void *)devs[i]);
+ if (error != 0) {
+ warnc(error, "pthread_create() failed");
+ goto bailout;
+ }
+ }
+
+ for (;;) {
+ if ((sem_wait(&camdd_sem) == -1)
+ || (need_exit != 0)) {
+ struct kevent ke;
+
+ for (i = 0; i < num_io_opts; i++) {
+ EV_SET(&ke, (uintptr_t)&devs[i]->work_queue,
+ EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
+
+ devs[i]->flags |= CAMDD_DEV_FLAG_EOF;
+
+ error = kevent(devs[i]->kq, &ke, 1, NULL, 0,
+ NULL);
+ if (error == -1)
+ warn("%s: unable to wake up thread",
+ __func__);
+ error = 0;
+ }
+ break;
+ } else if (need_status != 0) {
+ camdd_print_status(devs[0], devs[1], &start_time);
+ need_status = 0;
+ }
+ }
+ for (i = 0; i < num_io_opts; i++) {
+ pthread_join(threads[i], NULL);
+ }
+
+ camdd_print_status(devs[0], devs[1], &start_time);
+
+bailout:
+
+ for (i = 0; i < num_io_opts; i++)
+ camdd_free_dev(devs[i]);
+
+ return (error + error_exit);
+}
+
+void
+usage(void)
+{
+ fprintf(stderr,
+"usage: camdd <-i|-o pass=pass0,bs=1M,offset=1M,depth=4>\n"
+" <-i|-o file=/tmp/file,bs=512K,offset=1M>\n"
+" <-i|-o file=/dev/da0,bs=512K,offset=1M>\n"
+" <-i|-o file=/dev/nsa0,bs=512K>\n"
+" [-C retry_count][-E][-m max_io_amt][-t timeout_secs][-v][-h]\n"
+"Option description\n"
+"-i <arg=val> Specify input device/file and parameters\n"
+"-o <arg=val> Specify output device/file and parameters\n"
+"Input and Output parameters\n"
+"pass=name Specify a pass(4) device like pass0 or /dev/pass0\n"
+"file=name Specify a file or device, /tmp/foo, /dev/da0, /dev/null\n"
+" or - for stdin/stdout\n"
+"bs=blocksize Specify blocksize in bytes, or using K, M, G, etc. suffix\n"
+"offset=len Specify starting offset in bytes or using K, M, G suffix\n"
+" NOTE: offset cannot be specified on tapes, pipes, stdin/out\n"
+"depth=N Specify a numeric queue depth. This only applies to pass(4)\n"
+"mcs=N Specify a minimum cmd size for pass(4) read/write commands\n"
+"Optional arguments\n"
+"-C retry_cnt Specify a retry count for pass(4) devices\n"
+"-E Enable CAM error recovery for pass(4) devices\n"
+"-m max_io Specify the maximum amount to be transferred in bytes or\n"
+" using K, G, M, etc. suffixes\n"
+"-t timeout Specify the I/O timeout to use with pass(4) devices\n"
+"-v Enable verbose error recovery\n"
+"-h Print this message\n");
+}
+
+
+int
+camdd_parse_io_opts(char *args, int is_write, struct camdd_io_opts *io_opts)
+{
+ char *tmpstr, *tmpstr2;
+ char *orig_tmpstr = NULL;
+ int retval = 0;
+
+ io_opts->write_dev = is_write;
+
+ tmpstr = strdup(args);
+ if (tmpstr == NULL) {
+ warn("strdup failed");
+ retval = 1;
+ goto bailout;
+ }
+ orig_tmpstr = tmpstr;
+ while ((tmpstr2 = strsep(&tmpstr, ",")) != NULL) {
+ char *name, *value;
+
+ /*
+ * If the user creates an empty parameter by putting in two
+ * commas, skip over it and look for the next field.
+ */
+ if (*tmpstr2 == '\0')
+ continue;
+
+ name = strsep(&tmpstr2, "=");
+ if (*name == '\0') {
+ warnx("Got empty I/O parameter name");
+ retval = 1;
+ goto bailout;
+ }
+ value = strsep(&tmpstr2, "=");
+ if ((value == NULL)
+ || (*value == '\0')) {
+ warnx("Empty I/O parameter value for %s", name);
+ retval = 1;
+ goto bailout;
+ }
+ if (strncasecmp(name, "file", 4) == 0) {
+ io_opts->dev_type = CAMDD_DEV_FILE;
+ io_opts->dev_name = strdup(value);
+ if (io_opts->dev_name == NULL) {
+ warn("Error allocating memory");
+ retval = 1;
+ goto bailout;
+ }
+ } else if (strncasecmp(name, "pass", 4) == 0) {
+ io_opts->dev_type = CAMDD_DEV_PASS;
+ io_opts->dev_name = strdup(value);
+ if (io_opts->dev_name == NULL) {
+ warn("Error allocating memory");
+ retval = 1;
+ goto bailout;
+ }
+ } else if ((strncasecmp(name, "bs", 2) == 0)
+ || (strncasecmp(name, "blocksize", 9) == 0)) {
+ retval = expand_number(value, &io_opts->blocksize);
+ if (retval == -1) {
+ warn("expand_number(3) failed on %s=%s", name,
+ value);
+ retval = 1;
+ goto bailout;
+ }
+ } else if (strncasecmp(name, "depth", 5) == 0) {
+ char *endptr;
+
+ io_opts->queue_depth = strtoull(value, &endptr, 0);
+ if (*endptr != '\0') {
+ warnx("invalid queue depth %s", value);
+ retval = 1;
+ goto bailout;
+ }
+ } else if (strncasecmp(name, "mcs", 3) == 0) {
+ char *endptr;
+
+ io_opts->min_cmd_size = strtol(value, &endptr, 0);
+ if ((*endptr != '\0')
+ || ((io_opts->min_cmd_size > 16)
+ || (io_opts->min_cmd_size < 0))) {
+ warnx("invalid minimum cmd size %s", value);
+ retval = 1;
+ goto bailout;
+ }
+ } else if (strncasecmp(name, "offset", 6) == 0) {
+ retval = expand_number(value, &io_opts->offset);
+ if (retval == -1) {
+ warn("expand_number(3) failed on %s=%s", name,
+ value);
+ retval = 1;
+ goto bailout;
+ }
+ } else if (strncasecmp(name, "debug", 5) == 0) {
+ char *endptr;
+
+ io_opts->debug = strtoull(value, &endptr, 0);
+ if (*endptr != '\0') {
+ warnx("invalid debug level %s", value);
+ retval = 1;
+ goto bailout;
+ }
+ } else {
+ warnx("Unrecognized parameter %s=%s", name, value);
+ }
+ }
+bailout:
+ free(orig_tmpstr);
+
+ return (retval);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ camdd_argmask arglist = CAMDD_ARG_NONE;
+ int timeout = 0, retry_count = 1;
+ int error = 0;
+ uint64_t max_io = 0;
+ struct camdd_io_opts *opt_list = NULL;
+
+ if (argc == 1) {
+ usage();
+ exit(1);
+ }
+
+ opt_list = calloc(2, sizeof(struct camdd_io_opts));
+ if (opt_list == NULL) {
+ warn("Unable to allocate option list");
+ error = 1;
+ goto bailout;
+ }
+
+ while ((c = getopt(argc, argv, "C:Ehi:m:o:t:v")) != -1){
+ switch (c) {
+ case 'C':
+ retry_count = strtol(optarg, NULL, 0);
+ if (retry_count < 0)
+ errx(1, "retry count %d is < 0",
+ retry_count);
+ arglist |= CAMDD_ARG_RETRIES;
+ break;
+ case 'E':
+ arglist |= CAMDD_ARG_ERR_RECOVER;
+ break;
+ case 'i':
+ case 'o':
+ if (((c == 'i')
+ && (opt_list[0].dev_type != CAMDD_DEV_NONE))
+ || ((c == 'o')
+ && (opt_list[1].dev_type != CAMDD_DEV_NONE))) {
+ errx(1, "Only one input and output path "
+ "allowed");
+ }
+ error = camdd_parse_io_opts(optarg, (c == 'o') ? 1 : 0,
+ (c == 'o') ? &opt_list[1] : &opt_list[0]);
+ if (error != 0)
+ goto bailout;
+ break;
+ case 'm':
+ error = expand_number(optarg, &max_io);
+ if (error == -1) {
+ warn("invalid maximum I/O amount %s", optarg);
+ error = 1;
+ goto bailout;
+ }
+ break;
+ case 't':
+ timeout = strtol(optarg, NULL, 0);
+ if (timeout < 0)
+ errx(1, "invalid timeout %d", timeout);
+ /* Convert the timeout from seconds to ms */
+ timeout *= 1000;
+ arglist |= CAMDD_ARG_TIMEOUT;
+ break;
+ case 'v':
+ arglist |= CAMDD_ARG_VERBOSE;
+ break;
+ case 'h':
+ default:
+ usage();
+ exit(1);
+ break; /*NOTREACHED*/
+ }
+ }
+
+ if ((opt_list[0].dev_type == CAMDD_DEV_NONE)
+ || (opt_list[1].dev_type == CAMDD_DEV_NONE))
+ errx(1, "Must specify both -i and -o");
+
+ /*
+ * Set the timeout if the user hasn't specified one.
+ */
+ if (timeout == 0)
+ timeout = CAMDD_PASS_RW_TIMEOUT;
+
+ error = camdd_rw(opt_list, 2, max_io, retry_count, timeout);
+
+bailout:
+ free(opt_list);
+
+ exit(error);
+}
diff --git a/usr.sbin/config/config.h b/usr.sbin/config/config.h
index 93b2086..703d053 100644
--- a/usr.sbin/config/config.h
+++ b/usr.sbin/config/config.h
@@ -50,7 +50,7 @@ struct file_list {
int f_type; /* type */
u_char f_flags; /* see below */
char *f_compilewith; /* special make rule if present */
- char *f_depends; /* additional dependancies */
+ char *f_depends; /* additional dependencies */
char *f_clean; /* File list to add to clean rule */
char *f_warn; /* warning message */
const char *f_objprefix; /* prefix string for object name */
diff --git a/usr.sbin/cron/cron/do_command.c b/usr.sbin/cron/cron/do_command.c
index 8dfd4f6..7a7ac57 100644
--- a/usr.sbin/cron/cron/do_command.c
+++ b/usr.sbin/cron/cron/do_command.c
@@ -161,8 +161,10 @@ child_process(e, u)
/* create some pipes to talk to our future child
*/
- pipe(stdin_pipe); /* child's stdin */
- pipe(stdout_pipe); /* child's stdout */
+ if (pipe(stdin_pipe) != 0 || pipe(stdout_pipe) != 0) {
+ log_it("CRON", getpid(), "error", "can't pipe");
+ exit(ERROR_EXIT);
+ }
/* since we are a forked process, we can diddle the command string
* we were passed -- nobody else is going to use it again, right?
diff --git a/usr.sbin/cron/cron/popen.c b/usr.sbin/cron/cron/popen.c
index 428de2e..57b1f77 100644
--- a/usr.sbin/cron/cron/popen.c
+++ b/usr.sbin/cron/cron/popen.c
@@ -82,9 +82,8 @@ cron_popen(program, type, e)
if (!pids) {
if ((fds = getdtablesize()) <= 0)
return(NULL);
- if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
+ if (!(pids = calloc(fds, sizeof(PID_T))))
return(NULL);
- bzero((char *)pids, fds * sizeof(PID_T));
}
if (pipe(pdes) < 0)
return(NULL);
diff --git a/usr.sbin/cron/crontab/crontab.c b/usr.sbin/cron/crontab/crontab.c
index 1ac81b0..f2e97a7 100644
--- a/usr.sbin/cron/crontab/crontab.c
+++ b/usr.sbin/cron/crontab/crontab.c
@@ -558,7 +558,7 @@ replace_cmd() {
case FALSE:
e = load_entry(tmp, check_error, pw, envp);
if (e)
- free(e);
+ free_entry(e);
break;
case TRUE:
break;
diff --git a/usr.sbin/crunch/crunchide/exec_elf32.c b/usr.sbin/crunch/crunchide/exec_elf32.c
index fc9a959..6d94429 100644
--- a/usr.sbin/crunch/crunchide/exec_elf32.c
+++ b/usr.sbin/crunch/crunchide/exec_elf32.c
@@ -187,6 +187,10 @@ ELFNAMEEND(check)(int fd, const char *fn)
case /* EM_MIPS_RS3_LE */ EM_MIPS_RS4_BE: break;
case EM_PPC: break;
case EM_PPC64: break;
+#ifndef EM_RISCV
+#define EM_RISCV 243
+#endif
+ case EM_RISCV: break;
case EM_SPARCV9: break;
case EM_X86_64: break;
/* ELFDEFNNAME(MACHDEP_ID_CASES) */
diff --git a/usr.sbin/ctld/Makefile.depend b/usr.sbin/ctld/Makefile.depend
new file mode 100644
index 0000000..ece2325
--- /dev/null
+++ b/usr.sbin/ctld/Makefile.depend
@@ -0,0 +1,31 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libexpat \
+ lib/libmd \
+ lib/libsbuf \
+ lib/libutil \
+ usr.bin/lex/lib \
+ usr.bin/yacc.host \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+parse.o: parse.c
+parse.po: parse.c
+token.o: token.c
+token.o: y.tab.h
+token.po: token.c
+token.po: y.tab.h
+.endif
diff --git a/usr.sbin/ctld/ctl.conf.5 b/usr.sbin/ctld/ctl.conf.5
index 538699e..80b2f9e 100644
--- a/usr.sbin/ctld/ctl.conf.5
+++ b/usr.sbin/ctld/ctl.conf.5
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 27, 2015
+.Dd November 9, 2015
.Dt CTL.CONF 5
.Os
.Sh NAME
@@ -226,6 +226,8 @@ An IPv4 or IPv6 address and port to listen on for incoming connections.
.It Ic offload Ar driver
Define iSCSI hardware offload driver to use for this
.Sy portal-group .
+.It Ic option Ar name Ar value
+The CTL-specific port options passed to the kernel.
.It Ic redirect Ar address
IPv4 or IPv6 address to redirect initiators to.
When configured, all initiators attempting to connect to portal
diff --git a/usr.sbin/ctld/ctld.c b/usr.sbin/ctld/ctld.c
index 4813ae0..92fa553 100644
--- a/usr.sbin/ctld/ctld.c
+++ b/usr.sbin/ctld/ctld.c
@@ -615,6 +615,7 @@ portal_group_new(struct conf *conf, const char *name)
if (pg == NULL)
log_err(1, "calloc");
pg->pg_name = checked_strdup(name);
+ TAILQ_INIT(&pg->pg_options);
TAILQ_INIT(&pg->pg_portals);
TAILQ_INIT(&pg->pg_ports);
pg->pg_conf = conf;
@@ -629,6 +630,7 @@ portal_group_delete(struct portal_group *pg)
{
struct portal *portal, *tmp;
struct port *port, *tport;
+ struct option *o, *otmp;
TAILQ_FOREACH_SAFE(port, &pg->pg_ports, p_pgs, tport)
port_delete(port);
@@ -636,6 +638,8 @@ portal_group_delete(struct portal_group *pg)
TAILQ_FOREACH_SAFE(portal, &pg->pg_portals, p_next, tmp)
portal_delete(portal);
+ TAILQ_FOREACH_SAFE(o, &pg->pg_options, o_next, otmp)
+ option_delete(&pg->pg_options, o);
free(pg->pg_name);
free(pg->pg_offload);
free(pg->pg_redirection);
@@ -1406,7 +1410,7 @@ void
lun_delete(struct lun *lun)
{
struct target *targ;
- struct lun_option *lo, *tmp;
+ struct option *o, *tmp;
int i;
TAILQ_FOREACH(targ, &lun->l_conf->conf_targets, t_next) {
@@ -1417,8 +1421,8 @@ lun_delete(struct lun *lun)
}
TAILQ_REMOVE(&lun->l_conf->conf_luns, lun, l_next);
- TAILQ_FOREACH_SAFE(lo, &lun->l_options, lo_next, tmp)
- lun_option_delete(lo);
+ TAILQ_FOREACH_SAFE(o, &lun->l_options, o_next, tmp)
+ option_delete(&lun->l_options, o);
free(lun->l_name);
free(lun->l_backend);
free(lun->l_device_id);
@@ -1504,59 +1508,56 @@ lun_set_ctl_lun(struct lun *lun, uint32_t value)
lun->l_ctl_lun = value;
}
-struct lun_option *
-lun_option_new(struct lun *lun, const char *name, const char *value)
+struct option *
+option_new(struct options *options, const char *name, const char *value)
{
- struct lun_option *lo;
+ struct option *o;
- lo = lun_option_find(lun, name);
- if (lo != NULL) {
- log_warnx("duplicated lun option \"%s\" for lun \"%s\"",
- name, lun->l_name);
+ o = option_find(options, name);
+ if (o != NULL) {
+ log_warnx("duplicated option \"%s\"", name);
return (NULL);
}
- lo = calloc(1, sizeof(*lo));
- if (lo == NULL)
+ o = calloc(1, sizeof(*o));
+ if (o == NULL)
log_err(1, "calloc");
- lo->lo_name = checked_strdup(name);
- lo->lo_value = checked_strdup(value);
- lo->lo_lun = lun;
- TAILQ_INSERT_TAIL(&lun->l_options, lo, lo_next);
+ o->o_name = checked_strdup(name);
+ o->o_value = checked_strdup(value);
+ TAILQ_INSERT_TAIL(options, o, o_next);
- return (lo);
+ return (o);
}
void
-lun_option_delete(struct lun_option *lo)
+option_delete(struct options *options, struct option *o)
{
- TAILQ_REMOVE(&lo->lo_lun->l_options, lo, lo_next);
-
- free(lo->lo_name);
- free(lo->lo_value);
- free(lo);
+ TAILQ_REMOVE(options, o, o_next);
+ free(o->o_name);
+ free(o->o_value);
+ free(o);
}
-struct lun_option *
-lun_option_find(const struct lun *lun, const char *name)
+struct option *
+option_find(const struct options *options, const char *name)
{
- struct lun_option *lo;
+ struct option *o;
- TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
- if (strcmp(lo->lo_name, name) == 0)
- return (lo);
+ TAILQ_FOREACH(o, options, o_next) {
+ if (strcmp(o->o_name, name) == 0)
+ return (o);
}
return (NULL);
}
void
-lun_option_set(struct lun_option *lo, const char *value)
+option_set(struct option *o, const char *value)
{
- free(lo->lo_value);
- lo->lo_value = checked_strdup(value);
+ free(o->o_value);
+ o->o_value = checked_strdup(value);
}
static struct connection *
@@ -1595,7 +1596,7 @@ conf_print(struct conf *conf)
struct portal *portal;
struct target *targ;
struct lun *lun;
- struct lun_option *lo;
+ struct option *o;
TAILQ_FOREACH(ag, &conf->conf_auth_groups, ag_next) {
fprintf(stderr, "auth-group %s {\n", ag->ag_name);
@@ -1620,9 +1621,9 @@ conf_print(struct conf *conf)
TAILQ_FOREACH(lun, &conf->conf_luns, l_next) {
fprintf(stderr, "\tlun %s {\n", lun->l_name);
fprintf(stderr, "\t\tpath %s\n", lun->l_path);
- TAILQ_FOREACH(lo, &lun->l_options, lo_next)
+ TAILQ_FOREACH(o, &lun->l_options, o_next)
fprintf(stderr, "\t\toption %s %s\n",
- lo->lo_name, lo->lo_value);
+ lo->o_name, lo->o_value);
fprintf(stderr, "\t}\n");
}
TAILQ_FOREACH(targ, &conf->conf_targets, t_next) {
@@ -2028,7 +2029,7 @@ conf_apply(struct conf *oldconf, struct conf *newconf)
}
/*
- * Go through the new portals, opening the sockets as neccessary.
+ * Go through the new portals, opening the sockets as necessary.
*/
TAILQ_FOREACH(newpg, &newconf->conf_portal_groups, pg_next) {
if (newpg->pg_foreign)
diff --git a/usr.sbin/ctld/ctld.h b/usr.sbin/ctld/ctld.h
index 51775d7..808b722 100644
--- a/usr.sbin/ctld/ctld.h
+++ b/usr.sbin/ctld/ctld.h
@@ -105,6 +105,8 @@ struct portal {
int p_socket;
};
+TAILQ_HEAD(options, option);
+
#define PG_FILTER_UNKNOWN 0
#define PG_FILTER_NONE 1
#define PG_FILTER_PORTAL 2
@@ -114,6 +116,7 @@ struct portal {
struct portal_group {
TAILQ_ENTRY(portal_group) pg_next;
struct conf *pg_conf;
+ struct options pg_options;
char *pg_name;
struct auth_group *pg_discovery_auth_group;
int pg_discovery_filter;
@@ -152,17 +155,16 @@ struct port {
uint32_t p_ctl_port;
};
-struct lun_option {
- TAILQ_ENTRY(lun_option) lo_next;
- struct lun *lo_lun;
- char *lo_name;
- char *lo_value;
+struct option {
+ TAILQ_ENTRY(option) o_next;
+ char *o_name;
+ char *o_value;
};
struct lun {
TAILQ_ENTRY(lun) l_next;
struct conf *l_conf;
- TAILQ_HEAD(, lun_option) l_options;
+ struct options l_options;
char *l_name;
char *l_backend;
uint8_t l_device_type;
@@ -386,13 +388,11 @@ void lun_set_serial(struct lun *lun, const char *value);
void lun_set_size(struct lun *lun, size_t value);
void lun_set_ctl_lun(struct lun *lun, uint32_t value);
-struct lun_option *lun_option_new(struct lun *lun,
+struct option *option_new(struct options *os,
const char *name, const char *value);
-void lun_option_delete(struct lun_option *clo);
-struct lun_option *lun_option_find(const struct lun *lun,
- const char *name);
-void lun_option_set(struct lun_option *clo,
- const char *value);
+void option_delete(struct options *os, struct option *co);
+struct option *option_find(const struct options *os, const char *name);
+void option_set(struct option *o, const char *value);
void kernel_init(void);
int kernel_lun_add(struct lun *lun);
diff --git a/usr.sbin/ctld/kernel.c b/usr.sbin/ctld/kernel.c
index b9658b5..8f1cefb 100644
--- a/usr.sbin/ctld/kernel.c
+++ b/usr.sbin/ctld/kernel.c
@@ -396,7 +396,7 @@ conf_new_from_kernel(void)
struct pport *pp;
struct port *cp;
struct lun *cl;
- struct lun_option *lo;
+ struct option *o;
struct ctl_lun_list list;
struct cctl_devlist_data devlist;
struct cctl_lun *lun;
@@ -515,15 +515,20 @@ retry_port:
STAILQ_FOREACH(port, &devlist.port_list, links) {
if (strcmp(port->port_frontend, "ha") == 0)
continue;
- if (name)
- free(name);
- if (port->pp == 0 && port->vp == 0)
+ free(name);
+ if (port->pp == 0 && port->vp == 0) {
name = checked_strdup(port->port_name);
- else if (port->vp == 0)
- asprintf(&name, "%s/%d", port->port_name, port->pp);
- else
- asprintf(&name, "%s/%d/%d", port->port_name, port->pp,
- port->vp);
+ } else if (port->vp == 0) {
+ retval = asprintf(&name, "%s/%d",
+ port->port_name, port->pp);
+ if (retval <= 0)
+ log_err(1, "asprintf");
+ } else {
+ retval = asprintf(&name, "%s/%d/%d",
+ port->port_name, port->pp, port->vp);
+ if (retval <= 0)
+ log_err(1, "asprintf");
+ }
if (port->cfiscsi_target == NULL) {
log_debugx("CTL port %u \"%s\" wasn't managed by ctld; ",
@@ -583,8 +588,7 @@ retry_port:
}
cp->p_ctl_port = port->port_id;
}
- if (name)
- free(name);
+ free(name);
STAILQ_FOREACH(lun, &devlist.lun_list, links) {
struct cctl_lun_nv *nv;
@@ -626,8 +630,8 @@ retry_port:
lun_set_path(cl, nv->value);
continue;
}
- lo = lun_option_new(cl, nv->name, nv->value);
- if (lo == NULL)
+ o = option_new(&cl->l_options, nv->name, nv->value);
+ if (o == NULL)
log_warnx("unable to add CTL lun option %s "
"for CTL lun %ju \"%s\"",
nv->name, (uintmax_t) lun->lun_id,
@@ -652,7 +656,7 @@ str_arg(struct ctl_be_arg *arg, const char *name, const char *value)
int
kernel_lun_add(struct lun *lun)
{
- struct lun_option *lo;
+ struct option *o;
struct ctl_lun_req req;
int error, i, num_options;
@@ -687,31 +691,31 @@ kernel_lun_add(struct lun *lun)
}
if (lun->l_path != NULL) {
- lo = lun_option_find(lun, "file");
- if (lo != NULL) {
- lun_option_set(lo, lun->l_path);
+ o = option_find(&lun->l_options, "file");
+ if (o != NULL) {
+ option_set(o, lun->l_path);
} else {
- lo = lun_option_new(lun, "file", lun->l_path);
- assert(lo != NULL);
+ o = option_new(&lun->l_options, "file", lun->l_path);
+ assert(o != NULL);
}
}
- lo = lun_option_find(lun, "ctld_name");
- if (lo != NULL) {
- lun_option_set(lo, lun->l_name);
+ o = option_find(&lun->l_options, "ctld_name");
+ if (o != NULL) {
+ option_set(o, lun->l_name);
} else {
- lo = lun_option_new(lun, "ctld_name", lun->l_name);
- assert(lo != NULL);
+ o = option_new(&lun->l_options, "ctld_name", lun->l_name);
+ assert(o != NULL);
}
- lo = lun_option_find(lun, "scsiname");
- if (lo == NULL && lun->l_scsiname != NULL) {
- lo = lun_option_new(lun, "scsiname", lun->l_scsiname);
- assert(lo != NULL);
+ o = option_find(&lun->l_options, "scsiname");
+ if (o == NULL && lun->l_scsiname != NULL) {
+ o = option_new(&lun->l_options, "scsiname", lun->l_scsiname);
+ assert(o != NULL);
}
num_options = 0;
- TAILQ_FOREACH(lo, &lun->l_options, lo_next)
+ TAILQ_FOREACH(o, &lun->l_options, o_next)
num_options++;
req.num_be_args = num_options;
@@ -724,8 +728,8 @@ kernel_lun_add(struct lun *lun)
}
i = 0;
- TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
- str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
+ TAILQ_FOREACH(o, &lun->l_options, o_next) {
+ str_arg(&req.be_args[i], o->o_name, o->o_value);
i++;
}
assert(i == num_options);
@@ -760,7 +764,7 @@ kernel_lun_add(struct lun *lun)
int
kernel_lun_modify(struct lun *lun)
{
- struct lun_option *lo;
+ struct option *o;
struct ctl_lun_req req;
int error, i, num_options;
@@ -773,7 +777,7 @@ kernel_lun_modify(struct lun *lun)
req.reqdata.modify.lun_size_bytes = lun->l_size;
num_options = 0;
- TAILQ_FOREACH(lo, &lun->l_options, lo_next)
+ TAILQ_FOREACH(o, &lun->l_options, o_next)
num_options++;
req.num_be_args = num_options;
@@ -786,8 +790,8 @@ kernel_lun_modify(struct lun *lun)
}
i = 0;
- TAILQ_FOREACH(lo, &lun->l_options, lo_next) {
- str_arg(&req.be_args[i], lo->lo_name, lo->lo_value);
+ TAILQ_FOREACH(o, &lun->l_options, o_next) {
+ str_arg(&req.be_args[i], o->o_name, o->o_value);
i++;
}
assert(i == num_options);
@@ -945,6 +949,7 @@ kernel_limits(const char *offload, size_t *max_data_segment_length)
int
kernel_port_add(struct port *port)
{
+ struct option *o;
struct ctl_port_entry entry;
struct ctl_req req;
struct ctl_lun_map lm;
@@ -959,6 +964,8 @@ kernel_port_add(struct port *port)
strlcpy(req.driver, "iscsi", sizeof(req.driver));
req.reqtype = CTL_REQ_CREATE;
req.num_args = 5;
+ TAILQ_FOREACH(o, &pg->pg_options, o_next)
+ req.num_args++;
req.args = malloc(req.num_args * sizeof(*req.args));
if (req.args == NULL)
log_err(1, "malloc");
@@ -974,6 +981,8 @@ kernel_port_add(struct port *port)
if (targ->t_alias)
str_arg(&req.args[n++], "cfiscsi_target_alias", targ->t_alias);
str_arg(&req.args[n++], "ctld_portal_group_name", pg->pg_name);
+ TAILQ_FOREACH(o, &pg->pg_options, o_next)
+ str_arg(&req.args[n++], o->o_name, o->o_value);
req.num_args = n;
error = ioctl(ctl_fd, CTL_PORT_REQ, &req);
free(req.args);
diff --git a/usr.sbin/ctld/keys.c b/usr.sbin/ctld/keys.c
index f339a10..c2f1604 100644
--- a/usr.sbin/ctld/keys.c
+++ b/usr.sbin/ctld/keys.c
@@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
#include "ctld.h"
struct keys *
@@ -136,7 +137,7 @@ keys_save(struct keys *keys, struct pdu *pdu)
if (keys->keys_names[i] == NULL)
break;
data += sprintf(data, "%s=%s",
- keys->keys_names[i], keys->keys_values[i]);
+ keys->keys_names[i], keys->keys_values[i]);
data += 1; /* for '\0'. */
}
}
diff --git a/usr.sbin/ctld/parse.y b/usr.sbin/ctld/parse.y
index 03a511f..afbf315 100644
--- a/usr.sbin/ctld/parse.y
+++ b/usr.sbin/ctld/parse.y
@@ -346,6 +346,8 @@ portal_group_entry:
|
portal_group_offload
|
+ portal_group_option
+ |
portal_group_redirect
|
portal_group_tag
@@ -422,6 +424,18 @@ portal_group_offload: OFFLOAD STR
}
;
+portal_group_option: OPTION STR STR
+ {
+ struct option *o;
+
+ o = option_new(&portal_group->pg_options, $2, $3);
+ free($2);
+ free($3);
+ if (o == NULL)
+ return (1);
+ }
+ ;
+
portal_group_redirect: REDIRECT STR
{
int error;
@@ -963,12 +977,12 @@ lun_ctl_lun: CTL_LUN STR
lun_option: OPTION STR STR
{
- struct lun_option *clo;
+ struct option *o;
- clo = lun_option_new(lun, $2, $3);
+ o = option_new(&lun->l_options, $2, $3);
free($2);
free($3);
- if (clo == NULL)
+ if (o == NULL)
return (1);
}
;
diff --git a/usr.sbin/ctm/ctm/ctm.1 b/usr.sbin/ctm/ctm/ctm.1
index 3684b9f..6ba35c9 100644
--- a/usr.sbin/ctm/ctm/ctm.1
+++ b/usr.sbin/ctm/ctm/ctm.1
@@ -12,7 +12,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 25, 1995
+.Dd December 14, 2015
.Dt CTM 1
.Os
.Sh NAME
@@ -303,8 +303,19 @@ and
.Fl V
options.
.Sh SEE ALSO
+.Xr ctm_dequeue 1 ,
.Xr ctm_rmail 1 ,
+.Xr ctm_smail 1 ,
.Xr ctm 5
+.Rs
+.%B "The FreeBSD Handbook"
+.%T "Using CTM"
+.%U http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/ctm.html
+.Re
+.Rs
+.%T "Miscellaneous CTM on FreeBSD Resources"
+.%U http://ctm.berklix.org
+.Re
.Sh HISTORY
Initial trials were run during the work on
.Fx 1.1.5 ,
diff --git a/usr.sbin/dconschat/Makefile.depend b/usr.sbin/dconschat/Makefile.depend
index e2e70c8..442e3ca8 100644
--- a/usr.sbin/dconschat/Makefile.depend
+++ b/usr.sbin/dconschat/Makefile.depend
@@ -10,6 +10,7 @@ DIRDEPS = \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
+ lib/libelf \
lib/libkvm \
diff --git a/usr.sbin/devctl/Makefile.depend b/usr.sbin/devctl/Makefile.depend
new file mode 100644
index 0000000..34e1a91
--- /dev/null
+++ b/usr.sbin/devctl/Makefile.depend
@@ -0,0 +1,19 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libdevctl \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/editmap/Makefile b/usr.sbin/editmap/Makefile
index 20d86ab..23e967f 100644
--- a/usr.sbin/editmap/Makefile
+++ b/usr.sbin/editmap/Makefile
@@ -23,7 +23,7 @@ DPADD+=${SENDMAIL_DPADD}
LDADD+=${SENDMAIL_LDADD}
LDFLAGS+=${SENDMAIL_LDFLAGS}
-sm_os.h:
- ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/editmap/Makefile.depend b/usr.sbin/editmap/Makefile.depend
index afbd086..bc24fb7 100644
--- a/usr.sbin/editmap/Makefile.depend
+++ b/usr.sbin/editmap/Makefile.depend
@@ -12,7 +12,6 @@ DIRDEPS = \
lib/libsm \
lib/libsmdb \
lib/libsmutil \
- lib/libutil \
.include <dirdeps.mk>
diff --git a/usr.sbin/fifolog/lib/Makefile b/usr.sbin/fifolog/lib/Makefile
index fc8e6d2..f60529f 100644
--- a/usr.sbin/fifolog/lib/Makefile
+++ b/usr.sbin/fifolog/lib/Makefile
@@ -7,6 +7,7 @@ SRCS= fifolog_int.c fifolog_create.c fifolog_write_poll.c fifolog_reader.c
SRCS+= getdate.y
CFLAGS+= -I${.CURDIR}
+LIBADD= z
NO_WMISSING_VARIABLE_DECLARATIONS=
diff --git a/usr.sbin/mtree/Makefile b/usr.sbin/fmtree/Makefile
index 6d060e2..6d060e2 100644
--- a/usr.sbin/mtree/Makefile
+++ b/usr.sbin/fmtree/Makefile
diff --git a/usr.sbin/mtree/Makefile.depend b/usr.sbin/fmtree/Makefile.depend
index 064e492..064e492 100644
--- a/usr.sbin/mtree/Makefile.depend
+++ b/usr.sbin/fmtree/Makefile.depend
diff --git a/usr.sbin/mtree/compare.c b/usr.sbin/fmtree/compare.c
index fdd3767..fdd3767 100644
--- a/usr.sbin/mtree/compare.c
+++ b/usr.sbin/fmtree/compare.c
diff --git a/usr.sbin/mtree/create.c b/usr.sbin/fmtree/create.c
index 8be9b02..8be9b02 100644
--- a/usr.sbin/mtree/create.c
+++ b/usr.sbin/fmtree/create.c
diff --git a/usr.sbin/mtree/excludes.c b/usr.sbin/fmtree/excludes.c
index 21a49b0..21a49b0 100644
--- a/usr.sbin/mtree/excludes.c
+++ b/usr.sbin/fmtree/excludes.c
diff --git a/usr.sbin/mtree/extern.h b/usr.sbin/fmtree/extern.h
index 4b6fb3c..4b6fb3c 100644
--- a/usr.sbin/mtree/extern.h
+++ b/usr.sbin/fmtree/extern.h
diff --git a/usr.sbin/mtree/misc.c b/usr.sbin/fmtree/misc.c
index 65667d6..65667d6 100644
--- a/usr.sbin/mtree/misc.c
+++ b/usr.sbin/fmtree/misc.c
diff --git a/usr.sbin/mtree/mtree.8 b/usr.sbin/fmtree/mtree.8
index fd073b9..fd073b9 100644
--- a/usr.sbin/mtree/mtree.8
+++ b/usr.sbin/fmtree/mtree.8
diff --git a/usr.sbin/mtree/mtree.c b/usr.sbin/fmtree/mtree.c
index e90a5bb..e90a5bb 100644
--- a/usr.sbin/mtree/mtree.c
+++ b/usr.sbin/fmtree/mtree.c
diff --git a/usr.sbin/mtree/mtree.h b/usr.sbin/fmtree/mtree.h
index fb22f0d..fb22f0d 100644
--- a/usr.sbin/mtree/mtree.h
+++ b/usr.sbin/fmtree/mtree.h
diff --git a/usr.sbin/mtree/spec.c b/usr.sbin/fmtree/spec.c
index 417932d..417932d 100644
--- a/usr.sbin/mtree/spec.c
+++ b/usr.sbin/fmtree/spec.c
diff --git a/usr.sbin/mtree/specspec.c b/usr.sbin/fmtree/specspec.c
index f85882e..f85882e 100644
--- a/usr.sbin/mtree/specspec.c
+++ b/usr.sbin/fmtree/specspec.c
diff --git a/usr.sbin/mtree/test/test00.sh b/usr.sbin/fmtree/test/test00.sh
index fce801b..fce801b 100644
--- a/usr.sbin/mtree/test/test00.sh
+++ b/usr.sbin/fmtree/test/test00.sh
diff --git a/usr.sbin/mtree/test/test01.sh b/usr.sbin/fmtree/test/test01.sh
index e4d3fc3..e4d3fc3 100644
--- a/usr.sbin/mtree/test/test01.sh
+++ b/usr.sbin/fmtree/test/test01.sh
diff --git a/usr.sbin/mtree/test/test02.sh b/usr.sbin/fmtree/test/test02.sh
index a7aa916..a7aa916 100644
--- a/usr.sbin/mtree/test/test02.sh
+++ b/usr.sbin/fmtree/test/test02.sh
diff --git a/usr.sbin/mtree/test/test03.sh b/usr.sbin/fmtree/test/test03.sh
index bb3a5b5..bb3a5b5 100644
--- a/usr.sbin/mtree/test/test03.sh
+++ b/usr.sbin/fmtree/test/test03.sh
diff --git a/usr.sbin/mtree/test/test04.sh b/usr.sbin/fmtree/test/test04.sh
index 38acda2..38acda2 100644
--- a/usr.sbin/mtree/test/test04.sh
+++ b/usr.sbin/fmtree/test/test04.sh
diff --git a/usr.sbin/mtree/test/test05.sh b/usr.sbin/fmtree/test/test05.sh
index eda544f..eda544f 100644
--- a/usr.sbin/mtree/test/test05.sh
+++ b/usr.sbin/fmtree/test/test05.sh
diff --git a/usr.sbin/mtree/verify.c b/usr.sbin/fmtree/verify.c
index c9291c0..c9291c0 100644
--- a/usr.sbin/mtree/verify.c
+++ b/usr.sbin/fmtree/verify.c
diff --git a/usr.sbin/fstyp/Makefile b/usr.sbin/fstyp/Makefile
index bd981df..5eba12b 100644
--- a/usr.sbin/fstyp/Makefile
+++ b/usr.sbin/fstyp/Makefile
@@ -19,6 +19,8 @@ WARNS?= 2
SUBDIR+= tests
.endif
+CFLAGS+=-I${.CURDIR}/../../sys
+
.if ${MK_ZFS} != "no"
IGNORE_PRAGMA= YES
@@ -34,14 +36,10 @@ CFLAGS+= -I${.CURDIR}/../../sys/cddl/contrib/opensolaris/uts/common/sys
CFLAGS+= -I${.CURDIR}/../../cddl/contrib/opensolaris/head
.endif
-CFLAGS+=-I${.CURDIR}/../../sys
-
-DPADD= ${LIBGEOM} ${LIBMD}
-LDADD= -lgeom -lmd
+LIBADD= geom md
.if ${MK_ZFS} != "no"
-DPADD += ${LIBNVPAIR} ${LIBZFS}
-LDADD += -lnvpair -lzfs
+LIBADD+=nvpair zfs
.endif
.include <bsd.prog.mk>
diff --git a/usr.sbin/fstyp/Makefile.depend b/usr.sbin/fstyp/Makefile.depend
new file mode 100644
index 0000000..b1a2eff
--- /dev/null
+++ b/usr.sbin/fstyp/Makefile.depend
@@ -0,0 +1,32 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ cddl/lib/libavl \
+ cddl/lib/libnvpair \
+ cddl/lib/libumem \
+ cddl/lib/libuutil \
+ cddl/lib/libzfs \
+ cddl/lib/libzfs_core \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libexpat \
+ lib/libgeom \
+ lib/libmd \
+ lib/libsbuf \
+ lib/libthr \
+ lib/libutil \
+ lib/libz \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/fstyp/fstyp.c b/usr.sbin/fstyp/fstyp.c
index cd0bbf9..cde179f 100644
--- a/usr.sbin/fstyp/fstyp.c
+++ b/usr.sbin/fstyp/fstyp.c
@@ -39,7 +39,6 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.sbin/fstyp/geli.c b/usr.sbin/fstyp/geli.c
index 7f6d9a5..59e8653 100644
--- a/usr.sbin/fstyp/geli.c
+++ b/usr.sbin/fstyp/geli.c
@@ -29,11 +29,9 @@ __FBSDID("$FreeBSD$");
#include <sys/disk.h>
#include <sys/types.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
#include <geom/eli/g_eli.h>
diff --git a/usr.sbin/fstyp/zfs.c b/usr.sbin/fstyp/zfs.c
index 1c9ca4d..c37a5db 100644
--- a/usr.sbin/fstyp/zfs.c
+++ b/usr.sbin/fstyp/zfs.c
@@ -29,6 +29,9 @@
__FBSDID("$FreeBSD$");
#include <sys/types.h>
+#include <cddl/compat/opensolaris/sys/types.h>
+#include <sys/time.h>
+#include <cddl/compat/opensolaris/sys/time.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/usr.sbin/ftp-proxy/Makefile.depend b/usr.sbin/ftp-proxy/Makefile.depend
new file mode 100644
index 0000000..c02eb2d
--- /dev/null
+++ b/usr.sbin/ftp-proxy/Makefile.depend
@@ -0,0 +1,20 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libevent \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/fwcontrol/fwmpegts.c b/usr.sbin/fwcontrol/fwmpegts.c
index 4f84789..ae9a52b 100644
--- a/usr.sbin/fwcontrol/fwmpegts.c
+++ b/usr.sbin/fwcontrol/fwmpegts.c
@@ -119,7 +119,7 @@ bandwidth (R):
2) 1.5 < R < 3 Mbps: db0/db1 or db2/db3 or db4/db5 or db6/db7 is payload,
3) 3 < R < 6 Mbps: db0/db1/db2/db3 or db4/db5/db6/db7 is payload,
4) R > 6 Mbps: all db0..db7 contain the payload.
-Curently, only case (4) is supported in fwmpegts.c
+Currently, only case (4) is supported in fwmpegts.c
Each packet may contain N MPEG TS data blocks with timestamp header,
which are (4+188)B long. Experimentally, the N ranges from 0 through 3.
diff --git a/usr.sbin/gssd/gssd.c b/usr.sbin/gssd/gssd.c
index e85dfd7..f3e5ce9 100644
--- a/usr.sbin/gssd/gssd.c
+++ b/usr.sbin/gssd/gssd.c
@@ -254,6 +254,7 @@ main(int argc, char **argv)
gssd_syscall(_PATH_GSSDSOCK);
svc_run();
+ gssd_syscall("");
return (0);
}
@@ -1285,6 +1286,7 @@ void gssd_terminate(int sig __unused)
if (hostbased_initiator_cred != 0)
unlink(GSSD_CREDENTIAL_CACHE_FILE);
#endif
+ gssd_syscall("");
exit(0);
}
diff --git a/usr.sbin/gstat/Makefile.depend b/usr.sbin/gstat/Makefile.depend
index c24e161..c8fd534 100644
--- a/usr.sbin/gstat/Makefile.depend
+++ b/usr.sbin/gstat/Makefile.depend
@@ -11,6 +11,7 @@ DIRDEPS = \
lib/libcompiler_rt \
lib/libdevstat \
lib/libedit \
+ lib/libelf \
lib/libexpat \
lib/libgeom \
lib/libkvm \
diff --git a/usr.sbin/hyperv/tools/Makefile.depend b/usr.sbin/hyperv/tools/Makefile.depend
new file mode 100644
index 0000000..54c1f6f
--- /dev/null
+++ b/usr.sbin/hyperv/tools/Makefile.depend
@@ -0,0 +1,19 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/iostat/Makefile.depend b/usr.sbin/iostat/Makefile.depend
index bfcafb7..ca404f2 100644
--- a/usr.sbin/iostat/Makefile.depend
+++ b/usr.sbin/iostat/Makefile.depend
@@ -10,6 +10,7 @@ DIRDEPS = \
lib/libc \
lib/libcompiler_rt \
lib/libdevstat \
+ lib/libelf \
lib/libkvm \
lib/msun \
diff --git a/usr.sbin/iostat/iostat.c b/usr.sbin/iostat/iostat.c
index 195e59c..170ce0d 100644
--- a/usr.sbin/iostat/iostat.c
+++ b/usr.sbin/iostat/iostat.c
@@ -110,6 +110,7 @@
#include <limits.h>
#include <math.h>
#include <nlist.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -135,6 +136,8 @@ struct device_selection *dev_select;
int maxshowdevs;
volatile sig_atomic_t headercount;
volatile sig_atomic_t wresized; /* Tty resized, when non-zero. */
+volatile sig_atomic_t alarm_rang;
+volatile sig_atomic_t return_requested;
unsigned short wrows; /* Current number of tty rows. */
int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
int xflag = 0, zflag = 0;
@@ -143,6 +146,8 @@ int xflag = 0, zflag = 0;
static void usage(void);
static void needhdr(int signo);
static void needresize(int signo);
+static void needreturn(int signo);
+static void alarm_clock(int signo);
static void doresize(void);
static void phdr(void);
static void devstats(int perf_select, long double etime, int havelast);
@@ -172,6 +177,7 @@ main(int argc, char **argv)
int count = 0, waittime = 0;
char *memf = NULL, *nlistf = NULL;
struct devstat_match *matches;
+ struct itimerval alarmspec;
int num_matches = 0;
char errbuf[_POSIX2_LINE_MAX];
kvm_t *kd = NULL;
@@ -442,10 +448,28 @@ main(int argc, char **argv)
wrows = IOSTAT_DEFAULT_ROWS;
}
+ /*
+ * Register a SIGINT handler so that we can print out final statistics
+ * when we get that signal
+ */
+ (void)signal(SIGINT, needreturn);
+
+ /*
+ * Register a SIGALRM handler to implement sleeps if the user uses the
+ * -c or -w options
+ */
+ (void)signal(SIGALRM, alarm_clock);
+ alarmspec.it_interval.tv_sec = waittime / 1000;
+ alarmspec.it_interval.tv_usec = 1000 * (waittime % 1000);
+ alarmspec.it_value.tv_sec = waittime / 1000;
+ alarmspec.it_value.tv_usec = 1000 * (waittime % 1000);
+ setitimer(ITIMER_REAL, &alarmspec, NULL);
+
for (headercount = 1;;) {
struct devinfo *tmp_dinfo;
long tmp;
long double etime;
+ sigset_t sigmask, oldsigmask;
if (Tflag > 0) {
if ((readvar(kd, "kern.tty_nin", X_TTY_NIN, &cur.tk_nin,
@@ -599,10 +623,23 @@ main(int argc, char **argv)
}
fflush(stdout);
- if (count >= 0 && --count <= 0)
+ if ((count >= 0 && --count <= 0) || return_requested)
break;
- usleep(waittime * 1000);
+ /*
+ * Use sigsuspend to safely sleep until either signal is
+ * received
+ */
+ alarm_rang = 0;
+ sigemptyset(&sigmask);
+ sigaddset(&sigmask, SIGINT);
+ sigaddset(&sigmask, SIGALRM);
+ sigprocmask(SIG_BLOCK, &sigmask, &oldsigmask);
+ while (! (alarm_rang || return_requested) ) {
+ sigsuspend(&oldsigmask);
+ }
+ sigprocmask(SIG_UNBLOCK, &sigmask, NULL);
+
havelast = 1;
}
@@ -633,6 +670,24 @@ needresize(int signo)
}
/*
+ * Record the alarm so the main loop can break its sleep
+ */
+void
+alarm_clock(int signo)
+{
+ alarm_rang = 1;
+}
+
+/*
+ * Request that the main loop exit soon
+ */
+void
+needreturn(int signo)
+{
+ return_requested = 1;
+}
+
+/*
* Update the global `wrows' count of terminal rows.
*/
void
diff --git a/usr.sbin/iovctl/Makefile.depend b/usr.sbin/iovctl/Makefile.depend
new file mode 100644
index 0000000..d883529
--- /dev/null
+++ b/usr.sbin/iovctl/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libnv \
+ lib/libucl \
+ lib/msun \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/iscsid/Makefile.depend b/usr.sbin/iscsid/Makefile.depend
new file mode 100644
index 0000000..023ec43
--- /dev/null
+++ b/usr.sbin/iscsid/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libmd \
+ lib/libutil \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/iscsid/keys.c b/usr.sbin/iscsid/keys.c
index c4b478b..8ac4788 100644
--- a/usr.sbin/iscsid/keys.c
+++ b/usr.sbin/iscsid/keys.c
@@ -32,7 +32,6 @@
__FBSDID("$FreeBSD$");
#include <assert.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/usr.sbin/iscsid/pdu.c b/usr.sbin/iscsid/pdu.c
index b5a8cc0..4672ecd 100644
--- a/usr.sbin/iscsid/pdu.c
+++ b/usr.sbin/iscsid/pdu.c
@@ -34,7 +34,6 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
-#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
diff --git a/usr.sbin/jail/Makefile.depend b/usr.sbin/jail/Makefile.depend
index 28c1ed0..b24d6ea4 100644
--- a/usr.sbin/jail/Makefile.depend
+++ b/usr.sbin/jail/Makefile.depend
@@ -10,6 +10,7 @@ DIRDEPS = \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
+ lib/libelf \
lib/libjail \
lib/libkvm \
lib/libutil \
diff --git a/usr.sbin/jail/command.c b/usr.sbin/jail/command.c
index f6f9db3..f162c3c 100644
--- a/usr.sbin/jail/command.c
+++ b/usr.sbin/jail/command.c
@@ -761,7 +761,7 @@ add_proc(struct cfjail *j, pid_t pid)
if (j->timeout.tv_sec == 0)
requeue(j, &sleeping);
else {
- /* File the jail in the sleep queue acording to its timeout. */
+ /* File the jail in the sleep queue according to its timeout. */
TAILQ_REMOVE(j->queue, j, tq);
TAILQ_FOREACH(tj, &sleeping, tq) {
if (!tj->timeout.tv_sec ||
diff --git a/usr.sbin/jail/jailp.h b/usr.sbin/jail/jailp.h
index d2c929e..4498f4b 100644
--- a/usr.sbin/jail/jailp.h
+++ b/usr.sbin/jail/jailp.h
@@ -41,7 +41,7 @@
#define DF_SEEN 0x01 /* Dependency has been followed */
#define DF_LIGHT 0x02 /* Implied dependency on jail existence only */
-#define DF_NOFAIL 0x04 /* Don't propigate failed jails */
+#define DF_NOFAIL 0x04 /* Don't propagate failed jails */
#define PF_VAR 0x01 /* This is a variable, not a true parameter */
#define PF_APPEND 0x02 /* Append to existing parameter list */
diff --git a/usr.sbin/jail/jailparse.y b/usr.sbin/jail/jailparse.y
index 2df337f..d085eb8 100644
--- a/usr.sbin/jail/jailparse.y
+++ b/usr.sbin/jail/jailparse.y
@@ -103,7 +103,7 @@ param_l :
/*
* Parameters have a name and an optional list of value strings,
- * which may have "+=" or "=" preceeding them.
+ * which may have "+=" or "=" preceding them.
*/
param : name
{
diff --git a/usr.sbin/jls/Makefile b/usr.sbin/jls/Makefile
index d90d094..4c1de74 100644
--- a/usr.sbin/jls/Makefile
+++ b/usr.sbin/jls/Makefile
@@ -4,7 +4,7 @@
PROG= jls
MAN= jls.8
-LIBADD= jail
+LIBADD= jail xo
.if ${MK_INET6_SUPPORT} != "no"
CFLAGS+= -DINET6
diff --git a/usr.sbin/jls/jls.8 b/usr.sbin/jls/jls.8
index 15a80d4..3b83d73 100644
--- a/usr.sbin/jls/jls.8
+++ b/usr.sbin/jls/jls.8
@@ -33,6 +33,7 @@
.Nd "list jails"
.Sh SYNOPSIS
.Nm
+.Op Fl -libxo
.Op Fl dhNnqsv
.Op Fl j Ar jail
.Op Ar parameter ...
@@ -62,6 +63,13 @@ and path (path).
.Pp
The following options are available:
.Bl -tag -width indent
+.It Fl -libxo
+Generate output via
+.Xr libxo 3
+in a selection of different human and machine readable formats.
+See
+.Xr xo_parse_args 3
+for details on command line arguments.
.It Fl d
List
.Va dying
@@ -106,7 +114,9 @@ Without this option, all active jails will be listed.
.Sh SEE ALSO
.Xr jail_get 2 ,
.Xr jail 8 ,
-.Xr jexec 8
+.Xr jexec 8 ,
+.Xr libxo 3 ,
+.Xr xo_parse_args 3
.Sh HISTORY
The
.Nm
@@ -114,3 +124,5 @@ utility was added in
.Fx 5.1 .
Extensible jail parameters were introduced in
.Fx 8.0 .
+libxo support was added in
+.Fx 11.0 .
diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c
index b1e28fb..9dd7641 100644
--- a/usr.sbin/jls/jls.c
+++ b/usr.sbin/jls/jls.c
@@ -2,6 +2,7 @@
* Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
* Copyright (c) 2008 Bjoern A. Zeeb <bz@FreeBSD.org>
* Copyright (c) 2009 James Gritton <jamie@FreeBSD.org>
+ * Copyright (c) 2015 Emmanuel Vadot <manu@bocal.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,10 +46,13 @@ __FBSDID("$FreeBSD$");
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <libxo/xo.h>
#define JP_USER 0x01000000
#define JP_OPT 0x02000000
+#define JLS_XO_VERSION "1"
+
#define PRINT_DEFAULT 0x01
#define PRINT_HEADER 0x02
#define PRINT_NAMEVAL 0x04
@@ -73,7 +77,7 @@ static int sort_param(const void *a, const void *b);
static char *noname(const char *name);
static char *nononame(const char *name);
static int print_jail(int pflags, int jflags);
-static void quoted_print(char *str);
+static void quoted_print(int pflags, char *name, char *value);
int
main(int argc, char **argv)
@@ -81,6 +85,11 @@ main(int argc, char **argv)
char *dot, *ep, *jname, *pname;
int c, i, jflags, jid, lastjid, pflags, spc;
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ exit(1);
+
+ xo_set_version(JLS_XO_VERSION);
jname = NULL;
pflags = jflags = jid = 0;
while ((c = getopt(argc, argv, "adj:hNnqsv")) >= 0)
@@ -119,7 +128,7 @@ main(int argc, char **argv)
PRINT_VERBOSE;
break;
default:
- errx(1, "usage: jls [-dhNnqv] [-j jail] [param ...]");
+ xo_errx(1, "usage: jls [-dhNnqv] [-j jail] [param ...]");
}
#ifdef INET6
@@ -196,42 +205,48 @@ main(int argc, char **argv)
add_param("lastjid", &lastjid, sizeof(lastjid), NULL, 0);
/* Print a header line if requested. */
- if (pflags & PRINT_VERBOSE)
- printf(" JID Hostname Path\n"
- " Name State\n"
- " CPUSetID\n"
- " IP Address(es)\n");
+ if (pflags & PRINT_VERBOSE) {
+ xo_emit("{T:/%3s}{T:JID}{P: }{T:Hostname}{Pd:/%22s}{T:Path}\n",
+ "", "");
+ xo_emit("{P:/%8s}{T:Name}{Pd:/%26s}{T:State}\n", "", "");
+ xo_emit("{P:/%8s}{T:CPUSetID}\n", "");
+ xo_emit("{P:/%8s}{T:IP Address(es)}\n", "");
+ }
else if (pflags & PRINT_DEFAULT)
if (pflags & PRINT_JAIL_NAME)
- printf(" JID IP Address "
- "Hostname Path\n");
+ xo_emit("{P: }{T:JID/%-15s}{P: }{T:IP Address/%-15s}"
+ "{P: }{T:Hostname/%-29s}{P: }{T:Path}\n");
else
- printf(" JID IP Address "
- "Hostname Path\n");
+ xo_emit("{T:JID/%6s}{P: }{T:IP Address}{P:/%6s}"
+ "{T:Hostname}{P:/%22s}{T:Path}\n", "", "");
else if (pflags & PRINT_HEADER) {
for (i = spc = 0; i < nparams; i++)
if (params[i].jp_flags & JP_USER) {
if (spc)
- putchar(' ');
+ xo_emit("{P: }");
else
spc = 1;
- fputs(params[i].jp_name, stdout);
+ xo_emit(params[i].jp_name);
}
- putchar('\n');
+ xo_emit("{P:\n}");
}
- /* Fetch the jail(s) and print the paramters. */
+ xo_open_container("jail-information");
+ xo_open_list("jail");
+ /* Fetch the jail(s) and print the parameters. */
if (jid != 0 || jname != NULL) {
if (print_jail(pflags, jflags) < 0)
- errx(1, "%s", jail_errmsg);
+ xo_errx(1, "%s", jail_errmsg);
} else {
for (lastjid = 0;
(lastjid = print_jail(pflags, jflags)) >= 0; )
;
if (errno != 0 && errno != ENOENT)
- errx(1, "%s", jail_errmsg);
+ xo_errx(1, "%s", jail_errmsg);
}
-
+ xo_close_list("jail");
+ xo_close_container("jail-information");
+ xo_finish();
return (0);
}
@@ -248,7 +263,7 @@ add_param(const char *name, void *value, size_t valuelen,
if (!strcmp(name, "all")) {
tnparams = jailparam_all(&tparams);
if (tnparams < 0)
- errx(1, "%s", jail_errmsg);
+ xo_errx(1, "%s", jail_errmsg);
qsort(tparams, (size_t)tnparams, sizeof(struct jailparam),
sort_param);
for (i = 0; i < tnparams; i++)
@@ -263,7 +278,7 @@ add_param(const char *name, void *value, size_t valuelen,
if (!strcmp(name, params[i].jp_name)) {
if (value != NULL && jailparam_import_raw(params + i,
value, valuelen) < 0)
- errx(1, "%s", jail_errmsg);
+ xo_errx(1, "%s", jail_errmsg);
params[i].jp_flags |= flags;
if (source != NULL)
jailparam_free(source, 1);
@@ -276,14 +291,14 @@ add_param(const char *name, void *value, size_t valuelen,
params = malloc(paramlistsize * sizeof(*params));
param_parent = malloc(paramlistsize * sizeof(*param_parent));
if (params == NULL || param_parent == NULL)
- err(1, "malloc");
+ xo_err(1, "malloc");
} else if (nparams >= paramlistsize) {
paramlistsize *= 2;
params = realloc(params, paramlistsize * sizeof(*params));
param_parent = realloc(param_parent,
paramlistsize * sizeof(*param_parent));
if (params == NULL || param_parent == NULL)
- err(1, "realloc");
+ xo_err(1, "realloc");
}
/* Look up the parameter. */
@@ -301,7 +316,7 @@ add_param(const char *name, void *value, size_t valuelen,
nparams--;
return (-1);
}
- errx(1, "%s", jail_errmsg);
+ xo_errx(1, "%s", jail_errmsg);
}
param->jp_flags = flags;
return param - params;
@@ -332,7 +347,7 @@ noname(const char *name)
nname = malloc(strlen(name) + 3);
if (nname == NULL)
- err(1, "malloc");
+ xo_err(1, "malloc");
p = strrchr(name, '.');
if (p != NULL)
sprintf(nname, "%.*s.no%s", (int)(p - name), name, p + 1);
@@ -351,7 +366,7 @@ nononame(const char *name)
return NULL;
nname = malloc(strlen(name) - 1);
if (nname == NULL)
- err(1, "malloc");
+ xo_err(1, "malloc");
if (p != NULL)
sprintf(nname, "%.*s.%s", (int)(p - name), name, p + 3);
else
@@ -362,7 +377,7 @@ nononame(const char *name)
static int
print_jail(int pflags, int jflags)
{
- char *nname;
+ char *nname, *xo_nname;
char **param_values;
int i, ai, jid, count, n, spc;
char ipbuf[INET6_ADDRSTRLEN];
@@ -370,18 +385,19 @@ print_jail(int pflags, int jflags)
jid = jailparam_get(params, nparams, jflags);
if (jid < 0)
return jid;
+
+ xo_open_instance("jail");
+
if (pflags & PRINT_VERBOSE) {
- printf("%6d %-29.29s %.74s\n"
- "%6s %-29.29s %.74s\n"
- "%6s %-6d\n",
+ xo_emit("{:jid/%6d}{P: }{:hostname/%-29.29s/%s}{P: }"
+ "{:path/%.74s/%s}\n",
*(int *)params[0].jp_value,
(char *)params[1].jp_value,
- (char *)params[2].jp_value,
- "",
+ (char *)params[2].jp_value);
+ xo_emit("{P: }{:name/%-29.29s/%s}{P: }{:state/%.74s}\n",
(char *)params[3].jp_value,
- *(int *)params[4].jp_value ? "DYING" : "ACTIVE",
- "",
- *(int *)params[5].jp_value);
+ *(int *)params[4].jp_value ? "DYING" : "ACTIVE");
+ xo_emit("{P: }{:cpusetid/%d}\n", *(int *)params[5].jp_value);
n = 6;
#ifdef INET
if (ip4_ok && !strcmp(params[n].jp_name, "ip4.addr")) {
@@ -390,9 +406,10 @@ print_jail(int pflags, int jflags)
if (inet_ntop(AF_INET,
&((struct in_addr *)params[n].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
- err(1, "inet_ntop");
- else
- printf("%6s %-15.15s\n", "", ipbuf);
+ xo_err(1, "inet_ntop");
+ else {
+ xo_emit("{P: }{l:ipv4_addrs}{P:\n}", ipbuf);
+ }
n++;
}
#endif
@@ -404,20 +421,21 @@ print_jail(int pflags, int jflags)
&((struct in6_addr *)
params[n].jp_value)[ai],
ipbuf, sizeof(ipbuf)) == NULL)
- err(1, "inet_ntop");
+ xo_err(1, "inet_ntop");
else
- printf("%6s %s\n", "", ipbuf);
+ xo_emit("{P: }{l:ipv6_addrs}{P:\n}", ipbuf);
n++;
}
#endif
} else if (pflags & PRINT_DEFAULT) {
if (pflags & PRINT_JAIL_NAME)
- printf(" %-15s ", (char *)params[0].jp_value);
+ xo_emit("{P: }{:name/%-15s/%s}{P: }",
+ (char *)params[0].jp_value);
else
- printf("%6d ", *(int *)params[0].jp_value);
- printf("%-15.15s %-29.29s %.74s\n",
+ xo_emit("{:jid/%6d}{P: }", *(int *)params[0].jp_value);
+ xo_emit("{:ipv4/%-15.15s/%s}{P: }{:hostname/%-29.29s/%s}{P: }{:path/%.74s/%s}\n",
#ifdef INET
- (!ip4_ok || params[1].jp_valuelen == 0) ? "-"
+ (!ip4_ok || params[1].jp_valuelen == 0) ? ""
: inet_ntoa(*(struct in_addr *)params[1].jp_value),
(char *)params[2-!ip4_ok].jp_value,
(char *)params[3-!ip4_ok].jp_value);
@@ -433,7 +451,7 @@ print_jail(int pflags, int jflags)
continue;
param_values[i] = jailparam_export(params + i);
if (param_values[i] == NULL)
- errx(1, "%s", jail_errmsg);
+ xo_errx(1, "%s", jail_errmsg);
}
for (i = spc = 0; i < nparams; i++) {
if (!(params[i].jp_flags & JP_USER))
@@ -446,7 +464,7 @@ print_jail(int pflags, int jflags)
JAIL_SYS_NEW)))
continue;
if (spc)
- putchar(' ');
+ xo_emit("{P: }");
else
spc = 1;
if (pflags & PRINT_NAMEVAL) {
@@ -456,63 +474,82 @@ print_jail(int pflags, int jflags)
*/
if (params[i].jp_flags &
(JP_BOOL | JP_NOBOOL)) {
- if (*(int *)params[i].jp_value)
- printf("%s", params[i].jp_name);
+ if (*(int *)params[i].jp_value) {
+ asprintf(&xo_nname, "{en:%s/true}", params[i].jp_name);
+ xo_emit(xo_nname);
+ xo_emit("{d:/%s}", params[i].jp_name);
+ }
else {
nname = (params[i].jp_flags &
JP_NOBOOL) ?
nononame(params[i].jp_name)
: noname(params[i].jp_name);
- printf("%s", nname);
+ if (params[i].jp_flags & JP_NOBOOL) {
+ asprintf(&xo_nname, "{en:%s/true}", params[i].jp_name);
+ xo_emit(xo_nname);
+ } else {
+ asprintf(&xo_nname, "{en:%s/false}", params[i].jp_name);
+ xo_emit(xo_nname);
+ }
+ xo_emit("{d:/%s}", nname);
free(nname);
}
+ free(xo_nname);
continue;
}
- printf("%s=", params[i].jp_name);
+ xo_emit("{d:%s}=", params[i].jp_name);
}
if (params[i].jp_valuelen == 0) {
if (pflags & PRINT_QUOTED)
- printf("\"\"");
+ xo_emit("{P:\"\"}");
else if (!(pflags & PRINT_NAMEVAL))
- putchar('-');
- } else
- quoted_print(param_values[i]);
+ xo_emit("{P:-}");
+ } else {
+ quoted_print(pflags, params[i].jp_name, param_values[i]);
+ }
}
- putchar('\n');
+ xo_emit("{P:\n}");
for (i = 0; i < nparams; i++)
if (params[i].jp_flags & JP_USER)
free(param_values[i]);
}
+
+ xo_close_instance("jail");
return (jid);
}
static void
-quoted_print(char *str)
+quoted_print(int pflags, char *name, char *value)
{
- int c, qc;
- char *p = str;
+ int qc;
+ char *p = value;
+ char *param_name_value;
/* An empty string needs quoting. */
if (!*p) {
- fputs("\"\"", stdout);
+ asprintf(&param_name_value, "{k:%s}{d:%s/\"\"}", name, name);
+ xo_emit(param_name_value);
+ free(param_name_value);
return;
}
+ asprintf(&param_name_value, "{:%s/%%s}", name);
/*
* The value will be surrounded by quotes if it contains spaces
* or quotes.
*/
qc = strchr(p, '\'') ? '"'
- : strchr(p, '"') ? '\''
- : strchr(p, ' ') || strchr(p, '\t') ? '"'
- : 0;
- if (qc)
- putchar(qc);
- while ((c = *p++)) {
- if (c == '\\' || c == qc)
- putchar('\\');
- putchar(c);
- }
- if (qc)
- putchar(qc);
+ : strchr(p, '"') ? '\''
+ : strchr(p, ' ') || strchr(p, '\t') ? '"'
+ : 0;
+
+ if (qc && pflags & PRINT_QUOTED)
+ xo_emit("{P:/%c}", qc);
+
+ xo_emit(param_name_value, value);
+
+ free(param_name_value);
+
+ if (qc && pflags & PRINT_QUOTED)
+ xo_emit("{P:/%c}", qc);
}
diff --git a/usr.sbin/kbdcontrol/kbdmap.5 b/usr.sbin/kbdcontrol/kbdmap.5
index c7f437a..fda2ada 100644
--- a/usr.sbin/kbdcontrol/kbdmap.5
+++ b/usr.sbin/kbdcontrol/kbdmap.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd January 29, 2008
+.Dd January 2, 2016
.Dt KBDMAP 5
.Os
.Sh NAME
@@ -111,9 +111,9 @@ ack,
bel,
bs,
ht,
-nl,
+lf,
vt,
-np,
+ff,
cr,
so,
si,
@@ -132,10 +132,16 @@ esc,
fs,
gs,
rs,
-ns,
us,
sp,
del.
+.It Ar control-alias
+One of the historical aliases for certain
+.Tn ASCII
+control characters:
+nl,
+np,
+ns.
.It Ar accentname
By giving one of the accent names,
the next key pressed will produce
diff --git a/usr.sbin/kbdmap/kbdmap.c b/usr.sbin/kbdmap/kbdmap.c
index 08c0d77..0670d1b 100644
--- a/usr.sbin/kbdmap/kbdmap.c
+++ b/usr.sbin/kbdmap/kbdmap.c
@@ -57,6 +57,7 @@ static const char *dir;
static const char *menu = "";
static int x11;
+static int using_vt;
static int show;
static int verbose;
static int print;
@@ -150,7 +151,7 @@ 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)
+check_vt(void)
{
size_t len;
char term[3];
@@ -159,7 +160,7 @@ check_newcons(void)
if (sysctlbyname("kern.vty", &term, &len, NULL, 0) != 0 ||
strcmp(term, "vt") != 0)
return 0;
- return -1;
+ return 1;
}
/*
@@ -256,7 +257,7 @@ get_font(void)
static void
vidcontrol(const char *fnt)
{
- char *tmp, *p, *q;
+ char *tmp, *p, *q, *cmd;
char ch;
int i;
@@ -264,6 +265,13 @@ vidcontrol(const char *fnt)
if (x11)
return;
+ if (using_vt) {
+ asprintf(&cmd, "vidcontrol -f %s", fnt);
+ system(cmd);
+ free(cmd);
+ return;
+ }
+
tmp = strdup(fnt);
/* Extract font size */
@@ -281,7 +289,6 @@ vidcontrol(const char *fnt)
if (sscanf(p, "%dx%d%c", &i, &i, &ch) != 2)
fprintf(stderr, "Which font size? %s\n", fnt);
else {
- char *cmd;
asprintf(&cmd, "vidcontrol -f %s %s", p, fnt);
if (verbose)
fprintf(stderr, "%s\n", cmd);
@@ -685,7 +692,7 @@ menu_read(void)
fclose(fp);
} else
- printf("Could not open file\n");
+ fprintf(stderr, "Could not open %s for reading\n", filename);
if (show) {
qsort(lang_list->sl_str, lang_list->sl_cur, sizeof(char*),
@@ -832,7 +839,8 @@ main(int argc, char **argv)
sleep(2);
}
- if (check_newcons() == 0) {
+ using_vt = check_vt();
+ if (using_vt == 0) {
keymapdir = DEFAULT_SC_KEYMAP_DIR;
fontdir = DEFAULT_SC_FONT_DIR;
font_default = DEFAULT_SC_FONT;
diff --git a/usr.sbin/kgmon/Makefile.depend b/usr.sbin/kgmon/Makefile.depend
index a1ac545..34582cd 100644
--- a/usr.sbin/kgmon/Makefile.depend
+++ b/usr.sbin/kgmon/Makefile.depend
@@ -9,6 +9,7 @@ DIRDEPS = \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
+ lib/libelf \
lib/libkvm \
diff --git a/usr.sbin/kldxref/kldxref.c b/usr.sbin/kldxref/kldxref.c
index 1e81801..01b7c65 100644
--- a/usr.sbin/kldxref/kldxref.c
+++ b/usr.sbin/kldxref/kldxref.c
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/param.h>
+#include <sys/endian.h>
#include <sys/exec.h>
#include <sys/queue.h>
#include <sys/kernel.h>
@@ -53,7 +54,7 @@
#include "ef.h"
-#define MAXRECSIZE 8192
+#define MAXRECSIZE (64 << 10) /* 64k */
#define check(val) if ((error = (val)) != 0) break
static int dflag; /* do not create a hint file, only write on stdout */
@@ -134,14 +135,244 @@ record_string(const char *str)
return record_buf(str, len);
}
+/* From sys/isa/pnp.c */
+static char *
+pnp_eisaformat(uint32_t id)
+{
+ uint8_t *data;
+ static char idbuf[8];
+ const char hextoascii[] = "0123456789abcdef";
+
+ id = htole32(id);
+ data = (uint8_t *)&id;
+ idbuf[0] = '@' + ((data[0] & 0x7c) >> 2);
+ idbuf[1] = '@' + (((data[0] & 0x3) << 3) + ((data[1] & 0xe0) >> 5));
+ idbuf[2] = '@' + (data[1] & 0x1f);
+ idbuf[3] = hextoascii[(data[2] >> 4)];
+ idbuf[4] = hextoascii[(data[2] & 0xf)];
+ idbuf[5] = hextoascii[(data[3] >> 4)];
+ idbuf[6] = hextoascii[(data[3] & 0xf)];
+ idbuf[7] = 0;
+ return(idbuf);
+}
+
+struct pnp_elt
+{
+ int pe_kind; /* What kind of entry */
+#define TYPE_SZ_MASK 0x0f
+#define TYPE_FLAGGED 0x10 /* all f's is a wildcard */
+#define TYPE_INT 0x20 /* Is a number */
+#define TYPE_PAIRED 0x40
+#define TYPE_LE 0x80 /* Matches <= this value */
+#define TYPE_GE 0x100 /* Matches >= this value */
+#define TYPE_MASK 0x200 /* Specifies a mask to follow */
+#define TYPE_U8 (1 | TYPE_INT)
+#define TYPE_V8 (1 | TYPE_INT | TYPE_FLAGGED)
+#define TYPE_G16 (2 | TYPE_INT | TYPE_GE)
+#define TYPE_L16 (2 | TYPE_INT | TYPE_LE)
+#define TYPE_M16 (2 | TYPE_INT | TYPE_MASK)
+#define TYPE_U16 (2 | TYPE_INT)
+#define TYPE_V16 (2 | TYPE_INT | TYPE_FLAGGED)
+#define TYPE_U32 (4 | TYPE_INT)
+#define TYPE_V32 (4 | TYPE_INT | TYPE_FLAGGED)
+#define TYPE_W32 (4 | TYPE_INT | TYPE_PAIRED)
+#define TYPE_D 7
+#define TYPE_Z 8
+#define TYPE_P 9
+#define TYPE_E 10
+#define TYPE_T 11
+ int pe_offset; /* Offset within the element */
+ char * pe_key; /* pnp key name */
+ TAILQ_ENTRY(pnp_elt) next; /* Link */
+};
+typedef TAILQ_HEAD(pnp_head, pnp_elt) pnp_list;
+
+/*
+ * this function finds the data from the pnp table, as described by the
+ * the description and creates a new output (new_desc). This output table
+ * is a form that's easier for the agent that's automatically loading the
+ * modules.
+ *
+ * The format output is the simplified string from this routine in the
+ * same basic format as the pnp string, as documented in sys/module.h.
+ * First a string describing the format is output, the a count of the
+ * number of records, then each record. The format string also describes
+ * the length of each entry (though it isn't a fixed length when strings
+ * are present).
+ *
+ * type Output Meaning
+ * I uint32_t Integer equality comparison
+ * J uint32_t Pair of uint16_t fields converted to native
+ byte order. The two fields both must match.
+ * G uint32_t Greater than or equal to
+ * L uint32_t Less than or equal to
+ * M uint32_t Mask of which fields to test. Fields that
+ take up space increment the count. This
+ field must be first, and resets the count.
+ * D string Description of the device this pnp info is for
+ * Z string pnp string must match this
+ * T nothing T fields set pnp values that must be true for
+ * the entire table.
+ * Values are packed the same way that other values are packed in this file.
+ * Strings and int32_t's start on a 32-bit boundary and are padded with 0
+ * bytes. Objects that are smaller than uint32_t are converted, without
+ * sign extension to uint32_t to simplify parsing downstream.
+ */
+static int
+parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
+{
+ const char *walker = desc, *ep = desc + strlen(desc);
+ const char *colon, *semi;
+ struct pnp_elt *elt;
+ char *nd;
+ char type[8], key[32];
+ int off;
+
+ off = 0;
+ nd = *new_desc = malloc(strlen(desc) + 1);
+ if (verbose > 1)
+ printf("Converting %s into a list\n", desc);
+ while (walker < ep) {
+ colon = strchr(walker, ':');
+ semi = strchr(walker, ';');
+ if (semi != NULL && semi < colon)
+ goto err;
+ if (colon - walker > sizeof(type))
+ goto err;
+ strncpy(type, walker, colon - walker);
+ type[colon - walker] = '\0';
+ if (semi) {
+ if (semi - colon >= sizeof(key))
+ goto err;
+ strncpy(key, colon + 1, semi - colon - 1);
+ key[semi - colon - 1] = '\0';
+ walker = semi + 1;
+ } else {
+ if (strlen(colon + 1) >= sizeof(key))
+ goto err;
+ strcpy(key, colon + 1);
+ walker = ep;
+ }
+ if (verbose > 1)
+ printf("Found type %s for name %s\n", type, key);
+ /* Skip pointer place holders */
+ if (strcmp(type, "P") == 0) {
+ off += sizeof(void *);
+ continue;
+ }
+
+ /*
+ * Add a node of the appropriate type
+ */
+ elt = malloc(sizeof(struct pnp_elt) + strlen(key) + 1);
+ TAILQ_INSERT_TAIL(list, elt, next);
+ elt->pe_key = (char *)(elt + 1);
+ elt->pe_offset = off;
+ if (strcmp(type, "U8") == 0)
+ elt->pe_kind = TYPE_U8;
+ else if (strcmp(type, "V8") == 0)
+ elt->pe_kind = TYPE_V8;
+ else if (strcmp(type, "G16") == 0)
+ elt->pe_kind = TYPE_G16;
+ else if (strcmp(type, "L16") == 0)
+ elt->pe_kind = TYPE_L16;
+ else if (strcmp(type, "M16") == 0)
+ elt->pe_kind = TYPE_M16;
+ else if (strcmp(type, "U16") == 0)
+ elt->pe_kind = TYPE_U16;
+ else if (strcmp(type, "V16") == 0)
+ elt->pe_kind = TYPE_V16;
+ else if (strcmp(type, "U32") == 0)
+ elt->pe_kind = TYPE_U32;
+ else if (strcmp(type, "V32") == 0)
+ elt->pe_kind = TYPE_V32;
+ else if (strcmp(type, "W32") == 0)
+ elt->pe_kind = TYPE_W32;
+ else if (strcmp(type, "D") == 0) /* description char * */
+ elt->pe_kind = TYPE_D;
+ else if (strcmp(type, "Z") == 0) /* char * to match */
+ elt->pe_kind = TYPE_Z;
+ else if (strcmp(type, "P") == 0) /* Pointer -- ignored */
+ elt->pe_kind = TYPE_P;
+ else if (strcmp(type, "E") == 0) /* EISA PNP ID, as uint32_t */
+ elt->pe_kind = TYPE_E;
+ else if (strcmp(type, "T") == 0)
+ elt->pe_kind = TYPE_T;
+ else
+ goto err;
+ /*
+ * Maybe the rounding here needs to be more nuanced and/or somehow
+ * architecture specific. Fortunately, most tables in the system
+ * have sane ordering of types.
+ */
+ if (elt->pe_kind & TYPE_INT) {
+ elt->pe_offset = roundup2(elt->pe_offset, elt->pe_kind & TYPE_SZ_MASK);
+ off = elt->pe_offset + (elt->pe_kind & TYPE_SZ_MASK);
+ } else if (elt->pe_kind == TYPE_E) {
+ /* Type E stored as Int, displays as string */
+ elt->pe_offset = roundup2(elt->pe_offset, sizeof(uint32_t));
+ off = elt->pe_offset + sizeof(uint32_t);
+ } else if (elt->pe_kind == TYPE_T) {
+ /* doesn't actually consume space in the table */
+ off = elt->pe_offset;
+ } else {
+ elt->pe_offset = roundup2(elt->pe_offset, sizeof(void *));
+ off = elt->pe_offset + sizeof(void *);
+ }
+ if (elt->pe_kind & TYPE_PAIRED) {
+ char *word, *ctx;
+
+ for (word = strtok_r(key, "/", &ctx);
+ word; word = strtok_r(NULL, "/", &ctx)) {
+ sprintf(nd, "%c:%s;", elt->pe_kind & TYPE_FLAGGED ? 'J' : 'I',
+ word);
+ nd += strlen(nd);
+ }
+
+ }
+ else {
+ if (elt->pe_kind & TYPE_FLAGGED)
+ *nd++ = 'J';
+ else if (elt->pe_kind & TYPE_GE)
+ *nd++ = 'G';
+ else if (elt->pe_kind & TYPE_LE)
+ *nd++ = 'L';
+ else if (elt->pe_kind & TYPE_MASK)
+ *nd++ = 'M';
+ else if (elt->pe_kind & TYPE_INT)
+ *nd++ = 'I';
+ else if (elt->pe_kind == TYPE_D)
+ *nd++ = 'D';
+ else if (elt->pe_kind == TYPE_Z || elt->pe_kind == TYPE_E)
+ *nd++ = 'Z';
+ else if (elt->pe_kind == TYPE_T)
+ *nd++ = 'T';
+ else
+ errx(1, "Impossible type %x\n", elt->pe_kind);
+ *nd++ = ':';
+ strcpy(nd, key);
+ nd += strlen(nd);
+ *nd++ = ';';
+ }
+ }
+ *nd++ = '\0';
+ return 0;
+err:
+ errx(1, "Parse error of description string %s", desc);
+}
+
static int
parse_entry(struct mod_metadata *md, const char *cval,
struct elf_file *ef, const char *kldname)
{
struct mod_depend mdp;
struct mod_version mdv;
+ struct mod_pnp_match_info pnp;
+ char descr[1024];
Elf_Off data = (Elf_Off)md->md_data;
- int error = 0;
+ int error = 0, i, len;
+ char *walker;
+ void *table;
record_start();
switch (md->md_type) {
@@ -173,9 +404,119 @@ parse_entry(struct mod_metadata *md, const char *cval,
}
break;
case MDT_PNP_INFO:
+ check(EF_SEG_READ_REL(ef, data, sizeof(pnp), &pnp));
+ check(EF_SEG_READ(ef, (Elf_Off)pnp.descr, sizeof(descr), descr));
+ descr[sizeof(descr) - 1] = '\0';
if (dflag) {
- printf(" pnp info for bus %s\n", cval);
+ printf(" pnp info for bus %s format %s %d entries of %d bytes\n",
+ cval, descr, pnp.num_entry, pnp.entry_len);
+ } else {
+ pnp_list list;
+ struct pnp_elt *elt, *elt_tmp;
+ char *new_descr;
+
+ if (verbose > 1)
+ printf(" pnp info for bus %s format %s %d entries of %d bytes\n",
+ cval, descr, pnp.num_entry, pnp.entry_len);
+ /*
+ * Parse descr to weed out the chaff and to create a list
+ * of offsets to output.
+ */
+ TAILQ_INIT(&list);
+ parse_pnp_list(descr, &new_descr, &list);
+ record_int(MDT_PNP_INFO);
+ record_string(cval);
+ record_string(new_descr);
+ record_int(pnp.num_entry);
+ len = pnp.num_entry * pnp.entry_len;
+ walker = table = malloc(len);
+ check(EF_SEG_READ_REL(ef, (Elf_Off)pnp.table, len, table));
+
+ /*
+ * Walk the list and output things. We've collapsed all the
+ * variant forms of the table down to just ints and strings.
+ */
+ for (i = 0; i < pnp.num_entry; i++) {
+ TAILQ_FOREACH(elt, &list, next) {
+ uint8_t v1;
+ uint16_t v2;
+ uint32_t v4;
+ int value;
+ char buffer[1024];
+
+ if (elt->pe_kind == TYPE_W32) {
+ memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+ value = v4 & 0xffff;
+ record_int(value);
+ if (verbose > 1)
+ printf("W32:%#x", value);
+ value = (v4 >> 16) & 0xffff;
+ record_int(value);
+ if (verbose > 1)
+ printf(":%#x;", value);
+ } else if (elt->pe_kind & TYPE_INT) {
+ switch (elt->pe_kind & TYPE_SZ_MASK) {
+ case 1:
+ memcpy(&v1, walker + elt->pe_offset, sizeof(v1));
+ if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff)
+ value = -1;
+ else
+ value = v1;
+ break;
+ case 2:
+ memcpy(&v2, walker + elt->pe_offset, sizeof(v2));
+ if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff)
+ value = -1;
+ else
+ value = v2;
+ break;
+ case 4:
+ memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+ if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff)
+ value = -1;
+ else
+ value = v4;
+ break;
+ default:
+ errx(1, "Invalid size somehow %#x", elt->pe_kind);
+ }
+ if (verbose > 1)
+ printf("I:%#x;", value);
+ record_int(value);
+ } else if (elt->pe_kind == TYPE_T) {
+ /* Do nothing */
+ } else { /* E, Z or D -- P already filtered */
+ if (elt->pe_kind == TYPE_E) {
+ memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+ strcpy(buffer, pnp_eisaformat(v4));
+ } else {
+ char *ptr;
+
+ ptr = *(char **)(walker + elt->pe_offset);
+ buffer[0] = '\0';
+ if (ptr != 0) {
+ EF_SEG_READ(ef, (Elf_Off)ptr,
+ sizeof(buffer), buffer);
+ buffer[sizeof(buffer) - 1] = '\0';
+ }
+ }
+ if (verbose > 1)
+ printf("%c:%s;", elt->pe_kind == TYPE_E ? 'E' : (elt->pe_kind == TYPE_Z ? 'Z' : 'D'), buffer);
+ record_string(buffer);
+ }
+ }
+ if (verbose > 1)
+ printf("\n");
+ walker += pnp.entry_len;
+ }
+ /* Now free it */
+ TAILQ_FOREACH_SAFE(elt, &list, next, elt_tmp) {
+ TAILQ_REMOVE(&list, elt, next);
+ free(elt);
+ }
+ free(table);
}
+ break;
default:
warnx("unknown metadata record %d in file %s", md->md_type, kldname);
}
diff --git a/usr.sbin/lpr/filters/Makefile b/usr.sbin/lpr/filters/Makefile
index f1bc586..7976752 100644
--- a/usr.sbin/lpr/filters/Makefile
+++ b/usr.sbin/lpr/filters/Makefile
@@ -1,7 +1,7 @@
# @(#)Makefile 8.1 (Berkeley) 6/6/93
# $FreeBSD$
-BINDIR= /usr/libexec/lpr
+BINDIR= ${LIBEXECDIR}/lpr
PROG= lpf
MAN=
diff --git a/usr.sbin/mailstats/Makefile b/usr.sbin/mailstats/Makefile
index a7911a2..3d03ff8 100644
--- a/usr.sbin/mailstats/Makefile
+++ b/usr.sbin/mailstats/Makefile
@@ -24,7 +24,7 @@ DPADD+= ${SENDMAIL_DPADD}
LDADD+= ${SENDMAIL_LDADD}
LDFLAGS+= ${SENDMAIL_LDFLAGS}
-sm_os.h:
- ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/mailstats/Makefile.depend b/usr.sbin/mailstats/Makefile.depend
index 9bf3d52..0f94091 100644
--- a/usr.sbin/mailstats/Makefile.depend
+++ b/usr.sbin/mailstats/Makefile.depend
@@ -11,7 +11,6 @@ DIRDEPS = \
lib/libcompiler_rt \
lib/libsm \
lib/libsmutil \
- lib/libutil \
.include <dirdeps.mk>
diff --git a/usr.sbin/makefs/Makefile b/usr.sbin/makefs/Makefile
index 882fe45..7a0ebf0 100644
--- a/usr.sbin/makefs/Makefile
+++ b/usr.sbin/makefs/Makefile
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <src.opts.mk>
+
PROG= makefs
CFLAGS+=-I${.CURDIR}
@@ -32,4 +34,8 @@ SRCS+= ffs_tables.c
CFLAGS+= -I${.CURDIR}/../../lib/libnetbsd
LIBADD= netbsd util sbuf
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/makefs/cd9660.c b/usr.sbin/makefs/cd9660.c
index f0e2f38..e05e52a 100644
--- a/usr.sbin/makefs/cd9660.c
+++ b/usr.sbin/makefs/cd9660.c
@@ -163,7 +163,7 @@ static cd9660node *cd9660_create_special_directory(u_char, cd9660node *);
/*
- * Allocate and initalize a cd9660node
+ * Allocate and initialize a cd9660node
* @returns struct cd9660node * Pointer to new node, or NULL on error
*/
static cd9660node *
@@ -296,8 +296,8 @@ cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
int rv;
/* Set up allowed options - integer options ONLY */
option_t cd9660_options[] = {
- { "l", &diskStructure.isoLevel, 1, 3, "ISO Level" },
- { "isolevel", &diskStructure.isoLevel, 1, 3, "ISO Level" },
+ { "l", &diskStructure.isoLevel, 1, 2, "ISO Level" },
+ { "isolevel", &diskStructure.isoLevel, 1, 2, "ISO Level" },
{ "verbose", &diskStructure.verbose_level, 0, 2,
"Turns on verbose output" },
{ "v", &diskStructure.verbose_level, 0 , 2,
@@ -428,8 +428,7 @@ cd9660_parse_opts(const char *option, fsinfo_t *fsopts)
rv = set_option(cd9660_options, var, val);
}
- if (var)
- free(var);
+ free(var);
return (rv);
}
@@ -1056,6 +1055,7 @@ cd9660_rename_filename(cd9660node *iter, int num, int delete_chars)
if (diskStructure.verbose_level > 0)
printf("Rename_filename called\n");
+ assert(1 <= diskStructure.isoLevel && diskStructure.isoLevel <= 2);
/* TODO : A LOT of chanes regarding 8.3 filenames */
if (diskStructure.isoLevel == 1)
maxlength = 8;
@@ -1731,6 +1731,7 @@ cd9660_joliet_convert_filename(const char *oldname, char *newname, int is_file)
static int
cd9660_convert_filename(const char *oldname, char *newname, int is_file)
{
+ assert(1 <= diskStructure.isoLevel && diskStructure.isoLevel <= 2);
/* NEW */
cd9660_filename_conversion_functor conversion_function = 0;
if (diskStructure.isoLevel == 1)
diff --git a/usr.sbin/makefs/cd9660/cd9660_write.c b/usr.sbin/makefs/cd9660/cd9660_write.c
index f27a76f..e17752a 100644
--- a/usr.sbin/makefs/cd9660/cd9660_write.c
+++ b/usr.sbin/makefs/cd9660/cd9660_write.c
@@ -165,7 +165,7 @@ cd9660_write_path_table(FILE *fd, off_t sector, int mode)
diskStructure.pathTableLength);
unsigned char *buffer;
unsigned char *buffer_head;
- int len;
+ int len, ret;
path_table_entry temp_entry;
cd9660node *ptcur;
@@ -213,8 +213,10 @@ cd9660_write_path_table(FILE *fd, off_t sector, int mode)
ptcur = ptcur->ptnext;
}
- return cd9660_write_filedata(fd, sector, buffer_head,
+ ret = cd9660_write_filedata(fd, sector, buffer_head,
path_table_sectors);
+ free(buffer_head);
+ return ret;
}
diff --git a/usr.sbin/makefs/cd9660/iso9660_rrip.c b/usr.sbin/makefs/cd9660/iso9660_rrip.c
index 5382857..749747b 100644
--- a/usr.sbin/makefs/cd9660/iso9660_rrip.c
+++ b/usr.sbin/makefs/cd9660/iso9660_rrip.c
@@ -1,4 +1,4 @@
-/* $NetBSD: iso9660_rrip.c,v 1.11 2012/04/29 13:32:21 joerg Exp $ */
+/* $NetBSD: iso9660_rrip.c,v 1.14 2014/05/30 13:14:47 martin Exp $ */
/*
* Copyright (c) 2005 Daniel Watt, Walter Deignan, Ryan Gabrys, Alan
@@ -656,13 +656,14 @@ cd9660node_rrip_pn(struct ISO_SUSP_ATTRIBUTES *pn_field, fsnode *fnode)
pn_field->attr.rr_entry.PN.h.length[0] = 20;
pn_field->attr.rr_entry.PN.h.version[0] = 1;
- if (sizeof (fnode->inode->st.st_dev) > 32)
- cd9660_bothendian_dword((uint64_t)fnode->inode->st.st_dev >> 32,
+ if (sizeof (fnode->inode->st.st_rdev) > 4)
+ cd9660_bothendian_dword(
+ (uint64_t)fnode->inode->st.st_rdev >> 32,
pn_field->attr.rr_entry.PN.high);
else
cd9660_bothendian_dword(0, pn_field->attr.rr_entry.PN.high);
- cd9660_bothendian_dword(fnode->inode->st.st_dev & 0xffffffff,
+ cd9660_bothendian_dword(fnode->inode->st.st_rdev & 0xffffffff,
pn_field->attr.rr_entry.PN.low);
return 1;
}
diff --git a/usr.sbin/makefs/ffs/ffs_bswap.c b/usr.sbin/makefs/ffs/ffs_bswap.c
index a1a1c46..e62eb19 100644
--- a/usr.sbin/makefs/ffs/ffs_bswap.c
+++ b/usr.sbin/makefs/ffs/ffs_bswap.c
@@ -67,7 +67,7 @@ void ffs_csumtotal_swap(struct csum_total *o, struct csum_total *n);
void
ffs_sb_swap(struct fs *o, struct fs *n)
{
- int i;
+ size_t i;
u_int32_t *o32, *n32;
/*
@@ -97,7 +97,7 @@ ffs_sb_swap(struct fs *o, struct fs *n)
n->fs_csaddr = bswap64(o->fs_csaddr);
n->fs_pendingblocks = bswap64(o->fs_pendingblocks);
n->fs_pendinginodes = bswap32(o->fs_pendinginodes);
-
+
/* These fields overlap with the second half of the
* historic FS_42POSTBLFMT postbl table
*/
@@ -171,9 +171,9 @@ ffs_dinode2_swap(struct ufs2_dinode *o, struct ufs2_dinode *n)
void
ffs_csum_swap(struct csum *o, struct csum *n, int size)
{
- int i;
+ size_t i;
u_int32_t *oint, *nint;
-
+
oint = (u_int32_t*)o;
nint = (u_int32_t*)n;
diff --git a/usr.sbin/makefs/ffs/newfs_extern.h b/usr.sbin/makefs/ffs/newfs_extern.h
index 88559b6..a54c0e2 100644
--- a/usr.sbin/makefs/ffs/newfs_extern.h
+++ b/usr.sbin/makefs/ffs/newfs_extern.h
@@ -1,4 +1,4 @@
-/* $NetBSD: newfs_extern.h,v 1.2 2004/06/24 22:30:13 lukem Exp $ */
+/* $NetBSD: newfs_extern.h,v 1.3 2009/10/21 01:07:47 snj Exp $ */
/* From: NetBSD: extern.h,v 1.3 2000/12/01 12:03:27 simonb Exp $ */
/*
@@ -12,11 +12,6 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Christos Zoulas.
- * 4. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index 025066d..f80dc53 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -35,7 +35,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd August 16, 2013
+.Dd November 9, 2015
.Dt MAKEFS 8
.Os
.Sh NAME
@@ -44,16 +44,16 @@
.Sh SYNOPSIS
.Nm
.Op Fl DxZ
-.Op Fl B Ar byte-order
+.Op Fl B Ar endian
.Op Fl b Ar free-blocks
.Op Fl d Ar debug-mask
-.Op Fl F Ar specfile
+.Op Fl F Ar mtree-specfile
.Op Fl f Ar free-files
.Op Fl M Ar minimum-size
.Op Fl m Ar maximum-size
.Op Fl N Ar userdb-dir
.Op Fl o Ar fs-options
-.Op Fl r Ar roundup
+.Op Fl R Ar roundup-size
.Op Fl S Ar sector-size
.Op Fl s Ar image-size
.Op Fl t Ar fs-type
@@ -69,9 +69,9 @@ from the directory tree
.Ar directory
or from the mtree manifest
.Ar manifest .
-If optional directory tree
+If any optional directory trees are passed in the
.Ar extra-directory
-is passed, then the directory tree of each argument will be merged
+arguments, then the directory tree of each argument will be merged
into the
.Ar directory
or
@@ -82,9 +82,9 @@ No special devices or privileges are required to perform this task.
.Pp
The options are as follows:
.Bl -tag -width flag
-.It Fl B Ar byte-order
+.It Fl B Ar endian
Set the byte order of the image to
-.Ar byte-order .
+.Ar endian .
Valid byte orders are
.Ql 4321 ,
.Ql big ,
@@ -114,9 +114,9 @@ Enable various levels of debugging, depending upon which bits are
set in
.Ar debug-mask .
XXX: document these
-.It Fl F Ar specfile
+.It Fl F Ar mtree-specfile
Use
-.Ar specfile
+.Ar mtree-specfile
as an
.Xr mtree 8
.Sq specfile
@@ -174,13 +174,13 @@ Set the maximum size of the file system image to
.Ar maximum-size .
An error will be raised if the target file system needs to be larger
than this to accommodate the provided directory tree.
-.It Fl N Ar dbdir
+.It Fl N Ar userdb-dir
Use the user database text file
.Pa master.passwd
and group database text file
.Pa group
from
-.Ar dbdir ,
+.Ar userdb-dir ,
rather than using the results from the system's
.Xr getpwnam 3
and
@@ -196,9 +196,14 @@ Deprecated.
See the
.Fl Z
flag.
-.It Fl r Ar roundup
-Round the image up to specified block size that should be multiple
-of block size.
+.It Fl R Ar roundup-size
+Round the image up to
+.Ar roundup-size .
+.Ar roundup-size
+should be a multiple of the file system block size.
+This option only applies to the
+.Sy ffs
+file system type.
.It Fl S Ar sector-size
Set the file system sector size to
.Ar sector-size .
@@ -221,7 +226,9 @@ ISO 9660 file system.
.It Fl x
Exclude file system nodes not explicitly listed in the specfile.
.It Fl Z
-Create the image as a sparse file.
+Create a sparse file for
+.Sy ffs .
+This is useful for virtual machine images.
.El
.Pp
Where sizes are specified, a decimal number of bytes is expected.
@@ -296,10 +303,10 @@ The following keywords are supported:
.It Sy allow-deep-trees
Allow the directory structure to exceed the maximum specified in
the spec.
-.\" .It Sy allow-illegal-chars
-.\" Unknown
-.\" .It Sy allow-lowercase
-.\" Unknown
+.It Sy allow-illegal-chars
+Allow illegal characters in filenames. This option is not implemented.
+.It Sy allow-lowercase
+Allow lowercase characters in filenames. This option is not implemented.
.It Sy allow-max-name
Allow 37 instead of 33 characters for filenames by omitting the
version id.
@@ -313,6 +320,8 @@ Use the
extension to encode
.Tn RISC OS
metadata.
+.It Sy bootimagedir
+Boot image directory. This option is not implemented.
.It Sy chrp-boot
Write an MBR partition table to the image to allow older CHRP hardware to
boot.
@@ -333,8 +342,18 @@ or
Load a generic boot image into the first 32K of the cd9660 image.
.It Sy hard-disk-boot
Boot image is a hard disk image.
+.It Sy isolevel
+An integer representing the ISO 9660 interchange level where
+.Dq level
+is either
+.Ql 1
+or
+.Ql 2 .
+.Dq level
+.Ql 3
+is not implemented.
.It Sy keep-bad-images
-Do not throw away images whose write was aborted due to an error.
+Do not discard images whose write was aborted due to an error.
For debugging purposes.
.It Sy label
Label name of the image.
@@ -346,14 +365,16 @@ Boot image is a
ElTorito image.
.It Sy no-trailing-padding
Do not pad the image (apparently Linux needs the padding).
-.\" .It Sy omit-trailing-period
-.\" Unknown
+.It Sy omit-trailing-period
+Omit trailing periods in filenames.
.It Sy preparer
Preparer ID of the image.
.It Sy publisher
Publisher ID of the image.
.It Sy rockridge
Use RockRidge extensions (for longer filenames, etc.).
+.It Sy verbose
+Turns on verbose output.
.It Sy volumeid
Volume set identifier of the image.
.El
@@ -368,10 +389,10 @@ utility appeared in
.Nx 1.6 .
.Sh AUTHORS
.An Luke Mewburn Aq Mt lukem@NetBSD.org
-(original program)
-.An Daniel Watt
-.An Walter Deignan
-.An Ryan Gabrys
-.An Alan Perez-Rathke
+(original program),
+.An Daniel Watt ,
+.An Walter Deignan ,
+.An Ryan Gabrys ,
+.An Alan Perez-Rathke ,
.An Ram Vedam
(cd9660 support)
diff --git a/usr.sbin/makefs/makefs.c b/usr.sbin/makefs/makefs.c
index 5e419cc..a7ca751 100644
--- a/usr.sbin/makefs/makefs.c
+++ b/usr.sbin/makefs/makefs.c
@@ -66,9 +66,12 @@ typedef struct {
} fstype_t;
static fstype_t fstypes[] = {
- { "ffs", ffs_prep_opts, ffs_parse_opts, ffs_cleanup_opts, ffs_makefs },
- { "cd9660", cd9660_prep_opts, cd9660_parse_opts, cd9660_cleanup_opts,
- cd9660_makefs},
+#define ENTRY(name) { \
+ # name, name ## _prep_opts, name ## _parse_opts, \
+ name ## _cleanup_opts, name ## _makefs \
+}
+ ENTRY(ffs),
+ ENTRY(cd9660),
{ .type = NULL },
};
@@ -113,7 +116,7 @@ main(int argc, char *argv[])
start_time.tv_sec = start.tv_sec;
start_time.tv_nsec = start.tv_usec * 1000;
- while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pr:s:S:t:xZ")) != -1) {
+ while ((ch = getopt(argc, argv, "B:b:Dd:f:F:M:m:N:o:pR:s:S:t:xZ")) != -1) {
switch (ch) {
case 'B':
@@ -209,10 +212,10 @@ main(int argc, char *argv[])
fsoptions.sparse = 1;
break;
- case 'r':
+ case 'R':
/* Round image size up to specified block size */
fsoptions.roundup =
- strsuftoll("roundup", optarg, 0, LLONG_MAX);
+ strsuftoll("roundup-size", optarg, 0, LLONG_MAX);
break;
case 's':
@@ -365,7 +368,7 @@ usage(void)
prog = getprogname();
fprintf(stderr,
"usage: %s [-t fs-type] [-o fs-options] [-d debug-mask] [-B endian]\n"
-"\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-r roundup ]\n"
+"\t[-S sector-size] [-M minimum-size] [-m maximum-size] [-R roundup-size]\n"
"\t[-s image-size] [-b free-blocks] [-f free-files] [-F mtree-specfile]\n"
"\t[-xZ] [-N userdb-dir] image-file directory | manifest [extra-directory ...]\n",
prog);
diff --git a/usr.sbin/makefs/tests/Makefile b/usr.sbin/makefs/tests/Makefile
new file mode 100644
index 0000000..4373277
--- /dev/null
+++ b/usr.sbin/makefs/tests/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+ATF_TESTS_SH+= makefs_cd9660_tests
+ATF_TESTS_SH+= makefs_ffs_tests
+
+BINDIR= ${TESTSDIR}
+
+SCRIPTS+= makefs_tests_common.sh
+SCRIPTSNAME_makefs_tests_common.sh= makefs_tests_common.sh
+
+.for t in ${ATF_TESTS_SH}
+TEST_METADATA.$t+= required_user="root"
+.endfor
+
+.include <bsd.test.mk>
diff --git a/usr.sbin/makefs/tests/makefs_cd9660_tests.sh b/usr.sbin/makefs/tests/makefs_cd9660_tests.sh
new file mode 100755
index 0000000..161b56b
--- /dev/null
+++ b/usr.sbin/makefs/tests/makefs_cd9660_tests.sh
@@ -0,0 +1,373 @@
+#
+# Copyright 2015 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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$
+#
+
+# A note on specs:
+# - A copy of the ISO-9660 spec can be found here:
+# http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
+# - Any references to `rockridge` are referring to the `Rock Ridge` extensions
+# of the ISO-9660 spec. A copy of the draft `IEEE-P1282` spec can be found
+# here:
+# http://www.ymi.com/ymi/sites/default/files/pdf/Rockridge.pdf
+
+MAKEFS="makefs -t cd9660"
+MOUNT="mount_cd9660"
+
+. "$(dirname "$0")/makefs_tests_common.sh"
+
+common_cleanup()
+{
+ if ! test_md_device=$(cat $TEST_MD_DEVICE_FILE); then
+ echo "$TEST_MD_DEVICE_FILE could not be opened; has an md(4) device been attached?"
+ return
+ fi
+
+ umount -f /dev/$test_md_device || :
+ mdconfig -d -u $test_md_device || :
+}
+
+check_base_iso9660_image_contents()
+{
+ # Symlinks are treated like files when rockridge support isn't
+ # specified
+ check_image_contents "$@" -X c
+
+ atf_check -e empty -o empty -s exit:0 test -L $TEST_INPUTS_DIR/c
+ atf_check -e empty -o empty -s exit:0 test -f $TEST_MOUNT_DIR/c
+}
+
+atf_test_case D_flag cleanup
+D_flag_body()
+{
+ atf_skip "makefs crashes with SIGBUS with dupe mtree entries; see FreeBSD bug # 192839"
+
+ create_test_inputs
+
+ atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \
+ mtree -cp $TEST_INPUTS_DIR
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -F $TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+
+ atf_check -e empty -o empty -s exit:0 \
+ cp $TEST_SPEC_FILE spec2.mtree
+ atf_check -e empty -o save:dupe_$TEST_SPEC_FILE -s exit:0 \
+ cat $TEST_SPEC_FILE spec2.mtree
+
+ atf_check -e empty -o not-empty -s not-exit:0 \
+ $MAKEFS -F dupe_$TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -D -F dupe_$TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+}
+D_flag_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case F_flag cleanup
+F_flag_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \
+ mtree -cp $TEST_INPUTS_DIR
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -F $TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+F_flag_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case from_mtree_spec_file cleanup
+from_mtree_spec_file_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \
+ mtree -c -k "$DEFAULT_MTREE_KEYWORDS" -p $TEST_INPUTS_DIR
+ cd $TEST_INPUTS_DIR
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS $TEST_IMAGE $TEST_SPEC_FILE
+ cd -
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+from_mtree_spec_file_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case from_multiple_dirs cleanup
+from_multiple_dirs_body()
+{
+ test_inputs_dir2=$TMPDIR/inputs2
+
+ create_test_inputs
+
+ atf_check -e empty -o empty -s exit:0 mkdir -p $test_inputs_dir2
+ atf_check -e empty -o empty -s exit:0 \
+ touch $test_inputs_dir2/multiple_dirs_test_file
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS $TEST_IMAGE $TEST_INPUTS_DIR $test_inputs_dir2
+
+ mount_image
+ check_base_iso9660_image_contents -d $test_inputs_dir2
+}
+from_multiple_dirs_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case from_single_dir cleanup
+from_single_dir_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+from_single_dir_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_allow_deep_trees cleanup
+o_flag_allow_deep_trees_body()
+{
+ create_test_inputs
+
+ # Make sure the "more than 8 levels deep" requirement is met.
+ atf_check -e empty -o empty -s exit:0 \
+ mkdir -p $TEST_INPUTS_DIR/a/b/c/d/e/f/g/h/i/j
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o allow-deep-trees $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+o_flag_allow_deep_trees_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_allow_max_name cleanup
+o_flag_allow_max_name_body()
+{
+ atf_expect_fail "-o allow-max-name doesn't appear to be implemented on FreeBSD's copy of makefs [yet]"
+
+ create_test_inputs
+
+ long_path=$TEST_INPUTS_DIR/$(jot -s '' -b 0 37)
+
+ # Make sure the "37 char name" limit requirement is met.
+ atf_check -e empty -o empty -s exit:0 touch $long_path
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o allow-max-name $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+o_flag_allow_max_name_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_isolevel_1 cleanup
+o_flag_isolevel_1_body()
+{
+ atf_expect_fail "this testcase needs work; the filenames generated seem incorrect/corrupt"
+
+ create_test_inputs
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o isolevel=1 $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+o_flag_isolevel_1_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_isolevel_2 cleanup
+o_flag_isolevel_2_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o isolevel=2 $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_base_iso9660_image_contents
+}
+o_flag_isolevel_2_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_isolevel_3 cleanup
+o_flag_isolevel_3_body()
+{
+ create_test_inputs
+
+ # XXX: isolevel=3 isn't implemented yet. See FreeBSD bug # 203645
+ if true; then
+ atf_check -e match:'makefs: ISO Level 3 is greater than 2\.' -o empty -s not-exit:0 \
+ $MAKEFS -o isolevel=3 $TEST_IMAGE $TEST_INPUTS_DIR
+ else
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o isolevel=3 $TEST_IMAGE $TEST_INPUTS_DIR
+ mount_image
+ check_base_iso9660_image_contents
+ fi
+}
+o_flag_isolevel_3_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_preparer
+o_flag_preparer_body()
+{
+ create_test_dirs
+
+ preparer='My Very First ISO'
+ preparer_uppercase="$(echo $preparer | tr '[[:lower:]]' '[[:upper:]]')"
+
+ atf_check -e empty -o empty -s exit:0 touch $TEST_INPUTS_DIR/dummy_file
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o preparer="$preparer" $TEST_IMAGE $TEST_INPUTS_DIR
+ atf_check -e empty -o match:"$preparer_uppercase" -s exit:0 \
+ strings $TEST_IMAGE
+}
+
+atf_test_case o_flag_publisher
+o_flag_publisher_body()
+{
+ create_test_dirs
+
+ publisher='My Super Awesome Publishing Company LTD'
+ publisher_uppercase="$(echo $publisher | tr '[[:lower:]]' '[[:upper:]]')"
+
+ atf_check -e empty -o empty -s exit:0 touch $TEST_INPUTS_DIR/dummy_file
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o publisher="$publisher" $TEST_IMAGE $TEST_INPUTS_DIR
+ atf_check -e empty -o match:"$publisher_uppercase" -s exit:0 \
+ strings $TEST_IMAGE
+}
+
+atf_test_case o_flag_rockridge cleanup
+o_flag_rockridge_body()
+{
+ create_test_dirs
+
+ # Make sure the "more than 8 levels deep" requirement is met.
+ atf_check -e empty -o empty -s exit:0 \
+ mkdir -p $TEST_INPUTS_DIR/a/b/c/d/e/f/g/h/i/j
+
+ # Make sure the "pathname larger than 255 chars" requirement is met.
+ #
+ # $long_path's needs to be nested in a directory, as creating it
+ # outright as a 256 char filename via touch will fail with ENAMETOOLONG
+ long_path=$TEST_INPUTS_DIR/$(jot -s '/' -b "$(jot -s '' -b 0 64)" 4)
+ atf_check -e empty -o empty -s exit:0 mkdir -p "$(dirname $long_path)"
+ atf_check -e empty -o empty -s exit:0 touch "$long_path"
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o rockridge $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_image_contents -X .rr_moved
+
+ # .rr_moved is a special directory created when you have deep directory
+ # trees with rock ridge extensions on
+ atf_check -e empty -o empty -s exit:0 \
+ test -d $TEST_MOUNT_DIR/.rr_moved
+}
+o_flag_rockridge_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_rockridge_dev_nodes cleanup
+o_flag_rockridge_dev_nodes_head()
+{
+ atf_set "descr" "Functional tests to ensure that dev nodes are handled properly with rockridge extensions (NetBSD kern/48852; FreeBSD bug 203648)"
+}
+o_flag_rockridge_dev_nodes_body()
+{
+ create_test_dirs
+
+ (tar -cvf - -C /dev null && touch .tar_ok) | \
+ atf_check -e not-empty -o empty -s exit:0 tar -xvf - -C "$TEST_INPUTS_DIR"
+
+ atf_check -e empty -o empty -s exit:0 test -c $TEST_INPUTS_DIR/null
+ atf_check -e empty -o empty -s exit:0 test -f .tar_ok
+
+ atf_check -e empty -o empty -s exit:0 \
+ $MAKEFS -o rockridge $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_image_contents
+}
+o_flag_rockridge_dev_nodes_cleanup()
+{
+ common_cleanup
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case D_flag
+ atf_add_test_case F_flag
+
+ atf_add_test_case from_mtree_spec_file
+ atf_add_test_case from_multiple_dirs
+ atf_add_test_case from_single_dir
+
+ atf_add_test_case o_flag_allow_deep_trees
+ atf_add_test_case o_flag_allow_max_name
+ atf_add_test_case o_flag_isolevel_1
+ atf_add_test_case o_flag_isolevel_2
+ atf_add_test_case o_flag_isolevel_3
+ atf_add_test_case o_flag_preparer
+ atf_add_test_case o_flag_publisher
+ atf_add_test_case o_flag_rockridge
+ atf_add_test_case o_flag_rockridge_dev_nodes
+}
diff --git a/usr.sbin/makefs/tests/makefs_ffs_tests.sh b/usr.sbin/makefs/tests/makefs_ffs_tests.sh
new file mode 100755
index 0000000..121c2a2
--- /dev/null
+++ b/usr.sbin/makefs/tests/makefs_ffs_tests.sh
@@ -0,0 +1,237 @@
+#
+# Copyright 2015 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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$
+#
+
+MAKEFS="makefs -t ffs"
+MOUNT="mount"
+
+. "$(dirname "$0")/makefs_tests_common.sh"
+
+TEST_TUNEFS_OUTPUT=$TMPDIR/tunefs.output
+
+common_cleanup()
+{
+ if ! test_md_device=$(cat $TEST_MD_DEVICE_FILE); then
+ echo "$TEST_MD_DEVICE_FILE could not be opened; has an md(4) device been attached?"
+ return
+ fi
+
+ umount -f /dev/$test_md_device || :
+ mdconfig -d -u $test_md_device || :
+}
+
+check_ffs_image_contents()
+{
+ atf_check -e save:$TEST_TUNEFS_OUTPUT -o empty -s exit:0 \
+ tunefs -p /dev/$(cat $TEST_MD_DEVICE_FILE)
+
+ check_image_contents "$@"
+}
+
+atf_test_case D_flag cleanup
+D_flag_body()
+{
+ atf_skip "makefs crashes with SIGBUS with dupe mtree entries; see FreeBSD bug # 192839"
+
+ create_test_inputs
+
+ atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \
+ mtree -cp $TEST_INPUTS_DIR
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -F $TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+
+ atf_check -e empty -o empty -s exit:0 \
+ cp $TEST_SPEC_FILE spec2.mtree
+ atf_check -e empty -o save:dupe_$TEST_SPEC_FILE -s exit:0 \
+ cat $TEST_SPEC_FILE spec2.mtree
+
+ atf_check -e empty -o not-empty -s not-exit:0 \
+ $MAKEFS -F dupe_$TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -D -F dupe_$TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+}
+D_flag_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case F_flag cleanup
+F_flag_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \
+ mtree -cp $TEST_INPUTS_DIR
+
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -F $TEST_SPEC_FILE -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_ffs_image_contents
+}
+F_flag_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case from_mtree_spec_file cleanup
+from_mtree_spec_file_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o save:$TEST_SPEC_FILE -s exit:0 \
+ mtree -c -k "$DEFAULT_MTREE_KEYWORDS" -p $TEST_INPUTS_DIR
+
+ cd $TEST_INPUTS_DIR
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS $TEST_IMAGE $TEST_SPEC_FILE
+ cd -
+
+ mount_image
+ check_ffs_image_contents
+}
+from_mtree_spec_file_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case from_multiple_dirs cleanup
+from_multiple_dirs_body()
+{
+ test_inputs_dir2=$TMPDIR/inputs2
+
+ create_test_inputs
+
+ atf_check -e empty -o empty -s exit:0 mkdir -p $test_inputs_dir2
+ atf_check -e empty -o empty -s exit:0 \
+ touch $test_inputs_dir2/multiple_dirs_test_file
+
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS $TEST_IMAGE $TEST_INPUTS_DIR $test_inputs_dir2
+
+ mount_image
+ check_image_contents -d $test_inputs_dir2
+}
+from_multiple_dirs_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case from_single_dir cleanup
+from_single_dir_body()
+{
+ create_test_inputs
+
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -M 1m $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ check_ffs_image_contents
+}
+from_single_dir_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_version_1 cleanup
+o_flag_version_1_body()
+{
+ ffs_version=1
+
+ platform=$(uname)
+ case "$platform" in
+ FreeBSD)
+ ffs_label=UFS${ffs_version}
+ ;;
+ NetBSD)
+ ffs_label=FFSv${ffs_version}
+ ;;
+ *)
+ atf_skip "Unsupported platform"
+ ;;
+ esac
+
+ create_test_inputs
+
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -M 1m -o version=$ffs_version $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ atf_check -e empty -o match:"$ffs_label" dumpfs $TEST_MOUNT_DIR
+ check_ffs_image_contents
+}
+o_flag_version_1_cleanup()
+{
+ common_cleanup
+}
+
+atf_test_case o_flag_version_2 cleanup
+o_flag_version_2_body()
+{
+ ffs_version=2
+
+ platform=$(uname)
+ case "$platform" in
+ FreeBSD)
+ ffs_label=UFS${ffs_version}
+ ;;
+ NetBSD)
+ ffs_label=FFSv${ffs_version}
+ ;;
+ *)
+ atf_skip "Unsupported platform"
+ ;;
+ esac
+
+ create_test_inputs
+
+ atf_check -e empty -o not-empty -s exit:0 \
+ $MAKEFS -M 1m -o version=$ffs_version $TEST_IMAGE $TEST_INPUTS_DIR
+
+ mount_image
+ atf_check -e empty -o match:"$ffs_label" dumpfs $TEST_MOUNT_DIR
+ check_ffs_image_contents
+}
+o_flag_version_2_cleanup()
+{
+ common_cleanup
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case D_flag
+ atf_add_test_case F_flag
+
+ atf_add_test_case from_mtree_spec_file
+ atf_add_test_case from_multiple_dirs
+ atf_add_test_case from_single_dir
+
+ atf_add_test_case o_flag_version_1
+ atf_add_test_case o_flag_version_2
+}
diff --git a/usr.sbin/makefs/tests/makefs_tests_common.sh b/usr.sbin/makefs/tests/makefs_tests_common.sh
new file mode 100755
index 0000000..add0b88
--- /dev/null
+++ b/usr.sbin/makefs/tests/makefs_tests_common.sh
@@ -0,0 +1,152 @@
+#
+# Copyright 2015 EMC Corp.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+# OWNER 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$
+#
+
+KB=1024
+: ${TMPDIR=/tmp}
+# TODO: add mtree `time` support; get a lot of errors like this right now when
+# passing generating disk images with keyword mtree support, like:
+#
+# `[...]/mtree.spec:8: error: time: invalid value '1446458503'`
+#
+#DEFAULT_MTREE_KEYWORDS="type,mode,gid,uid,size,link,time"
+DEFAULT_MTREE_KEYWORDS="type,mode,gid,uid,size,link"
+TEST_IMAGE="$TMPDIR/test.img"
+TEST_INPUTS_DIR="$TMPDIR/inputs"
+TEST_MD_DEVICE_FILE="$TMPDIR/md.output"
+TEST_MOUNT_DIR="$TMPDIR/mnt"
+TEST_SPEC_FILE="$TMPDIR/mtree.spec"
+
+check_image_contents()
+{
+ local directories=$TEST_INPUTS_DIR
+ local excludes mtree_excludes_arg mtree_file
+ local mtree_keywords="$DEFAULT_MTREE_KEYWORDS"
+
+ while getopts "d:f:m:X:" flag; do
+ case "$flag" in
+ d)
+ directories="$directories $OPTARG"
+ ;;
+ f)
+ mtree_file=$OPTARG
+ ;;
+ m)
+ mtree_keywords=$OPTARG
+ ;;
+ X)
+ excludes="$excludes $OPTARG"
+ ;;
+ *)
+ echo "usage: check_image_contents [-d directory ...] [-f mtree-file] [-m mtree-keywords] [-X exclude]"
+ atf_fail "unhandled option: $flag"
+ ;;
+ esac
+ done
+
+ if [ -n "$excludes" ]; then
+ echo "$excludes" | tr ' ' '\n' > excludes.txt
+ mtree_excludes_arg="-X excludes.txt"
+ fi
+
+ if [ -z "$mtree_file" ]; then
+ mtree_file=input_spec.mtree
+ for directory in $directories; do
+ mtree -c -k $mtree_keywords -p $directory $mtree_excludes_arg
+ done > $mtree_file
+ fi
+
+ echo "<---- Input spec BEGIN ---->"
+ cat $mtree_file
+ echo "<---- Input spec END ---->"
+ atf_check -e empty -o empty -s exit:0 \
+ mtree -UW -f $mtree_file \
+ -p $TEST_MOUNT_DIR \
+ $mtree_excludes_arg
+}
+
+create_test_dirs()
+{
+ atf_check -e empty -s exit:0 mkdir -m 0777 -p $TEST_MOUNT_DIR
+ atf_check -e empty -s exit:0 mkdir -m 0777 -p $TEST_INPUTS_DIR
+}
+
+create_test_inputs()
+{
+ create_test_dirs
+
+ cd $TEST_INPUTS_DIR
+
+ atf_check -e empty -s exit:0 mkdir -m 0755 -p a/b/1
+ atf_check -e empty -s exit:0 ln -s a/b c
+ atf_check -e empty -s exit:0 touch d
+ atf_check -e empty -s exit:0 ln d e
+ atf_check -e empty -s exit:0 touch .f
+ atf_check -e empty -s exit:0 mkdir .g
+ # XXX: fifos on the filesystem don't match fifos created by makefs for
+ # some odd reason.
+ #atf_check -e empty -s exit:0 mkfifo h
+ atf_check -e ignore -s exit:0 dd if=/dev/zero of=i count=1000 bs=1
+ atf_check -e empty -s exit:0 touch klmn
+ atf_check -e empty -s exit:0 touch opqr
+ atf_check -e empty -s exit:0 touch stuv
+ atf_check -e empty -s exit:0 install -m 0755 /dev/null wxyz
+ atf_check -e empty -s exit:0 touch 0b00000001
+ atf_check -e empty -s exit:0 touch 0b00000010
+ atf_check -e empty -s exit:0 touch 0b00000011
+ atf_check -e empty -s exit:0 touch 0b00000100
+ atf_check -e empty -s exit:0 touch 0b00000101
+ atf_check -e empty -s exit:0 touch 0b00000110
+ atf_check -e empty -s exit:0 touch 0b00000111
+ atf_check -e empty -s exit:0 touch 0b00001000
+ atf_check -e empty -s exit:0 touch 0b00001001
+ atf_check -e empty -s exit:0 touch 0b00001010
+ atf_check -e empty -s exit:0 touch 0b00001011
+ atf_check -e empty -s exit:0 touch 0b00001100
+ atf_check -e empty -s exit:0 touch 0b00001101
+ atf_check -e empty -s exit:0 touch 0b00001110
+
+ for filesize in 1 512 $(( 2 * $KB )) $(( 10 * $KB )) $(( 512 * $KB )); \
+ do
+ atf_check -e ignore -o empty -s exit:0 \
+ dd if=/dev/zero of=${filesize}.file bs=1 \
+ count=1 oseek=${filesize} conv=sparse
+ files="${files} ${filesize}.file"
+ done
+
+ cd -
+}
+
+mount_image()
+{
+ atf_check -e empty -o save:$TEST_MD_DEVICE_FILE -s exit:0 \
+ mdconfig -a -f $TEST_IMAGE
+ atf_check -e empty -o empty -s exit:0 \
+ $MOUNT /dev/$(cat $TEST_MD_DEVICE_FILE) $TEST_MOUNT_DIR
+}
+
diff --git a/usr.sbin/makemap/Makefile b/usr.sbin/makemap/Makefile
index ceec1b3..af5f742 100644
--- a/usr.sbin/makemap/Makefile
+++ b/usr.sbin/makemap/Makefile
@@ -24,7 +24,7 @@ DPADD+=${SENDMAIL_DPADD}
LDADD+=${SENDMAIL_LDADD}
LDFLAGS+=${SENDMAIL_LDFLAGS}
-sm_os.h:
- ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/makemap/Makefile.depend b/usr.sbin/makemap/Makefile.depend
index f159c6f..3e7ef5e 100644
--- a/usr.sbin/makemap/Makefile.depend
+++ b/usr.sbin/makemap/Makefile.depend
@@ -12,7 +12,6 @@ DIRDEPS = \
lib/libsm \
lib/libsmdb \
lib/libsmutil \
- lib/libutil \
.include <dirdeps.mk>
diff --git a/usr.sbin/mfiutil/mfiutil.8 b/usr.sbin/mfiutil/mfiutil.8
index e999c77..e3adc0b 100644
--- a/usr.sbin/mfiutil/mfiutil.8
+++ b/usr.sbin/mfiutil/mfiutil.8
@@ -607,25 +607,25 @@ Scan for foreign configurations and display the number found. The
argument for the commands below takes the form of a number from 0 to the total
configurations found.
.It Cm foreign clear Op config
-Clear the specifed foreign
+Clear the specified foreign
.Ar config
or all if no
.Ar config
argument is provided.
.It Cm foreign diag Op config
-Display a diagnostic display of the specifed foreign
+Display a diagnostic display of the specified foreign
.Ar config
or all if no
.Ar config
argument is provided.
.It Cm foreign preview Op config
-Preview the specifed foreign
+Preview the specified foreign
.Ar config
after import or all if no
.Ar config
argument is provided.
.It Cm foreign import Op config
-Import the specifed foreign
+Import the specified foreign
.Ar config
or all if no
.Ar config
diff --git a/usr.sbin/mount_smbfs/Makefile.depend b/usr.sbin/mount_smbfs/Makefile.depend
index 4e37118..9c676a0 100644
--- a/usr.sbin/mount_smbfs/Makefile.depend
+++ b/usr.sbin/mount_smbfs/Makefile.depend
@@ -2,12 +2,15 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
+ gnu/lib/csu \
gnu/lib/libgcc \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
+ lib/libcompiler_rt \
lib/libkiconv \
+ lib/libsmb \
.include <dirdeps.mk>
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index 649c7d5f..535a3f7 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -422,7 +422,7 @@ main(int argc, char **argv)
* list.
*/
if (nhosts == 0) {
- hosts = malloc(sizeof(char**));
+ hosts = malloc(sizeof(char *));
if (hosts == NULL)
out_of_mem();
hosts[0] = "*";
diff --git a/usr.sbin/mpsutil/Makefile b/usr.sbin/mpsutil/Makefile
new file mode 100644
index 0000000..8ee4ec5
--- /dev/null
+++ b/usr.sbin/mpsutil/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+PROG= mpsutil
+SRCS= mps_cmd.c mps_flash.c mps_show.c mpsutil.c
+MAN= mpsutil.8
+
+WARNS?= 3
+
+#LIBADD= cam util
+LINKS= ${BINDIR}/mpsutil ${BINDIR}/mprutil
+MLINKS= mpsutil.8 mprutil.8
+
+CFLAGS+= -I${.CURDIR}/../../sys -I. -DUSE_MPT_IOCTLS
+# Avoid dirdep dependency on libutil
+CFLAGS+= -I${SRCTOP}/lib/libutil
+
+# Here be dragons
+.ifdef DEBUG
+CFLAGS+= -DDEBUG
+.endif
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/mpsutil/Makefile.depend b/usr.sbin/mpsutil/Makefile.depend
new file mode 100644
index 0000000..3646e2e
--- /dev/null
+++ b/usr.sbin/mpsutil/Makefile.depend
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/mpsutil/mpr_ioctl.h b/usr.sbin/mpsutil/mpr_ioctl.h
new file mode 100644
index 0000000..82627b9
--- /dev/null
+++ b/usr.sbin/mpsutil/mpr_ioctl.h
@@ -0,0 +1,388 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ *
+ * $FreeBSD$
+ */
+/*-
+ * Copyright (c) 2011-2014 LSI Corp.
+ * 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.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPR_IOCTL_H_
+#define _MPR_IOCTL_H_
+
+#include <dev/mpr/mpi/mpi2_type.h>
+#include <dev/mpr/mpi/mpi2.h>
+#include <dev/mpr/mpi/mpi2_cnfg.h>
+#include <dev/mpr/mpi/mpi2_sas.h>
+
+/*
+ * For the read header requests, the header should include the page
+ * type or extended page type, page number, and page version. The
+ * buffer and length are unused. The completed header is returned in
+ * the 'header' member.
+ *
+ * For the read page and write page requests, 'buf' should point to a
+ * buffer of 'len' bytes which holds the entire page (including the
+ * header).
+ *
+ * All requests specify the page address in 'page_address'.
+ */
+struct mpr_cfg_page_req {
+ MPI2_CONFIG_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_ext_cfg_page_req {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mpr_raid_action {
+ uint8_t action;
+ uint8_t volume_bus;
+ uint8_t volume_id;
+ uint8_t phys_disk_num;
+ uint32_t action_data_word;
+ void *buf;
+ int len;
+ uint32_t volume_status;
+ uint32_t action_data[4];
+ uint16_t action_status;
+ uint16_t ioc_status;
+ uint8_t write;
+};
+
+struct mpr_usr_command {
+ void *req;
+ uint32_t req_len;
+ void *rpl;
+ uint32_t rpl_len;
+ void *buf;
+ int len;
+ uint32_t flags;
+};
+
+typedef struct mpr_pci_bits
+{
+ union {
+ struct {
+ uint32_t DeviceNumber :5;
+ uint32_t FunctionNumber :3;
+ uint32_t BusNumber :24;
+ } bits;
+ uint32_t AsDWORD;
+ } u;
+ uint32_t PciSegmentId;
+} mpr_pci_bits_t;
+
+/*
+ * The following is the MPRIOCTL_GET_ADAPTER_DATA data structure. This data
+ * structure is setup so that we hopefully are properly aligned for both
+ * 32-bit and 64-bit mode applications.
+ *
+ * Adapter Type - Value = 6 = SCSI Protocol through SAS-3 adapter
+ *
+ * MPI Port Number - The PCI Function number for this device
+ *
+ * PCI Device HW Id - The PCI device number for this device
+ *
+ */
+#define MPRIOCTL_ADAPTER_TYPE_SAS3 6
+typedef struct mpr_adapter_data
+{
+ uint32_t StructureLength;
+ uint32_t AdapterType;
+ uint32_t MpiPortNumber;
+ uint32_t PCIDeviceHwId;
+ uint32_t PCIDeviceHwRev;
+ uint32_t SubSystemId;
+ uint32_t SubsystemVendorId;
+ uint32_t Reserved1;
+ uint32_t MpiFirmwareVersion;
+ uint32_t BiosVersion;
+ uint8_t DriverVersion[32];
+ uint8_t Reserved2;
+ uint8_t ScsiId;
+ uint16_t Reserved3;
+ mpr_pci_bits_t PciInformation;
+} mpr_adapter_data_t;
+
+
+typedef struct mpr_update_flash
+{
+ uint64_t PtrBuffer;
+ uint32_t ImageChecksum;
+ uint32_t ImageOffset;
+ uint32_t ImageSize;
+ uint32_t ImageType;
+} mpr_update_flash_t;
+
+
+#define MPR_PASS_THRU_DIRECTION_NONE 0
+#define MPR_PASS_THRU_DIRECTION_READ 1
+#define MPR_PASS_THRU_DIRECTION_WRITE 2
+#define MPR_PASS_THRU_DIRECTION_BOTH 3
+
+typedef struct mpr_pass_thru
+{
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+} mpr_pass_thru_t;
+
+
+/*
+ * Event queue defines
+ */
+#define MPR_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */
+#define MPR_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */
+
+typedef struct mpr_event_query
+{
+ uint16_t Entries;
+ uint16_t Reserved;
+ uint32_t Types[4];
+} mpr_event_query_t;
+
+typedef struct mpr_event_enable
+{
+ uint32_t Types[4];
+} mpr_event_enable_t;
+
+/*
+ * Event record entry for ioctl.
+ */
+typedef struct mpr_event_entry
+{
+ uint32_t Type;
+ uint32_t Number;
+ uint32_t Data[MPR_MAX_EVENT_DATA_LENGTH];
+} mpr_event_entry_t;
+
+typedef struct mpr_event_report
+{
+ uint32_t Size;
+ uint64_t PtrEvents;
+} mpr_event_report_t;
+
+
+typedef struct mpr_pci_info
+{
+ uint32_t BusNumber;
+ uint8_t DeviceNumber;
+ uint8_t FunctionNumber;
+ uint16_t InterruptVector;
+ uint8_t PciHeader[256];
+} mpr_pci_info_t;
+
+
+typedef struct mpr_diag_action
+{
+ uint32_t Action;
+ uint32_t Length;
+ uint64_t PtrDiagAction;
+ uint32_t ReturnCode;
+} mpr_diag_action_t;
+
+#define MPR_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF)
+
+#define MPR_FW_DIAG_NEW (0x806E6577)
+
+#define MPR_FW_DIAG_TYPE_REGISTER (0x00000001)
+#define MPR_FW_DIAG_TYPE_UNREGISTER (0x00000002)
+#define MPR_FW_DIAG_TYPE_QUERY (0x00000003)
+#define MPR_FW_DIAG_TYPE_READ_BUFFER (0x00000004)
+#define MPR_FW_DIAG_TYPE_RELEASE (0x00000005)
+
+#define MPR_FW_DIAG_INVALID_UID (0x00000000)
+
+#define MPR_DIAG_SUCCESS 0
+#define MPR_DIAG_FAILURE 1
+
+#define MPR_FW_DIAG_ERROR_SUCCESS (0x00000000)
+#define MPR_FW_DIAG_ERROR_FAILURE (0x00000001)
+#define MPR_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002)
+#define MPR_FW_DIAG_ERROR_POST_FAILED (0x00000010)
+#define MPR_FW_DIAG_ERROR_INVALID_UID (0x00000011)
+#define MPR_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012)
+#define MPR_FW_DIAG_ERROR_NO_BUFFER (0x00000013)
+#define MPR_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014)
+
+
+typedef struct mpr_fw_diag_register
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t RequestedBufferSize;
+ uint32_t UniqueId;
+} mpr_fw_diag_register_t;
+
+typedef struct mpr_fw_diag_unregister
+{
+ uint32_t UniqueId;
+} mpr_fw_diag_unregister_t;
+
+#define MPR_FW_DIAG_FLAG_APP_OWNED (0x0001)
+#define MPR_FW_DIAG_FLAG_BUFFER_VALID (0x0002)
+#define MPR_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004)
+
+typedef struct mpr_fw_diag_query
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t TotalBufferSize;
+ uint32_t DriverAddedBufferSize;
+ uint32_t UniqueId;
+} mpr_fw_diag_query_t;
+
+typedef struct mpr_fw_diag_release
+{
+ uint32_t UniqueId;
+} mpr_fw_diag_release_t;
+
+#define MPR_FW_DIAG_FLAG_REREGISTER (0x0001)
+#define MPR_FW_DIAG_FLAG_FORCE_RELEASE (0x0002)
+
+typedef struct mpr_diag_read_buffer
+{
+ uint8_t Status;
+ uint8_t Reserved;
+ uint16_t Flags;
+ uint32_t StartingOffset;
+ uint32_t BytesToRead;
+ uint32_t UniqueId;
+ uint64_t PtrDataBuffer;
+} mpr_diag_read_buffer_t;
+
+/*
+ * Register Access
+ */
+#define REG_IO_READ 1
+#define REG_IO_WRITE 2
+#define REG_MEM_READ 3
+#define REG_MEM_WRITE 4
+
+typedef struct mpr_reg_access
+{
+ uint32_t Command;
+ uint32_t RegOffset;
+ uint32_t RegData;
+} mpr_reg_access_t;
+
+typedef struct mpr_btdh_mapping
+{
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+} mpr_btdh_mapping_t;
+
+#define MPRIO_MPR_COMMAND_FLAG_VERBOSE 0x01
+#define MPRIO_MPR_COMMAND_FLAG_DEBUG 0x02
+#define MPRIO_READ_CFG_HEADER _IOWR('M', 200, struct mpr_cfg_page_req)
+#define MPRIO_READ_CFG_PAGE _IOWR('M', 201, struct mpr_cfg_page_req)
+#define MPRIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mpr_ext_cfg_page_req)
+#define MPRIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mpr_ext_cfg_page_req)
+#define MPRIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mpr_cfg_page_req)
+#define MPRIO_RAID_ACTION _IOWR('M', 205, struct mpr_raid_action)
+#define MPRIO_MPR_COMMAND _IOWR('M', 210, struct mpr_usr_command)
+
+#ifndef MPTIOCTL
+#define MPTIOCTL ('I')
+#define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\
+ struct mpr_adapter_data)
+#define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\
+ struct mpr_update_flash)
+#define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3)
+#define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\
+ struct mpr_pass_thru)
+#define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\
+ struct mpr_event_query)
+#define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\
+ struct mpr_event_enable)
+#define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\
+ struct mpr_event_report)
+#define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\
+ struct mpr_pci_info)
+#define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\
+ struct mpr_diag_action)
+#define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\
+ struct mpr_reg_access)
+#define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\
+ struct mpr_btdh_mapping)
+#endif
+
+#endif /* !_MPR_IOCTL_H_ */
diff --git a/usr.sbin/mpsutil/mps_cmd.c b/usr.sbin/mpsutil/mps_cmd.c
new file mode 100644
index 0000000..24ed74e
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_cmd.c
@@ -0,0 +1,731 @@
+/*-
+ * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * Copyright (c) 2015 Netflix, Inc.
+ * All rights reserved.
+ * Written by: Scott Long <scottl@freebsd.org>
+ *
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/ioctl.h>
+#if 0
+#include <sys/mps_ioctl.h>
+#else
+#include "mps_ioctl.h"
+#include "mpr_ioctl.h"
+#endif
+#include <sys/sysctl.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mpsutil.h"
+
+#ifndef USE_MPT_IOCTLS
+#define USE_MPT_IOCTLS
+#endif
+
+static const char *mps_ioc_status_codes[] = {
+ "Success", /* 0x0000 */
+ "Invalid function",
+ "Busy",
+ "Invalid scatter-gather list",
+ "Internal error",
+ "Reserved",
+ "Insufficient resources",
+ "Invalid field",
+ "Invalid state", /* 0x0008 */
+ "Operation state not supported",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0010 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0018 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Invalid configuration action", /* 0x0020 */
+ "Invalid configuration type",
+ "Invalid configuration page",
+ "Invalid configuration data",
+ "No configuration defaults",
+ "Unable to commit configuration change",
+ NULL,
+ NULL,
+ NULL, /* 0x0028 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0030 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0038 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Recovered SCSI error", /* 0x0040 */
+ "Invalid SCSI bus",
+ "Invalid SCSI target ID",
+ "SCSI device not there",
+ "SCSI data overrun",
+ "SCSI data underrun",
+ "SCSI I/O error",
+ "SCSI protocol error",
+ "SCSI task terminated", /* 0x0048 */
+ "SCSI residual mismatch",
+ "SCSI task management failed",
+ "SCSI I/O controller terminated",
+ "SCSI external controller terminated",
+ "EEDP guard error",
+ "EEDP reference tag error",
+ "EEDP application tag error",
+ NULL, /* 0x0050 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0058 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SCSI target priority I/O", /* 0x0060 */
+ "Invalid SCSI target port",
+ "Invalid SCSI target I/O index",
+ "SCSI target aborted",
+ "No connection retryable",
+ "No connection",
+ "FC aborted",
+ "Invalid FC receive ID",
+ "FC did invalid", /* 0x0068 */
+ "FC node logged out",
+ "Transfer count mismatch",
+ "STS data not set",
+ "FC exchange canceled",
+ "Data offset error",
+ "Too much write data",
+ "IU too short",
+ "ACK NAK timeout", /* 0x0070 */
+ "NAK received",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL, /* 0x0078 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "LAN device not found", /* 0x0080 */
+ "LAN device failure",
+ "LAN transmit error",
+ "LAN transmit aborted",
+ "LAN receive error",
+ "LAN receive aborted",
+ "LAN partial packet",
+ "LAN canceled",
+ NULL, /* 0x0088 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SAS SMP request failed", /* 0x0090 */
+ "SAS SMP data overrun",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Inband aborted", /* 0x0098 */
+ "No inband connection",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Diagnostic released", /* 0x00A0 */
+};
+
+struct mprs_pass_thru {
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+};
+
+struct mprs_btdh_mapping {
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+};
+
+const char *
+mps_ioc_status(U16 IOCStatus)
+{
+ static char buffer[16];
+
+ IOCStatus &= MPI2_IOCSTATUS_MASK;
+ if (IOCStatus < sizeof(mps_ioc_status_codes) / sizeof(char *) &&
+ mps_ioc_status_codes[IOCStatus] != NULL)
+ return (mps_ioc_status_codes[IOCStatus]);
+ snprintf(buffer, sizeof(buffer), "Status: 0x%04x", IOCStatus);
+ return (buffer);
+}
+
+#ifdef USE_MPT_IOCTLS
+int
+mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus, uint16_t *target)
+{
+ int error;
+ struct mprs_btdh_mapping map;
+
+ map.Bus = *bus;
+ map.TargetID = *target;
+ map.DevHandle = *devhandle;
+
+ if ((error = ioctl(fd, MPTIOCTL_BTDH_MAPPING, &map)) != 0) {
+ error = errno;
+ warn("Failed to map bus/target/device");
+ return (error);
+ }
+
+ *bus = map.Bus;
+ *target = map.TargetID;
+ *devhandle = map.DevHandle;
+
+ return (0);
+}
+
+int
+mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ req.Header.PageType = PageType;
+ req.Header.PageNumber = PageNumber;
+ req.PageAddress = PageAddress;
+
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, NULL, 0, 30))
+ return (errno);
+
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ return (EIO);
+ }
+ if (header == NULL)
+ return (EINVAL);
+ *header = reply.Header;
+ return (0);
+}
+
+int
+mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber, U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *ExtPageLength, U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ req.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
+ req.ExtPageType = ExtPageType;
+ req.Header.PageNumber = PageNumber;
+ req.PageAddress = PageAddress;
+
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, NULL, 0, 30))
+ return (errno);
+
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ return (EIO);
+ }
+ if ((header == NULL) || (ExtPageLength == NULL))
+ return (EINVAL);
+ *header = reply.Header;
+ *ExtPageLength = reply.ExtPageLength;
+ return (0);
+}
+
+void *
+mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_PAGE_HEADER header;
+ MPI2_CONFIG_REPLY reply;
+ void *buf;
+ int error, len;
+
+ bzero(&header, sizeof(header));
+ error = mps_read_config_page_header(fd, PageType, PageNumber,
+ PageAddress, &header, IOCStatus);
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ req.PageAddress = PageAddress;
+ req.Header = header;
+ req.Header.PageLength = reply.Header.PageLength;
+ if (reply.Header.PageLength == 0)
+ req.Header.PageLength = 4;
+
+ len = req.Header.PageLength * 4;
+ buf = malloc(len);
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ buf, len, NULL, 0, 30)) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ else
+ warnx("Reading config page failed: 0x%x %s",
+ reply.IOCStatus, mps_ioc_status(reply.IOCStatus));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+
+void *
+mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
+ U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
+{
+ MPI2_CONFIG_REQUEST req;
+ MPI2_CONFIG_PAGE_HEADER header;
+ MPI2_CONFIG_REPLY reply;
+ U16 pagelen;
+ void *buf;
+ int error, len;
+
+ if (IOCStatus != NULL)
+ *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
+ bzero(&header, sizeof(header));
+ error = mps_read_ext_config_page_header(fd, ExtPageType, PageNumber,
+ PageAddress, &header, &pagelen, IOCStatus);
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ bzero(&req, sizeof(req));
+ req.Function = MPI2_FUNCTION_CONFIG;
+ req.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ req.PageAddress = PageAddress;
+ req.Header = header;
+ if (pagelen == 0)
+ pagelen = 4;
+ req.ExtPageLength = pagelen;
+ req.ExtPageType = ExtPageType;
+
+ len = pagelen * 4;
+ buf = malloc(len);
+ if (mps_pass_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ buf, len, NULL, 0, 30)) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(reply.IOCStatus)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = reply.IOCStatus;
+ else
+ warnx("Reading extended config page failed: %s",
+ mps_ioc_status(reply.IOCStatus));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+
+int
+mps_firmware_send(int fd, unsigned char *fw, uint32_t len, bool bios)
+{
+ MPI2_FW_DOWNLOAD_REQUEST req;
+ MPI2_FW_DOWNLOAD_REPLY reply;
+
+ bzero(&req, sizeof(req));
+ bzero(&reply, sizeof(reply));
+ req.Function = MPI2_FUNCTION_FW_DOWNLOAD;
+ req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
+ req.TotalImageSize = len;
+ req.MsgFlags = MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT;
+
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ fw, len, 0)) {
+ return (-1);
+ }
+ return (0);
+}
+
+int
+mps_firmware_get(int fd, unsigned char **firmware, bool bios)
+{
+ MPI2_FW_UPLOAD_REQUEST req;
+ MPI2_FW_UPLOAD_REPLY reply;
+ int size;
+
+ *firmware = NULL;
+ bzero(&req, sizeof(req));
+ bzero(&reply, sizeof(reply));
+ req.Function = MPI2_FUNCTION_FW_UPLOAD;
+ req.ImageType = bios ? MPI2_FW_DOWNLOAD_ITYPE_BIOS : MPI2_FW_DOWNLOAD_ITYPE_FW;
+
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ NULL, 0, 0)) {
+ return (-1);
+ }
+ if (reply.ActualImageSize == 0) {
+ return (-1);
+ }
+
+ size = reply.ActualImageSize;
+ *firmware = calloc(1, sizeof(unsigned char) * size);
+ if (*firmware == NULL) {
+ warn("calloc");
+ return (-1);
+ }
+ if (mps_user_command(fd, &req, sizeof(req), &reply, sizeof(reply),
+ *firmware, size, 0)) {
+ free(*firmware);
+ return (-1);
+ }
+
+ return (size);
+}
+
+#else
+
+int
+mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus)
+{
+ struct mps_cfg_page_req req;
+
+ if (IOCStatus != NULL)
+ *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
+ if (header == NULL)
+ return (EINVAL);
+ bzero(&req, sizeof(req));
+ req.header.PageType = PageType;
+ req.header.PageNumber = PageNumber;
+ req.page_address = PageAddress;
+ if (ioctl(fd, MPSIO_READ_CFG_HEADER, &req) < 0)
+ return (errno);
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ return (EIO);
+ }
+ bcopy(&req.header, header, sizeof(*header));
+ return (0);
+}
+
+void *
+mps_read_config_page(int fd, U8 PageType, U8 PageNumber, U32 PageAddress,
+ U16 *IOCStatus)
+{
+ struct mps_cfg_page_req req;
+ void *buf;
+ int error;
+
+ error = mps_read_config_page_header(fd, PageType, PageNumber,
+ PageAddress, &req.header, IOCStatus);
+ if (error) {
+ errno = error;
+ return (NULL);
+ }
+
+ if (req.header.PageLength == 0)
+ req.header.PageLength = 4;
+ req.len = req.header.PageLength * 4;
+ buf = malloc(req.len);
+ req.buf = buf;
+ bcopy(&req.header, buf, sizeof(req.header));
+ if (ioctl(fd, MPSIO_READ_CFG_PAGE, &req) < 0) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ else
+ warnx("Reading config page failed: 0x%x %s",
+ req.ioc_status, mps_ioc_status(req.ioc_status));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+
+void *
+mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
+ U8 PageNumber, U32 PageAddress, U16 *IOCStatus)
+{
+ struct mps_ext_cfg_page_req req;
+ void *buf;
+ int error;
+
+ if (IOCStatus != NULL)
+ *IOCStatus = MPI2_IOCSTATUS_SUCCESS;
+ bzero(&req, sizeof(req));
+ req.header.PageVersion = PageVersion;
+ req.header.PageNumber = PageNumber;
+ req.header.ExtPageType = ExtPageType;
+ req.page_address = PageAddress;
+ if (ioctl(fd, MPSIO_READ_EXT_CFG_HEADER, &req) < 0)
+ return (NULL);
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ else
+ warnx("Reading extended config page header failed: %s",
+ mps_ioc_status(req.ioc_status));
+ errno = EIO;
+ return (NULL);
+ }
+ req.len = req.header.ExtPageLength * 4;
+ buf = malloc(req.len);
+ req.buf = buf;
+ bcopy(&req.header, buf, sizeof(req.header));
+ if (ioctl(fd, MPSIO_READ_EXT_CFG_PAGE, &req) < 0) {
+ error = errno;
+ free(buf);
+ errno = error;
+ return (NULL);
+ }
+ if (!IOC_STATUS_SUCCESS(req.ioc_status)) {
+ if (IOCStatus != NULL)
+ *IOCStatus = req.ioc_status;
+ else
+ warnx("Reading extended config page failed: %s",
+ mps_ioc_status(req.ioc_status));
+ free(buf);
+ errno = EIO;
+ return (NULL);
+ }
+ return (buf);
+}
+#endif
+
+int
+mps_open(int unit)
+{
+ char path[MAXPATHLEN];
+
+ snprintf(path, sizeof(path), "/dev/mp%s%d", is_mps ? "s": "r", unit);
+ return (open(path, O_RDWR));
+}
+
+int
+mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *buffer, int len, uint32_t flags)
+{
+ struct mps_usr_command cmd;
+
+ bzero(&cmd, sizeof(struct mps_usr_command));
+ cmd.req = req;
+ cmd.req_len = req_len;
+ cmd.rpl = reply;
+ cmd.rpl_len = reply_len;
+ cmd.buf = buffer;
+ cmd.len = len;
+ cmd.flags = flags;
+
+ if (ioctl(fd, is_mps ? MPSIO_MPS_COMMAND : MPRIO_MPR_COMMAND, &cmd) < 0)
+ return (errno);
+ return (0);
+}
+
+int
+mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
+ uint32_t dataout_len, uint32_t timeout)
+{
+ struct mprs_pass_thru pass;
+
+ pass.PtrRequest = (uint64_t)(uintptr_t)req;
+ pass.PtrReply = (uint64_t)(uintptr_t)reply;
+ pass.PtrData = (uint64_t)(uintptr_t)data_in;
+ pass.PtrDataOut = (uint64_t)(uintptr_t)data_out;
+ pass.RequestSize = req_len;
+ pass.ReplySize = reply_len;
+ pass.DataSize = datain_len;
+ pass.DataOutSize = dataout_len;
+ if (datain_len && dataout_len) {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_BOTH;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_BOTH;
+ }
+ } else if (datain_len) {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_READ;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_READ;
+ }
+ } else if (dataout_len) {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_WRITE;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_WRITE;
+ }
+ } else {
+ if (is_mps) {
+ pass.DataDirection = MPS_PASS_THRU_DIRECTION_NONE;
+ } else {
+ pass.DataDirection = MPR_PASS_THRU_DIRECTION_NONE;
+ }
+ }
+ pass.Timeout = timeout;
+
+ if (ioctl(fd, MPTIOCTL_PASS_THRU, &pass) < 0)
+ return (errno);
+ return (0);
+}
+
+MPI2_IOC_FACTS_REPLY *
+mps_get_iocfacts(int fd)
+{
+ MPI2_IOC_FACTS_REPLY *facts;
+ MPI2_IOC_FACTS_REQUEST req;
+ int error;
+
+ facts = malloc(sizeof(MPI2_IOC_FACTS_REPLY));
+ if (facts == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+
+ bzero(&req, sizeof(MPI2_IOC_FACTS_REQUEST));
+ req.Function = MPI2_FUNCTION_IOC_FACTS;
+
+#if 1
+ error = mps_pass_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
+ facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, NULL, 0, 10);
+#else
+ error = mps_user_command(fd, &req, sizeof(MPI2_IOC_FACTS_REQUEST),
+ facts, sizeof(MPI2_IOC_FACTS_REPLY), NULL, 0, 0);
+#endif
+ if (error) {
+ free(facts);
+ return (NULL);
+ }
+
+ if (!IOC_STATUS_SUCCESS(facts->IOCStatus)) {
+ free(facts);
+ errno = EINVAL;
+ return (NULL);
+ }
+ return (facts);
+}
+
diff --git a/usr.sbin/mpsutil/mps_flash.c b/usr.sbin/mpsutil/mps_flash.c
new file mode 100644
index 0000000..e22f29c
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_flash.c
@@ -0,0 +1,237 @@
+/*-
+ * Copyright (c) 2015 Baptiste Daroussin <bapt@FreeBSD.org>
+ *
+ * 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>
+__RCSID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mpsutil.h"
+
+MPS_TABLE(top, flash);
+
+static int
+flash_save(int argc, char **argv)
+{
+ const char *firmware_file;
+ unsigned char *firmware_buffer = NULL;
+ int error, fd, size;
+ bool bios = false;
+ ssize_t written = 0, ret = 0;
+
+ if (argc < 2) {
+ warnx("missing argument: expecting 'firmware' or bios'");
+ return (EINVAL);
+ }
+
+ if (strcmp(argv[1], "bios") == 0) {
+ bios = true;
+ } else if (strcmp(argv[1], "firmware") != 0) {
+ warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
+ argv[1]);
+ }
+
+ if (argc > 4) {
+ warnx("save %s: extra arguments", argv[1]);
+ return (EINVAL);
+ }
+
+ firmware_file = argv[1];
+ if (argc == 3) {
+ firmware_file = argv[2];
+ }
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ if ((size = mps_firmware_get(fd, &firmware_buffer, bios)) < 0) {
+ warnx("Fail to save %s", argv[1]);
+ return (1);
+ }
+
+ close(fd);
+ if (size > 0) {
+ fd = open(firmware_file, O_CREAT | O_TRUNC | O_RDWR, 0644);
+ if (fd <0) {
+ error = errno;
+ warn("open");
+ free(firmware_buffer);
+ return (error);
+ }
+ while (written != size) {
+ if ((ret = write(fd, firmware_buffer + written, size - written)) <0) {
+ error = errno;
+ warn("write");
+ free(firmware_buffer);
+ return (error);
+ }
+ written += ret;
+ }
+ close(fd);
+ }
+ free(firmware_buffer);
+ printf("%s successfully saved as %s\n", argv[1], firmware_file);
+ return (0);
+}
+
+MPS_COMMAND(flash, save, flash_save, "[firmware|bios] [file]",
+ "Save firmware/bios into a file");
+
+static int
+flash_update(int argc, char **argv)
+{
+ int error, fd;
+ unsigned char *mem = NULL;
+ struct stat st;
+ bool bios = false;
+ MPI2_FW_IMAGE_HEADER *fwheader;
+ MPI2_IOC_FACTS_REPLY *facts;
+
+ if (argc < 2) {
+ warnx("missing argument: expecting 'firmware' or bios'");
+ return (EINVAL);
+ }
+
+ if (strcmp(argv[1], "bios") == 0) {
+ bios = true;
+ } else if (strcmp(argv[1], "firmware") != 0) {
+ warnx("Invalid argument '%s', expecting 'firmware' or 'bios'",
+ argv[1]);
+ }
+
+ if (argc > 4) {
+ warnx("update firmware: extra arguments");
+ return (EINVAL);
+ }
+
+ if (argc != 3) {
+ warnx("no firmware specified");
+ return (EINVAL);
+ }
+
+ if (stat(argv[2], &st) == -1) {
+ error = errno;
+ warn("stat");
+ return (error);
+ }
+
+ fd = open(argv[2], O_RDONLY);
+ if (fd < 0) {
+ error = errno;
+ warn("open");
+ return (error);
+ }
+
+ mem = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (mem == MAP_FAILED) {
+ error = errno;
+ warn("mmap");
+ close(fd);
+ return (error);
+ }
+ close(fd);
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ munmap(mem, st.st_size);
+ return (error);
+ }
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ warnx("could not get controller IOCFacts\n");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (EINVAL);
+ }
+
+ if (bios) {
+ /* Check boot record magic number */
+ if (((mem[0x01]<<8) + mem[0x00]) != 0xaa55) {
+ warnx("Invalid bios: no boot record magic number");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ if ((st.st_size % 512) != 0) {
+ warnx("Invalid bios: size not a multiple of 512");
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ } else {
+ fwheader = (MPI2_FW_IMAGE_HEADER *)mem;
+ if (fwheader->VendorID != MPI2_MFGPAGE_VENDORID_LSI) {
+ warnx("Invalid firmware:");
+ warnx(" Expected Vendor ID: %04x",
+ MPI2_MFGPAGE_VENDORID_LSI);
+ warnx(" Image Vendor ID: %04x", fwheader->VendorID);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+
+ if (fwheader->ProductID != facts->ProductID) {
+ warnx("Invalid image:");
+ warnx(" Expected Product ID: %04x", facts->ProductID);
+ warnx(" Image Product ID: %04x", fwheader->ProductID);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+ }
+
+ printf("Updating %s...\n", argv[1]);
+ if (mps_firmware_send(fd, mem, st.st_size, bios) < 0) {
+ warnx("Fail to update %s", argv[1]);
+ munmap(mem, st.st_size);
+ close(fd);
+ return (1);
+ }
+
+ munmap(mem, st.st_size);
+ close(fd);
+ printf("%s successfully updated\n", argv[1]);
+ return (0);
+}
+
+MPS_COMMAND(flash, update, flash_update, "[firmware|bios] file",
+ "Update firmware/bios");
diff --git a/usr.sbin/mpsutil/mps_ioctl.h b/usr.sbin/mpsutil/mps_ioctl.h
new file mode 100644
index 0000000..a52f80e
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_ioctl.h
@@ -0,0 +1,387 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD userland interface
+ *
+ * $FreeBSD$
+ */
+/*-
+ * Copyright (c) 2011, 2012 LSI Corp.
+ * 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.
+ *
+ * LSI MPT-Fusion Host Adapter FreeBSD
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _MPS_IOCTL_H_
+#define _MPS_IOCTL_H_
+
+#include <dev/mps/mpi/mpi2_type.h>
+#include <dev/mps/mpi/mpi2.h>
+#include <dev/mps/mpi/mpi2_cnfg.h>
+#include <dev/mps/mpi/mpi2_sas.h>
+
+/*
+ * For the read header requests, the header should include the page
+ * type or extended page type, page number, and page version. The
+ * buffer and length are unused. The completed header is returned in
+ * the 'header' member.
+ *
+ * For the read page and write page requests, 'buf' should point to a
+ * buffer of 'len' bytes which holds the entire page (including the
+ * header).
+ *
+ * All requests specify the page address in 'page_address'.
+ */
+struct mps_cfg_page_req {
+ MPI2_CONFIG_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mps_ext_cfg_page_req {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER header;
+ uint32_t page_address;
+ void *buf;
+ int len;
+ uint16_t ioc_status;
+};
+
+struct mps_raid_action {
+ uint8_t action;
+ uint8_t volume_bus;
+ uint8_t volume_id;
+ uint8_t phys_disk_num;
+ uint32_t action_data_word;
+ void *buf;
+ int len;
+ uint32_t volume_status;
+ uint32_t action_data[4];
+ uint16_t action_status;
+ uint16_t ioc_status;
+ uint8_t write;
+};
+
+struct mps_usr_command {
+ void *req;
+ uint32_t req_len;
+ void *rpl;
+ uint32_t rpl_len;
+ void *buf;
+ int len;
+ uint32_t flags;
+};
+
+typedef struct mps_pci_bits
+{
+ union {
+ struct {
+ uint32_t DeviceNumber :5;
+ uint32_t FunctionNumber :3;
+ uint32_t BusNumber :24;
+ } bits;
+ uint32_t AsDWORD;
+ } u;
+ uint32_t PciSegmentId;
+} mps_pci_bits_t;
+
+/*
+ * The following is the MPSIOCTL_GET_ADAPTER_DATA data structure. This data
+ * structure is setup so that we hopefully are properly aligned for both
+ * 32-bit and 64-bit mode applications.
+ *
+ * Adapter Type - Value = 4 = SCSI Protocol through SAS-2 adapter
+ *
+ * MPI Port Number - The PCI Function number for this device
+ *
+ * PCI Device HW Id - The PCI device number for this device
+ *
+ */
+#define MPSIOCTL_ADAPTER_TYPE_SAS2 4
+#define MPSIOCTL_ADAPTER_TYPE_SAS2_SSS6200 5
+typedef struct mps_adapter_data
+{
+ uint32_t StructureLength;
+ uint32_t AdapterType;
+ uint32_t MpiPortNumber;
+ uint32_t PCIDeviceHwId;
+ uint32_t PCIDeviceHwRev;
+ uint32_t SubSystemId;
+ uint32_t SubsystemVendorId;
+ uint32_t Reserved1;
+ uint32_t MpiFirmwareVersion;
+ uint32_t BiosVersion;
+ uint8_t DriverVersion[32];
+ uint8_t Reserved2;
+ uint8_t ScsiId;
+ uint16_t Reserved3;
+ mps_pci_bits_t PciInformation;
+} mps_adapter_data_t;
+
+
+typedef struct mps_update_flash
+{
+ uint64_t PtrBuffer;
+ uint32_t ImageChecksum;
+ uint32_t ImageOffset;
+ uint32_t ImageSize;
+ uint32_t ImageType;
+} mps_update_flash_t;
+
+
+#define MPS_PASS_THRU_DIRECTION_NONE 0
+#define MPS_PASS_THRU_DIRECTION_READ 1
+#define MPS_PASS_THRU_DIRECTION_WRITE 2
+#define MPS_PASS_THRU_DIRECTION_BOTH 3
+
+typedef struct mps_pass_thru
+{
+ uint64_t PtrRequest;
+ uint64_t PtrReply;
+ uint64_t PtrData;
+ uint32_t RequestSize;
+ uint32_t ReplySize;
+ uint32_t DataSize;
+ uint32_t DataDirection;
+ uint64_t PtrDataOut;
+ uint32_t DataOutSize;
+ uint32_t Timeout;
+} mps_pass_thru_t;
+
+
+/*
+ * Event queue defines
+ */
+#define MPS_EVENT_QUEUE_SIZE (50) /* Max Events stored in driver */
+#define MPS_MAX_EVENT_DATA_LENGTH (48) /* Size of each event in Dwords */
+
+typedef struct mps_event_query
+{
+ uint16_t Entries;
+ uint16_t Reserved;
+ uint32_t Types[4];
+} mps_event_query_t;
+
+typedef struct mps_event_enable
+{
+ uint32_t Types[4];
+} mps_event_enable_t;
+
+/*
+ * Event record entry for ioctl.
+ */
+typedef struct mps_event_entry
+{
+ uint32_t Type;
+ uint32_t Number;
+ uint32_t Data[MPS_MAX_EVENT_DATA_LENGTH];
+} mps_event_entry_t;
+
+typedef struct mps_event_report
+{
+ uint32_t Size;
+ uint64_t PtrEvents;
+} mps_event_report_t;
+
+
+typedef struct mps_pci_info
+{
+ uint32_t BusNumber;
+ uint8_t DeviceNumber;
+ uint8_t FunctionNumber;
+ uint16_t InterruptVector;
+ uint8_t PciHeader[256];
+} mps_pci_info_t;
+
+
+typedef struct mps_diag_action
+{
+ uint32_t Action;
+ uint32_t Length;
+ uint64_t PtrDiagAction;
+ uint32_t ReturnCode;
+} mps_diag_action_t;
+
+#define MPS_FW_DIAGNOSTIC_UID_NOT_FOUND (0xFF)
+
+#define MPS_FW_DIAG_NEW (0x806E6577)
+
+#define MPS_FW_DIAG_TYPE_REGISTER (0x00000001)
+#define MPS_FW_DIAG_TYPE_UNREGISTER (0x00000002)
+#define MPS_FW_DIAG_TYPE_QUERY (0x00000003)
+#define MPS_FW_DIAG_TYPE_READ_BUFFER (0x00000004)
+#define MPS_FW_DIAG_TYPE_RELEASE (0x00000005)
+
+#define MPS_FW_DIAG_INVALID_UID (0x00000000)
+
+#define MPS_DIAG_SUCCESS 0
+#define MPS_DIAG_FAILURE 1
+
+#define MPS_FW_DIAG_ERROR_SUCCESS (0x00000000)
+#define MPS_FW_DIAG_ERROR_FAILURE (0x00000001)
+#define MPS_FW_DIAG_ERROR_INVALID_PARAMETER (0x00000002)
+#define MPS_FW_DIAG_ERROR_POST_FAILED (0x00000010)
+#define MPS_FW_DIAG_ERROR_INVALID_UID (0x00000011)
+#define MPS_FW_DIAG_ERROR_RELEASE_FAILED (0x00000012)
+#define MPS_FW_DIAG_ERROR_NO_BUFFER (0x00000013)
+#define MPS_FW_DIAG_ERROR_ALREADY_RELEASED (0x00000014)
+
+
+typedef struct mps_fw_diag_register
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t RequestedBufferSize;
+ uint32_t UniqueId;
+} mps_fw_diag_register_t;
+
+typedef struct mps_fw_diag_unregister
+{
+ uint32_t UniqueId;
+} mps_fw_diag_unregister_t;
+
+#define MPS_FW_DIAG_FLAG_APP_OWNED (0x0001)
+#define MPS_FW_DIAG_FLAG_BUFFER_VALID (0x0002)
+#define MPS_FW_DIAG_FLAG_FW_BUFFER_ACCESS (0x0004)
+
+typedef struct mps_fw_diag_query
+{
+ uint8_t ExtendedType;
+ uint8_t BufferType;
+ uint16_t ApplicationFlags;
+ uint32_t DiagnosticFlags;
+ uint32_t ProductSpecific[23];
+ uint32_t TotalBufferSize;
+ uint32_t DriverAddedBufferSize;
+ uint32_t UniqueId;
+} mps_fw_diag_query_t;
+
+typedef struct mps_fw_diag_release
+{
+ uint32_t UniqueId;
+} mps_fw_diag_release_t;
+
+#define MPS_FW_DIAG_FLAG_REREGISTER (0x0001)
+#define MPS_FW_DIAG_FLAG_FORCE_RELEASE (0x0002)
+
+typedef struct mps_diag_read_buffer
+{
+ uint8_t Status;
+ uint8_t Reserved;
+ uint16_t Flags;
+ uint32_t StartingOffset;
+ uint32_t BytesToRead;
+ uint32_t UniqueId;
+ uint64_t PtrDataBuffer;
+} mps_diag_read_buffer_t;
+
+/*
+ * Register Access
+ */
+#define REG_IO_READ 1
+#define REG_IO_WRITE 2
+#define REG_MEM_READ 3
+#define REG_MEM_WRITE 4
+
+typedef struct mps_reg_access
+{
+ uint32_t Command;
+ uint32_t RegOffset;
+ uint32_t RegData;
+} mps_reg_access_t;
+
+typedef struct mps_btdh_mapping
+{
+ uint16_t TargetID;
+ uint16_t Bus;
+ uint16_t DevHandle;
+ uint16_t Reserved;
+} mps_btdh_mapping_t;
+
+#define MPSIO_MPS_COMMAND_FLAG_VERBOSE 0x01
+#define MPSIO_MPS_COMMAND_FLAG_DEBUG 0x02
+#define MPSIO_READ_CFG_HEADER _IOWR('M', 200, struct mps_cfg_page_req)
+#define MPSIO_READ_CFG_PAGE _IOWR('M', 201, struct mps_cfg_page_req)
+#define MPSIO_READ_EXT_CFG_HEADER _IOWR('M', 202, struct mps_ext_cfg_page_req)
+#define MPSIO_READ_EXT_CFG_PAGE _IOWR('M', 203, struct mps_ext_cfg_page_req)
+#define MPSIO_WRITE_CFG_PAGE _IOWR('M', 204, struct mps_cfg_page_req)
+#define MPSIO_RAID_ACTION _IOWR('M', 205, struct mps_raid_action)
+#define MPSIO_MPS_COMMAND _IOWR('M', 210, struct mps_usr_command)
+
+#define MPTIOCTL ('I')
+#define MPTIOCTL_GET_ADAPTER_DATA _IOWR(MPTIOCTL, 1,\
+ struct mps_adapter_data)
+#define MPTIOCTL_UPDATE_FLASH _IOWR(MPTIOCTL, 2,\
+ struct mps_update_flash)
+#define MPTIOCTL_RESET_ADAPTER _IO(MPTIOCTL, 3)
+#define MPTIOCTL_PASS_THRU _IOWR(MPTIOCTL, 4,\
+ struct mps_pass_thru)
+#define MPTIOCTL_EVENT_QUERY _IOWR(MPTIOCTL, 5,\
+ struct mps_event_query)
+#define MPTIOCTL_EVENT_ENABLE _IOWR(MPTIOCTL, 6,\
+ struct mps_event_enable)
+#define MPTIOCTL_EVENT_REPORT _IOWR(MPTIOCTL, 7,\
+ struct mps_event_report)
+#define MPTIOCTL_GET_PCI_INFO _IOWR(MPTIOCTL, 8,\
+ struct mps_pci_info)
+#define MPTIOCTL_DIAG_ACTION _IOWR(MPTIOCTL, 9,\
+ struct mps_diag_action)
+#define MPTIOCTL_REG_ACCESS _IOWR(MPTIOCTL, 10,\
+ struct mps_reg_access)
+#define MPTIOCTL_BTDH_MAPPING _IOWR(MPTIOCTL, 11,\
+ struct mps_btdh_mapping)
+
+#endif /* !_MPS_IOCTL_H_ */
diff --git a/usr.sbin/mpsutil/mps_show.c b/usr.sbin/mpsutil/mps_show.c
new file mode 100644
index 0000000..d6a7840
--- /dev/null
+++ b/usr.sbin/mpsutil/mps_show.c
@@ -0,0 +1,772 @@
+/*-
+ * Copyright (c) 2015 Netflix, Inc.
+ * All rights reserved.
+ * Written by: Scott Long <scottl@freebsd.org>
+ *
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <err.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "mpsutil.h"
+
+static char * get_device_speed(uint8_t rate);
+static char * get_device_type(uint32_t di);
+static int show_all(int ac, char **av);
+static int show_devices(int ac, char **av);
+static int show_enclosures(int ac, char **av);
+static int show_expanders(int ac, char **av);
+
+MPS_TABLE(top, show);
+
+#define STANDALONE_STATE "ONLINE"
+
+static int
+show_adapter(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0;
+ MPI2_CONFIG_PAGE_SASIOUNIT_1 *sas1;
+ MPI2_SAS_IO_UNIT0_PHY_DATA *phy0;
+ MPI2_SAS_IO_UNIT1_PHY_DATA *phy1;
+ MPI2_CONFIG_PAGE_MAN_0 *man0;
+ MPI2_CONFIG_PAGE_BIOS_3 *bios3;
+ MPI2_IOC_FACTS_REPLY *facts;
+ U16 IOCStatus;
+ char *speed, *minspeed, *maxspeed, *isdisabled, *type;
+ char devhandle[5], ctrlhandle[5];
+ int error, fd, v, i;
+
+ if (ac != 1) {
+ warnx("show adapter: extra arguments");
+ return (EINVAL);
+ }
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ man0 = mps_read_man_page(fd, 0, NULL);
+ if (man0 == NULL) {
+ error = errno;
+ warn("Failed to get controller info");
+ return (error);
+ }
+ if (man0->Header.PageLength < sizeof(*man0) / 4) {
+ warnx("Invalid controller info");
+ return (EINVAL);
+ }
+ printf("mp%s%d Adapter:\n", is_mps ? "s": "r", mps_unit);
+ printf(" Board Name: %.16s\n", man0->BoardName);
+ printf(" Board Assembly: %.16s\n", man0->BoardAssembly);
+ printf(" Chip Name: %.16s\n", man0->ChipName);
+ printf(" Chip Revision: %.16s\n", man0->ChipRevision);
+ free(man0);
+
+ bios3 = mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_BIOS, 3, 0, NULL);
+ if (bios3 == NULL) {
+ error = errno;
+ warn("Failed to get BIOS page 3 info");
+ return (error);
+ }
+ v = bios3->BiosVersion;
+ printf(" BIOS Revision: %d.%02d.%02d.%02d\n",
+ ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
+ ((v & 0xff00) >> 8), (v & 0xff));
+ free(bios3);
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ printf("could not get controller IOCFacts\n");
+ close(fd);
+ return (errno);
+ }
+ v = facts->FWVersion.Word;
+ printf("Firmware Revision: %d.%02d.%02d.%02d\n",
+ ((v & 0xff000000) >> 24), ((v &0xff0000) >> 16),
+ ((v & 0xff00) >> 8), (v & 0xff));
+ printf(" Integrated RAID: %s\n",
+ (facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)
+ ? "yes" : "no");
+ free(facts);
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ sas0 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+ MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
+ if (sas0 == NULL) {
+ error = errno;
+ warn("Error retrieving SAS IO Unit page %d", IOCStatus);
+ return (error);
+ }
+
+ sas1 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+ MPI2_SASIOUNITPAGE1_PAGEVERSION, 1, 0, &IOCStatus);
+ if (sas0 == NULL) {
+ error = errno;
+ warn("Error retrieving SAS IO Unit page %d", IOCStatus);
+ return (error);
+ }
+ printf("\n");
+
+ printf("%-8s%-12s%-11s%-10s%-8s%-7s%-7s%s\n", "PhyNum", "CtlrHandle",
+ "DevHandle", "Disabled", "Speed", "Min", "Max", "Device");
+ for (i = 0; i < sas0->NumPhys; i++) {
+ phy0 = &sas0->PhyData[i];
+ phy1 = &sas1->PhyData[i];
+ if (phy0->PortFlags &
+ MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
+ printf("Discovery still in progress\n");
+ continue;
+ }
+ if (phy0->PhyFlags & MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED)
+ isdisabled = "Y";
+ else
+ isdisabled = "N";
+
+ minspeed = get_device_speed(phy1->MaxMinLinkRate);
+ maxspeed = get_device_speed(phy1->MaxMinLinkRate >> 4);
+ type = get_device_type(phy0->ControllerPhyDeviceInfo);
+
+ if (phy0->AttachedDevHandle != 0) {
+ snprintf(devhandle, 5, "%04x", phy0->AttachedDevHandle);
+ snprintf(ctrlhandle, 5, "%04x",
+ phy0->ControllerDevHandle);
+ speed = get_device_speed(phy0->NegotiatedLinkRate);
+ } else {
+ snprintf(devhandle, 5, " ");
+ snprintf(ctrlhandle, 5, " ");
+ speed = " ";
+ }
+ printf("%-8d%-12s%-11s%-10s%-8s%-7s%-7s%s\n",
+ i, ctrlhandle, devhandle, isdisabled, speed, minspeed,
+ maxspeed, type);
+ }
+ free(sas0);
+ free(sas1);
+ printf("\n");
+ close(fd);
+ return (0);
+}
+
+MPS_COMMAND(show, adapter, show_adapter, "", "display controller information")
+
+static int
+show_iocfacts(int ac, char **av)
+{
+ MPI2_IOC_FACTS_REPLY *facts;
+ int error, fd;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ if ((facts = mps_get_iocfacts(fd)) == NULL) {
+ printf("could not get controller IOCFacts\n");
+ close(fd);
+ return (errno);
+ }
+
+ printf(" MaxChainDepth: %d\n", facts->MaxChainDepth);
+ printf(" WhoInit: 0x%x\n", facts->WhoInit);
+ printf(" NumberOfPorts: %d\n", facts->NumberOfPorts);
+ printf(" MaxMSIxVectors: %d\n", facts->MaxMSIxVectors);
+ printf(" RequestCredit: %d\n", facts->RequestCredit);
+ printf(" ProductID: 0x%x\n", facts->ProductID);
+ printf(" IOCCapabilities: 0x%x\n", facts->IOCCapabilities);
+ printf(" FWVersion: 0x%08x\n", facts->FWVersion.Word);
+ printf(" IOCRequestFrameSize: %d\n", facts->IOCRequestFrameSize);
+ printf(" MaxInitiators: %d\n", facts->MaxInitiators);
+ printf(" MaxTargets: %d\n", facts->MaxTargets);
+ printf(" MaxSasExpanders: %d\n", facts->MaxSasExpanders);
+ printf(" MaxEnclosures: %d\n", facts->MaxEnclosures);
+ printf(" ProtocolFlags: 0x%x\n", facts->ProtocolFlags);
+ printf(" HighPriorityCredit: %d\n", facts->HighPriorityCredit);
+ printf("MaxRepDescPostQDepth: %d\n",
+ facts->MaxReplyDescriptorPostQueueDepth);
+ printf(" ReplyFrameSize: %d\n", facts->ReplyFrameSize);
+ printf(" MaxVolumes: %d\n", facts->MaxVolumes);
+ printf(" MaxDevHandle: %d\n", facts->MaxDevHandle);
+ printf("MaxPersistentEntries: %d\n", facts->MaxPersistentEntries);
+ printf(" MinDevHandle: %d\n", facts->MinDevHandle);
+
+ free(facts);
+ return (0);
+}
+
+MPS_COMMAND(show, iocfacts, show_iocfacts, "", "Show IOC Facts Message");
+
+static int
+show_adapters(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_MAN_0 *man0;
+ MPI2_IOC_FACTS_REPLY *facts;
+ int unit, fd, error;
+
+ printf("Device Name\t Chip Name Board Name Firmware\n");
+ for (unit = 0; unit < MPS_MAX_UNIT; unit++) {
+ fd = mps_open(unit);
+ if (fd < 0)
+ continue;
+ facts = mps_get_iocfacts(fd);
+ if (facts == NULL) {
+ error = errno;
+ warn("Faled to get controller iocfacts");
+ close(fd);
+ return (error);
+ }
+ man0 = mps_read_man_page(fd, 0, NULL);
+ if (man0 == NULL) {
+ error = errno;
+ warn("Failed to get controller info");
+ close(fd);
+ return (error);
+ }
+ if (man0->Header.PageLength < sizeof(*man0) / 4) {
+ warnx("Invalid controller info");
+ close(fd);
+ free(man0);
+ return (EINVAL);
+ }
+ printf("/dev/mp%s%d\t%16s %16s %08x\n",
+ is_mps ? "s": "r", unit,
+ man0->ChipName, man0->BoardName, facts->FWVersion.Word);
+ free(man0);
+ free(facts);
+ close(fd);
+ }
+ return (0);
+}
+MPS_COMMAND(show, adapters, show_adapters, "", "Show a summary of all adapters");
+
+static char *
+get_device_type(uint32_t di)
+{
+
+ if (di & 0x4000)
+ return ("SEP Target ");
+ if (di & 0x2000)
+ return ("ATAPI Target ");
+ if (di & 0x400)
+ return ("SAS Target ");
+ if (di & 0x200)
+ return ("STP Target ");
+ if (di & 0x100)
+ return ("SMP Target ");
+ if (di & 0x80)
+ return ("SATA Target ");
+ if (di & 0x70)
+ return ("SAS Initiator ");
+ if (di & 0x8)
+ return ("SATA Initiator");
+ if ((di & 0x7) == 0)
+ return ("No Device ");
+ return ("Unknown Device");
+}
+
+static char *
+get_enc_type(uint32_t flags, int *issep)
+{
+ char *type;
+
+ *issep = 0;
+ switch (flags & 0xf) {
+ case 0x01:
+ type = "Direct Attached SES-2";
+ *issep = 1;
+ break;
+ case 0x02:
+ type = "Direct Attached SGPIO";
+ break;
+ case 0x03:
+ type = "Expander SGPIO";
+ break;
+ case 0x04:
+ type = "External SES-2";
+ *issep = 1;
+ break;
+ case 0x05:
+ type = "Direct Attached GPIO";
+ break;
+ case 0x0:
+ default:
+ return ("Unknown");
+ }
+
+ return (type);
+}
+
+static char *
+mps_device_speed[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "1.5",
+ "3.0",
+ "6.0",
+ "12 "
+};
+
+static char *
+get_device_speed(uint8_t rate)
+{
+ char *speed;
+
+ rate &= 0xf;
+ if (rate >= sizeof(mps_device_speed))
+ return ("Unk");
+
+ if ((speed = mps_device_speed[rate]) == NULL)
+ return ("???");
+ return (speed);
+}
+
+static char *
+mps_page_name[] = {
+ "IO Unit",
+ "IOC",
+ "BIOS",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "RAID Volume",
+ "Manufacturing",
+ "RAID Physical Disk",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "SAS IO Unit",
+ "SAS Expander",
+ "SAS Device",
+ "SAS PHY",
+ "Log",
+ "Enclosure",
+ "RAID Configuration",
+ "Driver Persistent Mapping",
+ "SAS Port",
+ "Ethernet Port",
+ "Extended Manufacturing"
+};
+
+static char *
+get_page_name(u_int page)
+{
+ char *name;
+
+ if (page >= sizeof(mps_page_name))
+ return ("Unknown");
+ if ((name = mps_page_name[page]) == NULL)
+ return ("Unknown");
+ return (name);
+}
+
+static int
+show_all(int ac, char **av)
+{
+ int error;
+
+ printf("Adapter:\n");
+ error = show_adapter(ac, av);
+ printf("Devices:\n");
+ error = show_devices(ac, av);
+ printf("Enclosures:\n");
+ error = show_enclosures(ac, av);
+ printf("Expanders:\n");
+ error = show_expanders(ac, av);
+ return (error);
+}
+MPS_COMMAND(show, all, show_all, "", "Show all devices");
+
+static int
+show_devices(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_SASIOUNIT_0 *sas0;
+ MPI2_SAS_IO_UNIT0_PHY_DATA *phydata;
+ MPI2_CONFIG_PAGE_SAS_DEV_0 *device;
+ MPI2_CONFIG_PAGE_EXPANDER_1 *exp1;
+ uint16_t IOCStatus, handle, bus, target;
+ char *type, *speed, enchandle[5], slot[3], bt[8];
+ char buf[256];
+ int fd, error, nphys;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ sas0 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT,
+ MPI2_SASIOUNITPAGE0_PAGEVERSION, 0, 0, &IOCStatus);
+ if (sas0 == NULL) {
+ error = errno;
+ warn("Error retrieving SAS IO Unit page %d", IOCStatus);
+ return (error);
+ }
+ nphys = sas0->NumPhys;
+
+ printf("B____%-5s%-17s%-8s%-10s%-14s%-6s%-5s%-6s%s\n",
+ "T", "SAS Address", "Handle", "Parent", "Device", "Speed",
+ "Enc", "Slot", "Wdt");
+ handle = 0xffff;
+ while (1) {
+ device = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE,
+ MPI2_SASDEVICE0_PAGEVERSION, 0,
+ MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE | handle,
+ &IOCStatus);
+ if (device == NULL) {
+ if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ error = errno;
+ warn("Error retrieving device page");
+ return (error);
+ }
+ handle = device->DevHandle;
+
+ if (device->ParentDevHandle == 0x0) {
+ free(device);
+ continue;
+ }
+
+ bus = 0xffff;
+ target = 0xffff;
+ error = mps_map_btdh(fd, &handle, &bus, &target);
+ if (error) {
+ free(device);
+ continue;
+ }
+ if ((bus == 0xffff) || (target == 0xffff))
+ snprintf(bt, sizeof(bt), " ");
+ else
+ snprintf(bt, sizeof(bt), "%02d %02d", bus, target);
+
+ type = get_device_type(device->DeviceInfo);
+
+ if (device->PhyNum < nphys) {
+ phydata = &sas0->PhyData[device->PhyNum];
+ speed = get_device_speed(phydata->NegotiatedLinkRate);
+ } else if (device->ParentDevHandle > 0) {
+ exp1 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
+ MPI2_SASEXPANDER1_PAGEVERSION, 1,
+ MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
+ (device->PhyNum <<
+ MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
+ device->ParentDevHandle, &IOCStatus);
+ if (exp1 == NULL) {
+ if (IOCStatus != MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
+ error = errno;
+ warn("Error retrieving expander page 1: 0x%x",
+ IOCStatus);
+ return (error);
+ }
+ speed = " ";
+ } else {
+ speed = get_device_speed(exp1->NegotiatedLinkRate);
+ free(exp1);
+ }
+ } else
+ speed = " ";
+
+ if (device->EnclosureHandle != 0) {
+ snprintf(enchandle, 5, "%04x", device->EnclosureHandle);
+ snprintf(slot, 3, "%02d", device->Slot);
+ } else {
+ snprintf(enchandle, 5, " ");
+ snprintf(slot, 3, " ");
+ }
+ printf("%-10s", bt);
+ snprintf(buf, sizeof(buf), "%08x%08x", device->SASAddress.High,
+ device->SASAddress.Low);
+ printf("%-17s", buf);
+ snprintf(buf, sizeof(buf), "%04x", device->DevHandle);
+ printf("%-8s", buf);
+ snprintf(buf, sizeof(buf), "%04x", device->ParentDevHandle);
+ printf("%-10s", buf);
+ printf("%-14s%-6s%-5s%-6s%d\n", type, speed,
+ enchandle, slot, device->MaxPortConnections);
+ free(device);
+ }
+ printf("\n");
+ free(sas0);
+ close(fd);
+ return (0);
+}
+MPS_COMMAND(show, devices, show_devices, "", "Show attached devices");
+
+static int
+show_enclosures(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 *enc;
+ char *type, sepstr[5];
+ uint16_t IOCStatus, handle;
+ int fd, error, issep;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ printf("Slots Logical ID SEPHandle EncHandle Type\n");
+ handle = 0xffff;
+ while (1) {
+ enc = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE,
+ MPI2_SASENCLOSURE0_PAGEVERSION, 0,
+ MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE | handle,
+ &IOCStatus);
+ if (enc == NULL) {
+ if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ error = errno;
+ warn("Error retrieving enclosure page");
+ return (error);
+ }
+ type = get_enc_type(enc->Flags, &issep);
+ if (issep == 0)
+ snprintf(sepstr, 5, " ");
+ else
+ snprintf(sepstr, 5, "%04x", enc->SEPDevHandle);
+ printf(" %.2d %08x%08x %s %04x %s\n",
+ enc->NumSlots, enc->EnclosureLogicalID.High,
+ enc->EnclosureLogicalID.Low, sepstr, enc->EnclosureHandle,
+ type);
+ handle = enc->EnclosureHandle;
+ free(enc);
+ }
+ printf("\n");
+ close(fd);
+ return (0);
+}
+MPS_COMMAND(show, enclosures, show_enclosures, "", "Show attached enclosures");
+
+static int
+show_expanders(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_EXPANDER_0 *exp0;
+ MPI2_CONFIG_PAGE_EXPANDER_1 *exp1;
+ uint16_t IOCStatus, handle;
+ char enchandle[5], parent[5], rphy[3], rhandle[5];
+ char *speed, *min, *max, *type;
+ int fd, error, nphys, i;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ printf("NumPhys SAS Address DevHandle Parent EncHandle SAS Level\n");
+ handle = 0xffff;
+ while (1) {
+ exp0 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
+ MPI2_SASEXPANDER0_PAGEVERSION, 0,
+ MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL | handle,
+ &IOCStatus);
+ if (exp0 == NULL) {
+ if (IOCStatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ error = errno;
+ warn("Error retrieving expander page 0");
+ return (error);
+ }
+
+ nphys = exp0->NumPhys;
+ handle = exp0->DevHandle;
+
+ if (exp0->EnclosureHandle == 0x00)
+ snprintf(enchandle, 5, " ");
+ else
+ snprintf(enchandle, 5, "%04d", exp0->EnclosureHandle);
+ if (exp0->ParentDevHandle == 0x0)
+ snprintf(parent, 5, " ");
+ else
+ snprintf(parent, 5, "%04x", exp0->ParentDevHandle);
+ printf(" %02d %08x%08x %04x %s %s %d\n",
+ exp0->NumPhys, exp0->SASAddress.High, exp0->SASAddress.Low,
+ exp0->DevHandle, parent, enchandle, exp0->SASLevel);
+
+ printf("\n");
+ printf(" Phy RemotePhy DevHandle Speed Min Max Device\n");
+ for (i = 0; i < nphys; i++) {
+ exp1 = mps_read_extended_config_page(fd,
+ MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER,
+ MPI2_SASEXPANDER1_PAGEVERSION, 1,
+ MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
+ (i << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) |
+ exp0->DevHandle, &IOCStatus);
+ if (exp1 == NULL) {
+ if (IOCStatus !=
+ MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ warn("Error retrieving expander pg 1");
+ continue;
+ }
+ type = get_device_type(exp1->AttachedDeviceInfo);
+ if ((exp1->AttachedDeviceInfo &0x7) == 0) {
+ speed = " ";
+ snprintf(rphy, 3, " ");
+ snprintf(rhandle, 5, " ");
+ } else {
+ speed = get_device_speed(
+ exp1->NegotiatedLinkRate);
+ snprintf(rphy, 3, "%02d",
+ exp1->AttachedPhyIdentifier);
+ snprintf(rhandle, 5, "%04x",
+ exp1->AttachedDevHandle);
+ }
+ min = get_device_speed(exp1->HwLinkRate);
+ max = get_device_speed(exp1->HwLinkRate >> 4);
+ printf(" %02d %s %s %s %s %s %s\n", exp1->Phy, rphy, rhandle, speed, min, max, type);
+
+ free(exp1);
+ }
+ free(exp0);
+ }
+
+ printf("\n");
+ close(fd);
+ return (0);
+}
+
+MPS_COMMAND(show, expanders, show_expanders, "", "Show attached expanders");
+
+static int
+show_cfgpage(int ac, char **av)
+{
+ MPI2_CONFIG_PAGE_HEADER *hdr;
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER *ehdr;
+ void *data;
+ uint32_t addr;
+ uint16_t IOCStatus;
+ uint8_t page, num;
+ int fd, error, len, attrs;
+ char *pgname, *pgattr;
+
+ fd = mps_open(mps_unit);
+ if (fd < 0) {
+ error = errno;
+ warn("mps_open");
+ return (error);
+ }
+
+ addr = 0;
+ num = 0;
+ page = 0;
+
+ switch (ac) {
+ case 4:
+ addr = (uint32_t)strtoul(av[3], NULL, 0);
+ case 3:
+ num = (uint8_t)strtoul(av[2], NULL, 0);
+ case 2:
+ page = (uint8_t)strtoul(av[1], NULL, 0);
+ break;
+ default:
+ errno = EINVAL;
+ warn("cfgpage: not enough arguments");
+ return (EINVAL);
+ }
+
+ if (page >= 0x10)
+ data = mps_read_extended_config_page(fd, page, 0, num, addr,
+ &IOCStatus);
+ else
+ data = mps_read_config_page(fd, page, num, addr, &IOCStatus);
+
+ if (data == NULL) {
+ error = errno;
+ warn("Error retrieving cfg page: %s\n",
+ mps_ioc_status(IOCStatus));
+ return (error);
+ }
+
+ if (page >= 0x10) {
+ ehdr = data;
+ len = ehdr->ExtPageLength * 4;
+ page = ehdr->ExtPageType;
+ attrs = ehdr->PageType >> 4;
+ } else {
+ hdr = data;
+ len = hdr->PageLength * 4;
+ page = hdr->PageType & 0xf;
+ attrs = hdr->PageType >> 4;
+ }
+
+ pgname = get_page_name(page);
+ if (attrs == 0)
+ pgattr = "Read-only";
+ else if (attrs == 1)
+ pgattr = "Read-Write";
+ else if (attrs == 2)
+ pgattr = "Read-Write Persistent";
+ else
+ pgattr = "Unknown Page Attribute";
+
+ printf("Page 0x%x: %s %d, %s\n", page, pgname, num, pgattr);
+ hexdump(data, len, NULL, HD_REVERSED | 4);
+ free(data);
+ return (0);
+}
+
+MPS_COMMAND(show, cfgpage, show_cfgpage, "page [num] [addr]", "Display config page");
diff --git a/usr.sbin/mpsutil/mpsutil.8 b/usr.sbin/mpsutil/mpsutil.8
new file mode 100644
index 0000000..6634b37
--- /dev/null
+++ b/usr.sbin/mpsutil/mpsutil.8
@@ -0,0 +1,165 @@
+.\"
+.\" Copyright (c) Baptiste Daroussin <bapt@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 17, 2015
+.Dt MPSUTIL 8
+.Os
+.Sh NAME
+.Nm mpsutil ,
+.Nm mprutil
+.Nd Utility for managing LSI Fusion-MPT 2/3 controllers
+.Sh SYNOPSIS
+.Nm
+.Cm version
+.Nm
+.Op Fl u Ar unit
+.Cm show adapter
+.Nm
+.Op Fl u Ar unit
+.Cm show adapters
+.Nm
+.Op Fl u Ar unit
+.Cm show all
+.Nm
+.Op Fl u Ar unit
+.Cm show cfgpages page
+.Op Ar num
+.Op Ar addr
+.Nm
+.Op Fl u Ar unit
+.Cm show devices
+.Nm
+.Op Fl u Ar unit
+.Cm show enclosures
+.Nm
+.Op Fl u Ar unit
+.Cm show expanders
+.Nm
+.Op Fl u Ar unit
+.Cm show iocfacts
+.Nm
+.Op Fl u Ar unit
+.Cm flash save
+.Op Ar firmware Ns | Ns Ar bios
+.Op Ar file
+.Nm
+.Op Fl u Ar unit
+.Cm flash update
+.Op Ar firmware Ns | Ns Ar bios
+.Ar file
+.Sh DESCRIPTION
+The
+.Nm
+utility can be used to display or modify various parameters on LSI
+Fusion-MPS 2 controllers.
+.Pp
+The
+.Nm mprutil
+utility can be used to display or modify various parameters on LSI
+Fusion-MPS 3 controllers.
+.Pp
+The
+.Nm mprutil
+utility behave identically to
+.Nm .
+(same program)
+.Pp
+Each invocation of
+.Nm
+consists of zero or more global options followed by a command.
+Commands may support additional optional or required arguments after the
+command.
+.Pp
+Currently one global option is supported:
+.Bl -tag -width indent
+.It Fl u Ar unit
+.Ar unit
+specifies the unit of the controller to work with.
+If no unit is specified,
+then unit 0 is used.
+.El
+.Pp
+The
+.Nm
+utility supports several different groups of commands.
+The first group of commands provide information about the controller.
+The second group of commands are used to manager controller-wide operations.
+.Pp
+The informational commands include:
+.Bl -tag -width indent
+.It Cm version
+Displays the version of
+.Nm .
+.It Cm show adapter
+Displays information about the controller such as the model number or firmware
+version.
+.It Cm show adapters
+Displays a summary of all adapters.
+.It Cm show all
+Displays all devices, expanders and enclosures.
+.It Cm show devices
+Displays all devices.
+.It Cm show expanders
+Displays all expanders.
+.It Cm show enclosures
+Displays all enclosures.
+.It Cm show iocfacts
+Displays IOC Facts messages.
+.It Cm show cfgpage page Oo Ar num Oc Op Ar addr
+Show IOC Facts Message
+.El
+.Pp
+Controller management commands include:
+.Bl -tag -width indent
+.It Cm flash save Oo Ar firmware Ns | Ns Ar bios Oc Op Ar file
+Save the
+.Ar firmware
+or
+.Ar bios
+from the controller into a local
+.Ar file .
+If no
+.Ar file
+is specified then the file will be named
+.Pa firmware
+or
+.Pa bios .
+.It Cm flash update Oo Ar firmware Ns | Ns Ar bios Oc Ar file
+Replace the
+.Ar firmware
+or
+.Ar bios
+from the controller with the one specified via
+.Ar file .
+.El
+.Sh SEE ALSO
+.Xr mpr 4 ,
+.Xr mps 4
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 11.0 .
diff --git a/usr.sbin/mpsutil/mpsutil.c b/usr.sbin/mpsutil/mpsutil.c
new file mode 100644
index 0000000..666a46e
--- /dev/null
+++ b/usr.sbin/mpsutil/mpsutil.c
@@ -0,0 +1,207 @@
+/*-
+ * Copyright (c) 2015 Netflix, Inc.
+ * All rights reserved.
+ * Written by: Scott Long <scottl@freebsd.org>
+ *
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "mpsutil.h"
+
+SET_DECLARE(MPS_DATASET(top), struct mpsutil_command);
+SET_DECLARE(MPS_DATASET(usage), struct mpsutil_usage);
+
+int mps_unit;
+int is_mps;
+
+static void
+usage(void)
+{
+ struct mpsutil_usage **cmd;
+ const char *args, *desc;
+
+ fprintf(stderr, "usage: %s [-u unit] <command> ...\n\n", getprogname());
+ fprintf(stderr, "Commands include:\n");
+ SET_FOREACH(cmd, MPS_DATASET(usage)) {
+ if (*cmd == NULL)
+ fprintf(stderr, "\n");
+ else
+ (*cmd)->handler(&args, &desc);
+ if (strncmp((*cmd)->set, "top", 3) == 0)
+ fprintf(stderr, "%s %-30s\t%s\n",
+ (*cmd)->name, args, desc);
+ else
+ fprintf(stderr, "%s %s %-30s\t%s\n",
+ (*cmd)->set, (*cmd)->name, args, desc);
+ }
+ exit(1);
+}
+
+static int
+version(int ac, char **av)
+{
+
+ printf("%s: version %s", MPSUTIL_VERSION, getprogname());
+#ifdef DEBUG
+ printf(" (DEBUG)");
+#endif
+ printf("\n");
+ return (0);
+}
+
+MPS_COMMAND(top, version, version, "", "version")
+
+int
+main(int ac, char **av)
+{
+ struct mpsutil_command **cmd;
+ int ch;
+
+ is_mps = !strcmp(getprogname(), "mpsutil");
+
+ while ((ch = getopt(ac, av, "u:h?")) != -1) {
+ switch (ch) {
+ case 'u':
+ mps_unit = atoi(optarg);
+ break;
+ case 'h':
+ case '?':
+ usage();
+ return (1);
+ }
+ }
+
+ av += optind;
+ ac -= optind;
+
+ /* getopt() eats av[0], so we can't use mpt_table_handler() directly. */
+ if (ac == 0) {
+ usage();
+ return (1);
+ }
+
+ SET_FOREACH(cmd, MPS_DATASET(top)) {
+ if (strcmp((*cmd)->name, av[0]) == 0) {
+ if ((*cmd)->handler(ac, av))
+ return (1);
+ else
+ return (0);
+ }
+ }
+ warnx("Unknown command %s.", av[0]);
+ return (1);
+}
+
+int
+mps_table_handler(struct mpsutil_command **start, struct mpsutil_command **end,
+ int ac, char **av)
+{
+ struct mpsutil_command **cmd;
+
+ if (ac < 2) {
+ warnx("The %s command requires a sub-command.", av[0]);
+ return (EINVAL);
+ }
+ for (cmd = start; cmd < end; cmd++) {
+ if (strcmp((*cmd)->name, av[1]) == 0)
+ return ((*cmd)->handler(ac - 1, av + 1));
+ }
+
+ warnx("%s is not a valid sub-command of %s.", av[1], av[0]);
+ return (ENOENT);
+}
+
+void
+hexdump(const void *ptr, int length, const char *hdr, int flags)
+{
+ int i, j, k;
+ int cols;
+ const unsigned char *cp;
+ char delim;
+
+ if ((flags & HD_DELIM_MASK) != 0)
+ delim = (flags & HD_DELIM_MASK) >> 8;
+ else
+ delim = ' ';
+
+ if ((flags & HD_COLUMN_MASK) != 0)
+ cols = flags & HD_COLUMN_MASK;
+ else
+ cols = 16;
+
+ cp = ptr;
+ for (i = 0; i < length; i+= cols) {
+ if (hdr != NULL)
+ printf("%s", hdr);
+
+ if ((flags & HD_OMIT_COUNT) == 0)
+ printf("%04x ", i);
+
+ if ((flags & HD_OMIT_HEX) == 0) {
+ for (j = 0; j < cols; j++) {
+ if (flags & HD_REVERSED)
+ k = i + (cols - 1 - j);
+ else
+ k = i + j;
+ if (k < length)
+ printf("%c%02x", delim, cp[k]);
+ else
+ printf(" ");
+ }
+ }
+
+ if ((flags & HD_OMIT_CHARS) == 0) {
+ printf(" |");
+ for (j = 0; j < cols; j++) {
+ if (flags & HD_REVERSED)
+ k = i + (cols - 1 - j);
+ else
+ k = i + j;
+ if (k >= length)
+ printf(" ");
+ else if (cp[k] >= ' ' && cp[k] <= '~')
+ printf("%c", cp[k]);
+ else
+ printf(".");
+ }
+ printf("|");
+ }
+ printf("\n");
+ }
+}
diff --git a/usr.sbin/mpsutil/mpsutil.h b/usr.sbin/mpsutil/mpsutil.h
new file mode 100644
index 0000000..46c7d44
--- /dev/null
+++ b/usr.sbin/mpsutil/mpsutil.h
@@ -0,0 +1,147 @@
+/*-
+ * Copyright (c) 2008 Yahoo!, Inc.
+ * All rights reserved.
+ * Written by: John Baldwin <jhb@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of any co-contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __MPSUTIL_H__
+#define __MPSUTIL_H__
+
+#include <sys/cdefs.h>
+#include <sys/linker_set.h>
+#include <stdbool.h>
+
+#include <dev/mps/mpi/mpi2_type.h>
+#include <dev/mps/mpi/mpi2.h>
+#include <dev/mps/mpi/mpi2_cnfg.h>
+#include <dev/mps/mpi/mpi2_raid.h>
+#include <dev/mps/mpi/mpi2_ioc.h>
+
+#define MPSUTIL_VERSION "1.0.0"
+
+#define IOC_STATUS_SUCCESS(status) \
+ (((status) & MPI2_IOCSTATUS_MASK) == MPI2_IOCSTATUS_SUCCESS)
+
+struct mpsutil_command {
+ const char *name;
+ int (*handler)(int ac, char **av);
+};
+struct mpsutil_usage {
+ const char *set;
+ const char *name;
+ void (*handler)(const char **, const char**);
+};
+
+#define MPS_DATASET(name) mpsutil_ ## name ## _table
+
+#define MPS_COMMAND(set, name, function, args, desc) \
+ static struct mpsutil_command function ## _mpsutil_command = \
+ { #name, function }; \
+ DATA_SET(MPS_DATASET(set), function ## _mpsutil_command); \
+ static void \
+ function ## _usage(const char **a3, const char **a4) \
+ { \
+ *a3 = args; \
+ *a4 = desc; \
+ return; \
+ }; \
+ static struct mpsutil_usage function ## _mpsutil_usage = \
+ { #set, #name, function ## _usage }; \
+ DATA_SET(MPS_DATASET(usage), function ## _mpsutil_usage);
+
+#define _MPS_COMMAND(set, name, function) \
+ static struct mpsutil_command function ## _mpsutil_command = \
+ { #name, function }; \
+ DATA_SET(MPS_DATASET(set), function ## _mpsutil_command);
+
+#define MPS_TABLE(set, name) \
+ SET_DECLARE(MPS_DATASET(name), struct mpsutil_command); \
+ \
+ static int \
+ mpsutil_ ## name ## _table_handler(int ac, char **av) \
+ { \
+ return (mps_table_handler(SET_BEGIN(MPS_DATASET(name)), \
+ SET_LIMIT(MPS_DATASET(name)), ac, av)); \
+ } \
+ _MPS_COMMAND(set, name, mpsutil_ ## name ## _table_handler)
+
+extern int mps_unit;
+extern int is_mps;
+#define MPS_MAX_UNIT 10
+
+void hexdump(const void *ptr, int length, const char *hdr, int flags);
+#define HD_COLUMN_MASK 0xff
+#define HD_DELIM_MASK 0xff00
+#define HD_OMIT_COUNT (1 << 16)
+#define HD_OMIT_HEX (1 << 17)
+#define HD_OMIT_CHARS (1 << 18)
+#define HD_REVERSED (1 << 19)
+
+int mps_open(int unit);
+int mps_table_handler(struct mpsutil_command **start,
+ struct mpsutil_command **end, int ac, char **av);
+int mps_user_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *buffer, int len, uint32_t flags);
+int mps_pass_command(int fd, void *req, uint32_t req_len, void *reply,
+ uint32_t reply_len, void *data_in, uint32_t datain_len, void *data_out,
+ uint32_t dataout_len, uint32_t timeout);
+int mps_read_config_page_header(int fd, U8 PageType, U8 PageNumber,
+ U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header, U16 *IOCStatus);
+int mps_read_ext_config_page_header(int fd, U8 ExtPageType, U8 PageNumber,
+ U32 PageAddress, MPI2_CONFIG_PAGE_HEADER *header,
+ U16 *ExtPageLen, U16 *IOCStatus);
+void *mps_read_config_page(int fd, U8 PageType, U8 PageNumber,
+ U32 PageAddress, U16 *IOCStatus);
+void *mps_read_extended_config_page(int fd, U8 ExtPageType, U8 PageVersion,
+ U8 PageNumber, U32 PageAddress, U16 *IOCStatus);
+int mps_map_btdh(int fd, uint16_t *devhandle, uint16_t *bus,
+ uint16_t *target);
+const char *mps_ioc_status(U16 IOCStatus);
+int mps_firmware_send(int fd, unsigned char *buf, uint32_t len, bool bios);
+int mps_firmware_get(int fd, unsigned char **buf, bool bios);
+
+static __inline void *
+mps_read_man_page(int fd, U8 PageNumber, U16 *IOCStatus)
+{
+
+ return (mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_MANUFACTURING,
+ PageNumber, 0, IOCStatus));
+}
+
+static __inline void *
+mps_read_ioc_page(int fd, U8 PageNumber, U16 *IOCStatus)
+{
+
+ return (mps_read_config_page(fd, MPI2_CONFIG_PAGETYPE_IOC, PageNumber,
+ 0, IOCStatus));
+}
+
+MPI2_IOC_FACTS_REPLY * mps_get_iocfacts(int fd);
+
+#endif /* !__MPSUTIL_H__ */
diff --git a/usr.sbin/mptable/mptable.c b/usr.sbin/mptable/mptable.c
index 2c29934..c6fca67 100644
--- a/usr.sbin/mptable/mptable.c
+++ b/usr.sbin/mptable/mptable.c
@@ -217,7 +217,8 @@ main( int argc, char *argv[] )
apic_probe( &paddr, &where );
if ( where <= 0 ) {
fprintf( stderr, "\n MP FPS NOT found,\n" );
- fprintf( stderr, " suggest trying -grope option!!!\n\n" );
+ if (!grope)
+ fprintf( stderr, " suggest trying -grope option!!!\n\n" );
return 1;
}
diff --git a/usr.sbin/nandsim/Makefile.depend b/usr.sbin/nandsim/Makefile.depend
new file mode 100644
index 0000000..3646e2e
--- /dev/null
+++ b/usr.sbin/nandsim/Makefile.depend
@@ -0,0 +1,18 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/nandsim/nandsim.8 b/usr.sbin/nandsim/nandsim.8
index d89767b..0951cc7 100644
--- a/usr.sbin/nandsim/nandsim.8
+++ b/usr.sbin/nandsim/nandsim.8
@@ -177,7 +177,7 @@ list all blocks marked as bad on a given chip.
.El
.It Ic log
Prints activity log of the specified controller to stdout; if
-controller number is not specifed, logs for all available
+controller number is not specified, logs for all available
controllers are printed.
.It Ic stats
Print statistics of the selected controller, chip and page.
diff --git a/usr.sbin/nandsim/nandsim.c b/usr.sbin/nandsim/nandsim.c
index 082085f..bd3d080 100644
--- a/usr.sbin/nandsim/nandsim.c
+++ b/usr.sbin/nandsim/nandsim.c
@@ -421,7 +421,7 @@ cmdmod(int gargc __unused, char **gargv)
if (gargc >= 4) {
if (strcmp(gargv[2], "--loglevel") == 0 || strcmp(gargv[2],
"-l") == 0) {
- /* Set loglevel (ctrl:chip pair independant) */
+ /* Set loglevel (ctrl:chip pair independent) */
mods.field = SIM_MOD_LOG_LEVEL;
if (convert_arguint(gargv[3], &mods.new_value) != 0)
diff --git a/usr.sbin/nandsim/nandsim_cfgparse.c b/usr.sbin/nandsim/nandsim_cfgparse.c
index a965034..a9b5eb1 100644
--- a/usr.sbin/nandsim/nandsim_cfgparse.c
+++ b/usr.sbin/nandsim/nandsim_cfgparse.c
@@ -349,7 +349,7 @@ create_ctrls(struct rcfile *f, struct sim_ctrl **ctrls, int *cnt)
/*
* ECC layout have to end up with 0xffff, so
* we're filling buffer with 0xff. If ecc_layout is
- * defined in config file, values will be overriden.
+ * defined in config file, values will be overridden.
*/
memset((void *)&ctrl_conf.ecc_layout, 0xff,
sizeof(ctrl_conf.ecc_layout));
@@ -411,7 +411,7 @@ create_chips(struct rcfile *f, struct sim_chip **chips, int *cnt)
/*
* Bad block map have to end up with 0xffff, so
* we're filling array with 0xff. If bad block map is
- * defined in config file, values will be overriden.
+ * defined in config file, values will be overridden.
*/
memset((void *)&chip_conf.bad_block_map, 0xff,
sizeof(chip_conf.bad_block_map));
diff --git a/usr.sbin/nandtool/Makefile.depend b/usr.sbin/nandtool/Makefile.depend
new file mode 100644
index 0000000..851372c
--- /dev/null
+++ b/usr.sbin/nandtool/Makefile.depend
@@ -0,0 +1,21 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libexpat \
+ lib/libgeom \
+ lib/libsbuf \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ndiscvt/Makefile b/usr.sbin/ndiscvt/Makefile
index 3322a53..f0facf4 100644
--- a/usr.sbin/ndiscvt/Makefile
+++ b/usr.sbin/ndiscvt/Makefile
@@ -22,8 +22,7 @@ CFLAGS+=-I. -I${.CURDIR} -I${.CURDIR}/../../sys
CLEANFILES= y.output
FILES= windrv_stub.c
-FILESNAME= windrv_stub.c
-FILESDIR= /usr/share/misc
+FILESDIR= ${SHAREDIR}/misc
SCRIPTS= ndisgen.sh
diff --git a/usr.sbin/ndp/ndp.c b/usr.sbin/ndp/ndp.c
index a14520c..cf80149 100644
--- a/usr.sbin/ndp/ndp.c
+++ b/usr.sbin/ndp/ndp.c
@@ -563,8 +563,8 @@ dump(struct sockaddr_in6 *addr, int cflag)
struct sockaddr_in6 *sin;
struct sockaddr_dl *sdl;
extern int h_errno;
- struct in6_nbrinfo *nbi;
struct timeval now;
+ u_long expire;
int addrwidth;
int llwidth;
int ifwidth;
@@ -675,53 +675,47 @@ again:;
printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
- /* Print neighbor discovery specific informations */
- nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
- if (nbi) {
- if (nbi->expire > now.tv_sec) {
- printf(" %-9.9s",
- sec2str(nbi->expire - now.tv_sec));
- } else if (nbi->expire == 0)
- printf(" %-9.9s", "permanent");
- else
- printf(" %-9.9s", "expired");
+ /* Print neighbor discovery specific information */
+ expire = rtm->rtm_rmx.rmx_expire;
+ if (expire > now.tv_sec)
+ printf(" %-9.9s", sec2str(expire - now.tv_sec));
+ else if (expire == 0)
+ printf(" %-9.9s", "permanent");
+ else
+ printf(" %-9.9s", "expired");
- switch (nbi->state) {
- case ND6_LLINFO_NOSTATE:
- printf(" N");
- break;
+ switch (rtm->rtm_rmx.rmx_state) {
+ case ND6_LLINFO_NOSTATE:
+ printf(" N");
+ break;
#ifdef ND6_LLINFO_WAITDELETE
- case ND6_LLINFO_WAITDELETE:
- printf(" W");
- break;
+ case ND6_LLINFO_WAITDELETE:
+ printf(" W");
+ break;
#endif
- case ND6_LLINFO_INCOMPLETE:
- printf(" I");
- break;
- case ND6_LLINFO_REACHABLE:
- printf(" R");
- break;
- case ND6_LLINFO_STALE:
- printf(" S");
- break;
- case ND6_LLINFO_DELAY:
- printf(" D");
- break;
- case ND6_LLINFO_PROBE:
- printf(" P");
- break;
- default:
- printf(" ?");
- break;
- }
-
- isrouter = nbi->isrouter;
- prbs = nbi->asked;
- } else {
- warnx("failed to get neighbor information");
- printf(" ");
+ case ND6_LLINFO_INCOMPLETE:
+ printf(" I");
+ break;
+ case ND6_LLINFO_REACHABLE:
+ printf(" R");
+ break;
+ case ND6_LLINFO_STALE:
+ printf(" S");
+ break;
+ case ND6_LLINFO_DELAY:
+ printf(" D");
+ break;
+ case ND6_LLINFO_PROBE:
+ printf(" P");
+ break;
+ default:
+ printf(" ?");
+ break;
}
+ isrouter = rtm->rtm_flags & RTF_GATEWAY;
+ prbs = rtm->rtm_rmx.rmx_pksent;
+
/*
* other flags. R: router, P: proxy, W: ??
*/
diff --git a/usr.sbin/newsyslog/newsyslog.c b/usr.sbin/newsyslog/newsyslog.c
index b63234b..9490cda 100644
--- a/usr.sbin/newsyslog/newsyslog.c
+++ b/usr.sbin/newsyslog/newsyslog.c
@@ -280,6 +280,7 @@ static int age_old_log(const char *file);
static void savelog(char *from, char *to);
static void createdir(const struct conf_entry *ent, char *dirpart);
static void createlog(const struct conf_entry *ent);
+static int parse_signal(const char *str);
/*
* All the following take a parameter of 'int', but expect values in the
@@ -1270,20 +1271,6 @@ no_trimat:
working->flags |= CE_BINARY;
break;
case 'c':
- /*
- * XXX - Ick! Ugly! Remove ASAP!
- * We want `c' and `C' for "create". But we
- * will temporarily treat `c' as `g', because
- * FreeBSD releases <= 4.8 have a typo of
- * checking ('G' || 'c') for CE_GLOB.
- */
- if (*q == 'c') {
- warnx("Assuming 'g' for 'c' in flags for line:\n%s",
- errline);
- warnx("The 'c' flag will eventually mean 'CREATE'");
- working->flags |= CE_GLOB;
- break;
- }
working->flags |= CE_CREATE;
break;
case 'd':
@@ -1338,12 +1325,13 @@ no_trimat:
if (q && *q) {
if (*q == '/')
working->pid_cmd_file = strdup(q);
- else if (isdigit(*q))
+ else if (isalnum(*q))
goto got_sig;
- else
+ else {
errx(1,
- "illegal pid file or signal number in config file:\n%s",
+ "illegal pid file or signal in config file:\n%s",
errline);
+ }
}
if (eol)
q = NULL;
@@ -1354,17 +1342,13 @@ no_trimat:
working->sig = SIGHUP;
if (q && *q) {
- if (isdigit(*q)) {
- got_sig:
- working->sig = atoi(q);
- } else {
- err_sig:
+got_sig:
+ working->sig = parse_signal(q);
+ if (working->sig < 1 || working->sig >= sys_nsig) {
errx(1,
- "illegal signal number in config file:\n%s",
+ "illegal signal in config file:\n%s",
errline);
}
- if (working->sig < 1 || working->sig >= NSIG)
- goto err_sig;
}
/*
@@ -1915,7 +1899,7 @@ do_sigwork(struct sigwork_entry *swork)
/*
* Compute the pause between consecutive signals. Use a longer
* sleep time if we will be sending two signals to the same
- * deamon or process-group.
+ * daemon or process-group.
*/
secs = 0;
nextsig = SLIST_NEXT(swork, sw_nextp);
@@ -2662,3 +2646,28 @@ change_attrs(const char *fname, const struct conf_entry *ent)
warn("can't chflags %s NODUMP", fname);
}
}
+
+/*
+ * Parse a signal number or signal name. Returns the signal number parsed or -1
+ * on failure.
+ */
+static int
+parse_signal(const char *str)
+{
+ int sig, i;
+ const char *errstr;
+
+ sig = strtonum(str, 1, sys_nsig - 1, &errstr);
+
+ if (errstr == NULL)
+ return (sig);
+ if (strncasecmp(str, "SIG", 3) == 0)
+ str += 3;
+
+ for (i = 1; i < sys_nsig; i++) {
+ if (strcasecmp(str, sys_signame[i]) == 0)
+ return (i);
+ }
+
+ return (-1);
+}
diff --git a/usr.sbin/newsyslog/newsyslog.conf.5 b/usr.sbin/newsyslog/newsyslog.conf.5
index a053f2f..0d28aab 100644
--- a/usr.sbin/newsyslog/newsyslog.conf.5
+++ b/usr.sbin/newsyslog/newsyslog.conf.5
@@ -21,7 +21,7 @@
.\" the suitability of this software for any purpose. It is
.\" provided "as is" without express or implied warranty.
.\"
-.Dd March 21, 2012
+.Dd October 24, 2015
.Dt NEWSYSLOG.CONF 5
.Os
.Sh NAME
@@ -337,7 +337,7 @@ process ID or to find a group process ID if the
.Cm U
flag was specified.
If this field is present, a
-.Ar signal_number
+.Ar signal
is sent to the process ID contained in this file.
If this field is not present and the
.Cm N
@@ -358,14 +358,23 @@ flag, the file is treated as a path to a binary to be executed
by the
.Xr newsyslog 8
after rotation instead of sending the signal out.
-.It Ar signal_number
-This optional field specifies the signal number that will be sent
-to the daemon process (or to all processes in a process group, if the
+.It Ar signal
+This optional field specifies the signal that will be sent to the daemon
+process (or to all processes in a process group, if the
.Cm U
flag was specified).
If this field is not present, then a
.Dv SIGHUP
signal will be sent.
+Signal names
+must start with
+.Dq SIG
+and be the signal name, e.g.,
+.Dv SIGUSR1 .
+Alternatively,
+.Ar signal
+can be the signal number, e.g., 30 for
+.Dv SIGUSR1 .
.El
.Sh EXAMPLES
The following is an example of the
diff --git a/usr.sbin/nfsuserd/nfsuserd.8 b/usr.sbin/nfsuserd/nfsuserd.8
index 6e170db..84f4a22 100644
--- a/usr.sbin/nfsuserd/nfsuserd.8
+++ b/usr.sbin/nfsuserd/nfsuserd.8
@@ -24,14 +24,14 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 25, 2009
+.Dd November 1, 2015
.Dt NFSUSERD 8
.Os
.Sh NAME
.Nm nfsuserd
.Nd load user and group information into the kernel for
.Tn NFSv4
-services
+services plus support manage-gids for all NFS versions
.Sh SYNOPSIS
.Nm nfsuserd
.Op Fl domain Ar domain_name
@@ -39,11 +39,14 @@ services
.Op Fl usermax Ar max_cache_size
.Op Fl verbose
.Op Fl force
+.Op Fl manage-gids
.Op Ar num_servers
.Sh DESCRIPTION
.Nm
loads user and group information into the kernel for NFSv4.
It must be running for NFSv4 to function correctly, either client or server.
+It also provides support for manage-gids and must be running on the server if
+this is being used for any version of NFS.
.Pp
Upon startup, it loads the machines DNS domain name, plus timeout and
cache size limit into the kernel. It then preloads the cache with group
@@ -79,6 +82,15 @@ When set, the server logs a bunch of information to syslog.
This flag option must be set to restart the daemon after it has gone away
abnormally and refuses to start, because it thinks nfsuserd is already
running.
+.It Fl manage-gids
+This flag enables manage-gids for the NFS server
+.Xr nfsd 8 .
+When this is enabled, all NFS requests using
+AUTH_SYS authentication take the uid from the RPC request
+and uses the group list for that uid provided by
+.Xr getgrouplist 3
+on the server instead of the list of groups provided in the RPC authenticator.
+This can be used to avoid the 16 group limit for AUTH_SYS.
.It Ar num_servers
Specifies how many servers to create (max 20).
The default of 4 may be sufficient. You should run enough servers, so that
@@ -90,6 +102,7 @@ such as a process table entry and swap space.
.El
.Sh SEE ALSO
.Xr getgrent 3 ,
+.Xr getgrouplist 3 ,
.Xr getpwent 3 ,
.Xr nfsv4 4 ,
.Xr group 5 ,
@@ -103,7 +116,8 @@ utility was introduced with the NFSv4 experimental subsystem in 2009.
The
.Nm
use
-.Xr getgrent 3
+.Xr getgrent 3 ,
+.Xr getgrouplist 3
and
.Xr getpwent 3
library calls to resolve requests and will hang if the servers handling
diff --git a/usr.sbin/nfsuserd/nfsuserd.c b/usr.sbin/nfsuserd/nfsuserd.c
index 35e2849..293da71 100644
--- a/usr.sbin/nfsuserd/nfsuserd.c
+++ b/usr.sbin/nfsuserd/nfsuserd.c
@@ -92,7 +92,7 @@ uid_t defaultuid = (uid_t)32767;
u_char *defaultgroup = "nogroup";
gid_t defaultgid = (gid_t)32767;
int verbose = 0, im_a_slave = 0, nfsuserdcnt = -1, forcestart = 0;
-int defusertimeout = DEFUSERTIMEOUT;
+int defusertimeout = DEFUSERTIMEOUT, manage_gids = 0;
pid_t slaves[MAXNFSUSERD];
int
@@ -110,6 +110,8 @@ main(int argc, char *argv[])
char hostname[MAXHOSTNAMELEN + 1], *cp;
struct addrinfo *aip, hints;
static uid_t check_dups[MAXUSERMAX];
+ gid_t grps[NGROUPS];
+ int ngroup;
if (modfind("nfscommon") < 0) {
/* Not present in kernel, try loading it */
@@ -160,6 +162,8 @@ main(int argc, char *argv[])
verbose = 1;
} else if (!strcmp(*argv, "-force")) {
forcestart = 1;
+ } else if (!strcmp(*argv, "-manage-gids")) {
+ manage_gids = 1;
} else if (!strcmp(*argv, "-usermax")) {
if (argc == 1)
usage();
@@ -297,12 +301,14 @@ main(int argc, char *argv[])
nid.nid_gid = defaultgid;
nid.nid_name = dnsname;
nid.nid_namelen = strlen(nid.nid_name);
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
nid.nid_flag = NFSID_INITIALIZE;
#ifdef DEBUG
printf("Initialize uid=%d gid=%d dns=%s\n", nid.nid_uid, nid.nid_gid,
nid.nid_name);
#else
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error)
errx(1, "Can't initialize nfs user/groups");
#endif
@@ -316,11 +322,13 @@ main(int argc, char *argv[])
nid.nid_gid = grp->gr_gid;
nid.nid_name = grp->gr_name;
nid.nid_namelen = strlen(grp->gr_name);
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
nid.nid_flag = NFSID_ADDGID;
#ifdef DEBUG
printf("add gid=%d name=%s\n", nid.nid_gid, nid.nid_name);
#else
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error)
errx(1, "Can't add group %s", grp->gr_name);
#endif
@@ -352,11 +360,23 @@ main(int argc, char *argv[])
nid.nid_uid = pwd->pw_uid;
nid.nid_name = pwd->pw_name;
nid.nid_namelen = strlen(pwd->pw_name);
+ if (manage_gids != 0) {
+ /* Get the group list for this user. */
+ ngroup = NGROUPS;
+ if (getgrouplist(pwd->pw_name, pwd->pw_gid, grps,
+ &ngroup) < 0)
+ syslog(LOG_ERR, "Group list too small");
+ nid.nid_ngroup = ngroup;
+ nid.nid_grps = grps;
+ } else {
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
+ }
nid.nid_flag = NFSID_ADDUID;
#ifdef DEBUG
printf("add uid=%d name=%s\n", nid.nid_uid, nid.nid_name);
#else
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error)
errx(1, "Can't add user %s", pwd->pw_name);
#endif
@@ -439,6 +459,8 @@ nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
struct info info;
struct nfsd_idargs nid;
u_int32_t saddr;
+ gid_t grps[NGROUPS];
+ int ngroup;
/*
* Only handle requests from 127.0.0.1 on a reserved port number.
@@ -472,14 +494,28 @@ nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
nid.nid_usertimeout = defusertimeout;
nid.nid_uid = pwd->pw_uid;
nid.nid_name = pwd->pw_name;
+ if (manage_gids != 0) {
+ /* Get the group list for this user. */
+ ngroup = NGROUPS;
+ if (getgrouplist(pwd->pw_name, pwd->pw_gid,
+ grps, &ngroup) < 0)
+ syslog(LOG_ERR, "Group list too small");
+ nid.nid_ngroup = ngroup;
+ nid.nid_grps = grps;
+ } else {
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
+ }
} else {
nid.nid_usertimeout = 5;
nid.nid_uid = (uid_t)info.id;
nid.nid_name = defaultuser;
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
}
nid.nid_namelen = strlen(nid.nid_name);
nid.nid_flag = NFSID_ADDUID;
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error) {
info.retval = error;
syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
@@ -509,8 +545,10 @@ nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
nid.nid_name = defaultgroup;
}
nid.nid_namelen = strlen(nid.nid_name);
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
nid.nid_flag = NFSID_ADDGID;
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error) {
info.retval = error;
syslog(LOG_ERR, "Can't add group %s\n",
@@ -541,8 +579,10 @@ nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
nid.nid_name = info.name;
}
nid.nid_namelen = strlen(nid.nid_name);
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
nid.nid_flag = NFSID_ADDUSERNAME;
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error) {
info.retval = error;
syslog(LOG_ERR, "Can't add user %s\n", pwd->pw_name);
@@ -572,8 +612,10 @@ nfsuserdsrv(struct svc_req *rqstp, SVCXPRT *transp)
nid.nid_name = info.name;
}
nid.nid_namelen = strlen(nid.nid_name);
+ nid.nid_ngroup = 0;
+ nid.nid_grps = NULL;
nid.nid_flag = NFSID_ADDGROUPNAME;
- error = nfssvc(NFSSVC_IDNAME, &nid);
+ error = nfssvc(NFSSVC_IDNAME | NFSSVC_NEWSTRUCT, &nid);
if (error) {
info.retval = error;
syslog(LOG_ERR, "Can't add group %s\n",
@@ -679,5 +721,5 @@ usage(void)
{
errx(1,
- "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-domain domain_name] [n]");
+ "usage: nfsuserd [-usermax cache_size] [-usertimeout minutes] [-verbose] [-manage-gids] [-domain domain_name] [n]");
}
diff --git a/usr.sbin/ntp/config.h b/usr.sbin/ntp/config.h
index 4d0a5e1..5a51e0a 100644
--- a/usr.sbin/ntp/config.h
+++ b/usr.sbin/ntp/config.h
@@ -1418,7 +1418,7 @@
#define PACKAGE_NAME "ntp"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "ntp 4.2.8p3"
+#define PACKAGE_STRING "ntp 4.2.8p4"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "ntp"
@@ -1427,7 +1427,7 @@
#define PACKAGE_URL "http://www.ntp.org./"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "4.2.8p3"
+#define PACKAGE_VERSION "4.2.8p4"
/* data dir */
#define PERLLIBDIR "/usr/local/share/ntp/lib"
@@ -1608,7 +1608,7 @@ typedef unsigned int uintptr_t;
/* #undef USE_UDP_SIGPOLL */
/* Version number of package */
-#define VERSION "4.2.8p3"
+#define VERSION "4.2.8p4"
/* vsnprintf expands "%m" to strerror(errno) */
/* #undef VSNPRINTF_PERCENT_M */
@@ -1785,5 +1785,5 @@ typedef union mpinfou {
/*
* FreeBSD specific: Explicitly specify date/time for reproducible build.
*/
-#define MKREPRO_DATE "Jul 04 2015"
-#define MKREPRO_TIME "15:42:16"
+#define MKREPRO_DATE "Oct 22 2015"
+#define MKREPRO_TIME "17:58:31"
diff --git a/usr.sbin/ntp/doc/drivers/Makefile.depend b/usr.sbin/ntp/doc/drivers/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/drivers/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/drivers/icons/Makefile.depend b/usr.sbin/ntp/doc/drivers/icons/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/drivers/icons/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/drivers/scripts/Makefile.depend b/usr.sbin/ntp/doc/drivers/scripts/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/drivers/scripts/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/hints/Makefile.depend b/usr.sbin/ntp/doc/hints/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/hints/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/icons/Makefile.depend b/usr.sbin/ntp/doc/icons/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/icons/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/ntp-keygen.8 b/usr.sbin/ntp/doc/ntp-keygen.8
index 89c4e09..197adbf 100644
--- a/usr.sbin/ntp/doc/ntp-keygen.8
+++ b/usr.sbin/ntp/doc/ntp-keygen.8
@@ -1,11 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt NTP_KEYGEN 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp-keygen-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:44:02 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:40:10 PM by AutoGen 5.18.5
.\" From the definitions ntp-keygen-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/doc/ntp.conf.5 b/usr.sbin/ntp/doc/ntp.conf.5
index 4ed9440..c7af12d 100644
--- a/usr.sbin/ntp/doc/ntp.conf.5
+++ b/usr.sbin/ntp/doc/ntp.conf.5
@@ -1,11 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt NTP_CONF 5 File Formats
.Os
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:42:07 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:38:24 PM by AutoGen 5.18.5
.\" From the definitions ntp.conf.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -1905,7 +1905,7 @@ re\-associate accordingly.
Some administrators prefer to avoid running
.Xr ntpd 8
continuously and run either
-.Xr ntpdate 8
+.Xr sntp 8
or
.Xr ntpd 8
.Fl q
@@ -1997,7 +1997,7 @@ peers remaining.
This value defaults to 1, but can be changed
to any number from 1 to 15.
.It Cm minclock Ar minclock
-The clustering algorithm repeatedly casts out outlyer
+The clustering algorithm repeatedly casts out outlier
associations until no more than
.Cm minclock
associations remain.
@@ -2388,6 +2388,9 @@ This implies that
must have write permission for the directory the
drift file is located in, and that file system links, symbolic or
otherwise, should be avoided.
+.It Ic dscp Ar value
+This option specifies the Differentiated Services Control Point (DSCP) value,
+a 6\-bit code. The default value is 46, signifying Expedited Forwarding.
.It Xo Ic enable
.Oo
.Cm auth | Cm bclient |
@@ -2487,6 +2490,19 @@ This option is useful for sites that run
.Xr ntpd 8
on multiple hosts, with (mostly) common options (e.g., a
restriction list).
+.It Ic leapsmearinterval Ar seconds
+This EXPERIMENTAL option is only available if
+.Xr ntpd 8
+was built with the
+.Cm \-\-enable\-leap\-smear
+option to the
+.Cm configure
+script.
+It specifies the interval over which a leap second correction will be applied.
+Recommended values for this option are between
+7200 (2 hours) and 86400 (24 hours).
+.Sy DO NOT USE THIS OPTION ON PUBLIC\-ACCESS SERVERS!
+See http://bugs.ntp.org/2855 for more information.
.It Ic logconfig Ar configkeyword
This command controls the amount and type of output written to
the system
@@ -2620,7 +2636,9 @@ holds the names of the reference clock variables.
.Cm freq Ar freq |
.Cm huffpuff Ar huffpuff |
.Cm panic Ar panic |
-.Cm step Ar srep |
+.Cm step Ar step |
+.Cm stepback Ar stepback |
+.Cm stepfwd Ar stepfwd |
.Cm stepout Ar stepout
.Oc
.Xc
@@ -2680,6 +2698,19 @@ adjustments will never occur.
Note: The kernel time discipline is
disabled if the step threshold is set to zero or greater than the
default.
+.It Cm stepback Ar stepback
+The argument is the step threshold for the backward direction,
+which by default is 0.128 s.
+It can
+be set to any positive number in seconds.
+If both the forward and backward step thresholds are set to zero, step
+adjustments will never occur.
+Note: The kernel time discipline is
+disabled if
+each direction of step threshold are either
+set to zero or greater than .5 second.
+.It Cm stepfwd Ar stepfwd
+As for stepback, but for the forward direction.
.It Cm stepout Ar stepout
The argument is the stepout timeout, which by default is 900 s.
It can
@@ -2696,19 +2727,22 @@ pulses will not be suppressed.
.Xc
.Bl -tag -width indent
.It Cm memlock Ar Nmegabytes
-Specify the number of megabytes of memory that can be allocated.
-Probably only available under Linux, this option is useful
+Specify the number of megabytes of memory that should be
+allocated and locked.
+Probably only available under Linux, this option may be useful
when dropping root (the
.Fl i
option).
-The default is 32 megabytes. Setting this to zero will prevent any attemp to lock memory.
+The default is 32 megabytes on non\-Linux machines, and \-1 under Linux.
+-1 means "do not lock the process into memory".
+0 means "lock whatever memory the process wants into memory".
.It Cm stacksize Ar N4kPages
Specifies the maximum size of the process stack on systems with the
-.It Cm filenum Ar Nfiledescriptors
-Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
.Fn mlockall
function.
Defaults to 50 4k pages (200 4k pages in OpenBSD).
+.It Cm filenum Ar Nfiledescriptors
+Specifies the maximum number of file descriptors ntpd may have open at once. Defaults to the system default.
.El
.It Xo Ic trap Ar host_address
.Op Cm port Ar port_number
diff --git a/usr.sbin/ntp/doc/ntp.keys.5 b/usr.sbin/ntp/doc/ntp.keys.5
index 4ec3bb3..b1bcb3c 100644
--- a/usr.sbin/ntp/doc/ntp.keys.5
+++ b/usr.sbin/ntp/doc/ntp.keys.5
@@ -1,13 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt NTP_KEYS 5 File Formats
.Os SunOS 5.10
.\" EDIT THIS FILE WITH CAUTION (ntp.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" $FreeBSD$
-.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:42:10 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:38:28 PM by AutoGen 5.18.5
.\" From the definitions ntp.keys.def
.\" and the template file agmdoc-file.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/doc/ntpd.8 b/usr.sbin/ntp/doc/ntpd.8
index 665aa0b..243f96d 100644
--- a/usr.sbin/ntp/doc/ntpd.8
+++ b/usr.sbin/ntp/doc/ntpd.8
@@ -1,11 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt NTPD 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpd-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:42:12 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:38:30 PM by AutoGen 5.18.5
.\" From the definitions ntpd-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -146,7 +146,7 @@ The name and path of the frequency file,
by default.
This is the same operation as the
\fBdriftfile\fP \fIdriftfile\fP
-configuration specification in the
+configuration specification in the
\fI/etc/ntp.conf\fP
file.
.It Fl g , Fl \-panicgate
@@ -165,6 +165,19 @@ options.
See the
\fBtinker\fP
configuration file directive for other options.
+.It Fl G , Fl \-force\-step\-once
+Step any initial offset correction..
+.sp
+Normally,
+\fBntpd\fP
+steps the time if the time offset exceeds the step threshold,
+which is 128 ms by default, and otherwise slews the time.
+This option forces the initial offset correction to be stepped,
+so the highest time accuracy can be achieved quickly.
+However, this may also cause the time to be stepped back
+so this option must not be used if
+applications requiring monotonic time are running.
+See the \fBtinker\fP configuration file directive for other options.
.It Fl i Ar string , Fl \-jaildir Ns = Ns Ar string
Jail directory.
.sp
@@ -188,7 +201,7 @@ Open the network address given, or all the addresses associated with the
given interface name. This option may appear multiple times. This option
also implies not opening other addresses, except wildcard and localhost.
This option is deprecated. Please consider using the configuration file
-\fBinterface\fP command, which is more versatile.
+\fBinterface\fP command, which is more versatile.
.It Fl k Ar string , Fl \-keyfile Ns = Ns Ar string
path to symmetric keys.
.sp
@@ -521,6 +534,8 @@ when you have permission to do so from the owner of the target host.
Finally,
in the past many startup scripts would run
.Xr ntpdate 8
+or
+.Xr sntp 8
to get the system clock close to correct before starting
.Xr ntpd 8 ,
but this was never more than a mediocre hack and is no longer needed.
@@ -530,7 +545,9 @@ and you still need to set the system time before starting
.Nm ,
please open a bug report and document what is going on,
and then look at using
-.Xr sntp 8 .
+.Xr sntp 8
+if you really need to set the clock before starting
+.Nm .
.Pp
There is a way to start
.Xr ntpd 8
diff --git a/usr.sbin/ntp/doc/ntpdc.8 b/usr.sbin/ntp/doc/ntpdc.8
index 3373614..74129c4 100644
--- a/usr.sbin/ntp/doc/ntpdc.8
+++ b/usr.sbin/ntp/doc/ntpdc.8
@@ -1,11 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt NTPDC 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpdc-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:42:44 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:38:57 PM by AutoGen 5.18.5
.\" From the definitions ntpdc-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
diff --git a/usr.sbin/ntp/doc/ntpq.8 b/usr.sbin/ntp/doc/ntpq.8
index 1eba486..bcd1fba 100644
--- a/usr.sbin/ntp/doc/ntpq.8
+++ b/usr.sbin/ntp/doc/ntpq.8
@@ -1,11 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt NTPQ 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (ntpq-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:43:19 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:39:29 PM by AutoGen 5.18.5
.\" From the definitions ntpq-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -226,7 +226,9 @@ switch.
This command allows the specification of a key number to be
used to authenticate configuration requests.
This must correspond
-to a key number the server has been configured to use for this
+to the
+.Cm controlkey
+key number the server has been configured to use for this
purpose.
.It Ic keytype Xo Oo
.Cm md5 |
@@ -506,6 +508,14 @@ offset of server relative to this host
.It Ic jitter
jitter
.El
+.It Ic apeers
+Display a list of peers in the form:
+.Dl [tally]remote refid assid st t when pool reach delay offset jitter
+where the output is just like the
+.Ic peers
+command except that the
+.Ic refid
+is displayed in hex format and the association number is also displayed.
.It Ic pstats Ar assocID
Show the statistics for the peer with the given
.Ar assocID .
diff --git a/usr.sbin/ntp/doc/pic/Makefile.depend b/usr.sbin/ntp/doc/pic/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/pic/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/scripts/Makefile.depend b/usr.sbin/ntp/doc/scripts/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/ntp/doc/scripts/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/ntp/doc/sntp.8 b/usr.sbin/ntp/doc/sntp.8
index 4d09cb0..9bcc78d 100644
--- a/usr.sbin/ntp/doc/sntp.8
+++ b/usr.sbin/ntp/doc/sntp.8
@@ -1,11 +1,11 @@
-.Dd February 4 2015
+.Dd October 21 2015
.Dt SNTP 8 User Commands
.Os
.\" EDIT THIS FILE WITH CAUTION (sntp-opts.mdoc)
.\"
.\" $FreeBSD$
.\"
-.\" It has been AutoGen-ed February 4, 2015 at 02:34:20 AM by AutoGen 5.18.5pre4
+.\" It has been AutoGen-ed October 21, 2015 at 12:30:59 PM by AutoGen 5.18.5
.\" From the definitions sntp-opts.def
.\" and the template file agmdoc-cmd.tpl
.Sh NAME
@@ -59,7 +59,8 @@ Otherwise, only the
is displayed.
Finally, the
.Em stratum
-of the host is reported.
+of the host is reported
+and the leap indicator is decoded and displayed.
.Sh "OPTIONS"
.Bl -tag
.It Fl 4 , Fl \-ipv4
diff --git a/usr.sbin/ntp/scripts/mkver b/usr.sbin/ntp/scripts/mkver
index 0fc94be..2bc36b5 100755
--- a/usr.sbin/ntp/scripts/mkver
+++ b/usr.sbin/ntp/scripts/mkver
@@ -6,7 +6,7 @@ PROG=${1-UNKNOWN}
ConfStr="$PROG"
-ConfStr="$ConfStr 4.2.8p3"
+ConfStr="$ConfStr 4.2.8p4"
case "$CSET" in
'') ;;
diff --git a/usr.sbin/ofwdump/Makefile.depend b/usr.sbin/ofwdump/Makefile.depend
index 79eb58b..a5da8fd 100644
--- a/usr.sbin/ofwdump/Makefile.depend
+++ b/usr.sbin/ofwdump/Makefile.depend
@@ -2,11 +2,14 @@
# Autogenerated - do NOT edit!
DIRDEPS = \
+ gnu/lib/csu \
gnu/lib/libgcc \
include \
include/xlocale \
lib/${CSU_DIR} \
lib/libc \
+ lib/libc_nonshared \
+ lib/libcompiler_rt \
.include <dirdeps.mk>
diff --git a/usr.sbin/pciconf/cap.c b/usr.sbin/pciconf/cap.c
index 2e2e359..9ab6dd1 100644
--- a/usr.sbin/pciconf/cap.c
+++ b/usr.sbin/pciconf/cap.c
@@ -460,6 +460,10 @@ cap_express(int fd, struct pci_conf *p, uint8_t ptr)
MAX_PAYLOAD(cap & PCIEM_CAP_MAX_PAYLOAD));
if ((cap & PCIEM_CAP_FLR) != 0)
printf(" FLR");
+ if (ctl & PCIEM_CTL_RELAXED_ORD_ENABLE)
+ printf(" RO");
+ if (ctl & PCIEM_CTL_NOSNOOP_ENABLE)
+ printf(" NS");
cap = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_CAP, 4);
sta = read_config(fd, &p->pc_sel, ptr + PCIER_LINK_STA, 2);
printf(" link x%d(x%d)", (sta & PCIEM_LINK_STA_WIDTH) >> 4,
diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8
index 8dbb2a6..705b594 100644
--- a/usr.sbin/pciconf/pciconf.8
+++ b/usr.sbin/pciconf/pciconf.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 06, 2015
+.Dd November 23, 2015
.Dt PCICONF 8
.Os
.Sh NAME
@@ -33,7 +33,7 @@
.Nd diagnostic utility for the PCI bus
.Sh SYNOPSIS
.Nm
-.Fl l Oo Fl bcevV Oc Op Ar device
+.Fl l Oo Fl BbceVv Oc Op Ar device
.Nm
.Fl a Ar device
.Nm
@@ -112,6 +112,42 @@ device, which contains several (similar or independent) functions on
one chip.
.Pp
If the
+.Fl B
+option is supplied,
+.Nm
+will list additional information for
+.Tn PCI
+to
+.Tn PCI
+and
+.Tn PCI
+to
+.Tn CardBus
+bridges,
+specifically the resource ranges decoded by the bridge for use by devices
+behind the bridge.
+Each bridge lists a range of bus numbers handled by the bridge and its
+downstream devices.
+Memory and I/O port decoding windows are enumerated via a line in the
+following format:
+.Bd -literal
+ window[1c] = type I/O Port, range 16, addr 0x5000-0x8fff, enabled
+.Ed
+.Pp
+The first value after the
+.Dq Li window
+prefix in the square brackets is the offset of the decoding window in
+config space in hexadecimal.
+The type of a window is one of
+.Dq Memory ,
+.Dq Prefetchable Memory ,
+or
+.Dq I/O Port .
+The range indicates the binary log of the maximum address the window decodes.
+The address field indicates the start and end addresses of the decoded range.
+Finally, the last flag indicates if the window is enabled or disabled.
+.Pp
+If the
.Fl b
option is supplied,
.Nm
@@ -132,7 +168,7 @@ The type of a BAR is one of
.Dq Prefetchable Memory ,
or
.Dq I/O Port .
-The range indicates the maximum address the BAR decodes.
+The range indicates the binary log of the maximum address the BAR decodes.
The base and size indicate the start and length of the BAR's address window,
respectively.
Finally, the last flag indicates if the BAR is enabled or disabled.
diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c
index 721d120..194da6b 100644
--- a/usr.sbin/pciconf/pciconf.c
+++ b/usr.sbin/pciconf/pciconf.c
@@ -39,6 +39,7 @@ static const char rcsid[] =
#include <ctype.h>
#include <err.h>
#include <inttypes.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -69,9 +70,10 @@ struct pci_vendor_info
TAILQ_HEAD(,pci_vendor_info) pci_vendors;
static struct pcisel getsel(const char *str);
+static void list_bridge(int fd, struct pci_conf *p);
static void list_bars(int fd, struct pci_conf *p);
-static void list_devs(const char *name, int verbose, int bars, int caps,
- int errors, int vpd);
+static void list_devs(const char *name, int verbose, int bars, int bridge,
+ int caps, int errors, int vpd);
static void list_verbose(struct pci_conf *p);
static void list_vpd(int fd, struct pci_conf *p);
static const char *guess_class(struct pci_conf *p);
@@ -87,7 +89,7 @@ static void
usage(void)
{
fprintf(stderr, "%s\n%s\n%s\n%s\n",
- "usage: pciconf -l [-bcevV] [device]",
+ "usage: pciconf -l [-BbcevV] [device]",
" pciconf -a device",
" pciconf -r [-b | -h] device addr[:addr2]",
" pciconf -w [-b | -h] device addr value");
@@ -99,18 +101,22 @@ main(int argc, char **argv)
{
int c;
int listmode, readmode, writemode, attachedmode;
- int bars, caps, errors, verbose, vpd;
+ int bars, bridge, caps, errors, verbose, vpd;
int byte, isshort;
listmode = readmode = writemode = attachedmode = 0;
- bars = caps = errors = verbose = vpd = byte = isshort = 0;
+ bars = bridge = caps = errors = verbose = vpd = byte = isshort = 0;
- while ((c = getopt(argc, argv, "abcehlrwvV")) != -1) {
+ while ((c = getopt(argc, argv, "aBbcehlrwVv")) != -1) {
switch(c) {
case 'a':
attachedmode = 1;
break;
+ case 'B':
+ bridge = 1;
+ break;
+
case 'b':
bars = 1;
byte = 1;
@@ -161,7 +167,7 @@ main(int argc, char **argv)
if (listmode) {
list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose,
- bars, caps, errors, vpd);
+ bars, bridge, caps, errors, vpd);
} else if (attachedmode) {
chkattached(argv[optind]);
} else if (readmode) {
@@ -178,8 +184,8 @@ main(int argc, char **argv)
}
static void
-list_devs(const char *name, int verbose, int bars, int caps, int errors,
- int vpd)
+list_devs(const char *name, int verbose, int bars, int bridge, int caps,
+ int errors, int vpd)
{
int fd;
struct pci_conf_io pc;
@@ -190,7 +196,8 @@ list_devs(const char *name, int verbose, int bars, int caps, int errors,
if (verbose)
load_vendors();
- fd = open(_PATH_DEVPCI, (caps || errors) ? O_RDWR : O_RDONLY, 0);
+ fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY,
+ 0);
if (fd < 0)
err(1, "%s", _PATH_DEVPCI);
@@ -248,6 +255,8 @@ list_devs(const char *name, int verbose, int bars, int caps, int errors,
list_verbose(p);
if (bars)
list_bars(fd, p);
+ if (bridge)
+ list_bridge(fd, p);
if (caps)
list_caps(fd, p);
if (errors)
@@ -261,6 +270,189 @@ list_devs(const char *name, int verbose, int bars, int caps, int errors,
}
static void
+print_bus_range(int fd, struct pci_conf *p, int secreg, int subreg)
+{
+ uint8_t secbus, subbus;
+
+ secbus = read_config(fd, &p->pc_sel, secreg, 1);
+ subbus = read_config(fd, &p->pc_sel, subreg, 1);
+ printf(" bus range = %u-%u\n", secbus, subbus);
+}
+
+static void
+print_window(int reg, const char *type, int range, uint64_t base,
+ uint64_t limit)
+{
+
+ printf(" window[%02x] = type %s, range %2d, addr %#jx-%#jx, %s\n",
+ reg, type, range, (uintmax_t)base, (uintmax_t)limit,
+ base < limit ? "enabled" : "disabled");
+}
+
+static void
+print_special_decode(bool isa, bool vga, bool subtractive)
+{
+ bool comma;
+
+ if (isa || vga || subtractive) {
+ comma = false;
+ printf(" decode = ");
+ if (isa) {
+ printf("ISA");
+ comma = true;
+ }
+ if (vga) {
+ printf("%sVGA", comma ? ", " : "");
+ comma = true;
+ }
+ if (subtractive)
+ printf("%ssubtractive", comma ? ", " : "");
+ printf("\n");
+ }
+}
+
+static void
+print_bridge_windows(int fd, struct pci_conf *p)
+{
+ uint64_t base, limit;
+ uint32_t val;
+ uint16_t bctl;
+ bool subtractive;
+ int range;
+
+ /*
+ * XXX: This assumes that a window with a base and limit of 0
+ * is not implemented. In theory a window might be programmed
+ * at the smallest size with a base of 0, but those do not seem
+ * common in practice.
+ */
+ val = read_config(fd, &p->pc_sel, PCIR_IOBASEL_1, 1);
+ if (val != 0 || read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1) != 0) {
+ if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) {
+ base = PCI_PPBIOBASE(
+ read_config(fd, &p->pc_sel, PCIR_IOBASEH_1, 2),
+ val);
+ limit = PCI_PPBIOLIMIT(
+ read_config(fd, &p->pc_sel, PCIR_IOLIMITH_1, 2),
+ read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1));
+ range = 32;
+ } else {
+ base = PCI_PPBIOBASE(0, val);
+ limit = PCI_PPBIOLIMIT(0,
+ read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1));
+ range = 16;
+ }
+ print_window(PCIR_IOBASEL_1, "I/O Port", range, base, limit);
+ }
+
+ base = PCI_PPBMEMBASE(0,
+ read_config(fd, &p->pc_sel, PCIR_MEMBASE_1, 2));
+ limit = PCI_PPBMEMLIMIT(0,
+ read_config(fd, &p->pc_sel, PCIR_MEMLIMIT_1, 2));
+ print_window(PCIR_MEMBASE_1, "Memory", 32, base, limit);
+
+ val = read_config(fd, &p->pc_sel, PCIR_PMBASEL_1, 2);
+ if (val != 0 || read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2) != 0) {
+ if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) {
+ base = PCI_PPBMEMBASE(
+ read_config(fd, &p->pc_sel, PCIR_PMBASEH_1, 4),
+ val);
+ limit = PCI_PPBMEMLIMIT(
+ read_config(fd, &p->pc_sel, PCIR_PMLIMITH_1, 4),
+ read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2));
+ range = 64;
+ } else {
+ base = PCI_PPBMEMBASE(0, val);
+ limit = PCI_PPBMEMLIMIT(0,
+ read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2));
+ range = 32;
+ }
+ print_window(PCIR_PMBASEL_1, "Prefetchable Memory", range, base,
+ limit);
+ }
+
+ /*
+ * XXX: This list of bridges that are subtractive but do not set
+ * progif to indicate it is copied from pci_pci.c.
+ */
+ subtractive = p->pc_progif == PCIP_BRIDGE_PCI_SUBTRACTIVE;
+ switch (p->pc_device << 16 | p->pc_vendor) {
+ case 0xa002177d: /* Cavium ThunderX */
+ case 0x124b8086: /* Intel 82380FB Mobile */
+ case 0x060513d7: /* Toshiba ???? */
+ subtractive = true;
+ }
+ if (p->pc_vendor == 0x8086 && (p->pc_device & 0xff00) == 0x2400)
+ subtractive = true;
+
+ bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_1, 2);
+ print_special_decode(bctl & PCIB_BCR_ISA_ENABLE,
+ bctl & PCIB_BCR_VGA_ENABLE, subtractive);
+}
+
+static void
+print_cardbus_mem_window(int fd, struct pci_conf *p, int basereg, int limitreg,
+ bool prefetch)
+{
+
+ print_window(basereg, prefetch ? "Prefetchable Memory" : "Memory", 32,
+ PCI_CBBMEMBASE(read_config(fd, &p->pc_sel, basereg, 4)),
+ PCI_CBBMEMLIMIT(read_config(fd, &p->pc_sel, limitreg, 4)));
+}
+
+static void
+print_cardbus_io_window(int fd, struct pci_conf *p, int basereg, int limitreg)
+{
+ uint32_t base, limit;
+ uint32_t val;
+ int range;
+
+ val = read_config(fd, &p->pc_sel, basereg, 2);
+ if ((val & PCIM_CBBIO_MASK) == PCIM_CBBIO_32) {
+ base = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, basereg, 4));
+ limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 4));
+ range = 32;
+ } else {
+ base = PCI_CBBIOBASE(val);
+ limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 2));
+ range = 16;
+ }
+ print_window(basereg, "I/O Port", range, base, limit);
+}
+
+static void
+print_cardbus_windows(int fd, struct pci_conf *p)
+{
+ uint16_t bctl;
+
+ bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_2, 2);
+ print_cardbus_mem_window(fd, p, PCIR_MEMBASE0_2, PCIR_MEMLIMIT0_2,
+ bctl & CBB_BCR_PREFETCH_0_ENABLE);
+ print_cardbus_mem_window(fd, p, PCIR_MEMBASE1_2, PCIR_MEMLIMIT1_2,
+ bctl & CBB_BCR_PREFETCH_1_ENABLE);
+ print_cardbus_io_window(fd, p, PCIR_IOBASE0_2, PCIR_IOLIMIT0_2);
+ print_cardbus_io_window(fd, p, PCIR_IOBASE1_2, PCIR_IOLIMIT1_2);
+ print_special_decode(bctl & CBB_BCR_ISA_ENABLE,
+ bctl & CBB_BCR_VGA_ENABLE, false);
+}
+
+static void
+list_bridge(int fd, struct pci_conf *p)
+{
+
+ switch (p->pc_hdr & PCIM_HDRTYPE) {
+ case PCIM_HDRTYPE_BRIDGE:
+ print_bus_range(fd, p, PCIR_SECBUS_1, PCIR_SUBBUS_1);
+ print_bridge_windows(fd, p);
+ break;
+ case PCIM_HDRTYPE_CARDBUS:
+ print_bus_range(fd, p, PCIR_SECBUS_2, PCIR_SUBBUS_2);
+ print_cardbus_windows(fd, p);
+ break;
+ }
+}
+
+static void
list_bars(int fd, struct pci_conf *p)
{
int i, max;
diff --git a/usr.sbin/pmcstat/pmcpl_gprof.c b/usr.sbin/pmcstat/pmcpl_gprof.c
index 9ff78e8..5fc9b41 100644
--- a/usr.sbin/pmcstat/pmcpl_gprof.c
+++ b/usr.sbin/pmcstat/pmcpl_gprof.c
@@ -74,6 +74,14 @@ __FBSDID("$FreeBSD$");
#include "pmcpl_callgraph.h"
#include "pmcpl_gprof.h"
+typedef uint64_t WIDEHISTCOUNTER;
+
+#define WIDEHISTCOUNTER_MAX UINT64_MAX
+#define HISTCOUNTER_MAX USHRT_MAX
+#define WIDEHISTCOUNTER_GMONTYPE ((int) 64)
+#define HISTCOUNTER_GMONTYPE ((int) 0)
+static int hc_sz=0;
+
/*
* struct pmcstat_gmonfile tracks a given 'gmon.out' file. These
* files are mmap()'ed in as needed.
@@ -126,11 +134,13 @@ pmcstat_gmon_create_file(struct pmcstat_gmonfile *pgf,
gm.lpc = image->pi_start;
gm.hpc = image->pi_end;
- gm.ncnt = (pgf->pgf_nbuckets * sizeof(HISTCOUNTER)) +
- sizeof(struct gmonhdr);
+ gm.ncnt = (pgf->pgf_nbuckets * hc_sz) + sizeof(struct gmonhdr);
gm.version = GMONVERSION;
gm.profrate = 0; /* use ticks */
- gm.histcounter_type = 0; /* compatibility with moncontrol() */
+ if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC)
+ gm.histcounter_type = WIDEHISTCOUNTER_GMONTYPE;
+ else
+ gm.histcounter_type = HISTCOUNTER_GMONTYPE;
gm.spare[0] = gm.spare[1] = 0;
/* Write out the gmon header */
@@ -400,6 +410,7 @@ pmcpl_gmon_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
struct pmcstat_gmonfile *pgf;
uintfptr_t bucket;
HISTCOUNTER *hc;
+ WIDEHISTCOUNTER *whc;
pmc_id_t pmcid;
(void) nsamples; (void) usermode; (void) cpu;
@@ -437,6 +448,14 @@ pmcpl_gmon_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
*/
pgf = pmcstat_image_find_gmonfile(image, pmcid);
if (pgf == NULL) {
+ if (hc_sz == 0) {
+ /* Determine the correct histcounter size. */
+ if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC)
+ hc_sz = sizeof(WIDEHISTCOUNTER);
+ else
+ hc_sz = sizeof(HISTCOUNTER);
+ }
+
if ((pgf = calloc(1, sizeof(*pgf))) == NULL)
err(EX_OSERR, "ERROR:");
@@ -448,7 +467,7 @@ pmcpl_gmon_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
pgf->pgf_nbuckets = (image->pi_end - image->pi_start) /
FUNCTION_ALIGNMENT; /* see <machine/profile.h> */
pgf->pgf_ndatabytes = sizeof(struct gmonhdr) +
- pgf->pgf_nbuckets * sizeof(HISTCOUNTER);
+ pgf->pgf_nbuckets * hc_sz;
pgf->pgf_nsamples = 0;
pgf->pgf_file = NULL;
@@ -474,14 +493,25 @@ pmcpl_gmon_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
assert(bucket < pgf->pgf_nbuckets);
- hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
- sizeof(struct gmonhdr));
-
- /* saturating add */
- if (hc[bucket] < 0xFFFFU) /* XXX tie this to sizeof(HISTCOUNTER) */
- hc[bucket]++;
- else /* mark that an overflow occurred */
- pgf->pgf_overflow = 1;
+ if (args.pa_flags & FLAG_DO_WIDE_GPROF_HC) {
+ whc = (WIDEHISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
+ sizeof(struct gmonhdr));
+
+ /* saturating add */
+ if (whc[bucket] < WIDEHISTCOUNTER_MAX)
+ whc[bucket]++;
+ else /* mark that an overflow occurred */
+ pgf->pgf_overflow = 1;
+ } else {
+ hc = (HISTCOUNTER *) ((uintptr_t) pgf->pgf_gmondata +
+ sizeof(struct gmonhdr));
+
+ /* saturating add */
+ if (hc[bucket] < HISTCOUNTER_MAX)
+ hc[bucket]++;
+ else /* mark that an overflow occurred */
+ pgf->pgf_overflow = 1;
+ }
pgf->pgf_nsamples++;
}
diff --git a/usr.sbin/pmcstat/pmcstat.8 b/usr.sbin/pmcstat/pmcstat.8
index 25ff7a6..bc4bb74 100644
--- a/usr.sbin/pmcstat/pmcstat.8
+++ b/usr.sbin/pmcstat/pmcstat.8
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 27, 2015
+.Dd November 18, 2015
.Dt PMCSTAT 8
.Os
.Sh NAME
@@ -49,6 +49,7 @@
.Op Fl a Ar pathname
.Op Fl c Ar cpu-spec
.Op Fl d
+.Op Fl e
.Op Fl f Ar pluginopt
.Op Fl g
.Op Fl k Ar kerneldir
@@ -260,6 +261,12 @@ The default is to measure events for the target process alone.
.Fl P ,
or
.Fl S ) .
+.It Fl e
+Specify that the gprof profile files will use a wide history counter.
+These files are produced in a format compatible with
+.Xr gprof 1 .
+However, other tools that cannot fully parse a BSD-style
+gmon header might be unable to correctly parse these files.
.It Fl f Ar pluginopt
Pass option string to the active plugin.
.br
diff --git a/usr.sbin/pmcstat/pmcstat.c b/usr.sbin/pmcstat/pmcstat.c
index 914fc17..81b0cd0 100644
--- a/usr.sbin/pmcstat/pmcstat.c
+++ b/usr.sbin/pmcstat/pmcstat.c
@@ -506,6 +506,7 @@ pmcstat_show_usage(void)
"\t -a file\t print sampled PCs and callgraph to \"file\"\n"
"\t -c cpu-list\t set cpus for subsequent system-wide PMCs\n"
"\t -d\t\t (toggle) track descendants\n"
+ "\t -e\t\t use wide history counter for gprof(1) output\n"
"\t -f spec\t pass \"spec\" to as plugin option\n"
"\t -g\t\t produce gprof(1) compatible profiles\n"
"\t -k dir\t\t set the path to the kernel\n"
@@ -627,7 +628,7 @@ main(int argc, char **argv)
CPU_COPY(&rootmask, &cpumask);
while ((option = getopt(argc, argv,
- "CD:EF:G:M:NO:P:R:S:TWa:c:df:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1)
+ "CD:EF:G:M:NO:P:R:S:TWa:c:def:gk:l:m:n:o:p:qr:s:t:vw:z:")) != -1)
switch (option) {
case 'a': /* Annotate + callgraph */
args.pa_flags |= FLAG_DO_ANNOTATE;
@@ -668,6 +669,10 @@ main(int argc, char **argv)
args.pa_required |= FLAG_HAS_PROCESS_PMCS;
break;
+ case 'e': /* wide gprof metrics */
+ args.pa_flags |= FLAG_DO_WIDE_GPROF_HC;
+ break;
+
case 'F': /* produce a system-wide calltree */
args.pa_flags |= FLAG_DO_CALLGRAPHS;
args.pa_plugin = PMCSTAT_PL_CALLTREE;
@@ -1022,6 +1027,13 @@ main(int argc, char **argv)
"ERROR: options -g/-G/-m/-T require sampling PMCs or -R to be specified."
);
+ /* check if -e was specified without -g */
+ if ((args.pa_flags & FLAG_DO_WIDE_GPROF_HC) &&
+ !(args.pa_flags & FLAG_DO_GPROF))
+ errx(EX_USAGE,
+"ERROR: option -e requires gprof mode to be specified."
+ );
+
/* check if -O was spuriously specified */
if ((args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE) &&
(args.pa_required & FLAG_HAS_OUTPUT_LOGFILE) == 0)
@@ -1500,14 +1512,24 @@ main(int argc, char **argv)
"ERROR: Cannot retrieve driver statistics");
if (ds_start.pm_intr_bufferfull != ds_end.pm_intr_bufferfull &&
args.pa_verbosity > 0)
- warnx("WARNING: some samples were dropped.\n"
-"Please consider tuning the \"kern.hwpmc.nsamples\" tunable."
+ warnx(
+"WARNING: sampling was paused at least %u time%s.\n"
+"Please consider tuning the \"kern.hwpmc.nsamples\" tunable.",
+ ds_end.pm_intr_bufferfull -
+ ds_start.pm_intr_bufferfull,
+ ((ds_end.pm_intr_bufferfull -
+ ds_start.pm_intr_bufferfull) != 1) ? "s" : ""
);
if (ds_start.pm_buffer_requests_failed !=
ds_end.pm_buffer_requests_failed &&
args.pa_verbosity > 0)
- warnx("WARNING: some events were discarded.\n"
-"Please consider tuning the \"kern.hwpmc.nbuffers\" tunable."
+ warnx(
+"WARNING: at least %u event%s were discarded while running.\n"
+"Please consider tuning the \"kern.hwpmc.nbuffers\" tunable.",
+ ds_end.pm_buffer_requests_failed -
+ ds_start.pm_buffer_requests_failed,
+ ((ds_end.pm_buffer_requests_failed -
+ ds_start.pm_buffer_requests_failed) != 1) ? "s" : ""
);
}
diff --git a/usr.sbin/pmcstat/pmcstat.h b/usr.sbin/pmcstat/pmcstat.h
index 29dfeb7..5b1d3d9 100644
--- a/usr.sbin/pmcstat/pmcstat.h
+++ b/usr.sbin/pmcstat/pmcstat.h
@@ -55,6 +55,7 @@
#define FLAG_DO_ANALYSIS 0x00020000 /* -g or -G or -m or -T */
#define FLAGS_HAS_CPUMASK 0x00040000 /* -c */
#define FLAG_HAS_DURATION 0x00080000 /* -l secs */
+#define FLAG_DO_WIDE_GPROF_HC 0x00100000 /* -e */
#define DEFAULT_SAMPLE_COUNT 65536
#define DEFAULT_WAIT_INTERVAL 5.0
diff --git a/usr.sbin/pmcstudy/eval_expr.c b/usr.sbin/pmcstudy/eval_expr.c
index c225391..d8999a9 100644
--- a/usr.sbin/pmcstudy/eval_expr.c
+++ b/usr.sbin/pmcstudy/eval_expr.c
@@ -444,7 +444,7 @@ parse_expression(char *str)
* val OP val <or>
* val OP ( <recursively>
* d) A final optional step (not implemented yet) would be
- * to insert the mathimatical precedence paran's. For
+ * to insert the mathematical precedence paran's. For
* the start we will just do the left to right evaluation and
* then later we can add this guy to add paran's to make it
* mathimatically correct... i.e instead of 1 + 2 * 3 we
diff --git a/usr.sbin/pmcstudy/pmcstudy.8 b/usr.sbin/pmcstudy/pmcstudy.8
index 4ddb3e4..7c03897 100644
--- a/usr.sbin/pmcstudy/pmcstudy.8
+++ b/usr.sbin/pmcstudy/pmcstudy.8
@@ -32,7 +32,7 @@
.Nd Perform various studies on a system's overall PMCs.
.Sh SYNOPSIS
.Nm
-.Oo Fl i Ar inputfile | Fl T | Fl v | Fl m Ar max | Fl e exp | Fl Ar E | Fl h | fl H Oc
+.Oo Fl i Ar inputfile | Fl A | Fl T | Fl v | Fl m Ar max | Fl e exp | Fl Ar E | Fl h | fl H Oc
.Nm
.Fl i Ar inputfile
.Nm
@@ -59,8 +59,8 @@ PMCs and then run various formulas on the output information.
These formulas can be found in Intel documentation "Using Intel Vtune
amplifier xe on NNN Generation Intel Core Processors".
The NNN is either
-2nd, 3rd or 4th generation i.e., Sandy Bridge, Ivy Bridge and Haswell.
-Currently the program only works on these three Intel processor types.
+2nd, 3rd, 4th or 5th generation i.e., Sandy Bridge, Ivy Bridge, Haswell and Broadwell.
+Currently the program only works on these four Intel processor types.
.Sh OPTIONS
The following options are available:
.Bl -tag -width indent
@@ -128,6 +128,8 @@ test like
"UOPS_RETIRED.RETIRE_SLOTS / (4 * CPU_CLK_UNHALTED.THREAD_P)".
.It Fl L
This option will list all known PMCs and their abbreviation (%NNN).
+.It Fl A
+Run all canned tests.
.El
.Sh SEE ALSO
.Xr pmc 3 ,
diff --git a/usr.sbin/pmcstudy/pmcstudy.c b/usr.sbin/pmcstudy/pmcstudy.c
index 1a3da45..16c9f51 100644
--- a/usr.sbin/pmcstudy/pmcstudy.c
+++ b/usr.sbin/pmcstudy/pmcstudy.c
@@ -38,6 +38,9 @@
#include "eval_expr.h"
__FBSDID("$FreeBSD$");
+static int max_pmc_counters = 1;
+static int run_all = 0;
+
#define MAX_COUNTER_SLOTS 1024
#define MAX_NLEN 64
#define MAX_CPU 64
@@ -191,9 +194,9 @@ struct cpu_entry {
const char *thresh;
const char *command;
int (*func)(struct counters *, int);
+ int counters_required;
};
-
struct cpu_type {
char cputype[32];
int number;
@@ -217,10 +220,10 @@ explain_name_sb(const char *name)
printf("Examine (20 * BR_MISP_RETIRED.ALL_BRANCHES)/CPU_CLK_UNHALTED.THREAD_P\n");
mythresh = "thresh >= .2";
} else if (strcmp(name, "splitload") == 0) {
- printf("Examine MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+ printf("Examine MEM_UOPS_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
mythresh = "thresh >= .1";
} else if (strcmp(name, "splitstore") == 0) {
- printf("Examine MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES\n");
+ printf("Examine MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES\n");
mythresh = "thresh >= .01";
} else if (strcmp(name, "contested") == 0) {
printf("Examine (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 60) / CPU_CLK_UNHALTED.THREAD_P\n");
@@ -323,7 +326,7 @@ explain_name_ib(const char *name)
printf(" LD_BLOCKS.NO_SR)/CPU_CLK_UNHALTED.THREAD_P\n");
mythresh = "thresh >= .1";
} else if (strcmp(name, "splitstore") == 0) {
- printf("Examine MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES\n");
+ printf("Examine MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES\n");
mythresh = "thresh >= .01";
} else if (strcmp(name, "aliasing_4k") == 0) {
printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
@@ -403,10 +406,10 @@ explain_name_has(const char *name)
printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
mythresh = "thresh >= .05";
} else if (strcmp(name, "splitload") == 0) {
- printf("Examine (MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
+ printf("Examine (MEM_UOPS_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
mythresh = "thresh >= .1";
} else if (strcmp(name, "splitstore") == 0) {
- printf("Examine MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES\n");
+ printf("Examine MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES\n");
mythresh = "thresh >= .01";
} else if (strcmp(name, "aliasing_4k") == 0) {
printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P\n");
@@ -444,6 +447,7 @@ explain_name_has(const char *name)
}
+
static struct counters *
find_counter(struct counters *base, const char *name)
{
@@ -589,6 +593,48 @@ br_mispredictib(struct counters *cpu, int pos)
return(ret);
}
+
+static int
+br_mispredict_broad(struct counters *cpu, int pos)
+{
+ struct counters *brctr;
+ struct counters *unhalt;
+ struct counters *clear;
+ struct counters *uops;
+ struct counters *uops_ret;
+ struct counters *recv;
+ int ret;
+ double br, cl, uo, uo_r, re, con, un, res;
+
+ con = 4.0;
+
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ brctr = find_counter(cpu, "BR_MISP_RETIRED.ALL_BRANCHES");
+ clear = find_counter(cpu, "MACHINE_CLEARS.CYCLES");
+ uops = find_counter(cpu, "UOPS_ISSUED.ANY");
+ uops_ret = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
+ recv = find_counter(cpu, "INT_MISC.RECOVERY_CYCLES");
+
+ if (pos != -1) {
+ un = unhalt->vals[pos] * 1.0;
+ br = brctr->vals[pos] * 1.0;
+ cl = clear->vals[pos] * 1.0;
+ uo = uops->vals[pos] * 1.0;
+ uo_r = uops_ret->vals[pos] * 1.0;
+ re = recv->vals[pos] * 1.0;
+ } else {
+ un = unhalt->sum * 1.0;
+ br = brctr->sum * 1.0;
+ cl = clear->sum * 1.0;
+ uo = uops->sum * 1.0;
+ uo_r = uops_ret->sum * 1.0;
+ re = recv->sum * 1.0;
+ }
+ res = br / (br + cl) * (uo - uo_r + con * re) / (un * con);
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
static int
splitloadib(struct counters *cpu, int pos)
{
@@ -622,6 +668,7 @@ splitloadib(struct counters *cpu, int pos)
return(ret);
}
+
static int
splitload(struct counters *cpu, int pos)
{
@@ -629,6 +676,31 @@ splitload(struct counters *cpu, int pos)
struct counters *mem;
struct counters *unhalt;
double con, un, memd, res;
+/* 4 - (MEM_UOPS_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .1)*/
+
+ con = 5.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ mem = find_counter(cpu, "MEM_UOPS_RETIRED.SPLIT_LOADS");
+ if (pos != -1) {
+ memd = mem->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ } else {
+ memd = mem->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ }
+ res = (memd * con)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
+static int
+splitload_sb(struct counters *cpu, int pos)
+{
+ int ret;
+ struct counters *mem;
+ struct counters *unhalt;
+ double con, un, memd, res;
/* 4 - (MEM_UOP_RETIRED.SPLIT_LOADS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .1)*/
con = 5.0;
@@ -646,8 +718,9 @@ splitload(struct counters *cpu, int pos)
return(ret);
}
+
static int
-splitstore(struct counters *cpu, int pos)
+splitstore_sb(struct counters *cpu, int pos)
{
/* 5 - MEM_UOP_RETIRED.SPLIT_STORES / MEM_UOP_RETIRED.ALL_STORES (thresh > 0.01) */
int ret;
@@ -669,6 +742,30 @@ splitstore(struct counters *cpu, int pos)
}
+
+static int
+splitstore(struct counters *cpu, int pos)
+{
+ /* 5 - MEM_UOPS_RETIRED.SPLIT_STORES / MEM_UOPS_RETIRED.ALL_STORES (thresh > 0.01) */
+ int ret;
+ struct counters *mem_split;
+ struct counters *mem_stores;
+ double memsplit, memstore, res;
+ mem_split = find_counter(cpu, "MEM_UOPS_RETIRED.SPLIT_STORES");
+ mem_stores = find_counter(cpu, "MEM_UOPS_RETIRED.ALL_STORES");
+ if (pos != -1) {
+ memsplit = mem_split->vals[pos] * 1.0;
+ memstore = mem_stores->vals[pos] * 1.0;
+ } else {
+ memsplit = mem_split->sum * 1.0;
+ memstore = mem_stores->sum * 1.0;
+ }
+ res = memsplit/memstore;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
static int
contested(struct counters *cpu, int pos)
{
@@ -717,6 +814,35 @@ contested_has(struct counters *cpu, int pos)
return(ret);
}
+static int
+contestedbroad(struct counters *cpu, int pos)
+{
+ /* 6 - (MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) / CPU_CLK_UNHALTED.THREAD_P (thresh >.05) */
+ int ret;
+ struct counters *mem;
+ struct counters *mem2;
+ struct counters *unhalt;
+ double con, un, memd, memtoo, res;
+
+ con = 84.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ mem = find_counter(cpu, "MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM");
+ mem2 = find_counter(cpu,"MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS");
+
+ if (pos != -1) {
+ memd = mem->vals[pos] * 1.0;
+ memtoo = mem2->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ } else {
+ memd = mem->sum * 1.0;
+ memtoo = mem2->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ }
+ res = ((memd * con) + memtoo)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
static int
blockstoreforward(struct counters *cpu, int pos)
@@ -897,6 +1023,34 @@ cache2has(struct counters *cpu, int pos)
return(ret);
}
+
+static int
+cache2broad(struct counters *cpu, int pos)
+{
+ /*
+ * (29 * MEM_LOAD_UOPS_RETIRED.LLC_HIT / CPU_CLK_UNHALTED.THREAD_P (thresh >.2)
+ */
+ int ret;
+ struct counters *mem;
+ struct counters *unhalt;
+ double con, un, me, res;
+
+ con = 36.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.L3_HIT");
+ if (pos != -1) {
+ me = mem->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ } else {
+ me = mem->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ }
+ res = (con * me)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
static int
cache1(struct counters *cpu, int pos)
{
@@ -947,6 +1101,31 @@ cache1ib(struct counters *cpu, int pos)
static int
+cache1broad(struct counters *cpu, int pos)
+{
+ /* 9 - (MEM_LOAD_UOPS_L3_MISS_RETIRED.LCOAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P (thresh >= .2) */
+ int ret;
+ struct counters *mem;
+ struct counters *unhalt;
+ double con, un, me, res;
+
+ con = 180.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ mem = find_counter(cpu, "MEM_LOAD_UOPS_RETIRED.L3_MISS");
+ if (pos != -1) {
+ me = mem->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ } else {
+ me = mem->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ }
+ res = (me * con)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
+static int
dtlb_missload(struct counters *cpu, int pos)
{
/* 10 - ((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION) / CPU_CLK_UNHALTED.THREAD_P (t >=.1) */
@@ -1026,6 +1205,35 @@ itlb_miss(struct counters *cpu, int pos)
return(ret);
}
+
+static int
+itlb_miss_broad(struct counters *cpu, int pos)
+{
+ /* (7 * ITLB_MISSES.STLB_HIT_4K + ITLB_MISSES.WALK_DURATION) / CPU_CLK_UNTHREAD_P */
+ int ret;
+ struct counters *itlb;
+ struct counters *unhalt;
+ struct counters *four_k;
+ double un, d1, res, k;
+
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ itlb = find_counter(cpu, "ITLB_MISSES.WALK_DURATION");
+ four_k = find_counter(cpu, "ITLB_MISSES.STLB_HIT_4K");
+ if (pos != -1) {
+ d1 = itlb->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ k = four_k->vals[pos] * 1.0;
+ } else {
+ d1 = itlb->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ k = four_k->sum * 1.0;
+ }
+ res = (7.0 * k + d1)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
static int
icache_miss(struct counters *cpu, int pos)
{
@@ -1162,6 +1370,45 @@ clears(struct counters *cpu, int pos)
return(ret);
}
+
+
+static int
+clears_broad(struct counters *cpu, int pos)
+{
+ int ret;
+ struct counters *clr1, *clr2, *clr3, *cyc;
+ struct counters *unhalt;
+ double con, un, cl1, cl2, cl3, cy, res;
+
+ con = 100.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ clr1 = find_counter(cpu, "MACHINE_CLEARS.MEMORY_ORDERING");
+ clr2 = find_counter(cpu, "MACHINE_CLEARS.SMC");
+ clr3 = find_counter(cpu, "MACHINE_CLEARS.MASKMOV");
+ cyc = find_counter(cpu, "MACHINE_CLEARS.CYCLES");
+ if (pos != -1) {
+ cl1 = clr1->vals[pos] * 1.0;
+ cl2 = clr2->vals[pos] * 1.0;
+ cl3 = clr3->vals[pos] * 1.0;
+ cy = cyc->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ } else {
+ cl1 = clr1->sum * 1.0;
+ cl2 = clr2->sum * 1.0;
+ cl3 = clr3->sum * 1.0;
+ cy = cyc->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ }
+ /* Formula not listed but extrapulated to add the cy ?? */
+ res = ((cl1 + cl2 + cl3 + cy) * con)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
+
+
+
static int
microassist(struct counters *cpu, int pos)
{
@@ -1188,6 +1435,38 @@ microassist(struct counters *cpu, int pos)
static int
+microassist_broad(struct counters *cpu, int pos)
+{
+ int ret;
+ struct counters *idq;
+ struct counters *unhalt;
+ struct counters *uopiss;
+ struct counters *uopret;
+ double un, id, res, con, uoi, uor;
+
+ con = 4.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ idq = find_counter(cpu, "IDQ.MS_UOPS");
+ uopiss = find_counter(cpu, "UOPS_ISSUED.ANY");
+ uopret = find_counter(cpu, "UOPS_RETIRED.RETIRE_SLOTS");
+ if (pos != -1) {
+ id = idq->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ uoi = uopiss->vals[pos] * 1.0;
+ uor = uopret->vals[pos] * 1.0;
+ } else {
+ id = idq->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ uoi = uopiss->sum * 1.0;
+ uor = uopret->sum * 1.0;
+ }
+ res = (uor/uoi) * (id/(un * con));
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
+static int
aliasing(struct counters *cpu, int pos)
{
/* 15 - (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh > .1) */
@@ -1212,6 +1491,31 @@ aliasing(struct counters *cpu, int pos)
}
static int
+aliasing_broad(struct counters *cpu, int pos)
+{
+ /* 15 - (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 5) / CPU_CLK_UNHALTED.THREAD_P (thresh > .1) */
+ int ret;
+ struct counters *ld;
+ struct counters *unhalt;
+ double un, lds, con, res;
+
+ con = 7.0;
+ unhalt = find_counter(cpu, "CPU_CLK_UNHALTED.THREAD_P");
+ ld = find_counter(cpu, "LD_BLOCKS_PARTIAL.ADDRESS_ALIAS");
+ if (pos != -1) {
+ lds = ld->vals[pos] * 1.0;
+ un = unhalt->vals[pos] * 1.0;
+ } else {
+ lds = ld->sum * 1.0;
+ un = unhalt->sum * 1.0;
+ }
+ res = (lds * con)/un;
+ ret = printf("%1.3f", res);
+ return(ret);
+}
+
+
+static int
fpassists(struct counters *cpu, int pos)
{
/* 16 - FP_ASSIST.ANY/INST_RETIRED.ANY_P */
@@ -1336,64 +1640,65 @@ efficiency2(struct counters *cpu, int pos)
static struct cpu_entry sandy_bridge[SANDY_BRIDGE_COUNT] = {
/*01*/ { "allocstall1", "thresh > .05",
"pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.SLOW_LEA_WINDOW -w 1",
- allocstall1 },
-/*02*/ { "allocstall2", "thresh > .05",
- "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP_CYCLES -w 1",
- allocstall2 },
+ allocstall1, 2 },
+/* -- not defined for SB right (partial-rat_stalls) 02*/
+ { "allocstall2", "thresh > .05",
+ "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s PARTIAL_RAT_STALLS.FLAGS_MERGE_UOP -w 1",
+ allocstall2, 2 },
/*03*/ { "br_miss", "thresh >= .2",
"pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -w 1",
- br_mispredict },
+ br_mispredict, 2 },
/*04*/ { "splitload", "thresh >= .1",
"pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOP_RETIRED.SPLIT_LOADS -w 1",
- splitload },
-/*05*/ { "splitstore", "thresh >= .01",
+ splitload_sb, 2 },
+/* 05*/ { "splitstore", "thresh >= .01",
"pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
- splitstore },
+ splitstore_sb, 2 },
/*06*/ { "contested", "thresh >= .05",
"pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- contested },
+ contested, 2 },
/*07*/ { "blockstorefwd", "thresh >= .05",
"pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- blockstoreforward },
+ blockstoreforward, 2 },
/*08*/ { "cache2", "thresh >= .2",
"pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- cache2 },
+ cache2, 4 },
/*09*/ { "cache1", "thresh >= .2",
"pmcstat -s MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- cache1 },
+ cache1, 2 },
/*10*/ { "dtlbmissload", "thresh >= .1",
"pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- dtlb_missload },
+ dtlb_missload, 3 },
/*11*/ { "dtlbmissstore", "thresh >= .05",
"pmcstat -s DTLB_STORE_MISSES.STLB_HIT -s DTLB_STORE_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- dtlb_missstore },
+ dtlb_missstore, 3 },
/*12*/ { "frontendstall", "thresh >= .15",
"pmcstat -s IDQ_UOPS_NOT_DELIVERED.CORE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- frontendstall },
+ frontendstall, 2 },
/*13*/ { "clears", "thresh >= .02",
"pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- clears },
+ clears, 4 },
/*14*/ { "microassist", "thresh >= .05",
"pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- microassist },
+ microassist, 2 },
/*15*/ { "aliasing_4k", "thresh >= .1",
"pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- aliasing },
+ aliasing, 2 },
/*16*/ { "fpassist", "look for a excessive value",
"pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
- fpassists },
+ fpassists, 2 },
/*17*/ { "otherassistavx", "look for a excessive value",
"pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- otherassistavx },
+ otherassistavx, 2},
/*18*/ { "otherassistsse", "look for a excessive value",
"pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- otherassistsse },
+ otherassistsse, 2 },
/*19*/ { "eff1", "thresh < .9",
"pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- efficiency1 },
+ efficiency1, 2 },
/*20*/ { "eff2", "thresh > 1.0",
"pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- efficiency2 },
+ efficiency2, 2 },
};
@@ -1401,131 +1706,257 @@ static struct cpu_entry sandy_bridge[SANDY_BRIDGE_COUNT] = {
static struct cpu_entry ivy_bridge[IVY_BRIDGE_COUNT] = {
/*1*/ { "eff1", "thresh < .75",
"pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- efficiency1 },
+ efficiency1, 2 },
/*2*/ { "eff2", "thresh > 1.0",
"pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- efficiency2 },
+ efficiency2, 2 },
/*3*/ { "itlbmiss", "thresh > .05",
"pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- itlb_miss },
+ itlb_miss, 2 },
/*4*/ { "icachemiss", "thresh > .05",
"pmcstat -s ICACHE.IFETCH_STALL -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- icache_miss },
+ icache_miss, 3 },
/*5*/ { "lcpstall", "thresh > .05",
"pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- lcp_stall },
+ lcp_stall, 2 },
/*6*/ { "cache1", "thresh >= .2",
"pmcstat -s MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- cache1ib },
+ cache1ib, 2 },
/*7*/ { "cache2", "thresh >= .2",
"pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- cache2ib },
+ cache2ib, 2 },
/*8*/ { "contested", "thresh >= .05",
"pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- contested },
+ contested, 2 },
/*9*/ { "datashare", "thresh >= .05",
"pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- datasharing },
+ datasharing, 2 },
/*10*/ { "blockstorefwd", "thresh >= .05",
"pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- blockstoreforward },
+ blockstoreforward, 2 },
/*11*/ { "splitload", "thresh >= .1",
"pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s L1D_PEND_MISS.PENDING -s MEM_LOAD_UOPS_RETIRED.L1_MISS -s LD_BLOCKS.NO_SR -w 1",
- splitloadib },
+ splitloadib, 4 },
/*12*/ { "splitstore", "thresh >= .01",
- "pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
- splitstore },
+ "pmcstat -s MEM_UOPS_RETIRED.SPLIT_STORES -s MEM_UOPS_RETIRED.ALL_STORES -w 1",
+ splitstore, 2 },
/*13*/ { "aliasing_4k", "thresh >= .1",
"pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- aliasing },
+ aliasing, 2 },
/*14*/ { "dtlbmissload", "thresh >= .1",
"pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- dtlb_missload },
+ dtlb_missload , 3},
/*15*/ { "dtlbmissstore", "thresh >= .05",
"pmcstat -s DTLB_STORE_MISSES.STLB_HIT -s DTLB_STORE_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- dtlb_missstore },
+ dtlb_missstore, 3 },
/*16*/ { "br_miss", "thresh >= .2",
"pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",
- br_mispredictib },
+ br_mispredictib, 8 },
/*17*/ { "clears", "thresh >= .02",
"pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- clears },
+ clears, 4 },
/*18*/ { "microassist", "thresh >= .05",
"pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- microassist },
+ microassist, 2 },
/*19*/ { "fpassist", "look for a excessive value",
"pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
- fpassists },
+ fpassists, 2 },
/*20*/ { "otherassistavx", "look for a excessive value",
"pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- otherassistavx },
+ otherassistavx , 2},
/*21*/ { "otherassistsse", "look for a excessive value",
"pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- otherassistsse },
+ otherassistsse, 2 },
};
#define HASWELL_COUNT 20
static struct cpu_entry haswell[HASWELL_COUNT] = {
/*1*/ { "eff1", "thresh < .75",
"pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- efficiency1 },
+ efficiency1, 2 },
/*2*/ { "eff2", "thresh > 1.0",
"pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- efficiency2 },
+ efficiency2, 2 },
/*3*/ { "itlbmiss", "thresh > .05",
"pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- itlb_miss },
+ itlb_miss, 2 },
/*4*/ { "icachemiss", "thresh > .05",
- "pmcstat -s ICACHE.MISSES --s CPU_CLK_UNHALTED.THREAD_P -w 1",
- icache_miss_has },
+ "pmcstat -s ICACHE.MISSES -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ icache_miss_has, 2 },
/*5*/ { "lcpstall", "thresh > .05",
"pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- lcp_stall },
+ lcp_stall, 2 },
/*6*/ { "cache1", "thresh >= .2",
"pmcstat -s MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- cache1ib },
+ cache1ib, 2 },
/*7*/ { "cache2", "thresh >= .2",
"pmcstat -s MEM_LOAD_UOPS_RETIRED.LLC_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- cache2has },
+ cache2has, 4 },
/*8*/ { "contested", "thresh >= .05",
"pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- contested_has },
+ contested_has, 2 },
/*9*/ { "datashare", "thresh >= .05",
"pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- datasharing_has },
+ datasharing_has, 2 },
/*10*/ { "blockstorefwd", "thresh >= .05",
"pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- blockstoreforward },
+ blockstoreforward, 2 },
/*11*/ { "splitload", "thresh >= .1",
- "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOP_RETIRED.SPLIT_LOADS -w 1",
- splitload },
+ "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s MEM_UOPS_RETIRED.SPLIT_LOADS -w 1",
+ splitload , 2},
/*12*/ { "splitstore", "thresh >= .01",
- "pmcstat -s MEM_UOP_RETIRED.SPLIT_STORES -s MEM_UOP_RETIRED.ALL_STORES -w 1",
- splitstore },
+ "pmcstat -s MEM_UOPS_RETIRED.SPLIT_STORES -s MEM_UOPS_RETIRED.ALL_STORES -w 1",
+ splitstore, 2 },
/*13*/ { "aliasing_4k", "thresh >= .1",
"pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- aliasing },
+ aliasing, 2 },
/*14*/ { "dtlbmissload", "thresh >= .1",
"pmcstat -s DTLB_LOAD_MISSES.STLB_HIT -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- dtlb_missload },
+ dtlb_missload, 3 },
/*15*/ { "br_miss", "thresh >= .2",
"pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -w 1",
- br_mispredict },
+ br_mispredict, 2 },
/*16*/ { "clears", "thresh >= .02",
"pmcstat -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- clears },
+ clears, 4 },
/*17*/ { "microassist", "thresh >= .05",
"pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- microassist },
+ microassist, 2 },
/*18*/ { "fpassist", "look for a excessive value",
"pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
- fpassists },
+ fpassists, 2 },
/*19*/ { "otherassistavx", "look for a excessive value",
"pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- otherassistavx },
+ otherassistavx, 2 },
/*20*/ { "otherassistsse", "look for a excessive value",
"pmcstat -s OTHER_ASSISTS.SSE_TO_AVX -s CPU_CLK_UNHALTED.THREAD_P -w 1",
- otherassistsse },
+ otherassistsse, 2 },
+};
+
+
+static void
+explain_name_broad(const char *name)
+{
+ const char *mythresh;
+ if (strcmp(name, "eff1") == 0) {
+ printf("Examine (UOPS_RETIRED.RETIRE_SLOTS)/(4 *CPU_CLK_UNHALTED.THREAD_P)\n");
+ mythresh = "thresh < .75";
+ } else if (strcmp(name, "eff2") == 0) {
+ printf("Examine CPU_CLK_UNHALTED.THREAD_P/INST_RETIRED.ANY_P\n");
+ mythresh = "thresh > 1.0";
+ } else if (strcmp(name, "itlbmiss") == 0) {
+ printf("Examine (7 * ITLB_MISSES_STLB_HIT_4K + ITLB_MISSES.WALK_DURATION)/ CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh > .05";
+ } else if (strcmp(name, "icachemiss") == 0) {
+ printf("Examine ( 36.0 * ICACHE.MISSES)/ CPU_CLK_UNHALTED.THREAD_P ??? may not be right \n");
+ mythresh = "thresh > .05";
+ } else if (strcmp(name, "lcpstall") == 0) {
+ printf("Examine ILD_STALL.LCP/CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh > .05";
+ } else if (strcmp(name, "cache1") == 0) {
+ printf("Examine (MEM_LOAD_UOPS_LLC_MISS_RETIRED.LOCAL_DRAM * 180) / CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh >= .1";
+ } else if (strcmp(name, "cache2") == 0) {
+ printf("Examine (36.0 * MEM_LOAD_UOPS_RETIRED.L3_HIT / CPU_CLK_UNHALTED.THREAD_P)\n");
+ mythresh = "thresh >= .2";
+ } else if (strcmp(name, "contested") == 0) {
+ printf("Examine ((MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM * 84) + MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS)/ CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh >= .05";
+ } else if (strcmp(name, "datashare") == 0) {
+ printf("Examine (MEM_LOAD_UOPS_L3_HIT_RETIRED.XSNP_HIT * 72)/CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh > .05";
+ } else if (strcmp(name, "blockstorefwd") == 0) {
+ printf("Examine (LD_BLOCKS_STORE_FORWARD * 13) / CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh >= .05";
+ } else if (strcmp(name, "aliasing_4k") == 0) {
+ printf("Examine (LD_BLOCKS_PARTIAL.ADDRESS_ALIAS * 7) / CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh >= .1";
+ } else if (strcmp(name, "dtlbmissload") == 0) {
+ printf("Examine (((DTLB_LOAD_MISSES.STLB_HIT * 7) + DTLB_LOAD_MISSES.WALK_DURATION)\n");
+ printf(" / CPU_CLK_UNHALTED.THREAD_P)\n");
+ mythresh = "thresh >= .1";
+
+ } else if (strcmp(name, "br_miss") == 0) {
+ printf("Examine BR_MISP_RETIRED.ALL_BRANCHS_PS / (BR_MISP_RETIED.ALL_BRANCHES_PS + MACHINE_CLEARS.COUNT) *\n");
+ printf(" (UOPS_ISSUEDF.ANY - UOPS_RETIRED.RETIRE_SLOTS + 4 * INT_MISC.RECOVERY_CYCLES) /\n");
+ printf("CPU_CLK_UNHALTED.THREAD * 4)\n");
+ mythresh = "thresh >= .2";
+ } else if (strcmp(name, "clears") == 0) {
+ printf("Examine ((MACHINE_CLEARS.MEMORY_ORDERING + \n");
+ printf(" MACHINE_CLEARS.SMC + \n");
+ printf(" MACHINE_CLEARS.MASKMOV ) * 100 ) / CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "thresh >= .02";
+ } else if (strcmp(name, "fpassist") == 0) {
+ printf("Examine FP_ASSIST.ANY/INST_RETIRED.ANY_P\n");
+ mythresh = "look for a excessive value";
+ } else if (strcmp(name, "otherassistavx") == 0) {
+ printf("Examine (OTHER_ASSISTS.AVX_TO_SSE * 75)/CPU_CLK_UNHALTED.THREAD_P\n");
+ mythresh = "look for a excessive value";
+ } else if (strcmp(name, "microassist") == 0) {
+ printf("Examine (UOPS_RETIRED.RETIRE_SLOTS/UOPS_ISSUED.ANY) * (IDQ.MS_CYCLES / (4 * CPU_CLK_UNHALTED.THREAD_P)\n");
+ printf("***We use IDQ.MS_UOPS,cmask=1 to get cycles\n");
+ mythresh = "thresh >= .05";
+ } else {
+ printf("Unknown name:%s\n", name);
+ mythresh = "unknown entry";
+ }
+ printf("If the value printed is %s we may have the ability to improve performance\n", mythresh);
+}
+
+
+#define BROADWELL_COUNT 17
+static struct cpu_entry broadwell[BROADWELL_COUNT] = {
+/*1*/ { "eff1", "thresh < .75",
+ "pmcstat -s UOPS_RETIRED.RETIRE_SLOTS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ efficiency1, 2 },
+/*2*/ { "eff2", "thresh > 1.0",
+ "pmcstat -s INST_RETIRED.ANY_P -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ efficiency2, 2 },
+/*3*/ { "itlbmiss", "thresh > .05",
+ "pmcstat -s ITLB_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -s ITLB_MISSES.STLB_HIT_4K -w 1",
+ itlb_miss_broad, 3 },
+/*4*/ { "icachemiss", "thresh > .05",
+ "pmcstat -s ICACHE.MISSES -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ icache_miss_has, 2 },
+/*5*/ { "lcpstall", "thresh > .05",
+ "pmcstat -s ILD_STALL.LCP -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ lcp_stall, 2 },
+/*6*/ { "cache1", "thresh >= .1",
+ "pmcstat -s MEM_LOAD_UOPS_RETIRED.L3_MISS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ cache1broad, 2 },
+/*7*/ { "cache2", "thresh >= .2",
+ "pmcstat -s MEM_LOAD_UOPS_RETIRED.L3_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ cache2broad, 2 },
+/*8*/ { "contested", "thresh >= .05",
+ "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HITM -s CPU_CLK_UNHALTED.THREAD_P -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_MISS -w 1",
+ contestedbroad, 2 },
+/*9*/ { "datashare", "thresh >= .05",
+ "pmcstat -s MEM_LOAD_UOPS_LLC_HIT_RETIRED.XSNP_HIT -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ datasharing_has, 2 },
+/*10*/ { "blockstorefwd", "thresh >= .05",
+ "pmcstat -s LD_BLOCKS_STORE_FORWARD -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ blockstoreforward, 2 },
+/*11*/ { "aliasing_4k", "thresh >= .1",
+ "pmcstat -s LD_BLOCKS_PARTIAL.ADDRESS_ALIAS -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ aliasing_broad, 2 },
+/*12*/ { "dtlbmissload", "thresh >= .1",
+ "pmcstat -s DTLB_LOAD_MISSES.STLB_HIT_4K -s DTLB_LOAD_MISSES.WALK_DURATION -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ dtlb_missload, 3 },
+/*13*/ { "br_miss", "thresh >= .2",
+ "pmcstat -s CPU_CLK_UNHALTED.THREAD_P -s BR_MISP_RETIRED.ALL_BRANCHES -s MACHINE_CLEARS.CYCLES -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -s INT_MISC.RECOVERY_CYCLES -w 1",
+ br_mispredict_broad, 7 },
+/*14*/ { "clears", "thresh >= .02",
+ "pmcstat -s MACHINE_CLEARS.CYCLES -s MACHINE_CLEARS.MEMORY_ORDERING -s MACHINE_CLEARS.SMC -s MACHINE_CLEARS.MASKMOV -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ clears_broad, 5 },
+/*15*/ { "fpassist", "look for a excessive value",
+ "pmcstat -s FP_ASSIST.ANY -s INST_RETIRED.ANY_P -w 1",
+ fpassists, 2 },
+/*16*/ { "otherassistavx", "look for a excessive value",
+ "pmcstat -s OTHER_ASSISTS.AVX_TO_SSE -s CPU_CLK_UNHALTED.THREAD_P -w 1",
+ otherassistavx, 2 },
+/*17*/ { "microassist", "thresh >= .2",
+ "pmcstat -s IDQ.MS_UOPS,cmask=1 -s CPU_CLK_UNHALTED.THREAD_P -s UOPS_ISSUED.ANY -s UOPS_RETIRED.RETIRE_SLOTS -w 1",
+ microassist_broad, 4 },
};
@@ -1557,8 +1988,19 @@ set_haswell(void)
the_cpu.explain = explain_name_has;
}
+
static void
-set_expression(char *name)
+set_broadwell(void)
+{
+ strcpy(the_cpu.cputype, "HASWELL PMC");
+ the_cpu.number = BROADWELL_COUNT;
+ the_cpu.ents = broadwell;
+ the_cpu.explain = explain_name_broad;
+}
+
+
+static int
+set_expression(const char *name)
{
int found = 0, i;
for(i=0 ; i< the_cpu.number; i++) {
@@ -1567,6 +2009,17 @@ set_expression(char *name)
expression = the_cpu.ents[i].func;
command = the_cpu.ents[i].command;
threshold = the_cpu.ents[i].thresh;
+ if (the_cpu.ents[i].counters_required > max_pmc_counters) {
+ printf("Test %s requires that the CPU have %d counters and this CPU has only %d\n",
+ the_cpu.ents[i].name,
+ the_cpu.ents[i].counters_required, max_pmc_counters);
+ printf("Sorry this test can not be run\n");
+ if (run_all == 0) {
+ exit(-1);
+ } else {
+ return(-1);
+ }
+ }
break;
}
}
@@ -1575,6 +2028,7 @@ set_expression(char *name)
the_cpu.cputype, name);
exit(-1);
}
+ return(0);
}
@@ -1796,10 +2250,6 @@ process_file(char *filename)
if (filename == NULL) {
io = my_popen(command, "r", &pid_of_command);
- if (io == NULL) {
- printf("Can't popen the command %s\n", command);
- return;
- }
} else {
io = fopen(filename, "r");
if (io == NULL) {
@@ -1812,10 +2262,8 @@ process_file(char *filename)
if (cnts == NULL) {
/* Nothing we can do */
printf("Nothing to do -- no counters built\n");
- if (filename) {
- fclose(io);
- } else {
- my_pclose(io, pid_of_command);
+ if (io) {
+ fclose(io);
}
return;
}
@@ -1863,8 +2311,22 @@ process_file(char *filename)
#if defined(__amd64__)
#define cpuid(in,a,b,c,d)\
asm("cpuid": "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (in));
+
+static __inline void
+do_cpuid(u_int ax, u_int cx, u_int *p)
+{
+ __asm __volatile("cpuid"
+ : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
+ : "0" (ax), "c" (cx) );
+}
+
#else
#define cpuid(in, a, b, c, d)
+static __inline void
+do_cpuid(u_int ax, u_int cx, u_int *p)
+{
+}
+
#endif
static void
@@ -1876,6 +2338,7 @@ get_cpuid_set(void)
size_t sz, len;
FILE *io;
char linebuf[1024], *str;
+ u_int reg[4];
eax = ebx = ecx = edx = 0;
@@ -1992,6 +2455,23 @@ get_cpuid_set(void)
printf("Intel HASWELL\n");
set_haswell();
break;
+
+ case 0x4e:
+ case 0x5e:
+ printf("Intel SKY-LAKE\n");
+ goto not_supported;
+ break;
+ case 0x3D:
+ case 0x47:
+ printf("Intel BROADWELL\n");
+ set_broadwell();
+ break;
+ case 0x4f:
+ case 0x56:
+ printf("Intel BROADWEL (Xeon)\n");
+ set_broadwell();
+ break;
+
case 0x4D:
/* Per Intel document 330061-001 01/2014. */
printf("Intel ATOM_SILVERMONT\n");
@@ -2009,6 +2489,9 @@ get_cpuid_set(void)
goto not_supported;
break;
}
+ do_cpuid(0xa, 0, reg);
+ max_pmc_counters = (reg[3] & 0x0000000f) + 1;
+ printf("We have %d PMC counters to work with\n", max_pmc_counters);
/* Ok lets load the list of all known PMC's */
io = my_popen("/usr/sbin/pmccontrol -L", "r", &pid_of_command);
if (valid_pmcs == NULL) {
@@ -2320,14 +2803,18 @@ main(int argc, char **argv)
{
int i, j, cnt;
char *filename=NULL;
- char *name=NULL;
+ const char *name=NULL;
int help_only = 0;
int test_mode = 0;
+ int test_at = 0;
get_cpuid_set();
memset(glob_cpu, 0, sizeof(glob_cpu));
- while ((i = getopt(argc, argv, "LHhvm:i:?e:TE:")) != -1) {
+ while ((i = getopt(argc, argv, "ALHhvm:i:?e:TE:")) != -1) {
switch (i) {
+ case 'A':
+ run_all = 1;
+ break;
case 'L':
list_all();
return(0);
@@ -2383,23 +2870,28 @@ main(int argc, char **argv)
printf("-h -- Don't do the expression I put in -e xxx just explain what it does and exit\n");
printf("-H -- Don't run anything, just explain all canned expressions\n");
printf("-T -- Test all PMC's defined by this processor\n");
+ printf("-A -- Run all canned tests\n");
return(0);
break;
};
}
- if ((name == NULL) && (filename == NULL) && (test_mode == 0) && (master_exp == NULL)) {
+ if ((run_all == 0) && (name == NULL) && (filename == NULL) &&
+ (test_mode == 0) && (master_exp == NULL)) {
printf("Without setting an expression we cannot dynamically gather information\n");
printf("you must supply a filename (and you probably want verbosity)\n");
goto use;
}
+ if (run_all && max_to_collect > 10) {
+ max_to_collect = 3;
+ }
if (test_mode) {
run_tests();
return(0);
}
printf("*********************************\n");
- if (master_exp == NULL) {
+ if ((master_exp == NULL) && name) {
(*the_cpu.explain)(name);
- } else {
+ } else if (master_exp) {
printf("Examine your expression ");
print_exp(master_exp);
printf("User defined threshold\n");
@@ -2407,6 +2899,19 @@ main(int argc, char **argv)
if (help_only) {
return(0);
}
+ if (run_all) {
+ more:
+ name = the_cpu.ents[test_at].name;
+ printf("***Test %s (threshold %s)****\n", name, the_cpu.ents[test_at].thresh);
+ test_at++;
+ if (set_expression(name) == -1) {
+ if (test_at >= the_cpu.number) {
+ goto done;
+ } else
+ goto more;
+ }
+
+ }
process_file(filename);
if (verbose >= 2) {
for (i=0; i<ncnts; i++) {
@@ -2422,17 +2927,28 @@ main(int argc, char **argv)
if (expression == NULL) {
return(0);
}
- for(i=0, cnt=0; i<MAX_CPU; i++) {
- if (glob_cpu[i]) {
- do_expression(glob_cpu[i], -1);
- cnt++;
- if (cnt == cpu_count_out) {
- printf("\n");
- break;
- } else {
- printf("\t");
+ if (max_to_collect > 1) {
+ for(i=0, cnt=0; i<MAX_CPU; i++) {
+ if (glob_cpu[i]) {
+ do_expression(glob_cpu[i], -1);
+ cnt++;
+ if (cnt == cpu_count_out) {
+ printf("\n");
+ break;
+ } else {
+ printf("\t");
+ }
}
}
}
+ if (run_all && (test_at < the_cpu.number)) {
+ memset(glob_cpu, 0, sizeof(glob_cpu));
+ ncnts = 0;
+ printf("*********************************\n");
+ goto more;
+ } else if (run_all) {
+ done:
+ printf("*********************************\n");
+ }
return(0);
}
diff --git a/usr.sbin/ppp/ip.c b/usr.sbin/ppp/ip.c
index 5cd2272..5c25a09 100644
--- a/usr.sbin/ppp/ip.c
+++ b/usr.sbin/ppp/ip.c
@@ -473,7 +473,7 @@ FilterCheck(const unsigned char *packet,
ncpaddr_ntoa(&srcaddr), sport, dstip, dport);
}
return 1;
- } /* Explict match. Deny this packet */
+ } /* Explicit match. Deny this packet */
}
} else {
n++;
diff --git a/usr.sbin/ppp/ppp.8 b/usr.sbin/ppp/ppp.8
index 59eeaed..3fc6b81 100644
--- a/usr.sbin/ppp/ppp.8
+++ b/usr.sbin/ppp/ppp.8
@@ -5404,7 +5404,7 @@ and
.Dq default
can be used for
.Ar dest
-to sepcify the default route, and
+to specify the default route, and
.Dq 0.0.0.0
is understood to be the same as
.Dq default
@@ -5454,7 +5454,7 @@ and
.Dq default
can be used for
.Ar dest
-to sepcify the default route, and
+to specify the default route, and
.Dq ::
is understood to be the same as
.Dq default
diff --git a/usr.sbin/praliases/Makefile b/usr.sbin/praliases/Makefile
index 6fadc1b..b0b3e2d 100644
--- a/usr.sbin/praliases/Makefile
+++ b/usr.sbin/praliases/Makefile
@@ -24,7 +24,7 @@ LDFLAGS+=${SENDMAIL_LDFLAGS}
DPADD+= ${SENDMAIL_DPADD}
LDADD+= ${SENDMAIL_LDADD}
-sm_os.h:
- ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/praliases/Makefile.depend b/usr.sbin/praliases/Makefile.depend
index 0cd5be8..75daedb 100644
--- a/usr.sbin/praliases/Makefile.depend
+++ b/usr.sbin/praliases/Makefile.depend
@@ -12,7 +12,6 @@ DIRDEPS = \
lib/libsm \
lib/libsmdb \
lib/libsmutil \
- lib/libutil \
.include <dirdeps.mk>
diff --git a/usr.sbin/pstat/Makefile.depend b/usr.sbin/pstat/Makefile.depend
index e01f8c7..7c356c9 100644
--- a/usr.sbin/pstat/Makefile.depend
+++ b/usr.sbin/pstat/Makefile.depend
@@ -9,6 +9,7 @@ DIRDEPS = \
lib/${CSU_DIR} \
lib/libc \
lib/libcompiler_rt \
+ lib/libelf \
lib/libkvm \
lib/libutil \
diff --git a/usr.sbin/pw/pw_conf.c b/usr.sbin/pw/pw_conf.c
index e9606b4..d30c80e 100644
--- a/usr.sbin/pw/pw_conf.c
+++ b/usr.sbin/pw/pw_conf.c
@@ -313,7 +313,7 @@ read_userconfig(char const * file)
? NULL : newstr(q);
break;
case _UC_EXTRAGROUPS:
- for (i = 0; q != NULL; q = strtok(NULL, toks)) {
+ while ((q = strtok(NULL, toks)) != NULL) {
if (config.groups == NULL)
config.groups = sl_init();
sl_add(config.groups, newstr(q));
diff --git a/usr.sbin/pw/pw_group.c b/usr.sbin/pw/pw_group.c
index 711ef68..289a4c8 100644
--- a/usr.sbin/pw/pw_group.c
+++ b/usr.sbin/pw/pw_group.c
@@ -259,7 +259,7 @@ pw_group_next(int argc, char **argv, char *arg1 __unused)
struct userconf *cnf;
const char *cfg = NULL;
int ch;
- bool quiet;
+ bool quiet = false;
while ((ch = getopt(argc, argv, "Cq")) != -1) {
switch (ch) {
@@ -664,6 +664,11 @@ pw_group_mod(int argc, char **argv, char *arg1)
grp_add_members(&grp, newmembers);
}
+ if (dryrun) {
+ print_group(grp, pretty);
+ return (EXIT_SUCCESS);
+ }
+
if ((rc = chggrent(name, grp)) != 0) {
if (rc == -1)
errx(EX_IOERR, "group '%s' not available (NIS?)",
diff --git a/usr.sbin/pw/pw_user.c b/usr.sbin/pw/pw_user.c
index 1af8f81..30a2749 100644
--- a/usr.sbin/pw/pw_user.c
+++ b/usr.sbin/pw/pw_user.c
@@ -107,8 +107,10 @@ mkdir_home_parents(int dfd, const char *dir)
errx(EX_UNAVAILABLE, "out of memory");
tmp = strrchr(dirs, '/');
- if (tmp == NULL)
+ if (tmp == NULL) {
+ free(dirs);
return;
+ }
tmp[0] = '\0';
/*
@@ -272,7 +274,7 @@ pw_userlock(char *arg1, int mode)
char *passtmp = NULL;
char *name;
bool locked = false;
- uid_t id;
+ uid_t id = (uid_t)-1;
if (geteuid() != 0)
errx(EX_NOPERM, "you must be root");
@@ -280,15 +282,19 @@ pw_userlock(char *arg1, int mode)
if (arg1 == NULL)
errx(EX_DATAERR, "username or id required");
- if (arg1[strspn(arg1, "0123456789")] == '\0')
- id = pw_checkid(arg1, UID_MAX);
- else
- name = arg1;
+ name = arg1;
+ if (arg1[strspn(name, "0123456789")] == '\0')
+ id = pw_checkid(name, UID_MAX);
- pwd = (name != NULL) ? GETPWNAM(pw_checkname(name, 0)) : GETPWUID(id);
+ pwd = GETPWNAM(pw_checkname(name, 0));
+ if (pwd == NULL && id != (uid_t)-1) {
+ pwd = GETPWUID(id);
+ if (pwd != NULL)
+ name = pwd->pw_name;
+ }
if (pwd == NULL) {
- if (name == NULL)
- errx(EX_NOUSER, "no such uid `%ju'", (uintmax_t) id);
+ if (id == (uid_t)-1)
+ errx(EX_NOUSER, "no such name or uid `%ju'", (uintmax_t) id);
errx(EX_NOUSER, "no such user `%s'", name);
}
@@ -636,7 +642,8 @@ pw_checkname(char *name, int gecos)
}
if (!reject) {
while (*ch) {
- if (strchr(badchars, *ch) != NULL || *ch < ' ' ||
+ if (strchr(badchars, *ch) != NULL ||
+ (!gecos && *ch < ' ') ||
*ch == 127) {
reject = 1;
break;
diff --git a/usr.sbin/pw/pw_vpw.c b/usr.sbin/pw/pw_vpw.c
index a23c66e..2d1c75b 100644
--- a/usr.sbin/pw/pw_vpw.c
+++ b/usr.sbin/pw/pw_vpw.c
@@ -70,7 +70,6 @@ vnextpwent(char const *nam, uid_t uid, int doclose)
pw = NULL;
line = NULL;
linecap = 0;
- linelen = 0;
if (pwd_fp != NULL || (pwd_fp = fopen(getpwpath(_MASTERPASSWD), "r")) != NULL) {
while ((linelen = getline(&line, &linecap, pwd_fp)) > 0) {
@@ -153,7 +152,6 @@ vnextgrent(char const *nam, gid_t gid, int doclose)
gr = NULL;
line = NULL;
linecap = 0;
- linelen = 0;
if (grp_fp != NULL || (grp_fp = fopen(getgrpath(_GROUP), "r")) != NULL) {
while ((linelen = getline(&line, &linecap, grp_fp)) > 0) {
diff --git a/usr.sbin/pw/tests/pw_lock.sh b/usr.sbin/pw/tests/pw_lock.sh
index 9f14e24..5ec1b09 100755
--- a/usr.sbin/pw/tests/pw_lock.sh
+++ b/usr.sbin/pw/tests/pw_lock.sh
@@ -16,7 +16,27 @@ user_locking_body() {
grep "^test:\*:1001:" $HOME/master.passwd
}
+atf_test_case numeric_locking cleanup
+numeric_locking_body() {
+ populate_etc_skel
+ ${PW} useradd test || atf_fail "Creating test user"
+ ${PW} lock 1001 || atf_fail "Locking the user"
+ atf_check -s exit:0 -o match:"^test:\*LOCKED\*\*:1001:" \
+ grep "^test:\*LOCKED\*\*:1001:" $HOME/master.passwd
+ ${PW} unlock 1001 || atf_fail "Unlocking the user"
+ atf_check -s exit:0 -o match:"^test:\*:1001:" \
+ grep "^test:\*:1001:" $HOME/master.passwd
+ # Now numeric names
+ ${PW} useradd -n 1001 || atf_fail "Creating test user"
+ ${PW} lock 1001 || atf_fail "Locking the user"
+ atf_check -s exit:0 -o match:"^1001:\*LOCKED\*\*:1002:" \
+ grep "^1001:\*LOCKED\*\*:1002:" $HOME/master.passwd
+ ${PW} unlock 1001 || atf_fail "Unlocking the user"
+ atf_check -s exit:0 -o match:"^1001:\*:1002:" \
+ grep "^1001:\*:1002:" $HOME/master.passwd
+}
atf_init_test_cases() {
atf_add_test_case user_locking
+ atf_add_test_case numeric_locking
}
diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c
index c382cb5..fe44520 100644
--- a/usr.sbin/pwd_mkdb/pwd_mkdb.c
+++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c
@@ -352,7 +352,7 @@ main(int argc, char *argv[])
data.size = 1;
if ((dp->put)(dp, &key, &data, 0) == -1)
error("put");
- if ((dp->put)(sdp, &key, &data, 0) == -1)
+ if ((sdp->put)(sdp, &key, &data, 0) == -1)
error("put");
}
ypcnt = 0;
diff --git a/usr.sbin/rpc.lockd/lockd.c b/usr.sbin/rpc.lockd/lockd.c
index 4f1347e..88b19b7 100644
--- a/usr.sbin/rpc.lockd/lockd.c
+++ b/usr.sbin/rpc.lockd/lockd.c
@@ -220,7 +220,7 @@ main(int argc, char **argv)
* list.
*/
if (nhosts == 0) {
- hosts = malloc(sizeof(char**));
+ hosts = malloc(sizeof(char *));
if (hosts == NULL)
out_of_mem();
diff --git a/usr.sbin/rpc.statd/statd.c b/usr.sbin/rpc.statd/statd.c
index faa8513..256f58d 100644
--- a/usr.sbin/rpc.statd/statd.c
+++ b/usr.sbin/rpc.statd/statd.c
@@ -150,7 +150,7 @@ main(int argc, char **argv)
* list.
*/
if (nhosts == 0) {
- hosts = malloc(sizeof(char**));
+ hosts = malloc(sizeof(char *));
if (hosts == NULL)
out_of_mem();
diff --git a/usr.sbin/rpc.yppasswdd/Makefile b/usr.sbin/rpc.yppasswdd/Makefile
index 5f5fb77..9b2fb39 100644
--- a/usr.sbin/rpc.yppasswdd/Makefile
+++ b/usr.sbin/rpc.yppasswdd/Makefile
@@ -7,7 +7,7 @@ RPCDIR= ${DESTDIR}/usr/include/rpcsvc
PROG= rpc.yppasswdd
SCRIPTS=yppwupdate
-SCRIPTSDIR= /usr/libexec
+SCRIPTSDIR= ${LIBEXECDIR}
MAN= rpc.yppasswdd.8
SRCS= util.c yp_access.c yp_dblookup.c yp_dbwrite.c \
yp_error.c yppasswdd_main.c yppasswdd_server.c ypxfr_misc.c ${GENSRCS}
diff --git a/usr.sbin/rtadvd/config.c b/usr.sbin/rtadvd/config.c
index 4f14e0fb..d63af5a 100644
--- a/usr.sbin/rtadvd/config.c
+++ b/usr.sbin/rtadvd/config.c
@@ -808,7 +808,7 @@ getconfig_free_rti:
makeentry(entbuf, sizeof(entbuf), i, "rdnss");
addr = (char *)agetstr(entbuf, &bp);
if (addr == NULL)
- break;
+ continue;
ELM_MALLOC(rdn, exit(1));
TAILQ_INIT(&rdn->rd_list);
@@ -859,7 +859,7 @@ getconfig_free_rdn:
makeentry(entbuf, sizeof(entbuf), i, "dnssl");
addr = (char *)agetstr(entbuf, &bp);
if (addr == NULL)
- break;
+ continue;
ELM_MALLOC(dns, exit(1));
@@ -1528,6 +1528,7 @@ make_packet(struct rainfo *rai)
/* Padding to next 8 octets boundary */
len = buf - (char *)ndopt_dnssl;
len += (len % 8) ? 8 - len % 8 : 0;
+ buf = (char *)ndopt_dnssl + len;
/* Length field must be in 8 octets */
ndopt_dnssl->nd_opt_dnssl_len = len / 8;
diff --git a/usr.sbin/rtadvd/if.c b/usr.sbin/rtadvd/if.c
index 0eef734..b9af28d 100644
--- a/usr.sbin/rtadvd/if.c
+++ b/usr.sbin/rtadvd/if.c
@@ -358,8 +358,7 @@ update_persist_ifinfo(struct ifilist_head_t *ifi_head, const char *ifname)
ELM_MALLOC(ifi, exit(1));
ifi->ifi_ifindex = 0;
- strncpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname)-1);
- ifi->ifi_ifname[sizeof(ifi->ifi_ifname)-1] = '\0';
+ strlcpy(ifi->ifi_ifname, ifname, sizeof(ifi->ifi_ifname));
ifi->ifi_rainfo = NULL;
ifi->ifi_state = IFI_STATE_UNCONFIGURED;
TAILQ_INSERT_TAIL(ifi_head, ifi, ifi_next);
diff --git a/usr.sbin/rtsold/rtsold.c b/usr.sbin/rtsold/rtsold.c
index 85ee133..1482798 100644
--- a/usr.sbin/rtsold/rtsold.c
+++ b/usr.sbin/rtsold/rtsold.c
@@ -779,15 +779,15 @@ static void
usage(void)
{
#ifndef SMALL
- fprintf(stderr, "usage: rtsold [-adDfFm1] [-O script-name] "
- "[-P pidfile] [-R script-name] interfaces...\n");
fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
- "[-P pidfile] [-R script-name] -a\n");
+ "[-p pidfile] [-R script-name] interface ...\n");
+ fprintf(stderr, "usage: rtsold [-dDfFm1] [-O script-name] "
+ "[-p pidfile] [-R script-name] -a\n");
#else
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
- "[-P pidfile] [-R script-name] interfaces...\n");
+ "[-p pidfile] [-R script-name] interface ...\n");
fprintf(stderr, "usage: rtsol [-dDF] [-O script-name] "
- "[-P pidfile] [-R script-name] -a\n");
+ "[-p pidfile] [-R script-name] -a\n");
#endif
}
@@ -888,7 +888,7 @@ autoifprobe(void)
warnmsg(LOG_WARNING, __func__,
"multiple interfaces found");
- a = (char **)realloc(argv, (n + 1) * sizeof(char **));
+ a = realloc(argv, (n + 1) * sizeof(char *));
if (a == NULL) {
warnmsg(LOG_ERR, __func__, "realloc");
exit(1);
@@ -903,7 +903,7 @@ autoifprobe(void)
}
if (n) {
- a = (char **)realloc(argv, (n + 1) * sizeof(char **));
+ a = realloc(argv, (n + 1) * sizeof(char *));
if (a == NULL) {
warnmsg(LOG_ERR, __func__, "realloc");
exit(1);
diff --git a/usr.sbin/rtsold/rtsold.h b/usr.sbin/rtsold/rtsold.h
index 56b4185..f19fb3c 100644
--- a/usr.sbin/rtsold/rtsold.h
+++ b/usr.sbin/rtsold/rtsold.h
@@ -67,7 +67,7 @@ struct ifinfo {
int active; /* interface status */
int probeinterval; /* interval of probe timer (if necessary) */
int probetimer; /* rest of probe timer */
- int mediareqok; /* wheter the IF supports SIOCGIFMEDIA */
+ int mediareqok; /* whether the IF supports SIOCGIFMEDIA */
int otherconfig; /* need a separate protocol for the "other"
* configuration */
int state;
diff --git a/usr.sbin/sendmail/Makefile b/usr.sbin/sendmail/Makefile
index d201d91..f9641c1 100644
--- a/usr.sbin/sendmail/Makefile
+++ b/usr.sbin/sendmail/Makefile
@@ -7,7 +7,7 @@ SENDMAIL_DIR=${.CURDIR}/../../contrib/sendmail
SMDIR= ${SENDMAIL_DIR}/src
.PATH: ${SMDIR}
-BINDIR= /usr/libexec/sendmail
+BINDIR= ${LIBEXECDIR}/sendmail
PROG= sendmail
MAN= mailq.1 newaliases.1 aliases.5 sendmail.8
@@ -62,7 +62,7 @@ DPADD+=${SENDMAIL_DPADD}
LDADD+=${SENDMAIL_LDADD}
LDFLAGS+=${SENDMAIL_LDFLAGS}
-sm_os.h:
- ln -sf ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h sm_os.h
+sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA
+ ln -sf ${.ALLSRC} ${.TARGET}
.include <bsd.prog.mk>
diff --git a/usr.sbin/sesutil/Makefile b/usr.sbin/sesutil/Makefile
index 347223d..bf37192 100644
--- a/usr.sbin/sesutil/Makefile
+++ b/usr.sbin/sesutil/Makefile
@@ -4,4 +4,6 @@ PROG= sesutil
SRCS= sesutil.c eltsub.c
MAN= sesutil.8
+LIBADD= sbuf
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/sesutil/eltsub.c b/usr.sbin/sesutil/eltsub.c
index dae02fe..287530d 100644
--- a/usr.sbin/sesutil/eltsub.c
+++ b/usr.sbin/sesutil/eltsub.c
@@ -32,6 +32,11 @@
* mjacob@feral.com
*/
+#include <sys/endian.h>
+#include <sys/types.h>
+#include <sys/sbuf.h>
+
+#include <err.h>
#include <unistd.h>
#include <stddef.h>
#include <stdint.h>
@@ -43,6 +48,13 @@
#include "eltsub.h"
+/*
+ * offset by +20 degrees.
+ * The range of the value expresses a temperature between -19 and +235 degrees
+ * Celsius. A value of 00h is reserved.
+ */
+#define TEMPERATURE_OFFSET 20
+
char *
geteltnm(int type)
{
@@ -134,7 +146,7 @@ geteltnm(int type)
return (rbuf);
}
-static char *
+char *
scode2ascii(u_char code)
{
static char rbuf[32];
@@ -173,22 +185,51 @@ scode2ascii(u_char code)
return (rbuf);
}
-
-char *
-stat2ascii(int eletype, u_char *cstat)
+struct sbuf *
+stat2sbuf(int eletype, u_char *cstat)
{
- static char ebuf[256], *scode;
+ struct sbuf *buf;
+
+ buf = sbuf_new_auto();
+ if (buf == NULL)
+ err(EXIT_FAILURE, "sbuf_new_auto()");
- scode = scode2ascii(cstat[0]);
- sprintf(ebuf, "%s%s%s%s%s%s (0x%02x 0x%02x 0x%02x 0x%02x)",
- scode,
- (cstat[0] & 0x40) ? ", Prd.Fail" : "",
- (cstat[0] & 0x20) ? ", Disabled" : "",
- (cstat[0] & 0x10) ? ", Swapped" : "",
- (eletype == ELMTYP_DEVICE && (cstat[2] & 0x02)) ?
- ", LED=Locate" : "",
- (eletype == ELMTYP_DEVICE && (cstat[3] & 0x20)) ?
- ", LED=Fault" : "",
- cstat[0], cstat[1], cstat[2], cstat[3]);
- return (ebuf);
+ if (cstat[0] & 0x40)
+ sbuf_printf(buf, "\t\t- Predicted Failure\n");
+ if (cstat[0] & 0x20)
+ sbuf_printf(buf, "\t\t- Disabled\n");
+ if (cstat[0] & 0x10)
+ sbuf_printf(buf, "\t\t- Swapped\n");
+ switch (eletype) {
+ case ELMTYP_DEVICE:
+ if (cstat[2] & 0x02)
+ sbuf_printf(buf, "\t\t- LED=locate\n");
+ if (cstat[2] & 0x20)
+ sbuf_printf(buf, "\t\t- LED=fault\n");
+ break;
+ case ELMTYP_ARRAY_DEV:
+ if (cstat[2] & 0x02)
+ sbuf_printf(buf, "\t\t- LED=locate\n");
+ if (cstat[2] & 0x20)
+ sbuf_printf(buf, "\t\t- LED=fault\n");
+ break;
+ case ELMTYP_FAN:
+ sbuf_printf(buf, "\t\t- Speed: %d rpm\n",
+ (((0x7 & cstat[1]) << 8) + cstat[2]) * 10);
+ break;
+ case ELMTYP_THERM:
+ if (cstat[2]) {
+ sbuf_printf(buf, "\t\t- Temperature: %d C\n",
+ cstat[2] - TEMPERATURE_OFFSET);
+ } else {
+ sbuf_printf(buf, "\t\t- Temperature: -reserved-\n");
+ }
+ break;
+ case ELMTYP_VOM:
+ sbuf_printf(buf, "\t\t- Voltage: %.2f V\n",
+ be16dec(cstat + 2) / 100.0);
+ break;
+ }
+ sbuf_finish(buf);
+ return (buf);
}
diff --git a/usr.sbin/sesutil/eltsub.h b/usr.sbin/sesutil/eltsub.h
index 3d98572..299ada3 100644
--- a/usr.sbin/sesutil/eltsub.h
+++ b/usr.sbin/sesutil/eltsub.h
@@ -32,5 +32,6 @@
* mjacob@feral.com
*/
-char * geteltnm(int);
-char * stat2ascii(int, u_char *);
+char *geteltnm(int);
+char *scode2ascii(u_char);
+struct sbuf *stat2sbuf(int, u_char *);
diff --git a/usr.sbin/sesutil/sesutil.c b/usr.sbin/sesutil/sesutil.c
index 7ce9045..0f04c07 100644
--- a/usr.sbin/sesutil/sesutil.c
+++ b/usr.sbin/sesutil/sesutil.c
@@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/sbuf.h>
#include <err.h>
#include <errno.h>
@@ -170,7 +172,7 @@ sesled(int argc, char **argv, bool setfault)
sesid = strtoul(disk, &endptr, 10);
if (*endptr == '\0') {
endptr = strrchr(uflag, '*');
- if (*endptr == '*') {
+ if (endptr != NULL && *endptr == '*') {
warnx("Must specifying a SES device (-u) to use a SES "
"id# to identify a disk");
usage(stderr, (setfault ? "fault" : "locate"));
@@ -299,6 +301,8 @@ fault(int argc, char **argv)
static int
objmap(int argc, char **argv __unused)
{
+ struct sbuf *extra;
+ encioc_string_t stri;
encioc_elm_devnames_t e_devname;
encioc_elm_status_t e_status;
encioc_elm_desc_t e_desc;
@@ -307,6 +311,7 @@ objmap(int argc, char **argv __unused)
int fd;
unsigned int j, nobj;
size_t i;
+ char str[32];
if (argc != 1) {
usage(stderr, "map");
@@ -352,6 +357,15 @@ objmap(int argc, char **argv __unused)
}
printf("%s:\n", g.gl_pathv[i] + 5);
+ stri.bufsiz = sizeof(str);
+ stri.buf = &str[0];
+ if (ioctl(fd, ENCIOC_GETENCNAME, (caddr_t) &stri) == 0)
+ printf("\tEnclosure Name: %s\n", stri.buf);
+ stri.bufsiz = sizeof(str);
+ stri.buf = &str[0];
+ if (ioctl(fd, ENCIOC_GETENCID, (caddr_t) &stri) == 0)
+ printf("\tEnclosure ID: %s\n", stri.buf);
+
for (j = 0; j < nobj; j++) {
/* Get the status of the element */
memset(&e_status, 0, sizeof(e_status));
@@ -391,8 +405,10 @@ objmap(int argc, char **argv __unused)
}
printf("\tElement %u, Type: %s\n", e_ptr[j].elm_idx,
geteltnm(e_ptr[j].elm_type));
- printf("\t\tStatus: %s\n",
- stat2ascii(e_ptr[i].elm_type, e_status.cstat));
+ printf("\t\tStatus: %s (0x%02x 0x%02x 0x%02x 0x%02x)\n",
+ scode2ascii(e_status.cstat[0]), e_status.cstat[0],
+ e_status.cstat[1], e_status.cstat[2],
+ e_status.cstat[3]);
if (e_desc.elm_desc_len > 0) {
printf("\t\tDescription: %s\n",
e_desc.elm_desc_str);
@@ -401,6 +417,12 @@ objmap(int argc, char **argv __unused)
printf("\t\tDevice Names: %s\n",
e_devname.elm_devnames);
}
+ extra = stat2sbuf(e_ptr[j].elm_type, e_status.cstat);
+ if (sbuf_len(extra) > 0) {
+ printf("\t\tExtra status:\n%s",
+ sbuf_data(extra));
+ }
+ sbuf_delete(extra);
free(e_devname.elm_devnames);
}
close(fd);
diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c
index b5b57b3..cd0f1b6 100644
--- a/usr.sbin/syslogd/syslogd.c
+++ b/usr.sbin/syslogd/syslogd.c
@@ -341,6 +341,7 @@ static void printsys(char *);
static int p_open(const char *, pid_t *);
static void readklog(void);
static void reapchild(int);
+static const char *ttymsg_check(struct iovec *, int, char *, int);
static void usage(void);
static int validate(struct sockaddr *, const char *);
static void unmapped(struct sockaddr *);
@@ -1425,7 +1426,7 @@ wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
if (!f->f_un.f_uname[i][0])
break;
if (!strcmp(f->f_un.f_uname[i], ut->ut_user)) {
- if ((p = ttymsg(iov, iovlen, ut->ut_line,
+ if ((p = ttymsg_check(iov, iovlen, ut->ut_line,
TTYMSGTIME)) != NULL) {
errno = 0; /* already in msg */
logerror(p);
@@ -1438,6 +1439,29 @@ wallmsg(struct filed *f, struct iovec *iov, const int iovlen)
reenter = 0;
}
+/*
+ * Wrapper routine for ttymsg() that checks the terminal for messages enabled.
+ */
+static const char *
+ttymsg_check(struct iovec *iov, int iovcnt, char *line, int tmout)
+{
+ static char device[1024];
+ static char errbuf[1024];
+ struct stat sb;
+
+ (void) snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line);
+
+ if (stat(device, &sb) < 0) {
+ (void) snprintf(errbuf, sizeof(errbuf),
+ "%s: %s", device, strerror(errno));
+ return (errbuf);
+ }
+ if ((sb.st_mode & S_IWGRP) == 0)
+ /* Messages disabled. */
+ return (NULL);
+ return ttymsg(iov, iovcnt, line, tmout);
+}
+
static void
reapchild(int signo __unused)
{
diff --git a/usr.sbin/sysrc/Makefile.depend b/usr.sbin/sysrc/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/sysrc/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/sysrc/sysrc b/usr.sbin/sysrc/sysrc
index 2a24551..e384dff 100644
--- a/usr.sbin/sysrc/sysrc
+++ b/usr.sbin/sysrc/sysrc
@@ -40,18 +40,23 @@ BSDCFG_SHARE="/usr/share/bsdconfig"
#
# Version information
#
-SYSRC_VERSION="6.5 Sep-1,2015"
+SYSRC_VERSION="7.0 Sep-13,2015"
#
# Options
#
CHECK_ONLY=
+DEFAULT=
DELETE=
DESCRIBE=
+EXISTING_ONLY=
IGNORE_UNKNOWNS=
JAIL=
+LIST_SERVICE_CONFS=
+LIST_CONFS=
QUIET=
ROOTDIR=
+SERVICE=
SHOW_ALL=
SHOW_EQUALS=
SHOW_FILE=
@@ -80,7 +85,8 @@ die()
#
usage()
{
- f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] %s\n" "$pgm" \
+ "{name[[+|-]=value] ... | -a | -A | -l | -L [name ...]}"
f_err "Try \`%s --help' for more information.\n" "$pgm"
die
}
@@ -95,6 +101,8 @@ help()
local envfmt="\t%-17s%s\n"
f_err "Usage: %s [OPTIONS] name[[+|-]=value] ...\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] -a | -A\n" "$pgm"
+ f_err "Usage: %s [OPTIONS] -l | -L [name ...]\n" "$pgm"
f_err "OPTIONS:\n"
f_err "$optfmt" "-a" \
@@ -113,6 +121,8 @@ help()
"Print query results as \`var=value' (useful for producing"
f_err "$optfmt" "" \
"output to be fed back in). Ignored if \`-n' is specified."
+ f_err "$optfmt" "-E" \
+ "Existing files only with \`-[lL]' or when changing a setting."
f_err "$optfmt" "-f file" \
"Operate on the specified file(s) instead of rc_conf_files."
f_err "$optfmt" "" \
@@ -129,12 +139,20 @@ help()
"The jid or name of the jail to operate within (overrides"
f_err "$optfmt" "" \
"\`-R dir'; requires jexec(8))."
+ f_err "$optfmt" "-l" \
+ "List configuration files used at startup on stdout and exit."
+ f_err "$optfmt" "-L" \
+ "List all configuration files including rc.conf.d entries."
f_err "$optfmt" "-n" \
"Show only variable values, not their names."
f_err "$optfmt" "-N" \
"Show only variable names, not their values."
f_err "$optfmt" "-q" \
"Quiet. Disable verbose and hide certain errors."
+ f_err "$optfmt" "-s name" \
+ "Process additional \`rc.conf.d' entries for service name."
+ f_err "$optfmt" "" \
+ "Ignored if \`-f file' is given."
f_err "$optfmt" "-R dir" \
"Operate within the root directory \`dir' rather than \`/'."
f_err "$optfmt" "-v" \
@@ -245,27 +263,33 @@ unset arg
#
# Process command-line flags
#
-while getopts aAcdDef:Fhij:nNqR:vxX flag; do
+while getopts aAcdDeEf:Fhij:lLnNqR:s:vxX flag; do
case "$flag" in
a) SHOW_ALL=${SHOW_ALL:-1} ;;
A) SHOW_ALL=2 ;;
c) CHECK_ONLY=1 ;;
d) DESCRIBE=1 ;;
- D) RC_CONFS= ;;
+ D) DEFAULT=1 RC_CONFS= ;;
e) SHOW_EQUALS=1 ;;
- f) RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;;
+ E) EXISTING_ONLY=1 ;;
+ f) DEFAULT= RC_CONFS="$RC_CONFS${RC_CONFS:+ }$OPTARG" ;;
F) SHOW_FILE=1 ;;
h) usage ;; # NOTREACHED
i) IGNORE_UNKNOWNS=1 ;;
j) [ "$OPTARG" ] ||
die "%s: Missing or null argument to \`-j' flag" "$pgm"
JAIL="$OPTARG" ;;
+ l) LIST_CONFS=1 ;;
+ L) LIST_SERVICE_CONFS=1 ;;
n) SHOW_NAME= ;;
N) SHOW_VALUE= ;;
q) QUIET=1 VERBOSE= ;;
R) [ "$OPTARG" ] ||
die "%s: Missing or null argument to \`-R' flag" "$pgm"
ROOTDIR="$OPTARG" ;;
+ s) [ "$OPTARG" ] ||
+ die "%s: Missing or null argument to \`-s' flag" "$pgm"
+ SERVICE="$OPTARG" ;;
v) VERBOSE=1 QUIET= ;;
x) DELETE=${DELETE:-1} ;;
X) DELETE=2 ;;
@@ -275,6 +299,129 @@ done
shift $(( $OPTIND - 1 ))
#
+# Process `-L' flag
+#
+if [ "$LIST_SERVICE_CONFS" ]; then
+ list=
+
+ #
+ # List rc_conf_files if no service names given
+ #
+ files=
+ [ $# -eq 0 ] && files=$( f_sysrc_get rc_conf_files )
+ for file in $files; do
+ if [ "$EXISTING_ONLY" ]; then
+ [ -e "$file" -a ! -d "$file" ] || continue
+ fi
+ case "$list" in
+ "$file"|*" $file"|"$file "*|*" $file "*) continue ;;
+ esac
+ list="$list $file"
+ done
+ list="${list# }"
+ if [ $# -eq 0 ]; then
+ if [ "$VERBOSE" ]; then
+ echo rc_conf_files: $list
+ elif [ "$SHOW_EQUALS" ]; then
+ echo "rc_conf_files=\"$list\""
+ fi
+ fi
+
+ #
+ # List rc.conf.d entries
+ #
+ retval=$SUCCESS
+ for service in ${*:-$( service -l )}; do
+ slist=
+ f_sysrc_service_configs $service files || retval=$? continue
+ for file in $files; do
+ if [ "$EXISTING_ONLY" ]; then
+ [ -e "$file" -a ! -d "$file" ] || continue
+ fi
+ if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then
+ case "$list" in
+ "$file"|*" $file"|"$file "*|*" $file "*)
+ continue ;;
+ esac
+ fi
+ slist="$slist $file"
+ done
+ slist="${slist# }"
+ if [ $# -gt 0 ]; then
+ [ "$slist" ] || retval=$?
+ fi
+ if [ "$VERBOSE" ]; then
+ [ "$slist" ] && echo "$service: $slist"
+ continue
+ elif [ "$SHOW_EQUALS" ]; then
+ [ "$slist" ] && echo "$service=\"$slist\""
+ continue
+ fi
+ list="$list${slist:+ }$slist"
+ done
+ if [ ! "$VERBOSE" -a ! "$SHOW_EQUALS" ]; then
+ if [ $# -eq 0 -o ! "$QUIET" ]; then
+ list="${list# }"
+ [ "$list" ] && echo $list
+ fi
+ fi
+
+ exit $retval
+fi
+
+#
+# Process `-s name' argument
+#
+if [ "$SERVICE" -a ! "${RC_CONFS+set}" ]; then
+ if f_sysrc_service_configs "$SERVICE" RC_CONFS; then
+ rc_conf_files=$( f_sysrc_get rc_conf_files )
+ RC_CONFS="$rc_conf_files${RC_CONFS:+ }$RC_CONFS"
+ unset rc_conf_files
+ else
+ unset RC_CONFS
+ fi
+fi
+
+#
+# Process `-E' option flag
+#
+if [ "$EXISTING_ONLY" ]; then
+ #
+ # To get f_sysrc_*() to ignore missing rc_conf_files, we have to use
+ # RC_CONFS to override the unpreened value. If RC_CONFS already has a
+ # value (`-D', `-f file', `-s name', or inherited from parent), use it.
+ # Otherwise, include filtered contents of rc_conf_files.
+ #
+ RC_CONFS=$(
+ if [ "${RC_CONFS+set}" ]; then
+ set -- $RC_CONFS
+ else
+ set -- $( f_sysrc_get rc_conf_files )
+ fi
+ while [ $# -gt 0 ]; do
+ [ -f "$1" ] && echo -n " $1"
+ shift
+ done
+ )
+ RC_CONFS="${RC_CONFS# }"
+fi
+
+#
+# Process `-l' option flag
+#
+if [ "$LIST_CONFS" ]; then
+ [ $# -eq 0 ] || usage
+ if [ "$DEFAULT" ]; then
+ echo "$RC_DEFAULTS"
+ elif [ "${RC_CONFS+set}" ]; then
+ echo "$RC_CONFS"
+ else
+ f_sysrc_get rc_conf_files
+ fi
+ exit $SUCCESS
+fi
+
+#
# [More] Sanity checks (e.g., "sysrc --")
#
[ $# -eq 0 -a ! "$SHOW_ALL" ] && usage # NOTREACHED
@@ -344,6 +491,10 @@ if [ "$JAIL" -o "$ROOTDIR" ]; then
$( [ "$SHOW_ALL" = "1" ] && echo \ -a )
$( [ "$SHOW_ALL" = "2" ] && echo \ -A )
${CHECK_ONLY:+-c}
+ ${DEFAULT:+-D}
+ ${EXISTING_ONLY:+-E}
+ ${LIST_CONFS:+-l}
+ ${LIST_SERVICE_CONFS:+-L}
${DESCRIBE:+-d}
${SHOW_EQUALS:+-e}
${IGNORE_UNKNOWNS:+-i}
@@ -351,6 +502,11 @@ if [ "$JAIL" -o "$ROOTDIR" ]; then
$( [ "$SHOW_VALUE" ] || echo \ -N )
$( [ "$SHOW_FILE" ] && echo \ -F )
"
+ if [ "$SERVICE" ]; then
+ escape "$SERVICE" _SERVICE
+ args="$args -s '$_SERVICE'"
+ unset _SERVICE
+ fi
if [ "${RC_CONFS+set}" ]; then
escape "$RC_CONFS" _RC_CONFS
args="$args -f '$_RC_CONFS'"
@@ -454,9 +610,10 @@ if [ "$SHOW_ALL" ]; then
#
IFS="$IFS|"
EXCEPT="IFS|EXCEPT|PATH|RC_DEFAULTS|OPTIND|DESCRIBE|SEP"
- EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME"
- EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS"
- EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY"
+ EXCEPT="$EXCEPT|DELETE|SHOW_ALL|SHOW_EQUALS|SHOW_NAME|DEFAULT"
+ EXCEPT="$EXCEPT|SHOW_VALUE|SHOW_FILE|VERBOSE|RC_CONFS|SERVICE"
+ EXCEPT="$EXCEPT|pgm|SUCCESS|FAILURE|CHECK_ONLY|EXISTING_ONLY"
+ EXCEPT="$EXCEPT|LIST_CONFS|LIST_SERVICE_CONFS"
EXCEPT="$EXCEPT|f_sysrc_desc_awk|f_sysrc_delete_awk"
#
@@ -479,7 +636,13 @@ if [ "$SHOW_ALL" ]; then
# explicit value, modifying the default behavior of
# source_rc_confs().
#
- [ "${RC_CONFS+set}" ] && rc_conf_files="$RC_CONFS"
+ if [ "${RC_CONFS+set}" ]; then
+ [ "$SHOW_ALL" = "1" -a "$SERVICE" -a \
+ ! "$DEFAULT" ] || rc_conf_files=
+ rc_conf_files="$rc_conf_files $RC_CONFS"
+ rc_conf_files="${rc_conf_files# }"
+ rc_conf_files="${rc_conf_files% }"
+ fi
source_rc_confs
diff --git a/usr.sbin/sysrc/sysrc.8 b/usr.sbin/sysrc/sysrc.8
index b1767b8..dbd0e4b 100644
--- a/usr.sbin/sysrc/sysrc.8
+++ b/usr.sbin/sysrc/sysrc.8
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 2, 2015
+.Dd September 12, 2015
.Dt SYSRC 8
.Os
.Sh NAME
@@ -32,16 +32,27 @@
.Nd safely edit system rc files
.Sh SYNOPSIS
.Nm
-.Op Fl cdDeFhinNqvx
+.Op Fl cdDeEFhinNqvx
+.Op Fl s Ar name
.Op Fl f Ar file
.Op Fl j Ar jail | Fl R Ar dir
.Ar name Ns Op Ns Oo +|- Oc Ns = Ns Ar value
.Ar ...
.Nm
-.Op Fl cdDeFhinNqvx
+.Op Fl cdDeEFhinNqvx
+.Op Fl s Ar name
.Op Fl f Ar file
.Op Fl j Ar jail | Fl R Ar dir
.Fl a | A
+.Nm
+.Op Fl E
+.Op Fl s Ar name
+.Op Fl f Ar file
+.Fl l
+.Nm
+.Op Fl eEqv
+.Fl L
+.Op Ar name ...
.Sh DESCRIPTION
The
.Nm
@@ -81,6 +92,13 @@ Ignored if either
or
.Ql Fl F
is specified.
+.It Fl E
+When given
+.Sq Fl l
+or
+.Sq Fl L
+to list configuration files, only list those that exist.
+When changing a setting, prefer to modify existing files.
.It Fl f Ar file
Operate on the specified file(s) instead of the files obtained by reading the
.Sq rc_conf_files
@@ -105,6 +123,17 @@ or name of the
.Ar jail
to operate within
.Pq overrides So Fl R Ar dir Sc ; requires Xr jexec 8 .
+.It Fl l
+List configuration files used at startup on stdout and exit.
+.It Fl L
+List all configuration files including rc.conf.d entries on stdout and exit.
+Can be combined with
+.Sq Fl v
+or
+.Sq Fl e
+to show service names.
+.Nm
+exits with success if all named services are installed, failure otherwise.
.It Fl n
Show only variable values, not their names.
.It Fl N
@@ -112,11 +141,40 @@ Show only variable names, not their values.
.It Fl q
Quiet.
Disable verbose and hide certain errors.
+When combined with
+.Sq Fl L
+and one or more
+.Li Ar name
+arguments, provide only exit status and no output.
.It Fl R Ar dir
Operate within the root directory
.Sq Ar dir
rather than
.Sq / .
+.It Fl s Ar name
+If an
+.Li rc.d
+script of
+.Ar name
+exists
+.Po
+in
+.Dq /etc/rc.d
+or
+.Li local_startup
+directories
+.Pc ,
+process its
+.Dq rc.conf.d
+entries as potential overrides to
+.Sq rc_conf_files .
+See
+.Xr rc.subr 8
+for additional information on
+.Dq rc.conf.d .
+Can be combined with
+.Sq Fl l
+to list configuration files used by service at startup.
.It Fl v
Verbose.
Print the pathname of the specific
@@ -336,6 +394,10 @@ and
.It Pa /etc/defaults/rc.conf
.It Pa /etc/rc.conf
.It Pa /etc/rc.conf.local
+.It Pa /etc/rc.conf.d/name
+.It Pa /etc/rc.conf.d/name/*
+.It Pa /usr/local/etc/rc.conf.d/name
+.It Pa /usr/local/etc/rc.conf.d/name/*
.El
.Sh EXAMPLES
Below are some simple examples of how
@@ -397,6 +459,7 @@ cloned_interfaces+"alternate"
.Sh SEE ALSO
.Xr jls 1 ,
.Xr rc.conf 5 ,
+.Xr rc.subr 8 ,
.Xr jail 8 ,
.Xr jexec 8 ,
.Xr rc 8 ,
diff --git a/usr.sbin/tcpdchk/Makefile b/usr.sbin/tcpdchk/Makefile
index 5faea18..c7d4155 100644
--- a/usr.sbin/tcpdchk/Makefile
+++ b/usr.sbin/tcpdchk/Makefile
@@ -8,7 +8,7 @@ PROG= tcpdchk
MAN= tcpdchk.8
SRCS= tcpdchk.c fakelog.c inetcf.c scaffold.c
-CFLAGS+=-DREAL_DAEMON_DIR=\"/usr/libexec\" \
+CFLAGS+=-DREAL_DAEMON_DIR=\"${LIBEXECDIR}\" \
-DSEVERITY=LOG_INFO -DRFC931_TIMEOUT=10 -DPROCESS_OPTIONS \
-DHOSTS_DENY=\"/etc/hosts.deny\" -DHOSTS_ALLOW=\"/etc/hosts.allow\"
.if ${MK_INET6_SUPPORT} != "no"
diff --git a/usr.sbin/tcpdmatch/Makefile b/usr.sbin/tcpdmatch/Makefile
index bbe29a4..2f92427 100644
--- a/usr.sbin/tcpdmatch/Makefile
+++ b/usr.sbin/tcpdmatch/Makefile
@@ -8,7 +8,7 @@ PROG= tcpdmatch
MAN= tcpdmatch.8
SRCS= tcpdmatch.c fakelog.c inetcf.c scaffold.c
-CFLAGS+=-DREAL_DAEMON_DIR=\"/usr/libexec\" \
+CFLAGS+=-DREAL_DAEMON_DIR=\"${LIBEXECDIR}\" \
-DSEVERITY=LOG_INFO -DRFC931_TIMEOUT=10
.if ${MK_INET6_SUPPORT} != "no"
CFLAGS+=-DINET6
diff --git a/usr.sbin/tzsetup/tzsetup.c b/usr.sbin/tzsetup/tzsetup.c
index 7d2a936..fc80364 100644
--- a/usr.sbin/tzsetup/tzsetup.c
+++ b/usr.sbin/tzsetup/tzsetup.c
@@ -40,7 +40,6 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sysexits.h>
#include <time.h>
#include <unistd.h>
@@ -945,18 +944,23 @@ main(int argc, char **argv)
if (argc - optind > 1)
usage();
- if (chrootenv != NULL) {
- rv = chroot(chrootenv);
- if (rv != 0)
- err(EX_OSERR, "chroot to %s", chrootenv);
+ if (chrootenv == NULL) {
+ strcpy(path_zonetab, _PATH_ZONETAB);
+ strcpy(path_iso3166, _PATH_ISO3166);
+ strcpy(path_zoneinfo, _PATH_ZONEINFO);
+ strcpy(path_localtime, _PATH_LOCALTIME);
+ strcpy(path_db, _PATH_DB);
+ strcpy(path_wall_cmos_clock, _PATH_WALL_CMOS_CLOCK);
+ } else {
+ sprintf(path_zonetab, "%s/%s", chrootenv, _PATH_ZONETAB);
+ sprintf(path_iso3166, "%s/%s", chrootenv, _PATH_ISO3166);
+ sprintf(path_zoneinfo, "%s/%s", chrootenv, _PATH_ZONEINFO);
+ sprintf(path_localtime, "%s/%s", chrootenv, _PATH_LOCALTIME);
+ sprintf(path_db, "%s/%s", chrootenv, _PATH_DB);
+ sprintf(path_wall_cmos_clock, "%s/%s", chrootenv,
+ _PATH_WALL_CMOS_CLOCK);
}
- strcpy(path_zonetab, _PATH_ZONETAB);
- strcpy(path_iso3166, _PATH_ISO3166);
- strcpy(path_zoneinfo, _PATH_ZONEINFO);
- strcpy(path_localtime, _PATH_LOCALTIME);
- strcpy(path_db, _PATH_DB);
- strcpy(path_wall_cmos_clock, _PATH_WALL_CMOS_CLOCK);
/* Override the user-supplied umask. */
(void)umask(S_IWGRP | S_IWOTH);
diff --git a/usr.sbin/uathload/Makefile b/usr.sbin/uathload/Makefile
index d7b808c..949f800 100644
--- a/usr.sbin/uathload/Makefile
+++ b/usr.sbin/uathload/Makefile
@@ -7,10 +7,20 @@ SRCS= uathload.c ar5523.bin
CLEANFILES= ar5523.bin
+# It's hard to tag ar5523.o with the proper gnu note saying that it has a
+# non-executable stack, so ld doesn't properly mark his executable as
+# not having an executable stack. Mark it explicitly, but only for those
+# platforms that support his feature (otherwise signals don't work).
+# Note: Newer versions of ld than is in the tree ignore -z.
.if ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "amd64" || ${MACHINE_ARCH} == "powerpc" || ${MACHINE_ARCH} == "powerpc64"
LDFLAGS+= -Wl,-z,noexecstack
.endif
+# The conversion from .bin to .o doesn't always produce a pedantically correct
+# .o's. And it doesn't matter, so turn off the mismatch warnings since it is
+# pure data. On mips64 here's no easy way to produce a proper .o.
+LDFLAGS+= -Wl,--no-warn-mismatch
+
ar5523.bin: ${.CURDIR}/../../sys/contrib/dev/uath/ar5523.bin.uu
uudecode -p ${.CURDIR}/../../sys/contrib/dev/uath/ar5523.bin.uu > ${.TARGET}
diff --git a/usr.sbin/uefisign/Makefile.depend b/usr.sbin/uefisign/Makefile.depend
new file mode 100644
index 0000000..fc0b633
--- /dev/null
+++ b/usr.sbin/uefisign/Makefile.depend
@@ -0,0 +1,19 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ secure/lib/libcrypto \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/uefisign/magic.h b/usr.sbin/uefisign/magic.h
index 4c3ad4e..85f2c55 100644
--- a/usr.sbin/uefisign/magic.h
+++ b/usr.sbin/uefisign/magic.h
@@ -50,7 +50,7 @@ static const char *magic_fmt =
"a = FORMAT:HEX,BITSTRING:00\n"
/*
* Well, there should be some other struct here, "SPCLink", but it doesn't
- * appear to be neccessary for UEFI, and I have no idea how to synthesize it,
+ * appear to be necessary for UEFI, and I have no idea how to synthesize it,
* as it uses the CHOICE type.
*/
"\n"
diff --git a/usr.sbin/uefisign/pe.c b/usr.sbin/uefisign/pe.c
index f4695b4..768ba5a 100644
--- a/usr.sbin/uefisign/pe.c
+++ b/usr.sbin/uefisign/pe.c
@@ -304,7 +304,7 @@ parse_directory(struct executable *x, off_t off,
* Note that most software does not care about the checksum at all; perhaps
* we could just set it to 0 instead.
*
- * XXX: Endianess?
+ * XXX: Endianness?
*/
static uint32_t
compute_checksum(const struct executable *x)
diff --git a/usr.sbin/uhsoctl/uhsoctl.c b/usr.sbin/uhsoctl/uhsoctl.c
index 686d45f..9dc13ab 100644
--- a/usr.sbin/uhsoctl/uhsoctl.c
+++ b/usr.sbin/uhsoctl/uhsoctl.c
@@ -452,6 +452,7 @@ set_nameservers(struct ctx *ctx, const char *respath, int ns, ...)
free(ctx->ns[i]);
}
free(ctx->ns);
+ ctx->ns = NULL;
}
fd = open(respath, O_RDWR | O_CREAT | O_NOFOLLOW, 0666);
diff --git a/usr.sbin/unbound/anchor/Makefile.depend b/usr.sbin/unbound/anchor/Makefile.depend
new file mode 100644
index 0000000..399b8c2
--- /dev/null
+++ b/usr.sbin/unbound/anchor/Makefile.depend
@@ -0,0 +1,24 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libexpat \
+ lib/libthr \
+ lib/libunbound \
+ secure/lib/libcrypto \
+ secure/lib/libssl \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/unbound/checkconf/Makefile.depend b/usr.sbin/unbound/checkconf/Makefile.depend
new file mode 100644
index 0000000..36ffed0
--- /dev/null
+++ b/usr.sbin/unbound/checkconf/Makefile.depend
@@ -0,0 +1,23 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libthr \
+ lib/libunbound \
+ secure/lib/libcrypto \
+ secure/lib/libssl \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/unbound/control/Makefile.depend b/usr.sbin/unbound/control/Makefile.depend
new file mode 100644
index 0000000..36ffed0
--- /dev/null
+++ b/usr.sbin/unbound/control/Makefile.depend
@@ -0,0 +1,23 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libthr \
+ lib/libunbound \
+ secure/lib/libcrypto \
+ secure/lib/libssl \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/unbound/daemon/Makefile.depend b/usr.sbin/unbound/daemon/Makefile.depend
new file mode 100644
index 0000000..06c0c16
--- /dev/null
+++ b/usr.sbin/unbound/daemon/Makefile.depend
@@ -0,0 +1,24 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ gnu/lib/csu \
+ gnu/lib/libgcc \
+ include \
+ include/arpa \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+ lib/libthr \
+ lib/libunbound \
+ lib/libutil \
+ secure/lib/libcrypto \
+ secure/lib/libssl \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/unbound/local-setup/Makefile.depend b/usr.sbin/unbound/local-setup/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/unbound/local-setup/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/vigr/Makefile.depend b/usr.sbin/vigr/Makefile.depend
new file mode 100644
index 0000000..f80275d
--- /dev/null
+++ b/usr.sbin/vigr/Makefile.depend
@@ -0,0 +1,11 @@
+# $FreeBSD$
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/usr.sbin/wpa/Makefile.crypto b/usr.sbin/wpa/Makefile.crypto
index 46cd9ef..5c03f7d 100644
--- a/usr.sbin/wpa/Makefile.crypto
+++ b/usr.sbin/wpa/Makefile.crypto
@@ -1,7 +1,7 @@
# $FreeBSD$
.if ${MK_OPENSSL} != "no" && !defined(RELEASE_CRUNCH)
-SRCS+= crypto_openssl.c random.c sha1-prf.c sha256-prf.c
+SRCS+= crypto_openssl.c random.c sha1-prf.c sha256-prf.c sha256-tlsprf.c
LIBADD+= ssl crypto
CFLAGS+= -DCONFIG_SHA256
.else
@@ -19,6 +19,7 @@ CONFIG_INTERNAL_TLS=y
CONFIG_INTERNAL_DH5=y
CONFIG_INTERNAL_DH=y
NEED_AES_ENC=true
+NEED_AES_CBC=true
.endif
.if defined(TLS_FUNCS)
diff --git a/usr.sbin/wpa/hostapd/Makefile b/usr.sbin/wpa/hostapd/Makefile
index 743f917..4437839 100644
--- a/usr.sbin/wpa/hostapd/Makefile
+++ b/usr.sbin/wpa/hostapd/Makefile
@@ -97,7 +97,6 @@ NEED_SIM_COMMON=y
.if defined(NEED_SIM_COMMON)
SRCS+= eap_sim_common.c \
eap_sim_db.c
-NEED_AES_CBC=y
NEED_FIPS186_2_PRF=y
.endif
diff --git a/usr.sbin/wpa/wpa_supplicant/Makefile b/usr.sbin/wpa/wpa_supplicant/Makefile
index badae0d..65b0c77 100644
--- a/usr.sbin/wpa/wpa_supplicant/Makefile
+++ b/usr.sbin/wpa/wpa_supplicant/Makefile
@@ -96,10 +96,6 @@ NEED_AES_ENCBLOCK=y
NEED_AES_OMAC1=y
.endif
-.if !empty(CFLAGS:M-DCONFIG_WPS)
-NEED_AES_CBC=y
-.endif
-
.if !empty(CFLAGS:M*-DEAP_AKA)
SRCS+= eap_aka.c
NEED_SIM_COMMON=y
diff --git a/usr.sbin/ypbind/ypbind.c b/usr.sbin/ypbind/ypbind.c
index 7d18d22..39bdd74 100644
--- a/usr.sbin/ypbind/ypbind.c
+++ b/usr.sbin/ypbind/ypbind.c
@@ -199,7 +199,7 @@ rejecting.", *argp);
res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC;
return (&res);
}
- ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
+ ypdb = malloc(sizeof *ypdb);
if (ypdb == NULL) {
syslog(LOG_WARNING, "malloc: %m");
res.ypbind_resp_u.ypbind_error = YPBIND_ERR_RESC;
@@ -396,7 +396,7 @@ main(int argc, char *argv[])
if (flock(yplockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
errx(1, "another ypbind is already running. Aborting");
- /* XXX domainname will be overriden if we use restricted mode */
+ /* XXX domainname will be overridden if we use restricted mode */
yp_get_default_domain(&domain_name);
if (domain_name[0] == '\0')
errx(1, "domainname not set. Aborting");
@@ -452,7 +452,7 @@ main(int argc, char *argv[])
errx(1, "unable to register (YPBINDPROG, YPBINDVERS, tcp)");
/* build initial domain binding, make it "unsuccessful" */
- ypbindlist = (struct _dom_binding *)malloc(sizeof *ypbindlist);
+ ypbindlist = malloc(sizeof *ypbindlist);
if (ypbindlist == NULL)
errx(1, "malloc");
bzero(ypbindlist, sizeof *ypbindlist);
@@ -886,7 +886,7 @@ rpc_received(char *dom, struct sockaddr_in *raddrp, int force)
if (ypdb == NULL) {
if (force == 0)
return;
- ypdb = (struct _dom_binding *)malloc(sizeof *ypdb);
+ ypdb = malloc(sizeof *ypdb);
if (ypdb == NULL) {
syslog(LOG_WARNING, "malloc: %m");
return;
diff --git a/usr.sbin/ypldap/Makefile b/usr.sbin/ypldap/Makefile
new file mode 100644
index 0000000..1d3cabc
--- /dev/null
+++ b/usr.sbin/ypldap/Makefile
@@ -0,0 +1,20 @@
+# $OpenBSD: Makefile,v 1.8 2015/09/09 15:33:18 deraadt Exp $
+# $FreeBSD$
+
+PROG= ypldap
+SRCS= parse.y ypldap.c log.c \
+ ldapclient.c entries.c yp.c \
+ aldap.c ber.c \
+ ypldap_dns.c
+
+MAN= ypldap.8 ypldap.conf.5
+
+LIBADD= openbsd event util rpcsvc
+
+CFLAGS+=-I${.CURDIR}
+CFLAGS+=-I${.CURDIR}/../../contrib/pf/libevent
+CFLAGS+=-I${.CURDIR}/../../lib/libopenbsd
+
+WARNS= 2
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/ypldap/aldap.c b/usr.sbin/ypldap/aldap.c
new file mode 100644
index 0000000..7062507
--- /dev/null
+++ b/usr.sbin/ypldap/aldap.c
@@ -0,0 +1,1272 @@
+/* $Id: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
+/* $OpenBSD: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
+ * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "aldap.h"
+
+#if 0
+#define DEBUG
+#endif
+#define VERSION 3
+
+static struct ber_element *ldap_parse_search_filter(struct ber_element *,
+ char *);
+static struct ber_element *ldap_do_parse_search_filter(
+ struct ber_element *, char **);
+char **aldap_get_stringset(struct ber_element *);
+char *utoa(char *);
+char *parseval(char *, size_t);
+int aldap_create_page_control(struct ber_element *,
+ int, struct aldap_page_control *);
+
+#ifdef DEBUG
+void ldap_debug_elements(struct ber_element *);
+#endif
+
+#ifdef DEBUG
+#define DPRINTF(x...) printf(x)
+#define LDAP_DEBUG(x, y) do { fprintf(stderr, "*** " x "\n"); ldap_debug_elements(y); } while (0)
+#else
+#define DPRINTF(x...) do { } while (0)
+#define LDAP_DEBUG(x, y) do { } while (0)
+#endif
+
+int
+aldap_close(struct aldap *al)
+{
+ if (close(al->ber.fd) == -1)
+ return (-1);
+
+ ber_free(&al->ber);
+ free(al);
+
+ return (0);
+}
+
+struct aldap *
+aldap_init(int fd)
+{
+ struct aldap *a;
+
+ if ((a = calloc(1, sizeof(*a))) == NULL)
+ return NULL;
+ a->ber.fd = fd;
+
+ return a;
+}
+
+int
+aldap_bind(struct aldap *ldap, char *binddn, char *bindcred)
+{
+ struct ber_element *root = NULL, *elm;
+ int error;
+
+ if (binddn == NULL)
+ binddn = "";
+ if (bindcred == NULL)
+ bindcred = "";
+
+ if ((root = ber_add_sequence(NULL)) == NULL)
+ goto fail;
+
+ elm = ber_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP,
+ (unsigned long)LDAP_REQ_BIND, VERSION, binddn, bindcred,
+ BER_CLASS_CONTEXT, (unsigned long)LDAP_AUTH_SIMPLE);
+ if (elm == NULL)
+ goto fail;
+
+ LDAP_DEBUG("aldap_bind", root);
+
+ error = ber_write_elements(&ldap->ber, root);
+ ber_free_elements(root);
+ root = NULL;
+ if (error == -1)
+ goto fail;
+
+ return (ldap->msgid);
+fail:
+ if (root != NULL)
+ ber_free_elements(root);
+
+ ldap->err = ALDAP_ERR_OPERATION_FAILED;
+ return (-1);
+}
+
+int
+aldap_unbind(struct aldap *ldap)
+{
+ struct ber_element *root = NULL, *elm;
+ int error;
+
+ if ((root = ber_add_sequence(NULL)) == NULL)
+ goto fail;
+ elm = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
+ LDAP_REQ_UNBIND_30);
+ if (elm == NULL)
+ goto fail;
+
+ LDAP_DEBUG("aldap_unbind", root);
+
+ error = ber_write_elements(&ldap->ber, root);
+ ber_free_elements(root);
+ root = NULL;
+ if (error == -1)
+ goto fail;
+
+ return (ldap->msgid);
+fail:
+ if (root != NULL)
+ ber_free_elements(root);
+
+ ldap->err = ALDAP_ERR_OPERATION_FAILED;
+
+ return (-1);
+}
+
+int
+aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
+ char **attrs, int typesonly, int sizelimit, int timelimit,
+ struct aldap_page_control *page)
+{
+ struct ber_element *root = NULL, *ber, *c;
+ int i, error;
+
+ if ((root = ber_add_sequence(NULL)) == NULL)
+ goto fail;
+
+ ber = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
+ (unsigned long) LDAP_REQ_SEARCH);
+ if (ber == NULL) {
+ ldap->err = ALDAP_ERR_OPERATION_FAILED;
+ goto fail;
+ }
+
+ c = ber;
+ ber = ber_printf_elements(ber, "sEEddb", basedn, (long long)scope,
+ (long long)LDAP_DEREF_NEVER, sizelimit,
+ timelimit, typesonly);
+ if (ber == NULL) {
+ ldap->err = ALDAP_ERR_OPERATION_FAILED;
+ goto fail;
+ }
+
+ if ((ber = ldap_parse_search_filter(ber, filter)) == NULL) {
+ ldap->err = ALDAP_ERR_PARSER_ERROR;
+ goto fail;
+ }
+
+ if ((ber = ber_add_sequence(ber)) == NULL)
+ goto fail;
+ if (attrs != NULL)
+ for (i = 0; attrs[i] != NULL; i++) {
+ if ((ber = ber_add_string(ber, attrs[i])) == NULL)
+ goto fail;
+ }
+
+ aldap_create_page_control(c, 100, page);
+
+ LDAP_DEBUG("aldap_search", root);
+
+ error = ber_write_elements(&ldap->ber, root);
+ ber_free_elements(root);
+ root = NULL;
+ if (error == -1) {
+ ldap->err = ALDAP_ERR_OPERATION_FAILED;
+ goto fail;
+ }
+
+ return (ldap->msgid);
+
+fail:
+ if (root != NULL)
+ ber_free_elements(root);
+
+ return (-1);
+}
+
+int
+aldap_create_page_control(struct ber_element *elm, int size,
+ struct aldap_page_control *page)
+{
+ int len;
+ struct ber c;
+ struct ber_element *ber = NULL;
+
+ c.br_wbuf = NULL;
+ c.fd = -1;
+
+ ber = ber_add_sequence(NULL);
+
+ if (page == NULL) {
+ if (ber_printf_elements(ber, "ds", 50, "") == NULL)
+ goto fail;
+ } else {
+ if (ber_printf_elements(ber, "dx", 50, page->cookie,
+ page->cookie_len) == NULL)
+ goto fail;
+ }
+
+ if ((len = ber_write_elements(&c, ber)) < 1)
+ goto fail;
+ if (ber_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID,
+ c.br_wbuf, (size_t)len) == NULL)
+ goto fail;
+
+ ber_free_elements(ber);
+ ber_free(&c);
+ return len;
+fail:
+ if (ber != NULL)
+ ber_free_elements(ber);
+ ber_free(&c);
+
+ return (-1);
+}
+
+struct aldap_message *
+aldap_parse(struct aldap *ldap)
+{
+ int class;
+ unsigned long type;
+ long long msgid = 0;
+ struct aldap_message *m;
+ struct ber_element *a = NULL, *ep;
+
+ if ((m = calloc(1, sizeof(struct aldap_message))) == NULL)
+ return NULL;
+
+ if ((m->msg = ber_read_elements(&ldap->ber, NULL)) == NULL)
+ goto parsefail;
+
+ LDAP_DEBUG("message", m->msg);
+
+ if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0)
+ goto parsefail;
+ m->msgid = msgid;
+ m->message_type = type;
+ m->protocol_op = a;
+
+ switch (m->message_type) {
+ case LDAP_RES_BIND:
+ case LDAP_RES_MODIFY:
+ case LDAP_RES_ADD:
+ case LDAP_RES_DELETE:
+ case LDAP_RES_MODRDN:
+ case LDAP_RES_COMPARE:
+ case LDAP_RES_SEARCH_RESULT:
+ if (ber_scanf_elements(m->protocol_op, "{EeSeSe",
+ &m->body.res.rescode, &m->dn, &m->body.res.diagmsg, &a) != 0)
+ goto parsefail;
+ if (m->body.res.rescode == LDAP_REFERRAL)
+ if (ber_scanf_elements(a, "{e", &m->references) != 0)
+ goto parsefail;
+ if (m->msg->be_sub) {
+ for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
+ ber_scanf_elements(ep, "t", &class, &type);
+ if (class == 2 && type == 0)
+ m->page = aldap_parse_page_control(ep->be_sub->be_sub,
+ ep->be_sub->be_sub->be_len);
+ }
+ } else
+ m->page = NULL;
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ if (ber_scanf_elements(m->protocol_op, "{eS{e", &m->dn,
+ &m->body.search.attrs) != 0)
+ goto parsefail;
+ break;
+ case LDAP_RES_SEARCH_REFERENCE:
+ if (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
+ goto parsefail;
+ break;
+ }
+
+ return m;
+parsefail:
+ ldap->err = ALDAP_ERR_PARSER_ERROR;
+ aldap_freemsg(m);
+ return NULL;
+}
+
+struct aldap_page_control *
+aldap_parse_page_control(struct ber_element *control, size_t len)
+{
+ char *oid, *s;
+ char *encoded;
+ struct ber b;
+ struct ber_element *elm;
+ struct aldap_page_control *page;
+
+ b.br_wbuf = NULL;
+ b.fd = -1;
+ ber_scanf_elements(control, "ss", &oid, &encoded);
+ ber_set_readbuf(&b, encoded, control->be_next->be_len);
+ elm = ber_read_elements(&b, NULL);
+
+ if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
+ if (elm != NULL)
+ ber_free_elements(elm);
+ ber_free(&b);
+ return NULL;
+ }
+
+ ber_scanf_elements(elm->be_sub, "is", &page->size, &s);
+ page->cookie_len = elm->be_sub->be_next->be_len;
+
+ if ((page->cookie = malloc(page->cookie_len)) == NULL) {
+ if (elm != NULL)
+ ber_free_elements(elm);
+ ber_free(&b);
+ free(page);
+ return NULL;
+ }
+ memcpy(page->cookie, s, page->cookie_len);
+
+ ber_free_elements(elm);
+ ber_free(&b);
+ return page;
+}
+
+void
+aldap_freepage(struct aldap_page_control *page)
+{
+ free(page->cookie);
+ free(page);
+}
+
+void
+aldap_freemsg(struct aldap_message *msg)
+{
+ if (msg->msg)
+ ber_free_elements(msg->msg);
+ free(msg);
+}
+
+int
+aldap_get_resultcode(struct aldap_message *msg)
+{
+ return msg->body.res.rescode;
+}
+
+char *
+aldap_get_dn(struct aldap_message *msg)
+{
+ char *dn;
+
+ if (msg->dn == NULL)
+ return NULL;
+
+ if (ber_get_string(msg->dn, &dn) == -1)
+ return NULL;
+
+ return utoa(dn);
+}
+
+char **
+aldap_get_references(struct aldap_message *msg)
+{
+ if (msg->references == NULL)
+ return NULL;
+ return aldap_get_stringset(msg->references);
+}
+
+void
+aldap_free_references(char **values)
+{
+ int i;
+
+ if (values == NULL)
+ return;
+
+ for (i = 0; values[i] != NULL; i++)
+ free(values[i]);
+
+ free(values);
+}
+
+char *
+aldap_get_diagmsg(struct aldap_message *msg)
+{
+ char *s;
+
+ if (msg->body.res.diagmsg == NULL)
+ return NULL;
+
+ if (ber_get_string(msg->body.res.diagmsg, &s) == -1)
+ return NULL;
+
+ return utoa(s);
+}
+
+int
+aldap_count_attrs(struct aldap_message *msg)
+{
+ int i;
+ struct ber_element *a;
+
+ if (msg->body.search.attrs == NULL)
+ return (-1);
+
+ for (i = 0, a = msg->body.search.attrs;
+ a != NULL && ber_get_eoc(a) != 0;
+ i++, a = a->be_next)
+ ;
+
+ return i;
+}
+
+int
+aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
+{
+ struct ber_element *b, *c;
+ char *key;
+ char **ret;
+
+ if (msg->body.search.attrs == NULL)
+ goto fail;
+
+ if (ber_scanf_elements(msg->body.search.attrs, "{s(e)}e",
+ &key, &b, &c) != 0)
+ goto fail;
+
+ msg->body.search.iter = msg->body.search.attrs->be_next;
+
+ if ((ret = aldap_get_stringset(b)) == NULL)
+ goto fail;
+
+ (*outvalues) = ret;
+ (*outkey) = utoa(key);
+
+ return (1);
+fail:
+ (*outkey) = NULL;
+ (*outvalues) = NULL;
+ return (-1);
+}
+
+int
+aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
+{
+ struct ber_element *a, *b;
+ char *key;
+ char **ret;
+
+ if (msg->body.search.iter == NULL)
+ goto notfound;
+
+ LDAP_DEBUG("attr", msg->body.search.iter);
+
+ if (ber_get_eoc(msg->body.search.iter) == 0)
+ goto notfound;
+
+ if (ber_scanf_elements(msg->body.search.iter, "{s(e)}e", &key, &a, &b)
+ != 0)
+ goto fail;
+
+ msg->body.search.iter = msg->body.search.iter->be_next;
+
+ if ((ret = aldap_get_stringset(a)) == NULL)
+ goto fail;
+
+ (*outvalues) = ret;
+ (*outkey) = utoa(key);
+
+ return (1);
+fail:
+notfound:
+ (*outkey) = NULL;
+ (*outvalues) = NULL;
+ return (-1);
+}
+
+int
+aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues)
+{
+ struct ber_element *a, *b;
+ char *descr = NULL;
+ char **ret;
+
+ if (msg->body.search.attrs == NULL)
+ goto fail;
+
+ LDAP_DEBUG("attr", msg->body.search.attrs);
+
+ for (a = msg->body.search.attrs;;) {
+ if (a == NULL)
+ goto notfound;
+ if (ber_get_eoc(a) == 0)
+ goto notfound;
+ if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0)
+ goto fail;
+ if (strcasecmp(descr, inkey) == 0)
+ goto attrfound;
+ a = a->be_next;
+ }
+
+attrfound:
+ if ((ret = aldap_get_stringset(b)) == NULL)
+ goto fail;
+
+ (*outvalues) = ret;
+
+ return (1);
+fail:
+notfound:
+ (*outvalues) = NULL;
+ return (-1);
+}
+
+int
+aldap_free_attr(char **values)
+{
+ int i;
+
+ if (values == NULL)
+ return -1;
+
+ for (i = 0; values[i] != NULL; i++)
+ free(values[i]);
+
+ free(values);
+
+ return (1);
+}
+
+#if 0
+void
+aldap_free_url(struct aldap_url *lu)
+{
+ free(lu->buffer);
+ free(lu->filter);
+}
+
+int
+aldap_parse_url(char *url, struct aldap_url *lu)
+{
+ char *p, *forward, *forward2;
+ const char *errstr = NULL;
+ int i;
+
+ if ((lu->buffer = p = strdup(url)) == NULL)
+ return (-1);
+
+ /* protocol */
+ if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) != 0)
+ goto fail;
+ lu->protocol = LDAP;
+ p += strlen(LDAP_URL);
+
+ /* host and optional port */
+ if ((forward = strchr(p, '/')) != NULL)
+ *forward = '\0';
+ /* find the optional port */
+ if ((forward2 = strchr(p, ':')) != NULL) {
+ *forward2 = '\0';
+ /* if a port is given */
+ if (*(forward2+1) != '\0') {
+#define PORT_MAX UINT16_MAX
+ lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr);
+ if (errstr)
+ goto fail;
+ }
+ }
+ /* fail if no host is given */
+ if (strlen(p) == 0)
+ goto fail;
+ lu->host = p;
+ if (forward == NULL)
+ goto done;
+ /* p is assigned either a pointer to a character or to '\0' */
+ p = ++forward;
+ if (strlen(p) == 0)
+ goto done;
+
+ /* dn */
+ if ((forward = strchr(p, '?')) != NULL)
+ *forward = '\0';
+ lu->dn = p;
+ if (forward == NULL)
+ goto done;
+ /* p is assigned either a pointer to a character or to '\0' */
+ p = ++forward;
+ if (strlen(p) == 0)
+ goto done;
+
+ /* attributes */
+ if ((forward = strchr(p, '?')) != NULL)
+ *forward = '\0';
+ for (i = 0; i < MAXATTR; i++) {
+ if ((forward2 = strchr(p, ',')) == NULL) {
+ if (strlen(p) == 0)
+ break;
+ lu->attributes[i] = p;
+ break;
+ }
+ *forward2 = '\0';
+ lu->attributes[i] = p;
+ p = ++forward2;
+ }
+ if (forward == NULL)
+ goto done;
+ /* p is assigned either a pointer to a character or to '\0' */
+ p = ++forward;
+ if (strlen(p) == 0)
+ goto done;
+
+ /* scope */
+ if ((forward = strchr(p, '?')) != NULL)
+ *forward = '\0';
+ if (strcmp(p, "base") == 0)
+ lu->scope = LDAP_SCOPE_BASE;
+ else if (strcmp(p, "one") == 0)
+ lu->scope = LDAP_SCOPE_ONELEVEL;
+ else if (strcmp(p, "sub") == 0)
+ lu->scope = LDAP_SCOPE_SUBTREE;
+ else
+ goto fail;
+ if (forward == NULL)
+ goto done;
+ p = ++forward;
+ if (strlen(p) == 0)
+ goto done;
+
+ /* filter */
+ if (p)
+ lu->filter = p;
+done:
+ free(url);
+ return (1);
+fail:
+ free(lu->buffer);
+ lu->buffer = NULL;
+ return (-1);
+}
+
+int
+aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit,
+ int timelimit)
+{
+ struct aldap_url *lu;
+
+ if ((lu = calloc(1, sizeof(*lu))) == NULL)
+ return (-1);
+
+ if (aldap_parse_url(url, lu))
+ goto fail;
+
+ if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes,
+ typesonly, sizelimit, timelimit) == -1)
+ goto fail;
+
+ aldap_free_url(lu);
+ return (ldap->msgid);
+fail:
+ aldap_free_url(lu);
+ return (-1);
+}
+#endif /* 0 */
+
+/*
+ * internal functions
+ */
+
+char **
+aldap_get_stringset(struct ber_element *elm)
+{
+ struct ber_element *a;
+ int i;
+ char **ret;
+ char *s;
+
+ if (elm->be_type != BER_TYPE_OCTETSTRING)
+ return NULL;
+
+ for (a = elm, i = 1; i > 0 && a != NULL && a->be_type ==
+ BER_TYPE_OCTETSTRING; a = a->be_next, i++)
+ ;
+ if (i == 1)
+ return NULL;
+
+ if ((ret = calloc(i + 1, sizeof(char *))) == NULL)
+ return NULL;
+
+ for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
+ a = a->be_next, i++) {
+
+ ber_get_string(a, &s);
+ ret[i] = utoa(s);
+ }
+ ret[i + 1] = NULL;
+
+ return ret;
+}
+
+/*
+ * Base case for ldap_do_parse_search_filter
+ *
+ * returns:
+ * struct ber_element *, ber_element tree
+ * NULL, parse failed
+ */
+static struct ber_element *
+ldap_parse_search_filter(struct ber_element *ber, char *filter)
+{
+ struct ber_element *elm;
+ char *cp;
+
+ cp = filter;
+
+ if (cp == NULL || *cp == '\0') {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ if ((elm = ldap_do_parse_search_filter(ber, &cp)) == NULL)
+ return (NULL);
+
+ if (*cp != '\0') {
+ ber_free_elements(elm);
+ ber_link_elements(ber, NULL);
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ return (elm);
+}
+
+/*
+ * Translate RFC4515 search filter string into ber_element tree
+ *
+ * returns:
+ * struct ber_element *, ber_element tree
+ * NULL, parse failed
+ *
+ * notes:
+ * when cp is passed to a recursive invocation, it is updated
+ * to point one character beyond the filter that was passed
+ * i.e., cp jumps to "(filter)" upon return
+ * ^
+ * goto's used to discriminate error-handling based on error type
+ * doesn't handle extended filters (yet)
+ *
+ */
+static struct ber_element *
+ldap_do_parse_search_filter(struct ber_element *prev, char **cpp)
+{
+ struct ber_element *elm, *root = NULL;
+ char *attr_desc, *attr_val, *parsed_val, *cp;
+ size_t len;
+ unsigned long type;
+
+ root = NULL;
+
+ /* cpp should pass in pointer to opening parenthesis of "(filter)" */
+ cp = *cpp;
+ if (*cp != '(')
+ goto syntaxfail;
+
+ switch (*++cp) {
+ case '&': /* AND */
+ case '|': /* OR */
+ if (*cp == '&')
+ type = LDAP_FILT_AND;
+ else
+ type = LDAP_FILT_OR;
+
+ if ((elm = ber_add_set(prev)) == NULL)
+ goto callfail;
+ root = elm;
+ ber_set_header(elm, BER_CLASS_CONTEXT, type);
+
+ if (*++cp != '(') /* opening `(` of filter */
+ goto syntaxfail;
+
+ while (*cp == '(') {
+ if ((elm =
+ ldap_do_parse_search_filter(elm, &cp)) == NULL)
+ goto bad;
+ }
+
+ if (*cp != ')') /* trailing `)` of filter */
+ goto syntaxfail;
+ break;
+
+ case '!': /* NOT */
+ if ((root = ber_add_sequence(prev)) == NULL)
+ goto callfail;
+ ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT);
+
+ cp++; /* now points to sub-filter */
+ if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL)
+ goto bad;
+
+ if (*cp != ')') /* trailing `)` of filter */
+ goto syntaxfail;
+ break;
+
+ default: /* SIMPLE || PRESENCE */
+ attr_desc = cp;
+
+ len = strcspn(cp, "()<>~=");
+ cp += len;
+ switch (*cp) {
+ case '~':
+ type = LDAP_FILT_APPR;
+ cp++;
+ break;
+ case '<':
+ type = LDAP_FILT_LE;
+ cp++;
+ break;
+ case '>':
+ type = LDAP_FILT_GE;
+ cp++;
+ break;
+ case '=':
+ type = LDAP_FILT_EQ; /* assume EQ until disproven */
+ break;
+ case '(':
+ case ')':
+ default:
+ goto syntaxfail;
+ }
+ attr_val = ++cp;
+
+ /* presence filter */
+ if (strncmp(attr_val, "*)", 2) == 0) {
+ cp++; /* point to trailing `)` */
+ if ((root =
+ ber_add_nstring(prev, attr_desc, len)) == NULL)
+ goto bad;
+
+ ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
+ break;
+ }
+
+ if ((root = ber_add_sequence(prev)) == NULL)
+ goto callfail;
+ ber_set_header(root, BER_CLASS_CONTEXT, type);
+
+ if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL)
+ goto callfail;
+
+ len = strcspn(attr_val, "*)");
+ if (len == 0 && *cp != '*')
+ goto syntaxfail;
+ cp += len;
+ if (*cp == '\0')
+ goto syntaxfail;
+
+ if (*cp == '*') { /* substring filter */
+ int initial;
+
+ cp = attr_val;
+
+ ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
+
+ if ((elm = ber_add_sequence(elm)) == NULL)
+ goto callfail;
+
+ for (initial = 1;; cp++, initial = 0) {
+ attr_val = cp;
+
+ len = strcspn(attr_val, "*)");
+ if (len == 0) {
+ if (*cp == ')')
+ break;
+ else
+ continue;
+ }
+ cp += len;
+ if (*cp == '\0')
+ goto syntaxfail;
+
+ if (initial)
+ type = LDAP_FILT_SUBS_INIT;
+ else if (*cp == ')')
+ type = LDAP_FILT_SUBS_FIN;
+ else
+ type = LDAP_FILT_SUBS_ANY;
+
+ if ((parsed_val = parseval(attr_val, len)) ==
+ NULL)
+ goto callfail;
+ elm = ber_add_nstring(elm, parsed_val,
+ strlen(parsed_val));
+ free(parsed_val);
+ if (elm == NULL)
+ goto callfail;
+ ber_set_header(elm, BER_CLASS_CONTEXT, type);
+ if (type == LDAP_FILT_SUBS_FIN)
+ break;
+ }
+ break;
+ }
+
+ if ((parsed_val = parseval(attr_val, len)) == NULL)
+ goto callfail;
+ elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val));
+ free(parsed_val);
+ if (elm == NULL)
+ goto callfail;
+ break;
+ }
+
+ cp++; /* now points one char beyond the trailing `)` */
+
+ *cpp = cp;
+ return (root);
+
+syntaxfail: /* XXX -- error reporting */
+callfail:
+bad:
+ if (root != NULL)
+ ber_free_elements(root);
+ ber_link_elements(prev, NULL);
+ return (NULL);
+}
+
+#ifdef DEBUG
+/*
+ * Display a list of ber elements.
+ *
+ */
+void
+ldap_debug_elements(struct ber_element *root)
+{
+ static int indent = 0;
+ long long v;
+ int d;
+ char *buf;
+ size_t len;
+ u_int i;
+ int constructed;
+ struct ber_oid o;
+
+ /* calculate lengths */
+ ber_calc_len(root);
+
+ switch (root->be_encoding) {
+ case BER_TYPE_SEQUENCE:
+ case BER_TYPE_SET:
+ constructed = root->be_encoding;
+ break;
+ default:
+ constructed = 0;
+ break;
+ }
+
+ fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
+ switch (root->be_class) {
+ case BER_CLASS_UNIVERSAL:
+ fprintf(stderr, "class: universal(%u) type: ", root->be_class);
+ switch (root->be_type) {
+ case BER_TYPE_EOC:
+ fprintf(stderr, "end-of-content");
+ break;
+ case BER_TYPE_BOOLEAN:
+ fprintf(stderr, "boolean");
+ break;
+ case BER_TYPE_INTEGER:
+ fprintf(stderr, "integer");
+ break;
+ case BER_TYPE_BITSTRING:
+ fprintf(stderr, "bit-string");
+ break;
+ case BER_TYPE_OCTETSTRING:
+ fprintf(stderr, "octet-string");
+ break;
+ case BER_TYPE_NULL:
+ fprintf(stderr, "null");
+ break;
+ case BER_TYPE_OBJECT:
+ fprintf(stderr, "object");
+ break;
+ case BER_TYPE_ENUMERATED:
+ fprintf(stderr, "enumerated");
+ break;
+ case BER_TYPE_SEQUENCE:
+ fprintf(stderr, "sequence");
+ break;
+ case BER_TYPE_SET:
+ fprintf(stderr, "set");
+ break;
+ }
+ break;
+ case BER_CLASS_APPLICATION:
+ fprintf(stderr, "class: application(%u) type: ",
+ root->be_class);
+ switch (root->be_type) {
+ case LDAP_REQ_BIND:
+ fprintf(stderr, "bind");
+ break;
+ case LDAP_RES_BIND:
+ fprintf(stderr, "bind");
+ break;
+ case LDAP_REQ_UNBIND_30:
+ break;
+ case LDAP_REQ_SEARCH:
+ fprintf(stderr, "search");
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ fprintf(stderr, "search_entry");
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ fprintf(stderr, "search_result");
+ break;
+ case LDAP_REQ_MODIFY:
+ fprintf(stderr, "modify");
+ break;
+ case LDAP_RES_MODIFY:
+ fprintf(stderr, "modify");
+ break;
+ case LDAP_REQ_ADD:
+ fprintf(stderr, "add");
+ break;
+ case LDAP_RES_ADD:
+ fprintf(stderr, "add");
+ break;
+ case LDAP_REQ_DELETE_30:
+ fprintf(stderr, "delete");
+ break;
+ case LDAP_RES_DELETE:
+ fprintf(stderr, "delete");
+ break;
+ case LDAP_REQ_MODRDN:
+ fprintf(stderr, "modrdn");
+ break;
+ case LDAP_RES_MODRDN:
+ fprintf(stderr, "modrdn");
+ break;
+ case LDAP_REQ_COMPARE:
+ fprintf(stderr, "compare");
+ break;
+ case LDAP_RES_COMPARE:
+ fprintf(stderr, "compare");
+ break;
+ case LDAP_REQ_ABANDON_30:
+ fprintf(stderr, "abandon");
+ break;
+ }
+ break;
+ case BER_CLASS_PRIVATE:
+ fprintf(stderr, "class: private(%u) type: ", root->be_class);
+ fprintf(stderr, "encoding (%lu) type: ", root->be_encoding);
+ break;
+ case BER_CLASS_CONTEXT:
+ /* XXX: this is not correct */
+ fprintf(stderr, "class: context(%u) type: ", root->be_class);
+ switch(root->be_type) {
+ case LDAP_AUTH_SIMPLE:
+ fprintf(stderr, "auth simple");
+ break;
+ }
+ break;
+ default:
+ fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
+ break;
+ }
+ fprintf(stderr, "(%lu) encoding %lu ",
+ root->be_type, root->be_encoding);
+
+ if (constructed)
+ root->be_encoding = constructed;
+
+ switch (root->be_encoding) {
+ case BER_TYPE_BOOLEAN:
+ if (ber_get_boolean(root, &d) == -1) {
+ fprintf(stderr, "<INVALID>\n");
+ break;
+ }
+ fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d);
+ break;
+ case BER_TYPE_INTEGER:
+ if (ber_get_integer(root, &v) == -1) {
+ fprintf(stderr, "<INVALID>\n");
+ break;
+ }
+ fprintf(stderr, "value %lld\n", v);
+ break;
+ case BER_TYPE_ENUMERATED:
+ if (ber_get_enumerated(root, &v) == -1) {
+ fprintf(stderr, "<INVALID>\n");
+ break;
+ }
+ fprintf(stderr, "value %lld\n", v);
+ break;
+ case BER_TYPE_BITSTRING:
+ if (ber_get_bitstring(root, (void *)&buf, &len) == -1) {
+ fprintf(stderr, "<INVALID>\n");
+ break;
+ }
+ fprintf(stderr, "hexdump ");
+ for (i = 0; i < len; i++)
+ fprintf(stderr, "%02x", buf[i]);
+ fprintf(stderr, "\n");
+ break;
+ case BER_TYPE_OBJECT:
+ if (ber_get_oid(root, &o) == -1) {
+ fprintf(stderr, "<INVALID>\n");
+ break;
+ }
+ fprintf(stderr, "\n");
+ break;
+ case BER_TYPE_OCTETSTRING:
+ if (ber_get_nstring(root, (void *)&buf, &len) == -1) {
+ fprintf(stderr, "<INVALID>\n");
+ break;
+ }
+ fprintf(stderr, "string \"%.*s\"\n", len, buf);
+ break;
+ case BER_TYPE_NULL: /* no payload */
+ case BER_TYPE_EOC:
+ case BER_TYPE_SEQUENCE:
+ case BER_TYPE_SET:
+ default:
+ fprintf(stderr, "\n");
+ break;
+ }
+
+ if (constructed && root->be_sub) {
+ indent += 2;
+ ldap_debug_elements(root->be_sub);
+ indent -= 2;
+ }
+ if (root->be_next)
+ ldap_debug_elements(root->be_next);
+}
+#endif
+
+/*
+ * Convert UTF-8 to ASCII.
+ * notes:
+ * non-ASCII characters are displayed as '?'
+ * the argument u should be a NULL terminated sequence of UTF-8 bytes.
+ */
+char *
+utoa(char *u)
+{
+ int len, i, j;
+ char *str;
+
+ /* calculate the length to allocate */
+ for (len = 0, i = 0; u[i] != '\0'; ) {
+ if ((u[i] & 0xF0) == 0xF0)
+ i += 4;
+ else if ((u[i] & 0xE0) == 0xE0)
+ i += 3;
+ else if ((u[i] & 0xC0) == 0xC0)
+ i += 2;
+ else
+ i += 1;
+ len++;
+ }
+
+ if ((str = calloc(len + 1, sizeof(char))) == NULL)
+ return NULL;
+
+ /* copy the ASCII characters to the newly allocated string */
+ for (i = 0, j = 0; u[i] != '\0'; j++) {
+ if ((u[i] & 0xF0) == 0xF0) {
+ str[j] = '?';
+ i += 4;
+ } else if ((u[i] & 0xE0) == 0xE0) {
+ str[j] = '?';
+ i += 3;
+ } else if ((u[i] & 0xC0) == 0xC0) {
+ str[j] = '?';
+ i += 2;
+ } else {
+ str[j] = u[i];
+ i += 1;
+ }
+ }
+
+ return str;
+}
+
+/*
+ * Parse a LDAP value
+ * notes:
+ * the argument u should be a NULL terminated sequence of ASCII bytes.
+ */
+char *
+parseval(char *p, size_t len)
+{
+ char hex[3];
+ char *cp = p, *buffer, *newbuffer;
+ size_t size, newsize, i, j;
+
+ size = 50;
+ if ((buffer = calloc(1, size)) == NULL)
+ return NULL;
+
+ for (i = j = 0; j < len; i++) {
+ if (i >= size) {
+ newsize = size + 1024;
+ if ((newbuffer = realloc(buffer, newsize)) == NULL) {
+ free(buffer);
+ return (NULL);
+ }
+ buffer = newbuffer;
+ size = newsize;
+ }
+
+ if (cp[j] == '\\') {
+ strlcpy(hex, cp + j + 1, sizeof(hex));
+ buffer[i] = (char)strtoumax(hex, NULL, 16);
+ j += 3;
+ } else {
+ buffer[i] = cp[j];
+ j++;
+ }
+ }
+
+ return buffer;
+}
+
+int
+aldap_get_errno(struct aldap *a, const char **estr)
+{
+ switch (a->err) {
+ case ALDAP_ERR_SUCCESS:
+ *estr = "success";
+ break;
+ case ALDAP_ERR_PARSER_ERROR:
+ *estr = "parser failed";
+ break;
+ case ALDAP_ERR_INVALID_FILTER:
+ *estr = "invalid filter";
+ break;
+ case ALDAP_ERR_OPERATION_FAILED:
+ *estr = "operation failed";
+ break;
+ default:
+ *estr = "unknown";
+ break;
+ }
+ return (a->err);
+}
diff --git a/usr.sbin/ypldap/aldap.h b/usr.sbin/ypldap/aldap.h
new file mode 100644
index 0000000..cdf5316
--- /dev/null
+++ b/usr.sbin/ypldap/aldap.h
@@ -0,0 +1,221 @@
+/* $Id: aldap.h,v 1.9 2012/04/30 21:40:03 jmatthew Exp $ */
+/* $OpenBSD: aldap.h,v 1.9 2012/04/30 21:40:03 jmatthew Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
+ * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include "ber.h"
+
+#define LDAP_URL "ldap://"
+#define LDAP_PORT 389
+#define LDAP_PAGED_OID "1.2.840.113556.1.4.319"
+
+struct aldap {
+#define ALDAP_ERR_SUCCESS 0
+#define ALDAP_ERR_PARSER_ERROR 1
+#define ALDAP_ERR_INVALID_FILTER 2
+#define ALDAP_ERR_OPERATION_FAILED 3
+ u_int8_t err;
+ int msgid;
+ struct ber ber;
+};
+
+struct aldap_page_control {
+ int size;
+ char *cookie;
+ unsigned int cookie_len;
+};
+
+struct aldap_message {
+ int msgid;
+ int message_type;
+
+ struct ber_element *msg;
+
+ struct ber_element *header;
+ struct ber_element *protocol_op;
+
+ struct ber_element *dn;
+
+ union {
+ struct {
+ long long rescode;
+ struct ber_element *diagmsg;
+ } res;
+ struct {
+ struct ber_element *iter;
+ struct ber_element *attrs;
+ } search;
+ } body;
+ struct ber_element *references;
+ struct aldap_page_control *page;
+};
+
+enum aldap_protocol {
+ LDAP,
+ LDAPS
+};
+
+struct aldap_url {
+ int protocol;
+ char *host;
+ in_port_t port;
+ char *dn;
+#define MAXATTR 1024
+ char *attributes[MAXATTR];
+ int scope;
+ char *filter;
+ char *buffer;
+};
+
+enum protocol_op {
+ LDAP_REQ_BIND = 0,
+ LDAP_RES_BIND = 1,
+ LDAP_REQ_UNBIND_30 = 2,
+ LDAP_REQ_SEARCH = 3,
+ LDAP_RES_SEARCH_ENTRY = 4,
+ LDAP_RES_SEARCH_RESULT = 5,
+ LDAP_REQ_MODIFY = 6,
+ LDAP_RES_MODIFY = 7,
+ LDAP_REQ_ADD = 8,
+ LDAP_RES_ADD = 9,
+ LDAP_REQ_DELETE_30 = 10,
+ LDAP_RES_DELETE = 11,
+ LDAP_REQ_MODRDN = 12,
+ LDAP_RES_MODRDN = 13,
+ LDAP_REQ_COMPARE = 14,
+ LDAP_RES_COMPARE = 15,
+ LDAP_REQ_ABANDON_30 = 16,
+
+ LDAP_RES_SEARCH_REFERENCE = 19,
+};
+
+enum deref_aliases {
+ LDAP_DEREF_NEVER = 0,
+ LDAP_DEREF_SEARCHING = 1,
+ LDAP_DEREF_FINDING = 2,
+ LDAP_DEREF_ALWAYS = 3,
+};
+
+enum authentication_choice {
+ LDAP_AUTH_SIMPLE = 0,
+};
+
+enum scope {
+ LDAP_SCOPE_BASE = 0,
+ LDAP_SCOPE_ONELEVEL = 1,
+ LDAP_SCOPE_SUBTREE = 2,
+};
+
+enum result_code {
+ LDAP_SUCCESS = 0,
+ LDAP_OPERATIONS_ERROR = 1,
+ LDAP_PROTOCOL_ERROR = 2,
+ LDAP_TIMELIMIT_EXCEEDED = 3,
+ LDAP_SIZELIMIT_EXCEEDED = 4,
+ LDAP_COMPARE_FALSE = 5,
+ LDAP_COMPARE_TRUE = 6,
+ LDAP_STRONG_AUTH_NOT_SUPPORTED = 7,
+ LDAP_STRONG_AUTH_REQUIRED = 8,
+
+ LDAP_REFERRAL = 10,
+ LDAP_ADMINLIMIT_EXCEEDED = 11,
+ LDAP_UNAVAILABLE_CRITICAL_EXTENSION = 12,
+ LDAP_CONFIDENTIALITY_REQUIRED = 13,
+ LDAP_SASL_BIND_IN_PROGRESS = 14,
+ LDAP_NO_SUCH_ATTRIBUTE = 16,
+ LDAP_UNDEFINED_TYPE = 17,
+ LDAP_INAPPROPRIATE_MATCHING = 18,
+ LDAP_CONSTRAINT_VIOLATION = 19,
+ LDAP_TYPE_OR_VALUE_EXISTS = 20,
+ LDAP_INVALID_SYNTAX = 21,
+
+ LDAP_NO_SUCH_OBJECT = 32,
+ LDAP_ALIAS_PROBLEM = 33,
+ LDAP_INVALID_DN_SYNTAX = 34,
+
+ LDAP_ALIAS_DEREF_PROBLEM = 36,
+
+ LDAP_INAPPROPRIATE_AUTH = 48,
+ LDAP_INVALID_CREDENTIALS = 49,
+ LDAP_INSUFFICIENT_ACCESS = 50,
+ LDAP_BUSY = 51,
+ LDAP_UNAVAILABLE = 52,
+ LDAP_UNWILLING_TO_PERFORM = 53,
+ LDAP_LOOP_DETECT = 54,
+
+ LDAP_NAMING_VIOLATION = 64,
+ LDAP_OBJECT_CLASS_VIOLATION = 65,
+ LDAP_NOT_ALLOWED_ON_NONLEAF = 66,
+ LDAP_NOT_ALLOWED_ON_RDN = 67,
+ LDAP_ALREADY_EXISTS = 68,
+ LDAP_NO_OBJECT_CLASS_MODS = 69,
+
+ LDAP_AFFECTS_MULTIPLE_DSAS = 71,
+
+ LDAP_OTHER = 80,
+};
+
+enum filter {
+ LDAP_FILT_AND = 0,
+ LDAP_FILT_OR = 1,
+ LDAP_FILT_NOT = 2,
+ LDAP_FILT_EQ = 3,
+ LDAP_FILT_SUBS = 4,
+ LDAP_FILT_GE = 5,
+ LDAP_FILT_LE = 6,
+ LDAP_FILT_PRES = 7,
+ LDAP_FILT_APPR = 8,
+};
+
+enum subfilter {
+ LDAP_FILT_SUBS_INIT = 0,
+ LDAP_FILT_SUBS_ANY = 1,
+ LDAP_FILT_SUBS_FIN = 2,
+};
+
+struct aldap *aldap_init(int fd);
+int aldap_close(struct aldap *);
+struct aldap_message *aldap_parse(struct aldap *);
+void aldap_freemsg(struct aldap_message *);
+
+int aldap_bind(struct aldap *, char *, char *);
+int aldap_unbind(struct aldap *);
+int aldap_search(struct aldap *, char *, enum scope, char *, char **, int, int, int, struct aldap_page_control *);
+int aldap_get_errno(struct aldap *, const char **);
+
+int aldap_get_resultcode(struct aldap_message *);
+char *aldap_get_dn(struct aldap_message *);
+char *aldap_get_diagmsg(struct aldap_message *);
+char **aldap_get_references(struct aldap_message *);
+void aldap_free_references(char **values);
+#if 0
+int aldap_parse_url(char *, struct aldap_url *);
+void aldap_free_url(struct aldap_url *);
+int aldap_search_url(struct aldap *, char *, int, int, int);
+#endif
+
+int aldap_count_attrs(struct aldap_message *);
+int aldap_match_attr(struct aldap_message *, char *, char ***);
+int aldap_first_attr(struct aldap_message *, char **, char ***);
+int aldap_next_attr(struct aldap_message *, char **, char ***);
+int aldap_free_attr(char **);
+
+struct aldap_page_control *aldap_parse_page_control(struct ber_element *, size_t len);
+void aldap_freepage(struct aldap_page_control *);
diff --git a/usr.sbin/ypldap/ber.c b/usr.sbin/ypldap/ber.c
new file mode 100644
index 0000000..540df69
--- /dev/null
+++ b/usr.sbin/ypldap/ber.c
@@ -0,0 +1,1268 @@
+/* $OpenBSD: ber.c,v 1.9 2015/02/12 00:30:38 pelikan Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2007 Reyk Floeter <reyk@vantronix.net>
+ * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <err.h> /* XXX for debug output */
+#include <stdio.h> /* XXX for debug output */
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+
+#include "ber.h"
+
+#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
+
+#define BER_TYPE_CONSTRUCTED 0x20 /* otherwise primitive */
+#define BER_TYPE_SINGLE_MAX 30
+#define BER_TAG_MASK 0x1f
+#define BER_TAG_MORE 0x80 /* more subsequent octets */
+#define BER_TAG_TYPE_MASK 0x7f
+#define BER_CLASS_SHIFT 6
+
+static int ber_dump_element(struct ber *ber, struct ber_element *root);
+static void ber_dump_header(struct ber *ber, struct ber_element *root);
+static void ber_putc(struct ber *ber, u_char c);
+static void ber_write(struct ber *ber, void *buf, size_t len);
+static ssize_t get_id(struct ber *b, unsigned long *tag, int *class,
+ int *cstruct);
+static ssize_t get_len(struct ber *b, ssize_t *len);
+static ssize_t ber_read_element(struct ber *ber, struct ber_element *elm);
+static ssize_t ber_readbuf(struct ber *b, void *buf, size_t nbytes);
+static ssize_t ber_getc(struct ber *b, u_char *c);
+static ssize_t ber_read(struct ber *ber, void *buf, size_t len);
+
+#ifdef DEBUG
+#define DPRINTF(...) printf(__VA_ARGS__)
+#else
+#define DPRINTF(...) do { } while (0)
+#endif
+
+struct ber_element *
+ber_get_element(unsigned long encoding)
+{
+ struct ber_element *elm;
+
+ if ((elm = calloc(1, sizeof(*elm))) == NULL)
+ return NULL;
+
+ elm->be_encoding = encoding;
+ ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
+
+ return elm;
+}
+
+void
+ber_set_header(struct ber_element *elm, int class, unsigned long type)
+{
+ elm->be_class = class & BER_CLASS_MASK;
+ if (type == BER_TYPE_DEFAULT)
+ type = elm->be_encoding;
+ elm->be_type = type;
+}
+
+void
+ber_link_elements(struct ber_element *prev, struct ber_element *elm)
+{
+ if (prev != NULL) {
+ if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
+ prev->be_encoding == BER_TYPE_SET) &&
+ prev->be_sub == NULL)
+ prev->be_sub = elm;
+ else
+ prev->be_next = elm;
+ }
+}
+
+struct ber_element *
+ber_unlink_elements(struct ber_element *prev)
+{
+ struct ber_element *elm;
+
+ if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
+ prev->be_encoding == BER_TYPE_SET) &&
+ prev->be_sub != NULL) {
+ elm = prev->be_sub;
+ prev->be_sub = NULL;
+ } else {
+ elm = prev->be_next;
+ prev->be_next = NULL;
+ }
+
+ return (elm);
+}
+
+void
+ber_replace_elements(struct ber_element *prev, struct ber_element *new)
+{
+ struct ber_element *ber, *next;
+
+ ber = ber_unlink_elements(prev);
+ next = ber_unlink_elements(ber);
+ ber_link_elements(new, next);
+ ber_link_elements(prev, new);
+
+ /* cleanup old element */
+ ber_free_elements(ber);
+}
+
+struct ber_element *
+ber_add_sequence(struct ber_element *prev)
+{
+ struct ber_element *elm;
+
+ if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL)
+ return NULL;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+struct ber_element *
+ber_add_set(struct ber_element *prev)
+{
+ struct ber_element *elm;
+
+ if ((elm = ber_get_element(BER_TYPE_SET)) == NULL)
+ return NULL;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+struct ber_element *
+ber_add_enumerated(struct ber_element *prev, long long val)
+{
+ struct ber_element *elm;
+ u_int i, len = 0;
+ u_char cur, last = 0;
+
+ if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL)
+ return NULL;
+
+ elm->be_numeric = val;
+
+ for (i = 0; i < sizeof(long long); i++) {
+ cur = val & 0xff;
+ if (cur != 0 && cur != 0xff)
+ len = i;
+ if ((cur == 0 && last & 0x80) ||
+ (cur == 0xff && (last & 0x80) == 0))
+ len = i;
+ val >>= 8;
+ last = cur;
+ }
+ elm->be_len = len + 1;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+struct ber_element *
+ber_add_integer(struct ber_element *prev, long long val)
+{
+ struct ber_element *elm;
+ u_int i, len = 0;
+ u_char cur, last = 0;
+
+ if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL)
+ return NULL;
+
+ elm->be_numeric = val;
+
+ for (i = 0; i < sizeof(long long); i++) {
+ cur = val & 0xff;
+ if (cur != 0 && cur != 0xff)
+ len = i;
+ if ((cur == 0 && last & 0x80) ||
+ (cur == 0xff && (last & 0x80) == 0))
+ len = i;
+ val >>= 8;
+ last = cur;
+ }
+ elm->be_len = len + 1;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+int
+ber_get_integer(struct ber_element *elm, long long *n)
+{
+ if (elm->be_encoding != BER_TYPE_INTEGER)
+ return -1;
+
+ *n = elm->be_numeric;
+ return 0;
+}
+
+int
+ber_get_enumerated(struct ber_element *elm, long long *n)
+{
+ if (elm->be_encoding != BER_TYPE_ENUMERATED)
+ return -1;
+
+ *n = elm->be_numeric;
+ return 0;
+}
+
+
+struct ber_element *
+ber_add_boolean(struct ber_element *prev, int bool)
+{
+ struct ber_element *elm;
+
+ if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL)
+ return NULL;
+
+ elm->be_numeric = bool ? 0xff : 0;
+ elm->be_len = 1;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+int
+ber_get_boolean(struct ber_element *elm, int *b)
+{
+ if (elm->be_encoding != BER_TYPE_BOOLEAN)
+ return -1;
+
+ *b = !(elm->be_numeric == 0);
+ return 0;
+}
+
+struct ber_element *
+ber_add_string(struct ber_element *prev, const char *string)
+{
+ return ber_add_nstring(prev, string, strlen(string));
+}
+
+struct ber_element *
+ber_add_nstring(struct ber_element *prev, const char *string0, size_t len)
+{
+ struct ber_element *elm;
+ char *string;
+
+ if ((string = calloc(1, len)) == NULL)
+ return NULL;
+ if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
+ free(string);
+ return NULL;
+ }
+
+ bcopy(string0, string, len);
+ elm->be_val = string;
+ elm->be_len = len;
+ elm->be_free = 1; /* free string on cleanup */
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+int
+ber_get_string(struct ber_element *elm, char **s)
+{
+ if (elm->be_encoding != BER_TYPE_OCTETSTRING)
+ return -1;
+
+ *s = elm->be_val;
+ return 0;
+}
+
+int
+ber_get_nstring(struct ber_element *elm, void **p, size_t *len)
+{
+ if (elm->be_encoding != BER_TYPE_OCTETSTRING)
+ return -1;
+
+ *p = elm->be_val;
+ *len = elm->be_len;
+ return 0;
+}
+
+struct ber_element *
+ber_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
+{
+ struct ber_element *elm;
+ void *v;
+
+ if ((v = calloc(1, len)) == NULL)
+ return NULL;
+ if ((elm = ber_get_element(BER_TYPE_BITSTRING)) == NULL) {
+ free(v);
+ return NULL;
+ }
+
+ bcopy(v0, v, len);
+ elm->be_val = v;
+ elm->be_len = len;
+ elm->be_free = 1; /* free string on cleanup */
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+int
+ber_get_bitstring(struct ber_element *elm, void **v, size_t *len)
+{
+ if (elm->be_encoding != BER_TYPE_BITSTRING)
+ return -1;
+
+ *v = elm->be_val;
+ *len = elm->be_len;
+ return 0;
+}
+
+struct ber_element *
+ber_add_null(struct ber_element *prev)
+{
+ struct ber_element *elm;
+
+ if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL)
+ return NULL;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+int
+ber_get_null(struct ber_element *elm)
+{
+ if (elm->be_encoding != BER_TYPE_NULL)
+ return -1;
+
+ return 0;
+}
+
+struct ber_element *
+ber_add_eoc(struct ber_element *prev)
+{
+ struct ber_element *elm;
+
+ if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL)
+ return NULL;
+
+ ber_link_elements(prev, elm);
+
+ return elm;
+}
+
+int
+ber_get_eoc(struct ber_element *elm)
+{
+ if (elm->be_encoding != BER_TYPE_EOC)
+ return -1;
+
+ return 0;
+}
+
+size_t
+ber_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
+{
+ u_int32_t v;
+ u_int i, j = 0, k;
+
+ if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
+ o->bo_id[0] > 2 || o->bo_id[1] > 40)
+ return (0);
+
+ v = (o->bo_id[0] * 40) + o->bo_id[1];
+ for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
+ for (k = 28; k >= 7; k -= 7) {
+ if (v >= (u_int)(1 << k)) {
+ if (len)
+ buf[j] = v >> k | BER_TAG_MORE;
+ j++;
+ }
+ }
+ if (len)
+ buf[j] = v & BER_TAG_TYPE_MASK;
+ j++;
+ }
+
+ return (j);
+}
+
+int
+ber_string2oid(const char *oidstr, struct ber_oid *o)
+{
+ char *sp, *p, str[BUFSIZ];
+ const char *errstr;
+
+ if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
+ return (-1);
+ bzero(o, sizeof(*o));
+
+ /* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
+ for (p = sp = str; p != NULL; sp = p) {
+ if ((p = strpbrk(p, "._-")) != NULL)
+ *p++ = '\0';
+ o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
+ if (errstr || o->bo_n > BER_MAX_OID_LEN)
+ return (-1);
+ }
+
+ return (0);
+}
+
+struct ber_element *
+ber_add_oid(struct ber_element *prev, struct ber_oid *o)
+{
+ struct ber_element *elm;
+ u_int8_t *buf;
+ size_t len;
+
+ if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL)
+ return (NULL);
+
+ if ((len = ber_oid2ber(o, NULL, 0)) == 0)
+ goto fail;
+
+ if ((buf = calloc(1, len)) == NULL)
+ goto fail;
+
+ elm->be_val = buf;
+ elm->be_len = len;
+ elm->be_free = 1;
+
+ if (ber_oid2ber(o, buf, len) != len)
+ goto fail;
+
+ ber_link_elements(prev, elm);
+
+ return (elm);
+
+ fail:
+ ber_free_elements(elm);
+ return (NULL);
+}
+
+struct ber_element *
+ber_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
+{
+ struct ber_oid no;
+
+ if (n > BER_MAX_OID_LEN)
+ return (NULL);
+ no.bo_n = n;
+ bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
+
+ return (ber_add_oid(prev, &no));
+}
+
+struct ber_element *
+ber_add_oidstring(struct ber_element *prev, const char *oidstr)
+{
+ struct ber_oid o;
+
+ if (ber_string2oid(oidstr, &o) == -1)
+ return (NULL);
+
+ return (ber_add_oid(prev, &o));
+}
+
+int
+ber_get_oid(struct ber_element *elm, struct ber_oid *o)
+{
+ u_int8_t *buf;
+ size_t len, i = 0, j = 0;
+
+ if (elm->be_encoding != BER_TYPE_OBJECT)
+ return (-1);
+
+ buf = elm->be_val;
+ len = elm->be_len;
+
+ if (!buf[i])
+ return (-1);
+
+ bzero(o, sizeof(*o));
+ o->bo_id[j++] = buf[i] / 40;
+ o->bo_id[j++] = buf[i++] % 40;
+ for (; i < len && j < BER_MAX_OID_LEN; i++) {
+ o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
+ if (buf[i] & 0x80)
+ continue;
+ j++;
+ }
+ o->bo_n = j;
+
+ return (0);
+}
+
+struct ber_element *
+ber_printf_elements(struct ber_element *ber, char *fmt, ...)
+{
+ va_list ap;
+ int d, class;
+ size_t len;
+ unsigned long type;
+ long long i;
+ char *s;
+ void *p;
+ struct ber_oid *o;
+ struct ber_element *sub = ber, *e;
+
+ va_start(ap, fmt);
+ while (*fmt) {
+ switch (*fmt++) {
+ case 'B':
+ p = va_arg(ap, void *);
+ len = va_arg(ap, size_t);
+ if ((ber = ber_add_bitstring(ber, p, len)) == NULL)
+ goto fail;
+ break;
+ case 'b':
+ d = va_arg(ap, int);
+ if ((ber = ber_add_boolean(ber, d)) == NULL)
+ goto fail;
+ break;
+ case 'd':
+ d = va_arg(ap, int);
+ if ((ber = ber_add_integer(ber, d)) == NULL)
+ goto fail;
+ break;
+ case 'e':
+ e = va_arg(ap, struct ber_element *);
+ ber_link_elements(ber, e);
+ break;
+ case 'E':
+ i = va_arg(ap, long long);
+ if ((ber = ber_add_enumerated(ber, i)) == NULL)
+ goto fail;
+ break;
+ case 'i':
+ i = va_arg(ap, long long);
+ if ((ber = ber_add_integer(ber, i)) == NULL)
+ goto fail;
+ break;
+ case 'O':
+ o = va_arg(ap, struct ber_oid *);
+ if ((ber = ber_add_oid(ber, o)) == NULL)
+ goto fail;
+ break;
+ case 'o':
+ s = va_arg(ap, char *);
+ if ((ber = ber_add_oidstring(ber, s)) == NULL)
+ goto fail;
+ break;
+ case 's':
+ s = va_arg(ap, char *);
+ if ((ber = ber_add_string(ber, s)) == NULL)
+ goto fail;
+ break;
+ case 't':
+ class = va_arg(ap, int);
+ type = va_arg(ap, unsigned long);
+ ber_set_header(ber, class, type);
+ break;
+ case 'x':
+ s = va_arg(ap, char *);
+ len = va_arg(ap, size_t);
+ if ((ber = ber_add_nstring(ber, s, len)) == NULL)
+ goto fail;
+ break;
+ case '0':
+ if ((ber = ber_add_null(ber)) == NULL)
+ goto fail;
+ break;
+ case '{':
+ if ((ber = sub = ber_add_sequence(ber)) == NULL)
+ goto fail;
+ break;
+ case '(':
+ if ((ber = sub = ber_add_set(ber)) == NULL)
+ goto fail;
+ break;
+ case '}':
+ case ')':
+ ber = sub;
+ break;
+ case '.':
+ if ((e = ber_add_eoc(ber)) == NULL)
+ goto fail;
+ ber = e;
+ break;
+ default:
+ break;
+ }
+ }
+ va_end(ap);
+
+ return (ber);
+ fail:
+ ber_free_elements(ber);
+ return (NULL);
+}
+
+int
+ber_scanf_elements(struct ber_element *ber, char *fmt, ...)
+{
+#define _MAX_SEQ 128
+ va_list ap;
+ int *d, level = -1;
+ unsigned long *t;
+ long long *i;
+ void **ptr;
+ size_t *len, ret = 0, n = strlen(fmt);
+ char **s;
+ struct ber_oid *o;
+ struct ber_element *parent[_MAX_SEQ], **e;
+
+ bzero(parent, sizeof(struct ber_element *) * _MAX_SEQ);
+
+ va_start(ap, fmt);
+ while (*fmt) {
+ switch (*fmt++) {
+ case 'B':
+ ptr = va_arg(ap, void **);
+ len = va_arg(ap, size_t *);
+ if (ber_get_bitstring(ber, ptr, len) == -1)
+ goto fail;
+ ret++;
+ break;
+ case 'b':
+ d = va_arg(ap, int *);
+ if (ber_get_boolean(ber, d) == -1)
+ goto fail;
+ ret++;
+ break;
+ case 'e':
+ e = va_arg(ap, struct ber_element **);
+ *e = ber;
+ ret++;
+ continue;
+ case 'E':
+ i = va_arg(ap, long long *);
+ if (ber_get_enumerated(ber, i) == -1)
+ goto fail;
+ ret++;
+ break;
+ case 'i':
+ i = va_arg(ap, long long *);
+ if (ber_get_integer(ber, i) == -1)
+ goto fail;
+ ret++;
+ break;
+ case 'o':
+ o = va_arg(ap, struct ber_oid *);
+ if (ber_get_oid(ber, o) == -1)
+ goto fail;
+ ret++;
+ break;
+ case 'S':
+ ret++;
+ break;
+ case 's':
+ s = va_arg(ap, char **);
+ if (ber_get_string(ber, s) == -1)
+ goto fail;
+ ret++;
+ break;
+ case 't':
+ d = va_arg(ap, int *);
+ t = va_arg(ap, unsigned long *);
+ *d = ber->be_class;
+ *t = ber->be_type;
+ ret++;
+ continue;
+ case 'x':
+ ptr = va_arg(ap, void **);
+ len = va_arg(ap, size_t *);
+ if (ber_get_nstring(ber, ptr, len) == -1)
+ goto fail;
+ ret++;
+ break;
+ case '0':
+ if (ber->be_encoding != BER_TYPE_NULL)
+ goto fail;
+ ret++;
+ break;
+ case '.':
+ if (ber->be_encoding != BER_TYPE_EOC)
+ goto fail;
+ ret++;
+ break;
+ case '{':
+ case '(':
+ if (ber->be_encoding != BER_TYPE_SEQUENCE &&
+ ber->be_encoding != BER_TYPE_SET)
+ goto fail;
+ if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
+ goto fail;
+ parent[++level] = ber;
+ ber = ber->be_sub;
+ ret++;
+ continue;
+ case '}':
+ case ')':
+ if (parent[level] == NULL)
+ goto fail;
+ ber = parent[level--];
+ ret++;
+ continue;
+ default:
+ goto fail;
+ }
+
+ if (ber->be_next == NULL)
+ continue;
+ ber = ber->be_next;
+ }
+ va_end(ap);
+ return (ret == n ? 0 : -1);
+
+ fail:
+ va_end(ap);
+ return (-1);
+
+}
+
+/*
+ * write ber elements to the socket
+ *
+ * params:
+ * ber holds the socket
+ * root fully populated element tree
+ *
+ * returns:
+ * >=0 number of bytes written
+ * -1 on failure and sets errno
+ */
+int
+ber_write_elements(struct ber *ber, struct ber_element *root)
+{
+ size_t len;
+
+ /* calculate length because only the definite form is required */
+ len = ber_calc_len(root);
+ DPRINTF("write ber element of %zd bytes length\n", len);
+
+ if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
+ free(ber->br_wbuf);
+ ber->br_wbuf = NULL;
+ }
+ if (ber->br_wbuf == NULL) {
+ if ((ber->br_wbuf = malloc(len)) == NULL)
+ return -1;
+ ber->br_wend = ber->br_wbuf + len;
+ }
+
+ /* reset write pointer */
+ ber->br_wptr = ber->br_wbuf;
+
+ if (ber_dump_element(ber, root) == -1)
+ return -1;
+
+ /* XXX this should be moved to a different function */
+ if (ber->fd != -1)
+ return write(ber->fd, ber->br_wbuf, len);
+
+ return (len);
+}
+
+/*
+ * read ber elements from the socket
+ *
+ * params:
+ * ber holds the socket and lot more
+ * root if NULL, build up an element tree from what we receive on
+ * the wire. If not null, use the specified encoding for the
+ * elements received.
+ *
+ * returns:
+ * !=NULL, elements read and store in the ber_element tree
+ * NULL, type mismatch or read error
+ */
+struct ber_element *
+ber_read_elements(struct ber *ber, struct ber_element *elm)
+{
+ struct ber_element *root = elm;
+
+ if (root == NULL) {
+ if ((root = ber_get_element(0)) == NULL)
+ return NULL;
+ }
+
+ DPRINTF("read ber elements, root %p\n", root);
+
+ if (ber_read_element(ber, root) == -1) {
+ /* Cleanup if root was allocated by us */
+ if (elm == NULL)
+ ber_free_elements(root);
+ return NULL;
+ }
+
+ return root;
+}
+
+void
+ber_free_elements(struct ber_element *root)
+{
+ if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
+ root->be_encoding == BER_TYPE_SET))
+ ber_free_elements(root->be_sub);
+ if (root->be_next)
+ ber_free_elements(root->be_next);
+ if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
+ root->be_encoding == BER_TYPE_BITSTRING ||
+ root->be_encoding == BER_TYPE_OBJECT))
+ free(root->be_val);
+ free(root);
+}
+
+size_t
+ber_calc_len(struct ber_element *root)
+{
+ unsigned long t;
+ size_t s;
+ size_t size = 2; /* minimum 1 byte head and 1 byte size */
+
+ /* calculate the real length of a sequence or set */
+ if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
+ root->be_encoding == BER_TYPE_SET))
+ root->be_len = ber_calc_len(root->be_sub);
+
+ /* fix header length for extended types */
+ if (root->be_type > BER_TYPE_SINGLE_MAX)
+ for (t = root->be_type; t > 0; t >>= 7)
+ size++;
+ if (root->be_len >= BER_TAG_MORE)
+ for (s = root->be_len; s > 0; s >>= 8)
+ size++;
+
+ /* calculate the length of the following elements */
+ if (root->be_next)
+ size += ber_calc_len(root->be_next);
+
+ /* This is an empty element, do not use a minimal size */
+ if (root->be_type == BER_TYPE_EOC && root->be_len == 0)
+ return (0);
+
+ return (root->be_len + size);
+}
+
+/*
+ * internal functions
+ */
+
+static int
+ber_dump_element(struct ber *ber, struct ber_element *root)
+{
+ unsigned long long l;
+ int i;
+ uint8_t u;
+
+ ber_dump_header(ber, root);
+
+ switch (root->be_encoding) {
+ case BER_TYPE_BOOLEAN:
+ case BER_TYPE_INTEGER:
+ case BER_TYPE_ENUMERATED:
+ l = (unsigned long long)root->be_numeric;
+ for (i = root->be_len; i > 0; i--) {
+ u = (l >> ((i - 1) * 8)) & 0xff;
+ ber_putc(ber, u);
+ }
+ break;
+ case BER_TYPE_BITSTRING:
+ return -1;
+ case BER_TYPE_OCTETSTRING:
+ case BER_TYPE_OBJECT:
+ ber_write(ber, root->be_val, root->be_len);
+ break;
+ case BER_TYPE_NULL: /* no payload */
+ case BER_TYPE_EOC:
+ break;
+ case BER_TYPE_SEQUENCE:
+ case BER_TYPE_SET:
+ if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1)
+ return -1;
+ break;
+ }
+
+ if (root->be_next == NULL)
+ return 0;
+ return ber_dump_element(ber, root->be_next);
+}
+
+static void
+ber_dump_header(struct ber *ber, struct ber_element *root)
+{
+ u_char id = 0, t, buf[8];
+ unsigned long type;
+ size_t size;
+
+ /* class universal, type encoding depending on type value */
+ /* length encoding */
+ if (root->be_type <= BER_TYPE_SINGLE_MAX) {
+ id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
+ if (root->be_encoding == BER_TYPE_SEQUENCE ||
+ root->be_encoding == BER_TYPE_SET)
+ id |= BER_TYPE_CONSTRUCTED;
+
+ ber_putc(ber, id);
+ } else {
+ id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
+ if (root->be_encoding == BER_TYPE_SEQUENCE ||
+ root->be_encoding == BER_TYPE_SET)
+ id |= BER_TYPE_CONSTRUCTED;
+
+ ber_putc(ber, id);
+
+ for (t = 0, type = root->be_type; type > 0; type >>= 7)
+ buf[t++] = type & ~BER_TAG_MORE;
+
+ while (t-- > 0) {
+ if (t > 0)
+ buf[t] |= BER_TAG_MORE;
+ ber_putc(ber, buf[t]);
+ }
+ }
+
+ if (root->be_len < BER_TAG_MORE) {
+ /* short form */
+ ber_putc(ber, root->be_len);
+ } else {
+ for (t = 0, size = root->be_len; size > 0; size >>= 8)
+ buf[t++] = size & 0xff;
+
+ ber_putc(ber, t | BER_TAG_MORE);
+
+ while (t > 0)
+ ber_putc(ber, buf[--t]);
+ }
+}
+
+static void
+ber_putc(struct ber *ber, u_char c)
+{
+ if (ber->br_wptr + 1 <= ber->br_wend)
+ *ber->br_wptr = c;
+ ber->br_wptr++;
+}
+
+static void
+ber_write(struct ber *ber, void *buf, size_t len)
+{
+ if (ber->br_wptr + len <= ber->br_wend)
+ bcopy(buf, ber->br_wptr, len);
+ ber->br_wptr += len;
+}
+
+/*
+ * extract a BER encoded tag. There are two types, a short and long form.
+ */
+static ssize_t
+get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct)
+{
+ u_char u;
+ size_t i = 0;
+ unsigned long t = 0;
+
+ if (ber_getc(b, &u) == -1)
+ return -1;
+
+ *class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
+ *cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
+
+ if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
+ *tag = u & BER_TAG_MASK;
+ return 1;
+ }
+
+ do {
+ if (ber_getc(b, &u) == -1)
+ return -1;
+ t = (t << 7) | (u & ~BER_TAG_MORE);
+ i++;
+ } while (u & BER_TAG_MORE);
+
+ if (i > sizeof(unsigned long)) {
+ errno = ERANGE;
+ return -1;
+ }
+
+ *tag = t;
+ return i + 1;
+}
+
+/*
+ * extract length of a ber object -- if length is unknown an error is returned.
+ */
+static ssize_t
+get_len(struct ber *b, ssize_t *len)
+{
+ u_char u, n;
+ ssize_t s, r;
+
+ if (ber_getc(b, &u) == -1)
+ return -1;
+ if ((u & BER_TAG_MORE) == 0) {
+ /* short form */
+ *len = u;
+ return 1;
+ }
+
+ n = u & ~BER_TAG_MORE;
+ if (sizeof(ssize_t) < n) {
+ errno = ERANGE;
+ return -1;
+ }
+ r = n + 1;
+
+ for (s = 0; n > 0; n--) {
+ if (ber_getc(b, &u) == -1)
+ return -1;
+ s = (s << 8) | u;
+ }
+
+ if (s < 0) {
+ /* overflow */
+ errno = ERANGE;
+ return -1;
+ }
+
+ if (s == 0) {
+ /* invalid encoding */
+ errno = EINVAL;
+ return -1;
+ }
+
+ *len = s;
+ return r;
+}
+
+static ssize_t
+ber_read_element(struct ber *ber, struct ber_element *elm)
+{
+ long long val = 0;
+ struct ber_element *next;
+ unsigned long type;
+ int i, class, cstruct;
+ ssize_t len, r, totlen = 0;
+ u_char c;
+
+ if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
+ return -1;
+ DPRINTF("ber read got class %d type %lu, %s\n",
+ class, type, cstruct ? "constructive" : "primitive");
+ totlen += r;
+ if ((r = get_len(ber, &len)) == -1)
+ return -1;
+ DPRINTF("ber read element size %zd\n", len);
+ totlen += r + len;
+
+ elm->be_type = type;
+ elm->be_len = len;
+ elm->be_class = class;
+
+ if (elm->be_encoding == 0) {
+ /* try to figure out the encoding via class, type and cstruct */
+ if (cstruct)
+ elm->be_encoding = BER_TYPE_SEQUENCE;
+ else if (class == BER_CLASS_UNIVERSAL)
+ elm->be_encoding = type;
+ else if (ber->br_application != NULL) {
+ /*
+ * Ask the application to map the encoding to a
+ * universal type. For example, a SMI IpAddress
+ * type is defined as 4 byte OCTET STRING.
+ */
+ elm->be_encoding = (*ber->br_application)(elm);
+ } else
+ /* last resort option */
+ elm->be_encoding = BER_TYPE_NULL;
+ }
+
+ switch (elm->be_encoding) {
+ case BER_TYPE_EOC: /* End-Of-Content */
+ break;
+ case BER_TYPE_BOOLEAN:
+ case BER_TYPE_INTEGER:
+ case BER_TYPE_ENUMERATED:
+ if (len > (ssize_t)sizeof(long long))
+ return -1;
+ for (i = 0; i < len; i++) {
+ if (ber_getc(ber, &c) != 1)
+ return -1;
+ val <<= 8;
+ val |= c;
+ }
+
+ /* sign extend if MSB is set */
+ if (val >> ((i - 1) * 8) & 0x80)
+ val |= ULLONG_MAX << (i * 8);
+ elm->be_numeric = val;
+ break;
+ case BER_TYPE_BITSTRING:
+ elm->be_val = malloc(len);
+ if (elm->be_val == NULL)
+ return -1;
+ elm->be_free = 1;
+ elm->be_len = len;
+ ber_read(ber, elm->be_val, len);
+ break;
+ case BER_TYPE_OCTETSTRING:
+ case BER_TYPE_OBJECT:
+ elm->be_val = malloc(len + 1);
+ if (elm->be_val == NULL)
+ return -1;
+ elm->be_free = 1;
+ elm->be_len = len;
+ ber_read(ber, elm->be_val, len);
+ ((u_char *)elm->be_val)[len] = '\0';
+ break;
+ case BER_TYPE_NULL: /* no payload */
+ if (len != 0)
+ return -1;
+ break;
+ case BER_TYPE_SEQUENCE:
+ case BER_TYPE_SET:
+ if (elm->be_sub == NULL) {
+ if ((elm->be_sub = ber_get_element(0)) == NULL)
+ return -1;
+ }
+ next = elm->be_sub;
+ while (len > 0) {
+ r = ber_read_element(ber, next);
+ if (r == -1)
+ return -1;
+ len -= r;
+ if (len > 0 && next->be_next == NULL) {
+ if ((next->be_next = ber_get_element(0)) ==
+ NULL)
+ return -1;
+ }
+ next = next->be_next;
+ }
+ break;
+ }
+ return totlen;
+}
+
+static ssize_t
+ber_readbuf(struct ber *b, void *buf, size_t nbytes)
+{
+ size_t sz;
+ size_t len;
+
+ if (b->br_rbuf == NULL)
+ return -1;
+
+ sz = b->br_rend - b->br_rptr;
+ len = MINIMUM(nbytes, sz);
+ if (len == 0) {
+ errno = ECANCELED;
+ return (-1); /* end of buffer and parser wants more data */
+ }
+
+ bcopy(b->br_rptr, buf, len);
+ b->br_rptr += len;
+
+ return (len);
+}
+
+void
+ber_set_readbuf(struct ber *b, void *buf, size_t len)
+{
+ b->br_rbuf = b->br_rptr = buf;
+ b->br_rend = (u_int8_t *)buf + len;
+}
+
+ssize_t
+ber_get_writebuf(struct ber *b, void **buf)
+{
+ if (b->br_wbuf == NULL)
+ return -1;
+ *buf = b->br_wbuf;
+ return (b->br_wend - b->br_wbuf);
+}
+
+void
+ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *))
+{
+ b->br_application = cb;
+}
+
+void
+ber_free(struct ber *b)
+{
+ free(b->br_wbuf);
+}
+
+static ssize_t
+ber_getc(struct ber *b, u_char *c)
+{
+ ssize_t r;
+ /*
+ * XXX calling read here is wrong in many ways. The most obvious one
+ * being that we will block till data arrives.
+ * But for now it is _good enough_ *gulp*
+ */
+ if (b->fd == -1)
+ r = ber_readbuf(b, c, 1);
+ else
+ r = read(b->fd, c, 1);
+ return r;
+}
+
+static ssize_t
+ber_read(struct ber *ber, void *buf, size_t len)
+{
+ u_char *b = buf;
+ ssize_t r, remain = len;
+
+ /*
+ * XXX calling read here is wrong in many ways. The most obvious one
+ * being that we will block till data arrives.
+ * But for now it is _good enough_ *gulp*
+ */
+
+ while (remain > 0) {
+ if (ber->fd == -1)
+ r = ber_readbuf(ber, b, remain);
+ else
+ r = read(ber->fd, b, remain);
+ if (r == -1) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ }
+ if (r == 0)
+ return (b - (u_char *)buf);
+ b += r;
+ remain -= r;
+ }
+ return (b - (u_char *)buf);
+}
diff --git a/usr.sbin/ypldap/ber.h b/usr.sbin/ypldap/ber.h
new file mode 100644
index 0000000..eec02d4
--- /dev/null
+++ b/usr.sbin/ypldap/ber.h
@@ -0,0 +1,129 @@
+/* $OpenBSD: ber.h,v 1.2 2008/12/29 15:48:13 aschrijver Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2007 Reyk Floeter <reyk@vantronix.net>
+ * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+struct ber_element {
+ struct ber_element *be_next;
+ unsigned long be_type;
+ unsigned long be_encoding;
+ size_t be_len;
+ int be_free;
+ u_int8_t be_class;
+ union {
+ struct ber_element *bv_sub;
+ void *bv_val;
+ long long bv_numeric;
+ } be_union;
+#define be_sub be_union.bv_sub
+#define be_val be_union.bv_val
+#define be_numeric be_union.bv_numeric
+};
+
+struct ber {
+ int fd;
+ u_char *br_wbuf;
+ u_char *br_wptr;
+ u_char *br_wend;
+ u_char *br_rbuf;
+ u_char *br_rptr;
+ u_char *br_rend;
+
+ unsigned long (*br_application)(struct ber_element *);
+};
+
+/* well-known ber_element types */
+#define BER_TYPE_DEFAULT ((unsigned long)-1)
+#define BER_TYPE_EOC 0
+#define BER_TYPE_BOOLEAN 1
+#define BER_TYPE_INTEGER 2
+#define BER_TYPE_BITSTRING 3
+#define BER_TYPE_OCTETSTRING 4
+#define BER_TYPE_NULL 5
+#define BER_TYPE_OBJECT 6
+#define BER_TYPE_ENUMERATED 10
+#define BER_TYPE_SEQUENCE 16
+#define BER_TYPE_SET 17
+
+/* ber classes */
+#define BER_CLASS_UNIVERSAL 0x0
+#define BER_CLASS_UNIV BER_CLASS_UNIVERSAL
+#define BER_CLASS_APPLICATION 0x1
+#define BER_CLASS_APP BER_CLASS_APPLICATION
+#define BER_CLASS_CONTEXT 0x2
+#define BER_CLASS_PRIVATE 0x3
+#define BER_CLASS_MASK 0x3
+
+/* common definitions */
+#define BER_MIN_OID_LEN 2 /* OBJECT */
+#define BER_MAX_OID_LEN 32 /* OBJECT */
+
+struct ber_oid {
+ u_int32_t bo_id[BER_MAX_OID_LEN + 1];
+ size_t bo_n;
+};
+
+__BEGIN_DECLS
+struct ber_element *ber_get_element(unsigned long);
+void ber_set_header(struct ber_element *, int,
+ unsigned long);
+void ber_link_elements(struct ber_element *,
+ struct ber_element *);
+struct ber_element *ber_unlink_elements(struct ber_element *);
+void ber_replace_elements(struct ber_element *,
+ struct ber_element *);
+struct ber_element *ber_add_sequence(struct ber_element *);
+struct ber_element *ber_add_set(struct ber_element *);
+struct ber_element *ber_add_integer(struct ber_element *, long long);
+int ber_get_integer(struct ber_element *, long long *);
+struct ber_element *ber_add_enumerated(struct ber_element *, long long);
+int ber_get_enumerated(struct ber_element *, long long *);
+struct ber_element *ber_add_boolean(struct ber_element *, int);
+int ber_get_boolean(struct ber_element *, int *);
+struct ber_element *ber_add_string(struct ber_element *, const char *);
+struct ber_element *ber_add_nstring(struct ber_element *, const char *,
+ size_t);
+int ber_get_string(struct ber_element *, char **);
+int ber_get_nstring(struct ber_element *, void **,
+ size_t *);
+struct ber_element *ber_add_bitstring(struct ber_element *, const void *,
+ size_t);
+int ber_get_bitstring(struct ber_element *, void **,
+ size_t *);
+struct ber_element *ber_add_null(struct ber_element *);
+int ber_get_null(struct ber_element *);
+struct ber_element *ber_add_eoc(struct ber_element *);
+int ber_get_eoc(struct ber_element *);
+struct ber_element *ber_add_oid(struct ber_element *, struct ber_oid *);
+struct ber_element *ber_add_noid(struct ber_element *, struct ber_oid *, int);
+struct ber_element *ber_add_oidstring(struct ber_element *, const char *);
+int ber_get_oid(struct ber_element *, struct ber_oid *);
+size_t ber_oid2ber(struct ber_oid *, u_int8_t *, size_t);
+int ber_string2oid(const char *, struct ber_oid *);
+struct ber_element *ber_printf_elements(struct ber_element *, char *, ...);
+int ber_scanf_elements(struct ber_element *, char *, ...);
+ssize_t ber_get_writebuf(struct ber *, void **);
+int ber_write_elements(struct ber *, struct ber_element *);
+void ber_set_readbuf(struct ber *, void *, size_t);
+struct ber_element *ber_read_elements(struct ber *, struct ber_element *);
+void ber_free_elements(struct ber_element *);
+size_t ber_calc_len(struct ber_element *);
+void ber_set_application(struct ber *,
+ unsigned long (*)(struct ber_element *));
+void ber_free(struct ber *);
+__END_DECLS
diff --git a/usr.sbin/ypldap/entries.c b/usr.sbin/ypldap/entries.c
new file mode 100644
index 0000000..1adce5a
--- /dev/null
+++ b/usr.sbin/ypldap/entries.c
@@ -0,0 +1,149 @@
+/* $OpenBSD: entries.c,v 1.3 2015/01/16 06:40:22 deraadt Exp $ */
+/* $FreeBSD$ */
+/*
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/tree.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "ypldap.h"
+
+void
+flatten_entries(struct env *env)
+{
+ size_t wrlen;
+ size_t len;
+ char *linep;
+ char *endp;
+ char *tmp;
+ struct userent *ue;
+ struct groupent *ge;
+
+ log_debug("flattening trees");
+ /*
+ * This takes all the line pointers in RB elements and
+ * concatenates them in a single string, to be able to
+ * implement next element lookup without tree traversal.
+ *
+ * An extra octet is alloced to make space for an additional NUL.
+ */
+ wrlen = env->sc_user_line_len;
+ if ((linep = calloc(1, env->sc_user_line_len + 1)) == NULL) {
+ /*
+ * XXX: try allocating a smaller chunk of memory
+ */
+ fatal("out of memory");
+ }
+ endp = linep;
+
+ RB_FOREACH(ue, user_name_tree, env->sc_user_names) {
+ /*
+ * we convert the first nul back to a column,
+ * copy the string and then convert it back to a nul.
+ */
+ ue->ue_line[strlen(ue->ue_line)] = ':';
+ log_debug("pushing line: %s", ue->ue_line);
+ len = strlen(ue->ue_line) + 1;
+ memcpy(endp, ue->ue_line, len);
+ endp[strcspn(endp, ":")] = '\0';
+ free(ue->ue_line);
+ ue->ue_line = endp;
+ endp += len;
+ wrlen -= len;
+
+ /*
+ * To save memory strdup(3) the netid_line which originally used
+ * LINE_WIDTH bytes
+ */
+ tmp = ue->ue_netid_line;
+ ue->ue_netid_line = strdup(tmp);
+ if (ue->ue_netid_line == NULL) {
+ fatal("out of memory");
+ }
+ free(tmp);
+ }
+ env->sc_user_lines = linep;
+
+ wrlen = env->sc_group_line_len;
+ if ((linep = calloc(1, env->sc_group_line_len + 1)) == NULL) {
+ /*
+ * XXX: try allocating a smaller chunk of memory
+ */
+ fatal("out of memory");
+ }
+ endp = linep;
+ RB_FOREACH(ge, group_name_tree, env->sc_group_names) {
+ /*
+ * we convert the first nul back to a column,
+ * copy the string and then convert it back to a nul.
+ */
+ ge->ge_line[strlen(ge->ge_line)] = ':';
+ log_debug("pushing line: %s", ge->ge_line);
+ len = strlen(ge->ge_line) + 1;
+ memcpy(endp, ge->ge_line, len);
+ endp[strcspn(endp, ":")] = '\0';
+ free(ge->ge_line);
+ ge->ge_line = endp;
+ endp += len;
+ wrlen -= len;
+ }
+ env->sc_group_lines = linep;
+}
+
+int
+userent_name_cmp(struct userent *ue1, struct userent *ue2)
+{
+ return (strcmp(ue1->ue_line, ue2->ue_line));
+}
+
+int
+userent_uid_cmp(struct userent *ue1, struct userent *ue2)
+{
+ return (ue1->ue_uid - ue2->ue_uid);
+}
+
+int
+groupent_name_cmp(struct groupent *ge1, struct groupent *ge2)
+{
+ return (strcmp(ge1->ge_line, ge2->ge_line));
+}
+
+int
+groupent_gid_cmp(struct groupent *ge1, struct groupent *ge2)
+{
+ return (ge1->ge_gid - ge2->ge_gid);
+}
+
+RB_GENERATE(user_name_tree, userent, ue_name_node, userent_name_cmp);
+RB_GENERATE(user_uid_tree, userent, ue_uid_node, userent_uid_cmp);
+RB_GENERATE(group_name_tree, groupent, ge_name_node, groupent_name_cmp);
+RB_GENERATE(group_gid_tree, groupent, ge_gid_node, groupent_gid_cmp);
diff --git a/usr.sbin/ypldap/ldapclient.c b/usr.sbin/ypldap/ldapclient.c
new file mode 100644
index 0000000..d522fb4
--- /dev/null
+++ b/usr.sbin/ypldap/ldapclient.c
@@ -0,0 +1,705 @@
+/* $OpenBSD: ldapclient.c,v 1.31 2014/11/16 23:24:44 tedu Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/tree.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <netdb.h>
+#include <errno.h>
+#include <err.h>
+#include <event.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "aldap.h"
+#include "ypldap.h"
+
+void client_sig_handler(int, short, void *);
+void client_dispatch_dns(int, short, void *);
+void client_dispatch_parent(int, short, void *);
+void client_shutdown(void);
+void client_connect(int, short, void *);
+void client_configure(struct env *);
+void client_periodic_update(int, short, void *);
+int client_build_req(struct idm *, struct idm_req *, struct aldap_message *,
+ int, int);
+int client_search_idm(struct env *, struct idm *, struct aldap *,
+ char **, char *, int, int, enum imsg_type);
+int client_try_idm(struct env *, struct idm *);
+int client_addr_init(struct idm *);
+int client_addr_free(struct idm *);
+
+struct aldap *client_aldap_open(struct ypldap_addr *);
+
+/*
+ * dummy wrapper to provide aldap_init with its fd's.
+ */
+struct aldap *
+client_aldap_open(struct ypldap_addr *addr)
+{
+ int fd = -1;
+ struct ypldap_addr *p;
+
+ for (p = addr; p != NULL; p = p->next) {
+ char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+ struct sockaddr *sa = (struct sockaddr *)&p->ss;
+
+ if (getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), sbuf,
+ sizeof(sbuf), NI_NUMERICHOST | NI_NUMERICSERV))
+ errx(1, "could not get numeric hostname");
+
+ if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
+ return NULL;
+
+ if (connect(fd, sa, sa->sa_len) == 0)
+ break;
+
+ warn("connect to %s port %s (%s) failed", hbuf, sbuf, "tcp");
+ close(fd);
+ }
+
+ if (fd == -1)
+ return NULL;
+
+ return aldap_init(fd);
+}
+
+int
+client_addr_init(struct idm *idm)
+{
+ struct sockaddr_in *sa_in;
+ struct sockaddr_in6 *sa_in6;
+ struct ypldap_addr *h;
+
+ for (h = idm->idm_addr; h != NULL; h = h->next) {
+ switch (h->ss.ss_family) {
+ case AF_INET:
+ sa_in = (struct sockaddr_in *)&h->ss;
+ if (ntohs(sa_in->sin_port) == 0)
+ sa_in->sin_port = htons(LDAP_PORT);
+ idm->idm_state = STATE_DNS_DONE;
+ break;
+ case AF_INET6:
+ sa_in6 = (struct sockaddr_in6 *)&h->ss;
+ if (ntohs(sa_in6->sin6_port) == 0)
+ sa_in6->sin6_port = htons(LDAP_PORT);
+ idm->idm_state = STATE_DNS_DONE;
+ break;
+ default:
+ fatalx("king bula sez: wrong AF in client_addr_init");
+ /* not reached */
+ }
+ }
+
+ return (0);
+}
+
+int
+client_addr_free(struct idm *idm)
+{
+ struct ypldap_addr *h, *p;
+
+ if (idm->idm_addr == NULL)
+ return (-1);
+
+ for (h = idm->idm_addr; h != NULL; h = p) {
+ p = h->next;
+ free(h);
+ }
+
+ idm->idm_addr = NULL;
+
+ return (0);
+}
+
+void
+client_sig_handler(int sig, short event, void *p)
+{
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ client_shutdown();
+ break;
+ default:
+ fatalx("unexpected signal");
+ }
+}
+
+void
+client_dispatch_dns(int fd, short events, void *p)
+{
+ struct imsg imsg;
+ u_int16_t dlen;
+ u_char *data;
+ struct ypldap_addr *h;
+ int n, wait_cnt = 0;
+ struct idm *idm;
+ int shut = 0;
+
+ struct env *env = p;
+ struct imsgev *iev = env->sc_iev_dns;
+ struct imsgbuf *ibuf = &iev->ibuf;
+
+ if ((events & (EV_READ | EV_WRITE)) == 0)
+ fatalx("unknown event");
+
+ if (events & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0)
+ shut = 1;
+ }
+ if (events & EV_WRITE) {
+ if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0)
+ shut = 1;
+ goto done;
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("client_dispatch_dns: imsg_get error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_HOST_DNS:
+ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry)
+ if (idm->idm_id == imsg.hdr.peerid)
+ break;
+ if (idm == NULL) {
+ log_warnx("IMSG_HOST_DNS with invalid peerID");
+ break;
+ }
+ if (idm->idm_addr != NULL) {
+ log_warnx("IMSG_HOST_DNS but addr != NULL!");
+ break;
+ }
+
+ dlen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ if (dlen == 0) { /* no data -> temp error */
+ idm->idm_state = STATE_DNS_TEMPFAIL;
+ break;
+ }
+
+ data = (u_char *)imsg.data;
+ while (dlen >= sizeof(struct sockaddr_storage)) {
+ if ((h = calloc(1, sizeof(struct ypldap_addr))) ==
+ NULL)
+ fatal(NULL);
+ memcpy(&h->ss, data, sizeof(h->ss));
+
+ if (idm->idm_addr == NULL)
+ h->next = NULL;
+ else
+ h->next = idm->idm_addr;
+
+ idm->idm_addr = h;
+
+ data += sizeof(h->ss);
+ dlen -= sizeof(h->ss);
+ }
+ if (dlen != 0)
+ fatalx("IMSG_HOST_DNS: dlen != 0");
+
+ client_addr_init(idm);
+
+ break;
+ default:
+ break;
+ }
+ imsg_free(&imsg);
+ }
+
+ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
+ if (client_try_idm(env, idm) == -1)
+ idm->idm_state = STATE_LDAP_FAIL;
+
+ if (idm->idm_state < STATE_LDAP_DONE)
+ wait_cnt++;
+ }
+ if (wait_cnt == 0)
+ imsg_compose_event(env->sc_iev, IMSG_END_UPDATE, 0, 0, -1,
+ NULL, 0);
+
+done:
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
+client_dispatch_parent(int fd, short events, void *p)
+{
+ int n;
+ int shut = 0;
+ struct imsg imsg;
+ struct env *env = p;
+ struct imsgev *iev = env->sc_iev;
+ struct imsgbuf *ibuf = &iev->ibuf;
+
+ if ((events & (EV_READ | EV_WRITE)) == 0)
+ fatalx("unknown event");
+
+ if (events & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0)
+ shut = 1;
+ }
+ if (events & EV_WRITE) {
+ if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0)
+ shut = 1;
+ goto done;
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("client_dispatch_parent: imsg_get error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_CONF_START: {
+ struct env params;
+
+ if (env->sc_flags & F_CONFIGURING) {
+ log_warnx("configuration already in progress");
+ break;
+ }
+ memcpy(&params, imsg.data, sizeof(params));
+ log_debug("configuration starting");
+ env->sc_flags |= F_CONFIGURING;
+ purge_config(env);
+ memcpy(&env->sc_conf_tv, &params.sc_conf_tv,
+ sizeof(env->sc_conf_tv));
+ env->sc_flags |= params.sc_flags;
+ break;
+ }
+ case IMSG_CONF_IDM: {
+ struct idm *idm;
+
+ if (!(env->sc_flags & F_CONFIGURING))
+ break;
+ if ((idm = calloc(1, sizeof(*idm))) == NULL)
+ fatal(NULL);
+ memcpy(idm, imsg.data, sizeof(*idm));
+ idm->idm_env = env;
+ TAILQ_INSERT_TAIL(&env->sc_idms, idm, idm_entry);
+ break;
+ }
+ case IMSG_CONF_END:
+ env->sc_flags &= ~F_CONFIGURING;
+ log_debug("applying configuration");
+ client_configure(env);
+ break;
+ default:
+ log_debug("client_dispatch_parent: unexpect imsg %d",
+ imsg.hdr.type);
+
+ break;
+ }
+ imsg_free(&imsg);
+ }
+
+done:
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
+client_shutdown(void)
+{
+ log_info("ldap client exiting");
+ _exit(0);
+}
+
+pid_t
+ldapclient(int pipe_main2client[2])
+{
+ pid_t pid, dns_pid;
+ int pipe_dns[2];
+ struct passwd *pw;
+ struct event ev_sigint;
+ struct event ev_sigterm;
+ struct env env;
+
+ switch (pid = fork()) {
+ case -1:
+ fatal("cannot fork");
+ break;
+ case 0:
+ break;
+ default:
+ return (pid);
+ }
+
+ bzero(&env, sizeof(env));
+ TAILQ_INIT(&env.sc_idms);
+
+ if ((pw = getpwnam(YPLDAP_USER)) == NULL)
+ fatal("getpwnam");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_dns) == -1)
+ fatal("socketpair");
+ dns_pid = ypldap_dns(pipe_dns, pw);
+ close(pipe_dns[1]);
+
+#ifndef DEBUG
+ if (chroot(pw->pw_dir) == -1)
+ fatal("chroot");
+ if (chdir("/") == -1)
+ fatal("chdir");
+#else
+#warning disabling chrooting in DEBUG mode
+#endif
+ setproctitle("ldap client");
+ ypldap_process = PROC_CLIENT;
+
+#ifndef DEBUG
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("cannot drop privileges");
+#else
+#warning disabling privilege revocation in DEBUG mode
+#endif
+
+ event_init();
+ signal(SIGPIPE, SIG_IGN);
+ signal_set(&ev_sigint, SIGINT, client_sig_handler, NULL);
+ signal_set(&ev_sigterm, SIGTERM, client_sig_handler, NULL);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+
+ close(pipe_main2client[0]);
+ if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
+ fatal(NULL);
+ if ((env.sc_iev_dns = calloc(1, sizeof(*env.sc_iev_dns))) == NULL)
+ fatal(NULL);
+
+ env.sc_iev->events = EV_READ;
+ env.sc_iev->data = &env;
+ imsg_init(&env.sc_iev->ibuf, pipe_main2client[1]);
+ env.sc_iev->handler = client_dispatch_parent;
+ event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
+ env.sc_iev->handler, &env);
+ event_add(&env.sc_iev->ev, NULL);
+
+ env.sc_iev_dns->events = EV_READ;
+ env.sc_iev_dns->data = &env;
+ imsg_init(&env.sc_iev_dns->ibuf, pipe_dns[0]);
+ env.sc_iev_dns->handler = client_dispatch_dns;
+ event_set(&env.sc_iev_dns->ev, env.sc_iev_dns->ibuf.fd,
+ env.sc_iev_dns->events, env.sc_iev_dns->handler, &env);
+ event_add(&env.sc_iev_dns->ev, NULL);
+
+ event_dispatch();
+ client_shutdown();
+
+ return (0);
+
+}
+
+int
+client_build_req(struct idm *idm, struct idm_req *ir, struct aldap_message *m,
+ int min_attr, int max_attr)
+{
+ char **ldap_attrs;
+ int i, k;
+
+ bzero(ir, sizeof(*ir));
+ for (i = min_attr; i < max_attr; i++) {
+ if (idm->idm_flags & F_FIXED_ATTR(i)) {
+ if (strlcat(ir->ir_line, idm->idm_attrs[i],
+ sizeof(ir->ir_line)) >= sizeof(ir->ir_line))
+ /*
+ * entry yields a line > 1024, trash it.
+ */
+ return (-1);
+
+ if (i == ATTR_UID) {
+ ir->ir_key.ik_uid = strtonum(
+ idm->idm_attrs[i], 0,
+ UID_MAX, NULL);
+ } else if (i == ATTR_GR_GID) {
+ ir->ir_key.ik_gid = strtonum(
+ idm->idm_attrs[i], 0,
+ GID_MAX, NULL);
+ }
+ } else if (idm->idm_list & F_LIST(i)) {
+ aldap_match_attr(m, idm->idm_attrs[i], &ldap_attrs);
+ for (k = 0; k >= 0 && ldap_attrs && ldap_attrs[k] != NULL; k++) {
+ /* XXX: Fail when attributes have illegal characters e.g. ',' */
+ if (strlcat(ir->ir_line, ldap_attrs[k],
+ sizeof(ir->ir_line)) >= sizeof(ir->ir_line))
+ continue;
+ if (ldap_attrs[k+1] != NULL)
+ if (strlcat(ir->ir_line, ",",
+ sizeof(ir->ir_line))
+ >= sizeof(ir->ir_line)) {
+ aldap_free_attr(ldap_attrs);
+ return (-1);
+ }
+ }
+ aldap_free_attr(ldap_attrs);
+ } else {
+ if (aldap_match_attr(m, idm->idm_attrs[i], &ldap_attrs) == -1)
+ return (-1);
+ if (ldap_attrs[0] == NULL)
+ return (-1);
+ if (strlcat(ir->ir_line, ldap_attrs[0],
+ sizeof(ir->ir_line)) >= sizeof(ir->ir_line)) {
+ aldap_free_attr(ldap_attrs);
+ return (-1);
+ }
+ if (i == ATTR_UID) {
+ ir->ir_key.ik_uid = strtonum(
+ ldap_attrs[0], 0, UID_MAX, NULL);
+ } else if (i == ATTR_GR_GID) {
+ ir->ir_key.ik_uid = strtonum(
+ ldap_attrs[0], 0, GID_MAX, NULL);
+ }
+ aldap_free_attr(ldap_attrs);
+ }
+
+ if (i + 1 != max_attr)
+ if (strlcat(ir->ir_line, ":",
+ sizeof(ir->ir_line)) >= sizeof(ir->ir_line))
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+client_search_idm(struct env *env, struct idm *idm, struct aldap *al,
+ char **attrs, char *filter, int min_attr, int max_attr,
+ enum imsg_type type)
+{
+ struct idm_req ir;
+ struct aldap_message *m;
+ struct aldap_page_control *pg = NULL;
+ const char *errstr;
+ char *dn;
+
+ dn = idm->idm_basedn;
+ if (type == IMSG_GRP_ENTRY && idm->idm_groupdn[0] != '\0')
+ dn = idm->idm_groupdn;
+
+ do {
+ if (aldap_search(al, dn, LDAP_SCOPE_SUBTREE,
+ filter, attrs, 0, 0, 0, pg) == -1) {
+ aldap_get_errno(al, &errstr);
+ log_debug("%s", errstr);
+ return (-1);
+ }
+
+ if (pg != NULL) {
+ aldap_freepage(pg);
+ pg = NULL;
+ }
+
+ while ((m = aldap_parse(al)) != NULL) {
+ if (al->msgid != m->msgid) {
+ goto fail;
+ }
+
+ if (m->message_type == LDAP_RES_SEARCH_RESULT) {
+ if (m->page != NULL && m->page->cookie_len != 0)
+ pg = m->page;
+ else
+ pg = NULL;
+
+ aldap_freemsg(m);
+ break;
+ }
+
+ if (m->message_type != LDAP_RES_SEARCH_ENTRY) {
+ goto fail;
+ }
+
+ if (client_build_req(idm, &ir, m, min_attr, max_attr) == 0)
+ imsg_compose_event(env->sc_iev, type, 0, 0, -1,
+ &ir, sizeof(ir));
+
+ aldap_freemsg(m);
+ }
+ } while (pg != NULL);
+
+ return (0);
+
+fail:
+ aldap_freemsg(m);
+ if (pg != NULL) {
+ aldap_freepage(pg);
+ }
+
+ return (-1);
+}
+
+int
+client_try_idm(struct env *env, struct idm *idm)
+{
+ const char *where;
+ char *attrs[ATTR_MAX+1];
+ int i, j;
+ struct aldap_message *m;
+ struct aldap *al;
+
+ where = "connect";
+ if ((al = client_aldap_open(idm->idm_addr)) == NULL)
+ return (-1);
+
+ if (idm->idm_flags & F_NEEDAUTH) {
+ where = "binding";
+ if (aldap_bind(al, idm->idm_binddn, idm->idm_bindcred) == -1)
+ goto bad;
+
+ where = "parsing";
+ if ((m = aldap_parse(al)) == NULL)
+ goto bad;
+ where = "verifying msgid";
+ if (al->msgid != m->msgid) {
+ aldap_freemsg(m);
+ goto bad;
+ }
+ aldap_freemsg(m);
+ }
+
+ bzero(attrs, sizeof(attrs));
+ for (i = 0, j = 0; i < ATTR_MAX; i++) {
+ if (idm->idm_flags & F_FIXED_ATTR(i))
+ continue;
+ attrs[j++] = idm->idm_attrs[i];
+ }
+ attrs[j] = NULL;
+
+ /*
+ * build password line.
+ */
+ where = "search";
+ log_debug("searching password entries");
+ if (client_search_idm(env, idm, al, attrs,
+ idm->idm_filters[FILTER_USER], 0, ATTR_MAX, IMSG_PW_ENTRY) == -1)
+ goto bad;
+
+ bzero(attrs, sizeof(attrs));
+ for (i = ATTR_GR_MIN, j = 0; i < ATTR_GR_MAX; i++) {
+ if (idm->idm_flags & F_FIXED_ATTR(i))
+ continue;
+ attrs[j++] = idm->idm_attrs[i];
+ }
+ attrs[j] = NULL;
+
+ /*
+ * build group line.
+ */
+ where = "search";
+ log_debug("searching group entries");
+ if (client_search_idm(env, idm, al, attrs,
+ idm->idm_filters[FILTER_GROUP], ATTR_GR_MIN, ATTR_GR_MAX,
+ IMSG_GRP_ENTRY) == -1)
+ goto bad;
+
+ aldap_close(al);
+
+ idm->idm_state = STATE_LDAP_DONE;
+
+ return (0);
+bad:
+ aldap_close(al);
+ log_debug("directory %s errored out in %s", idm->idm_name, where);
+ return (-1);
+}
+
+void
+client_periodic_update(int fd, short event, void *p)
+{
+ struct env *env = p;
+
+ struct idm *idm;
+ int fail_cnt = 0;
+
+ /* If LDAP isn't finished, notify the master process to trash the
+ * update. */
+ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
+ if (idm->idm_state < STATE_LDAP_DONE)
+ fail_cnt++;
+
+ idm->idm_state = STATE_NONE;
+
+ client_addr_free(idm);
+ }
+ if (fail_cnt > 0) {
+ log_debug("trash the update");
+ imsg_compose_event(env->sc_iev, IMSG_TRASH_UPDATE, 0, 0, -1,
+ NULL, 0);
+ }
+
+ client_configure(env);
+}
+
+void
+client_configure(struct env *env)
+{
+ struct timeval tv;
+ struct idm *idm;
+ u_int16_t dlen;
+
+ log_debug("connecting to directories");
+
+ imsg_compose_event(env->sc_iev, IMSG_START_UPDATE, 0, 0, -1, NULL, 0);
+
+ /* Start the DNS lookups */
+ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
+ dlen = strlen(idm->idm_name) + 1;
+ imsg_compose_event(env->sc_iev_dns, IMSG_HOST_DNS, idm->idm_id,
+ 0, -1, idm->idm_name, dlen);
+ }
+
+ tv.tv_sec = env->sc_conf_tv.tv_sec;
+ tv.tv_usec = env->sc_conf_tv.tv_usec;
+ evtimer_set(&env->sc_conf_ev, client_periodic_update, env);
+ evtimer_add(&env->sc_conf_ev, &tv);
+}
diff --git a/usr.sbin/ypldap/log.c b/usr.sbin/ypldap/log.c
new file mode 100644
index 0000000..7fec6f7
--- /dev/null
+++ b/usr.sbin/ypldap/log.c
@@ -0,0 +1,162 @@
+/* $OpenBSD: log.c,v 1.1 2008/06/26 15:10:01 pyr Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <time.h>
+
+void log_init(int);
+void log_warn(const char *, ...);
+void log_warnx(const char *, ...);
+void log_info(const char *, ...);
+void log_debug(const char *, ...);
+__dead2 void fatal(const char *);
+__dead2 void fatalx(const char *);
+
+int debug;
+
+void vlog(int, const char *, va_list);
+void logit(int, const char *, ...);
+
+void
+log_init(int n_debug)
+{
+ extern char *__progname;
+
+ debug = n_debug;
+
+ if (!debug)
+ openlog(__progname, LOG_PID | LOG_NDELAY, LOG_DAEMON);
+
+ tzset();
+}
+
+void
+logit(int pri, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vlog(pri, fmt, ap);
+ va_end(ap);
+}
+
+void
+vlog(int pri, const char *fmt, va_list ap)
+{
+ char *nfmt;
+
+ if (debug) {
+ /* best effort in out of mem situations */
+ if (asprintf(&nfmt, "%s\n", fmt) == -1) {
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ } else {
+ vfprintf(stderr, nfmt, ap);
+ free(nfmt);
+ }
+ fflush(stderr);
+ } else
+ vsyslog(pri, fmt, ap);
+}
+
+
+void
+log_warn(const char *emsg, ...)
+{
+ char *nfmt;
+ va_list ap;
+
+ /* best effort to even work in out of memory situations */
+ if (emsg == NULL)
+ logit(LOG_CRIT, "%s", strerror(errno));
+ else {
+ va_start(ap, emsg);
+
+ if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) {
+ /* we tried it... */
+ vlog(LOG_CRIT, emsg, ap);
+ logit(LOG_CRIT, "%s", strerror(errno));
+ } else {
+ vlog(LOG_CRIT, nfmt, ap);
+ free(nfmt);
+ }
+ va_end(ap);
+ }
+}
+
+void
+log_warnx(const char *emsg, ...)
+{
+ va_list ap;
+
+ va_start(ap, emsg);
+ vlog(LOG_CRIT, emsg, ap);
+ va_end(ap);
+}
+
+void
+log_info(const char *emsg, ...)
+{
+ va_list ap;
+
+ va_start(ap, emsg);
+ vlog(LOG_INFO, emsg, ap);
+ va_end(ap);
+}
+
+void
+log_debug(const char *emsg, ...)
+{
+ va_list ap;
+
+ if (debug > 1) {
+ va_start(ap, emsg);
+ vlog(LOG_DEBUG, emsg, ap);
+ va_end(ap);
+ }
+}
+
+void
+fatal(const char *emsg)
+{
+ if (emsg == NULL)
+ logit(LOG_CRIT, "fatal: %s", strerror(errno));
+ else
+ if (errno)
+ logit(LOG_CRIT, "fatal: %s: %s",
+ emsg, strerror(errno));
+ else
+ logit(LOG_CRIT, "fatal: %s", emsg);
+
+ exit(1);
+}
+
+void
+fatalx(const char *emsg)
+{
+ errno = 0;
+ fatal(emsg);
+}
diff --git a/usr.sbin/ypldap/parse.y b/usr.sbin/ypldap/parse.y
new file mode 100644
index 0000000..15d3ff2
--- /dev/null
+++ b/usr.sbin/ypldap/parse.y
@@ -0,0 +1,838 @@
+/* $OpenBSD: parse.y,v 1.18 2015/01/16 06:40:22 deraadt Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
+ * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
+ * Copyright (c) 2004 Ryan McBride <mcbride@openbsd.org>
+ * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 2001 Markus Friedl. All rights reserved.
+ * Copyright (c) 2001 Daniel Hartmeier. All rights reserved.
+ * Copyright (c) 2001 Theo de Raadt. All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+%{
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "ypldap.h"
+
+TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files);
+static struct file {
+ TAILQ_ENTRY(file) entry;
+ FILE *stream;
+ char *name;
+ int lineno;
+ int errors;
+} *file, *topfile;
+struct file *pushfile(const char *, int);
+int popfile(void);
+int check_file_secrecy(int, const char *);
+int yyparse(void);
+int yylex(void);
+int yyerror(const char *, ...)
+ __attribute__((__format__ (printf, 1, 2)))
+ __attribute__((__nonnull__ (1)));
+int kw_cmp(const void *, const void *);
+int lookup(char *);
+int lgetc(int);
+int lungetc(int);
+int findeol(void);
+
+TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
+struct sym {
+ TAILQ_ENTRY(sym) entry;
+ int used;
+ int persist;
+ char *nam;
+ char *val;
+};
+int symset(const char *, const char *, int);
+char *symget(const char *);
+
+struct env *conf = NULL;
+struct idm *idm = NULL;
+static int errors = 0;
+
+typedef struct {
+ union {
+ int64_t number;
+ char *string;
+ } v;
+ int lineno;
+} YYSTYPE;
+
+%}
+
+%token SERVER FILTER ATTRIBUTE BASEDN BINDDN GROUPDN BINDCRED MAPS CHANGE DOMAIN PROVIDE
+%token USER GROUP TO EXPIRE HOME SHELL GECOS UID GID INTERVAL
+%token PASSWD NAME FIXED LIST GROUPNAME GROUPPASSWD GROUPGID MAP
+%token INCLUDE DIRECTORY CLASS PORT ERROR GROUPMEMBERS
+%token <v.string> STRING
+%token <v.number> NUMBER
+%type <v.number> opcode attribute
+%type <v.string> port
+
+%%
+
+grammar : /* empty */
+ | grammar '\n'
+ | grammar include '\n'
+ | grammar varset '\n'
+ | grammar directory '\n'
+ | grammar main '\n'
+ | grammar error '\n' { file->errors++; }
+ ;
+
+nl : '\n' optnl
+ ;
+
+optnl : '\n' optnl
+ | /* empty */
+ ;
+
+
+include : INCLUDE STRING {
+ struct file *nfile;
+
+ if ((nfile = pushfile($2, 0)) == NULL) {
+ yyerror("failed to include file %s", $2);
+ free($2);
+ YYERROR;
+ }
+ free($2);
+
+ file = nfile;
+ lungetc('\n');
+ }
+ ;
+
+varset : STRING '=' STRING {
+ if (symset($1, $3, 0) == -1)
+ fatal("cannot store variable");
+ free($1);
+ free($3);
+ }
+ ;
+
+port : /* empty */ { $$ = NULL; }
+ | PORT STRING { $$ = $2; }
+ ;
+
+opcode : GROUP { $$ = 0; }
+ | PASSWD { $$ = 1; }
+ ;
+
+
+attribute : NAME { $$ = 0; }
+ | PASSWD { $$ = 1; }
+ | UID { $$ = 2; }
+ | GID { $$ = 3; }
+ | CLASS { $$ = 4; }
+ | CHANGE { $$ = 5; }
+ | EXPIRE { $$ = 6; }
+ | GECOS { $$ = 7; }
+ | HOME { $$ = 8; }
+ | SHELL { $$ = 9; }
+ | GROUPNAME { $$ = 10; }
+ | GROUPPASSWD { $$ = 11; }
+ | GROUPGID { $$ = 12; }
+ | GROUPMEMBERS { $$ = 13; }
+ ;
+
+diropt : BINDDN STRING {
+ idm->idm_flags |= F_NEEDAUTH;
+ if (strlcpy(idm->idm_binddn, $2,
+ sizeof(idm->idm_binddn)) >=
+ sizeof(idm->idm_binddn)) {
+ yyerror("directory binddn truncated");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | BINDCRED STRING {
+ idm->idm_flags |= F_NEEDAUTH;
+ if (strlcpy(idm->idm_bindcred, $2,
+ sizeof(idm->idm_bindcred)) >=
+ sizeof(idm->idm_bindcred)) {
+ yyerror("directory bindcred truncated");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | BASEDN STRING {
+ if (strlcpy(idm->idm_basedn, $2,
+ sizeof(idm->idm_basedn)) >=
+ sizeof(idm->idm_basedn)) {
+ yyerror("directory basedn truncated");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | GROUPDN STRING {
+ if(strlcpy(idm->idm_groupdn, $2,
+ sizeof(idm->idm_groupdn)) >=
+ sizeof(idm->idm_groupdn)) {
+ yyerror("directory groupdn truncated");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | opcode FILTER STRING {
+ if (strlcpy(idm->idm_filters[$1], $3,
+ sizeof(idm->idm_filters[$1])) >=
+ sizeof(idm->idm_filters[$1])) {
+ yyerror("filter truncated");
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ | ATTRIBUTE attribute MAPS TO STRING {
+ if (strlcpy(idm->idm_attrs[$2], $5,
+ sizeof(idm->idm_attrs[$2])) >=
+ sizeof(idm->idm_attrs[$2])) {
+ yyerror("attribute truncated");
+ free($5);
+ YYERROR;
+ }
+ free($5);
+ }
+ | FIXED ATTRIBUTE attribute STRING {
+ if (strlcpy(idm->idm_attrs[$3], $4,
+ sizeof(idm->idm_attrs[$3])) >=
+ sizeof(idm->idm_attrs[$3])) {
+ yyerror("attribute truncated");
+ free($4);
+ YYERROR;
+ }
+ idm->idm_flags |= F_FIXED_ATTR($3);
+ free($4);
+ }
+ | LIST attribute MAPS TO STRING {
+ if (strlcpy(idm->idm_attrs[$2], $5,
+ sizeof(idm->idm_attrs[$2])) >=
+ sizeof(idm->idm_attrs[$2])) {
+ yyerror("attribute truncated");
+ free($5);
+ YYERROR;
+ }
+ idm->idm_list |= F_LIST($2);
+ free($5);
+ }
+ ;
+
+directory : DIRECTORY STRING port {
+ if ((idm = calloc(1, sizeof(*idm))) == NULL)
+ fatal(NULL);
+ idm->idm_id = conf->sc_maxid++;
+
+ if (strlcpy(idm->idm_name, $2,
+ sizeof(idm->idm_name)) >=
+ sizeof(idm->idm_name)) {
+ yyerror("attribute truncated");
+ free($2);
+ YYERROR;
+ }
+
+ free($2);
+ } '{' optnl diropts '}' {
+ TAILQ_INSERT_TAIL(&conf->sc_idms, idm, idm_entry);
+ idm = NULL;
+ }
+ ;
+
+main : INTERVAL NUMBER {
+ conf->sc_conf_tv.tv_sec = $2;
+ conf->sc_conf_tv.tv_usec = 0;
+ }
+ | DOMAIN STRING {
+ if (strlcpy(conf->sc_domainname, $2,
+ sizeof(conf->sc_domainname)) >=
+ sizeof(conf->sc_domainname)) {
+ yyerror("domainname truncated");
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ }
+ | PROVIDE MAP STRING {
+ if (strcmp($3, "passwd.byname") == 0)
+ conf->sc_flags |= YPMAP_PASSWD_BYNAME;
+ else if (strcmp($3, "passwd.byuid") == 0)
+ conf->sc_flags |= YPMAP_PASSWD_BYUID;
+ else if (strcmp($3, "master.passwd.byname") == 0)
+ conf->sc_flags |= YPMAP_MASTER_PASSWD_BYNAME;
+ else if (strcmp($3, "master.passwd.byuid") == 0)
+ conf->sc_flags |= YPMAP_MASTER_PASSWD_BYUID;
+ else if (strcmp($3, "group.byname") == 0)
+ conf->sc_flags |= YPMAP_GROUP_BYNAME;
+ else if (strcmp($3, "group.bygid") == 0)
+ conf->sc_flags |= YPMAP_GROUP_BYGID;
+ else if (strcmp($3, "netid.byname") == 0)
+ conf->sc_flags |= YPMAP_NETID_BYNAME;
+ else {
+ yyerror("unsupported map type: %s", $3);
+ free($3);
+ YYERROR;
+ }
+ free($3);
+ }
+ ;
+
+diropts : diropts diropt nl
+ | diropt optnl
+ ;
+
+%%
+
+struct keywords {
+ const char *k_name;
+ int k_val;
+};
+
+int
+yyerror(const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ file->errors++;
+ va_start(ap, fmt);
+ if (vasprintf(&msg, fmt, ap) == -1)
+ fatalx("yyerror vasprintf");
+ va_end(ap);
+ logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg);
+ free(msg);
+ return (0);
+}
+
+int
+kw_cmp(const void *k, const void *e)
+{
+ return (strcmp(k, ((const struct keywords *)e)->k_name));
+}
+
+int
+lookup(char *s)
+{
+ /* this has to be sorted always */
+ static const struct keywords keywords[] = {
+ { "attribute", ATTRIBUTE },
+ { "basedn", BASEDN },
+ { "bindcred", BINDCRED },
+ { "binddn", BINDDN },
+ { "change", CHANGE },
+ { "class", CLASS },
+ { "directory", DIRECTORY },
+ { "domain", DOMAIN },
+ { "expire", EXPIRE },
+ { "filter", FILTER },
+ { "fixed", FIXED },
+ { "gecos", GECOS },
+ { "gid", GID },
+ { "group", GROUP },
+ { "groupdn", GROUPDN },
+ { "groupgid", GROUPGID },
+ { "groupmembers", GROUPMEMBERS },
+ { "groupname", GROUPNAME },
+ { "grouppasswd", GROUPPASSWD },
+ { "home", HOME },
+ { "include", INCLUDE },
+ { "interval", INTERVAL },
+ { "list", LIST },
+ { "map", MAP },
+ { "maps", MAPS },
+ { "name", NAME },
+ { "passwd", PASSWD },
+ { "port", PORT },
+ { "provide", PROVIDE },
+ { "server", SERVER },
+ { "shell", SHELL },
+ { "to", TO },
+ { "uid", UID },
+ { "user", USER },
+ };
+ const struct keywords *p;
+
+ p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]),
+ sizeof(keywords[0]), kw_cmp);
+
+ if (p)
+ return (p->k_val);
+ else
+ return (STRING);
+}
+
+#define MAXPUSHBACK 128
+
+u_char *parsebuf;
+int parseindex;
+u_char pushback_buffer[MAXPUSHBACK];
+int pushback_index = 0;
+
+int
+lgetc(int quotec)
+{
+ int c, next;
+
+ if (parsebuf) {
+ /* Read character from the parsebuffer instead of input. */
+ if (parseindex >= 0) {
+ c = parsebuf[parseindex++];
+ if (c != '\0')
+ return (c);
+ parsebuf = NULL;
+ } else
+ parseindex++;
+ }
+
+ if (pushback_index)
+ return (pushback_buffer[--pushback_index]);
+
+ if (quotec) {
+ if ((c = getc(file->stream)) == EOF) {
+ yyerror("reached end of file while parsing "
+ "quoted string");
+ if (file == topfile || popfile() == EOF)
+ return (EOF);
+ return (quotec);
+ }
+ return (c);
+ }
+
+ while ((c = getc(file->stream)) == '\\') {
+ next = getc(file->stream);
+ if (next != '\n') {
+ c = next;
+ break;
+ }
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+
+ while (c == EOF) {
+ if (file == topfile || popfile() == EOF)
+ return (EOF);
+ c = getc(file->stream);
+ }
+ return (c);
+}
+
+int
+lungetc(int c)
+{
+ if (c == EOF)
+ return (EOF);
+ if (parsebuf) {
+ parseindex--;
+ if (parseindex >= 0)
+ return (c);
+ }
+ if (pushback_index < MAXPUSHBACK-1)
+ return (pushback_buffer[pushback_index++] = c);
+ else
+ return (EOF);
+}
+
+int
+findeol(void)
+{
+ int c;
+
+ parsebuf = NULL;
+
+ /* skip to either EOF or the first real EOL */
+ while (1) {
+ if (pushback_index)
+ c = pushback_buffer[--pushback_index];
+ else
+ c = lgetc(0);
+ if (c == '\n') {
+ file->lineno++;
+ break;
+ }
+ if (c == EOF)
+ break;
+ }
+ return (ERROR);
+}
+
+int
+yylex(void)
+{
+ u_char buf[8096];
+ u_char *p, *val;
+ int quotec, next, c;
+ int token;
+
+top:
+ p = buf;
+ while ((c = lgetc(0)) == ' ' || c == '\t')
+ ; /* nothing */
+
+ yylval.lineno = file->lineno;
+ if (c == '#')
+ while ((c = lgetc(0)) != '\n' && c != EOF)
+ ; /* nothing */
+ if (c == '$' && parsebuf == NULL) {
+ while (1) {
+ if ((c = lgetc(0)) == EOF)
+ return (0);
+
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ if (isalnum(c) || c == '_') {
+ *p++ = c;
+ continue;
+ }
+ *p = '\0';
+ lungetc(c);
+ break;
+ }
+ val = symget(buf);
+ if (val == NULL) {
+ yyerror("macro '%s' not defined", buf);
+ return (findeol());
+ }
+ parsebuf = val;
+ parseindex = 0;
+ goto top;
+ }
+
+ switch (c) {
+ case '\'':
+ case '"':
+ quotec = c;
+ while (1) {
+ if ((c = lgetc(quotec)) == EOF)
+ return (0);
+ if (c == '\n') {
+ file->lineno++;
+ continue;
+ } else if (c == '\\') {
+ if ((next = lgetc(quotec)) == EOF)
+ return (0);
+ if (next == quotec || c == ' ' || c == '\t')
+ c = next;
+ else if (next == '\n') {
+ file->lineno++;
+ continue;
+ } else
+ lungetc(next);
+ } else if (c == quotec) {
+ *p = '\0';
+ break;
+ } else if (c == '\0') {
+ yyerror("syntax error");
+ return (findeol());
+ }
+ if (p + 1 >= buf + sizeof(buf) - 1) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ *p++ = c;
+ }
+ yylval.v.string = strdup(buf);
+ if (yylval.v.string == NULL)
+ err(1, "yylex: strdup");
+ return (STRING);
+ }
+
+#define allowed_to_end_number(x) \
+ (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=')
+
+ if (c == '-' || isdigit(c)) {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && isdigit(c));
+ lungetc(c);
+ if (p == buf + 1 && buf[0] == '-')
+ goto nodigits;
+ if (c == EOF || allowed_to_end_number(c)) {
+ const char *errstr = NULL;
+
+ *p = '\0';
+ yylval.v.number = strtonum(buf, LLONG_MIN,
+ LLONG_MAX, &errstr);
+ if (errstr) {
+ yyerror("\"%s\" invalid number: %s",
+ buf, errstr);
+ return (findeol());
+ }
+ return (NUMBER);
+ } else {
+nodigits:
+ while (p > buf + 1)
+ lungetc(*--p);
+ c = *--p;
+ if (c == '-')
+ return (c);
+ }
+ }
+
+#define allowed_in_string(x) \
+ (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \
+ x != '{' && x != '}' && x != '<' && x != '>' && \
+ x != '!' && x != '=' && x != '#' && \
+ x != ','))
+
+ if (isalnum(c) || c == ':' || c == '_') {
+ do {
+ *p++ = c;
+ if ((unsigned)(p-buf) >= sizeof(buf)) {
+ yyerror("string too long");
+ return (findeol());
+ }
+ } while ((c = lgetc(0)) != EOF && (allowed_in_string(c)));
+ lungetc(c);
+ *p = '\0';
+ if ((token = lookup(buf)) == STRING)
+ if ((yylval.v.string = strdup(buf)) == NULL)
+ err(1, "yylex: strdup");
+ return (token);
+ }
+ if (c == '\n') {
+ yylval.lineno = file->lineno;
+ file->lineno++;
+ }
+ if (c == EOF)
+ return (0);
+ return (c);
+}
+
+int
+check_file_secrecy(int fd, const char *fname)
+{
+ struct stat st;
+
+ if (fstat(fd, &st)) {
+ log_warn("cannot stat %s", fname);
+ return (-1);
+ }
+ if (st.st_uid != 0 && st.st_uid != getuid()) {
+ log_warnx("%s: owner not root or current user", fname);
+ return (-1);
+ }
+ if (st.st_mode & (S_IWGRP | S_IXGRP | S_IRWXO)) {
+ log_warnx("%s: group writable or world read/writable", fname);
+ return (-1);
+ }
+ return (0);
+}
+
+struct file *
+pushfile(const char *name, int secret)
+{
+ struct file *nfile;
+
+ if ((nfile = calloc(1, sizeof(struct file))) == NULL) {
+ log_warn("malloc");
+ return (NULL);
+ }
+ if ((nfile->name = strdup(name)) == NULL) {
+ log_warn("malloc");
+ free(nfile);
+ return (NULL);
+ }
+ if ((nfile->stream = fopen(nfile->name, "r")) == NULL) {
+ log_warn("%s", nfile->name);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ } else if (secret &&
+ check_file_secrecy(fileno(nfile->stream), nfile->name)) {
+ fclose(nfile->stream);
+ free(nfile->name);
+ free(nfile);
+ return (NULL);
+ }
+ nfile->lineno = 1;
+ TAILQ_INSERT_TAIL(&files, nfile, entry);
+ return (nfile);
+}
+
+int
+popfile(void)
+{
+ struct file *prev;
+
+ if ((prev = TAILQ_PREV(file, files, entry)) != NULL)
+ prev->errors += file->errors;
+
+ TAILQ_REMOVE(&files, file, entry);
+ fclose(file->stream);
+ free(file->name);
+ free(file);
+ file = prev;
+ return (file ? 0 : EOF);
+}
+
+int
+parse_config(struct env *x_conf, const char *filename, int opts)
+{
+ struct sym *sym, *next;
+
+ conf = x_conf;
+ bzero(conf, sizeof(*conf));
+
+ TAILQ_INIT(&conf->sc_idms);
+ conf->sc_conf_tv.tv_sec = DEFAULT_INTERVAL;
+ conf->sc_conf_tv.tv_usec = 0;
+
+ errors = 0;
+
+ if ((file = pushfile(filename, 1)) == NULL) {
+ return (-1);
+ }
+ topfile = file;
+
+ /*
+ * parse configuration
+ */
+ setservent(1);
+ yyparse();
+ endservent();
+ errors = file->errors;
+ popfile();
+
+ /* Free macros and check which have not been used. */
+ for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
+ next = TAILQ_NEXT(sym, entry);
+ if ((opts & YPLDAP_OPT_VERBOSE) && !sym->used)
+ fprintf(stderr, "warning: macro '%s' not "
+ "used\n", sym->nam);
+ if (!sym->persist) {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+
+ if (errors) {
+ return (-1);
+ }
+
+ return (0);
+}
+
+int
+symset(const char *nam, const char *val, int persist)
+{
+ struct sym *sym;
+
+ for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam);
+ sym = TAILQ_NEXT(sym, entry))
+ ; /* nothing */
+
+ if (sym != NULL) {
+ if (sym->persist == 1)
+ return (0);
+ else {
+ free(sym->nam);
+ free(sym->val);
+ TAILQ_REMOVE(&symhead, sym, entry);
+ free(sym);
+ }
+ }
+ if ((sym = calloc(1, sizeof(*sym))) == NULL)
+ return (-1);
+
+ sym->nam = strdup(nam);
+ if (sym->nam == NULL) {
+ free(sym);
+ return (-1);
+ }
+ sym->val = strdup(val);
+ if (sym->val == NULL) {
+ free(sym->nam);
+ free(sym);
+ return (-1);
+ }
+ sym->used = 0;
+ sym->persist = persist;
+ TAILQ_INSERT_TAIL(&symhead, sym, entry);
+ return (0);
+}
+
+int
+cmdline_symset(char *s)
+{
+ char *sym, *val;
+ int ret;
+ size_t len;
+
+ if ((val = strrchr(s, '=')) == NULL)
+ return (-1);
+
+ len = strlen(s) - strlen(val) + 1;
+ if ((sym = malloc(len)) == NULL)
+ errx(1, "cmdline_symset: malloc");
+
+ (void)strlcpy(sym, s, len);
+
+ ret = symset(sym, val + 1, 1);
+ free(sym);
+
+ return (ret);
+}
+
+char *
+symget(const char *nam)
+{
+ struct sym *sym;
+
+ TAILQ_FOREACH(sym, &symhead, entry)
+ if (strcmp(nam, sym->nam) == 0) {
+ sym->used = 1;
+ return (sym->val);
+ }
+ return (NULL);
+}
diff --git a/usr.sbin/ypldap/yp.c b/usr.sbin/ypldap/yp.c
new file mode 100644
index 0000000..e461136
--- /dev/null
+++ b/usr.sbin/ypldap/yp.c
@@ -0,0 +1,652 @@
+/* $OpenBSD: yp.c,v 1.14 2015/02/11 01:26:00 pelikan Exp $ */
+/* $FreeBSD$ */
+/*
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/tree.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <event.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpc/pmap_clnt.h>
+#include <rpc/pmap_prot.h>
+#include <rpc/pmap_rmt.h>
+#include <rpcsvc/yp.h>
+#include <rpcsvc/ypclnt.h>
+
+#include "ypldap.h"
+
+void yp_dispatch(struct svc_req *, SVCXPRT *);
+void yp_disable_events(void);
+void yp_fd_event(int, short, void *);
+int yp_check(struct svc_req *);
+int yp_valid_domain(char *, struct ypresp_val *);
+void yp_make_val(struct ypresp_val *, char *, int);
+void yp_make_keyval(struct ypresp_key_val *, char *, char *);
+
+static struct env *env;
+
+struct yp_event {
+ TAILQ_ENTRY(yp_event) ye_entry;
+ struct event ye_event;
+};
+
+struct yp_data {
+ SVCXPRT *yp_trans_udp;
+ SVCXPRT *yp_trans_tcp;
+ TAILQ_HEAD(, yp_event) yd_events;
+};
+
+void
+yp_disable_events(void)
+{
+ struct yp_event *ye;
+
+ while ((ye = TAILQ_FIRST(&env->sc_yp->yd_events)) != NULL) {
+ TAILQ_REMOVE(&env->sc_yp->yd_events, ye, ye_entry);
+ event_del(&ye->ye_event);
+ free(ye);
+ }
+}
+
+void
+yp_enable_events(void)
+{
+ int i;
+ extern fd_set svc_fdset;
+ struct yp_event *ye;
+
+ for (i = 0; i < getdtablesize(); i++) {
+ if (FD_ISSET(i, &svc_fdset)) {
+ if ((ye = calloc(1, sizeof(*ye))) == NULL)
+ fatal(NULL);
+ event_set(&ye->ye_event, i, EV_READ, yp_fd_event, NULL);
+ event_add(&ye->ye_event, NULL);
+ TAILQ_INSERT_TAIL(&env->sc_yp->yd_events, ye, ye_entry);
+ }
+ }
+}
+
+void
+yp_fd_event(int fd, short event, void *p)
+{
+ svc_getreq_common(fd);
+ yp_disable_events();
+ yp_enable_events();
+}
+
+void
+yp_init(struct env *x_env)
+{
+ struct yp_data *yp;
+
+ if ((yp = calloc(1, sizeof(*yp))) == NULL)
+ fatal(NULL);
+ TAILQ_INIT(&yp->yd_events);
+
+ env = x_env;
+ env->sc_yp = yp;
+
+ (void)pmap_unset(YPPROG, YPVERS);
+
+ if ((yp->yp_trans_udp = svcudp_create(RPC_ANYSOCK)) == NULL)
+ fatal("cannot create udp service");
+ if ((yp->yp_trans_tcp = svctcp_create(RPC_ANYSOCK, 0, 0)) == NULL)
+ fatal("cannot create tcp service");
+
+ if (!svc_register(yp->yp_trans_udp, YPPROG, YPVERS,
+ yp_dispatch, IPPROTO_UDP)) {
+ fatal("unable to register (YPPROG, YPVERS, udp)");
+ }
+ if (!svc_register(yp->yp_trans_tcp, YPPROG, YPVERS,
+ yp_dispatch, IPPROTO_TCP)) {
+ fatal("unable to register (YPPROG, YPVERS, tcp)");
+ }
+}
+
+/*
+ * lots of inspiration from ypserv by Mats O Jansson
+ */
+void
+yp_dispatch(struct svc_req *req, SVCXPRT *trans)
+{
+ xdrproc_t xdr_argument;
+ xdrproc_t xdr_result;
+ char *result;
+ char *(*cb)(char *, struct svc_req *);
+ union {
+ domainname ypproc_domain_2_arg;
+ domainname ypproc_domain_nonack_2_arg;
+ ypreq_key ypproc_match_2_arg;
+ ypreq_nokey ypproc_first_2_arg;
+ ypreq_key ypproc_next_2_arg;
+ ypreq_xfr ypproc_xfr_2_arg;
+ ypreq_nokey ypproc_all_2_arg;
+ ypreq_nokey ypproc_master_2_arg;
+ ypreq_nokey ypproc_order_2_arg;
+ domainname ypproc_maplist_2_arg;
+ } argument;
+
+ xdr_argument = (xdrproc_t) xdr_void;
+ xdr_result = (xdrproc_t) xdr_void;
+ cb = NULL;
+ switch (req->rq_proc) {
+ case YPPROC_NULL:
+ xdr_argument = (xdrproc_t) xdr_void;
+ xdr_result = (xdrproc_t) xdr_void;
+ if (yp_check(req) == -1)
+ return;
+ result = NULL;
+ if (!svc_sendreply(trans, (xdrproc_t) xdr_void,
+ (void *)&result))
+ svcerr_systemerr(trans);
+ return;
+ case YPPROC_DOMAIN:
+ xdr_argument = (xdrproc_t) xdr_domainname;
+ xdr_result = (xdrproc_t) xdr_bool;
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_domain_2_svc;
+ break;
+ case YPPROC_DOMAIN_NONACK:
+ xdr_argument = (xdrproc_t) xdr_domainname;
+ xdr_result = (xdrproc_t) xdr_bool;
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_domain_nonack_2_svc;
+ break;
+ case YPPROC_MATCH:
+ xdr_argument = (xdrproc_t) xdr_ypreq_key;
+ xdr_result = (xdrproc_t) xdr_ypresp_val;
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_match_2_svc;
+ break;
+ case YPPROC_FIRST:
+ xdr_argument = (xdrproc_t) xdr_ypreq_nokey;
+ xdr_result = (xdrproc_t) xdr_ypresp_key_val;
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_first_2_svc;
+ break;
+ case YPPROC_NEXT:
+ xdr_argument = (xdrproc_t) xdr_ypreq_key;
+ xdr_result = (xdrproc_t) xdr_ypresp_key_val;
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_next_2_svc;
+ break;
+ case YPPROC_XFR:
+ if (yp_check(req) == -1)
+ return;
+ svcerr_noproc(trans);
+ return;
+ case YPPROC_CLEAR:
+ log_debug("ypproc_clear");
+ if (yp_check(req) == -1)
+ return;
+ svcerr_noproc(trans);
+ return;
+ case YPPROC_ALL:
+ log_debug("ypproc_all");
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_all_2_svc;
+ break;
+ case YPPROC_MASTER:
+ log_debug("ypproc_master");
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_master_2_svc;
+ break;
+ case YPPROC_ORDER:
+ log_debug("ypproc_order");
+ if (yp_check(req) == -1)
+ return;
+ svcerr_noproc(trans);
+ return;
+ case YPPROC_MAPLIST:
+ log_debug("ypproc_maplist");
+ if (yp_check(req) == -1)
+ return;
+ cb = (void *)ypproc_maplist_2_svc;
+ break;
+ default:
+ svcerr_noproc(trans);
+ return;
+ }
+ (void)memset(&argument, 0, sizeof(argument));
+
+ if (!svc_getargs(trans, xdr_argument, (caddr_t)&argument)) {
+ svcerr_decode(trans);
+ return;
+ }
+ result = (*cb)((char *)&argument, req);
+ if (result != NULL && !svc_sendreply(trans, xdr_result, result))
+ svcerr_systemerr(trans);
+ if (!svc_freeargs(trans, xdr_argument, (caddr_t)&argument)) {
+ /*
+ * ypserv does it too.
+ */
+ fatal("unable to free arguments");
+ }
+}
+
+int
+yp_check(struct svc_req *req)
+{
+ struct sockaddr_in *caller;
+
+ caller = svc_getcaller(req->rq_xprt);
+ /*
+ * We might want to know who we allow here.
+ */
+ return (0);
+}
+
+int
+yp_valid_domain(char *domain, struct ypresp_val *res)
+{
+ if (domain == NULL) {
+ log_debug("NULL domain !");
+ return (-1);
+ }
+ if (strcmp(domain, env->sc_domainname) != 0) {
+ res->stat = YP_NODOM;
+ return (-1);
+ }
+ return (0);
+}
+
+bool_t *
+ypproc_domain_2_svc(domainname *arg, struct svc_req *req)
+{
+ static bool_t res;
+
+ res = (bool_t)1;
+ if (strcmp(*arg, env->sc_domainname) != 0)
+ res = (bool_t)0;
+ return (&res);
+}
+
+bool_t *
+ypproc_domain_nonack_2_svc(domainname *arg, struct svc_req *req)
+{
+ static bool_t res;
+
+ if (strcmp(*arg, env->sc_domainname) != 0)
+ return NULL;
+ res = (bool_t)1;
+ return (&res);
+}
+
+ypresp_val *
+ypproc_match_2_svc(ypreq_key *arg, struct svc_req *req)
+{
+ struct userent ukey;
+ struct userent *ue;
+ struct groupent gkey;
+ struct groupent *ge;
+ static struct ypresp_val res;
+ const char *estr;
+ char *bp, *cp;
+ char key[YPMAXRECORD+1];
+
+ log_debug("matching '%.*s' in map %s", arg->key.keydat_len,
+ arg->key.keydat_val, arg->map);
+
+ if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
+ return (&res);
+
+ if (env->sc_user_names == NULL) {
+ /*
+ * tree not ready.
+ */
+ return (NULL);
+ }
+
+ if (arg->key.keydat_len > YPMAXRECORD) {
+ log_debug("argument too long");
+ return (NULL);
+ }
+ bzero(key, sizeof(key));
+ (void)strncpy(key, arg->key.keydat_val, arg->key.keydat_len);
+
+ if (strcmp(arg->map, "passwd.byname") == 0 ||
+ strcmp(arg->map, "master.passwd.byname") == 0) {
+ ukey.ue_line = key;
+ if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
+ &ukey)) == NULL) {
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+
+ yp_make_val(&res, ue->ue_line, 1);
+ return (&res);
+ } else if (strcmp(arg->map, "passwd.byuid") == 0 ||
+ strcmp(arg->map, "master.passwd.byuid") == 0) {
+ ukey.ue_uid = strtonum(key, 0, UID_MAX, &estr);
+ if (estr) {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+
+ if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
+ &ukey)) == NULL) {
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+
+ yp_make_val(&res, ue->ue_line, 1);
+ return (&res);
+ } else if (strcmp(arg->map, "group.bygid") == 0) {
+ gkey.ge_gid = strtonum(key, 0, GID_MAX, &estr);
+ if (estr) {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+ if ((ge = RB_FIND(group_gid_tree, &env->sc_group_gids,
+ &gkey)) == NULL) {
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+
+ yp_make_val(&res, ge->ge_line, 1);
+ return (&res);
+ } else if (strcmp(arg->map, "group.byname") == 0) {
+ gkey.ge_line = key;
+ if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
+ &gkey)) == NULL) {
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+
+ yp_make_val(&res, ge->ge_line, 1);
+ return (&res);
+ } else if (strcmp(arg->map, "netid.byname") == 0) {
+ bp = cp = key;
+
+ if (strncmp(bp, "unix.", strlen("unix.")) != 0) {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+
+ bp += strlen("unix.");
+
+ if (*bp == '\0') {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+
+ if (!(cp = strsep(&bp, "@"))) {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+
+ if (strcmp(bp, arg->domain) != 0) {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+
+ ukey.ue_uid = strtonum(cp, 0, UID_MAX, &estr);
+ if (estr) {
+ res.stat = YP_BADARGS;
+ return (&res);
+ }
+
+ if ((ue = RB_FIND(user_uid_tree, &env->sc_user_uids,
+ &ukey)) == NULL) {
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+
+ yp_make_val(&res, ue->ue_netid_line, 0);
+ return (&res);
+
+ } else {
+ log_debug("unknown map %s", arg->map);
+ res.stat = YP_NOMAP;
+ return (&res);
+ }
+}
+
+ypresp_key_val *
+ypproc_first_2_svc(ypreq_nokey *arg, struct svc_req *req)
+{
+ static struct ypresp_key_val res;
+
+ if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
+ return (&res);
+
+ if (strcmp(arg->map, "passwd.byname") == 0 ||
+ strcmp(arg->map, "master.passwd.byname") == 0) {
+ if (env->sc_user_lines == NULL)
+ return (NULL);
+
+ yp_make_keyval(&res, env->sc_user_lines, env->sc_user_lines);
+ } else if (strcmp(arg->map, "group.byname") == 0) {
+ if (env->sc_group_lines == NULL)
+ return (NULL);
+
+ yp_make_keyval(&res, env->sc_group_lines, env->sc_group_lines);
+ } else {
+ log_debug("unknown map %s", arg->map);
+ res.stat = YP_NOMAP;
+ }
+
+ return (&res);
+}
+
+ypresp_key_val *
+ypproc_next_2_svc(ypreq_key *arg, struct svc_req *req)
+{
+ struct userent ukey;
+ struct userent *ue;
+ struct groupent gkey;
+ struct groupent *ge;
+ char *line;
+ static struct ypresp_key_val res;
+ char key[YPMAXRECORD+1];
+
+ if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
+ return (&res);
+
+ if (strcmp(arg->map, "passwd.byname") == 0 ||
+ strcmp(arg->map, "master.passwd.byname") == 0) {
+ bzero(key, sizeof(key));
+ (void)strncpy(key, arg->key.keydat_val,
+ arg->key.keydat_len);
+ ukey.ue_line = key;
+ if ((ue = RB_FIND(user_name_tree, env->sc_user_names,
+ &ukey)) == NULL) {
+ /*
+ * canacar's trick:
+ * the user might have been deleted in between calls
+ * to next since the tree may be modified by a reload.
+ * next should still return the next user in
+ * lexicographical order, hence insert the search key
+ * and look up the next field, then remove it again.
+ */
+ RB_INSERT(user_name_tree, env->sc_user_names, &ukey);
+ if ((ue = RB_NEXT(user_name_tree, &env->sc_user_names,
+ &ukey)) == NULL) {
+ RB_REMOVE(user_name_tree, env->sc_user_names,
+ &ukey);
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+ RB_REMOVE(user_name_tree, env->sc_user_names, &ukey);
+ }
+ line = ue->ue_line + (strlen(ue->ue_line) + 1);
+ line = line + (strlen(line) + 1);
+ yp_make_keyval(&res, line, line);
+ return (&res);
+
+
+ } else if (strcmp(arg->map, "group.byname") == 0) {
+ bzero(key, sizeof(key));
+ (void)strncpy(key, arg->key.keydat_val,
+ arg->key.keydat_len);
+
+ gkey.ge_line = key;
+ if ((ge = RB_FIND(group_name_tree, env->sc_group_names,
+ &gkey)) == NULL) {
+ /*
+ * canacar's trick reloaded.
+ */
+ RB_INSERT(group_name_tree, env->sc_group_names, &gkey);
+ if ((ge = RB_NEXT(group_name_tree, &env->sc_group_names,
+ &gkey)) == NULL) {
+ RB_REMOVE(group_name_tree, env->sc_group_names,
+ &gkey);
+ res.stat = YP_NOKEY;
+ return (&res);
+ }
+ RB_REMOVE(group_name_tree, env->sc_group_names, &gkey);
+ }
+
+ line = ge->ge_line + (strlen(ge->ge_line) + 1);
+ line = line + (strlen(line) + 1);
+ yp_make_keyval(&res, line, line);
+ return (&res);
+ } else {
+ log_debug("unknown map %s", arg->map);
+ res.stat = YP_NOMAP;
+ return (&res);
+ }
+}
+
+ypresp_all *
+ypproc_all_2_svc(ypreq_nokey *arg, struct svc_req *req)
+{
+ static struct ypresp_all res;
+
+ if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
+ return (&res);
+
+ svcerr_auth(req->rq_xprt, AUTH_FAILED);
+ return (NULL);
+}
+
+ypresp_master *
+ypproc_master_2_svc(ypreq_nokey *arg, struct svc_req *req)
+{
+ static struct ypresp_master res;
+
+ if (yp_valid_domain(arg->domain, (struct ypresp_val *)&res) == -1)
+ return (&res);
+
+ res.stat = YP_YPERR;
+ return (&res);
+}
+
+ypresp_maplist *
+ypproc_maplist_2_svc(domainname *arg, struct svc_req *req)
+{
+ size_t i;
+ static struct {
+ char *name;
+ int cond;
+ } mapnames[] = {
+ { "passwd.byname", YPMAP_PASSWD_BYNAME },
+ { "passwd.byuid", YPMAP_PASSWD_BYUID },
+ { "master.passwd.byname", YPMAP_MASTER_PASSWD_BYNAME },
+ { "master.passwd.byuid", YPMAP_MASTER_PASSWD_BYUID },
+ { "group.byname", YPMAP_GROUP_BYNAME },
+ { "group.bygid", YPMAP_GROUP_BYGID },
+ { "netid.byname", YPMAP_NETID_BYNAME },
+ };
+ static ypresp_maplist res;
+ static struct ypmaplist maps[sizeof(mapnames) / sizeof(mapnames[0])];
+
+ if (yp_valid_domain(*arg, (struct ypresp_val *)&res) == -1)
+ return (&res);
+
+ res.stat = YP_TRUE;
+ res.maps = NULL;
+ for (i = 0; i < sizeof(mapnames) / sizeof(mapnames[0]); i++) {
+ if (!(env->sc_flags & mapnames[i].cond))
+ continue;
+ maps[i].map = mapnames[i].name;
+ maps[i].next = res.maps;
+ res.maps = &maps[i];
+ }
+
+ return (&res);
+}
+
+void
+yp_make_val(struct ypresp_val *res, char *line, int replacecolon)
+{
+ static char buf[LINE_WIDTH];
+
+ bzero(buf, sizeof(buf));
+
+ if (replacecolon)
+ line[strlen(line)] = ':';
+ (void)strlcpy(buf, line, sizeof(buf));
+ if (replacecolon)
+ line[strcspn(line, ":")] = '\0';
+ log_debug("sending out %s", buf);
+
+ res->stat = YP_TRUE;
+ res->val.valdat_len = strlen(buf);
+ res->val.valdat_val = buf;
+}
+
+void
+yp_make_keyval(struct ypresp_key_val *res, char *key, char *line)
+{
+ static char keybuf[YPMAXRECORD+1];
+ static char buf[LINE_WIDTH];
+
+ bzero(keybuf, sizeof(keybuf));
+ bzero(buf, sizeof(buf));
+
+ (void)strlcpy(keybuf, key, sizeof(keybuf));
+ res->key.keydat_len = strlen(keybuf);
+ res->key.keydat_val = keybuf;
+
+ if (*line == '\0') {
+ res->stat = YP_NOMORE;
+ return;
+ }
+ res->stat = YP_TRUE;
+ line[strlen(line)] = ':';
+ (void)strlcpy(buf, line, sizeof(buf));
+ line[strcspn(line, ":")] = '\0';
+ log_debug("sending out %s => %s", keybuf, buf);
+
+ res->val.valdat_len = strlen(buf);
+ res->val.valdat_val = buf;
+}
diff --git a/usr.sbin/ypldap/ypldap.8 b/usr.sbin/ypldap/ypldap.8
new file mode 100644
index 0000000..2974e24
--- /dev/null
+++ b/usr.sbin/ypldap/ypldap.8
@@ -0,0 +1,82 @@
+.\" $OpenBSD: ypldap.8,v 1.10 2015/07/27 17:28:40 sobrado Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: July 27 2015 $
+.Dt YPLDAP 8
+.Os
+.Sh NAME
+.Nm ypldap
+.Nd YP map server using LDAP backend
+.Sh SYNOPSIS
+.Nm
+.Op Fl dnv
+.Op Fl D Ar macro Ns = Ns Ar value
+.Op Fl f Ar file
+.Sh DESCRIPTION
+.Nm
+is a daemon providing YP maps using LDAP as a backend.
+RFC 2307 or similar LDAP schemas can be tied to the different YP maps.
+.Nm
+has the same role as
+.Xr ypserv 8
+and the two daemons are exclusive.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl D Ar macro Ns = Ns Ar value
+Define
+.Ar macro
+to be set to
+.Ar value
+on the command line.
+Overrides the definition of
+.Ar macro
+in the configuration file.
+.It Fl d
+Do not daemonize.
+If this option is specified,
+.Nm
+will run in the foreground and log to
+.Em stderr .
+.It Fl f Ar file
+Specify an alternative configuration file.
+.It Fl n
+Configtest mode.
+Only check the configuration file for validity.
+.It Fl v
+Produce more verbose output.
+.El
+.Sh FILES
+.Bl -tag -width "/etc/ypldap.confXX" -compact
+.It Pa /etc/ypldap.conf
+Default
+.Nm
+configuration file.
+.El
+.Sh SEE ALSO
+.Xr ypldap.conf 5 ,
+.Xr ypbind 8
+.Sh HISTORY
+The
+.Nm
+program first appeared in
+.Ox 4.4 .
+.Sh AUTHORS
+The
+.Nm
+program was written by
+.An Pierre-Yves Ritschard .
diff --git a/usr.sbin/ypldap/ypldap.c b/usr.sbin/ypldap/ypldap.c
new file mode 100644
index 0000000..7762270
--- /dev/null
+++ b/usr.sbin/ypldap/ypldap.c
@@ -0,0 +1,651 @@
+/* $OpenBSD: ypldap.c,v 1.16 2015/11/02 10:06:06 jmatthew Exp $ */
+/* $FreeBSD */
+
+/*
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <sys/tree.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <errno.h>
+#include <event.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "ypldap.h"
+
+__dead2 void usage(void);
+int check_child(pid_t, const char *);
+void main_sig_handler(int, short, void *);
+void main_shutdown(void);
+void main_dispatch_client(int, short, void *);
+void main_configure_client(struct env *);
+void main_init_timer(int, short, void *);
+void main_start_update(struct env *);
+void main_trash_update(struct env *);
+void main_end_update(struct env *);
+int main_create_user_groups(struct env *);
+void purge_config(struct env *);
+void reconfigure(struct env *);
+
+int pipe_main2client[2];
+
+pid_t client_pid = 0;
+char *conffile = YPLDAP_CONF_FILE;
+int opts = 0;
+
+void
+usage(void)
+{
+ extern const char *__progname;
+
+ fprintf(stderr, "usage: %s [-dnv] [-D macro=value] [-f file]\n",
+ __progname);
+ exit(1);
+}
+
+int
+check_child(pid_t pid, const char *pname)
+{
+ int status;
+
+ if (waitpid(pid, &status, WNOHANG) > 0) {
+ if (WIFEXITED(status)) {
+ log_warnx("check_child: lost child %s exited", pname);
+ return (1);
+ }
+ if (WIFSIGNALED(status)) {
+ log_warnx("check_child: lost child %s terminated; "
+ "signal %d", pname, WTERMSIG(status));
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/* ARGUSED */
+void
+main_sig_handler(int sig, short event, void *p)
+{
+ int die = 0;
+
+ switch (sig) {
+ case SIGTERM:
+ case SIGINT:
+ die = 1;
+ /* FALLTHROUGH */
+ case SIGCHLD:
+ if (check_child(client_pid, "ldap client")) {
+ client_pid = 0;
+ die = 1;
+ }
+ if (die)
+ main_shutdown();
+ break;
+ case SIGHUP:
+ /* reconfigure */
+ break;
+ default:
+ fatalx("unexpected signal");
+ }
+}
+
+void
+main_shutdown(void)
+{
+ _exit(0);
+}
+
+void
+main_start_update(struct env *env)
+{
+ env->update_trashed = 0;
+
+ log_debug("starting directory update");
+ env->sc_user_line_len = 0;
+ env->sc_group_line_len = 0;
+ if ((env->sc_user_names_t = calloc(1,
+ sizeof(*env->sc_user_names_t))) == NULL ||
+ (env->sc_group_names_t = calloc(1,
+ sizeof(*env->sc_group_names_t))) == NULL)
+ fatal(NULL);
+ RB_INIT(env->sc_user_names_t);
+ RB_INIT(env->sc_group_names_t);
+}
+
+/*
+ * XXX: Currently this function should only be called when updating is
+ * finished. A notification should be send to ldapclient that it should stop
+ * sending new pwd/grp entries before it can be called from different places.
+ */
+void
+main_trash_update(struct env *env)
+{
+ struct userent *ue;
+ struct groupent *ge;
+
+ env->update_trashed = 1;
+
+ while ((ue = RB_ROOT(env->sc_user_names_t)) != NULL) {
+ RB_REMOVE(user_name_tree,
+ env->sc_user_names_t, ue);
+ free(ue->ue_line);
+ free(ue->ue_netid_line);
+ free(ue);
+ }
+ free(env->sc_user_names_t);
+ env->sc_user_names_t = NULL;
+ while ((ge = RB_ROOT(env->sc_group_names_t))
+ != NULL) {
+ RB_REMOVE(group_name_tree,
+ env->sc_group_names_t, ge);
+ free(ge->ge_line);
+ free(ge);
+ }
+ free(env->sc_group_names_t);
+ env->sc_group_names_t = NULL;
+}
+
+int
+main_create_user_groups(struct env *env)
+{
+ struct userent *ue;
+ struct userent ukey;
+ struct groupent *ge;
+ gid_t pw_gid;
+ char *bp, *cp;
+ char *p;
+ const char *errstr = NULL;
+ size_t len;
+
+ RB_FOREACH(ue, user_name_tree, env->sc_user_names_t) {
+ bp = cp = ue->ue_line;
+
+ /* name */
+ bp += strlen(bp) + 1;
+
+ /* password */
+ bp += strcspn(bp, ":") + 1;
+
+ /* uid */
+ bp += strcspn(bp, ":") + 1;
+
+ /* gid */
+ bp[strcspn(bp, ":")] = '\0';
+
+ pw_gid = (gid_t)strtonum(bp, 0, GID_MAX, &errstr);
+ if (errstr) {
+ log_warnx("main: failed to parse gid for uid: %d\n", ue->ue_uid);
+ return (-1);
+ }
+
+ /* bring gid column back to its proper state */
+ bp[strlen(bp)] = ':';
+
+ if ((ue->ue_netid_line = calloc(1, LINE_WIDTH)) == NULL) {
+ return (-1);
+ }
+
+ if (snprintf(ue->ue_netid_line, LINE_WIDTH-1, "%d:%d", ue->ue_uid, pw_gid) >= LINE_WIDTH) {
+
+ return (-1);
+ }
+
+ ue->ue_gid = pw_gid;
+ }
+
+ RB_FOREACH(ge, group_name_tree, env->sc_group_names_t) {
+ bp = cp = ge->ge_line;
+
+ /* name */
+ bp += strlen(bp) + 1;
+
+ /* password */
+ bp += strcspn(bp, ":") + 1;
+
+ /* gid */
+ bp += strcspn(bp, ":") + 1;
+
+ cp = bp;
+ if (*bp == '\0')
+ continue;
+ bp = cp;
+ for (;;) {
+ if (!(cp = strsep(&bp, ",")))
+ break;
+ ukey.ue_line = cp;
+ if ((ue = RB_FIND(user_name_tree, env->sc_user_names_t,
+ &ukey)) == NULL) {
+ /* User not found */
+ log_warnx("main: user: %s is referenced as a "
+ "group member, but can't be found in the "
+ "users map.\n", ukey.ue_line);
+ if (bp != NULL)
+ *(bp-1) = ',';
+ continue;
+ }
+ if (bp != NULL)
+ *(bp-1) = ',';
+
+ /* Make sure the new group doesn't equal to the main gid */
+ if (ge->ge_gid == ue->ue_gid)
+ continue;
+
+ len = strlen(ue->ue_netid_line);
+ p = ue->ue_netid_line + len;
+
+ if ((snprintf(p, LINE_WIDTH-len-1, ",%d",
+ ge->ge_gid)) >= (int)(LINE_WIDTH-len)) {
+ return (-1);
+ }
+ }
+ }
+
+ return (0);
+}
+
+void
+main_end_update(struct env *env)
+{
+ struct userent *ue;
+ struct groupent *ge;
+
+ if (env->update_trashed)
+ return;
+
+ log_debug("updates are over, cleaning up trees now");
+
+ if (main_create_user_groups(env) == -1) {
+ main_trash_update(env);
+ return;
+ }
+
+ if (env->sc_user_names == NULL) {
+ env->sc_user_names = env->sc_user_names_t;
+ env->sc_user_lines = NULL;
+ env->sc_user_names_t = NULL;
+
+ env->sc_group_names = env->sc_group_names_t;
+ env->sc_group_lines = NULL;
+ env->sc_group_names_t = NULL;
+
+ flatten_entries(env);
+ goto make_uids;
+ }
+
+ /*
+ * clean previous tree.
+ */
+ while ((ue = RB_ROOT(env->sc_user_names)) != NULL) {
+ RB_REMOVE(user_name_tree, env->sc_user_names,
+ ue);
+ free(ue->ue_netid_line);
+ free(ue);
+ }
+ free(env->sc_user_names);
+ free(env->sc_user_lines);
+
+ env->sc_user_names = env->sc_user_names_t;
+ env->sc_user_lines = NULL;
+ env->sc_user_names_t = NULL;
+
+ while ((ge = RB_ROOT(env->sc_group_names)) != NULL) {
+ RB_REMOVE(group_name_tree,
+ env->sc_group_names, ge);
+ free(ge);
+ }
+ free(env->sc_group_names);
+ free(env->sc_group_lines);
+
+ env->sc_group_names = env->sc_group_names_t;
+ env->sc_group_lines = NULL;
+ env->sc_group_names_t = NULL;
+
+
+ flatten_entries(env);
+
+ /*
+ * trees are flat now. build up uid, gid and netid trees.
+ */
+
+make_uids:
+ RB_INIT(&env->sc_user_uids);
+ RB_INIT(&env->sc_group_gids);
+ RB_FOREACH(ue, user_name_tree, env->sc_user_names)
+ RB_INSERT(user_uid_tree,
+ &env->sc_user_uids, ue);
+ RB_FOREACH(ge, group_name_tree, env->sc_group_names)
+ RB_INSERT(group_gid_tree,
+ &env->sc_group_gids, ge);
+
+}
+
+void
+main_dispatch_client(int fd, short events, void *p)
+{
+ int n;
+ int shut = 0;
+ struct env *env = p;
+ struct imsgev *iev = env->sc_iev;
+ struct imsgbuf *ibuf = &iev->ibuf;
+ struct idm_req ir;
+ struct imsg imsg;
+
+ if ((events & (EV_READ | EV_WRITE)) == 0)
+ fatalx("unknown event");
+
+ if (events & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0)
+ shut = 1;
+ }
+ if (events & EV_WRITE) {
+ if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0)
+ shut = 1;
+ goto done;
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("main_dispatch_client: imsg_get error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_START_UPDATE:
+ main_start_update(env);
+ break;
+ case IMSG_PW_ENTRY: {
+ struct userent *ue;
+ size_t len;
+
+ if (env->update_trashed)
+ break;
+
+ (void)memcpy(&ir, imsg.data, sizeof(ir));
+ if ((ue = calloc(1, sizeof(*ue))) == NULL ||
+ (ue->ue_line = strdup(ir.ir_line)) == NULL) {
+ /*
+ * should cancel tree update instead.
+ */
+ fatal("out of memory");
+ }
+ ue->ue_uid = ir.ir_key.ik_uid;
+ len = strlen(ue->ue_line) + 1;
+ ue->ue_line[strcspn(ue->ue_line, ":")] = '\0';
+ if (RB_INSERT(user_name_tree, env->sc_user_names_t,
+ ue) != NULL) { /* dup */
+ free(ue->ue_line);
+ free(ue);
+ } else
+ env->sc_user_line_len += len;
+ break;
+ }
+ case IMSG_GRP_ENTRY: {
+ struct groupent *ge;
+ size_t len;
+
+ if (env->update_trashed)
+ break;
+
+ (void)memcpy(&ir, imsg.data, sizeof(ir));
+ if ((ge = calloc(1, sizeof(*ge))) == NULL ||
+ (ge->ge_line = strdup(ir.ir_line)) == NULL) {
+ /*
+ * should cancel tree update instead.
+ */
+ fatal("out of memory");
+ }
+ ge->ge_gid = ir.ir_key.ik_gid;
+ len = strlen(ge->ge_line) + 1;
+ ge->ge_line[strcspn(ge->ge_line, ":")] = '\0';
+ if (RB_INSERT(group_name_tree, env->sc_group_names_t,
+ ge) != NULL) { /* dup */
+ free(ge->ge_line);
+ free(ge);
+ } else
+ env->sc_group_line_len += len;
+ break;
+ }
+ case IMSG_TRASH_UPDATE:
+ main_trash_update(env);
+ break;
+ case IMSG_END_UPDATE: {
+ main_end_update(env);
+ break;
+ }
+ default:
+ log_debug("main_dispatch_client: unexpected imsg %d",
+ imsg.hdr.type);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+
+done:
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ log_debug("king bula sez: ran into dead pipe");
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
+main_configure_client(struct env *env)
+{
+ struct idm *idm;
+ struct imsgev *iev = env->sc_iev;
+
+ imsg_compose_event(iev, IMSG_CONF_START, 0, 0, -1, env, sizeof(*env));
+ TAILQ_FOREACH(idm, &env->sc_idms, idm_entry) {
+ imsg_compose_event(iev, IMSG_CONF_IDM, 0, 0, -1,
+ idm, sizeof(*idm));
+ }
+ imsg_compose_event(iev, IMSG_CONF_END, 0, 0, -1, NULL, 0);
+}
+
+void
+main_init_timer(int fd, short event, void *p)
+{
+ struct env *env = p;
+
+ main_configure_client(env);
+}
+
+void
+purge_config(struct env *env)
+{
+ struct idm *idm;
+
+ while ((idm = TAILQ_FIRST(&env->sc_idms)) != NULL) {
+ TAILQ_REMOVE(&env->sc_idms, idm, idm_entry);
+ free(idm);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+ int debug;
+ struct passwd *pw;
+ struct env env;
+ struct event ev_sigint;
+ struct event ev_sigterm;
+ struct event ev_sigchld;
+ struct event ev_sighup;
+ struct event ev_timer;
+ struct timeval tv;
+
+ debug = 0;
+ ypldap_process = PROC_MAIN;
+
+ log_init(1);
+
+ while ((c = getopt(argc, argv, "dD:nf:v")) != -1) {
+ switch (c) {
+ case 'd':
+ debug = 2;
+ break;
+ case 'D':
+ if (cmdline_symset(optarg) < 0)
+ log_warnx("could not parse macro definition %s",
+ optarg);
+ break;
+ case 'n':
+ debug = 2;
+ opts |= YPLDAP_OPT_NOACTION;
+ break;
+ case 'f':
+ conffile = optarg;
+ break;
+ case 'v':
+ opts |= YPLDAP_OPT_VERBOSE;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc)
+ usage();
+
+ RB_INIT(&env.sc_user_uids);
+ RB_INIT(&env.sc_group_gids);
+
+ if (parse_config(&env, conffile, opts))
+ exit(1);
+ if (opts & YPLDAP_OPT_NOACTION) {
+ fprintf(stderr, "configuration OK\n");
+ exit(0);
+ }
+
+ if (geteuid())
+ errx(1, "need root privileges");
+
+ log_init(debug);
+
+ if (!debug) {
+ if (daemon(1, 0) == -1)
+ err(1, "failed to daemonize");
+ }
+
+ log_info("startup%s", (debug > 1)?" [debug mode]":"");
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, PF_UNSPEC,
+ pipe_main2client) == -1)
+ fatal("socketpair");
+
+ client_pid = ldapclient(pipe_main2client);
+
+ setproctitle("parent");
+ event_init();
+
+ signal_set(&ev_sigint, SIGINT, main_sig_handler, &env);
+ signal_set(&ev_sigterm, SIGTERM, main_sig_handler, &env);
+ signal_set(&ev_sighup, SIGHUP, main_sig_handler, &env);
+ signal_set(&ev_sigchld, SIGCHLD, main_sig_handler, &env);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal_add(&ev_sighup, NULL);
+ signal_add(&ev_sigchld, NULL);
+
+ close(pipe_main2client[1]);
+ if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
+ fatal(NULL);
+ imsg_init(&env.sc_iev->ibuf, pipe_main2client[0]);
+ env.sc_iev->handler = main_dispatch_client;
+
+ env.sc_iev->events = EV_READ;
+ env.sc_iev->data = &env;
+ event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
+ env.sc_iev->handler, &env);
+ event_add(&env.sc_iev->ev, NULL);
+
+ yp_init(&env);
+
+ if ((pw = getpwnam(YPLDAP_USER)) == NULL)
+ fatal("getpwnam");
+
+#ifndef DEBUG
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("cannot drop privileges");
+#else
+#warning disabling privilege revocation in debug mode
+#endif
+
+ bzero(&tv, sizeof(tv));
+ evtimer_set(&ev_timer, main_init_timer, &env);
+ evtimer_add(&ev_timer, &tv);
+
+ yp_enable_events();
+ event_dispatch();
+ main_shutdown();
+
+ return (0);
+}
+
+void
+imsg_event_add(struct imsgev *iev)
+{
+ if (iev->handler == NULL) {
+ imsg_flush(&iev->ibuf);
+ return;
+ }
+
+ iev->events = EV_READ;
+ if (iev->ibuf.w.queued)
+ iev->events |= EV_WRITE;
+
+ event_del(&iev->ev);
+ event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data);
+ event_add(&iev->ev, NULL);
+}
+
+int
+imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid,
+ pid_t pid, int fd, void *data, u_int16_t datalen)
+{
+ int ret;
+
+ if ((ret = imsg_compose(&iev->ibuf, type, peerid,
+ pid, fd, data, datalen)) != -1)
+ imsg_event_add(iev);
+ return (ret);
+}
diff --git a/usr.sbin/ypldap/ypldap.conf.5 b/usr.sbin/ypldap/ypldap.conf.5
new file mode 100644
index 0000000..5c22b3b
--- /dev/null
+++ b/usr.sbin/ypldap/ypldap.conf.5
@@ -0,0 +1,167 @@
+.\" $OpenBSD: ypldap.conf.5,v 1.19 2012/04/30 11:28:25 jmatthew Exp $
+.\" $FreeBSD$
+.\"
+.\" Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate: April 30 2012 $
+.Dt YPLDAP.CONF 5
+.Os
+.Sh NAME
+.Nm ypldap.conf
+.Nd LDAP YP map daemon configuration file
+.Sh DESCRIPTION
+The
+.Xr ypldap 8
+daemon provides YP maps using LDAP as a backend.
+.Sh SECTIONS
+The
+.Nm
+config file is divided into three main sections.
+.Bl -tag -width xxxx
+.It Sy Macros
+User-defined variables may be defined and used later, simplifying the
+configuration file.
+.It Sy Global Configuration
+Global settings for
+.Xr ypldap 8 .
+.It Sy Directories
+LDAP Directory specific parameters.
+.El
+.Sh MACROS
+Much like
+.Xr cpp 1
+or
+.Xr m4 1 ,
+macros can be defined that will later be expanded in context.
+Macro names must start with a letter, digit, or underscore,
+and may contain any of those characters.
+Macro names may not be reserved words (for example,
+.Ic domain ) .
+Macros are not expanded inside quotes.
+.Pp
+For example:
+.Bd -literal -offset indent
+
+fixed_gecos="Pulled from LDAP"
+
+fixed attribute gecos $fixed_gecos
+.Ed
+.Sh GLOBAL CONFIGURATION
+Global settings concern the main behaviour of the daemon.
+.Pp
+.Bl -tag -width Ds -compact
+.It domain Ar string
+Specify the name of the NIS domain
+.Nm
+will provide.
+.It interval Ar seconds
+Specify the interval in seconds at which the whole directory will be pulled
+from LDAP.
+.It provide map Ar string
+Specify a map that should be provided by
+.Nm
+The currently implemented maps are: passwd.byname, passwd.byuid,
+group.byname, group.bygid.
+.El
+.Sh DIRECTORIES
+Directories are used to describe the LDAP schema and help
+.Nm
+convert LDAP entries to
+.Xr passwd 5 ,
+.Xr master.passwd 5 ,
+and
+.Xr group 5
+lines.
+A directory declaration is of the following form:
+.Bd -literal -offset indent
+directory "some.host" {
+ # directives
+}
+.Ed
+.Pp
+Valid directives for directories are:
+.Bl -tag -width Ds
+.It Xo
+.Ic attribute Ar name Ic maps to Ar string
+.Xc
+Map the
+.Xr passwd 5 ,
+.Xr master.passwd 5 ,
+or
+.Xr group 5
+attribute to the LDAP attribute name supplied.
+.It Ic basedn Ar string
+Use the supplied search base as starting point for the directory search.
+.It Ic groupdn Ar string
+Use the supplied search base as starting point for the directory search for
+groups.
+If not supplied, the basedn value will be used.
+.It Ic bindcred Ar string
+Use the supplied credentials for simple authentication against the directory.
+.It Ic binddn Ar string
+Use the supplied Distinguished Name to bind to the directory.
+.It Ic fixed attribute Ar attribute string
+Do not retrieve the specified attribute from LDAP but
+instead set it unconditionally to the supplied value for
+every entry.
+.It Ic group filter Ar string
+Use the supplied LDAP filter to retrieve group entries.
+.It Xo
+.Ic list Ar name Ic maps to Ar string
+.Xc
+Map the
+.Xr passwd 5 ,
+.Xr master.passwd 5 ,
+or
+.Xr group 5
+attribute to the LDAP attribute name supplied.
+A list creates a comma separated list of all the LDAP attributes found.
+.Pp
+Valid attributes are:
+.Pp
+.Bl -tag -width groupmembers -offset indent -compact
+.It Ic name
+.It Ic passwd
+.It Ic uid
+.It Ic gid
+.It Ic gecos
+.It Ic home
+.It Ic shell
+.It Ic change
+.It Ic expire
+.It Ic class
+.It Ic groupname
+.It Ic grouppasswd
+.It Ic groupgid
+.It Ic groupmembers
+.El
+.It Ic passwd filter Ar string
+Use the supplied LDAP filter to retrieve password entries.
+.El
+.Sh FILES
+.Bl -tag -width "/etc/ypldap.conf" -compact
+.It Pa /etc/ypldap.conf
+.Xr ypldap 8
+configuration file.
+.El
+.Sh SEE ALSO
+.Xr ypbind 8 ,
+.Xr ypldap 8 ,
+.Xr ypserv 8
+.Sh HISTORY
+The
+.Nm
+file format first appeared in
+.Ox 4.4 .
diff --git a/usr.sbin/ypldap/ypldap.h b/usr.sbin/ypldap/ypldap.h
new file mode 100644
index 0000000..b5e5fc0
--- /dev/null
+++ b/usr.sbin/ypldap/ypldap.h
@@ -0,0 +1,222 @@
+/* $OpenBSD: ypldap.h,v 1.16 2015/01/16 06:40:22 deraadt Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <imsg.h>
+
+#define YPLDAP_USER "_ypldap"
+#define YPLDAP_CONF_FILE "/etc/ypldap.conf"
+#define DEFAULT_INTERVAL 600
+#define LINE_WIDTH 1024
+#define FILTER_WIDTH 128
+#define ATTR_WIDTH 32
+
+#define MAX_SERVERS_DNS 8
+
+enum imsg_type {
+ IMSG_NONE,
+ IMSG_CONF_START,
+ IMSG_CONF_IDM,
+ IMSG_CONF_END,
+ IMSG_START_UPDATE,
+ IMSG_END_UPDATE,
+ IMSG_TRASH_UPDATE,
+ IMSG_PW_ENTRY,
+ IMSG_GRP_ENTRY,
+ IMSG_HOST_DNS
+};
+
+struct ypldap_addr {
+ struct ypldap_addr *next;
+ struct sockaddr_storage ss;
+};
+
+enum {
+ PROC_MAIN,
+ PROC_CLIENT
+} ypldap_process;
+
+struct userent {
+ RB_ENTRY(userent) ue_name_node;
+ RB_ENTRY(userent) ue_uid_node;
+ uid_t ue_uid;
+ char *ue_line;
+ char *ue_netid_line;
+ gid_t ue_gid;
+};
+
+struct groupent {
+ RB_ENTRY(groupent) ge_name_node;
+ RB_ENTRY(groupent) ge_gid_node;
+ gid_t ge_gid;
+ char *ge_line;
+};
+
+enum client_state {
+ STATE_NONE,
+ STATE_DNS_INPROGRESS,
+ STATE_DNS_TEMPFAIL,
+ STATE_DNS_DONE,
+ STATE_LDAP_FAIL,
+ STATE_LDAP_DONE
+};
+
+/*
+ * beck, djm, dlg: pay attention to the struct name
+ */
+struct idm {
+ TAILQ_ENTRY(idm) idm_entry;
+ u_int32_t idm_id;
+ char idm_name[MAXHOSTNAMELEN];
+#define F_SSL 0x00100000
+#define F_CONFIGURING 0x00200000
+#define F_NEEDAUTH 0x00400000
+#define F_FIXED_ATTR(n) (1<<n)
+#define F_LIST(n) (1<<n)
+ enum client_state idm_state;
+ u_int32_t idm_flags; /* lower 20 reserved */
+ u_int32_t idm_list;
+ struct ypldap_addr *idm_addr;
+ in_port_t idm_port;
+ char idm_binddn[LINE_WIDTH];
+ char idm_bindcred[LINE_WIDTH];
+ char idm_basedn[LINE_WIDTH];
+ char idm_groupdn[LINE_WIDTH];
+#define FILTER_USER 1
+#define FILTER_GROUP 0
+ char idm_filters[2][FILTER_WIDTH];
+#define ATTR_NAME 0
+#define ATTR_PASSWD 1
+#define ATTR_UID 2
+#define ATTR_GID 3
+#define ATTR_CLASS 4
+#define ATTR_CHANGE 5
+#define ATTR_EXPIRE 6
+#define ATTR_GECOS 7
+#define ATTR_DIR 8
+#define ATTR_SHELL 9
+#define ATTR_GR_NAME 10
+#define ATTR_GR_PASSWD 11
+#define ATTR_GR_GID 12
+#define ATTR_GR_MEMBERS 13
+#define ATTR_MAX 10
+#define ATTR_GR_MIN 10
+#define ATTR_GR_MAX 14
+ char idm_attrs[14][ATTR_WIDTH];
+ struct env *idm_env;
+ struct event idm_ev;
+#ifdef SSL
+ struct ssl *idm_ssl;
+#endif
+};
+
+struct idm_req {
+ union {
+ uid_t ik_uid;
+ uid_t ik_gid;
+ } ir_key;
+ char ir_line[LINE_WIDTH];
+};
+
+struct imsgev {
+ struct imsgbuf ibuf;
+ void (*handler)(int, short, void *);
+ struct event ev;
+ void *data;
+ short events;
+};
+
+struct env {
+#define YPLDAP_OPT_VERBOSE 0x01
+#define YPLDAP_OPT_NOACTION 0x02
+ u_int8_t sc_opts;
+#define YPMAP_PASSWD_BYNAME 0x00000001
+#define YPMAP_PASSWD_BYUID 0x00000002
+#define YPMAP_MASTER_PASSWD_BYNAME 0x00000004
+#define YPMAP_MASTER_PASSWD_BYUID 0x00000008
+#define YPMAP_GROUP_BYNAME 0x00000010
+#define YPMAP_GROUP_BYGID 0x00000020
+#define YPMAP_NETID_BYNAME 0x00000040
+ u_int32_t sc_flags;
+
+ u_int32_t sc_maxid;
+
+ char sc_domainname[MAXHOSTNAMELEN];
+ struct timeval sc_conf_tv;
+ struct event sc_conf_ev;
+ TAILQ_HEAD(idm_list, idm) sc_idms;
+ struct imsgev *sc_iev;
+ struct imsgev *sc_iev_dns;
+
+ RB_HEAD(user_name_tree,userent) *sc_user_names;
+ RB_HEAD(user_uid_tree,userent) sc_user_uids;
+ RB_HEAD(group_name_tree,groupent)*sc_group_names;
+ RB_HEAD(group_gid_tree,groupent) sc_group_gids;
+ struct user_name_tree *sc_user_names_t;
+ struct group_name_tree *sc_group_names_t;
+ size_t sc_user_line_len;
+ size_t sc_group_line_len;
+ char *sc_user_lines;
+ char *sc_group_lines;
+
+ struct yp_data *sc_yp;
+
+ int update_trashed;
+};
+
+/* log.c */
+void log_init(int);
+void log_warn(const char *, ...);
+void log_warnx(const char *, ...);
+void log_info(const char *, ...);
+void log_debug(const char *, ...);
+void logit(int, const char *, ...);
+void vlog(int, const char *, va_list);
+__dead2 void fatal(const char *);
+__dead2 void fatalx(const char *);
+
+/* parse.y */
+int parse_config(struct env *, const char *, int);
+int cmdline_symset(char *);
+
+/* ldapclient.c */
+pid_t ldapclient(int []);
+
+/* ypldap.c */
+void purge_config(struct env *);
+void imsg_event_add(struct imsgev *);
+int imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
+ pid_t, int, void *, u_int16_t);
+
+/* entries.c */
+void flatten_entries(struct env *);
+int userent_name_cmp(struct userent *, struct userent *);
+int userent_uid_cmp(struct userent *, struct userent *);
+int groupent_name_cmp(struct groupent *, struct groupent *);
+int groupent_gid_cmp(struct groupent *, struct groupent *);
+RB_PROTOTYPE( user_name_tree, userent, ue_name_node, userent_name_cmp);
+RB_PROTOTYPE( user_uid_tree, userent, ue_uid_node, userent_uid_cmp);
+RB_PROTOTYPE( group_name_tree, groupent, ge_name_node, groupent_name_cmp);
+RB_PROTOTYPE( group_gid_tree, groupent, ge_gid_node, groupent_gid_cmp);
+
+/* yp.c */
+void yp_init(struct env *);
+void yp_enable_events(void);
+
+/* ypldap_dns.c */
+pid_t ypldap_dns(int[2], struct passwd *);
diff --git a/usr.sbin/ypldap/ypldap_dns.c b/usr.sbin/ypldap/ypldap_dns.c
new file mode 100644
index 0000000..507253c
--- /dev/null
+++ b/usr.sbin/ypldap/ypldap_dns.c
@@ -0,0 +1,254 @@
+/* $OpenBSD: ypldap_dns.c,v 1.8 2015/01/16 06:40:22 deraadt Exp $ */
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+
+#include <netdb.h>
+#include <pwd.h>
+#include <errno.h>
+#include <event.h>
+#include <resolv.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#include "ypldap.h"
+
+volatile sig_atomic_t quit_dns = 0;
+struct imsgev *iev_dns;
+
+void dns_dispatch_imsg(int, short, void *);
+void dns_sig_handler(int, short, void *);
+void dns_shutdown(void);
+int host_dns(const char *s, struct ypldap_addr **hn);
+
+void
+dns_sig_handler(int sig, short event, void *p)
+{
+ switch (sig) {
+ case SIGINT:
+ case SIGTERM:
+ dns_shutdown();
+ break;
+ default:
+ fatalx("unexpected signal");
+ }
+}
+
+void
+dns_shutdown(void)
+{
+ log_info("dns engine exiting");
+ _exit(0);
+}
+
+pid_t
+ypldap_dns(int pipe_ntp[2], struct passwd *pw)
+{
+ pid_t pid;
+ struct event ev_sigint;
+ struct event ev_sigterm;
+ struct event ev_sighup;
+ struct env env;
+
+ switch (pid = fork()) {
+ case -1:
+ fatal("cannot fork");
+ break;
+ case 0:
+ break;
+ default:
+ return (pid);
+ }
+
+ setproctitle("dns engine");
+ close(pipe_ntp[0]);
+
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ fatal("can't drop privileges");
+ endservent();
+
+ event_init();
+ signal_set(&ev_sigint, SIGINT, dns_sig_handler, NULL);
+ signal_set(&ev_sigterm, SIGTERM, dns_sig_handler, NULL);
+ signal_set(&ev_sighup, SIGHUP, dns_sig_handler, NULL);
+ signal_add(&ev_sigint, NULL);
+ signal_add(&ev_sigterm, NULL);
+ signal_add(&ev_sighup, NULL);
+
+ if ((env.sc_iev = calloc(1, sizeof(*env.sc_iev))) == NULL)
+ fatal(NULL);
+
+ env.sc_iev->events = EV_READ;
+ env.sc_iev->data = &env;
+ imsg_init(&env.sc_iev->ibuf, pipe_ntp[1]);
+ env.sc_iev->handler = dns_dispatch_imsg;
+ event_set(&env.sc_iev->ev, env.sc_iev->ibuf.fd, env.sc_iev->events,
+ env.sc_iev->handler, &env);
+ event_add(&env.sc_iev->ev, NULL);
+
+ event_dispatch();
+ dns_shutdown();
+
+ return (0);
+}
+
+void
+dns_dispatch_imsg(int fd, short events, void *p)
+{
+ struct imsg imsg;
+ int n, cnt;
+ char *name;
+ struct ypldap_addr *h, *hn;
+ struct ibuf *buf;
+ struct env *env = p;
+ struct imsgev *iev = env->sc_iev;
+ struct imsgbuf *ibuf = &iev->ibuf;
+ int shut = 0;
+
+ if ((events & (EV_READ | EV_WRITE)) == 0)
+ fatalx("unknown event");
+
+ if (events & EV_READ) {
+ if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
+ fatal("imsg_read error");
+ if (n == 0)
+ shut = 1;
+ }
+ if (events & EV_WRITE) {
+ if ((n = msgbuf_write(&ibuf->w)) == -1 && errno != EAGAIN)
+ fatal("msgbuf_write");
+ if (n == 0)
+ shut = 1;
+ goto done;
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("client_dispatch_imsg: imsg_get error");
+ if (n == 0)
+ break;
+
+ switch (imsg.hdr.type) {
+ case IMSG_HOST_DNS:
+ name = imsg.data;
+ if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE)
+ fatalx("invalid IMSG_HOST_DNS received");
+ imsg.hdr.len -= 1 + IMSG_HEADER_SIZE;
+ if (name[imsg.hdr.len] != '\0' ||
+ strlen(name) != imsg.hdr.len)
+ fatalx("invalid IMSG_HOST_DNS received");
+ if ((cnt = host_dns(name, &hn)) == -1)
+ break;
+ buf = imsg_create(ibuf, IMSG_HOST_DNS,
+ imsg.hdr.peerid, 0,
+ cnt * sizeof(struct sockaddr_storage));
+ if (buf == NULL)
+ break;
+ if (cnt > 0) {
+ h = hn;
+ while (h != NULL) {
+ imsg_add(buf, &h->ss, sizeof(h->ss));
+ hn = h->next;
+ free(h);
+ h = hn;
+ }
+ }
+
+ imsg_close(ibuf, buf);
+ break;
+ default:
+ break;
+ }
+ imsg_free(&imsg);
+ }
+
+done:
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* this pipe is dead, so remove the event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+int
+host_dns(const char *s, struct ypldap_addr **hn)
+{
+ struct addrinfo hints, *res0, *res;
+ int error, cnt = 0;
+ struct sockaddr_in *sa_in;
+ struct sockaddr_in6 *sa_in6;
+ struct ypldap_addr *h, *hh = NULL;
+
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM; /* DUMMY */
+ error = getaddrinfo(s, NULL, &hints, &res0);
+ if (error == EAI_AGAIN || error == EAI_NONAME)
+ return (0);
+ if (error) {
+ log_warnx("could not parse \"%s\": %s", s,
+ gai_strerror(error));
+ return (-1);
+ }
+
+ for (res = res0; res && cnt < MAX_SERVERS_DNS; res = res->ai_next) {
+ if (res->ai_family != AF_INET &&
+ res->ai_family != AF_INET6)
+ continue;
+ if ((h = calloc(1, sizeof(struct ypldap_addr))) == NULL)
+ fatal(NULL);
+ h->ss.ss_family = res->ai_family;
+ if (res->ai_family == AF_INET) {
+ sa_in = (struct sockaddr_in *)&h->ss;
+ sa_in->sin_len = sizeof(struct sockaddr_in);
+ sa_in->sin_addr.s_addr = ((struct sockaddr_in *)
+ res->ai_addr)->sin_addr.s_addr;
+ } else {
+ sa_in6 = (struct sockaddr_in6 *)&h->ss;
+ sa_in6->sin6_len = sizeof(struct sockaddr_in6);
+ memcpy(&sa_in6->sin6_addr, &((struct sockaddr_in6 *)
+ res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
+ }
+
+ h->next = hh;
+ hh = h;
+ cnt++;
+ }
+ freeaddrinfo(res0);
+
+ *hn = hh;
+ return (cnt);
+}
diff --git a/usr.sbin/ypserv/Makefile.yp b/usr.sbin/ypserv/Makefile.yp
index fc207b6..17eabe5 100644
--- a/usr.sbin/ypserv/Makefile.yp
+++ b/usr.sbin/ypserv/Makefile.yp
@@ -141,6 +141,7 @@ target:
# If you want to omit some of them, feel free to comment
# them out from this list.
TARGETS= servers hosts networks protocols rpc services shells group
+TARGETS+= ipnodes
#TARGETS+= aliases
# Sanity checks: filter out targets we can't build
@@ -193,10 +194,8 @@ TARGETS+= amd.map
AMDHOST= /dev/null
.endif
-.if exists($(IPNODES))
-TARGETS+= ipnodes
-.else
-IPNODES= /dev/null
+.if !exists($(IPNODES))
+IPNODES= $(HOSTS)
.endif
all: $(TARGETS)
@@ -387,9 +386,22 @@ netgroup.byuser: $(NETGROUP)
.endif
+# Solaris 8 does the following:
+# - /etc/hosts and hosts.{byname,byaddr} are IPv4 only.
+# - /etc/inet/ipnodes and ipnodes.{byname,byaddr} are used for protocol
+# independent name-to-address mapping.
+#
+# For local name resolution, we made /etc/hosts protocol independent.
+# For NIS name resolution, we obey Solaris 8 practice.
+# - We keep hosts.{byname,byaddr} IPv4 only, to be friendly with Solaris 8
+# clients.
+# - ipnodes.{byname,byaddr} is used for protocol independent mapping.
+# We generate all the mappings from /etc/hosts unless /var/yp/ipnodes
+# exists, for compatibility with FreeBSD local name resolution.
+#
hosts.byname: $(HOSTS)
@echo "Updating $@..."
- @$(AWK) '/^[0-9]/ { for (n=2; n<=NF && $$n !~ "^#.*"; n++) \
+ @$(AWK) '/^[0-9.]+[\t ]/ { for (n=2; n<=NF && $$n !~ "^#.*"; n++) \
print $$n"\t"$$0 }' $(HOSTS) | $(DBLOAD) ${B} -i $(HOSTS) \
-o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
@$(DBLOAD) -c
@@ -399,7 +411,7 @@ hosts.byname: $(HOSTS)
hosts.byaddr: $(HOSTS)
@echo "Updating $@..."
- @$(AWK) '$$1 !~ "^#.*" { print $$1"\t"$$0 }' $(HOSTS) \
+ @$(AWK) '/^[0-9.]+[\t ]/ { print $$1"\t"$$0 }' $(HOSTS) \
| $(DBLOAD) ${B} -i $(HOSTS) -o $(YPMAPDIR)/$@ - $(TMP); \
$(RMV) $(TMP) $@
@$(DBLOAD) -c
@@ -409,30 +421,22 @@ hosts.byaddr: $(HOSTS)
ipnodes.byname: $(IPNODES)
@echo "Updating $@..."
-.if ${IPNODES} == "/dev/null"
- @echo "Ipnodes source file not found -- skipping"
-.else
@$(AWK) '/^[0-9a-fA-F:]/ { for (n=2; n<=NF && $$n !~ "^#.*"; n++) \
print $$n"\t"$$0 }' $(IPNODES) | $(DBLOAD) ${B} -i $(IPNODES) \
-o $(YPMAPDIR)/$@ - $(TMP); $(RMV) $(TMP) $@
@$(DBLOAD) -c
@if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
@if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
-.endif
ipnodes.byaddr: $(IPNODES)
@echo "Updating $@..."
-.if ${IPNODES} == "/dev/null"
- @echo "Ipnodes source file not found -- skipping"
-.else
@$(AWK) '$$1 !~ "^#.*" { print $$1"\t"$$0 }' $(IPNODES) \
| $(DBLOAD) ${B} -i $(IPNODES) -o $(YPMAPDIR)/$@ - $(TMP); \
$(RMV) $(TMP) $@
@$(DBLOAD) -c
@if [ ! $(NOPUSH) ]; then $(YPPUSH) -d $(DOMAIN) $@; fi
@if [ ! $(NOPUSH) ]; then echo "Pushed $@ map." ; fi
-.endif
networks.byname: $(NETWORKS)
diff --git a/usr.sbin/ypserv/yp_access.c b/usr.sbin/ypserv/yp_access.c
index a4ba504..dddde74 100644
--- a/usr.sbin/ypserv/yp_access.c
+++ b/usr.sbin/ypserv/yp_access.c
@@ -129,7 +129,7 @@ load_securenets(void)
if ((fp = fopen(path, "r")) == NULL) {
if (errno == ENOENT) {
- securenets = (struct securenet *)malloc(sizeof(struct securenet));
+ securenets = malloc(sizeof(struct securenet));
securenets->net.s_addr = INADDR_ANY;
securenets->mask.s_addr = INADDR_ANY;
securenets->next = NULL;
@@ -154,7 +154,7 @@ load_securenets(void)
continue;
}
- tmp = (struct securenet *)malloc(sizeof(struct securenet));
+ tmp = malloc(sizeof(struct securenet));
if (!inet_aton((char *)&addr1, (struct in_addr *)&tmp->net)) {
yp_error("badly formatted securenets entry: %s", addr1);
diff --git a/usr.sbin/ypserv/yp_dblookup.c b/usr.sbin/ypserv/yp_dblookup.c
index 6a3bf1c..ecd9052 100644
--- a/usr.sbin/ypserv/yp_dblookup.c
+++ b/usr.sbin/ypserv/yp_dblookup.c
@@ -103,13 +103,13 @@ yp_malloc_qent(void)
{
register struct circleq_entry *q;
- q = (struct circleq_entry *)malloc(sizeof(struct circleq_entry));
+ q = malloc(sizeof(struct circleq_entry));
if (q == NULL) {
yp_error("failed to malloc() circleq entry");
return(NULL);
}
bzero((char *)q, sizeof(struct circleq_entry));
- q->dbptr = (struct dbent *)malloc(sizeof(struct dbent));
+ q->dbptr = malloc(sizeof(struct dbent));
if (q->dbptr == NULL) {
yp_error("failed to malloc() circleq entry");
free(q);
diff --git a/usr.sbin/ypserv/yp_dnslookup.c b/usr.sbin/ypserv/yp_dnslookup.c
index dfb5594..1d83b64 100644
--- a/usr.sbin/ypserv/yp_dnslookup.c
+++ b/usr.sbin/ypserv/yp_dnslookup.c
@@ -149,7 +149,7 @@ circleq_dnsentry *yp_malloc_dnsent(void)
{
register struct circleq_dnsentry *q;
- q = (struct circleq_dnsentry *)malloc(sizeof(struct circleq_dnsentry));
+ q = malloc(sizeof(struct circleq_dnsentry));
if (q == NULL) {
yp_error("failed to malloc() circleq dns entry");
diff --git a/usr.sbin/ypserv/ypinit.sh b/usr.sbin/ypserv/ypinit.sh
index a55e4cb..5008bcf 100644
--- a/usr.sbin/ypserv/ypinit.sh
+++ b/usr.sbin/ypserv/ypinit.sh
@@ -235,7 +235,7 @@ then
for MAP in ${YPMAPLIST}
do
- echo "Transfering ${MAP}..."
+ echo "Transferring ${MAP}..."
if ! ${YPXFR} -p ${YP_DIR} -h ${MASTER} -c -d ${DOMAIN} ${MAP}; then
echo "Can't transfer map ${MAP}." 1>&2
ERROR_EXISTS="YES"
diff --git a/usr.sbin/zic/zdump/Makefile b/usr.sbin/zic/zdump/Makefile
index d654dee..2ff7db9 100644
--- a/usr.sbin/zic/zdump/Makefile
+++ b/usr.sbin/zic/zdump/Makefile
@@ -7,7 +7,7 @@ MAN= zdump.8
SRCS= zdump.c ialloc.c scheck.c
CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
-CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
+CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"${SHAREDIR}/zoneinfo\" -Demkdir=mkdir
CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../contrib/tzcode/stdtime
WARNS?= 2
diff --git a/usr.sbin/zic/zic/Makefile b/usr.sbin/zic/zic/Makefile
index f473da5..c38e3b8 100644
--- a/usr.sbin/zic/zic/Makefile
+++ b/usr.sbin/zic/zic/Makefile
@@ -7,7 +7,7 @@ MAN= zic.8
SRCS= zic.c ialloc.c scheck.c
CFLAGS+= -DTM_GMTOFF=tm_gmtoff -DTM_ZONE=tm_zone -DSTD_INSPIRED -DPCTS
-CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"/usr/share/zoneinfo\" -Demkdir=mkdir
+CFLAGS+= -DHAVE_LONG_DOUBLE -DTZDIR=\"${SHAREDIR}/zoneinfo\" -Demkdir=mkdir
CFLAGS+= -DHAVE_STRERROR -DHAVE_UNISTD_H
CFLAGS+= -I${.CURDIR}/.. -I${.CURDIR}/../../../contrib/tzcode/stdtime
OpenPOWER on IntegriCloud